发消息 前端调: 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