跳到正文
Hacker News· neuphonic_s·· 7 天前AI 评分34

用 NeuDecide 打造的语音赛车游戏:喊一声就能开车

Voice racer game built with OSS model NeuDecide

AI 导读

Neuphonic 的 43 MB 语音转工具调用模型 NeuDecide 被用来驱动一款像素风赛车游戏,玩家直接说 "go left"、"speed up"、"jump" 即可操控,无需语音转文字或聊天机器人。模型可在本机原生运行,也可通过 WebAssembly 完全跑在浏览器内,支持 6 条语音指令,原生引擎从说完到游戏响应约 200 ms,浏览器引擎约 0.3-0.6 s。

正文 · AI 翻译

一款用你的声音驾驶的像素艺术赛车游戏。说 "go left"、"speed up" 或 "jump",赛车就会照做。

整个流程中没有语音转文本,也没有聊天机器人。NeuDecide 是 Neuphonic 推出的一个小巧(43 MB)的语音到工具调用模型,它能听到你的声音并直接选出游戏指令。它运行在你自己的机器上:可以原生地运行在页面旁边,也可以完全通过 WebAssembly 在浏览器内运行。

Voice Racer driven by six spoken commands: start the game, go left, speed up, jump, go right and slow down. Each phrase is captioned at the top, the car reacts, and the matching command tile lights up under the game

六个语音指令,由原生引擎判定。语音是 macOS 文本转语音的声音,作为麦克风输入播放到浏览器中。GIF 没有声音,所以字幕显示了所说的话。

The game with the voice panel: the RIGHT tile lights up after the player said "go right"

工作原理

flowchart LR
  mic["Microphone"] --> vad["Voice detector<br/>(energy VAD)"]
  subgraph nd["NeuDecide, run by our JavaScript engine"]
    ae["Audio encoder"] --> te["Tool encoder"]
    menu["Tool menu<br/>9 game commands + noAction, as JSON"] --> te
    te --> dec["Constrained decoder<br/>(only valid tool-call JSON)"]
  end
  vad -- "16 kHz utterance" --> ae
  dec -- "moveLeft()" --> gate["Confidence gate"]
  gate --> game["Game"]

加载中

  1. 语音检测器监听麦克风,一旦你沉默 120 毫秒,就会切分出每一句话。
  2. NeuDecide 会结合一份工具菜单来读取音频(moveLeft、moveRight、moveToLane、speedUp、 slowDown、jump、dodge、start、pause、noAction,见 src/voice/tools.js)。 受语法约束的解码器只能写出有效的工具调用,而游戏会在调用确定的那一刻就执行动作,甚至在解码完成之前。
  3. 置信度门控会丢弃不确定的调用和“无动作”的回答,所以大多数闲聊不会触发任何操作。
  4. 游戏会把调用转化为动作:变道、加速、刹车、跳跃或闪避(游戏会选择最安全的车道)。

运行该模型的引擎是 neudecide Python 包(分词器、约束解码、 推理循环)在 ONNX Runtime 上的 JavaScript 移植版:原生引擎用 onnxruntime-node,浏览器中用 onnxruntime-web(WASM, 运行在 Web Worker 中)。更多细节见 docs/ARCHITECTURE.md。

快速开始

你需要 Node 22 或更高版本、一个麦克风,以及桌面版 Chrome(或 Edge)。

git clone https://github.com/vimalananddev/voice-racer.git
cd voice-racer
npm install

下载模型(一次即可,约 43 MB)。它是免费的,但在 Hugging Face 上需要授权:登录,在 https://huggingface.co/neuphonic/neudecide 接受条款,然后使用 Hugging Face CLI,hf:

brew install hf                  # or: pipx install huggingface_hub   or: uv tool install huggingface_hub
hf auth login                    # paste a read token from https://huggingface.co/settings/tokens
hf download neuphonic/neudecide --local-dir models/neudecide

没有 CLI?从模型页面的 Files and versions 标签页下载 config.json、tokenizer.json、audio_encoder_q4.onnx、tool_encoder_q4.onnx 和 decoder_step_q4.onnx 到 models/neudecide/。 (models/README.md 有详细说明。)然后:

npm start
  1. 打开 http://localhost:5180。
  2. 等待出现 Ready!,点击 Turn on the mic 并允许使用麦克风。
  3. 说 "start the game",然后开始驾驶:"go left"、"go right"、"speed up"、"jump"……

按 Enter 而不是点击,可以一次性打开麦克风并开始比赛(然后跳过第 3 步)。

npm start 在端口 5180 上运行游戏页面,并在 ws://127.0.0.1:5190 上运行原生语音引擎,两者都只在本机运行。Ctrl-C 可同时停止两者。端口被占用?PORT=5280 VOICE_PORT=5290 npm start(此时打印的地址会带有 ?localport=5290)。npm run check 会运行一个不需要麦克风的快速冒烟测试。

npm run dev 只运行游戏页面,因此会使用浏览器内引擎。没有原生引擎时,浏览器控制台会在每次页面加载时显示一个连接到 ws://127.0.0.1:5190 的 WebSocket 失败:这是页面在寻找原生引擎,属于预期现象。

