WhisperWoof · The full guide

How Mando listens

What happens between you speaking and text landing in your app: what each speech model actually does, where your own words get in, and how Memory learns from the fixes you make.

Mando thinking
01 · Follow one sentence through

The pipeline, one sentence at a time

Pick an engine, and whether Memory already knows your words. The transcripts are real outputs from the local engines, fed synthetic speech from macOS say.

“Please deploy the dashboard to Supabase and ping Kubernetes on Vercel.”

Engine
Memory
02 · What's inside the engines

Two families of speech models

Every engine turns sound into text, but they're built very differently, and that difference decides whether your words can be “suggested” to it before it listens.

Whisper

encoder → decoder that writes text

Chops audio into 30-second windows, turns each into a spectrogram, and an encoder summarises it. A decoder, a small language model, then writes the transcript one token at a time, each guess conditioned on the text before it.

Takes hints?
Yes. “Previous text” can be pre-filled: that's the prompt.
Languages
~100, detected per recording
Runs as
whisper-server (whisper.cpp), or cloud APIs
Streaming?
No: waits for the whole recording

Transducers: Parakeet, X-ASR

encoder → frame-by-frame token predictor

Walks through the audio frame by frame and, at each step, emits a token or moves on. Parakeet's TDT also predicts how many frames to skip, which is why it's fast. There is no “previous text” input, so there's nowhere to put a prompt.

Takes hints?
No. sherpa “hotwords” exist but had no effect on Parakeet (measured, below).
Languages
Parakeet v3: 25 European · X-ASR: Chinese + English
Runs as
sherpa-onnx websocket servers (offline, and online for live typing)
Streaming?
X-ASR yes (160 / 480 ms chunks) · Parakeet whole recording

SenseVoice

encoder → all tokens at once (non-autoregressive)

Predicts the whole transcript in one pass rather than word by word, with language set to auto and number formatting (“twenty” → 20) built in. Very fast; like the transducers, it has no text context to steer.

Takes hints?
No.
Languages
Chinese, Cantonese, English, Japanese, Korean
Runs as
sherpa-onnx offline server
Streaming?
No

Why a prompt works on Whisper: it's just “text that came before”

<|startofprev|> Mando, Kubernetes, Supabase <|startoftranscript|> <|en|> <|transcribe|> → Please deploy … Supabase …

The decoder has just “read” your words, so when the audio sounds like “super base”, the spelling it saw a moment ago is the likely next token. The language token (<|en|>) is guessed before your words are added, so hints don't sway language detection: we measured the same 0.998 “Chinese” confidence with and without a prompt. Hints can still pull the writing toward English, which is what section 07 guards against.

03 · Model files and word lists

Your two libraries

The model library is the set of downloaded model files: Whisper's ggml-*.bin in ~/.cache/openwhispr/whisper-models/, and Parakeet, X-ASR and SenseVoice under parakeet-models/. They never change as you use the app. Everything personal lives in the word library, which has three shelves:

ShelfWho fills itStored inWhat it holds
Memory Learned from your fixes, or added in the Memory view whisperwoof-vocabulary.json The right spelling and how it was misheard (“alternatives”), how often each fix happened, and which apps you use it in.
Dictionary You (Settings → Dictionary); auto-learn also adds new words SQLite custom_dictionary Plain words. Also shown to the polish model.
Word Packs Curated lists shipped with the app. Off by default since 1.22.0. resources/vocabulary-packs/ Brands & Products, Everyday Essentials, Food & Drink (266 words).

With encryption on (Settings → Encryption), Memory is stored encrypted as whisperwoof-vocabulary.json.wwenc and the SQLite database is encrypted too. Word Packs ship with the app and hold nothing personal.

Why packs are off now. Generic words in every prompt pull Whisper toward them. With Brands & Products on, “Vercel” came out as “Versacell” (from “Versace”). Turn on the packs you actually talk about.

04 · Hints, swaps, polish

