Agent Zero Whisper STT 语音转文字插件深度解析:架构、配置与端到端转写流程
2026/9/14 19:21:21 网站建设 项目流程

Agent Zero Whisper STT 语音转文字插件深度解析:架构、配置与端到端转写流程

【免费下载链接】agent-zeroAgent Zero AI framework项目地址: https://gitcode.com/GitHub_Trending/ag/agent-zero

导读

本文以 Agent Zero 内置的_whisper_stt插件(plugins/_whisper_stt)为对象,完整讲解这套基于 OpenAI Whisper 的语音转文字(Speech-to-Text)能力的职责划分、六大配置参数、两个插件 API、模型运行时原理与前端麦克风状态机。读完本文,你将掌握:如何在 Agent Zero 中启用并调优 Whisper STT、send/draft两种消息投递模式的区别、静音检测到转写派发的完整数据链路,以及该插件如何与sttService服务、Web UI 扩展点协同工作,为后续二次开发或故障排查提供源码级依据。

一、插件定位:职责边界清晰的 STT 提供者

从 plugins/_whisper_stt/README.md 与 plugins/_whisper_stt/AGENTS.md 可以看出,该插件遵循"一个插件只负责一件事"的设计原则,其核心职责是:

  • 在插件启用时,把 Whisper 注册为当前活跃的 STT 提供者;
  • 拥有麦克风运行时(microphone runtime)、设备选择 UI、消息投递模式与插件 API;
  • 将依赖安装与模型引导(bootstrap)约束在 Docker/启动路径上,插件本身不负责安装依赖。

与之配套,_kokoro_tts插件负责文本转语音(TTS),二者共同构成 Agent Zero 的语音能力双子插件。这种拆分也体现在目录结构上:语音能力从核心代码库迁出为插件后,旧的核心语音文件(如api/transcribe.pyhelpers/whisper.pywebui/css/speech.css等)已被移除,并由 tests/test_speech_plugin_split.py 中的test_legacy_core_speech_artifacts_are_removed测试用例逐一断言其不存在。

模块归属(Ownership)

根据 plugins/_whisper_stt/AGENTS.md 中声明的所有权边界,各文件分工如下:

模块归属职责
api/(status.py、transcribe.py)转写与状态端点
helpers/(runtime.py、migration.py)运行时与迁移行为
hooks.py提供者注册与生命周期行为
webui/设置页、主语音 UI、Store(状态仓库)与样式
default_config.yamlplugin.yamlREADME.md默认值、元数据与行为说明

插件元数据

plugins/_whisper_stt/plugin.yaml 声明了插件的基本信息:

name: _whisper_stt title: Whisper STT description: Built-in Whisper speech-to-text plugin. version: 1.0.0 always_enabled: false settings_sections: - agent per_project_config: false per_agent_config: false

要点:always_enabled: false表示插件默认不启用,需要在设置中显式打开;配置作用于全局(per_project_configper_agent_config均为false),不会按项目或按 Agent 隔离;settings_sections: [agent]表明其配置入口挂在 Agent 设置分区下,Web UI 通过 extensions/webui/voice-settings-main/whisper-card.html 在voice-settings-main扩展点渲染设置卡片。

二、配置详解:六大参数与取值约束

插件默认配置定义在 plugins/_whisper_stt/default_config.yaml:

model_size: base language: en message_mode: send silence_threshold: 0.3 silence_duration: 1000 waiting_timeout: 2000

同时,plugins/_whisper_stt/helpers/runtime.py 中维护了一份同值的DEFAULT_CONFIG字典,并在normalize_config()函数中实现了完整的参数校验与钳制(clamping)逻辑,这正是"配置参数说明"的权威来源:

参数默认值含义normalize 约束(源码行为)
model_sizebaseWhisper 模型变体仅接受集合{"tiny", "base", "small", "medium", "large", "turbo"}中的值,非法值回退默认
languageen语言提示,auto表示自动检测非空字符串即可;auto在运行时被解析为None(交给 Whisper 自动识别)
message_modesend最终转写结果的投递方式仅接受{"send", "draft"},小写归一化,非法值回退send
silence_threshold0.3触发录音的最低信号门限强制转 float 并钳制到[0.0, 1.0]
silence_duration1000进入等待阶段所需的静音毫秒数转 int,必须> 0
waiting_timeout2000静音后等待多久才派发转写(毫秒)转 int,必须> 0

