> ## Documentation Index
> Fetch the complete documentation index at: https://docs.pixeltable.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Transcribe audio files with Whisper

> Transcribe audio and video files into searchable text columns in Pixeltable using Whisper, WhisperX, and other speech-to-text models.

<a href="https://kaggle.com/kernels/welcome?src=https://github.com/pixeltable/pixeltable/blob/release/docs/release/howto/cookbooks/audio/audio-transcribe.ipynb" id="openKaggle" target="_blank" rel="noopener noreferrer"><img src="https://kaggle.com/static/images/open-in-kaggle.svg" alt="Open in Kaggle" style={{ display: 'inline', margin: '0px' }} noZoom /></a>  <a href="https://colab.research.google.com/github/pixeltable/pixeltable/blob/release/docs/release/howto/cookbooks/audio/audio-transcribe.ipynb" id="openColab" target="_blank" rel="noopener noreferrer"><img src="https://colab.research.google.com/assets/colab-badge.svg" alt="Open in Colab" style={{ display: 'inline', margin: '0px' }} noZoom /></a>  <a href="https://raw.githubusercontent.com/pixeltable/pixeltable/refs/tags/release/docs/release/howto/cookbooks/audio/audio-transcribe.ipynb" id="downloadNotebook" target="_blank" rel="noopener noreferrer"><img src="https://img.shields.io/badge/%E2%AC%87-Download%20Notebook-blue" alt="Download Notebook" style={{ display: 'inline', margin: '0px' }} noZoom /></a>

<Tip>This documentation page is also available as an interactive notebook. You can launch the notebook in
Kaggle or Colab, or download it for use with an IDE or local Jupyter installation, by clicking one of the
above links.</Tip>

