我把 Node.js 的语音转写链路改成本地后,最大的变化不是“更快”

0 阅读2分钟

ScreenShot_2026-03-17_141449_421.png 一开始我也觉得,语音转写这事直接上云 API 最省心。
但项目跑一阵子后,问题基本都不是“能不能转写”,而是这些更现实的事:

  • 费用会不会持续涨
  • 音频数据出网怎么跟客户解释
  • 网络抖动时接口超时怎么兜底

所以我们后面试了本地方案,最后选了 WhisperFast。简单说就是:技术同学能睡得更踏实一点。

先说为什么选它

不是因为它“概念新”,而是因为它在 Node.js 里接起来真的不费劲,不需要先集齐一套玄学编译环境。

它这套结构是:

  • whisper.cpp 负责推理
  • Rust 做封装
  • napi-rs 暴露给 Node.js

实际感受就是:业务层还在写熟悉的 JS/TS,但底层能吃到原生性能。

接入成本比我预期低

安装:

npm install whisper-fast

调用:

const { WhisperModel } = require('whisper-fast')

async function main() {
  const model = new WhisperModel('models/ggml-base.bin')
  await model.load(false)
  try {
    const result = await model.transcribeFile('audio.wav', {
      language'zh',
      nThreads4,
      wordTimestampstrue,
      prompt'请保留专有名词'
    })
    console.log(result.text)
  } finally {
    if (model.isLoaded()) {
      model.unload()
    }
  }
}

main()

这段里真正关键的是 finally 里的 unload()
不做这步,服务长跑后内存表现会很难看,监控图会变成你不想在周会上展示的样子。

三个我觉得最有用的实践

1)线程参数别上来就拉满

nThreads 不是越大越快。
我的做法是先给一个中间值,然后拿真实音频压测,观察吞吐和响应时间再调。

2)调试日志只在需要时开

printProgressprintRealtime 这些开关排障很好用,但生产常开会让日志噪音很重,重到你开始怀疑自己是不是在看弹幕。

3)模型文件当成正式资产管理

既然走本地 ggml 模型,那模型路径、版本、体积就得纳入发布规范,不要临时拼凑。

README 里这些信息也很实用

快速验证链路:

cd .tmp-node-new-case
npm run start

维护常用命令:

npm run build:debug
npm run build
npm run build:cross

最后想说

本地转写这条路不一定适合所有团队,但如果你在意数据可控、长期成本和链路稳定性,它真的值得试一次,至少能少几次“线上怎么又抖了”的灵魂发问。

你们现在在项目里是偏云 API,还是已经在做本地推理了?可以聊聊各自的取舍。