whisper
Whisper is OpenAI's automatic speech recognition (ASR) library that transcribes and translates audio into text using transformer-based neural networks. It processes audio files by converting them to mel spectrograms, encoding them through a neural network, and decoding the output into timestamped text with word-level alignment capabilities.
Key Features
- Audio-to-Mel Spectrogram Processing
- Transformer-based Speech Recognition
- Word-Level Timing Alignment
- Multilingual Tokenization
- Text Normalization
- Model Management
Entry Points
Start here when working with this codebase
whisper/__init__.pyModel discovery, downloading, validation, and initialization - exposes load_model(), available_models(), and core transcription functions
Start here when adding new model variants, changing model loading behavior, or modifying the public API surface
whisper/__main__.pyBootstrap entry point that delegates to CLI handler in transcribe.py
Start here when adding new CLI commands or modifying how the CLI is invoked
whisper/transcribe.pyMain transcription orchestration, CLI argument parsing, and result formatting
Start here when modifying transcription behavior, adding CLI arguments, or changing output formats
tests/conftest.pyPytest fixtures and test configuration shared across all test modules
Start here when adding new test fixtures or modifying test setup
How to Make Changes
Common modification patterns for this codebase
Add a new audio preprocessing feature
whisper/audio.pyAdd new preprocessing function following the existing pattern of load_audio() and log_mel_spectrogram()
Pattern: See how pad_or_trim() handles tensor operations with configurable parameters
whisper/transcribe.pyIntegrate the new preprocessing step into the transcription pipeline
Pattern: Follow how log_mel_spectrogram is called and its output passed to the model
whisper/__init__.pyExport the new function if it should be part of the public API
Pattern: See how load_model and transcribe are exposed in __all__
Conventions to follow:
Add a new decoding strategy or sampling option
whisper/decoding.pyAdd new sampling/decoding logic to the DecodingOptions dataclass and implement in the decoding pipeline
Pattern: See how temperature, beam_size, and best_of parameters are defined and used in decode()
whisper/transcribe.pyAdd CLI argument for the new option and pass it to DecodingOptions
Pattern: Follow how --temperature and --beam_size arguments are parsed and forwarded
whisper/model.pyModify model inference if the strategy requires changes to forward pass
Pattern: See how Whisper.decode() interfaces with the decoding module
Conventions to follow:
Add a new text normalizer
whisper/normalizers/basic.pyCreate normalizer class or add methods to BasicTextNormalizer
Pattern: Follow BasicTextNormalizer's __call__ pattern that takes text and returns normalized text
whisper/normalizers/english.pyIf language-specific, add to EnglishTextNormalizer or create new language file
Pattern: See how EnglishTextNormalizer extends BasicTextNormalizer and adds number/contraction handling
whisper/normalizers/__init__.pyExport the new normalizer class from the package
Pattern: Follow existing imports: from .basic import BasicTextNormalizer
Conventions to follow:
Add a new output format for transcription results
whisper/utils.pyCreate new Writer subclass for the output format
Pattern: Follow WriteTXT, WriteVTT, WriteSRT patterns - each has write_result() method
whisper/transcribe.pyRegister the new format in the CLI argument choices and writer dispatch
Pattern: See how --output_format argument maps to writer classes via get_writer()
Conventions to follow:
Add a new model architecture variant
whisper/model.pyDefine new ModelDimensions configuration and modify Whisper class if architecture differs
Pattern: See how ModelDimensions dataclass defines n_mels, n_audio_ctx, n_vocab, etc.
whisper/__init__.pyAdd model to _MODELS dict with download URL and expected hash
Pattern: Follow existing entries like 'tiny', 'base', 'small' with their URLs and SHA256 hashes
whisper/tokenizer.pyUpdate tokenizer if model uses different vocabulary or special tokens
Pattern: See how get_tokenizer() handles multilingual vs English-only models
Conventions to follow:
Add GPU-optimized operation with Triton
whisper/triton_ops.pyAdd new Triton kernel with @triton.jit decorator
Pattern: Follow dtw_kernel and median_filter_kernel patterns for block-based GPU computation
whisper/timing.pyIntegrate the optimized operation into timing alignment pipeline
Pattern: See how dtw_cuda() is called with fallback to CPU implementation
Conventions to follow:
Add word-level timing feature
whisper/timing.pyModify alignment logic using cross-attention weights and DTW
Pattern: See how find_alignment() extracts word boundaries from token-level alignments
whisper/tokenizer.pyAdd token manipulation helpers if needed for word boundary detection
Pattern: See how Tokenizer.decode_with_timestamps() handles timestamp tokens
whisper/transcribe.pyEnable feature via CLI flag and include in result dict
Pattern: Follow --word_timestamps argument and how it triggers add_word_timestamps()
Conventions to follow:
Coding Conventions
Standards and patterns used in this codebase
Use comprehensive type annotations with Optional, Union, List, Dict, and Tuple from typing module for all function signatures and class attributes
def detect_language(
model: "Whisper", mel: Tensor, tokenizer: Tokenizer = None
) -> Tuple[Tensor, List[dict]]:Use @dataclass decorator for configuration and result containers, with frozen=True for immutable data structures
@dataclass(frozen=True)
class DecodingOptions:
task: str = "transcribe"
language: Optional[str] = None
temperature: float = 0.0Place imports at top organized by: standard library, third-party packages, then local imports, with lazy imports inside functions for optional heavy dependencies
import torch
import numpy as np
from .audio import SAMPLE_RATE
from .utils import exact_divDefine module-level constants in UPPER_SNAKE_CASE at the top of files after imports
SAMPLE_RATE = 16000
N_FFT = 400
HOP_LENGTH = 160
CHUNK_LENGTH = 30Use assertions for internal invariants and raise specific exceptions (ValueError, RuntimeError) with descriptive messages for user-facing errors
if audio.shape[-1] > N_SAMPLES:
raise ValueError("audio is longer than 30s")
assert x.shape[1:] == self.positional_embedding.shape, "incorrect audio shape"Use concise docstrings for public functions describing parameters and return values, with inline comments for complex logic
def load_audio(file: str, sr: int = SAMPLE_RATE):
"""
Open an audio file and read as mono waveform, resampling as necessary
"""Accept device parameter as string or torch.device, defaulting to CUDA if available, and use consistent device placement patterns
device: str = "cuda" if torch.cuda.is_available() else "cpu"
model = model.to(device)Use torch.no_grad() context manager for inference, and prefer in-place operations with underscore suffix where appropriate
with torch.no_grad():
mel = log_mel_spectrogram(audio, model.dims.n_mels)
logits[logits == -np.inf] = -1e8Use argparse with add_argument for CLI, organizing arguments into logical groups with clear help text and sensible defaults
parser.add_argument(
"--model",
default="turbo",
choices=available_models(),
help="name of the Whisper model to use",
)Use pytest fixtures in conftest.py for shared test resources, with descriptive test function names prefixed with test_
@pytest.fixture
def model():
return whisper.load_model("tiny")
def test_transcribe(model):