Skip to content

syncalong.transcribe

Transcribe audio with OpenAI Whisper and extract word-level timestamps. Use Transcriber to load the model once and reuse it across many songs.

transcribe

Transcribe audio with OpenAI Whisper and extract word-level timestamps.

WordTimestamp dataclass

WordTimestamp(word: str, raw: str, start: float, end: float)

A single recognised word with its timing.

Attributes:

Name Type Description
word str

Normalized text (for matching).

raw str

Original text from Whisper.

start float

Start time in seconds.

end float

End time in seconds.

Transcriber

Transcriber(model_name: str = 'base', *, model: Any = None)

Reusable Whisper transcriber that loads its model once.

Loading a Whisper model is expensive, so a long-running consumer (e.g. a jukebox processing many songs) should create one Transcriber and call :meth:transcribe repeatedly rather than calling :func:transcribe_audio per song.

Parameters:

Name Type Description Default
model_name str

Whisper model size or variant (tiny, base, small, medium, large, turbo, small.en, large-v3, ...). Ignored when model is provided.

'base'
model Any

A preloaded Whisper model object. When given it is used as-is and model_name is not loaded — useful for sharing an already-loaded model or injecting a test double.

None

Initialize the transcriber, loading a Whisper model if none is given.

Parameters:

Name Type Description Default
model_name str

Whisper model size or variant to load when model is None. See the class docstring for accepted values.

'base'
model Any

A preloaded Whisper model to use as-is instead of loading one.

None
Source code in src/syncalong/transcribe.py
def __init__(self, model_name: str = "base", *, model: Any = None):
    """Initialize the transcriber, loading a Whisper model if none is given.

    Args:
        model_name: Whisper model size or variant to load when ``model`` is
            ``None``. See the class docstring for accepted values.
        model: A preloaded Whisper model to use as-is instead of loading one.
    """
    injected = model is not None
    if model is None:
        # Heavy import, kept lazy so `import syncalong` never pulls in
        # whisper/torch. It is also deliberately absent at type-check time
        # in CI, hence the ignore.
        import whisper  # type: ignore[import-not-found]

        model = whisper.load_model(model_name)
    self.model_name = None if injected else model_name
    self._model: Any = model

transcribe

transcribe(audio_path: Path, *, language: str | None = None, initial_prompt: str | None = None) -> list[WordTimestamp]

Transcribe one audio file into word-level timestamps.

Parameters:

Name Type Description Default
audio_path Path

Audio file (any format ffmpeg can decode).

required
language str | None

BCP-47 language code, or None to auto-detect.

None
initial_prompt str | None

Text to bias the decoder with (e.g. the lyrics).

None

Returns:

Type Description
list[WordTimestamp]

Every recognised word, in order, with start/end times in seconds.

Source code in src/syncalong/transcribe.py
def transcribe(
    self,
    audio_path: Path,
    *,
    language: str | None = None,
    initial_prompt: str | None = None,
) -> list[WordTimestamp]:
    """Transcribe one audio file into word-level timestamps.

    Args:
        audio_path: Audio file (any format ffmpeg can decode).
        language: BCP-47 language code, or ``None`` to auto-detect.
        initial_prompt: Text to bias the decoder with (e.g. the lyrics).

    Returns:
        Every recognised word, in order, with start/end times in seconds.
    """
    opts = _build_transcribe_options(
        language=language, initial_prompt=initial_prompt
    )
    result = self._model.transcribe(str(audio_path), **opts)
    return _extract_words(result)

transcribe_audio

transcribe_audio(audio_path: Path, *, model_name: str = 'base', language: str | None = None, initial_prompt: str | None = None) -> list[WordTimestamp]

Transcribe one audio file, loading the model for this call only.

Convenience wrapper around :class:Transcriber for one-shot use. A consumer that transcribes many files should instantiate a :class:Transcriber once and reuse it instead.

Parameters:

Name Type Description Default
audio_path Path

Audio file (any format ffmpeg can decode).

required
model_name str

Whisper model size or variant.

'base'
language str | None

BCP-47 language code, or None to auto-detect.

None
initial_prompt str | None

Text to bias the decoder with (e.g. the lyrics).

None

Returns:

Type Description
list[WordTimestamp]

Ordered word timestamps.

Source code in src/syncalong/transcribe.py
def transcribe_audio(
    audio_path: Path,
    *,
    model_name: str = "base",
    language: str | None = None,
    initial_prompt: str | None = None,
) -> list[WordTimestamp]:
    """Transcribe one audio file, loading the model for this call only.

    Convenience wrapper around :class:`Transcriber` for one-shot use. A
    consumer that transcribes many files should instantiate a
    :class:`Transcriber` once and reuse it instead.

    Args:
        audio_path: Audio file (any format ffmpeg can decode).
        model_name: Whisper model size or variant.
        language: BCP-47 language code, or ``None`` to auto-detect.
        initial_prompt: Text to bias the decoder with (e.g. the lyrics).

    Returns:
        Ordered word timestamps.
    """
    return Transcriber(model_name).transcribe(
        audio_path, language=language, initial_prompt=initial_prompt
    )