Skip to content

FatherMarz/SimpleTTS

Repository files navigation

kokoro-hotkey

Local, hotkey-driven text-to-speech for macOS. Highlight any text, press Cmd+I, and Kokoro reads it in a voice that does not sound like a 2008 GPS unit.

  • Runs entirely on your machine. No API calls, no cloud, no telemetry.
  • 50+ voices across English (US/UK), Spanish, French, Hindi, Italian, Japanese, Portuguese (BR), and Mandarin.
  • Menubar UI to switch voices and speed without touching code.
  • Auto-starts at login via launchd. The model stays loaded so the hotkey is instant.

Why

macOS has built-in say. The voices are flat, robotic, and unpleasant for anything longer than a sentence. Kokoro is a small (~340MB) neural TTS model with voices that are genuinely listenable. This wraps it as a localhost server that a Hammerspoon hotkey can hit.

Requirements

  • macOS (Apple Silicon or Intel)
  • Homebrew
  • uv (brew install uv)
  • ~400MB of disk for the model files
  • Hammerspoon (the installer will install it for you if missing)

Install

git clone https://github.com/<you>/kokoro-hotkey.git
cd kokoro-hotkey
./install.sh

The installer will:

  1. Install Hammerspoon (if missing).
  2. Copy the server to ~/.local/tts/ and uv sync its Python deps.
  3. Download Kokoro v1.0 model files into ~/.local/tts/models/.
  4. Install a launchd agent at ~/Library/LaunchAgents/local.kokoro-hotkey.plist and load it.
  5. Drop a Hammerspoon module at ~/.hammerspoon/tts.lua and add require("tts") to your init.lua.

After it finishes, grant Hammerspoon Accessibility permission once:

System Settings, Privacy & Security, Accessibility, toggle Hammerspoon ON.

Then click the Hammerspoon menubar icon and choose Reload Config.

Usage

Hotkey Action
Cmd+I Speak the current selection
Cmd+Shift+I Stop playback

Click the TTS menubar item for:

  • Voice picker (grouped by language and gender, picking a voice plays a sample)
  • Speed picker (0.7x to 2.0x)
  • Test current voice
  • Stop, restart server, open log

Settings persist to ~/.local/tts/config.json.

API

The server listens on 127.0.0.1:8765.

# speak something
curl -X POST http://127.0.0.1:8765/speak \
  -H 'Content-Type: application/json' \
  -d '{"text":"hello world"}'

# stop
curl -X POST http://127.0.0.1:8765/stop

# list voices
curl http://127.0.0.1:8765/voices

# get / set defaults
curl http://127.0.0.1:8765/config
curl -X POST http://127.0.0.1:8765/config \
  -H 'Content-Type: application/json' \
  -d '{"voice":"am_michael","speed":1.1}'

Voices

Voice IDs follow Kokoro's convention: <lang><gender>_<name>.

  • a American English, b British English
  • e Spanish, f French, h Hindi, i Italian, j Japanese, p Portuguese (BR), z Mandarin
  • f female, m male

Some commonly recommended voices:

  • af_heart (default), af_bella, af_nicole, af_sky
  • am_michael, am_puck, am_fenrir
  • bf_emma, bf_isabella
  • bm_george, bm_lewis

Pick by clicking through the menubar to audition them.

Architecture

[ Hammerspoon ] -- Cmd+I --> simulate Cmd+C, read pasteboard
       |
       | POST /speak {"text": "..."}
       v
[ Flask server (~/.local/tts/server.py) ]
       |
       | kokoro_onnx synth -> /tmp/tts-<uuid>.wav
       v
[ afplay subprocess ]   <-- killable via /stop

The Flask server is single-process, in-memory model. Generation is fast enough on M-series chips that streaming chunks isn't necessary for the typical "highlight a paragraph" use case.

Troubleshooting

Cmd+I does nothing. Hammerspoon doesn't have Accessibility permission. Grant it in System Settings.

Cmd+I plays the previous clipboard, not the selection. The app you're in didn't put the selection on the pasteboard within 180ms of Cmd+C. Increase the wait in ~/.hammerspoon/tts.lua (hs.timer.usleep(180000)).

TTS error 0 / connection refused. The server isn't running. Check ~/.local/tts/server.log, then launchctl kickstart -k gui/$(id -u)/local.kokoro-hotkey.

No "TTS" item in the menubar. Hammerspoon hasn't reloaded. Click its menubar icon, "Reload Config".

Voices submenu is empty. The Lua module loaded before the server was ready. Reload Hammerspoon.

Uninstall

./uninstall.sh

Stops and removes the LaunchAgent, removes the Hammerspoon module and the require("tts") line from your init.lua, and asks before deleting ~/.local/tts/ (which holds the 340MB model files).

Credits

  • Kokoro by hexgrad, the underlying TTS model.
  • kokoro-onnx by thewh1teagle, the ONNX runtime wrapper.
  • Hammerspoon for the hotkey and menubar plumbing.

License

MIT. See LICENSE.

About

Local Kokoro TTS for macOS, hotkey-triggered. Highlight text, press Cmd+I, hear it in a good voice.

Resources

License

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors