from __future__ import annotations import html import xml.etree.ElementTree as ET from typing import Any, Callable, Dict from wechat_ipad.models.message import MessageType def parse_quote_context(full_msg: Any, room_id: str, get_sender_name: Callable[[str, str], str]) -> Dict[str, str]: if not full_msg or not getattr(full_msg, "content", None): return {} xml_content = getattr(full_msg.content, "xml_content", "") or "" if not xml_content: return {} try: root = ET.fromstring(xml_content) except ET.ParseError: return {} appmsg = root.find(".//appmsg") if appmsg is None or appmsg.findtext("type", "").strip() != "57": return {} refer = appmsg.find("refermsg") if refer is None: return {} title = html.unescape(appmsg.findtext("title", "") or "").strip() quote_sender_name = html.unescape(refer.findtext("displayname", "") or "").strip() if not quote_sender_name: quote_sender = html.unescape(refer.findtext("chatusr", "") or "").strip() quote_sender_name = get_sender_name(room_id, quote_sender) if quote_sender else "未知成员" ref_type = int(refer.findtext("type", "0") or 0) ref_content = html.unescape(refer.findtext("content", "") or "").strip() quote_type_label = quote_type_label_for(ref_type) quote_body = build_quote_body(ref_type, ref_content, title) return { "title": title, "quote_sender_name": quote_sender_name, "quote_type_label": quote_type_label, "quote_body": quote_body, "raw_ref_content": ref_content, } def quote_type_label_for(ref_type: int) -> str: mapping = { MessageType.TEXT.value: "引用文本", MessageType.IMAGE.value: "引用图片", MessageType.VIDEO.value: "引用视频", MessageType.APP.value: "引用应用消息", MessageType.EMOTICON.value: "引用表情", } return mapping.get(ref_type, f"引用消息[{ref_type}]") def build_quote_body(ref_type: int, ref_content: str, title: str) -> str: if ref_type == MessageType.TEXT.value: return ref_content[:220].strip() if ref_type == MessageType.IMAGE.value: details = [] if title: details.append(f"当前追问文案:{title}") if ref_content: details.append("被引用的是一张图片") return ";".join(details) or "被引用的是一张图片" if title: return title[:220].strip() return ref_content[:220].strip()