diff --git a/docs_simplified.md b/docs_simplified.md new file mode 100644 index 00000000..7d655f9b --- /dev/null +++ b/docs_simplified.md @@ -0,0 +1,146 @@ +发消息 +前端调: +POST /api/chat/send +Authorization: Bearer +Content-Type: application/json +请求体最常用就是: +{ + "message": "给我发图片", + "image": null, + "useWebSocket": false +} +如果是“用户发自己的图片给 AI 看”,先上传图片,再把这些字段带进来: +{ + "message": "你看看这张图", + "imageId": "...", + "imageThumbUrl": "...", + "imageMediumUrl": "...", + "imageOriginalUrl": "...", + "imageWidth": 1080, + "imageHeight": 720, + "useWebSocket": false +} +返回给前端,重点只看这几个字段: +{ + "reply": "回复文本", + "audioUrl": "", + "messageId": "uuid", + "isGuest": true, + "timestamp": 1782281463683, + "image": { + "type": "elio_schedule", + "url": "https://..." + }, + "lockDetail": { + "locked": true, + "showContent": false, + "showUpgrade": true, + "reason": "image_paywall", + "hint": "嗯,你想看我……那就给你看一张。这是我06月15日的照片,你喜欢吗?", + "detail": { + "image": { + "type": "elio_schedule", + "url": "https://..." + } + } + } +} +前端规则很简单: +lockDetail.showContent=true:正常展示 reply、image.url、audioUrl +lockDetail.showContent=false:不要展示真实内容,改成会员引导卡 +lockDetail.showUpgrade=true:显示开会员入口 +也就是说,后端会正常生成内容,前端只靠 lockDetail 决定“显示还是锁住”。 +历史消息 +前端调: +GET /api/chat/history?limit=50&offset=0 +Authorization: Bearer +返回结构: +{ + "messages": [ + { + "role": "user", + "type": "text", + "content": "给我发图片", + "id": "uuid", + "created_at": "2026-06-24T06:13:27.000Z", + "audioUrl": null, + "image": { "type": null, "url": null }, + "lockDetail": { + "locked": false, + "showContent": true, + "showUpgrade": false, + "reason": null, + "hint": null, + "detail": null + } + }, + { + "role": "assistant", + "type": "text", + "content": "嗯,你想看我……那就给你看一张。这是我06月15日的照片,你喜欢吗?", + "id": "uuid", + "created_at": "2026-06-24T06:13:27.000Z", + "audioUrl": null, + "image": { + "type": "elio_schedule", + "url": "https://..." + }, + "lockDetail": { + "locked": true, + "showContent": false, + "showUpgrade": true, + "reason": "image_paywall", + "hint": "嗯,你想看我……那就给你看一张。这是我06月15日的照片,你喜欢吗?", + "detail": { + "image": { + "type": "elio_schedule", + "url": "https://..." + } + } + } + } + ], + "total": 2, + "limit": 50, + "offset": 0, + "isVip": false +} +历史列表也完全按同一套 lockDetail 渲染,不要自己猜 VIP 逻辑。 +看图片 +图片消息统一看这两个位置: +message.image.url +如果被锁,message.lockDetail.detail.image.url +前端建议处理: +先看 lockDetail.showContent +如果 true,直接展示 image.url +如果 false,不要展示真实图,只显示“图片已锁定”的会员引导卡 +也就是: +后端会返回真实图片 +非 VIP 前端不展示 +VIP 或解锁后前端正常展示 + +私密图片 / 私密消息 +现在前端不用区分很多旧字段,只看 lockDetail.reason: +image_paywall:图片锁 +private_message:私密消息锁 +voice_message:语音锁 +daily_limit:免费消息额度用完 +其中“私密图片”本质上也是同一套路子: +后端正常产出内容 +前端收到 lockDetail.showContent=false +前端不展示真实内容 +前端展示会员引导 +如果是 private_message,通常读: +content / reply:后端可能仍会返回 +但前端必须以 lockDetail.showContent 为准 +不要因为拿到了文本就直接渲染 + +前端最简对接结论 +你们只需要统一渲染这几个字段: +文本:content 或 reply +图片:image.url +语音:audioUrl +是否展示:lockDetail.showContent +是否引导会员:lockDetail.showUpgrade +锁类型:lockDetail.reason +引导文案:lockDetail.hint \ No newline at end of file diff --git a/src/stores/chat/chat-state.ts b/src/stores/chat/chat-state.ts index dc2197d1..ad114779 100644 --- a/src/stores/chat/chat-state.ts +++ b/src/stores/chat/chat-state.ts @@ -1,12 +1,3 @@ -/** - * Chat 状态机:State 形状 + 初始值 - * - * `wsConnected: boolean` 仅 VIP 会话期间有意义: - * - VIP + WS 已连 → 消息发送走 WS - * - 非 VIP / 游客 → 不连接 WS,消息走 HTTP - * - `ChatWebSocketConnected` 事件 → true - * - VIP 会话 exit → false(WS actor cleanup 时也会跑 exit) - */ import type { UiMessage } from "@/data/dto/chat"; export interface ChatState {