feat: record bot messages in chat history
This commit is contained in:
+15
-1
@@ -10,7 +10,7 @@ import config
|
||||
from db.models import Action, Ban, Message, Warning
|
||||
from services.admin_utils import require_admin, resolve_target_user
|
||||
from services.stats_service import get_daily_stats
|
||||
from services.message_utils import safe_reply
|
||||
from services.message_utils import record_bot_message, safe_reply
|
||||
|
||||
logger = logging.getLogger("spam_guard")
|
||||
|
||||
@@ -80,6 +80,7 @@ async def cmd_stats(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||
f"📦 历史封禁: {stats['total_bans']} 条\n"
|
||||
)
|
||||
reply = await safe_reply(update, context, text)
|
||||
await record_bot_message(reply)
|
||||
asyncio.create_task(auto_delete(reply))
|
||||
|
||||
|
||||
@@ -91,6 +92,7 @@ async def cmd_ban(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||
user_id, target = await resolve_target_user(update, context.args)
|
||||
if not user_id:
|
||||
reply = await safe_reply(update, context, "用法: 回复用户消息 /ban,或 /ban 用户ID/@历史用户名")
|
||||
await record_bot_message(reply)
|
||||
asyncio.create_task(auto_delete(reply))
|
||||
return
|
||||
|
||||
@@ -112,6 +114,7 @@ async def cmd_ban(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||
logger.error(f"手动封禁失败: {type(e).__name__}: {e}")
|
||||
reply = await safe_reply(update, context, "❌ 封禁失败,请检查 Bot 权限或目标用户状态")
|
||||
|
||||
await record_bot_message(reply)
|
||||
asyncio.create_task(auto_delete(reply))
|
||||
|
||||
|
||||
@@ -123,6 +126,7 @@ async def cmd_unban(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||
user_id, target = await resolve_target_user(update, context.args)
|
||||
if not user_id:
|
||||
reply = await safe_reply(update, context, "用法: /unban 用户ID/@历史用户名")
|
||||
await record_bot_message(reply)
|
||||
asyncio.create_task(auto_delete(reply))
|
||||
return
|
||||
|
||||
@@ -135,6 +139,7 @@ async def cmd_unban(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||
logger.error(f"手动解封失败: {type(e).__name__}: {e}")
|
||||
reply = await safe_reply(update, context, "❌ 解封失败,请检查 Bot 权限或目标用户状态")
|
||||
|
||||
await record_bot_message(reply)
|
||||
asyncio.create_task(auto_delete(reply))
|
||||
|
||||
|
||||
@@ -146,6 +151,7 @@ async def cmd_warn(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||
user_id, target = await resolve_target_user(update, context.args)
|
||||
if not user_id:
|
||||
reply = await safe_reply(update, context, "用法: 回复用户消息 /warn [原因],或 /warn 用户ID/@历史用户名 [原因]")
|
||||
await record_bot_message(reply)
|
||||
asyncio.create_task(auto_delete(reply))
|
||||
return
|
||||
|
||||
@@ -169,6 +175,7 @@ async def cmd_warn(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||
logger.error(f"警告失败: {type(e).__name__}: {e}")
|
||||
reply = await safe_reply(update, context, "❌ 警告失败,请检查 Bot 权限或数据库状态")
|
||||
|
||||
await record_bot_message(reply)
|
||||
asyncio.create_task(auto_delete(reply))
|
||||
|
||||
async def cmd_mute(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||
@@ -179,6 +186,7 @@ async def cmd_mute(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||
user_id, target = await resolve_target_user(update, context.args)
|
||||
if not user_id:
|
||||
reply = await safe_reply(update, context, "用法: 回复用户消息 /mute [分钟],或 /mute 用户ID/@历史用户名 [分钟]")
|
||||
await record_bot_message(reply)
|
||||
asyncio.create_task(auto_delete(reply))
|
||||
return
|
||||
|
||||
@@ -207,6 +215,7 @@ async def cmd_mute(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||
logger.error(f"禁言失败: {type(e).__name__}: {e}")
|
||||
reply = await safe_reply(update, context, "❌ 禁言失败,请检查 Bot 权限或目标用户状态")
|
||||
|
||||
await record_bot_message(reply)
|
||||
asyncio.create_task(auto_delete(reply))
|
||||
|
||||
|
||||
@@ -215,6 +224,7 @@ async def require_reply_shortcut(update: Update, command: str, usage: str) -> bo
|
||||
if update.message and update.message.reply_to_message:
|
||||
return True
|
||||
reply = await safe_reply(update, context, f"用法: 回复目标消息后使用 {usage}")
|
||||
await record_bot_message(reply)
|
||||
asyncio.create_task(auto_delete(reply))
|
||||
return False
|
||||
|
||||
@@ -253,11 +263,13 @@ async def cmd_purge(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||
|
||||
if not context.args or not context.args[0].isdigit():
|
||||
reply = await safe_reply(update, context, "用法: 回复一条消息后 /purge 数量(最多50)")
|
||||
await record_bot_message(reply)
|
||||
asyncio.create_task(auto_delete(reply))
|
||||
return
|
||||
|
||||
if not update.message.reply_to_message:
|
||||
reply = await safe_reply(update, context, "❌ /purge 需要回复一条消息作为删除起点")
|
||||
await record_bot_message(reply)
|
||||
asyncio.create_task(auto_delete(reply))
|
||||
return
|
||||
|
||||
@@ -279,6 +291,7 @@ async def cmd_purge(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||
|
||||
reply = await update.effective_chat.send_message(f"🧹 已尝试清理 {count} 条,成功删除 {deleted} 条")
|
||||
await Action.create(action="PURGE", chat_id=update.effective_chat.id, operator_id=update.effective_user.id, details={"count": count, "deleted": deleted})
|
||||
await record_bot_message(reply)
|
||||
asyncio.create_task(auto_delete(reply))
|
||||
|
||||
|
||||
@@ -311,6 +324,7 @@ async def cmd_help(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||
"🧹 回复消息 /purge 数量 - 从被引用消息开始尝试批量删除,最多 50 条\n"
|
||||
)
|
||||
reply = await safe_reply(update, context, text)
|
||||
await record_bot_message(reply)
|
||||
asyncio.create_task(auto_delete(reply, seconds=60))
|
||||
|
||||
|
||||
|
||||
+5
-1
@@ -8,7 +8,7 @@ from telegram.ext import ContextTypes, CommandHandler, MessageHandler, filters
|
||||
|
||||
from db.models import Action, GameScore
|
||||
from services.bind_service import bind_with_email_token, unbind, get_binding
|
||||
from services.message_utils import safe_reply
|
||||
from services.message_utils import record_bot_message, safe_reply
|
||||
from services.time_utils import format_dt
|
||||
from services.game_service import get_scores_summary
|
||||
|
||||
@@ -32,6 +32,7 @@ async def cmd_bind(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||
)
|
||||
reply = await safe_reply(update, context, text)
|
||||
asyncio.create_task(auto_delete(update.message, seconds=60))
|
||||
await record_bot_message(reply)
|
||||
asyncio.create_task(auto_delete(reply, seconds=60))
|
||||
return
|
||||
|
||||
@@ -50,6 +51,7 @@ async def cmd_bind(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||
logger.warning(f"🔗 绑定跳转按钮发送失败,改发普通文本: {type(e).__name__}: {e}")
|
||||
reply = await update.effective_chat.send_message(text, disable_web_page_preview=True)
|
||||
asyncio.create_task(auto_delete(update.message, seconds=60))
|
||||
await record_bot_message(reply)
|
||||
asyncio.create_task(auto_delete(reply, seconds=60))
|
||||
return
|
||||
|
||||
@@ -151,6 +153,7 @@ async def cmd_me(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||
reply = await safe_reply(update, context, text)
|
||||
if update.effective_chat.type != "private":
|
||||
asyncio.create_task(auto_delete(update.message, seconds=60))
|
||||
await record_bot_message(reply)
|
||||
asyncio.create_task(auto_delete(reply, seconds=60))
|
||||
|
||||
|
||||
@@ -164,6 +167,7 @@ async def cmd_unbind(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||
else:
|
||||
reply = await safe_reply(update, context, "❌ 你没有绑定的账号")
|
||||
asyncio.create_task(auto_delete(update.message, seconds=60))
|
||||
await record_bot_message(reply)
|
||||
asyncio.create_task(auto_delete(reply, seconds=60))
|
||||
|
||||
|
||||
|
||||
+15
-3
@@ -3,6 +3,7 @@ import asyncio
|
||||
import logging
|
||||
|
||||
import config
|
||||
from services.message_utils import record_bot_message
|
||||
|
||||
from telegram import InlineKeyboardButton, InlineKeyboardMarkup, Update
|
||||
from telegram.ext import ApplicationHandlerStop, CallbackQueryHandler, ContextTypes, CommandHandler, MessageHandler, filters
|
||||
@@ -91,6 +92,7 @@ async def cmd_checkin(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||
else:
|
||||
reply = await update.message.reply_text("❌ 你今天已经签到过了")
|
||||
asyncio.create_task(auto_delete(update.message, seconds=60))
|
||||
await record_bot_message(reply)
|
||||
asyncio.create_task(auto_delete(reply, seconds=60))
|
||||
|
||||
|
||||
@@ -105,6 +107,7 @@ async def cmd_trivia(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||
context.user_data["trivia_options"] = q["opts"]
|
||||
reply = await update.message.reply_text(text)
|
||||
asyncio.create_task(auto_delete(update.message, seconds=60))
|
||||
await record_bot_message(reply)
|
||||
asyncio.create_task(auto_delete(reply, seconds=60))
|
||||
|
||||
|
||||
@@ -121,6 +124,7 @@ async def cmd_score(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||
text += f"🎮 {s.game_type}: {s.score} 分 (胜率 {s.wins}/{s.total})\n"
|
||||
reply = await update.message.reply_text(text)
|
||||
asyncio.create_task(auto_delete(update.message, seconds=60))
|
||||
await record_bot_message(reply)
|
||||
asyncio.create_task(auto_delete(reply, seconds=60))
|
||||
|
||||
|
||||
@@ -137,6 +141,7 @@ async def cmd_rank(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||
text += f"{medal} @{s.username or s.user_id} — {s.score} 分\n"
|
||||
reply = await update.message.reply_text(text)
|
||||
asyncio.create_task(auto_delete(update.message, seconds=60))
|
||||
await record_bot_message(reply)
|
||||
asyncio.create_task(auto_delete(reply, seconds=60))
|
||||
|
||||
|
||||
@@ -195,11 +200,13 @@ async def create_lottery_from_text(update: Update, context: ContextTypes.DEFAULT
|
||||
creator_name=user.username or user.first_name or str(user.id),
|
||||
spec=spec,
|
||||
)
|
||||
lottery_text = await build_lottery_text(event)
|
||||
sent = await context.bot.send_message(
|
||||
chat_id=target_chat_id,
|
||||
text=await build_lottery_text(event),
|
||||
text=lottery_text,
|
||||
reply_markup=lottery_keyboard(event.id),
|
||||
)
|
||||
await record_bot_message(sent, lottery_text)
|
||||
event.message_id = sent.message_id
|
||||
await event.save()
|
||||
if event.end_type == "minutes":
|
||||
@@ -220,6 +227,7 @@ async def send_lottery_private入口(update: Update, context: ContextTypes.DEFAU
|
||||
)
|
||||
reply = await update.effective_message.reply_text(text, reply_markup=keyboard, disable_web_page_preview=True)
|
||||
asyncio.create_task(auto_delete(update.effective_message, seconds=60))
|
||||
await record_bot_message(reply)
|
||||
asyncio.create_task(auto_delete(reply, seconds=60))
|
||||
return reply
|
||||
|
||||
@@ -231,13 +239,14 @@ async def cmd_lottery(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||
|
||||
context.user_data["awaiting_lottery_spec"] = True
|
||||
context.user_data["lottery_target_chat_id"] = config.TG_CHAT_ID
|
||||
await update.message.reply_text(
|
||||
reply = await update.message.reply_text(
|
||||
"🎁 发起群内抽奖\n"
|
||||
"请发送:奖品 | 参与条件 | 结束条件\n\n"
|
||||
"示例:月卡一张 | all | people:3\n"
|
||||
"参与条件:all / checkin / points:N\n"
|
||||
"结束条件:people:N / minutes:N"
|
||||
)
|
||||
await record_bot_message(reply)
|
||||
|
||||
|
||||
async def cmd_shop(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||
@@ -250,6 +259,7 @@ async def cmd_shop(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||
text += "\n购买:/buy 商品编号,例如 /buy 1"
|
||||
reply = await update.message.reply_text(text)
|
||||
asyncio.create_task(auto_delete(update.message, seconds=60))
|
||||
await record_bot_message(reply)
|
||||
asyncio.create_task(auto_delete(reply, seconds=60))
|
||||
|
||||
|
||||
@@ -267,6 +277,7 @@ async def cmd_buy(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||
extra = f",需要 {item['cost']} 分" if item else ""
|
||||
reply = await update.message.reply_text(f"❌ 兑换失败:{result['reason']}{extra}")
|
||||
asyncio.create_task(auto_delete(update.message, seconds=60))
|
||||
await record_bot_message(reply)
|
||||
asyncio.create_task(auto_delete(reply, seconds=60))
|
||||
|
||||
|
||||
@@ -354,6 +365,7 @@ async def handle_trivia_answer(update: Update, context: ContextTypes.DEFAULT_TYP
|
||||
)
|
||||
reply = await msg.reply_text(text)
|
||||
asyncio.create_task(auto_delete(msg, seconds=60))
|
||||
await record_bot_message(reply)
|
||||
asyncio.create_task(auto_delete(reply, seconds=60))
|
||||
raise ApplicationHandlerStop
|
||||
|
||||
@@ -400,7 +412,7 @@ async def cmd_lottery_start(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||
target_chat_id = config.TG_CHAT_ID
|
||||
context.user_data["awaiting_lottery_spec"] = True
|
||||
context.user_data["lottery_target_chat_id"] = target_chat_id
|
||||
await update.message.reply_text(
|
||||
reply = await update.message.reply_text(
|
||||
"🎁 发起群内抽奖\n"
|
||||
"请发送:奖品 | 参与条件 | 结束条件\n\n"
|
||||
"示例:月卡一张 | all | people:3\n"
|
||||
|
||||
+11
-6
@@ -8,6 +8,7 @@ from telegram import Update
|
||||
from telegram.ext import CommandHandler, ContextTypes, filters
|
||||
|
||||
import config
|
||||
from services.message_utils import record_bot_message
|
||||
|
||||
logger = logging.getLogger("spam_guard")
|
||||
|
||||
@@ -89,23 +90,27 @@ async def safe_send(update: Update, context: ContextTypes.DEFAULT_TYPE, text: st
|
||||
use_markup = looks_like_markdown(text) if markdown is None else markdown
|
||||
send_text = markdown_to_html(text) if use_markup else text
|
||||
|
||||
async def _record(msg, body):
|
||||
await record_bot_message(msg, body)
|
||||
return msg
|
||||
|
||||
if use_markup:
|
||||
try:
|
||||
return await update.message.reply_text(send_text, parse_mode="HTML", disable_web_page_preview=True)
|
||||
return await _record(await update.message.reply_text(send_text, parse_mode="HTML", disable_web_page_preview=True), send_text)
|
||||
except Exception as e:
|
||||
if "Message to be replied not found" in str(e):
|
||||
try:
|
||||
return await context.bot.send_message(chat_id=chat_id, text=send_text, parse_mode="HTML", disable_web_page_preview=True)
|
||||
return await _record(await context.bot.send_message(chat_id=chat_id, text=send_text, parse_mode="HTML", disable_web_page_preview=True), send_text)
|
||||
except Exception:
|
||||
return await context.bot.send_message(chat_id=chat_id, text=text, disable_web_page_preview=True)
|
||||
return await _record(await context.bot.send_message(chat_id=chat_id, text=text, disable_web_page_preview=True), text)
|
||||
logger.warning(f"HTML 格式发送失败,降级普通文本: {e}")
|
||||
|
||||
try:
|
||||
return await update.message.reply_text(text, disable_web_page_preview=True)
|
||||
return await _record(await update.message.reply_text(text, disable_web_page_preview=True), text)
|
||||
except Exception as e:
|
||||
if "Message to be replied not found" not in str(e):
|
||||
logger.warning(f"reply_text 失败,改用 send_message: {e}")
|
||||
return await context.bot.send_message(chat_id=chat_id, text=text, disable_web_page_preview=True)
|
||||
logger.warning(f"发送回复失败,降级普通发送: {e}")
|
||||
return await _record(await context.bot.send_message(chat_id=chat_id, text=text, disable_web_page_preview=True), text)
|
||||
|
||||
|
||||
async def cmd_ask(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||
|
||||
@@ -6,6 +6,7 @@ from telegram import Update
|
||||
from telegram.ext import ContextTypes, CommandHandler, filters
|
||||
|
||||
import config
|
||||
from services.message_utils import record_bot_message
|
||||
from services.admin_utils import require_admin
|
||||
from services.night_scheduler import enable_night_mode, disable_night_mode
|
||||
|
||||
@@ -26,6 +27,7 @@ async def cmd_night(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||
"/night off 关闭"
|
||||
)
|
||||
asyncio.create_task(auto_delete(update.message, seconds=60))
|
||||
await record_bot_message(reply)
|
||||
asyncio.create_task(auto_delete(reply, seconds=60))
|
||||
return
|
||||
|
||||
@@ -40,6 +42,7 @@ async def cmd_night(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||
reply = await update.message.reply_text("❓ 用法: /night on|off")
|
||||
|
||||
asyncio.create_task(auto_delete(update.message, seconds=60))
|
||||
await record_bot_message(reply)
|
||||
asyncio.create_task(auto_delete(reply, seconds=60))
|
||||
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ from telegram import Update, InlineKeyboardButton, InlineKeyboardMarkup
|
||||
from telegram.ext import ContextTypes, CallbackQueryHandler, MessageHandler, filters
|
||||
|
||||
import config
|
||||
from services.message_utils import record_bot_message
|
||||
from db.models import Action
|
||||
from services.verify_service import create_verify, check_answer, get_pending_verify
|
||||
|
||||
@@ -77,6 +78,7 @@ async def handle_verify_answer(update: Update, context: ContextTypes.DEFAULT_TYP
|
||||
logger.error(f"⚠️ 恢复权限失败: {e}")
|
||||
|
||||
reply = await update.message.reply_text("🎉 验证通过!欢迎加入群组!")
|
||||
await record_bot_message(reply)
|
||||
asyncio.create_task(auto_delete(reply))
|
||||
await Action.create(action="VERIFY_PASS", chat_id=update.effective_chat.id, user_id=user_id, username=update.effective_user.username)
|
||||
logger.info(f"✅ 验证通过: {user_id}")
|
||||
@@ -85,6 +87,7 @@ async def handle_verify_answer(update: Update, context: ContextTypes.DEFAULT_TYP
|
||||
if result["reason"] == "max_attempts":
|
||||
context.user_data["verifying"] = False
|
||||
reply = await update.message.reply_text("❌ 验证失败次数过多,你将被移出群组")
|
||||
await record_bot_message(reply)
|
||||
asyncio.create_task(auto_delete(reply))
|
||||
try:
|
||||
await update.effective_chat.ban_member(user_id=user_id)
|
||||
@@ -95,6 +98,7 @@ async def handle_verify_answer(update: Update, context: ContextTypes.DEFAULT_TYP
|
||||
await Action.create(action="VERIFY_FAIL", chat_id=update.effective_chat.id, user_id=user_id, username=update.effective_user.username)
|
||||
else:
|
||||
reply = await update.message.reply_text(f"❌ 答案错误,剩余 {config.VERIFY_MAX_ATTEMPTS - result.get('attempts', 0)} 次机会")
|
||||
await record_bot_message(reply)
|
||||
asyncio.create_task(auto_delete(reply))
|
||||
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ from telegram import ChatMember, InlineKeyboardButton, InlineKeyboardMarkup, Upd
|
||||
from telegram.ext import ChatMemberHandler, ContextTypes
|
||||
|
||||
import config
|
||||
from services.message_utils import record_bot_message
|
||||
from db.models import Action, Ban
|
||||
from services.message_utils import schedule_delete
|
||||
from services.spam_detector import classify_username_spam
|
||||
|
||||
@@ -9,7 +9,7 @@ from telegram.ext import ContextTypes
|
||||
|
||||
import config
|
||||
from db.models import Action, Ban, Message
|
||||
from services.message_utils import schedule_delete
|
||||
from services.message_utils import schedule_delete, record_bot_message
|
||||
|
||||
logger = logging.getLogger("spam_guard")
|
||||
|
||||
@@ -38,6 +38,7 @@ async def require_admin(update: Update, context: ContextTypes.DEFAULT_TYPE) -> b
|
||||
return True
|
||||
reply = await update.message.reply_text("⛔ 只有群管理员可以使用这个命令")
|
||||
schedule_delete(update.message)
|
||||
await record_bot_message(reply)
|
||||
schedule_delete(reply)
|
||||
return False
|
||||
|
||||
|
||||
@@ -29,11 +29,56 @@ async def safe_reply(update, context, text: str, **kwargs):
|
||||
"""优先回复原消息;原消息已被删除/不可回复时,降级为普通群消息。"""
|
||||
try:
|
||||
if update and update.message:
|
||||
return await update.message.reply_text(text, **kwargs)
|
||||
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")
|
||||
return await context.bot.send_message(chat_id=chat_id, text=text, **kwargs)
|
||||
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 "")
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user