# aiSpeak

Convert text to natural-sounding speech audio using an AI provider.

## Syntax

```javascript
aiSpeak( text, params={}, options={} )
```

## Parameters

| Parameter | Type   | Required | Description                                                                               |
| --------- | ------ | -------- | ----------------------------------------------------------------------------------------- |
| `text`    | string | ✅ Yes    | The text content to synthesize into speech                                                |
| `params`  | struct | No       | Provider API parameters sent directly to the AI provider (e.g. `model`, `voice`, `speed`) |
| `options` | struct | No       | Module-level behavior options (provider, output format, file output, logging)             |

## Options

| Option                 | Type    | Default          | Description                                                                                                                                                                                                                                                            |
| ---------------------- | ------- | ---------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `provider`             | string  | (config default) | AI provider name: `openai`, `mistral`, `gemini`, `grok`, `elevenlabs`                                                                                                                                                                                                  |
| `apiKey`               | string  | (env var)        | Provider API key. Falls back to `<PROVIDER>_API_KEY` environment variable                                                                                                                                                                                              |
| `voice`                | string  | (config default) | Voice name or ID. Pass a provider-specific voice name (e.g. `nova`) **or** a gender keyword `"male"` / `"female"` which is resolved to the correct voice for the active provider using `audio.voiceGenderMap` from your module config. See voice reference table below |
| `outputFormat`         | string  | `mp3`            | Audio format: `mp3`, `wav`, `flac`, `opus`, `pcm`                                                                                                                                                                                                                      |
| `speed`                | numeric | `1.0`            | Playback speed multiplier. Range: 0.25 – 4.0                                                                                                                                                                                                                           |
| `outputFile`           | string  | `""`             | When set, saves audio to this path and returns the file path string instead of `AiSpeechResponse`                                                                                                                                                                      |
| `timeout`              | numeric | `30`             | HTTP request timeout in seconds                                                                                                                                                                                                                                        |
| `logRequest`           | boolean | `false`          | Log request to the module log file                                                                                                                                                                                                                                     |
| `logRequestToConsole`  | boolean | `false`          | Print request payload to the console                                                                                                                                                                                                                                   |
| `logResponse`          | boolean | `false`          | Log response to the module log file                                                                                                                                                                                                                                    |
| `logResponseToConsole` | boolean | `false`          | Print raw provider response to the console (useful for debugging)                                                                                                                                                                                                      |

## Returns

| Condition                | Returns                                                                   |
| ------------------------ | ------------------------------------------------------------------------- |
| `outputFile` **not** set | **`AiSpeechResponse`** — wraps binary audio data with convenience methods |
| `outputFile` **is** set  | **string** — absolute path to the saved audio file                        |

### `AiSpeechResponse` Methods

| Method                           | Returns | Description                                                  |
| -------------------------------- | ------- | ------------------------------------------------------------ |
| `saveToFile( filePath )`         | string  | Saves audio binary to the given path; returns absolute path  |
| `getBase64()`                    | string  | Base64-encoded audio data                                    |
| `getMimeType()`                  | string  | MIME type, e.g. `audio/mpeg`                                 |
| `toDataURI()`                    | string  | `data:audio/mpeg;base64,...` URI for HTML `<audio>` elements |
| `hasAudio()`                     | boolean | `true` if audio data is present and non-empty                |
| `getSize()`                      | numeric | Audio data size in bytes                                     |
| `getAudioFormat()`               | string  | Format string: `mp3`, `wav`, `flac`, etc.                    |
| `toStruct()`                     | struct  | Metadata struct (no binary data — safe for logging)          |
| `toJSON()`                       | string  | JSON-serialized metadata                                     |
| `getMetadataValue( key )`        | any     | Read a value from the response metadata bag                  |
| `setMetadataValue( key, value )` | this    | Write a value to the metadata bag (chainable)                |

## Events Fired

| Event            | When                                           |
| ---------------- | ---------------------------------------------- |
| `beforeAISpeech` | Before the TTS request is sent to the provider |
| `afterAISpeech`  | After the TTS response is received             |

## Examples

### Synthesize and save to file

```javascript
audio = aiSpeak( "Welcome to BoxLang AI!" )
audio.saveToFile( expandPath( "/audio/welcome.mp3" ) )
println( "Size: #audio.getSize()# bytes" )
```

### Shorthand — write directly to disk with `outputFile`

