Files
wecom_it_smart_desk/backend/app/schemas/message.py
T

173 lines
6.4 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# =============================================================================
# 企微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(default="", 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: Optional[str]) -> str:
"""校验消息类型是否合法。"""
# 处理 None 或 undefined 的情况
if v is None or v == "undefined":
return "text"
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
# 服务端时间戳(毫秒)
server_timestamp: Optional[int] = None
# 发送者头像(AI用静态图,员工/坐席用企微API获取)
sender_avatar: Optional[str] = None
model_config = {"from_attributes": True}
# --------------------------------------------------------------------------
# 消息列表响应 Schema
# --------------------------------------------------------------------------
class MessageListResponse(BaseModel):
"""消息列表响应 Schema。
包含消息列表和是否还有更多消息的标志,
用于向上加载历史消息。
Attributes:
items: 消息列表
has_more: 是否还有更多历史消息
"""
items: List[MessageResponse]
has_more: bool
# --------------------------------------------------------------------------
# 历史消息列表响应 Schema(跨会话聚合)
# --------------------------------------------------------------------------
class HistoryMessageListResponse(BaseModel):
"""历史消息列表响应(跨会话聚合)。
用于按员工ID聚合查询所有会话的历史消息,
返回合并后的时间线、是否有更多消息、以及会话摘要映射。
Attributes:
items: 消息列表(按时间倒序,最新在前)
has_more: 是否还有更多历史消息
conversation_summaries: {conversation_id: "前20字摘要"}
"""
items: List[MessageResponse]
has_more: bool
conversation_summaries: Dict[str, str]