# TTS Providers

URL: https://cogitator.app/docs/voice/tts-providers

> Text-to-speech providers for @cogitator-ai/voice — OpenAI (gpt-4o-mini-tts with 13 voices and instructions) and ElevenLabs (eleven_flash_v2_5 with low-latency streaming).

## Overview

TTS providers convert text to audio. Every provider implements the `TTSProvider` interface:

```typescript
interface TTSProvider {
  readonly name: string;
  synthesize(text: string, options?: TTSOptions): Promise<Buffer>;
  streamSynthesize(text: string, options?: TTSOptions): AsyncGenerator<Buffer>;
}
```

Both providers support batch synthesis via `synthesize()` and streaming via `streamSynthesize()`. Empty or whitespace-only text throws.

## Provider Comparison

| Feature            | OpenAI TTS                       | ElevenLabs TTS                                             |
| ------------------ | -------------------------------- | ---------------------------------------------------------- |
| Default model      | `gpt-4o-mini-tts`                | `eleven_flash_v2_5`                                        |
| Streaming          | Yes                              | Yes                                                        |
| Voice selection    | By name (13 built-in)            | By voice ID                                                |
| Voice instructions | Yes (style, tone, etc.)          | No                                                         |
| Speed control      | 0.25x - 4.0x                     | 0.7x - 1.2x                                                |
| Output formats     | mp3, opus, aac, flac, wav, pcm16 | mp3, opus, flac, pcm16                                     |
| Other models       | `tts-1`, `tts-1-hd`              | `eleven_turbo_v2_5`, `eleven_multilingual_v2`, `eleven_v3` |

## OpenAI TTS

Uses the OpenAI Audio Speech API. Default model is `gpt-4o-mini-tts` with 13 built-in voices.

Requires the optional `openai` peer (`pnpm add openai`). It is loaded on the first `synthesize` / `streamSynthesize` call, not when you import the package or construct `OpenAITTS`; if it is missing, that call throws with an install hint.

```typescript
import { OpenAITTS } from '@cogitator-ai/voice';

const tts = new OpenAITTS({
  apiKey: process.env.OPENAI_API_KEY!,
  model: 'gpt-4o-mini-tts',
  voice: 'coral',
});
```

### Batch Synthesis

```typescript
import fs from 'node:fs';

const audio = await tts.synthesize('Hello, world!', {
  speed: 1.0,
  format: 'mp3',
  instructions: 'Speak in a warm, friendly tone',
});

fs.writeFileSync('output.mp3', audio);
```

### Streaming

```typescript
for await (const chunk of tts.streamSynthesize('Streaming response...')) {
  playAudio(chunk);
}
```

### Voice Instructions

The `gpt-4o-mini-tts` model supports the `instructions` parameter to control speaking style:

```typescript
await tts.synthesize('Welcome to the show!', {
  instructions: 'Speak with excitement and energy, like a TV host',
});

await tts.synthesize('I am sorry for the inconvenience.', {
  instructions: 'Speak softly with genuine empathy',
});
```

### Available Voices

`alloy`, `ash`, `ballad`, `coral`, `echo`, `fable`, `onyx`, `nova`, `sage`, `shimmer`, `verse`, `marin`, `cedar`

### Configuration

| Field     | Type     | Default           | Description         |
| --------- | -------- | ----------------- | ------------------- |
| `apiKey`  | `string` | required          | OpenAI API key      |
| `model`   | `string` | `gpt-4o-mini-tts` | Model ID            |
| `voice`   | `string` | `alloy`           | Default voice name  |
| `baseURL` | `string` | —                 | Custom API base URL |

## ElevenLabs TTS

Uses the ElevenLabs text-to-speech API. Default model is `eleven_flash_v2_5` which offers low latency (\~75ms).

```typescript
import { ElevenLabsTTS } from '@cogitator-ai/voice';

const tts = new ElevenLabsTTS({
  apiKey: process.env.ELEVENLABS_API_KEY!,
  model: 'eleven_flash_v2_5',
  voiceId: '21m00Tcm4TlvDq8ikWAM',
});
```

### Batch Synthesis

```typescript
const audio = await tts.synthesize('Hello!', { format: 'mp3' });
fs.writeFileSync('output.mp3', audio);
```

### Streaming

```typescript
for await (const chunk of tts.streamSynthesize('Streaming audio...')) {
  playAudio(chunk);
}
```

### Configuration

| Field     | Type     | Default                | Description        |
| --------- | -------- | ---------------------- | ------------------ |
| `apiKey`  | `string` | required               | ElevenLabs API key |
| `voiceId` | `string` | `21m00Tcm4TlvDq8ikWAM` | Default voice ID   |
| `model`   | `string` | `eleven_flash_v2_5`    | Model ID           |

Formats map to ElevenLabs output formats: `mp3` → 44.1kHz 128kbps (default), `pcm16` → 24kHz, `opus` → 48kHz, `flac` → 22.05kHz; `wav` and `aac` throw. Requests use `stability: 0.5` and `similarity_boost: 0.75` and time out after 60 seconds.

## TTS Options

Options shared by both providers:

| Field          | Type               | Description                                                                                     |
| -------------- | ------------------ | ----------------------------------------------------------------------------------------------- |
| `voice`        | `string`           | Override the default voice (OpenAI voice name, ElevenLabs voice ID)                             |
| `speed`        | `number`           | Playback speed (OpenAI 0.25 - 4.0, ElevenLabs 0.7 - 1.2)                                        |
| `format`       | `VoiceAudioFormat` | Output format: `"mp3"` (default), `"pcm16"` (raw PCM16 mono **24kHz** for both providers), etc. |
| `instructions` | `string`           | Voice style instructions (OpenAI `gpt-4o-mini-tts` only)                                        |

`VoicePipeline` and pipeline-mode `VoiceAgent` pass their `ttsOptions` to every call (see [TTS options](/docs/voice/pipeline#tts-options)).

## Custom TTS Provider

Implement `TTSProvider` to integrate any speech synthesis service:

```typescript
import type { TTSProvider, TTSOptions } from '@cogitator-ai/voice';

class PiperTTS implements TTSProvider {
  readonly name = 'piper';

  async synthesize(text: string, options?: TTSOptions): Promise<Buffer> {
    // call your local Piper instance
    return Buffer.alloc(0);
  }

  async *streamSynthesize(text: string, options?: TTSOptions): AsyncGenerator<Buffer> {
    const audio = await this.synthesize(text, options);
    yield audio;
  }
}
```
