躺在沙发上追剧,屏幕那头有人说了句关键台词,你没听清。笔记本在房间另一头,遥控器不存在——因为那是台笔记本。有人干脆自己动手做了一个。

打开网易新闻 查看精彩图片

这个项目叫 Couch Commander(沙发指挥官)。喊一声“Hey Jarvis”,屏幕角落弹出一只像素树懒,然后你按平时说话的方式下指令:

  • “abeg go back small” → 回退 15 秒
  • “I no hear wetin she talk” → 回退 10 秒
  • “make am louder” → 调高音量
  • “skip this one” → 下一个视频

它控制的是 Mac 上 Chrome 里的 YouTube。没有遥控器,没有键盘,也不用起身。所有处理都在笔记本本地完成:不联网、不登录账号、不需要 API 密钥。

五个开源组件串成一条链

整个系统由五个开源部件拼起来,各管一段。最核心的一环是“大脑”:Gemma 拿到一句话,必须返回严格 JSON,只能从固定命令列表里选一个,或者返回 none:

{"command": "rewind", "value": 15}

作者把温度设为 0,用了 Ollama 的 JSON 模式,还在提示词里加了尼日利亚洋泾浜英语(Pidgin)的示例。如果返回不合法,就回退到 none。这条规则被作者称为整个项目里最重要的一条——无缘无故暂停你的电影,比什么都不做更糟。

30 条短语测出两个意外

作者用两个本地模型测了 30 条短语,其中 22 条是模型没见过的示例,包括现场编的洋泾浜说法(“carry am go front small”、“I wan hear am well well”)。

第一个意外:思考模式拖慢了速度。Gemma 4 首次运行平均每条命令 1489 毫秒,关掉思考(“think”: false)后降到约 190 毫秒,快了 8 倍,准确率没有下降。对遥控器来说,没人需要模型去推理,只需要它回答。

第二个意外:模型怎么失败,比失败多少次更重要。Gemma 4 的两次失误都返回了 none,也就是干脆不动。Gemma 3 的失误则是执行了动作:说“tell me a joke”时它暂停了视频,说“make we go back two minutes”时它反而前进了两分钟。这就是一个会留下的工具和一个会被卸载的工具之间的差别。

踩过的坑

作者最初从 Apple TV 应用入手,AppleScript 模拟按键到不了播放器,于是换到 Chrome 里的 YouTube,可以直接在元素上跑 JavaScript,可靠得多。前提是在 Chrome 里打开“显示 → 开发者 → 允许来自 Apple Events 的 JavaScript”。

Whisper 一度把指令转写成空字符串或“if you do”。原因是音频是原始 16 位数值,而 Whisper 要的是 -1 到 1 之间的浮点数,一行代码就修好了。

大部分延迟其实跟 AI 无关,而是一个固定的 4 秒录音窗口。唤醒词耗时 0.13 秒,Whisper 0.3 秒,Gemma 0.25 秒,剩下全在等计时器。换成语音活动检测后,这个问题解决了。

为什么坚持全本地

理由很直接:这东西的麦克风一直开着,就在客厅里。如果用闭源 API,每喊一声“Hey Jarvis”,家里的音频就会被送到别人的服务器上。作者说自己不会用那样的东西,也不会推荐别人用。在这里,音频从不离开这台 Mac,拔掉路由器它照样工作。

开源模型还让作者能测量和替换:同一批 30 条短语跑两个模型,比较准确率和速度,再关掉一个拖慢速度的功能——8 倍提速就是这么找到的。换成闭源 API,延迟是多少就只能接受多少。而且运行不花钱,让笔记本回退一段视频,没有按次计费的账单。

实际体验的诚实版本:几米之内效果最好。离得远、房间吵,笔记本麦克风就吃力;对小型 Whisper 模型来说,洋泾浜英语比标准英语更难。作者的下一步是用 AirPods 当麦克风,因为它就在嘴边。但核心闭环已经跑通:喊一声,树懒弹出,说“abeg go back small”,视频回退,人没动。

项目基于 openWakeWord、webrtcvad、Whisper、Gemma 4 和 Ollama 构建,MIT 协议开源,那只树懒是为项目原创的像素画。