""" 消息处理器模块 提供统一的消息处理流程,消除各消息类型处理器之间的重复代码。 处理流程: 1. 解析消息元数据和内容 2. (可选)下载附件(图片/文件/视频) 3. 调用 Agent 获取回复 """ import logging 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: logger.warning("Agent 未返回有效回复,用户: %s", user_id) 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}]"