语音指令

说 作用 命中率*
"start the game" 开始、崩溃后重新开始,或继续(按 Enter 也可以) 19/24
"go left" · "go right" 向左 / 向右变一条车道 30/32 · 31/32
"lane number three" 直接前往 1-4 号车道 53/56
"speed up" 加速约 2.5 秒 24/24
"slow down" 刹车约 2 秒 24/24
"jump" 跳过锥桶、油污和坑洞(不能跳过汽车) 23/24
"dodge it" 游戏会把你移到最安全的车道 23/24
"pause the game" · "resume" 暂停 / 继续 21/24 · 24/24

* 合成语音(macOS 文本转语音)、安静房间、麦克风中无游戏声音、原生引擎。真实语音和房间会有所不同。

提示:

  • 戴上耳机(或按 M 键将游戏静音)。麦克风中的游戏声音是漏掉“左”和“右”的主要原因:有它时,单车道命令的识别率从大约十分之九降到大约一半。
  • 说 “go left”/“go right”,而不是只说那个词。每次左/右移动一条车道;说两次可到达边缘车道,或使用车道编号(“lane number four”)。“Move left”、“shift left”和“switch right”也可以。
  • 驾驶时不要说“alright”:模型会听到“right”并变换车道。“All right”、“that's right”和“yeah right”也会这样。聊天前按 V 键将麦克风静音。
  • 当命令被漏掉时,通常什么也不会发生。如果游戏意外暂停,说“resume”。
  • 序数车道(“second lane”、“last lane”)和俚语(“floor it”)几乎从不生效。

引擎与延迟

本 README 中的所有延迟和命中率数据均在 M1 Pro MacBook Pro(桌面 Chrome 中的浏览器引擎)上使用合成语音测得。

引擎 如何选择 运行位置 从你说话结束到游戏做出反应
原生(默认) npm start,或 ?engine=local 页面旁边的 onnxruntime-node(工具编码器在 M1 Pro 上使用 5 个线程;其他机器上为 min(6, cores - 2)) ~200 ms(模型时间 ~80-100 ms)
浏览器 ?engine=browser,或当没有原生引擎响应时自动使用 Web Worker 中的 onnxruntime-web(WASM) ~0.3-0.6 s(4 个线程:~0.35 s;只有 1 个线程工作时 ~0.7 s)
远程 ?engine=ws://host:5190/?token=… 另一台机器上的原生引擎 那台机器的模型时间 + 网络

约 200 ms 包括语音检测器等待 120 ms 以确认你已停止说话(使用 ?ptt=1 时,它会在你松开通话键时开始)。几乎所有的模型时间都花在工具编码器上:它从第一层就将工具菜单与你的音频混合,因此无法缓存,并且每条命令都会运行。未使用 WebGPU:它在 Apple GPU 上失败(模型需要 11 个存储缓冲区,而限制是 10)。

如果引擎在游戏中途停止,页面会显示“Voice is reconnecting…”并自行重新连接。在默认模式下,如果原生引擎在 4 秒内没有恢复,就会被浏览器引擎替换(重新加载可恢复)。键盘始终可用。

在另一台机器上运行引擎

该引擎是 scripts/remote-voice-server.mjs。它已在 macOS 和 Linux(arm64)上测试过,应该能在任何 onnxruntime-node 可运行的地方运行。CPU 核心更多的机器每条命令更快。在那台机器上,使用该仓库,npm install 并放置好模型:

TOKEN=pick-a-secret HOST=0.0.0.0 PORT=5190 npm run engine

然后在装有游戏的机器上打开 http://localhost:5180/?engine=ws://<that-machine>:5190/?token=pick-a-secret。?dev=1 面板会以引擎报告的主机名来命名它;用 ENGINE_NAME=desktop(任意名称)启动它以显示其他内容,例如在你录制面板之前(?record=1 只显示“Remote”)。当 HOST 不是 127.0.0.1 时,始终设置一个 TOKEN,并在你信任的网络上使用它:该链接是明文 ws://。更简单且私密的方式:将引擎保留在 127.0.0.1 上并使用 SSH 隧道,ssh -N -L 5195:127.0.0.1:5190 you@that-machine,然后打开 ?engine=ws://127.0.0.1:5195。

引擎在启动时会打印其线程设置;TOOL_THREADS=n 会尝试其他设置。有关所有选项和协议,请参阅 scripts/remote-voice-server.mjs 的开头部分。

URL 选项

