Skip to content

plugin-asr-whisper-cpp — 本地 whisper.cpp 语音识别 ​

包名: @aalis/plugin-asr-whisper-cpp
源码: packages/plugin-asr-whisper-cpp/src/index.ts

概述 ​

语音识别(ASR)的本地 whisper.cpp 提供者:调用 whisper.cpp 提供的 whisper-cli 二进制完成转写,以 asr 服务注册。使用前需安装 whisper.cpp(如 brew install whisper-cpp)并下载模型文件(如 ggml-base.bin)。输入音频先经 ffmpeg 转为 16kHz 单声道 WAV,再交给 whisper-cli;ffmpeg 按内容探测输入格式,下载与解码出的临时文件一律叫 audio.bin。

插件声明 ​

ts
definePlugin({
  name: '@aalis/plugin-asr-whisper-cpp',
  displayName: 'Whisper.cpp 本地转写',
  subsystem: 'media',
  provides: [asr],
  uses: {
    logger,
    config,
    provide,
    proc: processService,
    storage,
  },
  apply(caps) { /* 见源码 */ },
})

配置 ​

字段类型默认值说明
binaryPathstring'whisper-cli'whisper-cli 路径:绝对路径,或 PATH 里能找到的命令名;留空时用默认值
modelPathstring必填模型文件路径 (.bin):GGML 模型文件(.bin)的绝对路径
languagestring'auto'默认语种
threadsnumber4线程数
timeoutMsnumber600000子进程超时 (ms):转码与识别子进程的最长运行时间。设 0 表示不限——届时卡住的子进程会把整轮对话一起挂住

modelPath 为必填:没填时插件激活失败,报「缺少配置项 modelPath」,WebUI 把它标成待配置,不注册 asr 服务。binaryPath 声明为必填并带默认值,留空时回到默认的 whisper-cli,不会以空命令运行。两个路径字段都不收相对路径(宿主进程的 cwd 不带语义),写了相对路径时插件拒绝激活。登记 asr 服务时的优先级是插件里的常量 80(云端接口 plugin-asr-openai 为 50),只作第一方提供者之间的默认先后,不可配置。转写由 media 调用,用哪个音频后端由 media 的 audio.prefer 定(处理器名为 asr:<插件实例 id>),没指定时取统一音频池里优先级最高的;服务偏好 servicePreferences.asr 在那里只在优先级相同时决胜。

相关 ​

子进程超时 ​

ffmpeg 转码与 whisper-cli 识别都经 ProcessService.execFile 带 timeout 调用:转码分到 timeoutMs / 2,识别拿完整 timeoutMs,两段子进程都卡住时上界是 1.5 × timeoutMs。http(s) 音频附件的下载不受 timeoutMs 约束,另有固定的 15 秒超时与 20 MiB 体积上限(与 plugin-media 同口径),超时或超限直接抛错。

默认值取 10 分钟而非更紧的数值:这道闸的目的是掐断真正卡死的子进程,不是给识别限速。CPU 上跑长语音本来就可能要几分钟,闸设得太紧会把本来能用的识别切掉——那是把一个挂死问题换成一个功能问题。

这个参数不是调优项而是必需项——plugin-process-local 的 spawn 只在 opts.timeout > 0 时才武装 killTree,不传就意味着子进程不退时 wait() 永不 settle:那一轮对话被永久挂住(回合 abort 也停不掉已经起来的子进程),而每条音频都会再堆一个 whisper/ffmpeg 进程。

配置校验 ​

可执行文件、模型路径、语言、线程数与进程超时的显式无效值会在注册服务前报配置错误。未填模型路径仍报缺失;timeoutMs 为 0 或负数时仍按不限时处理。

文档对应 dev@c4e046e41,core 0.21.0,构建于 2026-11-02
基于 MIT 许可发布