A real-time, fully local math scribe. You dictate mathematics and it appears line-by-line as rendered LaTeX; you edit it by voice ("change e2 to x squared"), extend the pending equation piece by piece, type into any line with MathQuill, and commit/undo with spoken wake words. Every utterance you accept or reject becomes training data for GemmaApollo — a planned end-to-end audio→edit-action model fine-tuned from Gemma.
Nothing leaves your machine: ASR, LaTeX correction, VAD, and wake-word spotting all run on the local GPU (developed on 16 GB cards).
uv sync --extra dev # pure-logic dev (no models, mock engine)
uv run pytest # 48 tests, CPU-only
uv run scribe serve # http://127.0.0.1:8017, mock engine
# the real thing (first run downloads Whisper large-v3 + the corrector, ~4 GB)
uv sync --extra dev --extra s2l --extra audio
uv run scribe serve --engine s2l --mic
Open the page, then just talk:
The wake words (commit / undo / scratch-that) are custom openWakeWord models running continuously beside the VAD — they work even while the engine is busy and never fire mid-equation.
Mic ─► Silero VAD chunker (utterances, 0.5–10 s)
├─► openWakeWord spotters: commit/undo/scratch → app intents, instant
└─► Engine.process(audio, doc_context) → Action (JSON)
│
▼
DocState applies; the app owns commit/undo/history
Two engines implement one frozen contract (src/scribe/engine/base.py —
append_math | replace | insert | delete | set_label | text_reply | clarify):
Every processed utterance is logged as a training triple (audio + doc context
data/sessions/ — accepted
edits are positives, scratches are negatives, wake-word fires are audited.uv run scribe serve [--engine mock|s2l] [--mic] [--mic-device N] [--port 8017]
uv run scribe bench --engine s2l # per-stage latency + CER on fixture clips
uv run scribe mics # list audio input devices
uv run scribe mic-test --seconds 10 # console level/VAD tester
uv run pytest # schema/router/docstate/ws tests (no GPU)
The web UI includes a mic device dropdown and a live level/VAD test bar when
serving with --mic.
| Phase | ||
|---|---|---|
| 0–2 | env, contracts, DocState, ws server + UI | ✅ |
| 3 | real S2L engine + bench (1.06 s median e2e, 4.9 GB VRAM) | ✅ |
| 4 | live audio: VAD chunker + backend mic | ✅ |
| 5 | wake-word spotters, custom-trained locally | ✅ |
| — | mic select/tester · pending-equation composition | ✅ |
| 6 | training-data export (scribe export → JSONL) | next |
| 7 | eval harness + real-voice corpus | |
| 8 | GemmaEngine swap |
Full plan with acceptance criteria: PLAN.md.
src/scribe/ — server, DocState, router, engines, audio
(pure logic is torch-free and tested on CPU)frontend/index.html — single-file UI (KaTeX +
MathQuill), server-driven over ws with an offline local modePROTOCOL.md — the ws protocol (kept in sync with
server.py and the frontend)models/wakewords/ — trained spotter modelstools/wakewords/ + docs/wakeword-training.md
— reproducible wake-word training pipeline (WSL2) and its runbooktests/ — schema, router, DocState, chunker, spotter, ws protocolmarsianin500/* correction checkpoints)14 commits
Python
66.1%
HTML
26.7%
Shell
7.2%
A real-time, fully local math scribe. You dictate mathematics and it appears line-by-line as rendered LaTeX; you edit it by voice ("change e2 to x squared"), extend the pending equation piece by piece, type into any line with MathQuill, and commit/undo with spoken wake words. Every utterance you accept or reject becomes training data for GemmaApollo — a planned end-to-end audio→edit-action model fine-tuned from Gemma.
Nothing leaves your machine: ASR, LaTeX correction, VAD, and wake-word spotting all run on the local GPU (developed on 16 GB cards).
uv sync --extra dev # pure-logic dev (no models, mock engine)
uv run pytest # 48 tests, CPU-only
uv run scribe serve # http://127.0.0.1:8017, mock engine
# the real thing (first run downloads Whisper large-v3 + the corrector, ~4 GB)
uv sync --extra dev --extra s2l --extra audio
uv run scribe serve --engine s2l --mic
Open the page, then just talk:
The wake words (commit / undo / scratch-that) are custom openWakeWord models running continuously beside the VAD — they work even while the engine is busy and never fire mid-equation.
Mic ─► Silero VAD chunker (utterances, 0.5–10 s)
├─► openWakeWord spotters: commit/undo/scratch → app intents, instant
└─► Engine.process(audio, doc_context) → Action (JSON)
│
▼
DocState applies; the app owns commit/undo/history
Two engines implement one frozen contract (src/scribe/engine/base.py —
append_math | replace | insert | delete | set_label | text_reply | clarify):
Every processed utterance is logged as a training triple (audio + doc context
data/sessions/ — accepted
edits are positives, scratches are negatives, wake-word fires are audited.uv run scribe serve [--engine mock|s2l] [--mic] [--mic-device N] [--port 8017]
uv run scribe bench --engine s2l # per-stage latency + CER on fixture clips
uv run scribe mics # list audio input devices
uv run scribe mic-test --seconds 10 # console level/VAD tester
uv run pytest # schema/router/docstate/ws tests (no GPU)
The web UI includes a mic device dropdown and a live level/VAD test bar when
serving with --mic.
| Phase | ||
|---|---|---|
| 0–2 | env, contracts, DocState, ws server + UI | ✅ |
| 3 | real S2L engine + bench (1.06 s median e2e, 4.9 GB VRAM) | ✅ |
| 4 | live audio: VAD chunker + backend mic | ✅ |
| 5 | wake-word spotters, custom-trained locally | ✅ |
| — | mic select/tester · pending-equation composition | ✅ |
| 6 | training-data export (scribe export → JSONL) | next |
| 7 | eval harness + real-voice corpus | |
| 8 | GemmaEngine swap |
Full plan with acceptance criteria: PLAN.md.
src/scribe/ — server, DocState, router, engines, audio
(pure logic is torch-free and tested on CPU)frontend/index.html — single-file UI (KaTeX +
MathQuill), server-driven over ws with an offline local modePROTOCOL.md — the ws protocol (kept in sync with
server.py and the frontend)models/wakewords/ — trained spotter modelstools/wakewords/ + docs/wakeword-training.md
— reproducible wake-word training pipeline (WSL2) and its runbooktests/ — schema, router, DocState, chunker, spotter, ws protocolmarsianin500/* correction checkpoints)14 commits
Python
66.1%
HTML
26.7%
Shell
7.2%