一开始我也觉得,语音转写这事直接上云 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',
nThreads: 4,
wordTimestamps: true,
prompt: '请保留专有名词'
})
console.log(result.text)
} finally {
if (model.isLoaded()) {
model.unload()
}
}
}
main()
这段里真正关键的是 finally 里的 unload()。
不做这步,服务长跑后内存表现会很难看,监控图会变成你不想在周会上展示的样子。
三个我觉得最有用的实践
1)线程参数别上来就拉满
nThreads 不是越大越快。
我的做法是先给一个中间值,然后拿真实音频压测,观察吞吐和响应时间再调。
2)调试日志只在需要时开
printProgress、printRealtime 这些开关排障很好用,但生产常开会让日志噪音很重,重到你开始怀疑自己是不是在看弹幕。
3)模型文件当成正式资产管理
既然走本地 ggml 模型,那模型路径、版本、体积就得纳入发布规范,不要临时拼凑。
README 里这些信息也很实用
快速验证链路:
cd .tmp-node-new-case
npm run start
维护常用命令:
npm run build:debug
npm run build
npm run build:cross
最后想说
本地转写这条路不一定适合所有团队,但如果你在意数据可控、长期成本和链路稳定性,它真的值得试一次,至少能少几次“线上怎么又抖了”的灵魂发问。
你们现在在项目里是偏云 API,还是已经在做本地推理了?可以聊聊各自的取舍。