Skip to main content
The official Rust library for the Typecast API. Convert text to lifelike speech using AI-powered voices. Built with async/await support using Tokio runtime. Works with Cargo package manager.

Crates.io

Typecast Rust SDK

Source Code

Typecast Rust SDK Source Code

Installation

Add the following to your Cargo.toml:
[dependencies]
typecast-rust = "0.1.1"
tokio = { version = "1", features = ["full"] }
Or use Cargo to add the dependency:
cargo add typecast-rust tokio --features tokio/full
Make sure you have version 0.1.1 or higher installed. Check your Cargo.toml if you need to update.

Quick Start

use typecast_rust::{TypecastClient, TTSRequest, TTSModel};
use std::fs;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Initialize client (reads TYPECAST_API_KEY from environment)
    let client = TypecastClient::from_env()?;

    // Convert text to speech
    let request = TTSRequest::new(
        "tc_672c5f5ce59fac2a48faeaee",
        "Hello there! I'm your friendly text-to-speech agent.",
        TTSModel::SsfmV30,
    );

    let response = client.text_to_speech(&request).await?;

    // Save audio file
    fs::write("output.wav", &response.audio_data)?;

    println!(
        "Audio saved! Duration: {:.2}s, Format: {:?}",
        response.duration, response.format
    );

    Ok(())
}

Features

The Typecast Rust 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
  • Builder Pattern: Fluent API with method chaining for easy request construction
  • Async/Await: Built on Tokio for efficient asynchronous operations
  • Comprehensive Error Handling: Typed error enum with pattern matching support

Configuration

Set your API key via environment variable or constructor:
use typecast_rust::{TypecastClient, ClientConfig};
use std::time::Duration;

// Using environment variable (recommended)
// export TYPECAST_API_KEY="your-api-key-here"
let client = TypecastClient::from_env()?;

// Or pass directly
let client = TypecastClient::with_api_key("your-api-key-here")?;

// Or with custom configuration
let config = ClientConfig::new("your-api-key-here")
    .base_url("https://api.typecast.ai")
    .timeout(Duration::from_secs(120));

let client = TypecastClient::new(config)?;

Environment File

Create a .env file in your project root:
TYPECAST_API_KEY=your-api-key-here
Use the dotenvy crate to load environment variables from .env files.

Advanced Usage

Emotion Control (ssfm-v30)

ssfm-v30 offers two emotion control modes: Preset and Smart.
Let the AI infer emotion from context:
use typecast_rust::{TTSRequest, TTSModel, SmartPrompt};

let request = TTSRequest::new(
    "tc_672c5f5ce59fac2a48faeaee",
    "Everything is going to be okay.",
    TTSModel::SsfmV30,
)
.prompt(
    SmartPrompt::new()
        .previous_text("I just got the best news!")  // Optional context
        .next_text("I can't wait to celebrate!")     // Optional context
);

let response = client.text_to_speech(&request).await?;

Audio Customization

Control loudness, pitch, tempo, and output format:
use typecast_rust::{TTSRequest, TTSModel, Output, AudioFormat};

let request = TTSRequest::new(
    "tc_672c5f5ce59fac2a48faeaee",
    "Customized audio output!",
    TTSModel::SsfmV30,
)
.output(
    Output::new()
        .target_lufs(-14.0)                 // Range: -70 to 0 (LUFS)
        .audio_pitch(2)                   // Range: -12 to +12 semitones
        .audio_tempo(1.2)                 // Range: 0.5x to 2.0x
        .audio_format(AudioFormat::Mp3)   // Options: Wav, Mp3
)
.seed(42);  // For reproducible results

let response = client.text_to_speech(&request).await?;

fs::write("output.mp3", &response.audio_data)?;
println!("Duration: {:.2}s, Format: {:?}", response.duration, response.format);

Voice Discovery (V2 API)

List and filter available voices with enhanced metadata:
use typecast_rust::{TypecastClient, VoicesV2Filter, TTSModel, Gender, Age};

// Get all voices
let voices = client.get_voices_v2(None).await?;

// Filter by criteria
let filter = VoicesV2Filter::new()
    .model(TTSModel::SsfmV30)
    .gender(Gender::Female)
    .age(Age::YoungAdult);

let filtered = client.get_voices_v2(Some(filter)).await?;

// Display voice info
for voice in &voices {
    println!("ID: {}, Name: {}", voice.voice_id, voice.voice_name);
    println!("Gender: {:?}, Age: {:?}", voice.gender, voice.age);
    
    for model in &voice.models {
        println!("Model: {:?}, Emotions: {:?}", model.version, model.emotions);
    }
    
    if let Some(use_cases) = &voice.use_cases {
        println!("Use cases: {}", use_cases.join(", "));
    }
}

// Get a specific voice by ID
let voice = client.get_voice_v2("tc_672c5f5ce59fac2a48faeaee").await?;
println!("Voice: {} ({:?})", voice.voice_name, voice.gender);

Multilingual Content

The SDK supports 37 languages with automatic language detection:
// Auto-detect language (recommended)
let request = TTSRequest::new(
    "tc_672c5f5ce59fac2a48faeaee",
    "こんにちは。お元気ですか。",
    TTSModel::SsfmV30,
);

let response = client.text_to_speech(&request).await?;

