SILMA TTS for Pipecat
A Pipecat text-to-speech integration for SILMA AI — English and Arabic speech synthesis, with Modern Standard Arabic and the Saudi (Najdi) dialect.
Maintained by SILMA AI. We build the TTS service this integration talks to, so it stays current with the API.
Tested with Pipecat v1.8.1.
Installation
uv add pipecat-silma
# or
pip install pipecat-silma
Prerequisites
An API key from app.silma.ai:
export SILMA_API_KEY="..."
Usage
from pipecat_silma import SilmaTTSService
tts = SilmaTTSService(
api_key=os.environ["SILMA_API_KEY"],
settings=SilmaTTSService.Settings(
model="silma-tts-v2-english",
voice="emma",
),
)
pipeline = Pipeline(
[
transport.input(),
stt,
user_aggregator,
llm,
tts,
transport.output(),
assistant_aggregator,
]
)
Models and voices
SILMA selects the language by model rather than by a language parameter. You
can still pass a Pipecat Language, in settings or in a
TTSUpdateSettingsFrame, and it will switch the model for you.
| Model | Language | Voices |
|---|---|---|
silma-tts-v2-english |
English | james, emma |
silma-tts-v2-msa |
Modern Standard Arabic | sarah, salma, salwa, saja, sultan, salman, sulaiman, salim |
silma-tts-v2-ksa |
Arabic, Saudi (Najdi) dialect | same as MSA |
Configuration
Constructor arguments, all also available on SilmaTTSService.Settings:
| Parameter | Default | Description |
|---|---|---|
api_key |
$SILMA_API_KEY |
Your SILMA API key |
model |
silma-tts-v2-msa |
Model id, which also picks the language |
voice |
sarah |
Pre-defined voice id |
creativity |
server default | Variance in speech prosody |
speed |
server default | Speed of the generated speech |
user_id |
None |
Required for cloned voices and pronunciation overrides |
custom_audio_id |
None |
Cloned voice id; requires user_id |
enable_server_pronunciation_overrides |
False |
Apply account-level overrides; requires user_id |
base_url |
https://api.silma.ai/tts/v2 |
API base URL |
keepalive_interval_s |
20.0 |
Ping interval for an idle connection; lower it if the proxy in front of the API has a shorter read timeout |
creativity and speed are omitted from the request unless you set them, so
SILMA's own defaults apply.
Settings can be changed while the pipeline runs, via Pipecat's
TTSUpdateSettingsFrame:
await task.queue_frame(TTSUpdateSettingsFrame(settings=SilmaTTSService.Settings(voice="salma")))
Cloned voices
Upload a voice under Custom Voices at app.silma.ai/voices, then pass its id together with your user id:
SilmaTTSService(
settings=SilmaTTSService.Settings(
model="silma-tts-v2-ksa",
voice="sarah",
user_id="...",
custom_audio_id="voice_1769817467123",
),
)
Pronunciation hints
SILMA reads phone numbers, emails and links correctly when they are tagged:
You can reach us on <STAG_PN>92005455</STAG_PN> or at <STAG_EMAIL>hi@silma.ai</STAG_EMAIL>.
The integration keeps these tags intact when it splits text, so a tag is never cut in half across two requests. Instruct your LLM to emit them — the example shows how.
Account-level pronunciation overrides configured at
app.silma.ai/control apply when you pass
user_id and enable_server_pronunciation_overrides=True.
Running the example
examples/foundational.py is a complete voice bot
over a local WebRTC transport — no telephony account, no cloud room.
uv add pipecat-silma "pipecat-ai[webrtc,silero,openai,runner]"
export SILMA_API_KEY="..."
export OPENAI_API_KEY="..."
python examples/foundational.py
Open the URL it prints and start talking. For English:
LANGUAGE=en python examples/foundational.py
How it works
SilmaTTSService extends Pipecat's InterruptibleTTSService, which is the
right base for a websocket service with no context id and no cancel message:
the way to stop SILMA mid-utterance is to drop the socket and reconnect, and
that base class does exactly that on an interruption.
Audio. SILMA returns a 24 kHz mono float32 waveform. The service converts it
to the 16-bit PCM Pipecat carries in TTSAudioRawFrame, buffering samples that
straddle a chunk boundary so a split never produces a click. Because the API
takes no sample-rate parameter, the service pins its rate at 24000 and rejects a
request for anything else rather than mislabelling the audio — let the output
transport resample if your transport needs a different rate.
Text limits. The API caps a request at 250 characters, so a longer aggregation is split on word boundaries and sent as sequential requests over the same socket; their audio arrives in order and is concatenated into one context.
Connection. One websocket is held open and reused across turns, with a
keepalive ping every keepalive_interval_s so an idle connection is not closed
by the proxy in front of the API. On an interruption the socket is dropped and replaced — SILMA has no
cancel message, so that is how speech stops promptly, including when the user
talks over the very start of a reply. The replacement is not waited for: the
old socket is detached at once and closed in the background, because Pipecat
forwards the frame that stops playback only once the service's interruption
handler returns.
Development
uv sync --extra dev
uv run pytest # 40 tests, no API key or network needed
uv run ruff check .
uv run ruff format --check .
Two tests drive a real Pipecat pipeline to check barge-in behaviour, and Pipecat's sentence aggregator needs NLTK's sentence data for that. They skip themselves if the data is absent; to run them:
uv run python -c "import nltk; nltk.download('punkt_tab')"
License
BSD 2-Clause, matching Pipecat. See LICENSE.
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 pipecat_silma-0.1.0.tar.gz.
File metadata
- Download URL: pipecat_silma-0.1.0.tar.gz
- Upload date:
- Size: 26.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
uv/0.12.10 {"installer":{"name":"uv","version":"0.12.10","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ec530a881e0b1ec73947a0b9f717d4548638530650782c646530534785d725db
|
|
| MD5 |
4f1d130aa8c768e59be58a72c8157473
|
|
| BLAKE2b-256 |
f71b95585d33f3f73a2cc9e8a076ec1c4634dab4ee94455a9fd4cc82e903f010
|
File details
Details for the file pipecat_silma-0.1.0-py3-none-any.whl.
File metadata
- Download URL: pipecat_silma-0.1.0-py3-none-any.whl
- Upload date:
- Size: 17.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
uv/0.12.10 {"installer":{"name":"uv","version":"0.12.10","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f960f6283b6b7445ac74bea7a4656c1f97bc06fb74fd71835a58dd4c3d51fa44
|
|
| MD5 |
77e2ce18bce6fc058a2d98c61ecd0364
|
|
| BLAKE2b-256 |
619a2ddf7e95292432dee6b4f55f238eeb9735bcfaa003ffb955b6c1d4c64293
|