Tapeclerk · Catalogue sheet 2 · How we do itPrinted 2026-09 · The landing page is sheet 1

HomeHow we do it

Method · model · limits · retention

How we do it

This page exists so that the claims on the landing page have somewhere to be checked. It covers the method, the model, the hardware, the enforced limits, what is deleted afterwards, and the claims we do not make.

The pipeline, in the order it runs

An episode link is not an audio file, so the first job is not transcription, it is resolution. An Apple Podcasts episode page carries its own metadata as JSON-LD in the document head; the show's RSS feed comes from the iTunes lookup API; the audio URL is the <enclosure> of the feed item whose title, duration and publish date match the episode the page described. A Spotify link goes through oEmbed and the show's RSS feed. A YouTube link is read with yt-dlp for its title, channel and length, and its audio track is fetched the same way when the job runs; a live stream is refused, because there is no finished recording to transcribe. A link that is already a feed or an audio file is used as given.

Then fetch: the enclosure is streamed to disk with a byte cap enforced inside the stream callback, so an episode that lies about its length stops the request rather than filling a volume. Then transcribe: ffmpeg decodes whatever the publisher served into 16 kHz mono PCM, and Parakeet, cut at the pauses Silero finds, writes the words with a time on each; a pyannote segmentation model with TitaNet speaker embeddings draws who spoke when, and every word takes the speaker whose region covers it.

Two decisions in that sequence change the output:

The model, and which one

NVIDIA's Parakeet TDT 0.6B v3, a 600-million-parameter transducer, through the sherpa-onnx runtime on a GPU we own, with a pyannote segmentation model and TitaNet speaker embeddings for who spoke when. Not a hosted API, which would put another company's speech service and its retention policy in the path. Parakeet replaced Whisper large-v3 for two measured reasons: on the public English benchmarks it makes fewer word errors, and it decodes an hour of audio in well under a minute on the card, which is what lets the audio be deleted minutes after it arrived rather than hours. It covers 25 European languages.

The language is the language the model was configured for. If the audio arrives in another one, the job returns LANG_UNSUPPORTED. A fluent transcript in the wrong language is worse than a refusal.

Verbatim means verbatim

The text is what the model heard, at the offsets the model reported. The model adds punctuation and capitalisation as part of decoding, and that is where the editing stops. Specifically, we do not run a spelling corrector over proper nouns, do not insert a period where the model left a comma, and do not merge two segments because the sentence reads better that way.

A corrected transcript is a claim about what was said. A verbatim one is a record of what the recogniser heard, with the timing attached, so you can jump to the audio and check. When the model writes "HatGPT" instead of "GPT", that is visible in the transcript, which is what tells you to fix it. Every transcript ships with a marker saying it is machine output.

Limits, as numbers

Episode length
4 hours of audio. Longer recordings are split into parts, transcribed one at a time, and the transcripts stitch back in order.
Download size
400 MB, enforced mid-stream. The cap is checked on every chunk of the response body, so the transfer stops at the cap instead of after it.
Workspace
A byte cap on the scratch directory, checked before each download, so a queue of jobs cannot fill the volume on the way to being deleted.
Redirects
A bounded number, and a visited set. A feed that redirects to itself is BAD_LINK, not a hang.
Feed cache
15 minutes per feed, so a batch of runs does not hit a publisher's server once per episode.
Cost
One credit per 30 minutes of audio, rounded up. No credits are taken for any failure.

What we delete, and when

The fetched audio is removed by the same step that produces the transcript, before the job reports itself done, not by a cleanup job that runs later. The raw download is written to a scratch directory under a name unique to the job, so two runs for the same episode cannot read each other's file, and the delete is a plain File.rm in the transcribe function.

What is kept after the run: the transcript, the episode metadata, the job record, and the fact that the job ran. No audio, no model training, no third-party speech API.

What we do not claim

Reproduce it yourself

The output on the landing page is what three commands print for a 45-second clip: cut it, decode it, draw the speakers. Any clip you have rights to works the same way:

ffmpeg -ss 00:11:02 -t 45 -i episode.mp3 -ac 1 -ar 16000 clip16.wav
sherpa-onnx-offline --model-type=nemo_transducer --encoder=parakeet/encoder.onnx \
  --decoder=parakeet/decoder.onnx --joiner=parakeet/joiner.onnx \
  --tokens=parakeet/tokens.txt clip16.wav
sherpa-onnx-offline-speaker-diarization --clustering.num-clusters=2 \
  --segmentation.pyannote-model=pyannote/model.onnx \
  --embedding.model=titanet_small.onnx clip16.wav

The decoder prints a time for every token, so the timings can be checked; the diarizer prints who spoke when; the two are joined by overlap, and that join is the only step of ours between the models and the page.

Changes to this page

2026-09-03
Accounts. The API and the form both need one now: a key (Authorization: Bearer) or the site's signed-in session. Each account starts with 6 credits, one per started half hour, charged only when a transcript files; a job an account cannot pay for is refused before it runs. A job is visible only to the account that ran it.
2026-09-03
YouTube video links accepted: the audio track is fetched with yt-dlp on our machine and goes through the same pipeline. Transcript downloads moved to opaque links under /t/ that say nothing about the job.
2026-09-03
Engine changed from whisper.cpp on a CPU to NVIDIA Parakeet TDT 0.6B v3 on our own GPU, with speaker turns from a pyannote + TitaNet pipeline. The API at /api/v1/transcriptions went live the same day. Later that day the speaker grouping was recalibrated after a two-host episode filed as 82 voices, and the speakers hint became a floor rather than a forced count.
2026-09-02
Reset as sheet 2 of the catalogue. The method, the limits and the claims are unchanged; only the print is.
2026-09-01
First published with the landing page. Limits section reflects the enforced values in code, not the intended ones.