选项 作用
?dev=1 开发者面板:显示工具调用、延迟、引擎、置信度和决策日志,而不是简洁面板
?record=1 适合录屏的清爽布局(9:16 窗口:单列;4:5、1:1 或 16:9:双列),更安静的游戏音效,更快的昼夜循环和更繁忙的交通
?ptt=1 按住说话:说话时按住 T(或按住麦克风按钮)
?engine=local · ?engine=browser · ?engine=ws://host:port/?token=… 选择引擎(默认:如果原生引擎能响应就用原生,否则用浏览器;native 和 wasm 也可以)
?voice=mock 完全不用模型:键盘伪造语音事件(用于调试 UI)
?minconf=0.6 更严格的置信度门槛(默认 0.45;调低会让噪声通过)
?tools=fast 更短的工具菜单:更快,但准确度更低
?tod=fast · ?traffic=busy ?record=1 之外的录制节奏(=normal 在内部将其关闭)
?tod=night 从那个时间点开始(day、sunset、dusk、night 或 dawn)
?sfx=0 完全关闭游戏音效
?ec=0 · ?ns=0 · ?agc=0 关闭浏览器对麦克风的回声消除 / 噪声抑制 / 自动增益(默认开启:它们有助于防止游戏声音进入麦克风)
?resampler=own · ?resampler=browser 强制麦克风重采样到 16 kHz 的方式(默认:Chrome / Edge 用浏览器自带的,其他环境用我们的)
?brand=@yourhandle 角落里的一个小水印

开发者选项:?god=1(车辆不会撞毁)和 ?keepalive=1(在后台标签页中继续运行)。浏览器 控制台还有更多:见 docs/ARCHITECTURE.md。

Developer panel with ?dev=1: each decision with its latency, the decision log and phrases to try   Record mode in a 9:16 window: the game above, the sound wave and the command tiles below

左:?dev=1(来自一次测试运行的真实决策和延迟)。右:?record=1 在 9:16 窗口中。

键盘

按键 功能
V 麦克风开 / 关
T(配合 ?ptt=1) 按住说话
← → 或 A D 向左 / 向右一条车道
Shift + ← → 最左 / 最右(仅键盘和触摸按钮)
1 2 3 4 切换到该车道
↑ W / ↓ S 加速 / 刹车
Space / X 跳跃 / 闪避
Enter / P 开始或继续 / 暂停
M 游戏音效开 / 关

在触摸屏上,游戏下方会出现触摸按钮。用手机游玩需要自己在游戏服务器前搭建 HTTPS:server.mjs 只监听 127.0.0.1,而浏览器只允许在 https:// 或 localhost 上使用麦克风。

限制

  • 仅支持英语。
  • 使用合成语音测试。上述数字来自 macOS 文本转语音语音,而非真人。 在依赖它之前,请用自己的声音和麦克风试一试。
  • 麦克风中的游戏声音影响很大,尤其是光秃秃的“左”/“右”。请使用耳机。
  • 闲聊可能触发指令。即使有置信度门槛,测试中约 1/8 的闲聊或噪声片段触发了某些操作 (通常是暂停、闪避或变道),而且有些短语,比如“thanks for watching”,经常会触发闪避。 与人交谈时请静音麦克风(V)或使用按住说话。
  • 在桌面版 Chrome 中,浏览器引擎比原生引擎慢约 2 倍,在无法多线程运行的浏览器中则慢得多。主要在 macOS 的桌面版 Chrome 中开发和测试。

项目结构

index.html, styles.css        the page
server.mjs                    static server (127.0.0.1 only; COOP/COEP headers for multi-threaded WASM)
scripts/
  start.mjs                   npm start: the game server + the native engine
  remote-voice-server.mjs     the native voice engine (WebSocket), also for another machine
  vendor-ort.mjs              copies onnxruntime-web into vendor/ort/ (runs after npm install)
  check.mjs                   npm run check: smoke test, no microphone or audio files
src/
  main.js                     wiring: engine choice, microphone, voice events -> game actions
  game/                       the racer: world, traffic, sprites and font (all drawn in code), lighting, HUD,
                              synthesised sound effects
  ui/                         the voice panel (show-overlay.js; overlay.js is the ?dev=1 panel), layout,
                              title card, touch buttons, mock voice
  voice/                      NeuDecide in JavaScript: tokenizer, constrained decoding, inference core, Web Worker,
                              microphone capture, VAD, confidence gate, tool menu
models/README.md              how to get the model (the weights go in models/neudecide/, never in git)
docs/                         ARCHITECTURE.md, screenshots

没有构建步骤,也没有打包器:纯 ES 模块作为静态文件提供。

致谢

  • NeuDecide 由 Neuphonic 开发(Apache-2.0): 模型,以及这个 JavaScript 引擎移植自的 neudecide Python 包。
  • ONNX Runtime 由 Microsoft 开发(MIT):onnxruntime-web 和 onnxruntime-node。
  • SentencePiece 由 Google 开发(Apache-2.0):JavaScript 分词器移植自它。
  • llguidance 由 Microsoft 开发(MIT):约束解码器的强制 token 逻辑改编自其 toktrie。
  • ws(MIT)。
  • 所有游戏美术都是用代码绘制的原创像素画;所有音效都用 Web Audio 合成。

详情见 NOTICE。

Voice Racer 是一个独立项目,与 Neuphonic 无关联,也未获得其认可。NeuDecide 是 Neuphonic 的模型;此处使用该名称仅用于指代该模型。

许可证

Apache License 2.0。版权所有 2026 Vimal Anand。

NeuDecide 模型权重不属于本仓库,其使用受 Hugging Face 上各自条款的约束。

来源:Hacker News · github.com