注意:normalize_config只做"防御性"校验,任何非法或缺失的键都会被安全地替换为默认值,不会抛异常——例如float("abc")会触发TypeError/ValueError捕获后静默保留默认值(见 runtime.py)。

配置的两个入口

  1. YAML 默认值:default_config.yaml,作为新环境的种子值来源;
  2. 运行时持久化配置:由migration.ensure_config_seeded()生成/校验的 JSON 配置文件,实际写入路径由plugins.determine_plugin_asset_path决定(见 migration.py)。Web UI 的 config.html 提供图形化编辑入口,其中:
    • Model Size下拉框列出全部六种模型(Tiny / Base / Small / Medium / Large / Turbo);
    • Language为文本输入框,占位符en,文档明确提示"Useautoto let Whisper detect it";
    • Voice Message Handling二选一:Send immediately/Draft in composer
    • Silence Threshold为 0~1 的 range 滑条(step 0.01);
    • Silence DurationWaiting Timeout为数字输入框(min 100、step 100 毫秒)。

配置保存在 Web UI 中修改后,会经hooks.pysave_plugin_config走一次normalize_config,保证落盘数据始终合法(见 hooks.py)。

三、后端 API:状态查询与音频转写

插件向外部暴露两个 REST 端点,均基于helpers.api.ApiHandler实现:

1.POST /api/plugins/_whisper_stt/status— 状态查询

实现见 plugins/_whisper_stt/api/status.py。该端点会先调用migration.ensure_config_seeded()确保配置已初始化,然后返回结构化状态:

{ "plugin": "_whisper_stt", "enabled": true, "config": { "model_size": "base", "language": "en", "message_mode": "send", "silence_threshold": 0.3, "silence_duration": 1000, "waiting_timeout": 2000 }, "model": { "ready": false, "loading": false, "loaded_model": "" }, "package": { "version": "20250625", "error": "" } }

其中model.ready对应运行时_model is not Nonemodel.loading对应is_updating_model(即模型正在预加载),package.version通过importlib.metadata.version("openai-whisper")读取,若依赖缺失则error字段携带异常信息——这也印证了"依赖安装走启动路径"的约束:插件运行时只负责读取已安装好的包。

2.POST /api/plugins/_whisper_stt/transcribe— 音频转写

实现见 plugins/_whisper_stt/api/transcribe.py,请求体为 JSON,关键字段:

字段必填说明
audio音频的 Base64 编码字符串(前端为 WAV Blob 转换而来)
ctxid上下文 ID,传入后调用self.use_context(ctxid)关联上下文

处理流程与返回约定:

  • 插件未启用 → 返回409,body 为"Whisper STT plugin is disabled"
  • audio缺失或为空 → 返回400,body 为"Missing audio"
  • 正常情况调用runtime.transcribe(audio),返回:
{ "success": true, "text": "转写文本", "language": "en" }
  • 转写过程抛异常 → 返回{"success": false, "error": "<异常信息>", "text": ""},错误不会以 500 形式打断前端状态机。

四、运行时原理:模型加载、语言解析与转写链路

模型预加载与全局单例

runtime.py 的preload()/_preload()是模型管理核心:

  • 使用模块级全局变量_model/_model_name缓存已加载模型,避免每次转写重复加载;
  • is_updating_model作为互斥锁,_preloadwhile is_updating_model: await asyncio.sleep(0.1)自旋等待其他加载完成,防止并发加载同一模型;
  • 仅在"模型未加载或模型名变化"时才真正执行whisper.load_model
  • 模型下载根目录固定在files.get_abs_path("/tmp/models/whisper"),这也解释了"模型 bootstrap 走 Docker/启动路径"的约定;
  • 加载过程中通过NotificationManager向界面推送"Loading Whisper model...",加载完成后推送"Whisper model loaded."(2 秒展示),并同步PrintStyle控制台日志。

hooks.pysave_plugin_config中还有一个贴心细节:当用户把model_size从 A 改成 B 时,会立即DeferredTask().start_task(runtime.preload, next_model)异步预热新模型(见 hooks.py),切换模型无需等到首次点击麦克风。

转写调用链

