Skip to main content

Stream speech output

POST https://api.kittenml.com/v1/audio/speech

Output streaming uses the same OpenAI-compatible speech endpoint. The request still contains the complete input text, but the client consumes audio before the complete response has downloaded.

Choose one wire format:

  • stream_format: "audio" streams raw bytes in the selected audio format and works with the official OpenAI SDK streaming helpers.
  • stream_format: "sse" sends explicit KittenML speech.audio.delta events containing Base64 audio.

To send the input text incrementally as well, use the separate text-input WebSocket.

Binary and SSE output streaming share the HTTP endpoint's 40,000-character, 256 KiB JSON-body, and 30-minute request limits. For predictable latency, keep individual requests around 400–5,000 characters.

Stream binary audio with Python

import os
from openai import OpenAI

client = OpenAI(
api_key=os.environ["KITTENML_API_KEY"],
base_url="https://api.kittenml.com/v1",
)

with client.audio.speech.with_streaming_response.create(
model="kitten-tts-mini-0.8",
input="The first sentence can play while the next sentence is generated.",
voice="Bella",
response_format="mp3",
speed=1.0,
) as audio:
audio.stream_to_file("kitten-output.mp3")

stream_to_file writes bytes as they arrive instead of keeping the complete audio response in application memory.

Stream binary audio with JavaScript

import {createWriteStream} from "node:fs";
import {Readable} from "node:stream";
import {pipeline} from "node:stream/promises";
import OpenAI from "openai";

const client = new OpenAI({
apiKey: process.env.KITTENML_API_KEY,
baseURL: "https://api.kittenml.com/v1",
});

const audio = await client.audio.speech.create({
model: "kitten-tts-mini-0.8",
input: "The first sentence can play while the next sentence is generated.",
voice: "Bella",
response_format: "mp3",
});

await pipeline(
Readable.fromWeb(audio.body),
createWriteStream("kitten-output.mp3"),
);

Stream SSE events

Set stream_format to sse when your application needs event boundaries:

curl --fail-with-body -sS -N \
https://api.kittenml.com/v1/audio/speech \
-H "Authorization: Bearer $KITTENML_API_KEY" \
-H "Content-Type: application/json" \
--data '{
"model": "kitten-tts-mini-0.8",
"input": "The first sentence can play while the next sentence is generated.",
"voice": "Bella",
"response_format": "mp3",
"stream_format": "sse"
}'

Each delta contains one Base64-encoded piece of the selected audio format:

data: {"type":"speech.audio.delta","audio":"SUQzBAAAAA..."}

data: {"type":"speech.audio.delta","audio":"qqqqqqqqqq..."}

data: {"type":"speech.audio.done","usage":{"input_tokens":0,"output_tokens":0,"total_tokens":0}}

Decode each audio value and concatenate the bytes in event order. The combined bytes are one playable file; the server does not create a separate file for each delta. speech.audio.done confirms that the stream completed.

Recover from interruption

If the connection closes before the HTTP response completes or before an SSE speech.audio.done event, treat the audio as incomplete. Discard or explicitly mark the partial output, then retry the generation as a new request. Do not blindly append a retry to the partial file because encoded audio containers may contain headers and trailers.

Runnable Python and JavaScript clients for both binary and SSE modes are in the output-streaming TTS examples.