Skip to main content

Crate wavo

Crate wavo 

Source
Expand description

Speech-to-text on the GPU, in pure Rust.

wavo runs the open ASR models that transcribe.cpp publishes as GGUF files on Hugging Face: NVIDIA’s Parakeet, Sber’s GigaAM, OpenAI’s Whisper and Useful Sensors’ Moonshine, with the same text and timestamps as transcribe.cpp. The encoder runs on the GPU through wgpu (Metal on Apple Silicon, Vulkan on Linux and Windows, DX12 on Windows without a Vulkan driver) with wavo’s own kernels; the audio frontend runs on the CPU, and so does the decoder except Whisper’s and Moonshine’s. It builds with a plain cargo build: no C++ toolchain, Python or ONNX Runtime.

§Features

  • cli (default): the wavo command-line tool. Leave it out when you use wavo as a library: cargo add wavo --no-default-features.
  • hub: the hub module, which downloads and manages models in the Hugging Face cache. It adds an HTTP client (ureq with rustls, whose ring compiles some C); without it the library is pure Rust and never uses the network.

§Models

Model::load takes the Q8_0 GGUF file of one of these models. With the hub feature, hub::MODELS lists them, and hub::Hub downloads them by short or full name.

NameFull nameSizeLanguagesOutput
parakeet-v3parakeet-tdt-0.6b-v30.74 GB25 European languagescased, punctuated
parakeet-v2parakeet-tdt-0.6b-v20.73 GBEnglishcased, punctuated
gigaam-v3gigaam-v3-e2e-rnnt0.27 GBRussiancased, punctuated
gigaam-v3-e2e-ctcgigaam-v3-e2e-ctc0.27 GBRussiancased, punctuated
gigaam-v3-rnntgigaam-v3-rnnt0.27 GBRussianlowercase, no punctuation
gigaam-v3-ctcgigaam-v3-ctc0.27 GBRussianlowercase, no punctuation
whisper-turbowhisper-large-v3-turbo0.89 GB100 languagescased, punctuated
whisper-tinywhisper-tiny0.05 GB99 languagescased, punctuated
whisper-basewhisper-base0.08 GB99 languagescased, punctuated
whisper-smallwhisper-small0.27 GB99 languagescased, punctuated
whisper-mediumwhisper-medium0.83 GB99 languagescased, punctuated
whisper-large-v3whisper-large-v31.67 GB100 languagescased, punctuated
whisper-tiny.enwhisper-tiny.en0.05 GBEnglishcased, punctuated
whisper-base.enwhisper-base.en0.08 GBEnglishcased, punctuated
whisper-small.enwhisper-small.en0.27 GBEnglishcased, punctuated
whisper-medium.enwhisper-medium.en0.83 GBEnglishcased, punctuated
whisper-largewhisper-large1.67 GB99 languagescased, punctuated
whisper-large-v2whisper-large-v21.67 GB99 languagescased, punctuated
breeze-asr-25Breeze-ASR-251.67 GBTaiwanese Mandarin and Englishcased, punctuated
moonshine-tinymoonshine-tiny0.04 GBEnglishcased, punctuated
moonshine-basemoonshine-base0.08 GBEnglishcased, punctuated

A model <full name> lives in the Hugging Face repository handy-computer/<full name>-gguf as <full name>-Q8_0.gguf.

§Transcribe

Model::transcribe takes 16 kHz mono samples as f32 in [-1, 1], and returns the text and its tokens with start times in milliseconds:

let model = wavo::Model::load("parakeet-tdt-0.6b-v3-Q8_0.gguf")?;
let pcm = vec![0.0f32; 16_000]; // one second of silence: 16 kHz mono in [-1, 1]
let transcript = model.transcribe(&pcm)?;

println!("{}", transcript.text);

for token in &transcript.tokens {
  println!("{:>6} ms  {}", token.start_ms, token.piece);
}

Load a model once and call transcribe as often as needed; loading takes about 0.1–0.2 s on an Apple M2. Model::device names the GPU and API it runs on, for a log line or a settings screen.

§Download a model

With cargo add wavo --no-default-features --features hub, hub::Hub finds a model in the Hugging Face cache that hf and huggingface_hub share, and downloads it when missing:

use std::ops::ControlFlow;

let hub = wavo::hub::Hub::new(); // or Hub::at(dir) for a folder of your app's own
let path = match hub.find("gigaam-v3") {
  Some(path) => path, // no network
  None => hub.pull("gigaam-v3", |_| ControlFlow::Continue(()))?,
};

let model = wavo::Model::load(path)?;

§Download on a thread, with progress and cancel

Hub::pull blocks until the file is complete, and the library starts no threads of its own: run it on a thread, with std::thread::spawn as here, or with tokio’s spawn_blocking. Its callback sees the bytes done and the total, and returns ControlFlow::Break to cancel; the partial file stays in the cache, and the next pull resumes it.

use std::ops::ControlFlow;
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering};

let cancel = Arc::new(AtomicBool::new(false));
let stop = Arc::clone(&cancel);
let download = std::thread::spawn(move || {
  wavo::hub::Hub::new().pull("parakeet-v3", |p| {
    if let Some(e) = p.retrying {
      eprintln!("\nretrying after: {e}");
    }
    eprint!("\r{} / {} MB", p.done / 1_000_000, p.total / 1_000_000);
    if stop.load(Ordering::Relaxed) { ControlFlow::Break(()) } else { ControlFlow::Continue(()) }
  })
});
// A cancel button elsewhere runs: cancel.store(true, Ordering::Relaxed);
match download.join().unwrap() {
  Ok(path) => println!("\ndownloaded {}", path.display()),
  Err(wavo::Error::Cancelled) => println!("\ncancelled; the next pull resumes"),
  Err(e) => eprintln!("\ndownload failed: {e}"),
}

§Left to the caller

  • Decoding and resampling. transcribe takes 16 kHz mono f32 only. Decode other formats, downmix to mono and resample yourself; the wavo CLI uses symphonia and rubato.
  • Long audio. transcribe takes audio of any length (Whisper runs its own 30 s windows), but accuracy drops past Model::max_audio_ms. Split longer audio at pauses, transcribe the pieces and shift their tokens’ start_ms by each piece’s offset, as wavo run does in src/cli/split.rs: it cuts at the quietest moments by frame energy.
  • Voice activity detection and streaming. Neither is built in: pass whole recordings or the pieces your own VAD cuts.

Modules§

hubhub
Download and manage the supported models in the Hugging Face cache (the hub feature).

Structs§

Device
The GPU a Model runs on, and the graphics API it reaches it through, as the driver reports them when the model loads. See Model::device.
Model
A speech-to-text model loaded on the GPU.
Token
One token of a Transcript.
Transcript
The text of a recording and the tokens it is made of.

Enums§

Api
The graphics API a Device is reached through.
DeviceKind
The kind of adapter a Device is, as the driver reports it.
Error
Everything that can fail in wavo: loading a model, running it on the GPU and, with the hub feature, managing downloads.

Type Aliases§

Result
Result with wavo’s Error.