AI Gateway Text to Speech
Generate spoken audio from text with ElevenLabs, Google, Microsoft, and OpenAI speech models. Use this for voiceovers, audio versions of written content, or spoken responses in your app.
Use this to turn text into spoken audio. For live, two-way voice, see Realtime; to transcribe recorded audio, see Speech to Text.
| Provider | Model ID |
|---|---|
| ElevenLabs | elevenlabs/eleven-flash-v2 |
| ElevenLabs | elevenlabs/eleven-flash-v2.5 |
| ElevenLabs | elevenlabs/eleven-multilingual-v2 |
| ElevenLabs | elevenlabs/eleven-v3 |
| ElevenLabs | elevenlabs/eleven-v3-conversational |
| ElevenLabs | elevenlabs/eleven-v4 |
| ElevenLabs | elevenlabs/eleven-v4-turbo |
| ElevenLabs | elevenlabs/music-v2 |
| ElevenLabs | elevenlabs/music-v2.5 |
| ElevenLabs | elevenlabs/sound-effects-v2 |
google/gemini-3.8-flash-lite-tts | |
google/gemini-3.8-flash-tts | |
| Microsoft | microsoft/mai-voice-2 |
| Microsoft | microsoft/mai-voice-2-flash |
| Microsoft | microsoft/mai-voice-2.1 |
| Microsoft | microsoft/mai-voice-2.1-flash |
| OpenAI | openai/tts-1 |
| OpenAI | openai/tts-1-hd |
For SDK options and result types, see AI SDK speech and Python speech.
Pass a speech model ID directly to generateSpeech. The AI SDK uses AI Gateway by default:
import { generateSpeech } from 'ai';
import { writeFile } from 'node:fs/promises';
const result = await generateSpeech({
model: 'openai/tts-1',
text: 'Hello! Thanks for trying out AI Gateway.',
voice: 'alloy',
outputFormat: 'mp3',
});
await writeFile('greeting.mp3', result.audio.uint8Array);
console.log("Saved greeting.mp3");import asyncio
import ai
import base64
from pathlib import Path
async def main():
result = await ai.ops.generate_audio(
ai.get_model('openai/tts-1'),
'Hello! Thanks for trying out AI Gateway.',
params=ai.ops.AudioParams(voice="alloy", output_format="mp3"),
)
audio = result.value[0]
data = audio.data if isinstance(audio.data, bytes) else base64.b64decode(audio.data)
Path("greeting.mp3").write_bytes(data)
print("Saved greeting.mp3")
asyncio.run(main())The Python examples use the AI SDK for Python beta. These audio operations use dedicated AI Gateway endpoints. They are separate from Chat Completions, Messages, and Responses. See the Python SDK setup for installation requirements.
Pass an ElevenLabs model ID to generateSpeech. Set voice to an ElevenLabs voice ID, such as hpp4J3VqNfWAUOO0d1Us (Bella):
import { generateSpeech } from 'ai';
import { writeFile } from 'node:fs/promises';
const result = await generateSpeech({
model: 'elevenlabs/eleven-flash-v2.5',
text: 'Welcome to the audio edition.',
voice: 'hpp4J3VqNfWAUOO0d1Us',
outputFormat: 'mp3',
});
await writeFile('greeting.mp3', result.audio.uint8Array);Use experimental_streamSpeech to receive audio chunks as the model generates them. text accepts a string or a stream of text deltas:
import { experimental_streamSpeech as streamSpeech } from 'ai';
import { writeFile } from 'node:fs/promises';
const result = streamSpeech({
model: 'elevenlabs/eleven-flash-v2.5',
text: 'Welcome to the audio edition.',
voice: 'hpp4J3VqNfWAUOO0d1Us',
outputFormat: { type: 'audio/mpeg' },
});
const chunks: Uint8Array[] = [];
for await (const chunk of result.audioStream) {
chunks.push(chunk);
}
await writeFile('greeting.mp3', Buffer.concat(chunks));Flash v2, Flash v2.5, and Multilingual v2 stream one voice per connection. To stream v3, v3 Conversational, v4, or v4 Turbo, set providerOptions.elevenlabs.dialogue.voices. For example, replace the streamSpeech call above with:
const result = streamSpeech({
model: 'elevenlabs/eleven-v4',
text: [
{ type: 'text', text: 'Welcome to the audio edition. ', voice: 'hpp4J3VqNfWAUOO0d1Us' },
{ type: 'text', text: 'Thanks for listening.', voice: 'CwhRBWXzGAHq8TQ4Fs17' },
],
outputFormat: { type: 'audio/mpeg' },
providerOptions: {
elevenlabs: {
dialogue: { voices: ['hpp4J3VqNfWAUOO0d1Us', 'CwhRBWXzGAHq8TQ4Fs17'] },
},
},
});Each text part's voice must appear in dialogue.voices. v3 Conversational accepts exactly one voice. For more options, see AI SDK speech.
Eleven v4 and v3 read audio tags in square brackets as delivery directions rather than words to say. Tags can set:
- Emotion, such as
[whispers]or[excited] - Reactions, such as
[laughs]or[sighs] - Sound cues, such as
[footsteps]
For example, replace the generateSpeech call in the first ElevenLabs example with:
const result = await generateSpeech({
model: 'elevenlabs/eleven-v4',
text: '[whispers] The deploy is live. [laughs] On a Friday.',
voice: 'hpp4J3VqNfWAUOO0d1Us',
});Use elevenlabs/music-v2.5 or elevenlabs/music-v2 with generateSpeech to turn a description into music. Use AI SDK v7. Omit voice; these models do not support streaming:
import { generateSpeech } from 'ai';
import { writeFile } from 'node:fs/promises';
const result = await generateSpeech({
model: 'elevenlabs/music-v2.5',
text: 'An upbeat synthwave intro with driving bass.',
providerOptions: {
elevenlabs: { musicLengthMs: 5000 },
},
});
await writeFile('audio.mp3', result.audio.uint8Array);To generate sound effects, replace the generateSpeech call above with:
const result = await generateSpeech({
model: 'elevenlabs/sound-effects-v2',
text: 'Glass shattering on a concrete floor.',
providerOptions: {
elevenlabs: { durationSeconds: 2 },
},
});Music also accepts forceInstrumental to leave out vocals, and compositionPlan to set the style and length of each section in place of the text prompt. Sound effects also accept loop for a clip that repeats without a gap, and promptInfluence, from 0 to 1, for how closely the result follows the description. For every option, see the AI SDK ElevenLabs provider.
Use either google/gemini-3.8-flash-lite-tts or google/gemini-3.8-flash-tts with generateSpeech. Both support single-voice narration and two-speaker dialogue.
Choose a prebuilt voice such as Kore, Puck, Zephyr, or Charon. Voice names are case-sensitive, and the default is Kore. Set instructions to control delivery without changing the spoken text:
import { generateSpeech } from 'ai';
import { writeFile } from 'node:fs/promises';
const result = await generateSpeech({
model: 'google/gemini-3.8-flash-lite-tts',
text: 'Welcome to the audio edition.',
voice: 'Kore',
instructions: 'Warm, relaxed, and speaking slowly',
outputFormat: 'wav',
});
await writeFile('greeting.wav', result.audio.uint8Array);
console.log('Saved greeting.wav');import { generateSpeech } from 'ai';
import { writeFile } from 'node:fs/promises';
const result = await generateSpeech({
model: 'google/gemini-3.8-flash-lite-tts',
text: 'Welcome to the audio edition.',
voice: 'Kore',
instructions: 'Warm, relaxed, and speaking slowly',
outputFormat: 'wav',
});
await writeFile('greeting.wav', result.audio.uint8Array);
console.log('Saved greeting.wav');Google returns WAV audio by default. Save result.audio.uint8Array directly as it already includes the WAV header. Gemini 3.8 also supports pcm, mulaw, and alaw through outputFormat.
For two-speaker dialogue, configure voices and structured turns under providerOptions.google. Set text to an empty string because turns supplies the transcript. Each turn's speechMetadata.speaker must match a configured speaker:
import { generateSpeech } from 'ai';
import { writeFile } from 'node:fs/promises';
const result = await generateSpeech({
model: 'google/gemini-3.8-flash-tts',
text: '',
outputFormat: 'wav',
providerOptions: {
google: {
multiSpeakerVoiceConfig: {
speakerVoiceConfigs: [
{
speaker: 'Host',
voiceConfig: { prebuiltVoiceConfig: { voiceName: 'Kore' } },
},
{
speaker: 'Guest',
voiceConfig: { prebuiltVoiceConfig: { voiceName: 'Puck' } },
},
],
},
turns: [
{
text: 'What are we exploring today?',
speechMetadata: { speaker: 'Host', style: 'curious' },
},
{
text: 'How to turn text into spoken audio.',
speechMetadata: { speaker: 'Guest', style: 'cheerful' },
},
],
},
},
});
await writeFile('dialogue.wav', result.audio.uint8Array);
console.log('Saved dialogue.wav');import { generateSpeech } from 'ai';
import { writeFile } from 'node:fs/promises';
const result = await generateSpeech({
model: 'google/gemini-3.8-flash-tts',
text: '',
outputFormat: 'wav',
providerOptions: {
google: {
multiSpeakerVoiceConfig: {
speakerVoiceConfigs: [
{
speaker: 'Host',
voiceConfig: { prebuiltVoiceConfig: { voiceName: 'Kore' } },
},
{
speaker: 'Guest',
voiceConfig: { prebuiltVoiceConfig: { voiceName: 'Puck' } },
},
],
},
turns: [
{
text: 'What are we exploring today?',
speechMetadata: { speaker: 'Host', style: 'curious' },
},
{
text: 'How to turn text into spoken audio.',
speechMetadata: { speaker: 'Guest', style: 'cheerful' },
},
],
},
},
});
await writeFile('dialogue.wav', result.audio.uint8Array);
console.log('Saved dialogue.wav');A turn's speechMetadata.style overrides instructions. Turns without a style inherit instructions. For more options, see the AI SDK Google speech documentation.
Use microsoft/mai-voice-2.1 or microsoft/mai-voice-2 for high-fidelity, long-form narration, and microsoft/mai-voice-2.1-flash or microsoft/mai-voice-2-flash for low-latency voice agents. All four models share the same voices and options.
Choose a prebuilt voice such as en-US-Harper, de-DE-Mia, or es-MX-Valeria. Each voice name includes its locale, which sets the spoken language, and the default is en-US-Harper. Set providerOptions.azure.style to control delivery, and styleDegree to set its intensity:
import { generateSpeech } from 'ai';
import { writeFile } from 'node:fs/promises';
const result = await generateSpeech({
model: 'microsoft/mai-voice-2-flash',
text: 'Thanks for calling! Your order shipped this morning.',
voice: 'en-US-Ethan',
outputFormat: 'mp3',
providerOptions: {
azure: { style: 'excited', styleDegree: 1.5 },
},
});
await writeFile('order-update.mp3', result.audio.uint8Array);
console.log('Saved order-update.mp3');import { generateSpeech } from 'ai';
import { writeFile } from 'node:fs/promises';
const result = await generateSpeech({
model: 'microsoft/mai-voice-2-flash',
text: 'Thanks for calling! Your order shipped this morning.',
voice: 'en-US-Ethan',
outputFormat: 'mp3',
providerOptions: {
azure: { style: 'excited', styleDegree: 1.5 },
},
});
await writeFile('order-update.mp3', result.audio.uint8Array);
console.log('Saved order-update.mp3');Microsoft returns MP3 audio by default. MAI-Voice also supports wav, pcm, and opus through outputFormat. When you omit voice, language picks a default voice for that language, such as de-DE-Mia for de. For more options, see the AI SDK Azure speech documentation.
| Option | Description |
|---|---|
text | The text to convert to speech. Required. |
voice | The voice to use, such as alloy. Available voices depend on the model. |
outputFormat | The audio format, such as mp3 or wav. |
instructions | Directions for how the model should speak, such as tone or pacing. |
speed | Playback speed. Defaults to 1. |
language | The language of the input text. |
Support for each option varies by model. Unsupported options are reported in warnings on the result instead of failing the request.
You can also call the speech endpoint directly. Send a POST request with the model in the ai-model-id header. The response contains the audio as a base64-encoded string:
import { writeFile } from 'node:fs/promises';
const response = await fetch(
'https://ai-gateway.vercel.sh/v4/ai/speech-model',
{
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.AI_GATEWAY_API_KEY}`,
'ai-gateway-protocol-version': '0.0.1',
'ai-speech-model-specification-version': '4',
'ai-model-id': 'openai/tts-1',
'Content-Type': 'application/json',
},
body: JSON.stringify({
text: 'Hello! Thanks for trying out AI Gateway.',
voice: 'alloy',
outputFormat: 'mp3',
}),
},
);
const result = await response.json();
await writeFile('greeting.mp3', Buffer.from(result.audio, 'base64'));
console.log("Saved greeting.mp3");import json
import os
import urllib.request
request = urllib.request.Request(
'https://ai-gateway.vercel.sh/v4/ai/speech-model',
data=json.dumps({'text': 'Hello! Thanks for trying out AI Gateway.', 'voice': 'alloy', 'outputFormat': 'mp3'}).encode(),
headers={'Authorization': "Bearer " + os.environ["AI_GATEWAY_API_KEY"], 'ai-gateway-protocol-version': '0.0.1', 'ai-speech-model-specification-version': '4', 'ai-model-id': 'openai/tts-1', 'Content-Type': 'application/json'},
)
with urllib.request.urlopen(request) as response:
print(json.load(response))set -euo pipefail
curl --fail-with-body -X POST https://ai-gateway.vercel.sh/v4/ai/speech-model \
-H "Authorization: Bearer $AI_GATEWAY_API_KEY" \
-H "ai-gateway-protocol-version: 0.0.1" \
-H "ai-speech-model-specification-version: 4" \
-H "ai-model-id: openai/tts-1" \
-H "Content-Type: application/json" \
-d '{
"text": "Hello! Thanks for trying out AI Gateway.",
"voice": "alloy",
"outputFormat": "mp3"
}' | jq -r '.audio' | base64 -d > greeting.mp3
if [ -s greeting.mp3 ]; then echo "Saved greeting.mp3"; else exit 1; fiThe response is a JSON object with the base64-encoded audio:
{
"audio": "SUQzBAAAAAAA...",
"warnings": []
}- Audio returns base64-encoded in a JSON response. Streaming audio output is not supported.
- Google speech models don't support
speedorlanguage. Set pacing throughinstructionssince the model detects the language from the text. - Microsoft speech models don't support
instructions. Set the delivery withproviderOptions.azure.styleinstead. - Microsoft speech models reject unknown voices and unsupported styles.
Was this helpful?