# Text to Speech
{: .no_toc }

Convert text into spoken audio
{: .fs-6 .fw-300 }

## Table of contents
{: .no_toc .text-delta }

1. TOC
{:toc}

---

After reading this guide, you will know:

*   How to generate speech from text.
*   How to save generated audio files.
*   How to choose models, voices, and formats.
*   How to access raw audio bytes.

## Basic Speech Generation

Generate audio with the global `RubyLLM.speak` method:

```ruby
speech = RubyLLM.speak "Hello, welcome to RubyLLM!"
speech.save "welcome.mp3"
```

The return value is a `RubyLLM::Speech` object:

```ruby
speech.model
# => "gpt-4o-mini-tts"

speech.voice
# => "alloy"

speech.format
# => "mp3"

speech.mime_type
# => "audio/mpeg"

speech.to_blob
# => raw audio bytes
```

## Choosing Models

By default, RubyLLM uses `config.default_speech_model`.

```ruby
RubyLLM.speak("Ship it.", model: "gpt-4o-mini-tts")

RubyLLM.speak(
  "Say cheerfully: Have a wonderful day!",
  model: "gemini-2.5-flash-preview-tts",
  provider: :gemini
)
```

Configure the default globally:

```ruby
RubyLLM.configure do |config|
  config.default_speech_model = "gpt-4o-mini-tts"
end
```

## Voices

RubyLLM picks a provider default voice for the simple case. Pass `voice:` when you want a specific one.

```ruby
RubyLLM.speak("Welcome back.", voice: "nova")

RubyLLM.speak(
  "Say warmly: Welcome back.",
  provider: :gemini,
  model: "gemini-2.5-flash-preview-tts",
  voice: "Kore"
)
```

OpenAI voices include `alloy`, `ash`, `ballad`, `coral`, `echo`, `fable`, `onyx`, `nova`, `sage`, `shimmer`, `verse`, `marin`, and `cedar`. Gemini supports its own voice set, including `Kore`, `Puck`, `Zephyr`, and `Sadachbia`.

## Formats

OpenAI supports several output formats:

```ruby
speech = RubyLLM.speak("Save this as a WAV file.", format: "wav")
speech.save("voiceover.wav")
```

Supported OpenAI formats are `mp3`, `opus`, `aac`, `flac`, `wav`, and `pcm`.

Gemini's generateContent speech endpoint returns raw PCM audio. RubyLLM reports that honestly:

```ruby
speech = RubyLLM.speak(
  "Say cheerfully: Have a wonderful day!",
  provider: :gemini,
  model: "gemini-2.5-flash-preview-tts"
)

speech.format
# => "pcm"
```

Convert PCM with a tool like ffmpeg when you need a container format:

```bash
ffmpeg -f s16le -ar 24000 -ac 1 -i out.pcm out.wav
```

## Style

`RubyLLM.speak` keeps the options every provider understands as keywords: `model:`, `voice:`, and `format:`. Provider-specific speech controls go in `provider_options:`, a hash of options in the provider's own request vocabulary that RubyLLM merges into the request as-is. OpenAI supports `instructions:` and `speed:`:

```ruby
RubyLLM.speak(
  "The build is green.",
  provider_options: {
    instructions: "Speak with calm confidence.",
    speed: 1.1
  }
)
```

Gemini handles style through the prompt:

```ruby
RubyLLM.speak(
  "Say in a bright, encouraging voice: The build is green.",
  provider: :gemini,
  model: "gemini-2.5-flash-preview-tts",
  voice: "Puck"
)
```

## Error Handling

```ruby
begin
  speech = RubyLLM.speak("Hello")
  speech.save("hello.mp3")
rescue RubyLLM::BadRequestError => e
  puts "Invalid request: #{e.message}"
rescue RubyLLM::Error => e
  puts "Speech generation failed: #{e.message}"
end
```

## Next Steps

*   [Audio Transcription](/next/audio-transcription/): Convert speech back to text.
*   [Model Resolution](/next/model-resolution/): Learn how `model:` and `provider:` are resolved.
*   [Instrumentation and Observability](/next/instrumentation/): Track speech generation events in production.
