Wyoming protocol TTS server wrapping Silero models. Supports Home Assistant integration, streaming audio, and optional per-voice LLM normalization.
-
Clone the repository
git clone https://github.com/dkindev/silero-server.git cd silero-server -
Create a virtual environment
python -m venv .venv source .venv/bin/activate -
Install dependencies
uv sync --extra dev
-
Run the application
python -m src.main
The server listens on
tcp://127.0.0.1:10200by default. -
Test with HTTP server
uv run --with "wyoming[http]" python -m wyoming.http.tts_server --uri tcp://127.0.0.1:10200
-
Build the image
docker build -t silero-server:latest . -
Run the container
docker run -p 10200:10200 \ -e TTS_ENV_TYPE=production \ -v ./data:/app/data \ -v ./models:/app/models \ silero-server:latest
The server exposes port
10200for Wyoming TCP connections.
Configuration is resolved with the following priority (highest first):
- CLI arguments —
--uri,--torch_device,--sample_rate, etc. - Environment variables —
TTS_URI,TTS_TORCH__DEVICE,TTS_SAMPLE_RATE, etc. - config.yml — YAML file at the project root
- Defaults — Default values in code
See config.yml for full configuration reference with all fields, CLI argument names, and environment variable names.
Voice and model mappings are defined in data/data.yml. The file has two top-level sections: models and prompts.
models:
v5_5_ru:
language: ru
warmup: true
hash_prefix: 50081637b602126ee06cb3bc8a744d25651d2da149ee8864b9a379bfdd934437
locales:
ru_RU:
voices:
- name: aidar
- name: eugene
- name: baya
- name: kseniya
- name: xenia
v3_en:
language: en
locales:
en_US:
voices:
- name: henry
speaker: en_2
- name: sophia
speaker: en_3Each model key (e.g., v5_5_ru) is the model name. Supported fields:
| Field | Required | Default | Description |
|---|---|---|---|
language |
Yes | — | Silero language identifier (ru, en, etc.) |
enabled |
No | true |
false to disable the model and exclude its voices |
warmup |
No | false |
true to preload at startup; false for lazy loading |
hash_prefix |
No | — | SHA-256 hash prefix for download integrity verification |
locales |
Yes | — | Map of locale codes to voice lists |
- Add a model entry under
models:indata/data.ymlwith the Silero language identifier. - Add locales with voices referencing the new model.
Set enabled: false on the model entry. Its voices are automatically excluded from discovery.
Each voice entry has the following fields:
| Field | Required | Default | Description |
|---|---|---|---|
name |
Yes | — | Voice name |
speaker |
No | voice name | Silero's native speaker identifier |
model |
No | parent model | Explicit model reference (usually inherited from parent) |
normalization.text.enabled |
No | true |
Override text normalization enabled state |
normalization.text.type |
No | simple |
Override normalization type (simple, llm) |
normalization.text.prompt_id |
No | — | Reference a custom LLM prompt from prompts |
normalization.ssml.enabled |
No | false |
Override SSML normalization enabled state |
normalization.ssml.type |
No | simple |
Override SSML normalization type |
normalization.ssml.prompt_id |
No | — | Reference a custom LLM prompt for SSML |
Voices are identified by their computed ID: {locale}-{model}-{name} (e.g., ru_RU-v5_5_ru-aidar).
Add or edit entries under locales.*.voices in data/data.yml. Set speaker to the Silero native speaker name only if it differs from the voice name.
Per-voice override of the server-wide normalization settings (defined in config.yml). Override the normalization type, disable it entirely, or reference a custom LLM prompt.
models:
v5_5_ru:
locales:
ru_RU:
voices:
- name: aidar
normalization:
text:
enabled: true
type: llm
prompt_id: ru_text
prompts:
- id: ru_text
text: "Normalize Russian text for TTS..."
model: qwen3.5:4bWithout a normalization block on a voice, the server-wide defaults from config.yml apply.
Reusable LLM prompt definitions referenced by prompt_id in voice normalization.
| Field | Required | Default | Description |
|---|---|---|---|
id |
Yes | — | Unique identifier referenced by prompt_id |
text |
Yes | — | LLM prompt instruction text |
model |
Yes | — | LLM model name (e.g., qwen3.5:4b) |
TEXT— plain textSSML— Speech Synthesis Markup Language
- Format: raw PCM (WAV-compatible)
- Sample rate: configurable (8000, 16000, 24000, 48000 Hz)
- Bit depth: 16-bit signed integer
- Channels: mono (1 channel)
pytest tests/ruff check src tests
ruff format src testspre-commit installThe project uses GitHub Actions for continuous integration. On every push:
- Lint: Ruff checks code quality across Python 3.11, 3.12, 3.13, and 3.14
- Test: pytest runs all tests across the same Python versions
See .github/workflows/ci.yml for details.
MIT License — see LICENSE file for details.