export const quartoRawHtml = [`
<table>
<thead>
<tr>
<th>File</th>
<th>Duration</th>
<th>Challenge</th>
</tr>
</thead>
<tbody>
<tr>
<td style="vertical-align: middle;">podcast.mp3</td>
<td style="vertical-align: middle;">60 min</td>
<td style="vertical-align: middle;">Too long to process at once</td>
</tr>
<tr>
<td style="vertical-align: middle;">interview.mp4</td>
<td style="vertical-align: middle;">30 min</td>
<td style="vertical-align: middle;">Need to extract audio first</td>
</tr>
<tr>
<td style="vertical-align: middle;">meeting.wav</td>
<td style="vertical-align: middle;">2 hours</td>
<td style="vertical-align: middle;">Must segment for memory efficiency</td>
</tr>
</tbody>
</table>
`, `
<table class="dataframe" data-quarto-postprocess="true" data-border="1">
<thead>
<tr style="text-align: right;">
<th data-quarto-table-cell-role="th">segment_start</th>
<th data-quarto-table-cell-role="th">segment_end</th>
</tr>
</thead>
<tbody>
<tr>
<td style="vertical-align: middle;">0.</td>
<td style="vertical-align: middle;">30.</td>
</tr>
<tr>
<td style="vertical-align: middle;">28.003</td>
<td style="vertical-align: middle;">58.003</td>
</tr>
</tbody>
</table>
`, `
<table class="dataframe" data-quarto-postprocess="true" data-border="1">
<thead>
<tr style="text-align: right;">
<th data-quarto-table-cell-role="th">segment_start</th>
<th data-quarto-table-cell-role="th">segment_end</th>
<th data-quarto-table-cell-role="th">text</th>
</tr>
</thead>
<tbody>
<tr>
<td style="vertical-align: middle;">0.</td>
<td style="vertical-align: middle;">30.</td>
<td style="vertical-align: middle;">of experiencing self versus remembering self. I was hoping you can
give a simple answer of how we should live life. Based on the fact that
our memories could be a source of happiness or could be the primary
source of happiness, that an event when experienced bears its fruits the
most when it's remembered over and over and over and over.</td>
</tr>
<tr>
<td style="vertical-align: middle;">28.003</td>
<td style="vertical-align: middle;">58.003</td>
<td style="vertical-align: middle;">over and over and over and over and maybe there is some wisdom in
the fact that we can control to some degree how we remember how we
evolve our memory of it such that it can maximize the long-term
happiness of that repeated experience. Okay, well first I'll say I wish
I could take you on the road with me. That was such a great description.
Can I be your opening ax? Oh my God, no, I'm going to open for you dude.
Otherwise it's like, you know, everybody leaves.</td>
</tr>
</tbody>
</table>
`, `
<table>
<thead>
<tr>
<th>Model</th>
<th>Speed</th>
<th>Quality</th>
<th>Best for</th>
</tr>
</thead>
<tbody>
<tr>
<td style="vertical-align: middle;"><code>tiny.en</code></td>
<td style="vertical-align: middle;">Fastest</td>
<td style="vertical-align: middle;">Basic</td>
<td style="vertical-align: middle;">Quick tests</td>
</tr>
<tr>
<td style="vertical-align: middle;"><code>base.en</code></td>
<td style="vertical-align: middle;">Fast</td>
<td style="vertical-align: middle;">Good</td>
<td style="vertical-align: middle;">General use</td>
</tr>
<tr>
<td style="vertical-align: middle;"><code>small.en</code></td>
<td style="vertical-align: middle;">Medium</td>
<td style="vertical-align: middle;">Better</td>
<td style="vertical-align: middle;">Higher accuracy</td>
</tr>
<tr>
<td style="vertical-align: middle;"><code>medium.en</code></td>
<td style="vertical-align: middle;">Slow</td>
<td style="vertical-align: middle;">Great</td>
<td style="vertical-align: middle;">Professional quality</td>
</tr>
<tr>
<td style="vertical-align: middle;"><code>large</code></td>
<td style="vertical-align: middle;">Slowest</td>
<td style="vertical-align: middle;">Best</td>
<td style="vertical-align: middle;">Maximum accuracy</td>
</tr>
</tbody>
</table>
`, `
<table>
<thead>
<tr>
<th>Parameter</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td style="vertical-align: middle;"><code>duration</code></td>
<td style="vertical-align: middle;">Duration of each segment in seconds</td>
</tr>
<tr>
<td style="vertical-align: middle;"><code>overlap</code></td>
<td style="vertical-align: middle;">Overlap between segments (helps with word boundaries)</td>
</tr>
<tr>
<td style="vertical-align: middle;"><code>min_segment_duration</code></td>
<td style="vertical-align: middle;">Drop the last segment if shorter than this</td>
</tr>
</tbody>
</table>
`];

Convert speech to text locally using OpenAI’s open-source Whisper
model—no API key needed.

## Problem

You have audio or video files that need transcription. Long files are
memory-intensive to process at once, so you need to split them into
manageable segments.

<div style={{ 'margin': '0px 20px 0px 20px' }} dangerouslySetInnerHTML={{ __html: quartoRawHtml[0] }} />

## Solution

**What’s in this recipe:**

* Transcribe audio files locally with Whisper (no API key)
* Automatically segment long files
* Extract and transcribe audio from videos

You create a view with `audio_splitter` to break long files into
segments, then add a computed column for transcription. Whisper runs
locally on your machine—no API calls needed.

### Setup

```python theme={"theme":{"light":"light-plus","dark":"dark-plus"}}
%pip install -qU pixeltable openai-whisper
```

### Load audio files

```python theme={"theme":{"light":"light-plus","dark":"dark-plus"}}
import pixeltable as pxt
from pixeltable.functions import whisper
from pixeltable.functions.audio import audio_splitter

# Create a fresh directory
pxt.drop_dir('audio_demo', force=True)
pxt.create_dir('audio_demo')
```

<pre style={{ 'margin': '-20px 20px 0px 20px', 'padding': '0px', 'background-color': 'transparent', 'color': 'black' }}>
  Connected to Pixeltable database at: postgresql+psycopg://postgres:@/pixeltable?host=/Users/asiegel/.pixeltable/pgdata
  Converting metadata from version 45 to 46
  Created directory 'audio\_demo'.
  \<pixeltable.catalog.dir.Dir at 0x169ab36a0>
