159 lines
5.5 KiB
Markdown
159 lines
5.5 KiB
Markdown
# 语音对话接口交互文档
|
||
|
||
本文档详细描述了前端 `webUI` 与后端 `server` 之间关于语音对话功能(`/voice-chat`)的交互流程、参数传递及返回值结构。
|
||
|
||
## 1. 概述
|
||
|
||
语音对话功能允许用户录制一段语音,前端将其上传至后端。后端依次执行以下操作:
|
||
1. **STT (Speech-to-Text)**:将语音转换为文本。
|
||
2. **LLM (Large Language Model)**:将识别出的文本作为输入,获取 AI 的文本回复。
|
||
3. **TTS (Text-to-Speech)**:将 AI 的文本回复转换为语音。
|
||
|
||
最终,后端将用户识别文本、AI 回复文本及合成的语音数据一次性返回给前端。
|
||
|
||
## 2. 前端调用 (WebUI)
|
||
|
||
前端主要涉及的文件为 `webUI/src/components/ChatBox.vue` 和 `webUI/src/utils/api.js`。
|
||
|
||
### 2.1 调用方式
|
||
|
||
在 `ChatBox.vue` 中,当用户完成录音后,调用 `handleVoiceModeMessage` 方法,进而调用 `voiceAPI.voiceChat`。
|
||
|
||
底层通过 `uni.uploadFile` 发起 `multipart/form-data` 类型的 POST 请求。
|
||
|
||
### 2.2 请求参数
|
||
|
||
前端向后端发送的请求包含 **文件** 和 **表单数据 (FormData)**。
|
||
|
||
* **URL**: `/api/chat/voice-chat` (由 `config.js` 中的 `VOICE_CHAT` 常量定义)
|
||
* **Method**: `POST`
|
||
* **Header**: `Authorization: Bearer <token>`
|
||
* **文件部分**:
|
||
* `name`: `"audio"`
|
||
* `filePath`: 录音文件的本地路径 (e.g., `.aac` 或 `.wav`)
|
||
|
||
* **表单数据 (FormData)**:
|
||
|
||
| 参数名 | 类型 | 必填 | 说明 | 来源 |
|
||
| :--- | :--- | :--- | :--- | :--- |
|
||
| `sessionId` | String | 否 | 会话 ID,用于保持上下文 | `conversationId.value` |
|
||
| `modelId` | Integer | 否 | 模型 ID | `characterConfig.modelId` |
|
||
| `templateId` | Integer | 否 | 模板 ID | `characterConfig.templateId` |
|
||
| `voiceStyle` | String | 否 | 语音风格 (用于 TTS) | `options.voiceStyle` |
|
||
| `ttsConfigId` | Integer | 否 | TTS 配置 ID | `aiConfig.ttsId` |
|
||
| `sttConfigId` | Integer | 否 | STT 配置 ID | `aiConfig.sttId` |
|
||
| `useFunctionCall` | Boolean | 否 | 是否使用函数调用 | 默认为 `false` |
|
||
|
||
### 2.3 响应处理
|
||
|
||
前端接收到后端返回的 JSON 数据后,进行如下解析:
|
||
|
||
1. **用户文本**: 从 `sttResult.text` 获取,显示在聊天界面右侧。
|
||
2. **AI 回复**: 从 `llmResult.response` 获取,显示在聊天界面左侧。
|
||
3. **语音播放**: 优先使用 `ttsResult.audioBase64` (Base64 编码音频),如果没有则使用 `ttsResult.audioPath` (音频 URL) 进行播放。
|
||
|
||
---
|
||
|
||
## 3. 后端处理 (Server)
|
||
|
||
后端入口为 `server/src/main/java/com/xiaozhi/controller/ChatController.java`,核心逻辑在 `ChatSessionServiceImpl.java`。
|
||
|
||
### 3.1 接口定义
|
||
|
||
* **Controller**: `ChatController`
|
||
* **Path**: `/api/chat/voice-chat`
|
||
* **Consumes**: `multipart/form-data`
|
||
|
||
### 3.2 处理流程
|
||
|
||
1. **接收文件**: 后端支持字段名为 `audioFile`, `file`, 或 `audio` 的文件上传 (前端使用 `audio`)。
|
||
2. **参数解析**: 解析 `sessionId`, `modelId` 等参数。
|
||
3. **文件验证**: 检查文件大小 (1KB - 50MB)、格式 (支持 mp3, wav, m4a, aac 等) 和 MIME 类型。
|
||
4. **音频处理**:
|
||
* 将上传的音频文件保存为临时文件。
|
||
* 使用 `AudioUtils` 将音频转换为 **PCM 16k 单声道** 格式(适配 STT 引擎)。
|
||
5. **业务逻辑 (`ChatSessionService.voiceChat`)**:
|
||
* **STT**: 调用配置的 STT 服务识别语音,得到 `recognizedText`。
|
||
* **LLM**: 如果识别到文本,调用 `syncChat` 获取 AI 回复 `chatResponse`。
|
||
* **TTS**: 调用 TTS 服务将 AI 回复转换为语音,生成音频文件并读取为 Base64。
|
||
6. **结果封装**: 将 STT、LLM、TTS 的结果封装到 Map 中返回。
|
||
|
||
---
|
||
|
||
## 4. 接口规范
|
||
|
||
### 4.1 请求结构
|
||
|
||
**POST** `/api/chat/voice-chat`
|
||
**Content-Type**: `multipart/form-data`
|
||
|
||
**Body**:
|
||
* `audio`: [二进制文件数据]
|
||
* `sessionId`: "session_12345"
|
||
* `modelId`: 10
|
||
* `templateId`: 6
|
||
* ...
|
||
|
||
### 4.2 响应结构
|
||
|
||
**Content-Type**: `application/json`
|
||
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"message": "语音对话成功",
|
||
"data": {
|
||
"sessionId": "session_12345",
|
||
"timestamp": 1717660000000,
|
||
|
||
// 1. STT 结果
|
||
"sttResult": {
|
||
"text": "你好,请介绍一下你自己。", // 用户语音识别结果
|
||
"audioSize": 32000,
|
||
"sttProvider": "vosk"
|
||
},
|
||
|
||
// 2. LLM 结果
|
||
"llmResult": {
|
||
"response": "你好!我是蔚AI,很高兴为你服务。", // AI 回复文本
|
||
"inputText": "你好,请介绍一下你自己。"
|
||
},
|
||
|
||
// 3. TTS 结果
|
||
"ttsResult": {
|
||
"audioBase64": "UklGRi...", // Base64 编码的音频数据 (用于直接播放)
|
||
"audioPath": "audio/output/...", // 服务器音频文件路径
|
||
"timestamp": 1717660005000
|
||
},
|
||
|
||
// 性能统计 (耗时: ms)
|
||
"sttDuration": 500,
|
||
"llmDuration": 1200,
|
||
"ttsDuration": 800,
|
||
|
||
// 文件元数据
|
||
"originalFileName": "temp_audio.aac",
|
||
"fileSize": 15000,
|
||
"contentType": "audio/aac",
|
||
"description": null
|
||
}
|
||
}
|
||
```
|
||
|
||
### 4.3 错误响应
|
||
|
||
```json
|
||
{
|
||
"code": 400, // 或 500
|
||
"message": "请求参数错误: 音频文件不能为空",
|
||
"data": null
|
||
}
|
||
```
|
||
|
||
## 5. 总结
|
||
|
||
* **交互模式**: 同步一次性交互。前端发送音频,等待后端完成所有处理(识别+对话+合成)后,一次性接收所有数据。
|
||
* **音频格式**: 前端通常录制 `aac` 或 `wav`,后端统一转码为 `pcm` 进行处理。
|
||
* **回退机制**: 如果后端处理失败,前端 `ChatBox.vue` 会捕获异常并提示用户,或使用本地模拟回复(在未登录等特定情况下)。
|
||
|