```javascript
path = aiSpeak(
    "Your shipment has been dispatched.",
    {},
    { outputFile: expandPath( "/audio/notification.mp3" ) }
)
println( "Saved to: #path#" )
```

### Custom voice and format

```javascript
audio = aiSpeak(
    "Hello, this is the onyx voice at 1.5x speed.",
    { speed: 1.5 },
    { provider: "openai", voice: "onyx", outputFormat: "wav" }
)
audio.saveToFile( expandPath( "/audio/onyx.wav" ) )
```

### Gender keyword voices

Instead of hard-coding a provider-specific voice name, pass `"male"` or `"female"`. The module resolves the keyword to the configured voice for the active provider using `audio.voiceGenderMap` in your module settings:

```javascript
// Uses the "male" voice for the default provider (e.g. "ash" on OpenAI)
audio = aiSpeak( "Hello from a male voice.", {}, { voice: "male" } )
audio.saveToFile( expandPath( "/audio/male.mp3" ) )

// Explicit provider — resolved to that provider's mapped female voice
audio = aiSpeak(
    "Hello from a female voice.",
    {},
    { provider: "openai", voice: "female" }
)
audio.saveToFile( expandPath( "/audio/female.mp3" ) )
```

The default gender-to-voice mapping (overridable in `config/boxlang.json`):

| Provider       | `"male"`             | `"female"`             |
| -------------- | -------------------- | ---------------------- |
| **OpenAI**     | `ash`                | `nova`                 |
| **Grok / xAI** | `onyx`               | `nova`                 |
| **Gemini**     | `Fenrir`             | `Aoede`                |
| **Mistral**    | *(provider default)* | `Charlotte`            |
| **ElevenLabs** | *(provider default)* | `21m00Tcm4TlvDq8ikWAM` |

To override any mapping, set `audio.voiceGenderMap` in your `config/boxlang.json`:

```json
"audio": {
    "voiceGenderMap": {
        "openai": { "male": "echo", "female": "shimmer" }
    }
}
```

### Base64 / data URI for web responses

```javascript
audio = aiSpeak( "Click here to play" )

// Embed in HTML
html = '<audio controls src="#audio.toDataURI()#"></audio>'

// Or return Base64 to a front-end client
response = { audio: audio.getBase64(), mimeType: audio.getMimeType() }
```

### ElevenLabs with voice ID

```javascript
audio = aiSpeak(
    "Bonjour, bienvenue dans BoxLang AI.",
    { voice_id: "21m00Tcm4TlvDq8ikWAM" },
    { provider: "elevenlabs" }
)
audio.saveToFile( expandPath( "/audio/french.mp3" ) )
```

### Custom interceptor for TTS logging

```javascript
BoxRegisterInterceptor( "afterAISpeech", function( event ) {
    var sizeKB = event.result.getSize() / 1024
    println( "TTS: #event.service.getName()# — #numberFormat( sizeKB, '0.0' )# KB" )
})
```

## Voice Reference

| Provider       | Available Voices                                           | `"male"` keyword     | `"female"` keyword     |
| -------------- | ---------------------------------------------------------- | -------------------- | ---------------------- |
| **OpenAI**     | `alloy`, `ash`, `echo`, `fable`, `onyx`, `nova`, `shimmer` | `ash`                | `nova`                 |
| **Mistral**    | `Charlotte`                                                | *(provider default)* | `Charlotte`            |
| **Gemini**     | `Fenrir`, `Aoede`, `Kore` (and others)                     | `Fenrir`             | `Aoede`                |
| **Grok / xAI** | `alloy`, `echo`, `fable`, `onyx`, `nova`, `shimmer`, `eve` | `onyx`               | `nova`                 |
| **ElevenLabs** | Voice IDs from your voice library                          | *(provider default)* | `21m00Tcm4TlvDq8ikWAM` |

> For ElevenLabs, pass a `voice_id` in `params` for specific voices. The `"male"`/`"female"` keywords resolve to the IDs in `audio.voiceGenderMap`.

## See Also

* [Text-to-Speech Guide](/main-components/audio/text-to-speech.md)
* [Audio Overview](/main-components/audio.md)
* [aiTranscribe](/advanced/reference/built-in-functions/aitranscribe.md)
* [aiTranslate](/advanced/reference/built-in-functions/aitranslate.md)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://ai.ortusbooks.com/advanced/reference/built-in-functions/aispeak.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
