Voice dictation for your whole desktop — a from-scratch recreation of Wispr Flow. Hold a hotkey and speak: your words are transcribed locally with Whisper and typed live into whatever app has focus, formatting themselves as you talk. Works in your editor, browser, terminal, Slack — anywhere you can type.
Everything runs on your machine. Audio never leaves it.
hold hotkey ──▶ mic ──▶ Whisper (local, every ~1.5s) ──▶ format ──▶ live-typed into the focused app
└─ self-corrects as the transcript firms up
release ──▶ final accurate pass ──▶ reconciled, punctuated, capitalized text
- Live streaming — while you speak, the accumulated audio is re-transcribed every ~1.5 seconds and typed at your cursor. When Whisper revises its hypothesis, Wisperflow backspaces over the changed tail and retypes it — the text visibly edits itself as you talk. On release, a final beam-search pass reconciles everything.
- Formatting as you speak — filler words (um, uh, er) removed, punctuation spacing and sentence capitalization fixed, applied live on every refresh.
- Self-correction — say "scratch that" to delete what you just said (the interrupted clause, or the previous sentence).
- Spoken commands — "new line", "new paragraph", and spoken emails: "john at gmail dot com" →
john@gmail.com. - Custom dictionary — teach it words Whisper gets wrong (
{"jason file": "JSON file"}). - Optional AI polish — with
ai_formatenabled, the final transcript gets a light copy-edit from the Claude API (homophones, punctuation) while preserving your words. Off by default; transcript text only, never audio. - History — transcripts logged locally to
~/.local/share/wisperflow/history.jsonl(optional).
Transcription is faster-whisper with voice-activity filtering; live passes use greedy decoding for latency, the final pass uses beam search for accuracy.
Requires Python 3.10+.
git clone https://github.com/hy0ren/wisperflow
cd wisperflow
pip install . # add: pip install .[ai] for the optional Claude formatting passGrant your terminal app all of these in System Settings → Privacy & Security:
- Microphone — to record you
- Accessibility and Input Monitoring — for the global hotkey and for typing into other apps
Works on X11. Wayland restricts global key listening and synthetic input; use an X11 session or a compositor that allows it.
wisperflowHold right Option/Alt (alt_r) and speak — text appears at your cursor as you talk. Release to finalize. The first run downloads the Whisper model (~150 MB for base).
wisperflow — local push-to-talk dictation
model: base · language: en · mode: streaming (live)
hold [alt_r] to dictate, release to type. Ctrl+C quits.
typed: "This is so much faster than typing." — waiting for hotkey
wisperflow # start dictating (live streaming)
wisperflow --batch # insert text all at once after you release instead
wisperflow --model small # more accurate model for this run
wisperflow --mode toggle # press once to start, again to stop
wisperflow config # print config path + current settings
wisperflow devices # list microphones
wisperflow history # show recent transcriptswisperflow config creates ~/.config/wisperflow/config.json:
| key | default | meaning |
|---|---|---|
hotkey |
"alt_r" |
pynput key name (alt_r, ctrl_r, cmd_r, f8, or a character) |
mode |
"hold" |
hold (push-to-talk) or toggle |
model |
"base" |
tiny / base / small / medium / large-v3 |
language |
"en" |
language code, or "auto" to detect |
streaming |
true |
type live while you speak; false = insert after release |
stream_interval |
1.5 |
seconds between live transcript refreshes |
inject |
"paste" |
batch mode only: paste (fast) or type (keystrokes) |
remove_fillers |
true |
strip um / uh / er |
spoken_commands |
true |
"new line", "new paragraph", "scratch that", spoken emails |
dictionary |
{} |
replacements for words Whisper mishears, e.g. {"jason file": "JSON file"} |
ai_format |
false |
Claude API copy-edit of the final transcript (needs pip install .[ai] + ANTHROPIC_API_KEY) |
trailing_space |
true |
append a space so phrases chain naturally |
save_history |
true |
keep a local transcript log |
input_device |
null |
mic index from wisperflow devices |
While dictating you can say:
- "new line" → line break
- "new paragraph" → blank line
- "scratch that" → deletes what you just said
- "[name] at [domain] dot com" → a real email address
Live streaming re-transcribes the whole utterance each refresh, so smaller models stream more smoothly. base is a good default on Apple Silicon; use small+ if accuracy matters more than live latency, or --batch for long dictations with a big model.
| model | size | speed | notes |
|---|---|---|---|
tiny |
75 MB | fastest | very smooth streaming, fine for short phrases |
base |
145 MB | fast | good default |
small |
480 MB | medium | noticeably more accurate |
medium |
1.5 GB | slow | consider --batch |
large-v3 |
3 GB | slowest | best available; use --batch |
wisperflow/
app.py — the dictation loop
streamer.py — live streaming: re-transcribe + diff + backspace/retype
cli.py — argument parsing and subcommands
config.py — JSON config at ~/.config/wisperflow/
recorder.py — microphone capture (sounddevice)
transcriber.py — local Whisper (faster-whisper)
formatter.py — fillers, spoken commands, scratch-that, dictionary
ai_formatter.py — optional Claude API polish (off by default)
injector.py — type/backspace/paste into the focused app (pynput)
hotkey.py — global hold/toggle hotkey listener
history.py — local jsonl transcript log
tests/
test_formatter.py
python tests/test_formatter.py # or: python -m pytest tests/MIT