Skip to content

Transcribing recordings offline

Short answer: yazses transcribe <file> turns an existing recording into text on your own machine. Add --diarize and it labels who spoke when. Nothing is uploaded, there is no per-minute charge, and it works on a laptop CPU.

yazses transcribe interview.m4a
yazses transcribe interview.m4a --diarize          # label Speaker 1, Speaker 2, …
yazses transcribe interview.m4a --diarize --format srt

Why not just upload it

Online transcription services are convenient and often accurate, but they come with three costs that rule them out for a lot of recordings:

  1. The recording leaves your control. For an interview with a confidential source, a patient consultation, a legal deposition, or an internal meeting, that is frequently unacceptable.
  2. Per-minute pricing. A backlog of long recordings gets expensive quickly.
  3. They need to be online. Large media files over a slow connection are painful, and on a restricted network the upload may not be permitted at all.

Local transcription trades wall-clock speed for privacy and cost. On a CPU it is not instantaneous, but it is unattended — start it and come back.

Any format

Input decoding handles essentially any audio or video container, because it decodes through PyAV (with an ffmpeg CLI fallback) down to the 16 kHz mono the model expects. MP3, M4A, WAV, FLAC, OGG, MP4, MKV — you do not need to convert anything first, and there is no extra dependency to install for it.

Speaker labels (diarization)

With --diarize, the transcript is attributed by speaker:

Speaker 1:  So the question I keep coming back to is …
Speaker 2:  Right, and that's exactly where the previous approach broke down.

Speakers are distinguished by voice embeddings and clustering — not by pitch — using a small int8 ONNX model (about 15 MB, fetched once). Diarization is an optional extra, so if you do not need it you do not pay for it in install size:

yazses features enable diarize

Naming speakers

Three levels, in priority order:

  1. Tell it directly--names "Alice,Bob" or --rename to relabel after the fact.
  2. Enrolled voiceprints — if someone has explicitly enrolled, they are recognised and named automatically in future recordings. This is opt-in and consent-gated by design; YazSes never silently enrolls a voice it hears.
  3. OtherwiseSpeaker 1, Speaker 2, …

Output formats

Format Use
txt Plain text
md Markdown, speaker-attributed
srt Subtitles
vtt Web subtitles
json Structured, with word-level timings

Subtitle output makes this a practical local workflow for captioning your own video — transcribe, then load the .srt alongside the file.

Whole meetings, live

Transcribing a file after the fact is one job; capturing a meeting as it happens is another. YazSes does both from the same install:

yazses meeting start
# … the meeting happens …
yazses meeting stop      # → labelled transcript, and optional minutes

Meeting Mode keeps a rolling live transcript during capture, then re-runs accurate batch diarization at stop — so you get both immediacy and quality. It can also generate speaker-aware minutes with a local LLM. See offline meeting notes for the full workflow and how it compares to Otter.ai, Fireflies and Granola.

Honest limits

  • It is not real-time on CPU. A long recording takes a meaningful fraction of its own duration to process. Plan for unattended runs.
  • Diarization is good, not perfect. Heavy crosstalk, more than a handful of speakers, or poor room audio will degrade attribution. Fix labels afterwards with --rename rather than re-running.
  • Diarization needs the optional extra. If you ask for speaker labels without it installed, YazSes warns you rather than silently producing an un-attributed transcript.
  • Accuracy tracks the model you chose. A larger local model is more accurate and slower; pick per job.