MP
⚡ Custom Dashboards with Real-Time Data

🎙️ whisper-captions

Whisper, but caption-ready. Turn whisper.cpp output into clean segments with whole-word timestamps, and export SRT or WebVTT.

CI statuscrates.io versiondocs.rsdownloads

whisper.cpp is great at transcribing speech, but its word-level output is made of BPE tokens, not words. Join them naively and your captions read M uld oon, was p or friend ., and control tokens like [_BEG_] and [_TT_150] leak into the text.

whisper-captions is a small, open-source Rust crate that fixes exactly that. It reads whisper.cpp's JSON or stdout, reassembles tokens into whole words with start and end times, drops the special tokens and gives you segments that are ready for a subtitle track.

RustWhisperwhisper.cppSpeech-to-textCaptionsSubtitlesSRTWebVTTOpen Source
whisper-captions: whisper.cpp tokens such as [_BEG_], ' Mul', 'do', 'on,' are merged into the words Hello, Muldoon, friend. with start and end times

📦 Get it

cargo add whisper-captions

Crates.io: crates.io/crates/whisper-captions

Documentation: docs.rs/whisper-captions

Changelog: CHANGELOG.md

🚀 Features

  • 📥 Reads every whisper.cpp output you are likely to have: -oj, -ojf (full JSON with tokens) and plain stdout
  • 🧩 Reassembles BPE tokens into whole words with start and end times
  • 🧹 Drops special tokens: [_BEG_], [_TT_150], <|endoftext|>
  • ⏱️ Normalizes whitespace and timestamps (strings, seconds or milliseconds)
  • 🎬 Exports SRT and WebVTT
  • 🪶 No whisper dependency: works on output files from any whisper.cpp version
  • 🤝 The token merger also accepts tokens from whisper-rs
  • 🧾 Serde-ready output in camelCase, easy to hand to a frontend

🦀 Example: whisper.cpp JSON to SRT

// whisper-cli -m ggml-base.en.bin -f audio.wav -ojf -of out
let json = std::fs::read_to_string("out.json")?;
let segments = whisper_captions::parse_whisper_json_str(&json)?;

for segment in &segments {
    println!("{}–{} ms: {}", segment.start_ms, segment.end_ms, segment.text);
    for word in &segment.words {
        println!("    {:>6} ms  {}", word.start_ms, word.text);
    }
}

std::fs::write("out.srt", whisper_captions::to_srt(&segments))?;

💻 Example: from the command line

The repository ships a small whisper2srt example:

cargo run --example whisper2srt -- out.json > out.srt
cargo run --example whisper2srt -- stdout.txt --vtt > out.vtt

🎯 Built for

  • Caption and subtitle editors that need word timings for karaoke-style or per-word captions
  • Video pipelines that run whisper.cpp and want SRT or VTT without extra tooling
  • Desktop apps on Tauri or Electron, where the parsing should be fast and dependency-free
  • whisper-rs projects that want clean words instead of raw tokens

🎬 Born in Flixlar

whisper-captions was extracted from Flixlar, my local-first caption editor, where it turns whisper.cpp auto-captions into editable subtitle tracks as a native Rust module. Flixlar needed it, so it is shaped by a real caption workflow, not a demo.

🤝 Need speech-to-text in your product?

I build with Whisper, FFmpeg and Rust: transcription and captioning pipelines, subtitle tooling, and desktop or backend integrations around them. I take on freelance work.

Made with 💛 by Mads Paaskesen · Powered by Rust & Open Source · MIT
Theme