Speech Synthesis and Recognition
AI Gateway offers models for speech synthesis and speech recognition. You can use them to convert text into spoken audio, add voice responses to your applications, transcribe calls, and turn other audio recordings into text.
For speech synthesis, or TTS (Text-to-Speech), AI Gateway provides the openai/gpt-4o-mini-tts model.
For speech recognition, or STT (Speech-to-Text), you can use openai/gpt-4o-mini-transcribe and openai/gpt-4o-transcribe.
Speech Synthesis Capabilities Copy link
The openai/gpt-4o-mini-tts model generates audio from text you provide. It supports different languages and lets you control how the speech sounds using an instruction—for example, setting the pace, intonation, emotional tone, or overall style.
You can choose from the following voices:
alloyashballadcoralechofablenovaonyxsageshimmerversemarincedar
You can listen to samples of each voice on OpenAI.fm.
The following audio formats are supported:
mp3: the default formatopus: suited for streaming and voice communicationaac: a compressed format commonly used on mobile devicesflac: lossless compressionwav: uncompressed audiopcm: raw audio data with no file header
The wav and pcm formats work well for use cases where low latency matters. AI Gateway also supports streaming, so playback can start before the entire audio file has finished generating.
Transcription Capabilities Copy link
The openai/gpt-4o-mini-transcribe and openai/gpt-4o-transcribe models convert speech from an audio file into text. You can either let the model detect the language automatically or specify it explicitly in the request.
Transcription supports the following file formats: mp3, mp4, mpeg, mpga, m4a, wav, and webm. You can get the result back as JSON or as plain text.
You can also pass a prompt parameter with additional context in your request. This helps the model correctly recognize:
- first and last names
- product and company names
- abbreviations
- professional or technical terms
- words that are hard to identify from pronunciation alone
If a recording is split into several chunks, you can pass the text of the previous chunk in the prompt parameter. This helps the model keep context between requests.
How Tokens Are Counted Copy link
Audio models count both text tokens and audio tokens. Text tokens depend on the amount of text involved, while audio tokens depend on the length of the audio.
For speech synthesis (TTS models):
input_tokens: text tokens from the input textoutput_tokens: audio tokens from the generated recording. One second of audio counts as one audio token.
For example, if the model generates four seconds of audio, that's four output audio tokens. The number of input text tokens depends on the length of the source text.
For transcription (STT models):
input_tokens: audio tokens from the source recording, roughly 10 tokens per secondoutput_tokens: text tokens from the transcript
For example, a 10-second recording uses roughly 100 input audio tokens. The number of output text tokens depends on the length of the transcript.
Limitations And Notes Copy link
- Audio models are only available through AI Gateway.
- Streaming generation and playback are only supported for TTS.
- Real-time transcription from a microphone isn't supported.
- Transcription responses are available in JSON or plain text format.
Getting Started Copy link
To use the audio models, you'll need to create an AI Gateway API key.
The examples below use an environment variable called HOSTMAN_AI_TOKEN so you don't have to paste your key directly into your code. On Linux and macOS, you can set it with:
export HOSTMAN_AI_TOKEN="your_API_key"Install the OpenAI library:
pip install openaiCreate a client and point it to the AI Gateway base URL:
import os
from openai import OpenAI
client = OpenAI(
api_key=os.environ["HOSTMAN_AI_TOKEN"],
base_url="https://ai-api.hostman.com/v1",
)Speech Synthesis Copy link
Speech synthesis uses the audio.speech.create() method.
Generating an Audio File Copy link
In the example below, the model converts text to speech and saves the result to a file called speech.mp3:
import os
from pathlib import Path
from openai import OpenAI
client = OpenAI(
api_key=os.environ["HOSTMAN_AI_TOKEN"],
base_url="https://ai-api.hostman.com/v1",
)
speech_file = Path("speech.mp3")
with client.audio.speech.with_streaming_response.create(
model="openai/gpt-4o-mini-tts",
voice="shimmer",
input="Hello! This is a speech synthesis test.",
instructions="Speak in a calm and friendly tone.",
response_format="mp3",
) as response:
response.stream_to_file(speech_file)Parameters:
model: the speech synthesis model to usevoice: the voice used to read the textinput: the text to convert to speechinstructions: an instruction describing the speaking styleresponse_format: the format of the generated audio
Streaming Playback Copy link
To start playback before generation finishes, use the async client together with LocalAudioPlayer.
To use LocalAudioPlayer, install the numpy and sounddevice libraries:
pip install numpy sounddeviceExample of streaming playback:
import asyncio
import os
from openai import AsyncOpenAI
from openai.helpers import LocalAudioPlayer
client = AsyncOpenAI(
api_key=os.environ["HOSTMAN_AI_TOKEN"],
base_url="https://ai-api.hostman.com/v1",
)
async def main() -> None:
async with client.audio.speech.with_streaming_response.create(
model="openai/gpt-4o-mini-tts",
voice="shimmer",
input="Hello! This is a streaming speech synthesis test.",
response_format="pcm",
) as response:
await LocalAudioPlayer().play(response)
if __name__ == "__main__":
asyncio.run(main())This example uses the pcm format, which lets you play the audio as it's received from the model.
Audio Transcription Copy link
Transcription uses the audio.transcriptions.create() method.
Transcribing a File Copy link
In the example below, the model transcribes English speech from a file called audio.mp3:
import os
from openai import OpenAI
client = OpenAI(
api_key=os.environ["HOSTMAN_AI_TOKEN"],
base_url="https://ai-api.hostman.com/v1",
)
with open("audio.mp3", "rb") as audio_file:
transcription = client.audio.transcriptions.create(
model="openai/gpt-4o-mini-transcribe",
file=audio_file,
language="en",
response_format="json",
)
print(transcription.text)Parameters:
model: the transcription model to usefile: the audio file to convert to textlanguage: the language of the audio. If not specified, the model detects it automatically.response_format: the response format—json or text
Passing Context Copy link
You can use the prompt parameter to give the model relevant terms, extra context, and requirements for the output. You can also ask it to remove filler words:
import os
from openai import OpenAI
client = OpenAI(
api_key=os.environ["HOSTMAN_AI_TOKEN"],
base_url="https://ai-api.hostman.com/v1",
)
with open("meeting.mp3", "rb") as audio_file:
transcription = client.audio.transcriptions.create(
model="openai/gpt-4o-transcribe",
file=audio_file,
language="en",
response_format="json",
prompt=(
"The recording is about Kubernetes and cloud infrastructure. "
"The conversation mentions Hostman, kubectl, and Ingress. "
"Remove filler words and interjections from the transcript. "
"Keep the meaning intact and don't paraphrase the rest of the speech."
),
)
print(transcription.text)In this example, prompt helps the model recognize technical terms and sets requirements for the final text. This parameter doesn't replace the audio content—it adds context and instructions on top of it.
Transcribing Audio From a Microphone Copy link
AI Gateway doesn't support real-time transcription. To get results close to real time, you can record audio in short chunks and send each chunk to the API separately.
Install the additional libraries:
pip install numpy sounddeviceThe example below records audio in three-second chunks. A small overlap is added between adjacent chunks so the model doesn't lose words at the boundary between recordings:
import io
import os
import queue
import threading
import time
import wave
from dataclasses import dataclass
import numpy as np
import sounddevice as sd
from openai import OpenAI
MODEL = "openai/gpt-4o-mini-transcribe"
SAMPLE_RATE = 16_000
CHANNELS = 1
SAMPLE_WIDTH_BYTES = 2
CHUNK_SECONDS = 3.0
OVERLAP_SECONDS = 0.4
FRAMES_PER_BLOCK = 1_600
client = OpenAI(
api_key=os.environ["HOSTMAN_AI_TOKEN"],
base_url="https://ai-api.hostman.com/v1",
)
@dataclass
class AudioChunk:
index: int
pcm_data: bytes
audio_queue: queue.Queue[AudioChunk | None] = queue.Queue(maxsize=10)
stop_event = threading.Event()
def pcm_to_wav_bytes(pcm_data: bytes) -> io.BytesIO:
wav_buffer = io.BytesIO()
with wave.open(wav_buffer, "wb") as wav_file:
wav_file.setnchannels(CHANNELS)
wav_file.setsampwidth(SAMPLE_WIDTH_BYTES)
wav_file.setframerate(SAMPLE_RATE)
wav_file.writeframes(pcm_data)
wav_buffer.seek(0)
wav_buffer.name = "chunk.wav"
return wav_buffer
def transcription_worker() -> None:
while True:
chunk = audio_queue.get()
if chunk is None:
audio_queue.task_done()
break
try:
wav_file = pcm_to_wav_bytes(chunk.pcm_data)
started_at = time.perf_counter()
transcription = client.audio.transcriptions.create(
model=MODEL,
file=wav_file,
language="en",
response_format="json",
)
elapsed = time.perf_counter() - started_at
text = getattr(transcription, "text", "").strip()
if text:
print(
f"\n[{chunk.index:04d}] "
f"({elapsed:.2f} sec.) {text}",
flush=True,
)
else:
print(
f"\n[{chunk.index:04d}] "
f"({elapsed:.2f} sec.) [silence]",
flush=True,
)
except Exception as exc:
print(
f"\nError transcribing chunk "
f"{chunk.index}: {exc}",
flush=True,
)
finally:
audio_queue.task_done()
def record_microphone() -> None:
chunk_samples = int(SAMPLE_RATE * CHUNK_SECONDS)
overlap_samples = int(SAMPLE_RATE * OVERLAP_SECONDS)
accumulated = np.empty(0, dtype=np.int16)
previous_tail = np.empty(0, dtype=np.int16)
chunk_index = 1
print("Speak now. Press Ctrl+C to stop.")
with sd.InputStream(
samplerate=SAMPLE_RATE,
channels=CHANNELS,
dtype="int16",
blocksize=FRAMES_PER_BLOCK,
) as stream:
while not stop_event.is_set():
block, overflowed = stream.read(FRAMES_PER_BLOCK)
if overflowed:
print("\nWarning: audio buffer overflow.")
accumulated = np.concatenate((accumulated, block[:, 0]))
while len(accumulated) >= chunk_samples:
current_samples = accumulated[:chunk_samples]
accumulated = accumulated[chunk_samples:]
if len(previous_tail) > 0:
samples_to_send = np.concatenate(
(previous_tail, current_samples)
)
else:
samples_to_send = current_samples
if overlap_samples > 0:
previous_tail = current_samples[-overlap_samples:].copy()
else:
previous_tail = np.empty(0, dtype=np.int16)
audio_chunk = AudioChunk(
index=chunk_index,
pcm_data=samples_to_send.astype(
"<i2",
copy=False,
).tobytes(),
)
try:
audio_queue.put(audio_chunk, timeout=1)
print(".", end="", flush=True)
except queue.Full:
print(
"\nQueue full: chunk skipped. "
"Increase CHUNK_SECONDS or check API speed."
)
chunk_index += 1
if len(accumulated) >= SAMPLE_RATE // 2:
if len(previous_tail) > 0:
accumulated = np.concatenate(
(previous_tail, accumulated)
)
audio_queue.put(
AudioChunk(
index=chunk_index,
pcm_data=accumulated.astype(
"<i2",
copy=False,
).tobytes(),
)
)
def main() -> None:
worker = threading.Thread(
target=transcription_worker,
daemon=True,
)
worker.start()
try:
record_microphone()
except KeyboardInterrupt:
print("\nStopping recording...")
stop_event.set()
finally:
audio_queue.put(None)
audio_queue.join()
worker.join(timeout=5)
print("Done.")
if __name__ == "__main__":
main()You can adjust the CHUNK_SECONDS and OVERLAP_SECONDS values. Shorter chunks reduce latency but increase the number of requests. Because of the overlap, some words may repeat in the result—remove these duplicates during further text processing if needed.