Files
live-caption/docs/asr-backends.md
T
blumia 370c869ad0 feat(gui): add an Apply button for live preview of settings
Split applying settings from closing the dialog, so appearance changes
(opacity, font size, line counts) can be previewed without dismissing it.
The caption window now listens to settingsApplied and updates immediately;
only model, language or capture-device changes restart the ASR backend.

设置对话框新增「应用」按钮:应用设置但不关闭对话框,方便实时预览(不透明度、
字号等立刻可见)。字幕窗改为监听 settingsApplied 即时更新;只有模型/识别语言/
采集设备变化才重启识别后端,外观调整不会打断正在进行的转写。
2026-10-12 17:18:16 +08:00

5.6 KiB
Raw Blame History

推理后端与模型管理

结构: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)
  • 下载:scripts/fetch-models.sh [id...] / --all;已存在的文件会跳过
./scripts/fetch-models.sh                # 列出模型与安装状态
./scripts/fetch-models.sh zipformer-zh-2025

用法

# 默认后端: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。

设置对话框

三个页签(模型 / 显示 / 高级),底部三个按钮:

  • 应用:应用设置但不关闭对话框,方便实时预览(改不透明度、字号时会立刻看到效果);
  • 取消:放弃本次改动;
  • 确定:应用并关闭。

只有模型 / 识别语言 / 采集设备变化才会重启识别后端;透明度、字号、行数、位置这类外观改动是即时生效的,不会打断正在进行的转写。

采集设备选择

默认跟随系统默认输出;也可以在设置里指定某个输出设备(--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

两个坑

  1. sherpa-onnx 的预编译库是旧 C++ ABI(_GLIBCXX_USE_CXX11_ABI=0),和 Qt 的新 ABI 冲突, C++ API 链接不上。必须用它的 C API(sherpa-onnx/c-api/c-api.h,extern "C",无名字改写)。
  2. 末尾要补一小段静音(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 语言兜底)