Three ways your words reach the text

  • Hints go into the model before it listens (Whisper's prompt). Best result, but only Whisper accepts them.
  • Swaps happen after the model: Memory replaces a mishearing you've approved (“super base” → Supabase). Works with every engine.
  • Polish is the local LLM clean-up pass; it sees your Dictionary words as a list and can fix obvious near-misses.
EngineHintsSwapsPolish
Whisper, localwhisper-serverYespinned language, or Auto with the guard in 07YesYes
Parakeet TDTNohotwords measured: no effectYesYes
X-ASR (live typing), SenseVoiceNoYeson the final textYes
Cloud, batchOpenAI · Groq · MistralYesYesYes
OpenWhispr Cloud, streaming providersPartlystreaming gets the Dictionary onlyNot yetYes
05 · The most important number: 224

The 224-token window

Whisper reads at most 224 tokens of prompt and keeps the last 224, silently dropping the start. A token is a word-piece; for these word lists it's about 3 characters. Token counts below come from whisper.cpp's own tokenizer run on the real word lists.

MemoryDictionaryWord Packmisheard spelling

06 · From your fix to a rule

How Memory learns

  • Watch. After a paste, a small native helper (macos-text-monitor, needs Accessibility) watches that text field for 30 seconds.
  • Compare. Each time you pause typing (1.5 s), the field is compared word by word with what was pasted. Each changed stretch is trimmed to the part that sounds alike, giving a pair: misheard → corrected. Words you typed next to the fix (“Supabase today”) aren't part of it.
  • Filter. Rewrites (more than half the words changed), unrelated swaps (the words don't sound alike) and fixes under 3 letters are ignored.
  • Remember. The pair is saved on the Memory word, tagged with the app you were in. A half-typed fix is replaced by the finished one, and new words also go into the Dictionary (so Whisper gets them as hints).
  • Ask. Once you've made the same fix twice, and the misheard text couldn't be something you really said, Memory asks: “Always change super base to Supabase?” Say Always and every engine gets it right from then on. Say Not now, or change a swapped word back, and Memory never asks again.
Examples

Why ask? A swap edits every future transcript, so one wrong rule does damage everywhere. Memory only offers a swap when it's a pattern (the same fix twice) and the misheard text couldn't be something you really said: “Superbase” and “shunade” aren't words, while “their”, “bills”, “10” and “a team” are, so those are never offered, though the fixed word still goes into your Dictionary and hints. And even then, nothing is swapped until you say so. The app checks single words against the Mac's 235,000-word dictionary; this demo uses a small built-in list.

07 · Bilingual dictation

Hints in Auto language mode

With the dictation language on Auto, an English word list once turned Chinese speech into an English translation: a clip of “现在天气很好” came out as “Now the time is good”. So hints used to be switched off entirely in Auto mode. Now they're on, with a guard that uses the one thing hints can't sway: Whisper's language detection.

08 · For developers

Where it lives in the code

PieceFile
Every transcript goes through here: swaps, then polishsrc/helpers/audioManager.js · processTranscription
Hint prompt: priority, 560-char budget, your words lastsrc/whisperwoof/core/vocabulary/pack-manager-pure.js · buildSttPrompt
Swap rules and applying themsrc/whisperwoof/core/vocabulary/memory-replacements.js
Finding misheard → corrected pairssrc/utils/correctionLearner.js · extractCorrectionPairs
Memory storage (learn, undo, delete)src/whisperwoof/bridge/vocabulary.js + vocabulary-pure.js
Watching the pasted fieldsrc/helpers/textEditMonitor.js + resources/macos-text-monitor.swift
Auto-mode guardsrc/whisperwoof/core/language/auto-hints.ts
Learning glue, undo, delete syncsrc/helpers/ipcHandlers.js · _learnCorrections, _getSttHintPrompt
How these numbers were measured
  • Whisper prompt tokens counted with whisper.cpp's tokenizer on the ggml-base vocabulary: about 2.97 characters per token for these word lists.
  • Transcripts from whisper-server (ggml-base, Auto language) and sherpa-onnx 1.13.4 (Parakeet TDT 0.6B v3), fed macOS say audio. Real voices vary more; the patterns hold.
  • Parakeet with --decoding-method=modified_beam_search --hotwords-file, score up to 5: “Superbase” unchanged.
WhisperWoof, built on OpenWhispr. Named after a good dog. Home · GitHub