The README still listed the settings UI as "todo" and its quick start told users to download models into the working directory; phase 3 still described the caption window's close button as "quit" and used the wrong binary name. Bring the docs up to date and fill the gaps: a GUI guide (first run, settings tabs, tray, download, verify), a full CLI option reference marking the test-only flags, a troubleshooting page, the model registry's size/sha256 fields plus a licence/size table, the RTF measurement caveat (llama-cli 0.19 vs the in-process 0.56), and a note that the streaming-ONNX backend has its own code path. phase0/phase1 experiment docs are marked as historical. 文档与现状对齐:README 的 Phase 4 从「待做」改为完成、快速开始不再让人把模型下到当前 目录;phase3 的 ✕ 说明改为「隐藏到托盘」、用法改用 live-caption;新增 GUI/CLI/排错三份 文档;asr-backends 补上注册表的 size/sha256 字段与模型许可/体积表;phase0 补上 RTF 口径 说明(llama-cli 的 0.19 与程序内的 0.56);phase2 补上「流式 ONNX 走另一条分支」的说明。
7.0 KiB
推理后端与模型管理
结构:2 个实现覆盖所有模型
实测确认了一件很重要的事:不同模型不需要各写一套代码。所有流式 ONNX 模型走的是同一套 API,差别只是「指向哪个模型文件 + 几行选项」。
IAsr(src/core/iasr.h)
├─ Qwen3Asr llama.cpp / ggml GGUF 模型(Qwen3-ASR) AsrKind::PrefixRollback
└─ SherpaAsr sherpa-onnx / onnxruntime
├─ X-ASR-zh-en 中英流式
├─ zipformer-zh-2025 中文流式(k2-fsa 官方)
└─ Nemotron-3.5 40 语言流式(含日语) AsrKind::NativeStreaming
两条路径的区别(StreamingAsr 里按 IAsr::kind() 分流):
| PrefixRollback | NativeStreaming | |
|---|---|---|
| 模型类型 | 离线模型(LLM 解码器) | 有状态流式识别器 |
| 上层要做的 | 切块 + 前缀回滚 + KV 复用 | 只喂音频,取当前整句文本 |
| 每步成本 | 随句子长度增长 | 恒定 |
| 已稳定/不稳定 | 用 token 回滚算 | 用「与上次的公共前缀」算 |
模型注册表与存储
新增模型 = 加一条数据,不改代码。
- 注册表:
data/models.json(编译进二进制,同时也给脚本用) - 存储位置:
~/.local/share/live-caption/models/<id>/(即QStandardPaths::GenericDataLocation + /live-caption/models) - 下载:GUI 的「模型 → 下载」,或
scripts/fetch-models.sh [id...]/--all;已存在的文件会跳过
./scripts/fetch-models.sh # 列出模型与安装状态
./scripts/fetch-models.sh zipformer-zh-2025
一条模型长这样:
{
"id": "zipformer-zh-2025",
"name": "中文流式(k2-fsa 官方 2025-06-30)",
"backend": "sherpa-online", // llama-cpp | sherpa-online
"languages": ["zh"],
"license": "Apache-2.0",
"note": "167MB,最快最准的中文流式模型",
"files": {
"encoder": { "name": "encoder.int8.onnx", "url": "https://...", "size": 161000000, "sha256": "5ac5..." },
"tokens": { "name": "tokens.txt", "url": "https://...", "size": 3000, "sha256": "6193..." }
}
}
size / sha256 就是完整性校验的依据:打开/选择模型时只比大小(快),
「校验完整性」或 --verify-model 才重算 sha256(慢,但能发现内容损坏)。
模型清单
| id | 语言 | 后端 | 许可 | 体积 | sha256(首个文件,前 16 位) |
|---|---|---|---|---|---|
qwen3-asr-0.6b-q8 |
52 语言 | llama-cpp | Apache-2.0 | 1019MB | bca259818b50ca7c… |
zipformer-zh-2025 |
zh | sherpa-online | Apache-2.0 | 167MB | 5ac51e27981bb4da… |
xasr-zh-en-480 |
zh, en | sherpa-online | Apache-2.0 | 615MB | 0c3454033d249081… |
nemotron35-560ms |
16 语言(含 ja) | sherpa-online | OpenMDW-1.1 | 682MB | 012e9321373af990… |
分发包模型时记得带上许可(尤其 Nemotron 是 OpenMDW-1.1,不是 Apache-2.0)。
用法
# 默认后端:llama.cpp + Qwen3-ASR GGUF
./build/live-caption-cli --model M.gguf --mmproj MM.gguf
# 流式 ONNX 后端:按注册表 id 从模型目录取
./build/live-caption-cli --asr-backend sherpa --asr-model zipformer-zh-2025
./build/live-caption-cli --asr-backend sherpa --asr-model nemotron35-560ms --language ja
# 覆盖模型目录 / 语言提示
./build/live-caption-cli --asr-backend sherpa --asr-model ... --model-dir /path/to/models
实测对比(同一批音频,1 线程)
| 模型 | 中文 | 英文 | 日语 | RTF | 核·秒/秒音频 | 首个字幕 | 体积 | 许可 |
|---|---|---|---|---|---|---|---|---|
| Qwen3-ASR 0.6B(llama) | ✅ | ✅ | ✅ | 0.56 | 4.27 | ~2.5s | 973MB | Apache-2.0 |
| zipformer-zh-2025 | ✅ | — | — | 0.098 | 0.10 | 0.48s | 167MB | Apache-2.0 |
| X-ASR-zh-en 480ms | ✅ | ✅ | — | 0.122 | 0.12 | 1.44s | 587MB | Apache-2.0 |
| Nemotron 3.5 560ms | ⚠️ 漏字 | ⚠️ 若干错词 | ⚠️ 有错字 | 0.35 | 0.35 | 1.12s | 651MB | OpenMDW-1.1 |
静态模型(zipformer-zh-2025)的多线程是负优化:onnxruntime 对小模型开多线程, 同步/自旋开销会让它更慢(8 线程比 1 线程慢 2.6 倍、CPU 高 28 倍)。所以适配器里固定
threads = 1。
设置对话框
三个页签(模型 / 显示 / 高级),底部三个按钮 应用 / 取消 / 确定 —— 「应用」= 应用但不关闭,方便实时预览(改不透明度、字号时会立刻看到效果)。
只有模型 / 识别语言 / 采集设备变化才会重启识别后端;透明度、字号、行数、位置这类外观改动是即时生效的,不会打断正在进行的转写。
各设置项的完整说明见 gui.md。
采集设备选择
默认跟随系统默认输出;也可以在设置里指定某个输出设备(--list-devices 可列出):
./build/live-caption-cli --list-devices
./build/live-caption-cli --cli-live --device alsa_output...HiFi__HDMI1__sink
完整性校验
注册表里每个文件都记了 size 与 sha256:
- 快速检查(打开/选择模型时):文件存在且大小对得上;
- 完整校验(设置里「校验完整性」或
--verify-model <id>):逐个重算 sha256,损坏的文件名会列出来。
./build/live-caption-cli --verify-model zipformer-zh-2025
两个坑
- sherpa-onnx 的预编译库是旧 C++ ABI(
_GLIBCXX_USE_CXX11_ABI=0),和 Qt 的新 ABI 冲突, C++ API 链接不上。必须用它的 C API(sherpa-onnx/c-api/c-api.h,extern "C",无名字改写)。 - 末尾要补一小段静音(
streamFinish()里补 0.3s),否则最后一个字会被截掉。 但不需要InputFinished:实时字幕的音频流永不结束,一句话的边界是「静音」而不是「输入结束」,InputFinished的语义只对文件成立。实测只补静音(不调InputFinished)结果就是完整的。 真实场景里那段尾部静音本来就会被喂进去(VAD 判定静音要 0.8s,这 0.8s 已经送给模型了), 所以补静音只是个兜底。
自动语言识别
| 模型 | 自带 LID |
|---|---|
| Qwen3-ASR | ✅ 输出 language X(实测中英都准) |
| Nemotron 3.5 | ✅ language=auto,但实测会串(日语开头吐韩文) |
| X-ASR / zipformer | ❌ 固定语言对,不出语言标签 |
LID 不必由 ASR 模型提供:Chrome 就带了个独立的 2.5MB ONDEVICE_langid.tflite(我们在它的语言包目录里看到了),
Windows 同样。sherpa-onnx 也有专门的语种识别模型。所以**「按语言装包 + 用户选语言或小 LID 模型」**是可行路线。
推荐组合(按语言装包)
| 语言 | 实时预览 | 定稿 |
|---|---|---|
| 中文 | zipformer-zh-2025(最快最准) |
Qwen3-ASR |
| 英文 | xasr-zh-en-480 |
Qwen3-ASR |
| 日语 | nemotron35-560ms --language ja(质量一般) |
Qwen3-ASR(开源日语第一) |
| 其他 | — | Qwen3-ASR(52 语言兜底) |