Files
voice_test/README.md
T

125 lines
6.1 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.
# voice_test — 实时 ASR 客服机器人测试台
Chrome 麦克风 → 实时 ASR(可选多模型)→ LLM 客服人设回答 → 下拉选择 TTS 模型、预置/复刻音色并配置语速、语调、音量和表达指令;页面还可录制并下载复刻用 WAV 样本。
## 运行
```bash
source ~/.zshenv # BAILIAN_* 环境变量
go build -o voicetest . && ./voicetest
# 打开 http://localhost:8090 (Chrome,需允许麦克风;仅 localhost/https 可用 getUserMedia)
```
## 可选 ASR 模型
| 模型 | 厂商 | 已验证 |
|---|---|---|
| `qwen-audio-3.0-asr-flash-streaming` | 阿里百炼 | ✅ 支持 continue-task 上下文 |
| `fun-asr-realtime` | 阿里百炼 | ✅ 支持 continue-task 上下文 |
| `fun-asr-flash-2026-06-15` | 阿里百炼 | ✅ 不支持上下文(自动跳过) |
| `volc-bigmodel` (Doubao-Seed-ASR / sauc) | 火山引擎 | ✅ X-Api-Key 新版鉴权 |
火山需要语音技术控制台(非 VOLCENGINE_ACCESS_KEY)的凭证,两种鉴权方式自动适配:
```bash
# 新版控制台(已验证可用):单 APP Key → X-Api-Key
export VOLC_ASR_APP_KEY=...
# 旧版控制台:APP ID + Access Token → X-Api-App-Key + X-Api-Access-Key
export VOLC_ASR_APP_ID=...
export VOLC_ASR_ACCESS_TOKEN=...
export VOLC_ASR_RESOURCE_ID=volc.bigasr.sauc.duration # 2.0 用 volc.seedasr.sauc.duration
```
## 环境变量
| 变量 | 默认 | 说明 |
|---|---|---|
| `BAILIAN_BASE_URL` / `BAILIAN_API_KEY` / `BAILIAN_WSS_BASE_URL` | - | 阿里百炼(zshenv 已有) |
| `BAILIAN_LLM_MODEL` | `qwen3.8-flash` | 客服回答模型(OpenAI 兼容流式) |
| `BAILIAN_TTS_MODEL` | `cosyvoice-v3.5-plus` | 语音合成模型 |
| `BAILIAN_TTS_VOICE` | zshenv 音色 | 默认音色或百炼复刻/设计生成的 `voice_id` |
| `BAILIAN_TTS_INSTRUCTION` | 空 | 默认声音表达指令,网页可覆盖 |
| `BAILIAN_VOICE_API_URL` | DashScope 声音管理接口 | 查询当前账号的复刻/设计音色下拉列表 |
| `PORT` | `:8090` | 监听地址 |
## 已验证的端到端指标(同一句“查询订单发货”,50ms/块推流,句级流式 TTS + 无 thinking)
| 模型 | ASR final | 首 token | 首音频 | 全轮完成 |
|---|---|---|---|---|
| qwen-audio-3.0-asr-flash-streaming | 2.04s | 2.54s | 3.35s | 5.73s |
| fun-asr-realtime | 2.17s | 2.60s | 3.31s | 5.59s |
| fun-asr-flash-2026-06-15 | 1.86s | 2.16s | 2.89s | 5.10s |
| volc-bigmodel (Doubao-Seed-ASR) | 2.60s | 4.29s | 5.18s | 7.84s |
优化前(TTS 等全文 + LLM 默认 thinking):首 token ~4.6s / 首音频 ~5.5s / 全轮 ~8.2s。
两项优化:
1. `enable_thinking: false`(qwen3 默认开思考,纯耗时 +0.5s,非流式实测 1.10s→0.55s)
2. 句级流式 TTS:LLM 出字遇句末标点(。!?;超长退逗号)即切句喂 TTS,不等全文
ASR 尾静音实测:语音结束→final 判定 ≈ 0.5s(qwen 0.6s),`max_end_pausing_time` 参数在该端点不生效(垃圾参数同样延迟,服务端忽略未知参数)。
多轮对话(含 ASR 上下文注入)验证通过:两轮 finals=2 replies=2 无错误(百炼与火山均验证)。
## 结构
- `main.go` — HTTP + `/agent` WS 会话编排(ASR 事件 → LLM 流式 → TTS 流式)
- `asr.go` — provider 接口
- `asr_bailian.go` — 百炼实时识别(run-task/continue-task 文本协议)
- `asr_volc.go` — 火山 sauc bigmodel(二进制帧协议)
- `llm.go` — OpenAI 兼容流式对话 + 客服 system prompt
- `tts.go` — CosyVoice 流式合成(PCM16/16k)
- `voices.go` — TTS 模型、预置音色与百炼复刻音色列表
- `web/index.html` — 测试页(AudioWorklet 采集 PCM16/16k、WAV 样本录制、音量条、双栏转录)
## 已知简化
- 无打断(barge-in):TTS 播报期间 ASR 仍在识别,建议戴耳机测试避免回声。
- 会话历史仅存内存、每连接独立;刷新页面即重置。
## 验证清单
### ✅ 已自动化验证(脚本模拟浏览器客户端,50ms/块推流)
- [x] 百炼 ASR 三模型协议全通:run-task → task-started → 音频流 → finish-task → task-finished
- [x] 识别正确性:同一句“你好,我想查询一下我的订单什么时候发货。”三模型 100% 准确
- [x] LLM `qwen3.8-flash` 流式回答,客服人设生效(口语化、无 markdown、主动要订单号)
- [x] TTS `cosyvoice-v3.5-plus` + zshenv 复刻音色:PCM16/16k 音频正常返回(cosyvoice-v2 会报 418,勿用)
- [x] E2E 指标见上表;多轮对话 finals=2 replies=2 无错误,ASR 上下文注入生效
- [x] `fun-asr-flash` 不支持 continue-task → 已加模型守卫自动跳过
- [x] 火山 sauc 二进制帧协议:新版 X-Api-Key 鉴权、句级 utterance definite 判定 final、负包(flags=2/3)结束,真实凭证 E2E 验证通过(含多轮)
### 👤 需人工在 Chrome 验证
```bash
source ~/.zshenv
cd ~/Workspace/voice_test && go build -o voicetest . && ./voicetest
```
1. [ ] Chrome 打开 `http://localhost:8090`,ASR/TTS 模型及预置/复刻音色均显示为下拉框
2. [ ] 选 `qwen-audio-3.0-asr-flash-streaming` → 🎤 开始 → 授权麦克风
3. [ ] 说“你好,我想查一下我的订单什么时候发货”:
- [ ] 左栏灰色 partial 实时上屏,停顿后固化为 final
- [ ] 延迟数字合理(<2s)
- [ ] 右栏客服回复流式出现
- [ ] 扬声器播出 TTS(建议戴耳机)
4. [ ] 追问“订单号是 12345”:确认多轮上下文生效(回答应引用订单号)
5. [ ] 停止 → 重新开始,切换 `fun-asr-realtime` / `fun-asr-flash-2026-06-15` 重复 3
6. [ ] 点停止后 asr badge 回 idle;服务端日志出现 `ASR started` 而非报错
7. [ ] 点击“录制复刻样本”,录制后可试听并下载单声道 PCM WAV
8. [ ] 火山:选 `volc-bigmodel` 重复 3、4(已自动化验证通过,人工复测语音即可)
### 🧹 清理
```bash
pkill -x voicetest
```
### 边界情况备忘
- 远程机器:SSH 端口转发 `ssh -L 8090:localhost:8090`,浏览器访问 `localhost:8090` 仍是安全上下文,麦克风可用
- 外放会自收音导致 ASR 把 TTS 也转写(无回声消除的浏览器实现依赖耳机)
- 端口冲突:`PORT=:9090 ./voicetest` 可换