// Or specify language explicitly
let korean_request = TTSRequest::new(
    "tc_672c5f5ce59fac2a48faeaee",
    "안녕하세요. 반갑습니다.",
    TTSModel::SsfmV30,
)
.language("kor");  // ISO 639-3 language code

let korean_response = client.text_to_speech(&korean_request).await?;

Supported Languages

The SDK supports 37 languages with automatic language detection:
CodeLanguageCodeLanguageCodeLanguage
engEnglishjpnJapaneseukrUkrainian
korKoreanellGreekindIndonesian
spaSpanishtamTamildanDanish
deuGermantglTagalogsweSwedish
fraFrenchfinFinnishmsaMalay
itaItalianzhoChinesecesCzech
polPolishslkSlovakporPortuguese
nldDutcharaArabicbulBulgarian
rusRussianhrvCroatianronRomanian
benBengalihinHindihunHungarian
nanHokkiennorNorwegianpanPunjabi
thaThaiturTurkishvieVietnamese
yueCantonese
If not specified, the language will be automatically detected from the input text.

Error Handling

The SDK provides a typed error enum for handling API errors with pattern matching:
use typecast_rust::{TypecastClient, TTSRequest, TTSModel, TypecastError};

let request = TTSRequest::new("voice_id", "Hello", TTSModel::SsfmV30);

match client.text_to_speech(&request).await {
    Ok(response) => {
        println!("Success! Duration: {:.2}s", response.duration);
    }
    Err(TypecastError::Unauthorized { detail }) => {
        // 401: Invalid API key
        eprintln!("Invalid API key: {}", detail);
    }
    Err(TypecastError::PaymentRequired { detail }) => {
        // 402: Insufficient credits
        eprintln!("Insufficient credits: {}", detail);
    }
    Err(TypecastError::NotFound { detail }) => {
        // 404: Resource not found
        eprintln!("Voice not found: {}", detail);
    }
    Err(TypecastError::RateLimited { detail }) => {
        // 429: Rate limit exceeded
        eprintln!("Rate limit exceeded - please retry later: {}", detail);
    }
    Err(TypecastError::ServerError { detail }) => {
        // 500: Server error
        eprintln!("Server error: {}", detail);
    }
    Err(e) => {
        eprintln!("Error: {}", e);
    }
}

Error Types

Error VariantStatus CodeDescription
BadRequest400Invalid request parameters
Unauthorized401Invalid or missing API key
PaymentRequired402Insufficient credits
Forbidden403Access denied
NotFound404Resource not found
ValidationError422Validation error
RateLimited429Rate limit exceeded
ServerError500Server error
HttpError-HTTP client error
JsonError-JSON serialization error

Helper Methods

if let Err(e) = result {
    if e.is_unauthorized() {
        println!("Check your API key");
    } else if e.is_rate_limited() {
        println!("Wait and retry");
    } else if e.is_server_error() {
        println!("Server issue, try again later");
    }
    
    if let Some(code) = e.status_code() {
        println!("HTTP status: {}", code);
    }
}

API Reference

TypecastClient Methods

MethodDescription
from_env()Create client from environment variables
with_api_key(key)Create client with API key
new(config)Create client with custom configuration
text_to_speech(&request)Convert text to speech audio
get_voices_v2(filter)Get available voices with optional filter
get_voice_v2(voice_id)Get a specific voice by ID

TTSRequest Fields

FieldTypeRequiredDescription
voice_idStringVoice ID (format: tc_* or uc_*)
textStringText to synthesize (max 2000 chars)
modelTTSModelTTS model (SsfmV21 or SsfmV30)
languageOption<String>ISO 639-3 code (auto-detected if omitted)
promptOption<TTSPrompt>Emotion settings (Prompt/PresetPrompt/SmartPrompt)
outputOption<Output>Audio output settings
seedOption<i32>Random seed for reproducibility

TTSResponse Fields

FieldTypeDescription
audio_dataVec<u8>Generated audio data
durationf64Audio duration in seconds
formatAudioFormatAudio format (Wav or Mp3)

Complete Example

use typecast_rust::{
    TypecastClient, TTSRequest, TTSModel, PresetPrompt, 
    EmotionPreset, Output, AudioFormat, VoicesV2Filter, Gender,
};
use std::fs;
use std::error::Error;

#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
    // Initialize client
    let client = TypecastClient::from_env()?;
    
    // Discover voices
    let filter = VoicesV2Filter::new()
        .model(TTSModel::SsfmV30)
        .gender(Gender::Female);
    
    let voices = client.get_voices_v2(Some(filter)).await?;
    println!("Found {} female voices", voices.len());
    
    // Use first voice
    if let Some(voice) = voices.first() {
        let request = TTSRequest::new(
            &voice.voice_id,
            "Welcome to Typecast! This is a demonstration of our text-to-speech API.",
            TTSModel::SsfmV30,
        )
        .language("eng")
        .prompt(
            PresetPrompt::new()
                .emotion_preset(EmotionPreset::Happy)
                .emotion_intensity(1.2)
        )
        .output(
            Output::new()
                .target_lufs(-14.0)
                .audio_format(AudioFormat::Mp3)
        );
        
        let response = client.text_to_speech(&request).await?;
        
        fs::write("welcome.mp3", &response.audio_data)?;
        println!("Saved welcome.mp3 ({:.2}s)", response.duration);
    }
    
    Ok(())
}