92 lines
2.8 KiB
Python
92 lines
2.8 KiB
Python
"""
|
||
消息处理器模块
|
||
提供统一的消息处理流程,消除各消息类型处理器之间的重复代码。
|
||
|
||
处理流程:
|
||
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}]"
|