2026-07-08 23:25:58 +08:00
|
|
|
|
"""发送域模型:发送文本 / 发送文件 / 发送响应。"""
|
|
|
|
|
|
|
|
|
|
|
|
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 查找",
|
|
|
|
|
|
)
|
2026-07-16 01:19:47 +08:00
|
|
|
|
client_request_id: str = Field(default="", description="客户端幂等去重 ID,空字符串表示不参与幂等校验")
|
2026-07-08 23:25:58 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class SendFileRequest(BaseModel):
|
|
|
|
|
|
"""发送图片/文件请求。"""
|
|
|
|
|
|
|
|
|
|
|
|
to_wxid: str = Field(description="目标 wxid")
|
|
|
|
|
|
file_path: str = Field(description="容器内文件绝对路径")
|
|
|
|
|
|
display_name: Optional[str] = Field(
|
|
|
|
|
|
default=None,
|
|
|
|
|
|
description="可选:用于微信搜索框定位会话的显示名。不传时 bridge 自动按备注->昵称->wxid 查找",
|
|
|
|
|
|
)
|
2026-07-16 16:53:42 +08:00
|
|
|
|
client_request_id: Optional[str] = Field(
|
|
|
|
|
|
default=None,
|
|
|
|
|
|
description="可选:客户端幂等去重 ID,None 或空字符串表示不参与幂等校验",
|
|
|
|
|
|
)
|
2026-07-08 23:25:58 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class SendResponse(BaseModel):
|
|
|
|
|
|
"""发送消息响应。
|
|
|
|
|
|
|
|
|
|
|
|
字段说明:
|
|
|
|
|
|
- local_send_id:bridge 本地生成的发送 ID,格式 local_<unix秒>_<随机>。
|
|
|
|
|
|
仅用于客户端幂等去重,**不对应微信原生 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="失败时的错误描述")
|
2026-07-16 01:19:47 +08:00
|
|
|
|
verified: bool = Field(default=False, description="是否已通过发送结果验证")
|
|
|
|
|
|
skipped: bool = Field(default=False, description="是否因幂等去重被跳过")
|
2026-07-08 23:25:58 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
# 消息撤回(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="失败时的错误描述")
|
2026-07-16 16:53:42 +08:00
|
|
|
|
verified: Optional[bool] = Field(
|
|
|
|
|
|
default=None,
|
|
|
|
|
|
description="post_verify 校验结果:True=已确认撤回标记写入 DB,"
|
|
|
|
|
|
"False=超时未检测到,None=未执行校验(DB 不可用或未接入)",
|
|
|
|
|
|
)
|
2026-07-08 23:25:58 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
# 消息转发(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="失败时的错误描述")
|
2026-07-16 16:53:42 +08:00
|
|
|
|
verified: Optional[bool] = Field(
|
|
|
|
|
|
default=None,
|
|
|
|
|
|
description="post_verify 校验结果:True=目标会话出现 type=49 转发消息,"
|
|
|
|
|
|
"False=超时未检测到,None=未执行校验",
|
|
|
|
|
|
)
|