> ## Documentation Index
> Fetch the complete documentation index at: https://docs.inputapi.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Text to speech

> Convert text to audio and save binary responses correctly.

The [speech endpoint](/en/api-reference/audio-speech.md) converts text to audio. Confirm that `API_MODEL` supports speech synthesis and set a compatible `API_VOICE`. Chat models and voice names are not interchangeable.

## Save an MP3

Configure `API_BASE_URL` (including `/v1`), `API_KEY`, and `API_MODEL` using the [Python SDK guide](/en/guides/python.md), then set `API_VOICE`. Save as `speech.py` and run `python speech.py`. It writes `speech.mp3` in the current directory without overwriting an existing file.

The example requests `response_format: mp3`, reads audio bytes, and caps the output at 16 MiB (an example-only limit). It checks HTTP status and Content-Type to avoid treating JSON errors as audio; it does not fully decode or validate the audio.

```python theme={null}
import os
from pathlib import Path
from openai import OpenAI, APIConnectionError, APIStatusError

with OpenAI(base_url=os.environ["API_BASE_URL"].rstrip("/"),
            api_key=os.environ["API_KEY"], timeout=120.0, max_retries=0) as client:
    try:
        with client.audio.speech.with_streaming_response.create(
            model=os.environ["API_MODEL"], voice=os.environ["API_VOICE"],
            input="Welcome to our application.", response_format="mp3",
        ) as response:
            media_type = response.headers.get("content-type", "").split(";")[0].lower()
            if not (media_type.startswith("audio/") or media_type == "application/octet-stream"):
                raise ValueError("Expected audio bytes.")
            audio = bytearray()
            for chunk in response.iter_bytes():
                audio.extend(chunk)
                if len(audio) > 16 * 1024 * 1024:
                    raise ValueError("Example output exceeds 16 MiB.")
            if not audio:
                raise ValueError("Empty audio.")
            with Path("speech.mp3").open("xb") as target:
                target.write(audio)
            print("Saved speech.mp3")
    except APIStatusError as error:
        raise SystemExit(f"Request failed (HTTP {error.status_code}). Check the request logs.")
    except APIConnectionError:
        raise SystemExit("Connection failed; check before resubmitting speech.")
    except (ValueError, OSError):
        raise SystemExit("Cannot save speech. Check the content type, size, and output file.")
```

## Formats and streaming boundaries

`input` is text, `voice` selects a voice, and `instructions` provides style guidance on supporting models. Speed, input length, languages, and output formats depend on the model. Changing an extension does not transcode audio. PCM also requires the correct sample rate, bit depth, and channel count; it is not a WAV file.

SDK `with_streaming_response` reads HTTP audio bytes in chunks. It is not SSE or a bidirectional live voice session. Use `stream_format: sse` only with explicit channel support and a matching event parser. Microphone interaction, WebRTC, and Realtime sessions are outside this file-synthesis workflow.

## Handle failures

For non-2xx responses, check the model, voice, parameters, permissions, and logs. Do not treat interrupted audio as a complete result; this example collects the full response before writing. Automatic retries are disabled to avoid duplicate synthesis after an ambiguous failure. Clearly label synthesized speech in your product; OpenAI explicitly requires disclosure, as described in its [text-to-speech guide](https://developers.openai.com/api/docs/guides/text-to-speech).

[简体中文](/zh/guides/speech.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.