# ============================================================================= # 企微IT智能服务台 — 消息 Pydantic Schema # ============================================================================= # 说明:定义消息相关的请求/响应数据结构 # 支持消息类型:文本(text)/图片(image)/文件(file)/系统(system) # ============================================================================= from datetime import datetime from typing import Any, Dict, List, Optional from pydantic import BaseModel, Field, field_validator # -------------------------------------------------------------------------- # 消息类型和发送者类型的合法值 # -------------------------------------------------------------------------- VALID_MSG_TYPES = {"text", "image", "file", "system"} VALID_SENDER_TYPES = {"employee", "agent", "ai", "system"} # -------------------------------------------------------------------------- # 创建消息 Schema(坐席发送消息时使用) # -------------------------------------------------------------------------- class MessageCreate(BaseModel): """创建消息请求 Schema。 坐席发送消息时使用。 支持文本消息和文件/图片消息。 Attributes: content: 消息内容(文本消息为正文,文件消息为文件URL或描述) msg_type: 消息类型(默认 text,支持 image/file) media_url: 媒体文件URL(图片/文件消息时使用) file_name: 文件名(文件消息时使用) file_size: 文件大小(字节,文件消息时使用) """ content: str = Field(..., min_length=1, description="消息内容") # 支持文本、图片、文件类型 msg_type: str = Field(default="text", description="消息类型: text/image/file") # M1 新增:文件上传相关字段 media_url: Optional[str] = Field(None, description="媒体文件URL(图片/文件消息时使用)") file_name: Optional[str] = Field(None, description="文件名") file_size: Optional[int] = Field(None, description="文件大小(字节)") # M1 新增:引用回复 reply_to_id: Optional[str] = Field(None, description="引用回复:被回复的消息ID") @field_validator("msg_type") @classmethod def validate_msg_type(cls, v: str) -> str: """校验消息类型是否合法。""" if v not in VALID_MSG_TYPES: raise ValueError(f"无效的消息类型: {v},合法值为: {VALID_MSG_TYPES}") return v # -------------------------------------------------------------------------- # 企微回调消息 Schema(从企微接收到的消息) # -------------------------------------------------------------------------- class WecomInboundMessage(BaseModel): """企微回调消息 Schema。 解析企微回调 XML 后得到的结构化消息。 Attributes: from_user_id: 发送者企微UserID content: 消息内容 msg_type: 消息类型(text/image等) create_time: 消息创建时间戳 agent_id: 应用AgentID """ from_user_id: str = Field(..., description="发送者企微UserID") content: str = Field(default="", description="消息内容") msg_type: str = Field(default="text", description="消息类型") create_time: Optional[int] = Field(None, description="消息创建时间戳") agent_id: Optional[str] = Field(None, description="应用AgentID") # -------------------------------------------------------------------------- # 消息响应 Schema(返回给前端的数据结构) # -------------------------------------------------------------------------- class MessageResponse(BaseModel): """消息响应 Schema。 返回给前端的消息数据结构。 使用 from_attributes=True 支持从 SQLAlchemy 模型直接转换。 Attributes: id: 消息ID conversation_id: 所属会话ID sender_type: 发送者类型 sender_id: 发送者ID sender_name: 发送者姓名 content: 消息内容 msg_type: 消息类型 media_url: 媒体文件URL file_name: 文件名 file_size: 文件大小 extra_data: 扩展元数据 ai_suggestion: 是否为AI建议 is_read: 是否已读 created_at: 创建时间 """ id: str conversation_id: str sender_type: str sender_id: str sender_name: str content: str msg_type: str # M1 新增:媒体/文件相关字段 media_url: Optional[str] = None file_name: Optional[str] = None file_size: Optional[int] = None extra_data: Optional[Dict[str, Any]] = None # M1 新增:引用回复 reply_to_id: Optional[str] = None ai_suggestion: bool is_read: bool created_at: datetime # M2 新增:消息状态和可撤回时间 status: str = "sent" recallable_until: Optional[datetime] = None model_config = {"from_attributes": True} # -------------------------------------------------------------------------- # 消息列表响应 Schema # -------------------------------------------------------------------------- class MessageListResponse(BaseModel): """消息列表响应 Schema。 包含消息列表和是否还有更多消息的标志, 用于向上加载历史消息。 Attributes: items: 消息列表 has_more: 是否还有更多历史消息 """ items: List[MessageResponse] has_more: bool