python text to speech api tutorial: build a speech app with rumik silk
python text to speech api tutorial: build a speech app with rumik silk
python text to speech api tutorial: build a speech app with rumik silk
people don't always want to read everything on a screen. customers may need to hear an order update, employees may need narration for a training course, or a caller may be waiting for an answer from a voice agent. text to speech makes those experiences possible, whether the audio is prepared in advance as a voiceover or generated during a conversation.
in this tutorial, we'll build a python app using rumik silk text to speech models. we'll cover saving audio, choosing a voice and speaking style, and playing speech as it streams. the examples use english and the rumik python sdk, with the setup and playback code included.
install the sdk and connect your rumik account
we'll use python with the rumik python sdk handling the requests to silk. if you're adding this to an existing python project, this is the dependency it needs:
python -mpython -myou'll see rumik-ai in the install command and rumikai in the imports. they're the package and module names for the same sdk. we're using version 1.0.0 in these examples.
the app also needs an api key from the rumik playground, where you can create one under api keys. we'll keep it out of the python file by making it available through the terminal:

windows powershell
$env:RUMIK_API_KEY = "your_api_key"
$env:RUMIK_API_KEY = "your_api_key"
mac or linux
export RUMIK_API_KEY="your_api_key"
export RUMIK_API_KEY="your_api_key"
note: your actual key goes in place of
your_api_key. the sdk picks upRUMIK_API_KEYautomatically from this terminal session. on machines where python is installed aspython3, that command works in place ofpythonthroughout the examples.
convert text to speech and save it as a wav file
our first input is an order update. we'll ask rumik silk for a steady, professional read and save the result as order-update.wav, ready to open in an audio player.
the request and file save sit together in our first script, generate_speech.py:
from rumikai import Rumik TEXT = "Your order is confirmed. Delivery is scheduled for Friday at 1 PM." def main(): with Rumik() as client: audio = client.speech.create( text=TEXT, model="mulberry", speaker="emma", description="a calm female voice with an american accent and steady pacing, like a customer support agent", ) audio.save("order-update.wav") print("Saved order-update.wav") if __name__ == "__main__": main()
from rumikai import Rumik TEXT = "Your order is confirmed. Delivery is scheduled for Friday at 1 PM." def main(): with Rumik() as client: audio = client.speech.create( text=TEXT, model="mulberry", speaker="emma", description="a calm female voice with an american accent and steady pacing, like a customer support agent", ) audio.save("order-update.wav") print("Saved order-update.wav") if __name__ == "__main__": main()
here's what we're sending in that request:
text: the content the app needs to say.model:mulberry, the api value for silk mulberry 1.5.speaker:emma, the named voice selected for our english order update.description: the accent, pace, and delivery you're asking for.
we're using silk mulberry 1.5 with the emma voice preset. the model value in the request is mulberry.
the terminal where we set the key already has what the sdk needs. from there, we can run:
once the request succeeds, you'll find order-update.wav beside the script. opening that file in an audio player lets you hear the update. saving and playback are separate here, which gives you a file to review or reuse.
here's how the order update sounds with emma:
TEXT is where your own content will go. each run makes a new synthesis request and replaces the same file. a different output filename lets you keep earlier versions for comparison.
note: mulberry 1.5 accepts up to 2,000 characters of text per request. longer scripts need to be split before they are sent to the api.
set the speaker, accent, and pace
the order update currently asks for a steady delivery. for a different script, you might want a slower read. the request keeps the speaker and delivery separate, so we can adjust either:
speakerselects a named voice. we're usingemma. other named voices includesiya,ira, andnoah.descriptionguides the delivery. this is where we ask for an accent, pace, and tone in plain language. it stays in the request even when we choose a named speaker.
we can ask for a diffrent version of the order update with this description inside client.speech.create():
description="a male 40s british voice, low pitch, gravelly timbre, neutral, formal register, like a dramatic narrator."
description="a male 40s british voice, low pitch, gravelly timbre, neutral, formal register, like a dramatic narrator."
running generate_speech.py again gives us another version to listen to. keeping the text and speaker fixed makes the pace comparison clearer. if it's the voice itself you want to change, the speaker field is the next thing to try.
for e-learning, a passage with the actual names, dates, and numbers gives you something representative to listen to before generating the full script.
stream text to speech from python to your speakers
the saved file gives us something to review or reuse. for spoken responses, we can also have the app play audio as it arrives. that needs a connection to silk and a player on our computer.
we'll add the sdk's websocket support and sounddevice for playback:
python -m pip install "rumik-ai[ws]" "sounddevice"
python -m pip install "rumik-ai[ws]" "sounddevice"
rumik-ai[ws]adds the websocket support used by the sdk.sounddevicesends audio to your computer's output device. on linux, it may also need the portaudio system library, covered in the installation guide.
the audio arrives as 24 khz, mono, signed 16-bit pcm. the chunks don't carry a wav header, so the player needs the sample rate, channel count, and sample format set explicitly.
our second script, stream_speech.py, connects those pieces:
import sounddevice as sd from rumikai import Rumik TEXT = "Your order is confirmed. Delivery is scheduled for Friday at 3 PM." def main(): with Rumik() as client: with sd.RawOutputStream( samplerate=24000, channels=1, dtype="int16", ) as player: with client.speech.stream( text=TEXT, model="mulberry", speaker="emma", description="a calm female voice with an american accent and steady pacing, like a customer support agent", ) as stream: pending = b"" played_audio = False for chunk in stream: pending += chunk complete_bytes = len(pending) - (len(pending) % 2) if complete_bytes: player.write(pending[:complete_bytes]) pending = pending[complete_bytes:] played_audio = True if pending: raise RuntimeError("The stream ended with an incomplete audio sample.") if not played_audio: raise RuntimeError("The stream returned no audio.") print("Playback finished.") if __name__ == "__main__": main()
import sounddevice as sd from rumikai import Rumik TEXT = "Your order is confirmed. Delivery is scheduled for Friday at 3 PM." def main(): with Rumik() as client: with sd.RawOutputStream( samplerate=24000, channels=1, dtype="int16", ) as player: with client.speech.stream( text=TEXT, model="mulberry", speaker="emma", description="a calm female voice with an american accent and steady pacing, like a customer support agent", ) as stream: pending = b"" played_audio = False for chunk in stream: pending += chunk complete_bytes = len(pending) - (len(pending) % 2) if complete_bytes: player.write(pending[:complete_bytes]) pending = pending[complete_bytes:] played_audio = True if pending: raise RuntimeError("The stream ended with an incomplete audio sample.") if not played_audio: raise RuntimeError("The stream returned no audio.") print("Playback finished.") if __name__ == "__main__": main()
here's where the audio goes:
client.speech.stream()receives chunks from silk.player.write()passes complete samples to the speakers through sounddevice's raw audio output.pendingkeeps a leftover byte when a chunk ends partway through a two-byte sample.
the with blocks close the connections and audio device when the script finishes or fails. if you found a speaker and description you prefer in the previous example, the same settings belong in this request too.
we can run this from the same terminal as the first script:
after a successful request, you should hear the order update as the audio arrives. the player uses your computer's default output, so there's no saved file to open this time.
if you can't hear audio: python -m sounddevice lists the available devices. the output device and volume are the first things to check. a different output can be selected with device=... in sd.RawOutputStream(), using the numeric id from that list.
note: we're sending the complete text at the start and streaming the generated audio back. this example doesn't feed text word by word from an llm. playback also needs a computer with speakers or headphones, which a remote server may not have.
take your python speech app beyond the example
your app already has the text: an order update, a training lesson, or a reply to a customer. with the connection to rumik silk in place, those inputs can use the voice settings and audio handling we've built here.
a saved wav works when your team needs to review or reuse the audio. streaming fits responses that need to play as they're generated. whichever path you use, the most useful next test is your own content, with the names, numbers, and phrasing your users will hear.
people don't always want to read everything on a screen. customers may need to hear an order update, employees may need narration for a training course, or a caller may be waiting for an answer from a voice agent. text to speech makes those experiences possible, whether the audio is prepared in advance as a voiceover or generated during a conversation.
in this tutorial, we'll build a python app using rumik silk text to speech models. we'll cover saving audio, choosing a voice and speaking style, and playing speech as it streams. the examples use english and the rumik python sdk, with the setup and playback code included.
install the sdk and connect your rumik account
we'll use python with the rumik python sdk handling the requests to silk. if you're adding this to an existing python project, this is the dependency it needs:
python -myou'll see rumik-ai in the install command and rumikai in the imports. they're the package and module names for the same sdk. we're using version 1.0.0 in these examples.
the app also needs an api key from the rumik playground, where you can create one under api keys. we'll keep it out of the python file by making it available through the terminal:

