# CozSweet 多角色聊天前端对接 ## 3. Character IDs 前端先调用: ```http GET /api/characters?capability=chat ``` 聊天业务统一使用响应里的 `items[].id`。当前规范 ID 是: ```text elio maya-tan nayeli-cervantes ``` 只允许传递角色目录响应中的 `items[].id`,不要传展示名或 `@handle`。 角色响应中的 `capabilities` 是后端权威开关。`chat=false` 时不得开放输入框;直接调用聊天接口会得到 `CHARACTER_DISABLED`,不会返回 Elio 历史。 ## 4. Send Message ### Request URL ```http POST /api/chat/send Content-Type: application/json Authorization: Bearer ``` ### Parameters | Field | Type | Required | Example | Meaning | | --- | --- | --- | --- | --- | | `characterId` | string | 新前端必传 | `maya-tan` | 当前聊天角色 ID | | `message` | string | 与图片至少一项有值 | `Hello Maya` | 用户文本,最多 4000 字符 | | `imageId` | string | 否 | `abc123` | 上传图片 ID | | `imageThumbUrl` | string | 否 | `/images/...` | 缩略图 | | `imageMediumUrl` | string | 否 | `/images/...` | 模型识图使用 | | `imageOriginalUrl` | string | 否 | `/images/...` | 原图 | | `imageWidth` | integer | 否 | `1080` | 图片宽 | | `imageHeight` | integer | 否 | `1440` | 图片高 | | `useWebSocket` | boolean | 否 | `false` | 是否同时通过已连接 WS 推送 | ```bash curl -X POST 'https://proapi.banlv-ai.com/api/chat/send' \ -H 'Authorization: Bearer ' \ -H 'Content-Type: application/json' \ -d '{"characterId":"maya-tan","message":"Hello Maya","useWebSocket":false}' ``` 响应沿用现有发送结构。前端仍读取 `data.reply`、`data.messageId`、`data.audioUrl`、`data.image` 和 `data.lockDetail`,无需从响应推断角色。 ## 5. Chat History ```http GET /api/chat/history?characterId=maya-tan&limit=50&offset=0 Authorization: Bearer ``` | Query | Type | Required | Rule | | --- | --- | --- | --- | | `characterId` | string | 新前端必传 | 只返回该角色数据 | | `limit` | integer | 否 | `1-200`,默认 `50` | | `offset` | integer | 否 | 最小 `0` | `messages` 和 `total` 都只统计指定角色。切换角色时必须重新请求 history,不能复用上一个角色的本地数组。 ```json { "code": 200, "success": true, "message": "success", "data": { "messages": [ { "role": "user", "type": "text", "content": "Hello Maya", "id": "", "created_at": "2026-07-17T09:00:00Z", "audioUrl": null, "image": {"type": null, "url": null}, "lockDetail": {"locked": false, "showContent": true, "showUpgrade": false} } ], "total": 1, "limit": 50, "offset": 0, "isVip": false } } ``` ## 6. Latest Previews 角色会话列表可一次请求所有可聊天角色的最后一条消息: ```http GET /api/chat/previews Authorization: Bearer ``` ```json { "code": 200, "success": true, "data": { "items": [ {"characterId": "elio", "message": {"id": "...", "role": "assistant", "type": "text", "content": "..."}}, {"characterId": "maya-tan", "message": null} ] } } ``` 锁定私密文本不会泄露内容,锁定语音不会返回 `audioUrl`(文字仍正常返回)。图片沿用现有协议,URL 可以存在;前端必须以 `lockDetail.locked=true` 覆盖展示,不能把“URL 非空”当作已解锁。 ## 7. Unlock One Message ```http POST /api/chat/unlock-private Content-Type: application/json Authorization: Bearer ``` ```json { "characterId": "maya-tan", "messageId": "", "lockType": "voice_message", "clientLockId": "maya-card-001" } ``` `messageId` 存在时,后端会核对消息角色。拿 Elio 的 `messageId` 配 Maya 的 `characterId` 会返回 HTTP `409 / CHARACTER_MISMATCH`,且不会扣积分。 前端临时伪造锁卡片没有 `messageId` 时,仍传 `characterId + lockType + clientLockId`。`clientLockId` 的幂等查找范围已包含账号和角色,同一个 ID 可以在不同角色下分别使用。 ## 8. Unlock Current Character History ```http POST /api/chat/unlock-history Content-Type: application/json Authorization: Bearer ``` ```json {"characterId":"maya-tan"} ``` 费用、锁消息数量、成功解锁数量及 `messageIds` 都只计算当前角色。钱包余额仍是账号全局余额。 ## 12. Tip Attribution 只有 Tip 订单使用角色归属: ```json { "planId": "tip_coffee_usd_4_99", "payChannel": "stripe", "autoRenew": false, "recipientCharacterId": "maya-tan" } ``` Tip 订单必须携带 `recipientCharacterId`。VIP 和积分充值会忽略该字段。