</pre>

```python theme={"theme":{"light":"light-plus","dark":"dark-plus"}}
# Create table for audio files
audio = pxt.create_table('audio_demo/files', {'audio': pxt.Audio})
```

<pre style={{ 'margin': '-20px 20px 0px 20px', 'padding': '0px', 'background-color': 'transparent', 'color': 'black' }}>
  Created table 'files'.
</pre>

```python theme={"theme":{"light":"light-plus","dark":"dark-plus"}}
# Insert a sample audio file (video files also work - audio is extracted automatically)
audio.insert(
    [
        {
            'audio': 'https://raw.githubusercontent.com/pixeltable/pixeltable/main/docs/resources/audio-transcription-demo/Lex-Fridman-Podcast-430-Excerpt-0.mp4'
        }
    ]
)
```

<pre style={{ 'margin': '-20px 20px 0px 20px', 'padding': '0px', 'background-color': 'transparent', 'color': 'black' }}>
  Inserted 1 row with 0 errors in 1.05 s (0.95 rows/s)
  1 row inserted.
</pre>

### Split into segments

Create a view that splits audio into 30-second segments with overlap:

```python theme={"theme":{"light":"light-plus","dark":"dark-plus"}}
# Split audio into segments for transcription
segments = pxt.create_view(
    'audio_demo/segments',
    audio,
    iterator=audio_splitter(
        audio.audio,
        duration=30.0,  # 30-second segments
        overlap=2.0,  # 2-second overlap for context
        min_segment_duration=5.0,  # Drop segments shorter than 5 seconds
    ),
)
```

```python theme={"theme":{"light":"light-plus","dark":"dark-plus"}}
# View the segments
segments.select(segments.segment_start, segments.segment_end).collect()
```

<div style={{ 'margin': '0px 20px 0px 20px' }} dangerouslySetInnerHTML={{ __html: quartoRawHtml[1] }} />

### Transcribe with Whisper

Add a computed column that transcribes each segment:

```python theme={"theme":{"light":"light-plus","dark":"dark-plus"}}
# Add transcription column (runs locally - no API key needed)
segments.add_computed_column(
    transcription=whisper.transcribe(
        audio=segments.audio_segment,
        model='base.en',  # Options: tiny.en, base.en, small.en, medium.en, large
    )
)
```

<pre style={{ 'margin': '-20px 20px 0px 20px', 'padding': '0px', 'background-color': 'transparent', 'color': 'black' }}>
  Added 2 column values with 0 errors in 3.35 s (0.60 rows/s)
  2 rows updated.
</pre>

```python theme={"theme":{"light":"light-plus","dark":"dark-plus"}}
# Extract just the text
segments.add_computed_column(text=segments.transcription.text)
```

<pre style={{ 'margin': '-20px 20px 0px 20px', 'padding': '0px', 'background-color': 'transparent', 'color': 'black' }}>
  Added 2 column values with 0 errors in 0.06 s (31.82 rows/s)
  2 rows updated.
</pre>

```python theme={"theme":{"light":"light-plus","dark":"dark-plus"}}
# View transcriptions with timestamps
segments.select(
    segments.segment_start, segments.segment_end, segments.text
).collect()
```

<div style={{ 'margin': '0px 20px 0px 20px' }} dangerouslySetInnerHTML={{ __html: quartoRawHtml[2] }} />

## Explanation

**Whisper models:**

<div style={{ 'margin': '0px 20px 0px 20px' }} dangerouslySetInnerHTML={{ __html: quartoRawHtml[3] }} />

Models ending in `.en` are English-only and faster. Remove `.en` for
multilingual support.

**audio\_splitter parameters:**

<div style={{ 'margin': '0px 20px 0px 20px' }} dangerouslySetInnerHTML={{ __html: quartoRawHtml[4] }} />

**Video files work too:**

When you insert a video file, Pixeltable automatically extracts the
audio track.

## See also

* [Iterators
  documentation](/platform/iterators)
* [Whisper library](https://github.com/openai/whisper)