windows powershell
$env:RUMIK_API_KEY = "your_api_key"
mac or linux
export RUMIK_API_KEY="your_api_key"
note: your actual key goes in place of
your_api_key. the sdk picks upRUMIK_API_KEYautomatically from this terminal session. on machines where python is installed aspython3, that command works in place ofpythonthroughout the examples.
convert text to speech and save it as a wav file
our first input is an order update. we'll ask rumik silk for a steady, professional read and save the result as order-update.wav, ready to open in an audio player.
the request and file save sit together in our first script, generate_speech.py:
from rumikai import Rumik TEXT = "Your order is confirmed. Delivery is scheduled for Friday at 1 PM." def main(): with Rumik() as client: audio = client.speech.create( text=TEXT, model="mulberry", speaker="emma", description="a calm female voice with an american accent and steady pacing, like a customer support agent", ) audio.save("order-update.wav") print("Saved order-update.wav") if __name__ == "__main__": main()
here's what we're sending in that request:
text: the content the app needs to say.model:mulberry, the api value for silk mulberry 1.5.speaker:emma, the named voice selected for our english order update.description: the accent, pace, and delivery you're asking for.
we're using silk mulberry 1.5 with the emma voice preset. the model value in the request is mulberry.
the terminal where we set the key already has what the sdk needs. from there, we can run:
once the request succeeds, you'll find order-update.wav beside the script. opening that file in an audio player lets you hear the update. saving and playback are separate here, which gives you a file to review or reuse.
here's how the order update sounds with emma:
TEXT is where your own content will go. each run makes a new synthesis request and replaces the same file. a different output filename lets you keep earlier versions for comparison.
note: mulberry 1.5 accepts up to 2,000 characters of text per request. longer scripts need to be split before they are sent to the api.
set the speaker, accent, and pace
the order update currently asks for a steady delivery. for a different script, you might want a slower read. the request keeps the speaker and delivery separate, so we can adjust either:
speakerselects a named voice. we're usingemma. other named voices includesiya,ira, andnoah.descriptionguides the delivery. this is where we ask for an accent, pace, and tone in plain language. it stays in the request even when we choose a named speaker.
we can ask for a diffrent version of the order update with this description inside client.speech.create():
description="a male 40s british voice, low pitch, gravelly timbre, neutral, formal register, like a dramatic narrator."
running generate_speech.py again gives us another version to listen to. keeping the text and speaker fixed makes the pace comparison clearer. if it's the voice itself you want to change, the speaker field is the next thing to try.
for e-learning, a passage with the actual names, dates, and numbers gives you something representative to listen to before generating the full script.
stream text to speech from python to your speakers
the saved file gives us something to review or reuse. for spoken responses, we can also have the app play audio as it arrives. that needs a connection to silk and a player on our computer.
we'll add the sdk's websocket support and sounddevice for playback:
python -m pip install "rumik-ai[ws]" "sounddevice"
rumik-ai[ws]adds the websocket support used by the sdk.sounddevicesends audio to your computer's output device. on linux, it may also need the portaudio system library, covered in the installation guide.
the audio arrives as 24 khz, mono, signed 16-bit pcm. the chunks don't carry a wav header, so the player needs the sample rate, channel count, and sample format set explicitly.
our second script, stream_speech.py, connects those pieces:
import sounddevice as sd from rumikai import Rumik TEXT = "Your order is confirmed. Delivery is scheduled for Friday at 3 PM." def main(): with Rumik() as client: with sd.RawOutputStream( samplerate=24000, channels=1, dtype="int16", ) as player: with client.speech.stream( text=TEXT, model="mulberry", speaker="emma", description="a calm female voice with an american accent and steady pacing, like a customer support agent", ) as stream: pending = b"" played_audio = False for chunk in stream: pending += chunk complete_bytes = len(pending) - (len(pending) % 2) if complete_bytes: player.write(pending[:complete_bytes]) pending = pending[complete_bytes:] played_audio = True if pending: raise RuntimeError("The stream ended with an incomplete audio sample.") if not played_audio: raise RuntimeError("The stream returned no audio.") print("Playback finished.") if __name__ == "__main__": main()
here's where the audio goes:
client.speech.stream()receives chunks from silk.player.write()passes complete samples to the speakers through sounddevice's raw audio output.pendingkeeps a leftover byte when a chunk ends partway through a two-byte sample.
the with blocks close the connections and audio device when the script finishes or fails. if you found a speaker and description you prefer in the previous example, the same settings belong in this request too.
we can run this from the same terminal as the first script:
after a successful request, you should hear the order update as the audio arrives. the player uses your computer's default output, so there's no saved file to open this time.
if you can't hear audio: python -m sounddevice lists the available devices. the output device and volume are the first things to check. a different output can be selected with device=... in sd.RawOutputStream(), using the numeric id from that list.
note: we're sending the complete text at the start and streaming the generated audio back. this example doesn't feed text word by word from an llm. playback also needs a computer with speakers or headphones, which a remote server may not have.
take your python speech app beyond the example
your app already has the text: an order update, a training lesson, or a reply to a customer. with the connection to rumik silk in place, those inputs can use the voice settings and audio handling we've built here.
a saved wav works when your team needs to review or reuse the audio. streaming fits responses that need to play as they're generated. whichever path you use, the most useful next test is your own content, with the names, numbers, and phrasing your users will hear.
frequently asked questions
frequently asked questions
frequently asked questions






read other articles
read other articles
read other articles




