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

146 lines
5.4 KiB
Python
Raw Normal View History

# =============================================================================
# 企微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