83 lines
2.7 KiB
Python
83 lines
2.7 KiB
Python
"""知识库问答 handler"""
|
|
import asyncio
|
|
import logging
|
|
|
|
from telegram import Update
|
|
from telegram.ext import CommandHandler, ContextTypes, filters
|
|
|
|
import config
|
|
|
|
logger = logging.getLogger("spam_guard")
|
|
|
|
|
|
def split_answer(text: str, max_len: int = 3500, max_parts: int = 3) -> list[str]:
|
|
"""Telegram 单条消息长度有限,长回答按段发送,不再硬截断。"""
|
|
if len(text) <= max_len:
|
|
return [text]
|
|
|
|
parts = []
|
|
rest = text
|
|
while rest and len(parts) < max_parts:
|
|
if len(rest) <= max_len:
|
|
parts.append(rest)
|
|
break
|
|
cut = rest.rfind("\n\n", 0, max_len)
|
|
if cut < max_len // 2:
|
|
cut = rest.rfind("\n", 0, max_len)
|
|
if cut < max_len // 2:
|
|
cut = max_len
|
|
parts.append(rest[:cut].strip())
|
|
rest = rest[cut:].strip()
|
|
|
|
if rest and parts:
|
|
parts[-1] += "\n\n...(回答较长,后续内容已省略;可以追问具体部分)"
|
|
return parts
|
|
|
|
|
|
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(
|
|
"❓ 用法: /ask <你的问题>\n"
|
|
"例如: /ask 怎么安装收割机\n"
|
|
f"文档地址: {config.SITE_URL}"
|
|
)
|
|
asyncio.create_task(auto_delete(update.message))
|
|
asyncio.create_task(auto_delete(reply))
|
|
return
|
|
|
|
logger.info(f"📩 用户提问: [{update.message.from_user.username}] {query}")
|
|
searching_msg = await update.message.reply_text("🔍 正在搜索知识库并整理详细答案...")
|
|
asyncio.create_task(auto_delete(update.message))
|
|
asyncio.create_task(auto_delete(searching_msg, seconds=8))
|
|
|
|
try:
|
|
from services.knowledge_base import ask_knowledge_base
|
|
|
|
answer = await ask_knowledge_base(query)
|
|
replies = []
|
|
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)
|
|
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}")
|
|
asyncio.create_task(auto_delete(reply))
|
|
|
|
|
|
async def auto_delete(message, seconds=60):
|
|
try:
|
|
await asyncio.sleep(seconds)
|
|
await message.delete()
|
|
except Exception:
|
|
pass
|
|
|
|
|
|
def register_knowledge(app):
|
|
app.add_handler(CommandHandler("ask", cmd_ask, filters.ChatType.GROUPS))
|