Skip to content

Repository files navigation

Whisper Clean Mac

Local-first voice-to-text for macOS. Transcribe audio files or dictate with a hotkey — everything stays on your machine unless you opt into LLM cleanup.

License: MIT Python 3.10+ Tests: 52 passing PRs Welcome Status: Beta

Beta — Under active development. Core transcription and dictation work. Expect rough edges, incomplete features, and breaking changes. Not production-ready.

The Problem

You want to dictate text on your Mac without sending audio to the cloud. Apple's built-in dictation is limited. Cloud services like Otter or Whisper API work but your audio leaves your machine. You want something that runs locally, transcribes accurately, and optionally cleans up the output with your own API keys.

What You Get

  • Local transcriptionfaster-whisper runs entirely on your machine
  • File mode — Drop in wav, mp3, m4a, flac, aac, ogg, mp4 files
  • Dictation mode — Record live audio in-app (up to 6 minutes)
  • Background service — Global hotkey triggers record → transcribe → paste into any app
  • BYOK cleanup — Bring your own API key (Grok, OpenAI, OpenRouter) for LLM-powered text cleanup
  • Deterministic fallback — Local cleanup (filler removal, punctuation) always runs, even if API fails
  • Menu bar icon — Quick toggle and status visibility from the macOS menu bar

Quick Start

git clone https://github.com/bennjph/whisper-clean-mac.git
cd whisper-clean-mac
python3 -m venv venv && source venv/bin/activate
pip install -r requirements.txt

GUI mode:

python -m app_whisper_clean.main

Background dictation service:

python -m app_whisper_clean.main --service

CLI mode:

python -m app_whisper_clean.cli --file /path/to/audio.wav --provider none

How It Works

┌──────────────────────────────────────────────────────┐
│  GUI / Hotkey / CLI                                  │
├──────────────────────────────────────────────────────┤
│  Audio Input                                         │
│  ├─ File picker (wav, mp3, m4a, flac, aac, ogg)     │
│  └─ Live recording (sounddevice, up to 6 min)       │
├──────────────────────────────────────────────────────┤
│  Pipeline                                            │
│  ├─ 1. Transcribe (faster-whisper, local)            │
│  ├─ 2. Deterministic cleanup (fillers, punctuation)  │
│  └─ 3. LLM cleanup (optional, BYOK)                 │
├──────────────────────────────────────────────────────┤
│  Output                                              │
│  ├─ Display in app                                   │
│  ├─ Copy to clipboard                                │
│  ├─ Save to file (.txt / .md)                        │
│  └─ Paste into active app (service mode)             │
└──────────────────────────────────────────────────────┘

Service mode flow: Press Option+Space → recording starts → press again → transcription runs → cleaned text is pasted into whatever app has focus.

Status

Feature Status Notes
Local transcription (faster-whisper) Working All supported audio formats
File mode GUI Working Select file, transcribe, copy/save
Live dictation recording Working Requires sounddevice + soundfile
Deterministic text cleanup Working Filler removal, punctuation normalization
LLM cleanup (BYOK) Working Grok, OpenAI, OpenRouter
GUI (customtkinter) Working Dark/light mode, card-based layout
Background service (--service) Working Requires Accessibility permission for hotkey
Global hotkey (Option+Space) Working Needs Accessibility granted to terminal
Menu bar icon Working State feedback (idle/recording/transcribing)
Clipboard paste injection Working save → write → Cmd+V → restore
Audio feedback (beeps) Working Start, stop, success, error tones
macOS .app bundle Untested py2app config exists but not validated
Windows / Linux Not supported macOS-only

Known Limitations

  • Accessibility permission required for the global hotkey. Without it, service mode falls back to menu bar toggle only. Grant it in System Settings > Privacy & Security > Accessibility for your terminal app.
  • Short recordings (<1s) are padded to 16k samples to prevent Whisper hallucination. This is intentional.
  • simpleaudio (audio feedback) may need PortAudio on some systems.
  • Dark mode is supported but not fully QA'd across all components.
  • No auto-update mechanism — manual git pull for now.
  • First transcription takes longer as faster-whisper downloads the model.

