Skip to content

SPEV: turn decisions up to 36% sooner. Details →

Pipecat: text to speech

Speak the reply in a Pipecat pipeline with a Sprag voice.

SpragTTSService speaks the reply in a Pipecat pipeline. It holds one WebSocket to wss://api.sprag.ai/v1/audio/speech and sends each sentence as the LLM produces it, so the first sentence plays while the rest of the reply is still being written. Audio comes back as 24 kHz PCM16.

Setup

from pipecat_sprag.tts import SpragTTSService

tts = SpragTTSService(
    settings=SpragTTSService.Settings(model="chorus", voice="marin"),
)

Add it to the pipeline in the speak position, between the LLM and the transport output:

pipeline = Pipeline([
    transport.input(),
    stt,
    user_aggregator,
    llm,
    tts,
    transport.output(),
    assistant_aggregator,
])
ArgumentRequiredTypeNotes
settings.modelNostringA speech model id from Models. Defaults to chorus.
settings.voiceNostringA preset id, or the id of a voice your organization created. Defaults to wade.
api_keyNostringYour Sprag API key. Defaults to SPRAG_API_KEY.
urlNostringDefaults to wss://api.sprag.ai/v1/audio/speech.

How it works

Each sentence is one response on the session. Responses are spoken in the order they were sent, and each response's audio is delivered to the turn it belongs to. SpragTTSService reports time to first byte and the characters spoken as Pipecat metrics.

If the user interrupts, SpragTTSService closes the connection and opens a new one, because a response cannot be stopped once it has started.

model and voice are fixed for the life of a session. If a TTSUpdateSettingsFrame changes either, SpragTTSService opens a new session with the new settings.

Voices

voice takes any Sprag voice id. A voice returned by POST /v1/audio/voices, designed or cloned, is passed the same way as a preset id. See Voice presets, Voice design, and Voice cloning. To clone a speaker in a Pipecat pipeline, create a voice from the clip and pass its id.

Errors

If voice is not a voice of the model, the session is refused with the error code unknown_voice. SpragTTSService pushes an ErrorFrame carrying that code, and the reply is not spoken. More information about the session's errors can be found in the WebSocket docs.

Pipecat's OpenAI service

OpenAITTSService posts each sentence to POST /v1/audio/speech and plays the response. It runs against Sprag with base_url and api_key passed to the constructor.

import os

from pipecat.services.openai.tts import VALID_VOICES, OpenAITTSService

for voice_id in ("marin", "dominic"):
    VALID_VOICES[voice_id] = voice_id

tts = OpenAITTSService(
    api_key=os.environ["SPRAG_API_KEY"],
    base_url="https://api.sprag.ai/v1",
    sample_rate=24000,
    settings=OpenAITTSService.Settings(
        model="chorus",
        voice="marin",
        speed=1.1,
    ),
)

OpenAITTSService validates voice against VALID_VOICES, its list of OpenAI voice names, before sending a request. Register every Sprag voice id the pipeline can reach, including ids you switch to later with a TTSUpdateSettingsFrame, and set voice explicitly. speed is sent as the field of the same name on POST /v1/audio/speech. Audio is 24 kHz PCM, so pass sample_rate=24000 for the transport to resample when the pipeline runs at another rate.