Piper text-to-speech (synaplan-tts)
Module id: piper_tts · Kind: sidecar · Configured by: SYNAPLAN_TTS_URL · Capability: text_to_speech · Provider: piper
Spoken answers without a cloud: synaplan-tts is a small HTTP service around Piper with five voices baked into the image — English, German, Spanish, French, Turkish. The UI language picks the voice; the audio never leaves your infrastructure. Off by default.
The companion page Text-to-Speech covers voices, the image and adding your own models. This page is the module view.
What it adds
- The speaker control on chat answers, using a local voice.
- The
text_to_speechcapability the assistant can use in multi-task plans ("read this back to me"). - A voice per UI language — German UI → Thorsten, Spanish → davefx, and so on — with no separate picker to configure.
Without it
The speaker control does not appear and the capability inventory reports text-to-speech as unavailable — unless you use a cloud voice instead: ELEVENLABS_API_KEY, or a catalog TTS model from Gemini, Mistral Voxtral or xAI. Those live inside the main app and do not need this module. Speech input (Whisper transcription) ships with the core and is unaffected either way.
How to enable
Option A — Compose profile (recommended)
docker compose --profile tts up -d # dev / evaluation stack
docker compose -f docker-compose-minimal.yml --profile tts up -d # minimal stack
This pulls ghcr.io/metadist/synaplan-tts and binds it to 127.0.0.1:10200. Both Compose files default SYNAPLAN_TTS_URL to http://host.docker.internal:10200, so the backend finds it without further configuration.
Option B — standalone container, same or another host
docker run -d --name synaplan-tts \
-p 127.0.0.1:10200:10200 \
ghcr.io/metadist/synaplan-tts:latest
Then point the backend at it and restart backend + worker:
SYNAPLAN_TTS_URL=http://host.docker.internal:10200 # same host
SYNAPLAN_TTS_URL=http://10.0.0.7:10200 # a LAN box or GPU host serving several Synaplan nodes
Production deploy/compose.yaml does not include the service; use Option B and set the variable in deploy/.env.
Check it works
- Operate → Feature Status → Piper text-to-speech shows Available / Synaplan TTS is running. The probe is
GET /healthon the service. Synaplan TTS is not reachable means the URL is set but nothing answered; SYNAPLAN_TTS_URL is unset means the module is off. - Send a chat message and click the speaker icon on the answer.
- Directly:
curl -s http://127.0.0.1:10200/health
Configuration reference
| Variable | Default | Meaning |
|---|---|---|
SYNAPLAN_TTS_URL |
empty (Compose: http://host.docker.internal:10200) |
Base URL of synaplan-tts. Empty = module off. |
Extra voices: mount .onnx + .onnx.json Piper models into the service's extra-voices volume — see the synaplan-tts README. Cloud alternatives (ELEVENLABS_API_KEY, catalog TTS models) are provider settings, not part of this module.
Troubleshooting
not reachablealthoughcurlon the host works. The backend resolves the URL from inside its container.localhostthere is the backend; usehost.docker.internal(Compose adds the mapping) or the host's LAN address.- No speaker icon. The control only renders when the service answers; check Feature Status first, then the browser console for the
/api/v1/tts/streamcall. - Wrong voice. The backend sends the frontend locale; if it detects a different reply language, that language's voice wins. There is no manual voice picker by design.
Related
- Text-to-Speech — voices, image details, adding models, cloud alternatives
- Feature modules — states, gates, the CLI