"""发送域模型:发送文本 / 发送文件 / 发送响应。""" from __future__ import annotations from typing import Optional from pydantic import BaseModel, Field # --------------------------------------------------------------------------- # 发送接口 # --------------------------------------------------------------------------- class SendTextRequest(BaseModel): """发送文本消息请求。""" to_wxid: str = Field(description="目标 wxid") content: str = Field(description="文本内容") display_name: Optional[str] = Field( default=None, description="可选:用于微信搜索框定位会话的显示名。不传时 bridge 自动按备注->昵称->wxid 查找", ) client_request_id: str = Field(default="", description="客户端幂等去重 ID,空字符串表示不参与幂等校验") class SendFileRequest(BaseModel): """发送图片/文件请求。""" to_wxid: str = Field(description="目标 wxid") file_path: str = Field(description="容器内文件绝对路径") display_name: Optional[str] = Field( default=None, description="可选:用于微信搜索框定位会话的显示名。不传时 bridge 自动按备注->昵称->wxid 查找", ) client_request_id: Optional[str] = Field( default=None, description="可选:客户端幂等去重 ID,None 或空字符串表示不参与幂等校验", ) class SendResponse(BaseModel): """发送消息响应。 字段说明: - local_send_id:bridge 本地生成的发送 ID,格式 local__<随机>。 仅用于客户端幂等去重,**不对应微信原生 msg_id**,禁止用于 /api/media/{msg_id} 查媒体。 - placeholder:是否为占位实现(true 表示真实文件/图片内容未传输, 仅发了提示文本;客户端应走降级处理)。 """ success: bool = Field(default=False) local_send_id: str = Field(default="", description="本地生成的发送 ID,非微信原生 msg_id") placeholder: bool = Field(default=False, description="是否为占位实现(真实内容未传输)") error: Optional[str] = Field(default=None, description="失败时的错误描述") verified: bool = Field(default=False, description="是否已通过发送结果验证") skipped: bool = Field(default=False, description="是否因幂等去重被跳过") # --------------------------------------------------------------------------- # 消息撤回(experimental) # --------------------------------------------------------------------------- class RevokeMessageRequest(BaseModel): """撤回消息请求(experimental)。""" talker: str = Field(description="会话对方 wxid") create_time: int = Field(description="消息发送时间戳(Unix 秒),用于校验撤回时限,必须 > 0") display_name: Optional[str] = Field( default=None, description="会话显示名(备注/昵称),用于微信搜索框定位会话;" "不传则从 contact.db 解析(优先 remark,其次 nickname,回退 wxid)", ) class RevokeMessageResponse(BaseModel): """撤回消息响应。""" success: bool = Field(default=False) error: Optional[str] = Field(default=None, description="失败时的错误描述") verified: Optional[bool] = Field( default=None, description="post_verify 校验结果:True=已确认撤回标记写入 DB," "False=超时未检测到,None=未执行校验(DB 不可用或未接入)", ) # --------------------------------------------------------------------------- # 消息转发(experimental) # --------------------------------------------------------------------------- class ForwardMessageRequest(BaseModel): """转发消息请求(experimental)。""" talker: str = Field(description="源会话对方 wxid") target_display_name: str = Field( description="转发目标联系人的显示名(备注/昵称)" ) source_display_name: Optional[str] = Field( default=None, description="源会话显示名,用于搜索框定位源会话;不传则从 contact.db 解析", ) class ForwardMessageResponse(BaseModel): """转发消息响应。""" success: bool = Field(default=False) error: Optional[str] = Field(default=None, description="失败时的错误描述") verified: Optional[bool] = Field( default=None, description="post_verify 校验结果:True=目标会话出现 type=49 转发消息," "False=超时未检测到,None=未执行校验", )