kitten-tts-rs ๐Ÿฑ๐Ÿฆ€

March 29, 2026 ยท View on GitHub

Rust implementation of KittenTTS. KittenTTS delivers high-quality voice synthesis with models ranging from 15M to 80M parameters (25โ€“80 MB on disk). This Rust implementation provides self-contained binaries with no Python dependency.

Adapted from: KittenML/KittenTTS (Apache-2.0). All model weights are from the original project.

Key Features of KittenTTS

  • Ultra-lightweight โ€” 15M to 80M parameters; smallest model is just 25 MB (int8)
  • CPU-optimized โ€” ONNX-based inference runs efficiently without a GPU
  • 8 built-in voices โ€” Bella, Jasper, Luna, Bruno, Rosie, Hugo, Kiki, and Leo
  • Adjustable speech speed โ€” control playback rate via the --speed parameter
  • Text preprocessing โ€” built-in pipeline handles numbers, currencies, units, and more
  • 24 kHz output โ€” high-quality audio at a standard sample rate
  • Edge-ready โ€” small enough to run on embedded devices, Raspberry Pi, phones

What This Rust Port Adds

  • Two binaries โ€” kitten-tts CLI and kitten-tts-server (OpenAI-compatible API)
  • Fast startup โ€” ~100ms vs ~2s for Python import overhead
  • Tiny footprint โ€” ~10 MB binary (+ model weights) vs ~500 MB Python environment
  • GPU acceleration โ€” optional CUDA, TensorRT, CoreML, or DirectML via Cargo features
  • Cross-platform โ€” builds for Linux (x86_64, aarch64) and macOS (aarch64)

Available Models

ModelParametersSizeDownload
kitten-tts-mini80M80 MBKittenML/kitten-tts-mini-0.8
kitten-tts-micro40M41 MBKittenML/kitten-tts-micro-0.8
kitten-tts-nano15M56 MBKittenML/kitten-tts-nano-0.8
kitten-tts-nano (int8)15M25 MBKittenML/kitten-tts-nano-0.8-int8

Quick Start

1. Install Dependencies

espeak-ng is required for phonemization:

# macOS
brew install espeak-ng

# Ubuntu/Debian
sudo apt-get install -y espeak-ng

# Fedora/RHEL
sudo dnf install espeak-ng

# Arch
sudo pacman -S espeak-ng

2. Download Binaries

Download the pre-built binaries for your platform from the Releases page:

# Example: Linux x86_64
curl -LO https://github.com/second-state/kitten_tts_rs/releases/latest/download/kitten-tts-x86_64-linux.tar.gz
tar xzf kitten-tts-x86_64-linux.tar.gz

# Example: macOS Apple Silicon
curl -LO https://github.com/second-state/kitten_tts_rs/releases/latest/download/kitten-tts-aarch64-macos.tar.gz
tar xzf kitten-tts-aarch64-macos.tar.gz

Each archive contains two binaries:

  • kitten-tts โ€” CLI tool for one-off speech generation
  • kitten-tts-server โ€” OpenAI-compatible API server

3. Download Models

curl -LO https://github.com/second-state/kitten_tts_rs/releases/latest/download/kitten-tts-models.tar.gz
tar xzf kitten-tts-models.tar.gz

This extracts a models/ directory with all available models:

models/
โ”œโ”€โ”€ kitten-tts-mini/         # 80M params, 80 MB โ€” highest quality
โ”œโ”€โ”€ kitten-tts-micro/        # 40M params, 41 MB โ€” balanced
โ”œโ”€โ”€ kitten-tts-nano/         # 15M params, 56 MB (fp32)
โ””โ”€โ”€ kitten-tts-nano-int8/    # 15M params, 25 MB โ€” smallest

4. Generate Speech (CLI)

# Basic usage (outputs output.wav)
./kitten-tts ./models/kitten-tts-mini 'Hello, world!' Bruno

# Specify output file and speed
./kitten-tts ./models/kitten-tts-mini 'Hello, world!' --voice Luna --speed 1.2 --output hello.wav

# List available voices
./kitten-tts ./models/kitten-tts-mini "" --list-voices

5. Run the API Server

Start the server with a model directory:

./kitten-tts-server ./models/kitten-tts-mini --host 0.0.0.0 --port 8080

The server exposes an OpenAI-compatible /v1/audio/speech endpoint:

curl -X POST http://localhost:8080/v1/audio/speech \
  -H 'Content-Type: application/json' \
  -d '{
    "model": "kitten-tts",
    "input": "Hello, world! This is KittenTTS running as an API server.",
    "voice": "alloy"
  }' \
  --output speech.mp3

Request body:

