Docs · Leokani-tts

Leokani server

One Docker image with two servers: Wyoming for Home Assistant, and an OpenAI-compatible speech API. For 64-bit Linux on x86_64 or ARM.

Install

Intel or AMD:

curl -O https://milliwattlabs.com/models/leokani-tts/downloads/leokani-server-1.1-amd64.tar.gz
echo "d1697a3d7fb7bb185503e0a0fc65b96f979466b5ffd8eee8a4d7c2e25d8c10c2  leokani-server-1.1-amd64.tar.gz" | sha256sum -c
docker load -i leokani-server-1.1-amd64.tar.gz

64-bit ARM:

curl -O https://milliwattlabs.com/models/leokani-tts/downloads/leokani-server-1.1-arm64.tar.gz
echo "8df107b624f44d35c604e100268e7ab98929d72aaf5aabc3ce6278245496af1f  leokani-server-1.1-arm64.tar.gz" | sha256sum -c
docker load -i leokani-server-1.1-arm64.tar.gz

On a Mac, check with shasum -a 256 -c instead of sha256sum -c.

Run

Start one server or both:

docker run -d --name leokani-wyoming --restart unless-stopped -p 10200:10200 leokani-server:1.1 wyoming
docker run -d --name leokani-openai --restart unless-stopped -p 8880:8880 leokani-server:1.1 openai

Or with Docker Compose, save this as docker-compose.yml and run docker compose up -d:

services:
  leokani-wyoming:
    image: leokani-server:1.1
    command: ["wyoming", "--zeroconf", "leokani"]
    network_mode: host
    restart: unless-stopped
  leokani-openai:
    image: leokani-server:1.1
    command: ["openai"]
    ports: ["8880:8880"]
    restart: unless-stopped

Home Assistant

In Home Assistant, go to Settings > Devices & services > Add integration > Wyoming Protocol. Enter the server's IP address and port 10200.

Then go to Settings > Voice assistants, open your assistant, and choose leokani as the text-to-speech voice.

With host networking and wyoming --zeroconf, as in the Compose file, Home Assistant finds the server by itself: click Configure on the discovered device instead. On a machine with several network interfaces, add --zeroconf-host IP to choose the address it announces.

To try it, in Developer tools > Actions:

action: tts.speak
target:
  entity_id: tts.leokani
data:
  media_player_entity_id: media_player.kitchen
  message: Dinner is ready.
Option
--port NTCP port. Default 10200.
--speed N0.5 to 2.0. Default 1.0.
--zeroconf [NAME]Announce on the network. Needs host networking.
--zeroconf-host IPThe address to announce.
docker run --rm leokani-server:1.1 wyoming --help

OpenAI speech API

Point any OpenAI speech client at http://HOST:8880/v1.

curl http://localhost:8880/v1/audio/speech \
  -H "Content-Type: application/json" \
  -d '{"model": "leokani-tts", "voice": "leokani", "input": "Hello there!", "response_format": "mp3"}' \
  -o hello.mp3

With the openai Python package:

from openai import OpenAI

client = OpenAI(base_url="http://localhost:8880/v1", api_key="unused")
client.audio.speech.create(model="leokani-tts", voice="leokani", input="Hello there!").write_to_file("hello.mp3")

POST /v1/audio/speech takes:

Field
modelleokani-tts. tts-1, tts-1-hd and gpt-4o-mini-tts also work.
inputThe text, up to 4,096 characters.
voiceleokani. OpenAI's voice names also work and give the same voice.
response_formatmp3 (default), opus, aac, flac, wav or pcm.
speed0.25 to 4.0, default 1.0. The voice speaks from 0.5 to 2.0.
stream_formataudio (default) or sse.

Every format streams. pcm is raw 16-bit little-endian mono at 24 kHz.

GET /v1/models lists leokani-tts. GET /health returns {"status": "ok"}.

To require a key, start it with -e LEOKANI_API_KEY=KEY and send Authorization: Bearer KEY.

Licenses

The image includes espeak-ng (GPL-3.0), built from this source: license, also at /usr/share/doc/espeak-ng/espeak-ng-COPYING in the image.

Leokani-tts is CC BY-NC 4.0. For a commercial license or a custom voice, email hello@milliwattlabs.com.