Skip to main content

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.

Metadata

Release files for pipecat-silma 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for pipecat-silma 0.1.0
File Size Uploaded
pipecat_silma-0.1.0.tar.gz 26.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for pipecat-silma 0.1.0
File Interpreter ABI Platform
pipecat_silma-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 44.1 kB

Release files / pipecat_silma-0.1.0.tar.gz

Download URL pipecat_silma-0.1.0.tar.gz
Size 26.9 kB
Tags Source
SHA-256 checksum
How to use checksums
ec530a881e0b1ec73947a0b9f717d4548638530650782c646530534785d725db
BLAKE2b-256 checksum
How to use checksums
f71b95585d33f3f73a2cc9e8a076ec1c4634dab4ee94455a9fd4cc82e903f010
Upload date
Uploaded using Trusted Publishing?
What is 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}

Release files / pipecat_silma-0.1.0-py3-none-any.whl

Download URL pipecat_silma-0.1.0-py3-none-any.whl
Size 17.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
f960f6283b6b7445ac74bea7a4656c1f97bc06fb74fd71835a58dd4c3d51fa44
BLAKE2b-256 checksum
How to use checksums
619a2ddf7e95292432dee6b4f55f238eeb9735bcfaa003ffb955b6c1d4c64293
Upload date
Uploaded using Trusted Publishing?
What is 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}

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page