runtime.transcribe()_transcribe()的完整链路(runtime.py):

  1. 归一化配置(未传则读取已保存配置);
  2. _resolve_language()解析语言:空字符串或autoNone(不传language参数,交给 Whisper 自动检测);否则原样小写传递;
  3. await _preload(model_name)确保模型就绪;
  4. base64.b64decode还原音频字节,写入tempfile.NamedTemporaryFile(suffix=".wav")临时文件;
  5. 调用_model.transcribe(temp_path, fp16=False, language=...)——fp16: False确保在无 CUDA 或需要高精度的环境中也能稳定转写;
  6. finally中删除临时文件,避免磁盘残留。

启用状态判定

is_globally_enabled()通过plugins.determined_toggle_from_paths(True, reversed(plugins.get_plugin_roots(PLUGIN_NAME)))判定全局开关(runtime.py),保证插件目录被多次叠加时,最终以最上层启停状态为准。

五、旧配置迁移:从核心设置到插件配置

该插件从核心代码库拆分出来后,需要把旧版核心配置(存放在usr/settings.json)平滑迁移到插件自己的配置文件,这部分由 plugins/_whisper_stt/helpers/migration.py 完成:

  • ensure_config_seeded():若插件配置尚不存在,则基于旧设置构建种子配置并落盘;
  • build_seed_config()读取旧键:stt_model_sizestt_languagestt_silence_thresholdstt_silence_durationstt_waiting_timeout,逐项映射到新键,缺失项使用默认值;
  • _coerce_float/_coerce_int提供容错转换,旧值为非法类型时回退默认值。

这也与测试 tests/test_speech_plugin_split.py 中的断言相呼应:stt_model_size等旧键已从核心设置中移除,settings.get_default_settings()的输出中不再出现任何 legacy 语音键。

六、前端运行时:麦克风状态机与端到端流程

STT 提供者注册机制

Web 前端通过 webui/js/stt-service.js 暴露全局sttService(单例,继承EventTarget),以"提供者注册表"模式管理多个 STT 实现:插件启用时registerProvider("_whisper_stt", {...})注入handleMicrophoneClickrequestMicrophonePermissionupdateMicrophoneButtonUIstopgetStatus五个钩子;插件禁用或状态拉取失败时unregisterProvider清理并停止当前录音(见 whisper-stt-store.js)。麦克风按钮由此实现"谁启用谁接管"的解耦。

插件的前端状态仓库 webui/whisper-stt-store.js 定义了完整状态机:

状态含义按钮颜色(whisper-stt.css)
inactive麦克风待机grey
activating麦克风激活中silver(图标 0.8s 脉冲动画)
listening侦听语音red
recording正在录音green
waiting等待最终静音teal
processing转写中darkcyan(图标脉冲动画)

按钮本体由 extensions/webui/chat-input-box-end/microphone-button.html 通过x-teleport注入到聊天输入区(#chat-buttons-wrapper),并随状态切换mic-*class 与aria-label(无障碍标签),同时以sttService.emitStatusChange(micStatus)广播状态。

静音检测算法(核心逻辑)

MicrophoneInput类(whisper-stt-store.js)使用 Web Audio API 的AnalyserNode做实时音量分析:

  • 采样时域数据,计算RMS 幅度sqrt(sum((sample-128)/128)² / N)
  • 门限并非直接用silence_threshold,而是经过densify(value) = Math.exp(-5 * (1 - value))非线性映射后比较——这使得 0~1 的滑条值在实际声学感知上更均匀;
  • RMS 超过门限(且 TTS 未在播报)→ 从listening进入recordingMediaRecorder.start(1000)按 1 秒分片采集;
  • 录音中 RMS 持续低于门限达到silence_duration毫秒 → 进入waiting
  • waiting阶段再等waiting_timeout毫秒 → 进入processing,触发转写派发;
  • silence_duration到达前声音恢复,silenceStartTime重置,继续录音。

整个状态推进由requestAnimationFrame驱动的analyzeFrame循环完成(whisper-stt-store.js),并且在dispose()时彻底清理 MediaRecorder、MediaStream、AudioContext,避免浏览器资源泄漏。

转写结果投递:send 与 draft 模式

process()把录音分片合成Blobtype: "audio/wav"),转 Base64 后 POST 到/plugins/_whisper_stt/transcribe。返回文本先经过filterResult()过滤——若文本整体被{}()[]包裹(疑似模型输出异常内容),直接丢弃并记日志,避免把非语音噪声当消息发送。

