69 lines
2.3 KiB
Python
69 lines
2.3 KiB
Python
"""
|
|
企微入站归一模型。
|
|
|
|
本文件职责:定义 InboundMessage,作为 channel → handler 的唯一入站结构。
|
|
禁止:在本文件调企微换 ID、写六态、调 LLM。
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from dataclasses import dataclass, field
|
|
from typing import Any
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class InboundMessage:
|
|
"""
|
|
归一后的入站消息(只读)。
|
|
|
|
sender_id:必须来自入站报文 FromUserName / AIBOT 发送人,禁止事后向企微拉取。
|
|
sender_id 为空时不得入业务队列。
|
|
message_id:全局去重键;缺省时由调用方用 msg_id/CreateTime 拼。
|
|
"""
|
|
|
|
sender_id: str
|
|
message_id: str
|
|
content: str
|
|
msg_type: str = "text"
|
|
chat_id: str = ""
|
|
chat_type: str = "single" # single | group
|
|
agent_id: str = ""
|
|
create_time: int = 0
|
|
media: dict[str, Any] = field(default_factory=dict)
|
|
raw: dict[str, Any] = field(default_factory=dict)
|
|
|
|
def has_sender(self) -> bool:
|
|
"""是否具备可进入业务的发送人身份。"""
|
|
return bool(self.sender_id and self.sender_id.strip())
|
|
|
|
def to_dict(self) -> dict[str, Any]:
|
|
"""序列化进 PG JSONB;不含密钥。"""
|
|
return {
|
|
"sender_id": self.sender_id,
|
|
"message_id": self.message_id,
|
|
"content": self.content,
|
|
"msg_type": self.msg_type,
|
|
"chat_id": self.chat_id,
|
|
"chat_type": self.chat_type,
|
|
"agent_id": self.agent_id,
|
|
"create_time": self.create_time,
|
|
"media": self.media,
|
|
"raw": self.raw,
|
|
}
|
|
|
|
@classmethod
|
|
def from_dict(cls, data: dict[str, Any]) -> "InboundMessage":
|
|
"""从 JSONB / dict 还原。"""
|
|
return cls(
|
|
sender_id=str(data.get("sender_id") or ""),
|
|
message_id=str(data.get("message_id") or ""),
|
|
content=str(data.get("content") or ""),
|
|
msg_type=str(data.get("msg_type") or "text"),
|
|
chat_id=str(data.get("chat_id") or ""),
|
|
chat_type=str(data.get("chat_type") or "single"),
|
|
agent_id=str(data.get("agent_id") or ""),
|
|
create_time=int(data.get("create_time") or 0),
|
|
media=dict(data.get("media") or {}),
|
|
raw=dict(data.get("raw") or {}),
|
|
)
|