Local, private, offline voice-to-text dictation for macOS. Press a hotkey, speak, and watch cleaned text appear in any app โ no internet required, completely free, and your voice never leaves your computer.
Inspired by Wispr Flow, built with faster-whisper.
- ๐ 100% Private โ Everything runs locally using OpenAI's Whisper model. No data sent to servers.
- โก Fast โ Transcribes 10 seconds of speech in ~1-3 seconds on Apple Silicon
- ๐ฏ Smart Cleanup โ Automatically removes filler words ("um", "uh", "like", "you know") and adds punctuation
- ๐๏ธ Two Recording Modes:
- Toggle mode: Press hotkey to start, press again to stop
- Hold-to-talk mode: Hold hotkey while speaking, release to transcribe
- ๐ Universal Paste โ Works in any text field in any macOS app
- ๐ Optional Feedback โ Sound beeps and preview notifications for better UX
- ๐๏ธ Configurable โ Choose model size, language, recording mode, and more
git clone https://github.com/ADJ-HUB1/dictate.git
cd dictate
bash scripts/install.shThe install script will:
- Create a Python virtual environment
- Install all dependencies
- Copy
.env.exampleto.env - You're ready to go!
If you prefer manual setup:
# Create virtual environment
python3 -m venv .venv
source .venv/bin/activate
# Install dependencies
pip install -e .
# Create configuration file
cp .env.example .env
# Run the app
python -m dictate-
Start the app:
cd dictate source .venv/bin/activate python -m dictate
-
Grant permissions when macOS prompts you:
- Microphone โ Required for recording (automatic prompt)
- Accessibility โ Required for global hotkey and paste:
- Open System Settings โ Privacy & Security โ Accessibility
- Click the + button and add your terminal app (Terminal.app, iTerm, etc.)
-
Look for the menu bar icon โ Dictate runs in your macOS menu bar
-
Start dictating:
- Toggle mode (default): Press Option+Space to start recording, speak naturally, press Option+Space again to stop
- Hold-to-talk mode: Hold Option+Space while speaking, release to transcribe and paste
- Speak naturally โ No need to pause between words
- Don't worry about filler words โ "um", "uh", "like", etc. are automatically removed
- Punctuation is automatic โ The AI adds commas and periods for you
- Wait for the beep (if enabled) โ The stop beep confirms recording has ended
- First transcription is slower โ The Whisper model loads on first use (~2-3 seconds), then it's fast
Edit .env to customize your experience:
# Recording mode: "toggle" or "hold"
HOTKEY_MODE=toggle
# Whisper model: tiny, base, small, medium, large-v3
# Recommendation: "small" for best accuracy/speed balance
WHISPER_MODEL=small
# Enable sound feedback (beeps on start/stop)
ENABLE_SOUND_FEEDBACK=true
# Show preview notification before pasting
SHOW_PREVIEW_NOTIFICATION=false| Model | RAM Usage | Speed | Accuracy | Best For |
|---|---|---|---|---|
tiny |
~150 MB | โก Fastest | โญ Low | Quick notes, testing |
base |
~300 MB | โก Fast | โญโญ Good | General use on older Macs |
small |
~1 GB | โก Moderate | โญโญโญ Better | Recommended โ Best balance |
medium |
~3 GB | ๐ Slower | โญโญโญโญ High | Accuracy-critical tasks |
large-v3 |
~6 GB | ๐ Slowest | โญโญโญโญโญ Highest | Maximum accuracy, powerful hardware |
| Variable | Default | Options | Description |
|---|---|---|---|
ASR_ENGINE |
local |
local, openai_api |
Use local Whisper or OpenAI API |
WHISPER_MODEL |
small |
tiny, base, small, medium, large-v3 |
Model size (see table above) |
WHISPER_LANGUAGE |
en |
ISO 639-1 codes | Language for transcription |
HOTKEY_MODE |
toggle |
toggle, hold |
Recording mode |
TEXT_PROCESSOR |
regex |
regex, ollama |
Text cleanup method |
SAMPLE_RATE |
16000 |
Hz | Audio sample rate |
ENABLE_SOUND_FEEDBACK |
false |
true, false |
Play beeps on start/stop |
SHOW_PREVIEW_NOTIFICATION |
false |
true, false |
Show transcription before pasting |
OPENAI_API_KEY |
โ | Your API key | Required if ASR_ENGINE=openai_api |
This app uses macOS-specific APIs (rumps, pyobjc) and is designed for macOS only.
- Check System Settings โ Privacy & Security โ Accessibility
- Make sure your terminal app is in the list and enabled
- Try removing and re-adding it
- Restart the terminal app after granting permissions
- Check microphone permission in System Settings โ Privacy & Security โ Microphone
- Make sure your microphone is set as the default input device
- Check the logs for errors:
python -m dictatewill show debug output
- The app pastes text using Cmd+V, so make sure:
- You have a text field focused (cursor blinking)
- The app supports clipboard paste
- Try clicking into a text field before recording
- Try a smaller model: Change
WHISPER_MODEL=baseortinyin.env - Check CPU usage during transcription
- The first transcription loads the model (one-time delay)
- Set
WHISPER_LANGUAGE=en(or your language code) in.env - Force language prevents Whisper from auto-detecting incorrectly
# Reinstall dependencies
source .venv/bin/activate
pip install --force-reinstall -e .
# Check Python version (requires 3.10-3.13)
python --versionTo run Dictate automatically when you log in:
-
Edit
scripts/com.dictate.app.plist:- Update the Python path to your virtual environment
- Update the working directory path
-
Install the launch agent:
cp scripts/com.dictate.app.plist ~/Library/LaunchAgents/ launchctl load ~/Library/LaunchAgents/com.dictate.app.plist
-
Verify it's running:
launchctl list | grep dictate
To stop auto-start:
launchctl unload ~/Library/LaunchAgents/com.dictate.app.plist
rm ~/Library/LaunchAgents/com.dictate.app.plistsrc/dictate/
โโโ app.py # Menu bar UI (rumps)
โโโ pipeline.py # Orchestrator: audio โ ASR โ cleanup โ paste
โโโ config.py # Configuration loader (.env)
โโโ audio/
โ โโโ recorder.py # Microphone recording (sounddevice)
โ โโโ sound_feedback.py # Beep sounds for start/stop
โโโ asr/
โ โโโ whisper_local.py # Local Whisper transcription
โ โโโ whisper_api.py # OpenAI API fallback
โโโ processing/
โ โโโ regex_processor.py # Filler removal + punctuation
โ โโโ ollama_processor.py # LLM-based cleanup (stub)
โโโ hotkey/
โ โโโ pynput_listener.py # Global hotkey (pynput)
โ โโโ pyobjc_fn_listener.py # Alternative implementation
โโโ injection/
โ โโโ injector.py # Clipboard + Cmd+V paste
โโโ notification/
โโโ notifier.py # macOS notifications
Each component uses Protocol interfaces + factory pattern for easy swapping and testing.
source .venv/bin/activate
pip install -e ".[dev]"
pytest tests/ -v- Modular design โ Each component (ASR, processor, hotkey, etc.) is swappable
- Protocol-based โ All interfaces use Python Protocols for type safety
- Factory pattern โ Components are created via factory functions based on config
- Fully tested โ 29 unit tests covering core functionality
See CONTRIBUTING.md for guidelines.
- macOS 12+ (Monterey or later)
- Python 3.10โ3.13 โ Use Python 3.12 for best compatibility
โ ๏ธ Python 3.14 is NOT supported (faster-whisper lacks 3.14 wheels)- If you have Python 3.14, install Python 3.12:
brew install python@3.12
- ~1 GB RAM for the
smallmodel - ~500 MB disk space for model download
- Toggle and hold-to-talk modes
- Sound feedback
- Preview notifications
- Ollama/LLM-based text processing for better grammar
- Transcription history log
- Per-app cleanup profiles
- System-wide settings UI
- Code dictation mode (no filler removal)
MIT License โ See LICENSE for details.
- Inspiration: Wispr Flow
- ASR: faster-whisper by SYSTRAN
- Whisper: OpenAI Whisper
- Issues: GitHub Issues
- Questions: Check Troubleshooting first
- Feature Requests: Open an issue with the "enhancement" label
Made with โค๏ธ for privacy-conscious Mac users who want fast, offline dictation.