from __future__ import annotations from yuxi.channels.models import ChatType TARGET_PREFIX_MAP: dict[str, str] = { "chat_id:": "chat_id", "chat_guid:": "chat_guid", "chat_identifier:": "chat_identifier", "handle:": "handle", "phone:": "phone", "email:": "email", } EXPLICIT_TARGET_RE_PREFIXES = ( "chat_id:", "chat_guid:", "chat_identifier:", "iMessage;", "iMessage", "handle:", "phone:", "email:", ) IMESSAGE_TARGET_PREFIXES = ( "chat_id:", "chat_guid:", "chat_identifier:", "iMessage;", "iMessage", "handle:", "phone:", "email:", "tel:", "mailto:", "+", ) def parse_target(raw_target: str) -> dict[str, str]: """解析目标字符串,返回 {type, value}。 支持的类型: - chat_id: → chat_id - chat_guid: → chat_guid - chat_identifier: → chat_identifier (chat_id 或 chat_guid) - handle: → handle - phone: → phone (E.164) - email: → email - 其他:自动推断为 handle """ if not raw_target: return {"type": "unknown", "value": ""} raw_lower = raw_target.lower() for prefix, type_name in TARGET_PREFIX_MAP.items(): if raw_lower.startswith(prefix): return {"type": type_name, "value": raw_target[len(prefix) :]} if looks_like_explicit_target_id(raw_target): if ";-;" in raw_target or "@chat" in raw_target: return {"type": "chat_guid", "value": raw_target} if raw_target.startswith("iMessage;"): return {"type": "chat_id", "value": raw_target} if "@" in raw_target and "." in raw_target.split("@")[-1]: return {"type": "email", "value": raw_target} return {"type": "handle", "value": raw_target} def looks_like_explicit_target_id(target: str) -> bool: return any(target.lower().startswith(p.lower()) for p in EXPLICIT_TARGET_RE_PREFIXES) def looks_like_imessage_target_id(target: str) -> bool: return any(target.lower().startswith(p.lower()) for p in IMESSAGE_TARGET_PREFIXES) def resolve_chat_type_from_target(target: str) -> ChatType: parsed = parse_target(target) value = parsed["value"] if ";-;" in value or "@chat" in value: return ChatType.GROUP return ChatType.DIRECT