Skip to main content
You transcribe recorded conversations, identify who spoke each word, and search what was said. What’s in this recipe:
  • Preview WhisperX transcription and save it for each clip
  • Extract word timestamps and speaker labels
  • Search speech segments with an embedding index

Problem

You have recorded conversations and need a transcript with word timestamps and speaker labels. You want to find relevant speech and return to the point in the recording where it was said.

Solution

You use WhisperX to transcribe speech locally and align each word to a time and a speaker. pixeltable.functions.whisperx.transcribe() does that as a computed column on audio, or on audio taken from a video with extract_audio(). diarize=True is the switch that adds word-level timestamps and speaker labels: Pixeltable then runs WhisperX alignment and diarization, and stores segments plus word_segments. A view splits those segments into rows, and an embedding index searches what was said. diarize=False returns language and segments with start, end, text, and avg_logprob. It does not need a Hugging Face token. alignment_model_name, interpolate_method, return_char_alignments, diarization_model_name, num_speakers, min_speakers, and max_speakers are valid only when diarize=True. You use the Query-then-Commit pattern: preview a transcript with a query on one clip, then save the same expression with add_computed_column() to transcribe every clip.

Setup

You need Python 3.11 or newer and WhisperX 3.8 or newer. The search step needs sentence-transformers. WhisperX also needs FFmpeg available on your system to load audio.
Diarization loads WhisperX’s default pyannote pipeline. On WhisperX 3.8 and later that model is pyannote/speaker-diarization-community-1. Accept that model’s terms on Hugging Face, then export a token. Pixeltable reads HF_TOKEN (or the [hf] token setting in Configuration). Pass diarization_model_name when you want a different pyannote pipeline, such as pyannote/speaker-diarization-3.1.

Load a video clip

Each run creates a fresh catalog directory. The later views use the same demo namespace.

Transcribe audio from video

extract_audio() copies the soundtrack of a pxt.Video column into a pxt.Audio value. A file that is already audio goes in a pxt.Audio column, and you pass that column to transcribe() without extract_audio(). model is a Whisper model name. tiny.en is the small English model. On CUDA, compute_type defaults to float16. Otherwise it defaults to int8.
You preview one transcript, then save the same expression as a computed column.
With diarize=True, each segment has start, end, text, avg_logprob, and words, plus speaker when the diarizer overlapped that span. word_segments is the flat list of words. Each word has word, start, end, score, and speaker when alignment and diarization assigned them. A missing timestamp or speaker is null.

Word-level timestamps and speakers

list_iterator() turns word_segments into one row per word. The astype() calls give Pixeltable the list types it needs. str | None and float | None keep a word whose start or speaker was not assigned.
num_speakers, min_speakers, and max_speakers constrain the diarizer when you already know how many people are speaking.

Search what was said

Index the speech segments. Each row is one utterance, with its start time and speaker, which is the unit you search. add_embedding_index() embeds text and stays current when you insert another clip. The first call downloads all-MiniLM-L6-v2.
Long-file splitting with OpenAI Whisper, without word alignment, is in Transcribe audio files with Whisper. Chapter titles from WhisperX segments are in Generate podcast chapters. Index behavior is in Embedding indexes.

In an application

These snippets call pxt.create_table(), create_view(), and add_embedding_index() so you can run them in a notebook or a REPL. An application declares the table and the view on a TableModel in app.py, puts the embedding index in __indexes__, and creates them with pxt schema update.

See also

Last modified on October 15, 2026