Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

File transcription

Start by turning a short WAV recording into text with Whisper. Once that works, you can choose a language or correct project terms in the result. Add the aria-stt dependency and check your build tools before continuing.

Model and audio

Whisper needs a GGML model from the whisper.cpp model collection. This example uses ggml-base.en.bin, a small English model:

curl -fL -o ggml-base.en.bin \
  https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-base.en.bin

Use the model’s absolute path below.

The input must be a nonempty WAV containing 16 kHz, mono, signed 16-bit PCM (uncompressed audio), with at most 15 minutes of audio. MP3, stereo WAV, and other sample rates are not converted automatically. To convert a recording with ffmpeg:

ffmpeg -i input.m4a \
  -ar 16000 \
  -ac 1 \
  -c:a pcm_s16le \
  speech.wav

Use a short recording with a known sentence for your first test.

Replace src/main.rs with:

use aria_stt::{prelude::*, whisper::Whisper};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let engine = Whisper::load("/absolute/path/ggml-base.en.bin")?;
    let transcription = Transcription::streaming(engine);
    let transcript = transcription.transcribe_file("speech.wav")?;
    println!("{}", transcript.as_str());
    Ok(())
}

Replace the model path, put speech.wav in your project directory, and run:

cargo run \
  --release

The program prints the recognized sentence. Whisper::load loads the model; Transcription uses it to process the recording. Reuse transcription for later files to avoid loading the model for each one.

transcribe_file uses automatic language selection; an English-only model still recognizes English only. Transcription::streaming also works with a completed file and returns the complete result here.

If model loading fails, check that you downloaded a GGML file and supplied an absolute path. Model files must be owned by your user or root and must not be writable by group or others (for example, chmod 644). If input loading fails, check the WAV format above. Silence or empty recognized output is reported as TranscriptionError::NoSpeech.

Choose a language

If you know the recording’s language, you can select it explicitly. Use a RecordingReader to read the WAV and pass the language to transcribe. Replace src/main.rs with:

use aria_stt::{prelude::*, whisper::Whisper};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let engine = Whisper::load("/absolute/path/ggml-base.en.bin")?;
    let transcription = Transcription::streaming(engine);
    let mut audio = RecordingReader::from_wav_file("speech.wav")?;
    let language: Language = "en".parse()?;
    let transcript = transcription.transcribe(&mut audio, &language)?;
    println!("{}", transcript.as_str());
    Ok(())
}

The selected language must be supported by the model.

Project spellings

Recognition may spell a project name differently from how you write it. Text layers let you correct those spellings after recognition. Keep the model-loading line and replace let transcription = ... with:

use aria_stt::{prelude::*, whisper::Whisper};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let engine = Whisper::load("/absolute/path/ggml-base.en.bin")?;
let transcription = Transcription::streaming(engine)
    .with(RemoveHesitations)
    .with(Vocabulary::new(["aria-stt", "Cargo.toml"])?);
let _ = transcription;
Ok(())
}

Layers run in .with(...) order. RemoveHesitations removes a fixed set of English fillers. Vocabulary can turn “aria dash stt” into aria-stt and “cargo dot toml” into Cargo.toml. It corrects text after recognition; it does not train or prompt the model, and it is not general fuzzy spelling correction.

With live transcription, layers process each finalized segment separately. A phrase split across segments cannot be matched as one vocabulary term.

Test your spellings

Vocabulary works without a model, so you can test it directly. Put this in tests/vocabulary.rs:

use aria_stt::Vocabulary;

#[test]
fn vocabulary_formats_project_terms() {
    let vocabulary = Vocabulary::new(["aria-stt", "Cargo.toml"]).unwrap();

    assert_eq!(
        vocabulary
            .correct("aria dash stt and cargo dot toml")
            .as_deref(),
        Some("aria-stt and Cargo.toml")
    );
    assert_eq!(vocabulary.correct("unchanged"), None);
}

Run cargo test. correct returns Some when it changes text and None when it leaves text alone. Add cases for your own terms and for ordinary text that must stay unchanged.

To use the same transcription with microphone input, continue to Microphone transcription.