feat(chat): sync multi-role backend APIs
This commit is contained in:
@@ -0,0 +1,209 @@
|
||||
# CozSweet 多角色聊天前端对接
|
||||
|
||||
## 3. Character IDs
|
||||
|
||||
前端先调用:
|
||||
|
||||
```http
|
||||
GET <API_BASE_URL>/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_BASE_URL>/api/chat/send
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer <TOKEN>
|
||||
```
|
||||
|
||||
### 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 <TOKEN>' \
|
||||
-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_BASE_URL>/api/chat/history?characterId=maya-tan&limit=50&offset=0
|
||||
Authorization: Bearer <TOKEN>
|
||||
```
|
||||
|
||||
| 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": "<MESSAGE_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_BASE_URL>/api/chat/previews
|
||||
Authorization: Bearer <TOKEN>
|
||||
```
|
||||
|
||||
```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_BASE_URL>/api/chat/unlock-private
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer <TOKEN>
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"characterId": "maya-tan",
|
||||
"messageId": "<MESSAGE_ID>",
|
||||
"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_BASE_URL>/api/chat/unlock-history
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer <TOKEN>
|
||||
```
|
||||
|
||||
```json
|
||||
{"characterId":"maya-tan"}
|
||||
```
|
||||
|
||||
费用、锁消息数量、成功解锁数量及 `messageIds` 都只计算当前角色。钱包余额仍是账号全局余额。
|
||||
|
||||
## 9. Guest History Sync
|
||||
|
||||
```http
|
||||
POST <API_BASE_URL>/api/chat/sync
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer <LOGIN_TOKEN>
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"characterId": "maya-tan",
|
||||
"messages": [
|
||||
{"role": "user", "content": "Hello", "timestamp": "2026-07-17T09:00:00Z"},
|
||||
{"role": "assistant", "content": "Hi", "timestamp": "2026-07-17T09:00:01Z"}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
每次同步只能包含一个角色。本地若保存了多个角色,前端按角色分组分别调用。
|
||||
|
||||
若页面使用用户聊天统计,也必须带角色:
|
||||
|
||||
```http
|
||||
GET <API_BASE_URL>/api/user/stats?characterId=maya-tan
|
||||
```
|
||||
|
||||
其中 `totalMessages`、近期记忆、亲密度、情绪和关系状态都按角色返回。
|
||||
响应会明确带上 `characterId`、`relationshipStage` 和 `currentMood`,前端不要把这些状态写回其他角色的本地缓存。
|
||||
|
||||
## 12. Tip Attribution
|
||||
|
||||
只有 Tip 订单使用角色归属:
|
||||
|
||||
```json
|
||||
{
|
||||
"planId": "tip_coffee_usd_4_99",
|
||||
"payChannel": "stripe",
|
||||
"autoRenew": false,
|
||||
"recipientCharacterId": "maya-tan"
|
||||
}
|
||||
```
|
||||
|
||||
Tip 订单必须携带 `recipientCharacterId`。VIP 和积分充值会忽略该字段。
|
||||
|
||||
## 13. Failures
|
||||
|
||||
| HTTP | `detail.errorCode` | Meaning | Frontend action |
|
||||
| ---: | --- | --- | --- |
|
||||
| 403 | `CHARACTER_DISABLED` | 角色或对应能力未开放 | 禁用输入并刷新角色目录 |
|
||||
| 404 | `CHARACTER_NOT_FOUND` | 角色 ID 不存在 | 清理本地旧角色 ID,回角色列表 |
|
||||
| 409 | `CHARACTER_MISMATCH` | 消息或双参数属于不同角色 | 不重试、不扣费,刷新当前角色历史 |
|
||||
| 503 | `CHARACTER_STATE_UNAVAILABLE` | 角色会话状态暂不可用 | 保留输入并稍后重试 |
|
||||
|
||||
新前端的角色业务请求必须显式携带角色 ID。应用入口未指定角色时选择 Elio;显式错误、停用或不匹配的角色不会回退 Elio。
|
||||
Reference in New Issue
Block a user