101 lines
3.4 KiB
Python
101 lines
3.4 KiB
Python
"""消息工具函数"""
|
|
from __future__ import annotations
|
|
|
|
import asyncio
|
|
import logging
|
|
|
|
import config
|
|
|
|
logger = logging.getLogger("spam_guard")
|
|
|
|
TRANSIENT_BOT_RECORD_PREFIXES = (
|
|
"🔍 正在搜索知识库",
|
|
"正在搜索知识库",
|
|
"🔎 正在搜索知识库",
|
|
"正在整理详细答案",
|
|
)
|
|
|
|
|
|
def should_record_bot_message(text: str) -> bool:
|
|
body = (text or "").strip()
|
|
if not body:
|
|
return False
|
|
return not any(body.startswith(prefix) for prefix in TRANSIENT_BOT_RECORD_PREFIXES)
|
|
|
|
|
|
async def auto_delete(message, seconds: int | None = None) -> None:
|
|
"""延迟删除消息。删除失败不影响主流程。"""
|
|
if not message:
|
|
return
|
|
try:
|
|
await asyncio.sleep(seconds or config.AUTO_DELETE_SECONDS)
|
|
await message.delete()
|
|
except Exception as e:
|
|
logger.debug(f"自动删除消息失败: {e}")
|
|
|
|
|
|
def schedule_delete(message, seconds: int | None = None) -> None:
|
|
"""创建自动删除任务。"""
|
|
asyncio.create_task(auto_delete(message, seconds=seconds))
|
|
|
|
|
|
async def safe_reply(update, context, text: str, **kwargs):
|
|
"""优先回复原消息;原消息已被删除/不可回复时,降级为普通群消息。"""
|
|
try:
|
|
if update and update.message:
|
|
msg = await update.message.reply_text(text, **kwargs)
|
|
await record_bot_message(msg, text)
|
|
return msg
|
|
except Exception as e:
|
|
if "Message to be replied not found" not in str(e):
|
|
logger.warning(f"回复消息失败,降级普通发送: {type(e).__name__}: {e}")
|
|
chat_id = update.effective_chat.id if update and update.effective_chat else None
|
|
if not chat_id:
|
|
raise RuntimeError("missing chat_id for safe_reply")
|
|
msg = await context.bot.send_message(chat_id=chat_id, text=text, **kwargs)
|
|
await record_bot_message(msg, text)
|
|
return msg
|
|
|
|
|
|
async def record_bot_message(message, text: str | None = None, username: str = "tg-bot"):
|
|
"""把机器人发出的群消息写入聊天记录,作为工作记录。"""
|
|
if not message or not getattr(message, "chat_id", None):
|
|
return None
|
|
try:
|
|
chat_type = getattr(getattr(message, "chat", None), "type", None)
|
|
if chat_type == "private":
|
|
return None
|
|
from db.models import Message
|
|
from web.api import broadcast_sse, json_safe
|
|
|
|
body = text if text is not None else (getattr(message, "text", None) or getattr(message, "caption", None) or "")
|
|
if not should_record_bot_message(str(body)):
|
|
return None
|
|
rec = await Message.get_or_none(chat_id=message.chat_id, msg_id=message.message_id)
|
|
if rec:
|
|
return rec
|
|
rec = await Message.create(
|
|
msg_id=message.message_id,
|
|
chat_id=message.chat_id,
|
|
user_id=0,
|
|
username=username,
|
|
first_name="机器人工作记录",
|
|
text=str(body)[:500],
|
|
)
|
|
await broadcast_sse("chat", json_safe({
|
|
"id": rec.id,
|
|
"msg_id": rec.msg_id,
|
|
"chat_id": rec.chat_id,
|
|
"user_id": 0,
|
|
"username": username,
|
|
"first_name": "机器人工作记录",
|
|
"text": rec.text,
|
|
"time": rec.created_at,
|
|
"spam": False,
|
|
"bot_record": True,
|
|
}))
|
|
return rec
|
|
except Exception as e:
|
|
logger.debug(f"记录机器人消息失败: {e}")
|
|
return None
|