149 lines
7.4 KiB
Markdown
149 lines
7.4 KiB
Markdown
# voice_test — 实时 ASR 客服机器人测试台
|
||
|
||
Chrome 麦克风 → 实时 ASR(可选多模型)→ LLM 客服人设回答 → 下拉选择 TTS 模型、预置/复刻音色并配置语速、语调、音量和表达指令;页面还可录制并下载复刻用 WAV 样本。
|
||
|
||
## 运行
|
||
|
||
```bash
|
||
cp .env.example .env # 按注释填写百炼/火山凭证及地域地址
|
||
go build -o voicetest . && ./voicetest
|
||
# 程序启动时自动加载当前目录的 .env;系统环境变量优先
|
||
```
|
||
|
||
`.env.example` 已注明 API Key、Workspace ID、复刻音色及火山语音凭证的控制台获取入口;`.env` 已加入 `.gitignore`,不要提交真实密钥。
|
||
|
||
## Chrome 在 HTTP 地址授权麦克风
|
||
|
||
`http://localhost:8090` 默认可以使用麦克风。通过局域网 IP 或域名访问 HTTP 服务时,Chrome 默认禁止 `getUserMedia`,开发测试可这样放行:
|
||
|
||
1. 打开 `chrome://flags/#unsafely-treat-insecure-origin-as-secure`。
|
||
2. 将 **Insecure origins treated as secure** 设置为 **Enabled**。
|
||
3. 填入完整来源,例如 `http://192.168.1.10:8090`,不能省略协议或端口。
|
||
4. 点击 **Relaunch** 重启 Chrome。
|
||
5. 重新打开页面,点击地址栏左侧站点图标 → **网站设置** → **麦克风** → **允许**。
|
||
|
||
也可使用独立测试配置启动 Chrome:
|
||
|
||
```bash
|
||
google-chrome \
|
||
--user-data-dir=/tmp/voice-test-chrome \
|
||
--unsafely-treat-insecure-origin-as-secure=http://192.168.1.10:8090
|
||
```
|
||
|
||
该选项仅用于受信任的开发网络;正式部署应使用 HTTPS。也可以通过 `ssh -L 8090:localhost:8090 user@server` 转发后访问 `http://localhost:8090`,无需放宽 Chrome 安全策略。
|
||
|
||
## 可选 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
|
||
```
|
||
|
||
## 环境变量
|
||
|
||
完整模板与参数获取方式见 [`.env.example`](.env.example)。
|
||
|
||
| 变量 | 默认 | 说明 |
|
||
|---|---|---|
|
||
| `BAILIAN_BASE_URL` / `BAILIAN_API_KEY` / `BAILIAN_WSS_BASE_URL` | - | 阿里百炼地址与 API Key |
|
||
| `BAILIAN_LLM_MODEL` | `qwen3.8-flash` | 客服回答模型(OpenAI 兼容流式) |
|
||
| `BAILIAN_TTS_MODEL` | `cosyvoice-v3.5-plus` | 语音合成模型 |
|
||
| `BAILIAN_TTS_VOICE` | 空 | 默认音色或百炼复刻/设计生成的 `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 模型、预置音色与百炼复刻音色列表
|
||
- `.env.example` — 环境变量模板及各参数获取方式
|
||
- `web/index.html` — 测试页(AudioWorklet 采集 PCM16/16k、WAV 样本录制、音量条、双栏转录)
|
||
|
||
## 已知简化
|
||
|
||
- 打断依赖 ASR 产生 partial 事件;外放回声可能误触发,建议戴耳机测试。
|
||
- 会话历史仅存内存、每连接独立;刷新页面即重置。
|
||
|
||
## 验证清单
|
||
|
||
### ✅ 已自动化验证(脚本模拟浏览器客户端,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` + 百炼复刻音色: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
|
||
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` 可换
|