Files
Wechat-Bot/wechat-bot/bot/handlers.py
2026-04-08 11:00:31 +08:00

92 lines
2.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
消息处理器模块
提供统一的消息处理流程,消除各消息类型处理器之间的重复代码。
处理流程:
1. 解析消息元数据和内容
2. (可选)下载附件(图片/文件/视频)
3. 调用 Agent 获取回复
"""
import logging
from aibot import generate_req_id
from bot.agent_client import call_agent_stream
from bot.message_parser import extract_metadata, extract_text_content
logger = logging.getLogger(__name__)
async def handle_message(ws_client, frame: dict, msg_type: str):
"""
通用消息处理器,适用于所有消息类型。
对于需要下载附件的消息类型image/file/video
会先尝试下载附件并附加描述信息。
"""
meta = extract_metadata(frame)
user_id = meta["user_id"]
# ---- 提取消息内容 ----
content = await _resolve_content(ws_client, frame, msg_type, meta)
logger.info("收到%s消息 - 用户: %s, 内容: %s", msg_type, user_id, content[:100])
# ---- 调用 Agent ----
reply = await call_agent_stream(ws_client, frame, user_id, content)
# ---- 兜底:未收到回复 ----
if not reply:
stream_id = generate_req_id("stream")
await ws_client.reply_stream(frame, stream_id, "(未收到回复)", True)
async def _resolve_content(
ws_client, frame: dict, msg_type: str, meta: dict
) -> str:
"""
解析消息内容。
对于文本类消息直接提取文本;对于附件类消息尝试下载并附加描述。
"""
if msg_type in ("text", "voice", "mixed"):
return extract_text_content(frame)
if msg_type == "image":
return await _download_and_describe(ws_client, frame, "image", "图片")
if msg_type == "file":
return await _download_and_describe(ws_client, frame, "file", "文件")
if msg_type == "video":
return await _download_and_describe(ws_client, frame, "video", "视频")
return extract_text_content(frame)
async def _download_and_describe(
ws_client, frame: dict, media_type: str, label: str
) -> str:
"""
尝试下载附件并返回描述文本。
下载失败时返回简单描述,不阻断流程。
"""
body = frame.get("body", {})
media_info = body.get(media_type, {})
if not media_info:
return f"[用户发送了一个{label}]"
url = media_info.get("url")
aeskey = media_info.get("aeskey")
if not url:
return f"[用户发送了一个{label}]"
try:
buffer, filename = await ws_client.download_file(url, aeskey)
desc = f"[用户发送了{label}: {filename}, 大小: {len(buffer)} bytes]"
logger.info("%s下载成功: %s, 大小: %d bytes", label, filename, len(buffer))
return desc
except Exception as e:
logger.warning("%s下载失败: %s", label, e)
return f"[用户发送了一个{label}]"