2026-07-08 23:25:58 +08:00
|
|
|
|
"""朋友圈域模型:发表朋友圈 / 分享公众号文章到朋友圈。"""
|
|
|
|
|
|
|
|
|
|
|
|
from __future__ import annotations
|
|
|
|
|
|
|
|
|
|
|
|
from typing import Optional
|
|
|
|
|
|
|
|
|
|
|
|
from pydantic import BaseModel, Field
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
# 朋友圈接口(POST /api/moments/publish)
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
class MomentPublishRequest(BaseModel):
|
|
|
|
|
|
"""发表朋友圈请求(纯文字)。
|
|
|
|
|
|
|
|
|
|
|
|
MVP 仅支持纯文字朋友圈。图片朋友圈涉及文件选择器交互,留给后续。
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
|
content: str = Field(description="朋友圈文字内容")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class MomentPublishResponse(BaseModel):
|
|
|
|
|
|
"""发表朋友圈响应。
|
|
|
|
|
|
|
|
|
|
|
|
字段说明:
|
|
|
|
|
|
- local_moment_id:bridge 本地生成的朋友圈发表 ID,格式
|
|
|
|
|
|
moment_<unix秒>_<随机>。仅用于客户端幂等去重,不对应微信原生
|
|
|
|
|
|
朋友圈 ID。
|
|
|
|
|
|
- placeholder:恒为 false(真实执行 UI 发表操作,非占位)。
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
|
success: bool = Field(default=False)
|
|
|
|
|
|
local_moment_id: str = Field(default="", description="本地生成的朋友圈发表 ID")
|
|
|
|
|
|
placeholder: bool = Field(default=False, description="是否为占位实现(恒为 false)")
|
|
|
|
|
|
error: Optional[str] = Field(default=None, description="失败时的错误描述")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class MomentShareArticleRequest(BaseModel):
|
|
|
|
|
|
"""分享公众号文章到朋友圈请求。
|
|
|
|
|
|
|
|
|
|
|
|
通过搜索公众号名称进入会话,点击第 N 篇推送文章卡片打开文章页,
|
|
|
|
|
|
再经「分享到朋友圈」UI 路径生成带卡片预览的朋友圈。
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
|
public_account: str = Field(
|
|
|
|
|
|
description="公众号名称或 wxid,用于搜索定位公众号会话"
|
|
|
|
|
|
)
|
|
|
|
|
|
article_index: int = Field(
|
|
|
|
|
|
default=1,
|
|
|
|
|
|
description="从会话顶部往下的第几篇推送文章卡片,默认 1(最新一篇)",
|
|
|
|
|
|
)
|
|
|
|
|
|
comment: Optional[str] = Field(
|
|
|
|
|
|
default=None,
|
|
|
|
|
|
description="可选:分享时附带的「说点什么」评论文字,不传则跳过",
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class MomentShareArticleResponse(BaseModel):
|
|
|
|
|
|
"""分享公众号文章到朋友圈响应。
|
|
|
|
|
|
|
|
|
|
|
|
字段说明:
|
|
|
|
|
|
- local_moment_id:bridge 本地生成的分享 ID,格式
|
|
|
|
|
|
share_<unix秒>_<随机>。仅用于客户端幂等去重。
|
|
|
|
|
|
- placeholder:恒为 false(真实执行 UI 分享操作,非占位)。
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
|
success: bool = Field(default=False)
|
|
|
|
|
|
local_moment_id: str = Field(default="", description="本地生成的分享 ID")
|
|
|
|
|
|
placeholder: bool = Field(default=False, description="是否为占位实现(恒为 false)")
|
|
|
|
|
|
error: Optional[str] = Field(default=None, description="失败时的错误描述")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
# 朋友圈时间线(GET /api/moments/timeline)
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
class MomentItem(BaseModel):
|
|
|
|
|
|
"""单条朋友圈。"""
|
|
|
|
|
|
|
|
|
|
|
|
moment_id: str = Field(description="朋友圈 ID")
|
|
|
|
|
|
content: str = Field(default="", description="文字内容")
|
|
|
|
|
|
create_time: int = Field(description="发布时间戳(Unix 秒)")
|
|
|
|
|
|
author_wxid: str = Field(default="", description="发布者 wxid")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class MomentsTimelineResponse(BaseModel):
|
|
|
|
|
|
"""朋友圈时间线响应。
|
|
|
|
|
|
|
|
|
|
|
|
status 字段说明(因 WeChat 4.x 朋友圈 schema 未公开,需容错探测):
|
|
|
|
|
|
- ok:正常读取
|
|
|
|
|
|
- db_not_found:未找到朋友圈 DB 文件
|
|
|
|
|
|
- table_not_found:DB 存在但无朋友圈表
|
|
|
|
|
|
- db_encrypted:DB 加密且无法解密
|
|
|
|
|
|
- no_time_column / no_columns / query_error:探测/查询失败
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
|
moments: list[MomentItem] = Field(default_factory=list)
|
|
|
|
|
|
next_cursor: int = Field(description="下次拉取应使用的 cursor")
|
|
|
|
|
|
has_more: bool = Field(default=False, description="是否可能还有更多")
|
|
|
|
|
|
status: str = Field(default="", description="探测/查询状态码")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
# 朋友圈互动(experimental)
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
class MomentLikeRequest(BaseModel):
|
|
|
|
|
|
"""朋友圈点赞请求(experimental)。"""
|
|
|
|
|
|
|
|
|
|
|
|
moment_index: int = Field(default=1, description="朋友圈序号,1=最新")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class MomentLikeResponse(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=截图 absdiff 检测到点赞位置像素变化,"
|
|
|
|
|
|
"False=未检测到变化,None=未执行校验",
|
|
|
|
|
|
)
|
2026-07-08 23:25:58 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class MomentCommentRequest(BaseModel):
|
|
|
|
|
|
"""朋友圈评论请求(experimental)。"""
|
|
|
|
|
|
|
|
|
|
|
|
comment: str = Field(description="评论文字内容")
|
|
|
|
|
|
moment_index: int = Field(default=1, description="朋友圈序号,1=最新")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class MomentCommentResponse(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=MomentsComment 表出现新评论或截图检测到变化,"
|
|
|
|
|
|
"False=未检测到,None=未执行校验",
|
|
|
|
|
|
)
|
2026-07-08 23:25:58 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class MomentDeleteRequest(BaseModel):
|
|
|
|
|
|
"""删除朋友圈请求(experimental)。"""
|
|
|
|
|
|
|
|
|
|
|
|
moment_index: int = Field(default=1, description="朋友圈序号,1=最新")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class MomentDeleteResponse(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=MomentsPost 表对应记录已删除,"
|
|
|
|
|
|
"False=记录仍存在,None=未执行校验",
|
|
|
|
|
|
)
|
2026-07-08 23:25:58 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class MomentPublishImageRequest(BaseModel):
|
|
|
|
|
|
"""发表图片朋友圈请求(experimental)。"""
|
|
|
|
|
|
|
|
|
|
|
|
image_path: str = Field(description="图片文件容器内绝对路径")
|
|
|
|
|
|
content: str = Field(default="", description="可选文字内容")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class MomentPublishImageResponse(BaseModel):
|
|
|
|
|
|
"""发表图片朋友圈响应。"""
|
|
|
|
|
|
|
|
|
|
|
|
success: bool = Field(default=False)
|
|
|
|
|
|
local_moment_id: str = Field(default="", description="本地生成的朋友圈 ID")
|
|
|
|
|
|
placeholder: bool = Field(default=False, description="是否为占位实现(恒为 false)")
|
|
|
|
|
|
error: Optional[str] = Field(default=None, description="失败时的错误描述")
|