Offline voice dictation & voice assistant for Windows β paste text anywhere, manage notes & reminders hands-free, and speak symbols & code directly (say forward slash, dash, one two three β / - 123).
π getwrither.com Β· β¬οΈ Download Β· π¬ Demo video
- π Visible first-launch feedback β the widget now appears right away with a "Downloading speech modelβ¦" status and animated loading eyes while the model loads, then confirms "Ready β hold βΉyour hotkeyβΊ". No more silent minutes where the app looked dead.
- π Welcome toast β the very first launch ends with a Windows notification explaining both hotkeys. If the model download fails (no internet on first launch), a clear error state and toast tell you what to do.
- π Second-instance toast β launching WritHer twice now shows "WritHer is already running" instead of exiting silently.
- π Custom vocabulary β teach WritHer to render your spoken jargon or acronyms as their written form. Case-insensitive whole-word matching, multi-word spoken forms supported. Priming terms also feed faster-whisper's
initial_promptto nudge recognition. - π’ Symbol & spelling mode (opt-in) β enable in Settings and say "forward slash", "dash", "semicolon", or number words to get actual characters. Spell code letter-by-letter: "W H forward slash F A T" β
WH/FAT. Contractions (don't,we're) stay intact and prose is never mangled. - π Recognition language dropdown β pick Whisper's language independently of the UI:
Auto(default),en,it,de. The detected language is logged for every clip. - π Clipboard restore (default) β your clipboard is saved before paste and restored after. Optional toggle keeps the transcript in the clipboard for re-pasting.
- π Single-instance lock (per-session) β launching a second copy exits immediately. Now scoped to the current Windows user so it does not block other users on the same machine.
- π¨ Per-mode colour themes β dictation widget renders in cyan, assistant in violet.
- β¨οΈ Combo hotkeys β assistant hotkey is now
Ctrl+Alt+R(avoids browser conflicts). Settings window captures live key combos. - π Log viewer in Settings β tail the latest log lines directly from the Settings window.
- ποΈ Delete by voice - say "delete the dentist appointment" or "remove the shopping list" and WritHer finds and removes it. Voice confirmation required before any deletion (15s timeout).
- β¨οΈ Customizable hotkeys - change dictation and assistant shortcuts from Settings. Press the β¨ button, hit any key, done. No restart needed.
- ποΈ Microphone selection - pick your input device from Settings, with hot-plug refresh
- π Toggle recording mode - press once to start, press again to stop (alternative to hold)
- β±οΈ Safety timeout - auto-stops recording in toggle mode if you forget
- π¨ Redesigned UI - CustomTkinter with unified Pandora Blackboard theme (pure black + bright white)
- π₯οΈ Resizable Notes window - drag to resize, maximize/restore, DPI-aware
- β‘ Faster Ollama responses - timeout increased from 10s to 30s for larger models
- π Bug fixes - clean shutdown, widget positioning, visual artifacts removed
- π Reliable mic switching - select any microphone (USB, Bluetooth, AirPods) from Settings and switch on the fly without restart. Tested with Bluetooth HFP devices.
- π¦ Standalone exe - download and run, no Python installation required. Whisper model downloads automatically on first launch.
- βοΈ Full Settings panel - Ollama model/URL, Whisper model, language, microphone, recording mode - all configurable from the tray menu.
- π― Toggle mode fix - resolved issue where Ctrl+Alt+R required double-press to start recording. Added debounce to prevent key-repeat interference.
- π€ Sample rate fix - microphones with 48kHz default (e.g. Logitech C310) now work correctly. Audio is recorded at 16kHz when possible, resampled if not.
- π Portable data paths - database, logs, and recovery files stored in %APPDATA%/WritHer when running as exe, preventing permission issues.
- β Cleaner widget feedback - assistant confirmations show minimal icons instead of long text that overflowed the widget.
π¬ Feedback welcome! If you test WritHer with different microphones or setups, please open an issue and let us know how it goes. Your feedback helps improve the app for everyone.
WritHer sits quietly in your system tray and gives you two super-powers:
| Mode | Hotkey (default) | What it does |
|---|---|---|
| Dictation | AltGr |
Transcribes your voice and pastes the text directly into whichever app has focus - editors, browsers, chat windows, anything. Optional Symbol & spelling mode substitutes spoken symbols and digits. |
| Assistant | Ctrl+Alt+R |
Understands natural-language commands and saves notes, creates appointments, sets reminders, manages lists - all by voice. |
Both hotkeys are fully customizable from the Settings window, click the β¨ button next to each shortcut and press your preferred key. The change takes effect immediately, no restart required.
Both hotkeys support two recording modes, configurable from the Settings window in the system tray:
| Recording mode | How it works |
|---|---|
| Hold (default) | Hold the key to record, release to stop. |
| Toggle | Press once to start recording, press again to stop. A configurable safety timeout auto-stops the recording if you forget. |
Everything runs locally: speech recognition via faster-whisper, intent parsing via Ollama, and data stored in a local SQLite database. No cloud, no API keys, no telemetry.
- Real-time dictation - speak and text appears. Supports both hold-to-record and toggle (press to start/stop) modes. Clipboard is saved and restored automatically (opt-in toggle to keep the transcript in the clipboard).
- Custom vocabulary - a user-defined map of
spoken form β written form, applied whole-word and case-insensitively before any symbol substitution. Multi-word spoken forms and longest-first precedence are supported. Editable from Settings and persisted in the SQLite DB. - Priming terms - a free-text list joined into faster-whisper's
initial_promptto bias recognition toward domain terms. Labelled best-effort in the UI hint. - Symbol & spelling mode (opt-in) - toggle in Settings. When ON, spoken symbol names and number words are substituted ("W H forward slash F A T" β
WH/FAT, "one two three" β123, "semicolon" β;) and letter-by-letter spelling is glued. Contractions likedon'tare preserved and prose is never mangled: multi-character words on either side of a symbol block gluing. - Recognition language - independent of the UI language. Set to
Auto(default) to let Whisper detect each clip, or pin toen/it/de. - Voice-controlled assistant - save notes, create shopping/todo lists, schedule appointments, set reminders, and delete items by voice. All through natural speech.
- Voice delete with confirmation - say "delete the shopping list" or "remove the dentist appointment". WritHer finds the item by keyword and asks for voice confirmation before deleting. 15-second timeout for safety.
- Smart date parsing - say "remind me tomorrow at 9" or "meeting next Monday at 3pm" and the LLM converts relative times to absolute datetimes.
- Toast notifications - get Windows notifications when reminders fire or appointments are approaching.
- Animated floating widget - a minimal pill-shaped overlay with expressive "Pandora Blackboard" eyes that react to state (listening, thinking, happy, error, etc.). Cyan for dictation, violet for assistant.
- Notes & Agenda window - a dark-themed resizable window to browse, check off list items, and delete notes/appointments/reminders. Supports maximize/restore and drag-to-resize.
- Settings window - configure recording mode, max recording duration, keyboard shortcuts, and microphone device directly from the system tray. All settings are persisted across restarts.
- Customizable combo hotkeys - reassign dictation and assistant keys (including multi-key combos like
Ctrl+Alt+R) from the Settings window. Blocked keys are rejected, duplicate detection prevents conflicts. - Microphone selection - choose your input device from a dropdown in Settings. Supports hot-plug detection with a refresh button - no restart needed.
- Single-instance protection - a per-session mutex prevents two copies running at once, eliminating the double-paste bug.
- Modern UI - built with CustomTkinter and a unified "Pandora Blackboard" theme (pure black + bright white) defined in a single
theme.pyfile. - Multi-language UI - ships with English, Italian and German; easy to add more via the
locales.pystring table. - Log viewer - the Settings window tails the latest lines of
writher.logfor quick diagnostics. - Fully offline - no internet required after model download.
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β main.py β
β (orchestrator + Tk event loop) β
ββββββββββββ¬ββββββββββββ¬ββββββββββββ¬ββββββββββββββββββββ€
β hotkey β recorder β widget β tray_icon β
β listener β (audio) β (overlay) β (system tray) β
ββββββββββββ΄ββββββββββββ΄ββββββββββββ΄ββββββββββββββββββββ€
β β
β Dictation pipeline Assistant pipeline β
β βββββββββββββ βββββββββββββ β
β βtranscriberβ βtranscriberβ β
β β (Whisper) β β (Whisper) β β
β βββββββ¬ββββββ βββββββ¬ββββββ β
β βΌ βΌ β
β replacements.py assistant β
β (user vocab + (Ollama LLM β
β opt-in symbols) + function calls) β
β β β β
β βΌ βΌ β
β injector database β
β (clipboard (SQLite) β
β + Ctrl+V) β β
β notifier β
β (toast scheduler) β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
- Windows 10/11
- A working microphone
- Internet connection on first launch (to download the Whisper speech model)
- Ollama installed and running locally (only required for assistant mode; dictation works without it)
Ollama setup: download and install from ollama.com, then pull the configured model, for example:
ollama pull llama3.1:8bOllama runs as a background service on Windows. If the assistant hotkey is triggered while Ollama is not reachable, WritHer shows a toast notification and aborts the request β dictation is unaffected.
- Download
WritHer-v1.3.1-win64.zipfrom the latest release - Extract to any folder
- Install and start Ollama (only needed for assistant mode)
- Run
WritHer.exe - On first launch, the Whisper model is downloaded automatically
- Right-click the tray icon for Settings and Notes & Agenda
git clone https://github.com/benmaster82/writher.git
cd writherpython -m venv venv
venv\Scripts\activateRequires Python 3.11+
pip install faster-whisper numpy sounddevice pynput pystray Pillow requests winotify customtkinterOptional: install
plyeras a fallback notification backend:pip install plyer
python main.pyWrither appears in the system tray. Hold AltGr to dictate, hold Ctrl+Alt+R for assistant commands. Make sure Ollama is running (ollama serve or the installed service) before invoking the assistant.
All settings live in config.py:
# Hotkeys (defaults β can be changed from Settings at runtime)
HOTKEY = Key.alt_gr # Dictation
ASSISTANT_HOTKEY = (frozenset({"ctrl", "alt"}), KeyCode.from_vk(82)) # Ctrl+Alt+R
# UI language ("en", "it" or "de") β controls interface strings only.
LANGUAGE = "en"
# Recognition language (Whisper). None = per-clip auto-detect.
WHISPER_LANGUAGE = None
# Clipboard behaviour after paste. False = restore previous clipboard.
KEEP_TRANSCRIPT_IN_CLIPBOARD = False
# Recording mode
HOLD_TO_RECORD = True # True = hold key, False = toggle (press/press)
MAX_RECORD_SECONDS = 120 # Safety timeout for toggle mode (seconds)
# Microphone
MIC_DEVICE_NAME = None # None = system default, or device name (str)
# Whisper
MODEL_SIZE = "small" # tiny, base, small (default), medium, large-v3
DEVICE = "cpu" # "cpu" or "cuda"
COMPUTE_TYPE = "int8" # int8, float16, float32
# Ollama
OLLAMA_URL = "http://localhost:11434"
OLLAMA_MODEL = "llama3.1:8b"
# Notification lead time
APPOINTMENT_REMIND_MINUTES = 15Note:
HOLD_TO_RECORD,MAX_RECORD_SECONDS,MIC_DEVICE_NAME,HOTKEY, andASSISTANT_HOTKEYcan also be changed at runtime from the Settings window in the system tray. Changes made there are persisted in the database and overrideconfig.pydefaults.
| Model | Size | Speed | Accuracy |
|---|---|---|---|
tiny |
39 MB | β‘ fastest | basic |
base |
74 MB | β‘ fast | good |
small |
244 MB | moderate | better (default) |
medium |
769 MB | slower | great |
large-v3 |
1.5 GB | slowest | best |
The
smallmodel is the default because it handles symbol and code spelling (e.g. "forward slash") reliably. Thebasemodel can mishear multi-word phrases and is not recommended for code dictation.
For CUDA acceleration, install ctranslate2 with CUDA support and set DEVICE = "cuda".
Hold mode (default):
- Focus any text field (editor, browser, chatβ¦)
- Hold
AltGr - Speak
- Release - transcribed text is pasted automatically
Toggle mode:
- Focus any text field
- Press
AltGronce to start recording - Speak
- Press
AltGragain to stop - transcribed text is pasted automatically
In toggle mode, a safety timeout (configurable in Settings) will auto-stop the recording if you forget to press the key again.
Off by default. Enable the toggle in Settings to substitute spoken symbol names and number words, and to glue letter-by-letter spelling. Prose stays intact β the spacing compaction only fires when both neighbours of a symbol are single characters or digit sequences, so "The 100 meter dash was thrilling" becomes "The 100 meter - was thrilling" rather than gluing across words. Contractions like don't and we're are always preserved.
| You say | You get |
|---|---|
forward slash |
/ |
back slash |
\ |
dash / hyphen / minus |
- |
semicolon |
; |
colon |
: |
double colon |
:: |
underscore |
_ |
asterisk |
* |
at sign |
@ |
hash sign |
# |
open bracket / close bracket |
( / ) |
open curly / close curly |
{ / } |
open square / close square |
[ / ] |
new line |
β΅ |
one two three β¦ nine |
1 2 3 β¦ 9 |
Spell code identifiers letter-by-letter and spaces are removed automatically:
- "W H F A T" β
WHFAT - "W H forward slash F A T" β
WH/FAT - "one two three dash four five six" β
123-456
Hold mode (default):
- Hold
Ctrl+Alt+R - Speak a command
- Release - Writher processes and confirms
Toggle mode:
- Press
Ctrl+Alt+Ronce to start recording - Speak a command
- Press
Ctrl+Alt+Ragain to stop - Writher processes and confirms
Example commands:
- "Save a note: remember to buy milk"
- "Create a shopping list: bread, eggs, butter, coffee"
- "Add pasta to the shopping list"
- "Appointment with the dentist tomorrow at 3pm"
- "Remind me to call Marco in one hour"
- "Show me my notes"
- "Show my agenda"
- "Delete the dentist appointment"
- "Remove the shopping list"
- "Delete the reminder about Marco"
Right-click the tray icon to access:
- Notes & Agenda - open the notes/appointments/reminders viewer
- Settings - configure recording mode (hold vs toggle), max recording duration, keyboard shortcuts, and microphone device
- Quit - exit WritHer
Tip: Windows may hide the tray icon in the overflow area (the ^ arrow). To keep it always visible, go to Settings β Personalization β Taskbar β Other system tray icons and enable WritHer.
- Open
locales.py - Add a new entry to the
_STRINGSdictionary (copy"en"as a template) - Set
LANGUAGEinconfig.pyto your language code
writher/
βββ main.py # Entry point and orchestrator
βββ config.py # All user-configurable settings
βββ hotkey.py # Dual-hotkey listener with hold/toggle modes (pynput)
βββ hotkey_util.py # Hotkey serialisation, display names, and validation
βββ recorder.py # Microphone recording (sounddevice)
βββ transcriber.py # Speech-to-text (faster-whisper)
βββ replacements.py # Two-layer post-processing (user vocab + opt-in symbols)
βββ injector.py # Clipboard paste into active app (Win32 API)
βββ assistant.py # Ollama LLM integration + function calling
βββ database.py # SQLite storage (notes, appointments, reminders, settings)
βββ notifier.py # Toast notifications + reminder/appointment scheduler
βββ widget.py # Floating pill overlay with animated eyes
βββ notes_window.py # Notes/Agenda/Reminders viewer window (CustomTkinter)
βββ settings_window.py # Settings window (CustomTkinter)
βββ tray_icon.py # System tray icon (pystray)
βββ brand.py # "Pandora Blackboard" icon renderer
βββ theme.py # Unified colour palette and font definitions
βββ locales.py # i18n string tables (EN, IT, DE)
βββ paths.py # Data-directory resolution (source vs frozen exe)
βββ logger.py # Rotating file + console logger
βββ debug_keys.py # Key event debugger utility
βββ test_delete.py # Unit tests for voice-delete feature
βββ test_replacements.py # Regression tests for the two-layer replacement engine
βββ test_hotkey.py # Hotkey serialisation + conflict detection tests
βββ requirements.txt # Python dependencies
βββ img/
β βββ logo_writher.png # Logo for README
βββ LICENSE
AltGr not detected?
Run python debug_keys.py to see exactly what pynput reports for your keyboard. Some keyboard layouts map AltGr differently.
Ollama not reachable?
WritHer expects Ollama to be running locally. Start it with ollama serve (or via the installed Windows service), then verify the URL in Settings matches. When you trigger assistant mode with Ollama down, WritHer shows a toast notification and flashes the widget in the error state β dictation continues to work.
No audio / microphone not found? WritHer uses the system default input device unless you select a specific one in Settings. If the widget shows "π€ No microphone detected", check your Windows sound settings. You can also open Settings from the tray and use the microphone dropdown to pick the correct device. Hit the β³ button to refresh the list if you just plugged in a new mic.
"No speech detected" but microphone works? This usually means Whisper received audio but couldn't recognize speech. Common causes:
- Wrong input device selected (e.g. "Stereo Mix" instead of your actual mic) - check the microphone dropdown in Settings
- Microphone volume too low in Windows sound settings (aim for 70-80%)
- The default
smallmodel requires ~244 MB download on first launch; check the console for progress
Symbol substitution not working / weird output?
Enable "Symbol & spelling mode" in Settings β it is off by default. For reliable multi-word phrases ("forward slash", "less than") set the Whisper model to small or larger; the base default is fast and accurate for prose but can mishear multi-word symbol names.
Custom vocabulary not applying? Layer A runs case-insensitively and matches whole words. If your spoken form contains a symbol or punctuation, add it exactly as Whisper transcribes it. Layer A is applied before Symbol & spelling mode, so vocabulary entries always win over the built-in substitutions.
Text not pasting?
The injector uses Ctrl+V via the clipboard. Some apps with custom input handling may not respond. If injection fails, the text is saved to recovery_notes.txt so nothing is lost.
Tray icon not visible? Windows 11 hides new tray icons by default. Go to Settings β Personalization β Taskbar β Other system tray icons and enable WritHer to keep it always visible.
MIT - see LICENSE for the full text.
Core architecture - voice dictation pipeline, Ollama assistant integration, floating widget, notes/agenda/reminders, tray icon - is by benmaster82 (this repository).
Contributions to upstream via pull request:
| Contributor | Contribution |
|---|---|
| LeikeBaus | Unit test structure and coverage |
| LikeARealGinger | Voice-delete by keyword, localized confirmations |
| Steven OhΓ‘d | Appointment and reminder voice deletion, delete confirmation popup |
| Marcel Alsleben | Assistant dispatcher refactoring, pending delete handling |
| Aaron Dutton | OS-locale date/time formatting |
The following features originate from the fork by @rusty-bit and have been integrated into upstream - their commits are preserved in this repository's history:
- Combo hotkeys with live key capture (default assistant hotkey now
Ctrl+Alt+R) - Per-mode widget accent colours (cyan for dictation, violet for assistant)
- Log viewer in the Settings window
- German locale
- Single-instance lock (adapted to a per-session
Local\mutex here) - The spoken symbol / number substitution concept (redesigned here as the opt-in Layer B of
replacements.py, with contraction safety and stricter spacing rules)
WritHer is a young project and contributions are very welcome!
Here are the areas where help is most needed:
- macOS port - replace Win32 injection and winotify with macOS equivalents
- Linux port - same as above for Linux (xdotool, libnotify, etc.)
- New languages - just add an entry to
locales.py - Ollama model testing - report which models work best with function calling
- Bug reports and UX feedback - open an issue, any feedback is appreciated
If you want to contribute, feel free to open an issue to discuss your idea first, or just fork and submit a PR. No formal process required, just good intentions.
Built with ποΈ faster-whisper Β· π§ Ollama Β· π Python
