feat(docs): add simplified API documentation for chat messages
This commit is contained in:
@@ -0,0 +1,146 @@
|
|||||||
|
发消息
|
||||||
|
前端调:
|
||||||
|
POST /api/chat/send
|
||||||
|
Authorization: Bearer <token>
|
||||||
|
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 <token>
|
||||||
|
返回结构:
|
||||||
|
{
|
||||||
|
"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
|
||||||
@@ -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";
|
import type { UiMessage } from "@/data/dto/chat";
|
||||||
|
|
||||||
export interface ChatState {
|
export interface ChatState {
|
||||||
|
|||||||
Reference in New Issue
Block a user