从Hey Jarvis到开口说话:J.A.R.V.I.S.语音管线双引擎设计(ElevenLabs可选、自动降级)

【免费下载链接】jarvis

J.A.R.V.I.S for automating your daily tasks using Claude Code

项目地址: https://gitcode.com/gh_mirrors/jarvis90/jarvis
点击查看 免费下载

J.A.R.V.I.S.(jarvis)是一个跑在浏览器里的钢铁侠风格语音助手:说一声 "Hey Jarvis",它就会醒来、听懂、开口回答,还能调用你本地工具帮你查资料、生成图片。它的语音管线采用双引擎设计——默认的浏览器原生语音,和可选的 ElevenLabs 云端语音,启动时自动探测、全程自动降级,不配任何 API key 也能正常说话和听懂。这篇文章带你搞懂这套设计是怎么工作的。

双引擎架构:一张图看懂

整个系统由两部分组成,通过 WebSocket(ws://localhost:8787)对话:

  • 浏览器(脸和嘴):负责唤醒词检测、语音转文字、播放回复声音、渲染全息 UI
  • bridge(大脑和手):一个 Node 进程 bridge/server.mjs,以 headless 方式运行 Claude Code,并代理 ElevenLabs 的语音请求

语音相关的两条"引擎轨道":

环节默认轨道(零配置)增强轨道(有 ElevenLabs key)
听(STT)浏览器 SpeechRecognition本地 VAD + ElevenLabs Scribe
说(TTS)浏览器 speechSynthesisElevenLabs 云端语音

关键点:两条轨道由同一个小探测决定,全程无开关、无手动选择。

启动时的能力探测:一次 /health 请求定乾坤

浏览器在开机序列里会向 bridge 发一次 GET /health 请求,bridge 检查本机有没有 ElevenLabs 的 key,然后返回一个极简的能力报告:

{ "ok": true, "tts": true, "stt": true }
  • 有 key → tts 和 stt 都为 true,语音和转写双双升级到云端引擎
  • 没有 key(或 bridge 没启动)→ 两个都是 false,安心用浏览器自带语音,功能完整可用

这个探测逻辑集中在 src/lib/capabilities.ts 的 probeCapabilities() 里,它的注释写得很直白:"探测失败就留在浏览器回退方案上——bridge 不可达时这才是正确行为"。探测在开机序列中、第一句 "Hey Jarvis" 之前就完成(见 src/App.tsx),所以你第一次开口时用的就是正确的引擎。

💡 这个设计的哲学:默认值必须"安全可用"。学生党只装了 Claude Code 也能玩;有 key 的人则自动升级,不需要改任何配置项。

听:STT 的两条路径

增强路径:本地 VAD 秒级响应 + 云端转写

有 ElevenLabs key 时,"听"被拆成两步:

  1. 检测(本地、即时):src/lib/vad.ts 实现了一个基于能量的语音活动检测器——滑动噪声底 + 阈值 + 滞回门。你张嘴的瞬间它就知道,这就是"插话(barge-in)"能这么自然的原因:JARVIS 正在说话时你一开口,它立刻停嘴。
  2. 转写(云端、可靠):VAD 把一段完整的音频切片打包,POST 到 bridge 的 /stt 端点(bridge/server.mjs),由 ElevenLabs Scribe 转成文字再回来。

为什么要这么拆?因为浏览器原生的 SpeechRecognition 在 7×24 常开场景下会无声地死掉——Chrome 会节流它、停止触发事件、且不抛任何可捕获的错误。而"有人在说话"本质是个能量问题,自己每帧都能量一次,不存在黑盒静默失效。

默认路径:SpeechRecognition + 心跳保活

没有 key 时,src/lib/voice.ts 走浏览器自带的 SpeechRecognition,它更弱一些(Chrome 会节流),所以加了一个心跳定时器:每 5 秒检查引擎是否还有"生命迹象",超过 15 秒没任何动静就判定它哑了,强制拆掉重建一个新的识别器。注释里说得很实在:这一个守卫,就是"唤醒词上节课还好好用、这节课突然失灵"和"助手一直在线"的区别。

两条路径共用同一个"语句组装器":你在句子中间停顿想词,它不会把半句话当成完整问题发出去;你说得完整,它就零额外延迟立刻发送。

说:TTS 的两条路径与降级链

云端语音:一句一请求,失败即降级

选择引擎的核心在 src/lib/tts.ts 的 synthesise() 里,优先级是:

  1. 探测到 ElevenLabs 可用(或你强制开启)→ 每句话 POST 到 bridge 的 /tts(bridge/server.mjs),bridge 持有 key 调 ElevenLabs,返回 22kHz 单声道 mp3 音频
  2. 配置了 VITE_TTS_ENGINE=kokoro → 用 src/lib/kokoro.ts 跑一个 82M 参数的本地神经网络 TTS(WebGPU/ONNX,零云端零 key,代价是首次下载约 86MB 模型)
  3. 否则 → 浏览器原生 speechSynthesis

任何一步失败都不会让这句话哑掉:云端请求失败就丢弃回系统声音;音频播不出来就走下一层。

系统语音:细节里全是坑位

原生路径看着简单,src/lib/tts.ts 里其实处理了大量真实世界的坑:

  • Chrome 卡死修复:speechSynthesis.cancel() 之后引擎会进入"接受一切 speak 但什么都不说"的僵尸态——这是整个会话突然全程静音的头号元凶。代码在每次发声前先 resume() 松绑,并配了 700ms 看门狗:start 事件迟迟不来就先松绑重试一次,再不行才判定失效
  • 长句保活:Chrome 大约 15 秒不说话就掐断,代码用不可闻的 pause/resume 对每 5 秒"挠一下"引擎
  • 音色选择:给系统音色打分排序,偏好英式男声(macOS 上 Enhanced 版 Daniel 是免费的最优解),排除各种搞笑音色
  • 流式断句:回复按句子边界切分、边写边说,Claude 还在生成 JARVIS 已经在开口;"Mr."、"e.g." 这类缩写不会误切,"sir" 前自动补逗号留出那口标志性的停顿

自动降级:三条兜底路径

这是整条 TTS 链最漂亮的部分:

故障场景自动行为
云端请求失败(网络抖动等)本句降级为浏览器系统声音
系统声音被证实坏了(onstart 从未触发)闩锁:不再反复重试死路,本句由 bridge 的 ElevenLabs 代理"救场"(rescued 计数 +1),后续全部走云端
云端也没有保持沉默但不卡死队列,诊断面板记录原因

注意"闩锁"这个词:系统语音坏了不是瞬态故障,每句都重试只会让回答在一条死路上磕磕绊绊。所以第一次真失败后就永久切换,诊断对象 src/lib/tts.ts 会如实记录 engine、nativeBroken、rescued 等字段。

如何启用 ElevenLabs 增强引擎

不用碰任何 flag,二选一:

  • 启动 bridge 前设置环境变量 ELEVENLABS_API_KEY
  • 或把 key 写进 ~/.claude.json 里 elevenlabs MCP server 的 env——bridge 会自己去那里读(bridge/server.mjs)

key 就位后,/health 开始报告能力,浏览器下一次开机自动拾取,语音和转写同时升级。免费额度做 demo 完全够用。

🔒 安全细节:key 只留在 bridge 进程里,浏览器永远看不到秘密——它只是把文字 POST 给 /tts、拿回音频。

怎么验证当前跑的是哪套引擎

项目内置了诊断能力,不用翻控制台:

  • 按 D 打开实时诊断面板:直说它在没在听你、在不在出声,window.__tts / window.__voice 里的计数一清二楚
  • 按 T 做单行音频自检
  • HUD 上会显示当前引擎标签:ElevenLabs、ElevenLabs voice 或 browser speech(由 src/lib/capabilities.ts 的 engineLabel() 给出)

常见问题的快速排查:完全没声音 → 确认是真实 Chrome/Edge 窗口(内嵌预览窗格会屏蔽麦克风)且已授权麦克风;bridge 连不上 → 检查 npm run bridge 是否还在跑、端口 8787 有没有被占用。

小结

jarvis 的语音管线设计可以浓缩成三句话:

  1. 默认零门槛:只装 Claude Code + Node.js + Chrome 就能说能听,不花一分钱
  2. 探测即选择:开机一次 /health 探测,自动决定 STT/TTS 各走哪条轨道,无需任何开关
  3. 故障不静默:云端失败降系统声音、系统声音坏了闩锁到云端救援、识别器心跳超时自动重建——每一句都不允许无声地死掉

对想自己做语音助手的人来说,这套"本地能量检测 + 云端转写 + 多级降级"的分层思路非常值得借鉴:把不可靠的黑盒和可靠的物理量分开处理,再给每一层配好兜底,鲁棒性自然就出来了。更多配置项(如 JARVIS_VOICE_ID、VITE_TTS_ENGINE)见 README.md。

【免费下载链接】jarvis

J.A.R.V.I.S for automating your daily tasks using Claude Code

项目地址: https://gitcode.com/gh_mirrors/jarvis90/jarvis
点击查看 免费下载

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

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值