随后sendVoiceMessage(text)(whisper-stt-store.js)按message_mode分流:

  • send模式updateChatInput(message)填充输入框后立即sendMessage()发送;
  • draft模式:只updateChatInput(message)把文本留在编辑器中,由用户审阅后再手动发送,sendsImmediatelyfalse时不触发发送。

此外,前端还实现了两个易用性细节:通过navigator.mediaDevices.enumerateDevices()枚举音频输入设备,选择结果存入localStorage(键whisperSttSelectedDevice),并监听devicechange事件在插拔设备时刷新列表;同时订阅ttsServicestatechange,一旦 TTS 开始播报且麦克风处于活动状态,立即stop()停止录音,避免语音助手自说自话被误转写。

状态页与配置页

  • webui/main.html 提供状态面板:Provider State(启用/模型就绪/已加载模型/Package 版本)、Resolved Config(六项归一化后的实际配置)、Microphone(当前状态、设备下拉选择),以及"Request Mic Permission / Open Settings / Refresh"三个操作按钮;
  • extensions/webui/voice-settings-main/whisper-card.html 在设置页展示精简卡片(模型、语言、消息模式、麦克风),可直接跳转配置或状态面板。

七、依赖与验证:如何确认插件工作正常

依赖声明

仓库 requirements.txt 固定了openai-whisper==20250625,插件运行所需的 Whisper 依赖由此声明。如前所述,依赖安装与模型下载(/tmp/models/whisper)均发生在 Docker/启动路径,插件运行时只做加载与推理。

测试覆盖

tests/test_speech_plugin_split.py 是理解该插件行为契约的最佳测试入口,重点覆盖:

  • test_builtin_speech_plugins_are_discoverable_and_toggleable_whisper_stt可被发现、可切换,always_enabled=False且挂载agent设置分区;
  • test_plugin_owned_voice_files_exist:断言plugin.yamlapi/transcribe.py、三个 WebUI 扩展点文件与whisper-stt-store.js均存在;
  • test_whisper_message_mode_defaults_to_send_and_supports_draft:验证message_mode默认senddraft大小写归一化(DRAFTdraft)、非法值回退send,并逐文件核对 UI 选项与 Store 行为;
  • test_chat_bar_keeps_existing_send_and_mic_icon_contract:对七个mic-*状态类在 Store、CSS、按钮扩展点三处的同步存在性做了全量断言。

快速自检清单

按 plugins/_whisper_stt/AGENTS.md 的 Verification 指引,改动后应冒烟测试以下链路:

  1. 状态端点:/api/plugins/_whisper_stt/status返回enabledconfigmodel信息正确;
  2. 转写链路:录音→Base64→/transcribe返回textlanguage
  3. 模型/语言设置:切换model_size触发预热,language=auto时后端不传 language 参数;
  4. send/draft 模式:send立即发送、draft仅留在编辑器;
  5. 静音处理:silence_threshold/silence_duration/waiting_timeout三参数联动符合预期。

八、扩展与定制方向

基于上述架构,开发者可以低成本地扩展语音能力:

  • 替换模型:在设置中把model_size改为tiny(最快)到turbo(质量最高),模型变更后hooks.py会自动异步预加载;
  • 多语言支持:将language设为具体语言代码(如zhjade)提升识别准确率,或保持auto交给 Whisper 自动检测;
  • 消息审阅流程:将message_mode设为draft,让用户在任何转写结果进入对话前拥有最终确认权;
  • 二次开发:若要接入其他 STT 引擎,可仿照_whisper_stt实现一套api/+helpers/+ WebUI 扩展点,并复用sttService.registerProvider接口(webui/js/stt-service.js)完成提供者注册,前端无需改动即可无缝切换。

结语

_whisper_stt插件是 Agent Zero"核心瘦身、能力插件化"架构的典型样本:后端把 Whisper 的模型管理、配置归一化、迁移与推理封装在helpers/中,api/仅暴露statustranscribe两个薄端点,前端则通过sttService提供者模式与 Web UI 扩展点实现麦克风状态机与消息投递。理解这层分工,无论是调参、排障还是接入新语音引擎,你都能在 plugins/_whisper_stt、webui/js/stt-service.js 与 tests/test_speech_plugin_split.py 之间快速定位问题根源。

【免费下载链接】agent-zeroAgent Zero AI framework项目地址: https://gitcode.com/GitHub_Trending/ag/agent-zero

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询