> ## Documentation Index
> Fetch the complete documentation index at: https://typecast.ai/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Go

> Access the Typecast API with our official Go SDK.

The official Go library for the [Typecast API](https://typecast.ai). Convert text to lifelike speech using AI-powered voices.

Compatible with Go 1.21 and later versions. Zero external dependencies - uses only the Go standard library.

<CardGroup cols={2}>
  <Card title="Go Reference" icon="cube" href="https://pkg.go.dev/github.com/neosapience/typecast-sdk/typecast-go">
    Typecast Go SDK
  </Card>

  <Card title="Source Code" icon="github" href="https://github.com/neosapience/typecast-sdk/tree/main/typecast-go">
    Typecast Go SDK Source Code
  </Card>
</CardGroup>

## Installation

```bash theme={null}
go get github.com/neosapience/typecast-sdk/typecast-go
```

<Warning>
  Latest registered version: **typecast-go/v0.3.7** via Go modules. Make sure you have **Go 1.21 or higher** installed. Check your version with `go version`.
</Warning>

## Quick Start

```go theme={null}
package main

import (
    "context"
    "os"

    typecast "github.com/neosapience/typecast-sdk/typecast-go"
)

func main() {
    // Initialize client
    client := typecast.NewClient(&typecast.ClientConfig{
        APIKey: "YOUR_API_KEY",
    })

    ctx := context.Background()

    // Convert text to speech
    response, err := client.TextToSpeech(ctx, &typecast.TTSRequest{
        VoiceID: "tc_672c5f5ce59fac2a48faeaee", // Find voice IDs at https://typecast.ai/developers/api/voices
        Text:    "Hello there! I'm your friendly text-to-speech agent.",
        Model:   typecast.ModelSSFMV30,
    })
    if err != nil {
        panic(err)
    }

    // Save audio file
    os.WriteFile("output.wav", response.AudioData, 0644)
    
    println("Audio saved! Format:", string(response.Format))
}
```

## Features

The Typecast Go SDK provides powerful features for text-to-speech conversion:

* **Multiple Voice Models**: Support for `ssfm-v30` (latest) and `ssfm-v21` AI voice models
* **Multi-language Support**: 37 languages including English, Korean, Spanish, Japanese, Chinese, and more
* **Emotion Control**: Preset emotions (normal, happy, sad, angry, whisper, toneup, tonedown) or smart context-aware inference
* **Audio Customization**: Control loudness (LUFS -70 to 0), pitch (-12 to +12 semitones), tempo (0.5x to 2.0x), and format (WAV/MP3)
* **Voice Discovery**: V2 Voices API with filtering by model, gender, age, and use cases
* **Instant Voice Cloning**: Upload a WAV/MP3 sample and create a custom voice ID
* **Context Support**: Full `context.Context` support for cancellation and timeouts
* **Timestamp TTS**: Word- and character-level alignment data for subtitles, karaoke, and lip-sync
* **Zero Dependencies**: Uses only the Go standard library
* **Streaming**: Real-time chunked audio delivery for low-latency playback

## Voice Recommendations

Use `RecommendVoices` when you know the desired style but not the exact `voice_id`.

```go theme={null}
voices, err := client.RecommendVoices(
    context.Background(),
    "warm female voice for a product tutorial",
    3,
)
if err != nil {
    panic(err)
}

for _, voice := range voices {
    fmt.Println(voice.VoiceID, voice.VoiceName, voice.Score)
}
```

Recommendation results contain only `VoiceID`, `VoiceName`, and `Score`. Use `GetVoiceV2` or `GetVoicesV2` when you need detailed metadata such as supported models, emotions, gender, age, or use cases.

## Configuration

Set your API key via environment variable or pass directly:

```go theme={null}
import typecast "github.com/neosapience/typecast-sdk/typecast-go"

// Using environment variable (recommended)
// export TYPECAST_API_KEY="your-api-key-here"
client := typecast.NewClient(nil)

// Or pass directly
client := typecast.NewClient(&typecast.ClientConfig{
    APIKey: "your-api-key-here",
})

// With custom settings
client := typecast.NewClient(&typecast.ClientConfig{
    APIKey:  "your-api-key-here",
    BaseURL: "https://api.typecast.ai",  // optional
    Timeout: 60 * time.Second,           // optional
})
```

<Info>
  When requests go through your own proxy, set `BaseURL` or `TYPECAST_API_HOST` to the proxy endpoint and omit `APIKey`. The SDK will not send the `X-API-KEY` header for empty or missing keys. Requests to the default Typecast host still require an API key.
</Info>

```go Proxy without API key theme={null}
client := typecast.NewClient(&typecast.ClientConfig{
    BaseURL: "https://your-proxy.example.com",
})
```

### Environment Variables

| Variable            | Description                    |
| ------------------- | ------------------------------ |
| `TYPECAST_API_KEY`  | Your Typecast API key          |
| `TYPECAST_API_HOST` | Custom API base URL (optional) |

## Advanced Usage

### Emotion Control (ssfm-v30)

ssfm-v30 offers two emotion control modes: **Preset** and **Smart**.

<Tabs>
  <Tab title="Smart Mode">
    Let the AI infer emotion from context:

    ```go theme={null}
    response, err := client.TextToSpeech(ctx, &typecast.TTSRequest{
        VoiceID: "tc_672c5f5ce59fac2a48faeaee",
        Text:    "Everything is going to be okay.",
        Model:   typecast.ModelSSFMV30,
        Prompt: &typecast.SmartPrompt{
            EmotionType:  "smart",
            PreviousText: "I just got the best news!",  // Optional context
            NextText:     "I can't wait to celebrate!", // Optional context
        },
    })
    ```
  </Tab>

  <Tab title="Preset Mode">
    Explicitly set emotion with preset values:

    ```go theme={null}
    intensity := 1.5

    response, err := client.TextToSpeech(ctx, &typecast.TTSRequest{
        VoiceID: "tc_672c5f5ce59fac2a48faeaee",
        Text:    "I am so excited to show you these features!",
        Model:   typecast.ModelSSFMV30,
        Prompt: &typecast.PresetPrompt{
            EmotionType:      "preset",
            EmotionPreset:    typecast.EmotionHappy,  // normal, happy, sad, angry, whisper, toneup, tonedown
            EmotionIntensity: &intensity,             // Range: 0.0 to 2.0
        },
    })
    ```
  </Tab>
</Tabs>

### Audio Customization

Control loudness, pitch, tempo, and output format:

```go theme={null}
lufs := -14.0
pitch := 2
tempo := 1.2
response, err := client.TextToSpeech(ctx, &typecast.TTSRequest{
    Text:    "Customized audio output!",
    Model:   typecast.ModelSSFMV30,
    VoiceID: "tc_672c5f5ce59fac2a48faeaee",
    Output: &typecast.Output{
        TargetLUFS:  &lufs,                   // Range: -70 to 0 (LUFS)
        AudioPitch:  &pitch,                  // Range: -12 to +12 semitones
        AudioTempo:  &tempo,                  // Range: 0.5x to 2.0x
        AudioFormat: typecast.AudioFormatMP3, // Options: wav, mp3
    },
})
```

### Generate audio to a file

Use `GenerateToFile` when you want the SDK to synthesize speech and write the audio bytes directly to a local file. The model defaults to `ssfm-v30`, and `.mp3` / `.wav` extensions infer the output format when `Output.AudioFormat` is not set. Browse available voice IDs on the [Voices](https://typecast.ai/developers/api/voices) page.

```go theme={null}
_, err := client.GenerateToFile(ctx, "output.mp3", typecast.GenerateToFileRequest{
    Text:    "Hello from Typecast.",
    VoiceID: "tc_672c5f5ce59fac2a48faeaee", // Find voice IDs at https://typecast.ai/developers/api/voices
})
if err != nil {
    panic(err)
}
```

### Text pauses

Use text pause markup when you only need silent gaps inside one composed text segment. Put `<|5s|>`, `<|1s|>`, `<|0.3s|>`, or `<|0.34413s|>` directly in the text. The value is interpreted as seconds and must end with `s`. This keeps the pause expression visible in plain text without adding separate pause calls.

```go theme={null}
audio, err := client.ComposeSpeech().
    Defaults(typecast.ComposerSettings{VoiceID: "tc_672c5f5ce59fac2a48faeaee", Model: typecast.TTSModelSSFMV30}).
    Say("Hello<|5s|>Nice to meet you<|1s|>Today<|2s|>how does the weather feel?").
    Generate(ctx)
```

### Multi-speaker composition

Use the composer chaining API when one output file needs different voices or per-segment options such as pitch, tempo, prompt, or seed. The composer generates each segment as WAV, trims leading/trailing silent PCM samples, and concatenates the result. If you need MP3, generate WAV first and convert it in your app or server pipeline.

```go theme={null}
package main

import (
    "context"
    "os"

    typecast "github.com/neosapience/typecast-sdk/typecast-go"
)

func main() {
    client := typecast.NewClient("YOUR_API_KEY")
    response, err := client.ComposeSpeech().
        Defaults(typecast.ComposerSettings{VoiceID: "tc_672c5f5ce59fac2a48faeaee", Model: typecast.ModelSSFMV30}).
        Say("Hello there").
        Pause(5).
        SayWith("Nice to meet you", typecast.ComposerSettings{VoiceID: "tc_60e5426de8b95f1d3000d7b5", Output: &typecast.Output{AudioPitch: 2}}).
        Say("Today").
        Pause(2).
        Say("How does the weather feel?").
        Generate(context.Background())
    if err != nil {
        panic(err)
    }
    _ = os.WriteFile("conversation.wav", response.AudioData, 0644)
}
```

### Voice Discovery (V2 API)

List and filter available voices with enhanced metadata:

```go theme={null}
// Get all voices
voices, err := client.GetVoicesV2(ctx, nil)

// Filter by criteria
voices, err := client.GetVoicesV2(ctx, &typecast.VoicesV2Filter{
    Model:  typecast.ModelSSFMV30,
    Gender: typecast.GenderFemale,
    Age:    typecast.AgeYoungAdult,
})

// Display voice info
for _, voice := range voices {
    fmt.Printf("ID: %s, Name: %s\n", voice.VoiceID, voice.VoiceName)
    
    if voice.Gender != nil {
        fmt.Printf("Gender: %s\n", *voice.Gender)
    }
    if voice.Age != nil {
        fmt.Printf("Age: %s\n", *voice.Age)
    }
    
    for _, model := range voice.Models {
        fmt.Printf("Model: %s, Emotions: %v\n", model.Version, model.Emotions)
    }
}

// Get specific voice details
voice, err := client.GetVoiceV2(ctx, "tc_672c5f5ce59fac2a48faeaee")
```

### Multilingual Content

The SDK supports 37 languages with automatic language detection:

```go theme={null}
// Auto-detect language (recommended)
response, err := client.TextToSpeech(ctx, &typecast.TTSRequest{
    VoiceID: "tc_672c5f5ce59fac2a48faeaee",
    Text:    "こんにちは。お元気ですか。",
    Model:   typecast.ModelSSFMV30,
})

// Or specify language explicitly
response, err := client.TextToSpeech(ctx, &typecast.TTSRequest{
    VoiceID:  "tc_672c5f5ce59fac2a48faeaee",
    Text:     "안녕하세요. 반갑습니다.",
    Model:    typecast.ModelSSFMV30,
    Language: "kor",  // ISO 639-3 language code
})
```

### Streaming

Stream audio chunks in real-time for low-latency playback:

```go theme={null}
// Stream and extract raw PCM (skip 44-byte WAV header)
reader, _ := client.TextToSpeechStream(context.Background(), request)
defer reader.Close()

buf := make([]byte, 4096)
first := true
for {
    n, err := reader.Read(buf)
    if n > 0 {
        data := buf[:n]
        if first {
            data = data[44:]  // Skip WAV header
            first = false
        }
        // data is raw 16-bit mono PCM at 32000 Hz
        // Feed to your audio output (e.g. oto, portaudio)
        _ = data
    }
    if err != nil {
        break
    }
}
```

<Note>
  **WAV streaming format:** 32000 Hz, 16-bit, mono PCM. The first chunk includes a 44-byte WAV header (size = `0xFFFFFFFF`); subsequent chunks are raw PCM only. For MP3: 320 kbps, 44100 Hz, each chunk is independently decodable.
</Note>

## Timestamp TTS

`TextToSpeechWithTimestamps()` wraps `POST /v1/text-to-speech/with-timestamps` and returns the audio together with per-word and per-character alignment data — useful for karaoke highlights, subtitle generation, and lip-sync applications.

### Basic Usage

```go theme={null}
package main

import (
    "context"
    "fmt"
    "os"

    typecast "github.com/neosapience/typecast-sdk/typecast-go"
)

func main() {
    client := typecast.NewClient(&typecast.ClientConfig{APIKey: "YOUR_API_KEY"})
    ctx := context.Background()

    result, err := client.TextToSpeechWithTimestamps(ctx, &typecast.TTSRequestWithTimestamps{
        VoiceID: "tc_60e5426de8b95f1d3000d7b5",
        Text:    "Hello. How are you?",
        Model:   typecast.ModelSSFMV30,
    })
    if err != nil {
        panic(err)
    }

    os.WriteFile("output.wav", result.AudioBytes(), 0644)
    fmt.Printf("Duration: %.3fs\n", result.AudioDuration)

    for _, w := range result.Words {
        fmt.Printf("  [%.3fs – %.3fs] %s\n", w.StartTime, w.EndTime, w.Text)
    }
}
```

### Granularity

Pass `Granularity: typecast.GranularityWord` (default) or `Granularity: typecast.GranularityChar` to control the alignment unit.

```go theme={null}
// Character-level alignment — required for Japanese / Chinese
result, err := client.TextToSpeechWithTimestamps(ctx, &typecast.TTSRequestWithTimestamps{
    VoiceID:     "tc_60e5426de8b95f1d3000d7b5",
    Text:        "Hello. How are you?",
    Model:       typecast.ModelSSFMV30,
    Granularity: typecast.GranularityChar,
})
```

### Subtitle Export

```go theme={null}
srt, _ := result.ToSrt()
os.WriteFile("output.srt", []byte(srt), 0644)

vtt, _ := result.ToVtt()
os.WriteFile("output.vtt", []byte(vtt), 0644)
```

<Note>
  **Japanese / Chinese:** Word-level segmentation is not meaningful for languages without whitespace delimiters (jpn, zho). Use `GranularityChar` for these languages to get character-level alignment.
</Note>

## Instant Voice Cloning

Clone a custom voice from a short audio sample, then pass the returned `uc_` voice ID directly to TTS.

```go theme={null}
package main

import (
    "context"
    "os"

    typecast "github.com/neosapience/typecast-sdk/typecast-go"
)

func main() {
    client := typecast.NewClient(&typecast.ClientConfig{APIKey: "YOUR_API_KEY"})
    ctx := context.Background()

    audioBytes, err := os.ReadFile("sample.wav")
    if err != nil {
        panic(err)
    }

    voice, err := client.CloneVoice(ctx, audioBytes, "sample.wav", "MyVoice", "ssfm-v30")
    if err != nil {
        panic(err)
    }

    response, err := client.TextToSpeech(ctx, &typecast.TTSRequest{
        VoiceID: voice.VoiceID,
        Text:    "Hello from my cloned voice!",
        Model:   typecast.ModelSSFMV30,
    })
    if err != nil {
        panic(err)
    }

    os.WriteFile("output.wav", response.AudioData, 0644)
    client.DeleteVoice(ctx, voice.VoiceID)
}
```

<Warning>
  Voice cloning audio must be **25 MB or smaller**, the audio duration must be **5-150 seconds**, and the custom voice name must be **1-30 characters**.
</Warning>

## Supported Languages

The SDK supports 37 languages with automatic language detection:

| Code  | Language  | Code  | Language  | Code  | Language   |
| ----- | --------- | ----- | --------- | ----- | ---------- |
| `eng` | English   | `jpn` | Japanese  | `ukr` | Ukrainian  |
| `kor` | Korean    | `ell` | Greek     | `ind` | Indonesian |
| `spa` | Spanish   | `tam` | Tamil     | `dan` | Danish     |
| `deu` | German    | `tgl` | Tagalog   | `swe` | Swedish    |
| `fra` | French    | `fin` | Finnish   | `msa` | Malay      |
| `ita` | Italian   | `zho` | Chinese   | `ces` | Czech      |
| `pol` | Polish    | `slk` | Slovak    | `por` | Portuguese |
| `nld` | Dutch     | `ara` | Arabic    | `bul` | Bulgarian  |
| `rus` | Russian   | `hrv` | Croatian  | `ron` | Romanian   |
| `ben` | Bengali   | `hin` | Hindi     | `hun` | Hungarian  |
| `nan` | Hokkien   | `nor` | Norwegian | `pan` | Punjabi    |
| `tha` | Thai      | `tur` | Turkish   | `vie` | Vietnamese |
| `yue` | Cantonese |       |           |       |            |

<Info>
  If not specified, the language will be automatically detected from the input text.
</Info>

## Error Handling

The SDK provides an `APIError` type with helper methods for handling specific errors:

```go theme={null}
import typecast "github.com/neosapience/typecast-sdk/typecast-go"

response, err := client.TextToSpeech(ctx, request)
if err != nil {
    if apiErr, ok := err.(*typecast.APIError); ok {
        fmt.Printf("Error %d: %s\n", apiErr.StatusCode, apiErr.Message)
        
        // Handle specific errors
        switch {
        case apiErr.IsUnauthorized():
            // 401: Invalid API key
        case apiErr.IsForbidden():
            // 403: Access denied
        case apiErr.IsPaymentRequired():
            // 402: Insufficient credits
        case apiErr.IsNotFound():
            // 404: Resource not found
        case apiErr.IsValidationError():
            // 422: Validation error
        case apiErr.IsRateLimited():
            // 429: Rate limit exceeded
        case apiErr.IsServerError():
            // 5xx: Server error
        case apiErr.IsBadRequest():
            // 400: Bad request
        }
    }
}
```

### Error Types

| Method                | Status Code | Description                |
| --------------------- | ----------- | -------------------------- |
| `IsBadRequest()`      | 400         | Invalid request parameters |
| `IsUnauthorized()`    | 401         | Invalid or missing API key |
| `IsPaymentRequired()` | 402         | Insufficient credits       |
| `IsForbidden()`       | 403         | Access denied              |
| `IsNotFound()`        | 404         | Resource not found         |
| `IsValidationError()` | 422         | Validation error           |
| `IsRateLimited()`     | 429         | Rate limit exceeded        |
| `IsServerError()`     | 5xx         | Server error               |

## Context and Timeouts

The SDK fully supports Go's `context.Context` for cancellation and timeouts:

```go theme={null}
// With timeout
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()

response, err := client.TextToSpeech(ctx, request)
if err != nil {
    if ctx.Err() == context.DeadlineExceeded {
        fmt.Println("Request timed out")
    }
}

// With cancellation
ctx, cancel := context.WithCancel(context.Background())
go func() {
    time.Sleep(5 * time.Second)
    cancel()  // Cancel after 5 seconds
}()

response, err := client.TextToSpeech(ctx, request)
```

## API Reference

### Client Methods

| Method                                          | Description                                          |
| ----------------------------------------------- | ---------------------------------------------------- |
| `TextToSpeech(ctx, request)`                    | Convert text to speech audio                         |
| `GenerateToFile(ctx, path, request)`            | Generate speech and save it directly to a local file |
| `CloneVoice(ctx, audio, filename, name, model)` | Create a custom voice via instant cloning            |
| `DeleteVoice(ctx, voiceID)`                     | Delete a custom cloned voice                         |
| `GetVoicesV2(ctx, filter)`                      | Get available voices with filtering                  |
| `GetVoiceV2(ctx, voiceID)`                      | Get a specific voice by ID                           |
| `GetVoices(ctx, model)`                         | Get voices (V1 API, deprecated)                      |
| `GetVoice(ctx, voiceID, model)`                 | Get voice (V1 API, deprecated)                       |

### TTSRequest Fields

| Field      | Type                                         | Required | Description                                     |
| ---------- | -------------------------------------------- | -------- | ----------------------------------------------- |
| `VoiceID`  | `string`                                     | ✓        | Voice ID (format: `tc_*` or `uc_*`)             |
| `Text`     | `string`                                     | ✓        | Text to synthesize (max 2000 chars)             |
| `Model`    | `TTSModel`                                   | ✓        | TTS model (`ModelSSFMV21` or `ModelSSFMV30`)    |
| `Language` | `string`                                     |          | ISO 639-3 code (auto-detected if omitted)       |
| `Prompt`   | `*Prompt` / `*PresetPrompt` / `*SmartPrompt` |          | Emotion settings                                |
| `Output`   | `*Output`                                    |          | Audio output settings                           |
| `Seed`     | `*uint32`                                    |          | Unsigned integer seed for reproducibility (≥ 0) |

### TTSResponse Fields

| Field       | Type          | Description                   |
| ----------- | ------------- | ----------------------------- |
| `AudioData` | `[]byte`      | Generated audio data          |
| `Duration`  | `float64`     | Audio duration in seconds     |
| `Format`    | `AudioFormat` | Audio format (`wav` or `mp3`) |

### Constants

#### Models

| Constant       | Value      | Description                        |
| -------------- | ---------- | ---------------------------------- |
| `ModelSSFMV30` | `ssfm-v30` | Latest model with improved prosody |
| `ModelSSFMV21` | `ssfm-v21` | Stable production model            |

#### Emotion Presets

| Constant          | ssfm-v21 | ssfm-v30 |
| ----------------- | -------- | -------- |
| `EmotionNormal`   | ✓        | ✓        |
| `EmotionHappy`    | ✓        | ✓        |
| `EmotionSad`      | ✓        | ✓        |
| `EmotionAngry`    | ✓        | ✓        |
| `EmotionWhisper`  | ✗        | ✓        |
| `EmotionToneUp`   | ✗        | ✓        |
| `EmotionToneDown` | ✗        | ✓        |

#### Audio Formats

| Constant         | Value | Description            |
| ---------------- | ----- | ---------------------- |
| `AudioFormatWAV` | `wav` | Uncompressed PCM audio |
| `AudioFormatMP3` | `mp3` | Compressed MP3 audio   |