FieldTypeDefaultDescription
inputstring(required)Text to synthesize
voicestring(required)Voice name (OpenAI or KittenTTS names)
modelstring""Accepted for compatibility; ignored
response_formatstring"mp3"Output audio format (see below)
speedfloat1.0Speech speed multiplier (0.25โ€“4.0)
streamboolfalseEnable SSE streaming (requires "pcm" format)

Supported audio formats:

FormatContent-TypeDescription
mp3audio/mpegMP3 128 kbps CBR (default, resampled to 44.1 kHz)
opusaudio/oggOpus in OGG container (resampled to 48 kHz)
flacaudio/flacFLAC lossless (24 kHz native)
wavaudio/wavWAV 16-bit PCM (24 kHz native)
pcmaudio/pcmRaw 16-bit signed little-endian PCM (24 kHz)
aacโ€”Not yet supported (returns error)

API endpoints:

MethodPathDescription
POST/v1/audio/speechGenerate speech from text
GET/v1/modelsList loaded model
GET/healthHealth check

Voice mapping (OpenAI โ†’ KittenTTS):

OpenAIKittenTTSGender
alloyBellaFemale
echoJasperMale
fableLunaFemale
onyxBrunoMale
novaRosieFemale
shimmerHugoMale

All 8 KittenTTS voices (Bella, Jasper, Luna, Bruno, Rosie, Hugo, Kiki, Leo) can also be used directly by name.

SSE Streaming

For lower time-to-first-audio on longer texts, set "stream": true with "response_format": "pcm". The server returns Server-Sent Events with base64-encoded PCM audio chunks, compatible with the OpenAI streaming TTS format:

curl -N -X POST http://localhost:8080/v1/audio/speech \
  -H "Content-Type: application/json" \
  -d '{
    "model": "kitten-tts",
    "input": "Hello, this is a streaming test. Each sentence is sent as a separate audio chunk.",
    "voice": "alloy",
    "response_format": "pcm",
    "stream": true
  }'

Each event is a JSON object on a data: line:

data: {"type":"speech.audio.delta","delta":"<base64-encoded-pcm>"}
data: {"type":"speech.audio.delta","delta":"<base64-encoded-pcm>"}
data: {"type":"speech.audio.done"}

The delta field contains 16-bit signed little-endian PCM at 24 kHz, base64-encoded. The first chunk is split at the earliest clause boundary for fast initial playback.

Building from Source

git clone https://github.com/second-state/kitten_tts_rs.git
cd kitten_tts_rs

cargo build --release
# Binaries at: target/release/kitten-tts and target/release/kitten-tts-server

With CUDA (NVIDIA GPU)

Requires CUDA toolkit and cuDNN installed on the system. Linux and Windows only.

cargo build --release --features cuda

With TensorRT (NVIDIA GPU, optimized)

Requires TensorRT runtime. Linux and Windows only.

cargo build --release --features tensorrt

With CoreML (Apple Silicon / macOS)

cargo build --release --features coreml

With DirectML (Windows GPU)

cargo build --release --features directml

Building and Testing Locally

After building from source, download models directly from Hugging Face to test:

# Download the nano-int8 model (smallest, 25 MB โ€” good for testing)
mkdir -p models/kitten-tts-nano-int8
for FILE in config.json kitten_tts_nano_v0_8.onnx voices.npz; do
  curl -L -o "models/kitten-tts-nano-int8/$FILE" \
    "https://huggingface.co/KittenML/kitten-tts-nano-0.8-int8/resolve/main/$FILE"
done

For other models, replace the directory name and URL with the appropriate values from the Available Models table:

# Mini (80M params, highest quality)
mkdir -p models/kitten-tts-mini
for FILE in config.json kitten_tts_mini_v0_8.onnx voices.npz; do
  curl -L -o "models/kitten-tts-mini/$FILE" \
    "https://huggingface.co/KittenML/kitten-tts-mini-0.8/resolve/main/$FILE"
done

# Micro (40M params, balanced)
mkdir -p models/kitten-tts-micro
for FILE in config.json kitten_tts_micro_v0_8.onnx voices.npz; do
  curl -L -o "models/kitten-tts-micro/$FILE" \
    "https://huggingface.co/KittenML/kitten-tts-micro-0.8/resolve/main/$FILE"
done

# Nano fp32 (15M params)
mkdir -p models/kitten-tts-nano
for FILE in config.json kitten_tts_nano_v0_8.onnx voices.npz; do
  curl -L -o "models/kitten-tts-nano/$FILE" \
    "https://huggingface.co/KittenML/kitten-tts-nano-0.8-fp32/resolve/main/$FILE"
done

Test the CLI:

./target/release/kitten-tts ./models/kitten-tts-nano-int8 'Hello, world!' Bruno

Test the API server:

