---
title: "Transcription"
description: "How Whisper-based audio transcription works in Voicebox"
---

## Overview

Voicebox uses OpenAI's Whisper model for automatic speech recognition (ASR). This powers the transcription feature for creating reference text from audio recordings.

## Architecture

The transcription system is built around the `WhisperModel` class:

**Model Loading:** Lazy loading with HuggingFace Hub download.

**Audio Processing:** Resampling and preprocessing for Whisper.

**Inference:** Running transcription with optional language hints.

## WhisperModel Class

```python
class WhisperModel:
    def __init__(self, model_size: str = "base"):
        self.model = None
        self.processor = None
        self.model_size = model_size
        self.device = self._get_device()
```

### Model Sizes

| Size | Parameters | VRAM | Speed | Quality |
|------|------------|------|-------|---------|
| tiny | 39M | ~1GB | Fastest | Basic |
| base | 74M | ~1GB | Fast | Good |
| small | 244M | ~2GB | Medium | Better |
| medium | 769M | ~5GB | Slow | High |
| large | 1550M | ~10GB | Slowest | Best |

Default is `base` for balance of speed and quality.

## Model Loading

Models are downloaded from HuggingFace Hub:

```python
def load_model(self, model_size: Optional[str] = None):
    from transformers import WhisperProcessor, WhisperForConditionalGeneration
    
    model_name = f"openai/whisper-{model_size}"
    
    # Track download progress
    progress_manager = get_progress_manager()
    task_manager = get_task_manager()
    task_manager.start_download(f"whisper-{model_size}")
    
    # Load processor and model
    with tracker.patch_download():
        self.processor = WhisperProcessor.from_pretrained(model_name)
        self.model = WhisperForConditionalGeneration.from_pretrained(model_name)
    
    self.model.to(self.device)
    
    # Mark complete
    progress_manager.mark_complete(f"whisper-{model_size}")
    task_manager.complete_download(f"whisper-{model_size}")
```

### Async Loading

Like TTS, loading runs in a thread pool:

```python
async def load_model_async(self, model_size: Optional[str] = None):
    if self.model is not None and self.model_size == model_size:
        return
    await asyncio.to_thread(self.load_model, model_size)
```

## Transcription

### Basic Transcription

```python
async def transcribe(
    self,
    audio_path: str,
    language: Optional[str] = None,
) -> str:
    await self.load_model_async()
    
    def _transcribe_sync():
        # Load and resample to 16kHz (Whisper requirement)
        audio, sr = load_audio(audio_path, sample_rate=16000)
        
        # Process audio
        inputs = self.processor(
            audio,
            sampling_rate=16000,
            return_tensors="pt",
        )
        inputs = inputs.to(self.device)
        
        # Set language hint if provided
        forced_decoder_ids = None
        if language:
            forced_decoder_ids = self.processor.get_decoder_prompt_ids(
                language=language,
                task="transcribe",
            )
        
        # Generate
        with torch.no_grad():
            predicted_ids = self.model.generate(
                inputs["input_features"],
                forced_decoder_ids=forced_decoder_ids,
            )
        
        # Decode
        transcription = self.processor.batch_decode(
            predicted_ids,
            skip_special_tokens=True,
        )[0]
        
        return transcription.strip()
    
    return await asyncio.to_thread(_transcribe_sync)
```

### Supported Languages

Whisper supports 99+ languages. Common ones in Voicebox:

| Code | Language |
|------|----------|
| en | English |
| zh | Chinese |
| ja | Japanese |
| ko | Korean |
| de | German |
| fr | French |
| ru | Russian |
| pt | Portuguese |
| es | Spanish |
| it | Italian |

### Language Detection

When no language is specified, Whisper auto-detects:

```python
# Without language hint - auto-detect
transcription = await whisper.transcribe(audio_path)

# With language hint - more accurate for short clips
transcription = await whisper.transcribe(audio_path, language="en")
```

## Transcription with Timestamps

For advanced use cases, word-level timestamps are available:

```python
async def transcribe_with_timestamps(
    self,
    audio_path: str,
    language: Optional[str] = None,
) -> List[Dict[str, any]]:
    await self.load_model_async()
    
    def _transcribe_timestamps_sync():
        audio, sr = load_audio(audio_path, sample_rate=16000)
        inputs = self.processor(audio, sampling_rate=16000, return_tensors="pt")
        
        with torch.no_grad():
            predicted_ids = self.model.generate(
                inputs["input_features"],
                return_timestamps=True,
            )
        
        # Parse timestamps
        return [
            {
                "text": transcription,
                "start": 0.0,
                "end": len(audio) / sr,
            }
        ]
    
    return await asyncio.to_thread(_transcribe_timestamps_sync)
```

## Memory Management

### Unloading

Free memory when not needed:

```python
def unload_model(self):
    if self.model is not None:
        del self.model
        del self.processor
        self.model = None
        self.processor = None
        
        if torch.cuda.is_available():
            torch.cuda.empty_cache()
```

### Global Instance

A singleton pattern manages the model:

```python
_whisper_model: Optional[WhisperModel] = None

def get_whisper_model() -> WhisperModel:
    global _whisper_model
    if _whisper_model is None:
        _whisper_model = WhisperModel()
    return _whisper_model
```

## Audio Preprocessing

### Resampling

Whisper requires 16kHz audio:

```python
audio, sr = load_audio(audio_path, sample_rate=16000)
```

### Format Support

The `load_audio` utility handles:
- WAV
- MP3
- FLAC
- OGG
- M4A

All formats are converted to mono 16kHz.

## API Endpoints

| Method | Endpoint | Description |
|--------|----------|-------------|
| POST | `/transcribe` | Transcribe audio file |

### Request

Multipart form data:

```
POST /transcribe
Content-Type: multipart/form-data

file: <audio_file>
language: en  (optional)
```

### Response

```json
{
  "text": "Hello, this is a test transcription.",
  "duration": 3.5
}
```

## Use Cases

### Reference Text for Voice Cloning

1. User records audio sample
2. Audio is sent to `/transcribe`
3. Transcription becomes `reference_text`
4. Both are added to voice profile

### Quality Tips

- Provide language hint for short audio
- Use clean audio with minimal noise
- Longer audio (>5s) improves accuracy
- Consider `small` or `medium` model for better quality

## Error Handling

Common issues:

| Error | Cause | Solution |
|-------|-------|----------|
| Model not found | First run, download failed | Retry with network |
| OOM | Model too large | Use smaller model |
| Empty result | No speech detected | Check audio has speech |
| Wrong language | Auto-detect failed | Provide language hint |
