fix: use host network and restore web chat records
This commit is contained in:
+15
-4
@@ -34,11 +34,22 @@ def split_answer(text: str, max_len: int = 3500, max_parts: int = 3) -> list[str
|
||||
return parts
|
||||
|
||||
|
||||
async def safe_send(update: Update, context: ContextTypes.DEFAULT_TYPE, text: str):
|
||||
"""优先回复原消息;若原消息已被自动删除,退回普通 send_message。"""
|
||||
chat_id = update.effective_chat.id
|
||||
try:
|
||||
return await update.message.reply_text(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)
|
||||
|
||||
|
||||
async def cmd_ask(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||
"""向知识库提问"""
|
||||
query = " ".join(context.args) if context.args else ""
|
||||
if not query:
|
||||
reply = await update.message.reply_text(
|
||||
reply = await safe_send(update, context,
|
||||
"❓ 用法: /ask <你的问题>\n"
|
||||
"例如: /ask 怎么安装收割机\n"
|
||||
f"文档地址: {config.SITE_URL}"
|
||||
@@ -48,7 +59,7 @@ async def cmd_ask(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||
return
|
||||
|
||||
logger.info(f"📩 用户提问: [{update.message.from_user.username}] {query}")
|
||||
searching_msg = await update.message.reply_text("🔍 正在搜索知识库并整理详细答案...")
|
||||
searching_msg = await safe_send(update, context, "🔍 正在搜索知识库并整理详细答案...")
|
||||
asyncio.create_task(auto_delete(update.message))
|
||||
asyncio.create_task(auto_delete(searching_msg, seconds=8))
|
||||
|
||||
@@ -60,13 +71,13 @@ async def cmd_ask(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||
parts = split_answer(answer)
|
||||
for i, part in enumerate(parts, 1):
|
||||
prefix = f"📚 回答 {i}/{len(parts)}\n\n" if len(parts) > 1 else ""
|
||||
reply = await update.message.reply_text(prefix + part)
|
||||
reply = await safe_send(update, context, prefix + part)
|
||||
replies.append(reply)
|
||||
for reply in replies:
|
||||
asyncio.create_task(auto_delete(reply, seconds=180))
|
||||
except Exception as e:
|
||||
logger.error(f"❌ 回答失败: {e}")
|
||||
reply = await update.message.reply_text(f"❌ 回答失败: {e}")
|
||||
reply = await safe_send(update, context, f"❌ 回答失败: {e}")
|
||||
asyncio.create_task(auto_delete(reply))
|
||||
|
||||
|
||||
|
||||
+40
-3
@@ -9,6 +9,7 @@ from telegram.ext import ContextTypes, MessageHandler, filters
|
||||
import config
|
||||
from db.models import Message, Ban, Action
|
||||
from services.spam_detector import detect
|
||||
from web.api import broadcast_sse, json_safe
|
||||
|
||||
logger = logging.getLogger("spam_guard")
|
||||
|
||||
@@ -48,8 +49,8 @@ async def handle_message(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||
logger.warning(f"⚡ 防刷屏: @{username} ({user.id}) {len(_flood_cache[user.id])}条/{config.RATE_LIMIT_WINDOW}s")
|
||||
return
|
||||
|
||||
# 记录消息
|
||||
await Message.create(
|
||||
# 记录消息并推送到 Web 管理页
|
||||
message_record = await Message.create(
|
||||
msg_id=msg.message_id,
|
||||
chat_id=update.effective_chat.id,
|
||||
user_id=user.id,
|
||||
@@ -57,12 +58,36 @@ async def handle_message(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||
first_name=first_name,
|
||||
text=text[:500],
|
||||
)
|
||||
await broadcast_sse("chat", json_safe({
|
||||
"id": message_record.id,
|
||||
"msg_id": msg.message_id,
|
||||
"chat_id": update.effective_chat.id,
|
||||
"user_id": user.id,
|
||||
"username": username,
|
||||
"first_name": first_name,
|
||||
"text": text[:500],
|
||||
"time": message_record.created_at,
|
||||
"spam": False,
|
||||
}))
|
||||
|
||||
# === 垃圾检测 ===
|
||||
is_spam, reason = await detect(text, username, first_name)
|
||||
|
||||
if is_spam:
|
||||
logger.warning(f"🚨 垃圾消息 [{username}]: {reason}")
|
||||
await message_record.update_from_dict({"is_spam": True, "spam_reason": reason}).save()
|
||||
await broadcast_sse("spam", json_safe({
|
||||
"id": message_record.id,
|
||||
"msg_id": msg.message_id,
|
||||
"chat_id": update.effective_chat.id,
|
||||
"user_id": user.id,
|
||||
"username": username,
|
||||
"first_name": first_name,
|
||||
"text": text[:500],
|
||||
"time": message_record.created_at,
|
||||
"spam": True,
|
||||
"reason": reason,
|
||||
}))
|
||||
|
||||
# 删消息
|
||||
try:
|
||||
@@ -86,8 +111,20 @@ async def handle_message(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||
"duration_minutes": config.BAN_DURATION_MINUTES,
|
||||
"unban_at": unban_at,
|
||||
}
|
||||
await Ban.create(**ban_record)
|
||||
ban = await Ban.create(**ban_record)
|
||||
await Action.create(action="BAN", user_id=user.id, username=username, details={"reason": reason})
|
||||
await broadcast_sse("ban", json_safe({
|
||||
"id": ban.id,
|
||||
"user_id": user.id,
|
||||
"username": username,
|
||||
"first_name": first_name,
|
||||
"reason": reason,
|
||||
"method": "auto",
|
||||
"duration_minutes": config.BAN_DURATION_MINUTES,
|
||||
"auto_unban": True,
|
||||
"unban_at": unban_at,
|
||||
"time": ban.created_at,
|
||||
}))
|
||||
logger.info(f"🔨 已封禁 [{username}] {config.BAN_DURATION_MINUTES} 分钟")
|
||||
except Exception as e:
|
||||
logger.error(f"❌ 封禁失败: {e}")
|
||||
|
||||
Reference in New Issue
Block a user