rtc-voice-chat/java-mock/API-FULL.md
2026-04-02 20:15:15 +08:00

756 lines
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# java-mock 接口文档 & 数据设计
> Base URL: `http://localhost:8080`
>
> 认证方式: JWT Bearer Token除登录/注册外,所有接口均需在请求头附加 `Authorization: Bearer <token>`
---
## 目录
- [接口总览](#接口总览)
- [一、认证接口](#一认证接口)
- [1.1 登录](#11-登录)
- [1.2 注册](#12-注册)
- [1.3 获取当前用户信息](#13-获取当前用户信息)
- [二、AI 代理接口(转发 Python](#二ai-代理接口转发-python)
- [2.1 获取场景列表](#21-获取场景列表)
- [2.2 开始语音对话](#22-开始语音对话)
- [2.3 停止语音对话](#23-停止语音对话)
- [2.4 写入历史上下文](#24-写入历史上下文)
- [三、对话记录接口](#三对话记录接口)
- [3.1 保存对话](#31-保存对话)
- [3.2 对话列表(分页)](#32-对话列表分页)
- [3.3 对话详情](#33-对话详情)
- [3.4 追加消息](#34-追加消息)
- [3.5 删除对话](#35-删除对话)
- [四、其他](#四其他)
- [4.1 健康检查](#41-健康检查)
- [数据结构设计](#数据结构设计)
- [User用户表](#user用户表)
- [Conversation对话表](#conversation对话表)
- [Message消息子文档](#message消息子文档)
- [内部转发签名协议](#内部转发签名协议)
- [通用错误响应](#通用错误响应)
- [环境变量](#环境变量)
---
## 接口总览
| 方法 | 路径 | 是否需要 Token | 说明 |
|---|---|---|---|
| GET | `/health` | 否 | 健康检查 |
| POST | `/api/auth/login` | 否 | 登录 |
| POST | `/api/auth/register` | 否 | 注册 |
| GET | `/api/auth/me` | ✅ | 获取当前用户信息 |
| POST | `/api/ai/getScenes` | ✅ | 获取场景列表(转发 Python |
| POST | `/api/ai/proxy?Action=StartVoiceChat` | ✅ | 开始语音对话(转发 Python |
| POST | `/api/ai/proxy?Action=StopVoiceChat` | ✅ | 停止语音对话(转发 Python |
| POST | `/api/ai/session/history` | ✅ | 写入历史上下文(转发 Python |
| POST | `/api/ai/conversations` | ✅ | 保存对话记录 |
| GET | `/api/ai/conversations` | ✅ | 对话列表(分页) |
| GET | `/api/ai/conversations/:id` | ✅ | 对话详情 |
| POST | `/api/ai/conversations/:id/append` | ✅ | 追加消息到对话 |
| DELETE | `/api/ai/conversations/:id` | ✅ | 删除对话 |
---
## 一、认证接口
### 1.1 登录
```
POST /api/auth/login
```
**请求体JSON**
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| username | string | ✅ | 用户名 |
| password | string | ✅ | 密码(明文) |
**请求示例:**
```json
{
"username": "admin",
"password": "admin123"
}
```
**成功响应 200**
```json
{
"code": 200,
"data": {
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"name": "管理员",
"sex": "male",
"isDriver": false,
"deptId": 1,
"deptName": "办公室",
"roleList": ["admin", "user"]
}
}
```
**失败响应:**
| HTTP 状态码 | code | message |
|---|---|---|
| 400 | 400 | 用户名和密码不能为空 |
| 401 | 401 | 用户名或密码错误 |
---
### 1.2 注册
```
POST /api/auth/register
```
**请求体JSON**
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| username | string | ✅ | 用户名(唯一) |
| password | string | ✅ | 密码(明文) |
| nickname | string | ❌ | 昵称,不传时默认等于 username |
**请求示例:**
```json
{
"username": "newuser",
"password": "pass123",
"nickname": "新用户"
}
```
**成功响应 200**
```json
{
"code": 200,
"data": {
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"name": "新用户",
"sex": "unknown",
"isDriver": false,
"deptId": 0,
"deptName": "",
"roleList": ["user"]
}
}
```
**失败响应:**
| HTTP 状态码 | code | message |
|---|---|---|
| 400 | 400 | 用户名和密码不能为空 |
| 409 | 409 | 用户名已存在 |
> 注册成功后新用户默认属性:`sex=unknown`、`isDriver=false`、`deptId=0`、`roleList=["user"]`
---
### 1.3 获取当前用户信息
```
GET /api/auth/me
```
**成功响应 200**
```json
{
"code": 200,
"data": {
"name": "管理员",
"sex": "male",
"isDriver": false,
"deptId": 1,
"deptName": "办公室",
"roleList": ["admin", "user"]
}
}
```
**失败响应:**
| HTTP 状态码 | code | message |
|---|---|---|
| 401 | 401 | 未提供 Authorization Token |
| 401 | 401 | Token 无效或已过期 |
| 404 | 404 | 用户不存在 |
---
## 二、AI 代理接口(转发 Python
> 所有 AI 代理接口均带 HMAC-SHA256 内部签名后转发至 Python 后端(`PYTHON_BACKEND_URL`),响应内容原样透传。
>
> 详细签名规则见 [内部转发签名协议](#内部转发签名协议)。
---
### 2.1 获取场景列表
```
POST /api/ai/getScenes
```
**请求体:** `{}` 或空
**成功响应Python 原样返回):**
```json
{
"ResponseMetadata": {
"Action": "getScenes"
},
"Result": {
"scenes": [
{
"scene": {
"id": "Custom",
"botName": "BotUser001",
"isInterruptMode": true,
"isVision": false,
"isScreenMode": false,
"isAvatarScene": false,
"avatarBgUrl": null
},
"rtc": {
"AppId": "6xxxxxxx",
"RoomId": "room-abc123",
"UserId": "user-xyz",
"Token": "AQBhMGI3Zm...",
"TaskId": "task-001"
}
}
]
}
}
```
---
### 2.2 开始语音对话
```
POST /api/ai/proxy?Action=StartVoiceChat
```
**请求体JSON**
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| SceneID | string | ✅ | 场景 ID从 getScenes 获取) |
**请求示例:**
```json
{
"SceneID": "Custom"
}
```
**成功响应Python 原样返回):**
```json
{
"ResponseMetadata": {
"RequestId": "2024xxxxxxxxxx",
"Action": "StartVoiceChat",
"Version": "2024-12-01",
"Service": "rtc"
},
"Result": {
"Message": "success"
}
}
```
---
### 2.3 停止语音对话
```
POST /api/ai/proxy?Action=StopVoiceChat
```
**请求体JSON**
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| SceneID | string | ✅ | 场景 ID |
**请求示例:**
```json
{
"SceneID": "Custom"
}
```
**成功响应Python 原样返回):**
```json
{
"ResponseMetadata": {
"RequestId": "2024xxxxxxxxxx",
"Action": "StopVoiceChat",
"Version": "2024-12-01",
"Service": "rtc"
},
"Result": {
"Message": "success"
}
}
```
---
### 2.4 写入历史上下文
> 在 StartVoiceChat 之前调用,将历史对话上下文注入 Python Session以便 AI 延续上下文。
```
POST /api/ai/session/history
```
**请求体JSON**
转发到 Python `/api/session/history`,具体字段由 Python 接口定义,典型示例:
```json
{
"roomId": "room-abc123",
"history": [
{ "role": "user", "content": "你好" },
{ "role": "assistant", "content": "你好!有什么可以帮你?" }
]
}
```
**成功响应:** Python 原样返回
---
## 三、对话记录接口
### 3.1 保存对话
```
POST /api/ai/conversations
```
**请求体JSON**
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| sceneId | string | ✅ | 场景 ID |
| roomId | string | ❌ | RTC 房间 ID |
| messages | array | ✅ | 消息数组(见下表) |
**messages 数组每条消息字段:**
| 字段 | 类型 | 说明 |
|---|---|---|
| role | string | `"user"``"assistant"`(优先使用) |
| content | string | 消息文本 |
| time | string | ISO 时间戳,不传取服务器当前时间 |
| userId | string | 兼容旧格式。与当前登录用户 ID 相同则视为 `user`,否则视为 `assistant` |
| text | string | 兼容旧格式,与 `content` 二选一 |
**请求示例:**
```json
{
"sceneId": "Custom",
"roomId": "room-abc123",
"messages": [
{ "role": "assistant", "content": "你好,我是小块", "time": "2026-04-02T10:00:00Z" },
{ "role": "user", "content": "今天出勤情况咋样", "time": "2026-04-02T10:00:05Z" },
{ "role": "assistant", "content": "今天出勤率 90%", "time": "2026-04-02T10:00:08Z" }
]
}
```
**成功响应 200**
```json
{
"code": 200,
"data": {
"sessionId": "9864c5ef-cdee-4c35-8f6a-81a9a4f6d323"
}
}
```
**失败响应:**
| HTTP 状态码 | code | message |
|---|---|---|
| 400 | 400 | sceneId 和 messages 不能为空 |
---
### 3.2 对话列表(分页)
```
GET /api/ai/conversations?page=1&size=20
```
**Query 参数:**
| 字段 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| page | number | 1 | 页码(从 1 开始) |
| size | number | 20 | 每页条数(上限 100 |
**成功响应 200**
```json
{
"code": 200,
"data": {
"total": 5,
"page": 1,
"size": 20,
"list": [
{
"id": "9864c5ef-cdee-4c35-8f6a-81a9a4f6d323",
"sceneId": "Custom",
"roomId": "room-abc123",
"startedAt": "2026-04-02T10:00:00Z",
"endedAt": "2026-04-02T10:00:08Z",
"messageCount": 3,
"firstMessage": "今天出勤情况咋样"
}
]
}
}
```
> - 列表按 `createdAt` **倒序**排列
> - `firstMessage` 取第一条 `role === "user"` 的消息内容,无用户消息时为空串
> - 仅返回**当前登录用户**的对话记录
---
### 3.3 对话详情
```
GET /api/ai/conversations/:id
```
**Path 参数:**
| 字段 | 说明 |
|---|---|
| id | 对话 UUID |
**成功响应 200**
```json
{
"code": 200,
"data": {
"id": "9864c5ef-cdee-4c35-8f6a-81a9a4f6d323",
"userId": "user-admin-001",
"sceneId": "Custom",
"roomId": "room-abc123",
"startedAt": "2026-04-02T10:00:00Z",
"endedAt": "2026-04-02T10:00:08Z",
"createdAt": "2026-04-02T10:00:10Z",
"messages": [
{ "role": "assistant", "content": "你好,我是小块", "createdAt": "2026-04-02T10:00:00Z" },
{ "role": "user", "content": "今天出勤情况咋样", "createdAt": "2026-04-02T10:00:05Z" },
{ "role": "assistant", "content": "今天出勤率 90%", "createdAt": "2026-04-02T10:00:08Z" }
]
}
}
```
**失败响应:**
| HTTP 状态码 | code | message |
|---|---|---|
| 404 | 404 | 对话记录不存在 |
| 403 | 403 | 无权访问该对话 |
---
### 3.4 追加消息
> 对话保存后如需继续追加消息(例如语音会话延续),调用此接口。
```
POST /api/ai/conversations/:id/append
```
**Path 参数:**
| 字段 | 说明 |
|---|---|
| id | 对话 UUID |
**请求体JSON**
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| messages | array | ✅ | 追加的消息数组,格式同 3.1 |
**请求示例:**
```json
{
"messages": [
{ "role": "user", "content": "那明天呢", "time": "2026-04-02T10:01:00Z" },
{ "role": "assistant", "content": "明天是周末,无需考勤", "time": "2026-04-02T10:01:03Z" }
]
}
```
**成功响应 200**
```json
{
"code": 200,
"data": {
"sessionId": "9864c5ef-cdee-4c35-8f6a-81a9a4f6d323"
}
}
```
**失败响应:**
| HTTP 状态码 | code | message |
|---|---|---|
| 400 | 400 | messages 不能为空 |
| 404 | 404 | 对话记录不存在 |
| 403 | 403 | 无权操作该对话 |
---
### 3.5 删除对话
```
DELETE /api/ai/conversations/:id
```
**Path 参数:**
| 字段 | 说明 |
|---|---|
| id | 对话 UUID |
**成功响应 200**
```json
{
"code": 200,
"data": null
}
```
**失败响应:**
| HTTP 状态码 | code | message |
|---|---|---|
| 404 | 404 | 对话记录不存在 |
| 403 | 403 | 无权删除该对话 |
---
## 四、其他
### 4.1 健康检查
```
GET /health
```
**响应(无需 Token**
```json
{
"status": "ok",
"service": "java-mock",
"timestamp": "2026-04-02T10:00:00.000Z"
}
```
---
## 数据结构设计
### User用户表
> 文件存储路径:`data/users.json`(数组)
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| id | string | ✅ | 唯一 ID格式 `user-<uuid>``user-admin-001`(内置账号) |
| username | string | ✅ | 登录用户名,全局唯一 |
| password | string | ✅ | 明文密码Mock 环境,生产请改用 bcrypt 哈希) |
| name | string | ✅ | 显示名 / 昵称 |
| sex | string | ✅ | 性别:`"male"` / `"female"` / `"unknown"` |
| isDriver | boolean | ✅ | 是否为司机角色 |
| deptId | number | ✅ | 部门 ID`0` 表示无部门 |
| deptName | string | ✅ | 部门名称 |
| roleList | string[] | ✅ | 角色列表,如 `["admin","user"]` / `["user"]` |
| createdAt | string | ✅ | 创建时间 ISO8601 |
**示例数据:**
```json
[
{
"id": "user-admin-001",
"username": "admin",
"password": "admin123",
"name": "管理员",
"sex": "male",
"isDriver": false,
"deptId": 1,
"deptName": "办公室",
"roleList": ["admin", "user"],
"createdAt": "2026-01-01T00:00:00.000Z"
},
{
"id": "user-001",
"username": "user1",
"password": "user123",
"name": "测试用户",
"sex": "female",
"isDriver": false,
"deptId": 2,
"deptName": "工程部",
"roleList": ["user"],
"createdAt": "2026-01-01T00:00:00.000Z"
}
]
```
---
### Conversation对话表
> 文件存储路径:`data/conversations.json`(数组)
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| id | string | ✅ | UUID v4全局唯一 |
| userId | string | ✅ | 所属用户 ID关联 User.id |
| sceneId | string | ✅ | 场景 ID`"Custom"` |
| roomId | string | ✅ | RTC 房间 ID无则为空串 |
| startedAt | string | ✅ | 对话开始时间(取第一条消息 `createdAt` |
| endedAt | string | ✅ | 对话结束时间(取最后一条消息 `createdAt` |
| createdAt | string | ✅ | 记录入库时间 |
| messages | Message[] | ✅ | 消息数组(见 Message 结构) |
**示例数据:**
```json
{
"id": "85ce1273-7279-44fb-b018-3e49295c89f7",
"userId": "user-admin-001",
"sceneId": "Custom",
"roomId": "4fea87af-5b23-445d-9754-d4d878a1c705",
"startedAt": "2026-04-02T05:06:57.828Z",
"endedAt": "2026-04-02T05:07:18.750Z",
"createdAt": "2026-04-02T05:07:28.729Z",
"messages": [...]
}
```
---
### Message消息子文档
> 嵌套在 Conversation.messages 数组中
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| role | string | ✅ | `"user"`(用户说)或 `"assistant"`AI 说) |
| content | string | ✅ | 消息文本内容 |
| createdAt | string | ✅ | 消息时间 ISO8601 |
**示例:**
```json
[
{ "role": "assistant", "content": "你好,我是小块,有什么需要帮忙的吗?", "createdAt": "2026-04-02T05:06:57.828Z" },
{ "role": "user", "content": "今天办公室出勤情况咋样", "createdAt": "2026-04-02T05:07:12.023Z" },
{ "role": "assistant", "content": "今天办公室一共九个人,出勤率 90%。", "createdAt": "2026-04-02T05:07:18.750Z" }
]
```
---
## 内部转发签名协议
> 转发到 Python 时java-mock 会附加以下请求头Python 侧需验证签名合法性。
| Header | 说明 |
|---|---|
| `X-Internal-Service` | 固定值 `java-gateway` |
| `X-Internal-User-Id` | 当前登录用户 ID |
| `X-Internal-Timestamp` | 毫秒级 Unix 时间戳(字符串) |
| `X-Internal-Signature` | HMAC-SHA256 签名,见下方算法 |
| `X-User-Name` | URL 编码的用户显示名 |
| `X-User-Sex` | 性别字符串 |
| `X-User-Is-Driver` | `"true"``"false"` |
| `X-User-Dept-Id` | 部门 ID 字符串 |
| `X-User-Dept-Name` | URL 编码的部门名称 |
| `X-User-Role-List` | URL 编码的 JSON 数组字符串,如 `%5B%22admin%22%5D` |
**签名算法:**
```
message = "java-gateway:{userId}:{timestamp}"
signature = HMAC-SHA256(INTERNAL_SERVICE_SECRET, message) // hex 输出
```
---
## 通用错误响应
所有接口在出错时均返回如下结构:
```json
{
"code": <HTTP状态码>,
"message": "错误描述"
}
```
| code | 含义 |
|---|---|
| 400 | 请求参数缺失或格式错误 |
| 401 | 未登录或 Token 无效 / 过期 |
| 403 | 无权限访问该资源 |
| 404 | 资源不存在 |
| 409 | 资源冲突(如用户名重复) |
| 502 | 无法连接 Python 后端 |
| 500 | 服务器内部错误 |
---
## 环境变量
| 变量名 | 默认值 | 说明 |
|---|---|---|
| `PORT` | `8080` | 服务监听端口 |
| `JWT_SECRET` | — | JWT 签名密钥(**必填** |
| `JWT_EXPIRES_IN` | `7d` | JWT 过期时间 |
| `PYTHON_BACKEND_URL` | `http://localhost:3001` | Python 后端地址 |
| `INTERNAL_SERVICE_SECRET` | — | 内部签名密钥(**必填** |