Apple-Silicon-native TTS and STT for Home Assistant and OpenAI-compatible clients
Project description
wyoming-mlx
Apple-Silicon-native TTS (Kokoro) and STT (distil-whisper) for Home Assistant and OpenAI-compatible clients.
Why?
If you have a Mac on your network, it can be your voice server. wyoming-mlx turns it into a fast, fully local speech-to-text and text-to-speech service:
- Private by construction. Audio never leaves your network — no cloud speech APIs, no per-request pricing, nothing to subscribe to. Models run entirely on your machine.
- Uses hardware you already own. Apple Silicon's GPU and unified memory run Whisper and Kokoro comfortably alongside whatever else the Mac is doing — no dedicated GPU server, no idle power draw of a CUDA box.
- One service, two ecosystems. Home Assistant talks to it natively over
the Wyoming protocol (drop-in
replacement for
wyoming-faster-whisper/wyoming-pipersatellites), while anything that speaks the OpenAI audio API — scripts, editors, chat UIs — can use the same instance via/v1/audio/transcriptionsand/v1/audio/speech. - Set-and-forget. Install with Homebrew, run as a launchd service via
brew services, and models are fetched once into the Hugging Face cache.
Speech-to-text runs on MLX via
mlx-whisper; text-to-speech runs Kokoro on Metal via PyTorch. The real
backends therefore require an Apple Silicon Mac. Everything else (config,
HTTP API, Wyoming protocol handling, fake backends, tests) is portable, and
CI runs on Linux against the fake backends.
Install (Homebrew)
brew tap rnorth/tap
brew install wyoming-mlx
Run it in the foreground with wyoming-mlx, or as a launchd service:
brew services start wyoming-mlx
Logs go to $(brew --prefix)/var/log/wyoming-mlx.log. Apple Silicon only.
Quick start (dev)
mise install
uv sync
uv run pytest
Works on Linux too: CPU-only torch is selected automatically (the fake
backends need no GPU). Integration tests against real models are skipped by
default; run them with uv run pytest --integration (Apple Silicon only).
Run locally (fake backends)
uv run python scripts/dev_run.py
The dev server uses the API key dev.
Run locally (real MLX backends)
uv run wyoming-mlx
By default it loads:
- distil-whisper-large-v3 (MLX) on Wyoming port 10300 / HTTP
/v1/audio/transcriptions - Kokoro-82M (MLX) on Wyoming port 10200 / HTTP
/v1/audio/speech - HTTP on port 10400 with API-key auth
Models download on first use to the Hugging Face cache.
API keys
HTTP endpoints require a bearer token. Keys are read at startup from
~/.config/wyoming-mlx/apikeys (override with --http-api-keys-file),
one key per line, # comments allowed. The file should be mode 0600.
If the file is missing or empty, all HTTP requests are rejected with 401.
Note that the HTTP API listens on all interfaces by default (set
WYOMING_MLX_HTTP__HOST=127.0.0.1 to restrict it), and GET /v1/models
is unauthenticated, matching OpenAI API behaviour.
mkdir -p ~/.config/wyoming-mlx
(umask 077; openssl rand -hex 32 > ~/.config/wyoming-mlx/apikeys)
HTTP API
List models
curl http://localhost:10400/v1/models
Transcribe an audio file
curl http://localhost:10400/v1/audio/transcriptions \
-H "Authorization: Bearer $API_KEY" \
-F file=@some.wav
Synthesize speech
curl http://localhost:10400/v1/audio/speech \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{"input":"Hello there.","voice":"af_heart"}' \
--output /tmp/out.wav
Home Assistant integration
Settings → Integrations → Wyoming Protocol → Add:
- STT:
<host>:10300 - TTS:
<host>:10200
No keys, no TLS (HA convention, trusted LAN).
Configuration
Pass --config /path/to/config.toml or set env vars with the
WYOMING_MLX_ prefix and __ for nesting (e.g.
WYOMING_MLX_HTTP__PORT=10401). See src/wyoming_mlx/config.py for the
full schema.
License
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file wyoming_mlx-0.1.0.tar.gz.
File metadata
- Download URL: wyoming_mlx-0.1.0.tar.gz
- Upload date:
- Size: 168.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.11.21 {"installer":{"name":"uv","version":"0.11.21","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
071c0782b8d34c651ebdea3f3c19a7b72720946e2beeb290144d2069841153ad
|
|
| MD5 |
60892ca97b638e5b0a436399615456df
|
|
| BLAKE2b-256 |
3a23ab5e15e27a284fb6d5873fce848f5d7e847f9e39de148dff257ced593381
|
File details
Details for the file wyoming_mlx-0.1.0-py3-none-any.whl.
File metadata
- Download URL: wyoming_mlx-0.1.0-py3-none-any.whl
- Upload date:
- Size: 22.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.11.21 {"installer":{"name":"uv","version":"0.11.21","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fdb9d0b9b8323097e1bdeaff6a16efb9a9d36d768b2c0772824dbe882caca5a5
|
|
| MD5 |
f525f005ab867cff641efe2c317e4076
|
|
| BLAKE2b-256 |
3e661a0b8fe6da2e3707ed25b58954d4a44822f858dc961601d8160a6836a37b
|