修复 Pipecat 实时链路并补齐网页测试
This commit is contained in:
@@ -28,7 +28,7 @@ app/ 助手本体(部署到服务器)
|
||||
│ ├── stt.py sherpa-onnx 流式 Zipformer(CPU)
|
||||
│ ├── tts.py 本地 vits-zh-ll(sherpa-onnx)
|
||||
│ └── remote_tts.py Qwen3-TTS 远端服务适配(当前主用)
|
||||
└── tests/ 4 个测试,共 88 项断言,全部无需硬件
|
||||
└── tests/ 5 个测试脚本,全部无需硬件
|
||||
|
||||
services/
|
||||
├── tts_server.py Qwen3-TTS 服务(跑在 ~/tts-qwen,独立 venv)
|
||||
@@ -52,6 +52,7 @@ cd ~/ai-companion
|
||||
.venv/bin/python app/tests/test_memory.py # 28 项
|
||||
.venv/bin/python app/tests/test_identity.py # 17 项
|
||||
.venv/bin/python app/tests/test_engine_e2e.py # 16 项,端到端
|
||||
.venv/bin/python app/tests/test_transport.py # 3 项,媒体时钟/VAD/静音判定
|
||||
```
|
||||
|
||||
端到端测试**不需要麦克风、音箱、摄像头、ESP32**——
|
||||
@@ -80,28 +81,32 @@ cd ~/ai-companion
|
||||
**引擎与传输解耦。** 不依赖 Pipecat、不依赖任何传输方式,只依赖四个接口。
|
||||
好处:可以用文件音频端到端测试;接 WebRTC 时只需写薄适配层。
|
||||
|
||||
## 当前卡点:Pipecat 传了但没接上
|
||||
## Pipecat 实时链路:已闭环
|
||||
|
||||
方案文档写"Pipecat 作为唯一会话管线框架",但**代码里它只在 requirements.txt 里**。
|
||||
2026-09-15 复查并修复传输层实验:
|
||||
|
||||
2026-09-15 做了传输层实验(`services/bot_server.py` + `client/test_client.py`):
|
||||
- ✅ 信令、ICE、data channel、双向媒体轨
|
||||
- ✅ `PipelineWorker` 自动 `StartFrame`,自定义 `EngineProcessor` 正常收帧
|
||||
- ✅ 文件音频 → STT → DeepSeek → Qwen3-TTS → WebRTC 非静音回复
|
||||
- ✅ 保留 RTVI 和 `/client/` prebuilt 网页客户端,并提供其需要的 `/start` 入口
|
||||
|
||||
- ✅ **传输层跑通**:信令、ICE、data channel、双向媒体轨
|
||||
- ❌ **帧路由未通**:自定义处理器的 `process_frame` 调用次数为 0,
|
||||
连自己注入的 StartFrame 都没进去;引擎从未运行
|
||||
原来的“`process_frame` 调用次数为 0”并非管线接线或模型不兼容。真实根因是
|
||||
Pipecat 启动预热 NLTK `punkt_tab` 时发生运行时下载,20 秒 setup 超时,worker
|
||||
尚未发送 `StartFrame` 就退出。数据预装后帧路由正常,因此确定采用 A 方案:
|
||||
Pipecat 管传输、帧与 RTVI,自有 `ConversationEngine` 管会话语义。
|
||||
|
||||
现象是"连接全对、音轨协商成功、但助手永远不说话,且日志里一条错误都没有"。
|
||||
自写客户端另有两处测试缺陷也已修复:文件结束后的静音帧没有推进 PTS,导致 VAD
|
||||
收不到 700ms 尾静音;接收端又把 WebRTC 自动静音误判为回复。现在成功条件是收到
|
||||
非静音语音,并按实际 WebRTC 采样率保存 WAV。
|
||||
|
||||
**这直接影响 A/B 架构方案**:A 是"Pipecat 只做传输、逻辑归自有引擎",
|
||||
B 是"按 Pipecat 的 service 模型重构"。帧送不进自定义处理器,
|
||||
说明 A 的核心假设不是开箱即用的。
|
||||
|
||||
根因未定位,两种可能必须区分:接线错误(接缝浅,A 可行)
|
||||
vs 模型不兼容(接缝深,应转 B)。
|
||||
2026-09-16 又通过 SSH 隧道用 `/client/` 做了真人浏览器测试:补齐 Playground
|
||||
要求的 `/start` 后,麦克风 → STT → LLM → TTS → 浏览器播放正常,单轮服务端指标
|
||||
约 3.0 秒。这个页面是调试工具而非产品 UI;当前连接期间由 VAD 检出每段话后都会
|
||||
响应,**尚无唤醒门控**。正式唤醒仍按方案放在 P2 的 N5095 本地端,待机时不上传音频。
|
||||
|
||||
完整记录见代码仓库外的 `P0-Pipecat传输层实验报告.md`(在 Obsidian 笔记库里)。
|
||||
|
||||
### 实验挖出的 8 个坑
|
||||
### 实验挖出的 10 个坑
|
||||
|
||||
每个都表现为"什么都没发生",极难排查:
|
||||
|
||||
@@ -109,10 +114,12 @@ vs 模型不兼容(接缝深,应转 B)。
|
||||
2. 客户端必须建 data channel 并定期发 `"ping"`,否则服务端一帧音频都不推
|
||||
3. offer 里没有媒体时 aiortc **完全不收集 ICE 候选**(连连通性测试都要加静音轨)
|
||||
4. ICE 收集完成前发 offer → SDP 里 0 个候选地址
|
||||
5. `PipelineTask.run()` 要 `WorkerParams(task_manager=...)`,不是 `PipelineParams`
|
||||
5. `PipelineWorker.run()` 要 `WorkerParams(task_manager=...)`,不是 `PipelineParams`
|
||||
6. `TaskManager()` 必须在事件循环内创建
|
||||
7. **后台任务里的异常被静默吞掉**,日志里查不到
|
||||
8. 信令回调里必须 `create_task`,不能 `await task.run()`
|
||||
9. Pipecat 会预热 NLTK `punkt_tab`;生产部署必须预装,不能在首个会话临时下载
|
||||
10. `PipelineWorker` 自动发送 `StartFrame`,手工再发会造成重复启动帧
|
||||
|
||||
## 踩过的坑
|
||||
|
||||
|
||||
Reference in New Issue
Block a user