88 lines
7.4 KiB
Markdown
88 lines
7.4 KiB
Markdown
|
|
# Demo 说话人链路修复与验收
|
|||
|
|
|
|||
|
|
本次仅修改 `demo/`。参考原 `app/services/qwen3_websocket_asr.py` 的前滚音频、同句异步说话人更新和结束提交方式,保留独立 vLLM ASR + 辅助声纹服务 + WebSocket 三个进程。当前机器没有显卡,验证采用模拟模型,真实声纹准确率和模型加载状态需在部署机器上验收。
|
|||
|
|
|
|||
|
|
## 已确认的代码问题
|
|||
|
|
|
|||
|
|
1. 页面只处理 `sentences`,忽略已实现的 `display_state`,因此后端合并结果没有展示。未知片段还会临时附在上一位已确认说话人的气泡里。
|
|||
|
|
2. 页面点击停止后 5 秒强制断开,但辅助 HTTP 请求的超时是 45 秒,可能截掉迟到的声纹更新。
|
|||
|
|
3. 无 embedding、低置信度、协议字段不完整等情况被静默丢弃,用户无法区分等待、短音频、服务错误和证据拒绝。
|
|||
|
|
4. 旧声纹长度检查把句尾 800ms 静音一起计算,可能让短插话通过长度要求;WAV 固定去掉 44 字节也会破坏带额外元数据的输入。
|
|||
|
|
5. 仅 vLLM 启动器加载 `demo/.env`,另两个进程没有加载;`0.6b` 下载别名也可能被直接当作公开模型名发送。
|
|||
|
|
|
|||
|
|
这些是代码中可复现的问题,不能据此断言部署中的声纹模型一定已经正常加载。新版本将具体原因直接显示在片段气泡和日志里。
|
|||
|
|
|
|||
|
|
## 修复后的行为
|
|||
|
|
|
|||
|
|
- partial/final 和声纹更新继续使用同一 `sentence_id`。页面显示完整聚合快照,过时的 `revision` 不覆盖新快照。
|
|||
|
|
- 仅合并相邻且身份可信的片段。未知短插话独立显示;A→B→A 保留顺序。不同实名或实名与弱匿名身份不会因为簇 ID 相同而合并。
|
|||
|
|
- 每条声纹证据必须来自当前片段;同步、异步两种入口都拒绝 `short_attach` / `embedding_attach`。不复制上一段 embedding。声纹向量拒绝零向量、NaN、Infinity 和多样本矩阵。
|
|||
|
|
- WebSocket 以有效有声帧判断长度。少于 800ms 的语音保持 pending;800ms~1.6s 也必须独立提取特征,不能直接继承前一位身份。该长度门槛属于保守保护,不能保证短样本识别准确率。
|
|||
|
|
- 保留 200ms 前滚,提交时去除尾部静音。增量解析 WAV 的 RIFF/fmt/data/JUNK 等头,拒绝非 16kHz 单声道 PCM16 文件。
|
|||
|
|
- `stop/eof` 返回 `draining`,排空 ASR 和声纹队列后才发送最终快照及 `end`。声纹失败不阻断 ASR。abort、断线、异常和正常结束均清理聚类会话。
|
|||
|
|
- ASR worker 异常会立即发送 `error`,不会一直等待客户端停止。
|
|||
|
|
|
|||
|
|
## 如何判断卡在哪里
|
|||
|
|
|
|||
|
|
页面顶部显示已确认数量;未匹配到说话人的气泡统一显示“未知说话人”,详细等待或失败原因通过标签悬停提示和原始日志查看。原始日志保留 `speaker_status`、`speaker_reason`、`speaker_strategy` 和置信度。
|
|||
|
|
|
|||
|
|
| `speaker_status` | 含义与排查方向 |
|
|||
|
|
|---|---|
|
|||
|
|
| `waiting_final` | 讲话仍在进行,等待静音或最大时长切段 |
|
|||
|
|
| `queued` / `processing` | 文本已完成,声纹正在排队或推理 |
|
|||
|
|
| `confirmed` | 当前片段声纹已确认,应该显示说话人标签 |
|
|||
|
|
| `insufficient_audio` | 有效语音过短,不继承上一位;使用较长发言复测 |
|
|||
|
|
| `service_unavailable` / `service_error` | 未配置、无法访问或模型推理失败;检查辅助服务及完整错误 |
|
|||
|
|
| `no_embedding` | 服务没有产生可用特征 |
|
|||
|
|
| `evidence_rejected` | 缺少 fresh/confirmed 证据、置信度不足或使用了继承策略 |
|
|||
|
|
| `disabled` | 本次未开启说话人分离 |
|
|||
|
|
|
|||
|
|
健康检查为 `http://辅助服务器:8010/health`。新版本有 `speaker_protocol_version: 2`,重点检查 `speaker_embedding_ready` 与 `speaker_embedding_model`。若没有版本字段,检查是否重启了更新后的辅助进程。HTTP 健康检查不执行真实声纹推理,不能代替音频验收。
|
|||
|
|
|
|||
|
|
辅助服务目前返回匿名的“说话人 1、2……”;demo 没有接入原应用的声纹注册库,因此不会自动识别人员实名。vLLM 仅输出转写文本,声纹标签由 `scripts/auxiliary_server.py` 负责。
|
|||
|
|
|
|||
|
|
模型职责要区分:`iic/speech_campplus_sv_zh-cn_16k-common` 是实时 turn 的 CAM++ embedding 模型,必须加载;`iic/speech_campplus_speaker-diarization_common` 是完整音频分离 pipeline,包含额外的 change locator/VAD 依赖,当前实时 WebSocket 不在启动阶段调用它。WebSocket 自身仍用轻量 RMS 帧门控切句,辅助服务的 FunASR VAD 对外提供 `/v1/vad`,并供完整 diarization 依赖使用;因此启动辅助服务是为了 CAM++ 声纹和聚类,不能把整段 diarization 的加载失败误认为 vLLM 失败。
|
|||
|
|
|
|||
|
|
## 部署后操作
|
|||
|
|
|
|||
|
|
在部署机更新这些文件后,已有 vLLM 可继续运行。重新安装增补的 `python-dotenv` 依赖,并重启辅助服务及 WebSocket。辅助服务启动时强制依赖 VAD + CAM++ `speaker_verification`;完整 CAM++ diarization 不再阻断实时启动;以下命令都从 `demo/` 目录执行:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
pip install -r requirements-auxiliary.txt
|
|||
|
|
pip install -r realtime_asr_optimization_demo/requirements.txt
|
|||
|
|
python scripts/auxiliary_server.py
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
如果仍提示核心模型缺失或加载失败,日志会列出模型 ID、实际查找路径、状态和底层异常。先执行 `python scripts/download_models.py --auxiliary-only`,或设置 `.env` 的 `MODEL_DIR` 指向同时包含 `damo/speech_fsmn_vad_zh-cn-16k-common-pytorch` 与 `iic/speech_campplus_sv_zh-cn_16k-common` 的目录。不要用 `AUXILIARY_ALLOW_MISSING=true` 掩盖 VAD/CAM++ 核心模型缺失;该选项只适合临时查看可选模型状态。
|
|||
|
|
|
|||
|
|
另一个终端执行:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
python realtime_asr_optimization_demo/server.py --no-browser
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
三个进程现在均读取 `demo/.env`,系统环境变量优先。确认 `MODEL_SERVICE_URL` 指向现有 vLLM 的 `/v1`,`AUXILIARY_SERVICE_URL` 指向辅助服务。`QWEN3_ASR_MODEL` 支持部署清单别名,设置 `VLLM_SERVED_MODEL_NAME` 时优先使用该公开名称。更新后刷新浏览器;脚本 URL 已更新版本号。
|
|||
|
|
|
|||
|
|
`127.0.0.1` 指各 Python 服务运行的机器,不是浏览器所在机器。跨服务器部署时填写对应服务器 IP。浏览器麦克风访问远程页面需要安全上下文(HTTPS);本机 localhost 可用于测试。
|
|||
|
|
|
|||
|
|
## 验收顺序
|
|||
|
|
|
|||
|
|
1. 单人讲话 2~4 秒后停顿:先出现文本,随后同句变为“说话人 1”。
|
|||
|
|
2. 同一人再次讲话并停顿:确认后相邻块应合并;取消页面“合并相邻”可对照物理片段。
|
|||
|
|
3. A→B→A,各说 2 秒以上:应保持三个时间顺序块。标签准确率需要真实声纹模型验证。
|
|||
|
|
4. A 后 B 说一个很短的“嗯”:应显示“有效语音不足”,不能进入 A 的气泡。
|
|||
|
|
5. 辅助服务关闭时测试:ASR 仍完成,片段明确显示服务错误。
|
|||
|
|
6. 讲话中点击停止:等待最终结果,不能在五秒时丢失说话人更新。
|
|||
|
|
|
|||
|
|
无显卡回归命令:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
cd demo
|
|||
|
|
python -m unittest discover -s tests -v
|
|||
|
|
cd realtime_asr_optimization_demo
|
|||
|
|
python -m unittest discover -s tests -v
|
|||
|
|
node --test tests/test_frontend.cjs
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
这些测试覆盖状态机、模拟 HTTP/WebSocket、延迟更新、前端脚本和有效向量校验,不执行模型下载或 GPU 推理。当前 VLLM 适配器仍是 HTTP 累积窗口 partial,`native_partial_supported=false`;本次没有把 HTTP 接口包装成原生增量模型状态。单个内部片段中无停顿的多人换话或重叠讲话仍需真实模型和更细粒度切段验证。
|