Dependencies

Package Purpose
faster-whisper Local transcription engine
numpy Audio array processing
sounddevice Live audio recording
soundfile WAV file I/O
customtkinter Modern Tkinter UI
pynput Global keyboard hotkey listener
pystray macOS menu bar icon
simpleaudio Audio feedback beeps
Pillow Icon generation

macOS Permissions

The background service needs Accessibility permission for the global hotkey:

  1. System Settings > Privacy & Security > Accessibility
  2. Click +, add your terminal app (Terminal, iTerm2, Ghostty, etc.)
  3. Toggle it ON
  4. Restart the terminal (macOS caches trust per-process)

Without this, the service still runs — menu bar toggle works, hotkey doesn't.

Testing

python -m pytest tests/ -q
# 52 passed

Tests cover: pipeline, providers, config, CLI, hotkey listener, clipboard injection, recording quality, service state machine.

Configuration

Settings persist at ~/.whisper-clean/config.json:

  • Whisper model and language
  • Provider endpoints and API keys (stored locally, never transmitted except to your chosen provider)
  • Custom replacement map for domain-specific corrections
  • allow_unsafe_base_url (default false) — strict HTTPS + host allowlist for provider endpoints

Project Structure

whisper-clean-mac/
├── app_whisper_clean/
│   ├── ui/                  # UI package (customtkinter)
│   │   ├── app.py           # Main window, event wiring
│   │   ├── theme.py         # Design tokens (colors, typography, spacing)
│   │   ├── components.py    # CardFrame, StatusIndicator, button factories
│   │   ├── input_panel.py   # File picker + dictation recorder
│   │   ├── settings_panel.py # Model settings + advanced disclosure
│   │   └── output_panel.py  # Output text + copy/save
│   ├── config.py            # AppConfig, load/save
│   ├── recorder.py          # Audio recording (sounddevice)
│   ├── transcriber.py       # faster-whisper wrapper
│   ├── text_cleaning.py     # Deterministic cleanup
│   ├── providers.py         # BYOK LLM provider clients
│   ├── pipeline.py          # Transcribe + cleanup orchestration
│   ├── clipboard.py         # Clipboard paste injection
│   ├── hotkey.py            # Global hotkey (pynput + SIGTRAP prevention)
│   ├── audio_feedback.py    # Beep tones (simpleaudio)
│   ├── service.py           # Background dictation state machine
│   ├── menubar.py           # Menu bar icon (pystray)
│   ├── main.py              # Entry point (GUI or --service)
│   └── cli.py               # CLI mode
├── tests/                   # 52 tests
├── assets/                  # App icons (PNG, ICNS)
├── docs/                    # QA plan, verification receipts
├── DESIGN-GUIDE.md          # Design system documentation
├── TRANSFER-LEARNINGS-AND-ROADMAP.md
├── SPEC.md                  # Original specification
├── CONTRIBUTING.md
├── LICENSE                  # MIT
└── requirements.txt

Roadmap

See TRANSFER-LEARNINGS-AND-ROADMAP.md for the full roadmap:

Version Focus
v1.5 (current) Global hotkey, clipboard paste, menu bar, recording quality, modern UI
v2.0 (planned) Voice Activity Detection, push-to-talk modes, floating overlay
v3.0 (planned) App-aware context, multi-language auto-detect, plugin system

Security

  • Audio stays on your machine. Transcription is fully local.
  • API keys are stored in your user profile (~/.whisper-clean/config.json), never committed or transmitted except to your chosen provider endpoint.
  • Provider endpoints are validated (HTTPS + trusted host allowlist) unless you explicitly set allow_unsafe_base_url: true.
  • No telemetry, no analytics, no phone-home.

Contributing

See CONTRIBUTING.md. Bug reports, test improvements, and macOS compatibility fixes are especially welcome.

License

MIT


Built by Benison Joseph. This project is in beta — feedback and contributions welcome.

About

Local-first voice-to-text for macOS. Transcribe audio files or dictate with a hotkey — powered by faster-whisper, everything stays on your machine.

Topics

Resources

Contributing

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages