J.B-Lin commited on
Commit
36bb211
·
2 Parent(s): a3f130a2ce3e61

Merge branch 'main' of https://huggingface.co/spaces/build-small-hackathon/PregoPal

Browse files
docs/技术调研_与并行工作路径.md ADDED
@@ -0,0 +1,277 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # 技术调研 & 并行工作方案:MiniCPM-o 全双工语音升级(路线 A)
2
+
3
+ > 日期:2026-06-10
4
+ > 状态:技术调研完成,方案待 agent 执行
5
+ > 参考来源:MiniCPM-V-Cookbook(llama.cpp 部署 + llama.cpp-omni 全双工语音)
6
+
7
+ ---
8
+
9
+ ## 一、当前状态速查
10
+
11
+ | 项目 | 值 |
12
+ |------|-----|
13
+ | API URL | `https://andrew-jiabin--prego-pal-minicpm-serve.modal.run` |
14
+ | GPU | T4 (16GB VRAM) |
15
+ | 运行时 | **llama-cpp-python** (预编译 wheel, CUDA 12.1) |
16
+ | 模型 | MiniCPM-o-4_5-Q4_K_M.gguf (~5GB) + vision mmproj |
17
+ | 音频 | **不支持**(仅挂载了 vision mmproj) |
18
+ | 端点 | `/v1/chat/completions`, `/v1/embeddings`, `/v1/vision`(冗余) |
19
+
20
+ ## 二、核心发现:为什么当前架构不支持全双工语音
21
+
22
+ ### 2.1 软件层限制
23
+
24
+ ```
25
+ 当前架构:
26
+ Modal ASGI → llama-cpp-python (Python binding)
27
+ └── ggml-org/llama.cpp 主线
28
+ └── mmproj= 只支持单个投影层 (vision)
29
+ └── 无 audio mmproj 参数
30
+ └── 无 token2wav 集成
31
+ └── 无 WebRTC 实时流
32
+ ```
33
+
34
+ | 能力 | 当前 (`llama-cpp-python`) | 需要的 (`llama.cpp-omni`) |
35
+ |------|--------------------------|---------------------------|
36
+ | 同时加载 vision + audio + tts mmproj | ❌ 只支持 1 个 | ✅ 支持多个 |
37
+ | 全双工实时语音 (`CPP_MODE=duplex`) | ❌ | ✅ WebRTC 原语 |
38
+ | TTS 端点 `/v1/audio/speech` | ❌ | ✅ OpenAI 兼容 |
39
+ | 流式语音输出 (streaming WAV) | ❌ | ✅ |
40
+ | 声音克隆 (voice cloning) | ❌ | ✅ |
41
+ | 语音 token 识别 (S2T) | ❌ | ✅ |
42
+
43
+ ### 2.2 VRAM 预算——T4 16GB 完全够用
44
+
45
+ | 组件 | 文件 | 大小 |
46
+ |------|------|------|
47
+ | 主模型 (LLM) | `MiniCPM-o-4_5-Q4_K_M.gguf` | ~5.0 GB |
48
+ | 视觉投影层 | `vision/MiniCPM-o-4_5-vision-F16.gguf` | ~1.1 GB |
49
+ | 音频投影层 (S2T) | `audio/MiniCPM-o-4_5-audio-F16.gguf` | ~0.6 GB |
50
+ | TTS 模型 | `tts/MiniCPM-o-4_5-tts-F16.gguf` | ~1.1 GB |
51
+ | 声学投影层 | `tts/MiniCPM-o-4_5-projector-F16.gguf` | ~14 MB |
52
+ | Token2Wav | encoder + flow + hifigan2 + cache 共 4 文件 | ~0.9 GB |
53
+ | KV Cache (8K ctx) | 运行时 | ~1.5 GB |
54
+ | **总计** | | **~10.2 GB** |
55
+
56
+ **结论:T4 16GB 跑全双工语音 + 视觉 + 文本完全可行,还剩 ~5.8GB 余量。**
57
+
58
+ ---
59
+
60
+ ## 三、升级路线:从 llama-cpp-python → llama.cpp-omni
61
+
62
+ ### 3.1 架构变化
63
+
64
+ ```
65
+ 升级前:
66
+ FastAPI ←→ llama-cpp-python (Python binding, 单 mmproj)
67
+
68
+ 升级后:
69
+ FastAPI ←→ subprocess: llama-server (OpenBMB/llama.cpp-omni, 多 mmproj + token2wav)
70
+ ├── -m Q4_K_M.gguf (主模型)
71
+ ├── --mmproj vision.gguf (视觉)
72
+ ├── --mmproj audio.gguf (音频, S2T)
73
+ ├── --voxcpm2-base-lm tts.gguf (TTS)
74
+ ├── --voxcpm2-acoustic projector.gguf (声学投影)
75
+ └── token2wav/ (encoder + flow + hifigan2 + cache)
76
+ ```
77
+
78
+ ### 3.2 新增端点
79
+
80
+ | 端点 | 方法 | 功能 |
81
+ |------|------|------|
82
+ | `/v1/chat/completions` | POST | 文本 + 多模态(图片/音频),支持 streaming |
83
+ | `/v1/audio/speech` | POST | TTS:文本 → 语音 WAV/PCM |
84
+ | `/v1/audio/speech/stream` | POST | 流式 TTS |
85
+ | `/v1/audio/transcriptions` | POST | STT:语音 → 文本(需 audio mmproj 挂载后可用) |
86
+ | `/v1/embeddings` | POST | 文本嵌入 |
87
+ | `/v1/models` | GET | 模型列表 |
88
+ | `/health` | GET | 健康检查(含音视频组件状态) |
89
+ | `/v1/voxcpm2/init` | POST | 动态加载/切换 TTS 模型 |
90
+
91
+ ### 3.3 全双工流程
92
+
93
+ ```
94
+ 浏览器/客户端 Modal (T4)
95
+ │ │
96
+ │── WebRTC offer ──────────────────→│
97
+ │←─ WebRTC answer ──────────────────│
98
+ │ │
99
+ │── Opus 音频帧 ───────────────────→│ llama.cpp-omni
100
+ │ │ ├── audio mmproj: 语音 → 文本
101
+ │ │ ├── LLM: 推理
102
+ │ │ └── token2wav: 文本 → 语音
103
+ │←─ Opus 音频帧 ────────────────────│
104
+ │ │
105
+ │── 图片/文字 ─────────────────────→│ vision mmproj + LLM
106
+ │←─ 文本/语音 ──────────────────────│
107
+ ```
108
+
109
+ ---
110
+
111
+ ## 四、并行工作方案(可分给多个 agent)
112
+
113
+ ### Agent 1(你):编译 & 部署 llama.cpp-omni 到 Modal
114
+
115
+ **文件:`modal_deploy/deploy_omni.py`**(新建,不动现有 `deploy.py`)
116
+
117
+ #### 步骤:
118
+
119
+ 1. **修改 Docker 镜像**:从 `pip install llama-cpp-python` → 在 Image 中 `git clone OpenBMB/llama.cpp-omni && cmake && make`
120
+ ```python
121
+ _omni_image = (
122
+ Image.debian_slim(python_version="3.11")
123
+ .apt_install("curl", "git", "build-essential", "cmake", "libcurl4-openssl-dev",
124
+ "libsndfile1", "libasound2-dev")
125
+ .pip_install("fastapi", "uvicorn[standard]", "httpx", "numpy", "Pillow", "soundfile")
126
+ .run_commands(
127
+ "git clone --depth 1 https://github.com/OpenBMB/llama.cpp-omni /llama.cpp-omni",
128
+ "cd /llama.cpp-omni && cmake -B build -DGGML_CUDA=ON -DCMAKE_BUILD_TYPE=Release",
129
+ "cd /llama.cpp-omni && cmake --build build -j$(nproc) --target llama-server llama-mtmd-cli",
130
+ )
131
+ )
132
+ ```
133
+
134
+ 2. **新增 `serve_omni()` ASGI 函数**:
135
+ - 启动 `llama-server` 子进程:
136
+ ```bash
137
+ /llama.cpp-omni/build/bin/llama-server \
138
+ -m /models/MiniCPM-o-4_5-gguf/MiniCPM-o-4_5-Q4_K_M.gguf \
139
+ --mmproj /models/MiniCPM-o-4_5-gguf/vision/MiniCPM-o-4_5-vision-F16.gguf \
140
+ --mmproj /models/MiniCPM-o-4_5-gguf/audio/MiniCPM-o-4_5-audio-F16.gguf \
141
+ --voxcpm2-base-lm /models/MiniCPM-o-4_5-gguf/tts/MiniCPM-o-4_5-tts-F16.gguf \
142
+ --voxcpm2-acoustic /models/MiniCPM-o-4_5-gguf/tts/MiniCPM-o-4_5-projector-F16.gguf \
143
+ --host 127.0.0.1 --port 8081 \
144
+ -ngl 99 -c 8192 \
145
+ --no-mmap \
146
+ --jinja \
147
+ --reasoning-budget -1
148
+ ```
149
+ - FastAPI 代理 `llama-server`(纯文本/嵌入直接转发,多模态构造标准 OpenAl content 格式)
150
+ - 健康检查包含音视频组件状态验证
151
+
152
+ 3. **Volume 确认**:验证 Volume 中是否有所有必需文件(vision, audio, tts, token2wav-gguf)
153
+
154
+ 4. **测试**:
155
+ - `modal run modal_deploy.deploy_omni::test_inference` → 文本 + 图片理解
156
+ - `modal run modal_deploy.deploy_omni::test_audio` → TTS 生成
157
+ - `modal run modal_deploy.deploy_omni::test_multimodal` → 图片+文本联合
158
+
159
+ 5. **部署**:`modal deploy modal_deploy.deploy_omni`
160
+
161
+ #### 关键踩坑提醒:
162
+
163
+ | 坑 | 解决方案 |
164
+ |----|---------|
165
+ | CMake 找不到 CUDA | Modal T4 已有 CUDA 驱动,cmake -DGGML_CUDA=ON 即可 |
166
+ | `libcurl4-openssl-dev` 必须安装 | 否则 LLAMA_CURL=ON 编译失败 |
167
+ | `llama-server` 的 `--mmproj` 可以传多次 | vision + audio 各传一次 |
168
+ | `--no-mmap` 必需 | Modal tmpfs 不支持 mmap |
169
+ | token2wav 文件需要放在模型目录的 `token2wav-gguf/` 子目录 | llama-server 自动查找 |
170
+ | 编译时间 ~10-15 分钟 | 首次 deploy 后 Docker 层缓存,下次热更新 < 1min |
171
+
172
+ ---
173
+
174
+ ### Agent 2:升级客户端 `client.py` 支持全双工语音
175
+
176
+ **文件:`modal_deploy/client.py`**(修改现有文件)
177
+
178
+ #### 改动:
179
+
180
+ 1. **修复 bug**:`describe_image()` 第 157 行 `result.get("response", ...)` → `result["choices"][0]["message"]["content"]`
181
+ 2. **新增 TTS 方法**:
182
+ ```python
183
+ def text_to_speech(self, text, voice="default", stream=False) -> bytes:
184
+ """TTS: 文本 → WAV 音频字节"""
185
+ ```
186
+ 3. **新增 STT 方法**:
187
+ ```python
188
+ def speech_to_text(self, audio_bytes, audio_format="wav") -> str:
189
+ """STT: 音频 → 文本"""
190
+ ```
191
+ 注意:STT 需要确认 llama.cpp-omni 的 `/v1/audio/transcriptions` 端点是否可用(需 audio mmproj)
192
+ 4. **新增全双工对话方法**(如果需要 WebRTC 前端集成):
193
+ ```python
194
+ def duplex_chat(self, audio_stream, ...) -> AsyncGenerator:
195
+ """全双工:边说边听,返回音频流"""
196
+ ```
197
+
198
+ ---
199
+
200
+ ### Agent 3:确认 Volume 模型文件 & 补传
201
+
202
+ **检查清单**:
203
+
204
+ ```bash
205
+ # 确认 Volume 中有哪些文件
206
+ modal volume ls minicpm-o-4_5-models /MiniCPM-o-4_5-gguf
207
+
208
+ # 必需的全部文件:
209
+ # ✅ MiniCPM-o-4_5-Q4_K_M.gguf
210
+ # ✅ vision/MiniCPM-o-4_5-vision-F16.gguf
211
+ # ✅ audio/MiniCPM-o-4_5-audio-F16.gguf
212
+ # ✅ tts/MiniCPM-o-4_5-tts-F16.gguf
213
+ # ✅ tts/MiniCPM-o-4_5-projector-F16.gguf
214
+ # ✅ token2wav-gguf/encoder.gguf
215
+ # ✅ token2wav-gguf/flow_extra.gguf
216
+ # ✅ token2wav-gguf/flow_matching.gguf
217
+ # ✅ token2wav-gguf/hifigan2.gguf
218
+ # ✅ token2wav-gguf/prompt_cache.gguf
219
+ ```
220
+
221
+ **缺失文件补传**:
222
+ ```bash
223
+ modal volume put minicpm-o-4_5-models \
224
+ ./models/MiniCPM-o-4_5-gguf/audio /MiniCPM-o-4_5-gguf/audio
225
+
226
+ modal volume put minicpm-o-4_5-models \
227
+ ./models/MiniCPM-o-4_5-gguf/tts /MiniCPM-o-4_5-gguf/tts
228
+
229
+ modal volume put minicpm-o-4_5-models \
230
+ ./models/MiniCPM-o-4_5-gguf/token2wav-gguf /MiniCPM-o-4_5-gguf/token2wav-gguf
231
+ ```
232
+
233
+ ---
234
+
235
+ ### Agent 4:docs & README 更新
236
+
237
+ **文件:`README.md` §11**(更新端点表、部署架构)
238
+
239
+ **文件新建:`docs/API接口规范_v3_全双工.md`**(完整 API 文档)
240
+
241
+ ---
242
+
243
+ ## 五、时间估算
244
+
245
+ | 阶段 | 预估时间 | 并行? |
246
+ |------|---------|-------|
247
+ | Agent 3: Volume 文件检查 & 补传 | 10-30 min | ✅ 可立即开始 |
248
+ | Agent 1: 编译 llama.cpp-omni 镜像 | 15-30 min | ✅ 可与 Agent 3 并行 |
249
+ | Agent 1: 写 `deploy_omni.py` | 30-60 min | 等待编译完成后 |
250
+ | Agent 1: 测试文本+视觉+TTS | 10-20 min | |
251
+ | Agent 2: ��级 `client.py` | 15-30 min | ✅ 可与 Agent 1 并行 |
252
+ | Agent 4: 写文档 | 15-20 min | ✅ 可与 Agent 1 并行 |
253
+ | Agent 1: `modal deploy` | 5-10 min | |
254
+ | **总计(并行后)** | **~1-1.5 小时** | |
255
+
256
+ ---
257
+
258
+ ## 六、风险 & 备用方案
259
+
260
+ | 风险 | 概率 | 影响 | 缓解 |
261
+ |------|------|------|------|
262
+ | `llama.cpp-omni` 的 multi-mmproj 同时加载 audio+vision+TTS 在 T4 上 OOM | 低 | 高 | 可先只启用 vision+TTS,audio 后续加 |
263
+ | token2wav 子目录问题导致 TTS 不工作 | 中 | 中 | 先确认路径结构,Cookbook 有明确说明 |
264
+ | WebRTC 集成复杂度过高 | 高 | 中 | 黑客松先做非 WebRTC 版本(普通 HTTP TTS+STT),全双工后续迭代 |
265
+ | 编译耗时过长导致冷启动慢 | 中 | 低 | Docker 层缓存;容器 keep_warm 参数 |
266
+
267
+ ---
268
+
269
+ ## 七、立即可以开始的并行任务
270
+
271
+ 1. **Agent 3**(无需等待):立即 `modal volume ls` 检查模型文件完整性
272
+ 2. **Agent 2**(独立):立即修复 `client.py` 的 `describe_image()` bug + 新增 TTS/STT 方法
273
+ 3. **Agent 1**(本 agent):`deploy_omni.py` 编写 + `modal deploy`
274
+
275
+ ---
276
+
277
+ *文档生成时间:2026-06-10 | 由 PregoPal Cline (deploy agent) 编写*