VoxCPM WASM Playground
March 18, 2026 · View on GitHub
这个仓库现在包含一套面向浏览器的 VoxCPM 原型方案,分成三层:
wasm/Emscripten 目标,负责把VoxCPMRuntime + AudioVAE + Tokenizer编译成voxcpm_wasm.js/.wasmweb/packages/voxcpm-web/TypeScript 封装,使用rslib打包web/playground/React + Tailwind + TypeScript + Rsbuild 的浏览器演示页面
设计选择
1. 当前使用 CPU + SIMD + pthread
参考 Emscripten 官方 SIMD 文档:
https://emscripten.org/docs/porting/simd.html
当前方案使用:
-msimd128-pthread-sUSE_PTHREADS=1-sPTHREAD_POOL_SIZE
也就是说它现在是浏览器侧多线程推理方案,结构上参考了 third_party/SenseVoice.wasm。
这要求运行页面具备跨源隔离:
Cross-Origin-Opener-Policy: same-originCross-Origin-Embedder-Policy: require-corp
web/playground 的开发服务器已经加上这两个响应头。生产环境部署时也必须配置。
2. 模型文件与音频持久保存在 OPFS
当前实现会优先把浏览器内的持久化文件系统挂载到 OPFS,并在其下维护:
/persist/models/persist/audio/persist/downloads
远程 GGUF 权重会直接下载到浏览器的文件系统里,而不是写入用户本地磁盘。下载过程中会先写入 .part 临时文件,并尝试通过 Range 请求进行断点续传。
推荐入口:
- Hugging Face 仓库:
https://huggingface.co/bluryar/VoxCPM-GGUF - 镜像直链:
https://hf-mirror.com/bluryar/VoxCPM-GGUF/resolve/main/voxcpm-0.5b-q4_k.gguf
本地选择的 GGUF 文件仍然支持直接导入;远程下载完成后的权重可以从浏览器存储里快速切换加载。生成音频也会自动保存到浏览器文件系统中,文件名默认使用目标文本作为基底。
3. Prompt 音频在 JS 侧解码
浏览器里更适合用 Web Audio API 解码任意用户上传的音频文件,然后把单声道 Float32Array 传给 WASM。这样可以避免在 C++ 里再做一遍浏览器文件格式兼容。
目录说明
scripts/build_wasm.sh使用emcmake构建 wasm 目标,并把生成物输出到web/packages/voxcpm-web/src/wasm/generated/web/packages/voxcpm-web/src/index.tsTS 封装入口,提供VoxCpmSessionweb/playground/src/workers/voxcpm.worker.ts把重型推理放到 Worker,避免阻塞 React 主线程web/playground/src/App.tsx演示 UI,内置 Hugging Face 下载引导、浏览器存储面板和断点续传下载入口
构建步骤
先进入 web workspace:
cd web
先准备依赖:
pnpm install
构建 wasm:
pnpm build:wasm
构建 TS 库:
pnpm build:web
启动 Playground:
pnpm --filter voxcpm-playground dev
当前限制
- 目前只接 CPU backend,没有接 WebGPU
- 浏览器内存压力仍然比较大,更适合
voxcpm-0.5b-q4_k.gguf - 目前导出的是“整段推理后一次性返回音频”,还没有做流式回调