Full‑duplex realtime voice assistant in your browser with jax‑js
9
stars
34
commits
TypeScript
primary language
Aug 19, 2026
updated
A real-time, full-duplex voice assistant that runs entirely in your browser on WebGPU, built with jax-js.
Every stage (speech → ASR → LLM → TTS → speech, plus optional vision) runs locally in the tab; nothing is sent to a server.
It's inspired by the Thinking Machines interaction model and GPT-Live, rebuilt as a small-model cascade that fits in a browser tab. The goal is a conversation that feels live: you can interrupt it mid-sentence, pause mid-thought without losing your turn, and it keeps searching in the background while you talk.
| Stage | Model | Runs on |
|---|---|---|
| Ear (ASR) | Whisper base.en (int8, dequantized to fp16) | WebGPU via jax-js |
| Turn-taking (VAD) | Silero VAD v5, ported to TypeScript | CPU (~2 ms / 32 ms frame) |
| Brain (LLM) | SmolLM2-360M-Instruct (fp16) | WebGPU via jax-js |
| Voice (TTS) | Kyutai Pocket TTS + Mimi codec (fp16) | WebGPU via jax-js |
| Eye (vision) | D-FINE small (COCO-80) | WebGPU via @jax-js/onnx |
Everything shares the single WebGPU device. The streaming ASR lane is paused while the assistant speaks so it doesn't contend with TTS for the GPU; barge-in is therefore energy-based (see below), and captions resume the moment the assistant stops.
The turn-latency floor is set by the single GPU, so the work went into cutting
GPU cost per token/frame rather than overlapping stages (which a single device
can't do; see docs/BENCHMARKS.md for the full
map-reduce campaign log, including the negative results):
Runtime behaviour is tunable at src/tunables.ts (read live, so A/B
experiments don't need a rebuild).
npm install
npm run dev
Open http://localhost:5173 in a WebGPU-capable browser (Chrome/Edge on desktop, Safari 26+). Click Load models: ~1.0 GB on first run, cached in OPFS afterwards. The Eye is on by default and requests camera access; uncheck it before loading to skip it. Then press the orb once and just talk, hands-free. Press it again to end.
Weights come from Hugging Face: SmolLM2 at full fp16 for conversation quality, Whisper as a per-row int8 build dequantized at load (it transcribes the bench suite identically to fp16).
The pipeline stages, from microphone to speaker:
| Path | What's there |
|---|---|
src/mic.ts | 16 kHz PCM capture via an AudioWorklet. |
src/asr/ | Whisper encoder/decoder and features. streaming.ts transcribes live (LocalAgreement-2: words lock in once two passes agree) and filters out the assistant's own voice. vad.ts is the Silero VAD v5 port. |
src/llm/smollm.ts | SmolLM2-360M forward pass with a KV cache: one fused GPU dispatch per token, bucket-padded prefill so jit traces are reused across turns. |
src/memory.ts | Extraction and deterministic recall of facts the user shared. |
src/tts/ | Pocket TTS flow-matching LM + the Mimi codec on jax-js, streamed to an AudioContext player. src/sentence-split.ts chunks reply text at clause boundaries for synthesis. |
src/vision/ | D-FINE detector on @jax-js/onnx, webcam VisionSession, COCO labels, box-dedupe and person-count smoothing. |
src/tools/tools.ts | Keyless intent detection → weather / Wikipedia / calc / clock. |
MIT. Model inference code is adapted from the jax-js repository by Eric Zhang (MIT licensed); model weights remain under their respective licenses.
29 commits
5 commits
TypeScript
96.6%
CSS
3.3%
Full‑duplex realtime voice assistant in your browser with jax‑js
9
stars
34
commits
TypeScript
primary language
Aug 19, 2026
updated
A real-time, full-duplex voice assistant that runs entirely in your browser on WebGPU, built with jax-js.
Every stage (speech → ASR → LLM → TTS → speech, plus optional vision) runs locally in the tab; nothing is sent to a server.
It's inspired by the Thinking Machines interaction model and GPT-Live, rebuilt as a small-model cascade that fits in a browser tab. The goal is a conversation that feels live: you can interrupt it mid-sentence, pause mid-thought without losing your turn, and it keeps searching in the background while you talk.
| Stage | Model | Runs on |
|---|---|---|
| Ear (ASR) | Whisper base.en (int8, dequantized to fp16) | WebGPU via jax-js |
| Turn-taking (VAD) | Silero VAD v5, ported to TypeScript | CPU (~2 ms / 32 ms frame) |
| Brain (LLM) | SmolLM2-360M-Instruct (fp16) | WebGPU via jax-js |
| Voice (TTS) | Kyutai Pocket TTS + Mimi codec (fp16) | WebGPU via jax-js |
| Eye (vision) | D-FINE small (COCO-80) | WebGPU via @jax-js/onnx |
Everything shares the single WebGPU device. The streaming ASR lane is paused while the assistant speaks so it doesn't contend with TTS for the GPU; barge-in is therefore energy-based (see below), and captions resume the moment the assistant stops.
The turn-latency floor is set by the single GPU, so the work went into cutting
GPU cost per token/frame rather than overlapping stages (which a single device
can't do; see docs/BENCHMARKS.md for the full
map-reduce campaign log, including the negative results):
Runtime behaviour is tunable at src/tunables.ts (read live, so A/B
experiments don't need a rebuild).
npm install
npm run dev
Open http://localhost:5173 in a WebGPU-capable browser (Chrome/Edge on desktop, Safari 26+). Click Load models: ~1.0 GB on first run, cached in OPFS afterwards. The Eye is on by default and requests camera access; uncheck it before loading to skip it. Then press the orb once and just talk, hands-free. Press it again to end.
Weights come from Hugging Face: SmolLM2 at full fp16 for conversation quality, Whisper as a per-row int8 build dequantized at load (it transcribes the bench suite identically to fp16).
The pipeline stages, from microphone to speaker:
| Path | What's there |
|---|---|
src/mic.ts | 16 kHz PCM capture via an AudioWorklet. |
src/asr/ | Whisper encoder/decoder and features. streaming.ts transcribes live (LocalAgreement-2: words lock in once two passes agree) and filters out the assistant's own voice. vad.ts is the Silero VAD v5 port. |
src/llm/smollm.ts | SmolLM2-360M forward pass with a KV cache: one fused GPU dispatch per token, bucket-padded prefill so jit traces are reused across turns. |
src/memory.ts | Extraction and deterministic recall of facts the user shared. |
src/tts/ | Pocket TTS flow-matching LM + the Mimi codec on jax-js, streamed to an AudioContext player. src/sentence-split.ts chunks reply text at clause boundaries for synthesis. |
src/vision/ | D-FINE detector on @jax-js/onnx, webcam VisionSession, COCO labels, box-dedupe and person-count smoothing. |
src/tools/tools.ts | Keyless intent detection → weather / Wikipedia / calc / clock. |
MIT. Model inference code is adapted from the jax-js repository by Eric Zhang (MIT licensed); model weights remain under their respective licenses.
29 commits
5 commits
TypeScript
96.6%
CSS
3.3%