./target/release/kitten-tts-server ./models/kitten-tts-nano-int8 --port 8080
# In another terminal:
curl -X POST http://localhost:8080/v1/audio/speech \
  -H 'Content-Type: application/json' \
  -d '{"input": "Hello from the API", "voice": "alloy"}' \
  --output test.mp3

CoreML on Apple Silicon: Pros and Cons

Pros

  • Uses Apple's Neural Engine and Metal GPU for compatible operations
  • No additional software installation needed (built into macOS)
  • Can accelerate larger models where GPU compute outweighs overhead

Cons

  • Slower than CPU for small models โ€” In our benchmarks on Apple Silicon (Mac mini M4 Pro), the 80M-parameter mini model ran ~1.7x slower with CoreML (8.2s) than CPU-only (4.8s)
  • Dynamic shape limitations โ€” CoreML requires static tensor shapes; KittenTTS uses dynamic output shapes, so CoreML can only accelerate a subset of operations while the rest falls back to CPU
  • Model compilation overhead โ€” CoreML compiles the ONNX model to its internal format on first load, adding latency
  • First build is slower โ€” The ort crate may need to build ONNX Runtime from source with CoreML support

Recommendation

For KittenTTS models (15Mโ€“80M params), CPU-only is faster and simpler. ONNX Runtime's CPU backend already uses SIMD (NEON on ARM, AVX on x86) and multi-threading effectively. CoreML would be more beneficial for models with 1B+ parameters where GPU compute dominates.

Architecture

src/
โ”œโ”€โ”€ main.rs                          # CLI binary (clap)
โ”œโ”€โ”€ lib.rs                           # Library root
โ”œโ”€โ”€ model.rs                         # ONNX session, inference, text chunking
โ”œโ”€โ”€ phonemize.rs                     # espeak-ng โ†’ IPA phonemes โ†’ token IDs
โ”œโ”€โ”€ preprocess.rs                    # Text normalization (numbers, currency, etc.)
โ”œโ”€โ”€ voices.rs                        # NPZ voice embedding loader
โ””โ”€โ”€ bin/kitten-tts-server/           # API server binary
    โ”œโ”€โ”€ main.rs                      # Axum/Tokio server, model loading
    โ”œโ”€โ”€ error.rs                     # OpenAI-style error responses
    โ”œโ”€โ”€ state.rs                     # Shared model state (Arc<Mutex>)
    โ””โ”€โ”€ routes/{health,models,speech,encode}.rs

How It Works

  1. Text preprocessing โ€” Expands numbers ("42" โ†’ "forty-two"), currencies ("$10.50" โ†’ "ten dollars and fifty cents"), and normalizes whitespace
  2. Phonemization โ€” Converts English text to IPA phonemes via espeak-ng
  3. Token encoding โ€” Maps IPA phonemes to integer token IDs using a symbol table matching the original Python implementation
  4. Voice selection โ€” Loads style embeddings from the NPZ voice file
  5. ONNX inference โ€” Runs the model with input tokens, voice style, and speed parameters
  6. Audio encoding โ€” Outputs MP3 (default), Opus, FLAC, WAV, or raw PCM

Compared to Python KittenTTS

PythonRust
Dependenciesonnxruntime, misaki, phonemizer, numpy, soundfile, spacyort, hound, espeak-ng (system)
Install size~500 MB (with venv)~10 MB binary
Startup time~2s (Python import)~100ms
Deploymentpip install + venvSingle binary (CLI + API server)
GPU supportonnxruntime-gpu pip packageCargo feature flags

Performance

Benchmarked on Apple Mac M4 Pro (CPU only, no GPU acceleration). WAV output format. RTF (Real-Time Factor) = execution time / audio length โ€” lower is better, < 1.0 means faster than real-time.

Test inputs:

  • Short: "Hello, world!" (14 chars)
  • Long: 5-sentence paragraph (571 chars, multiple chunks)

kitten-tts-nano-int8 (15M params, 25 MB)

TestExec TimeAudio LengthRTF
CLI short0.93s1.47s0.63
CLI long5.73s47.18s0.12
API short0.24s1.94s0.12
API long6.78s61.91s0.11

kitten-tts-mini (80M params, 80 MB)

TestExec TimeAudio LengthRTF
CLI short0.71s1.52s0.47
CLI long11.33s44.11s0.26
API short0.64s2.04s0.31
API long14.35s55.91s0.26

CLI times include model loading (~0.3s). API server times are warm (model pre-loaded, after warmup requests).

The nano-int8 model runs 8โ€“9x faster than real-time and is recommended for interactive and real-time applications. The mini model produces higher quality audio at ~4x faster than real-time.

License

Apache-2.0 (same as KittenTTS)

Acknowledgments

  • KittenML for the original KittenTTS models and Python library
  • pyke/ort for the excellent ONNX Runtime Rust bindings
  • espeak-ng for phonemization