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): thewavocommand-line tool. Leave it out when you use wavo as a library:cargo add wavo --no-default-features.hub: thehubmodule, which downloads and manages models in the Hugging Face cache. It adds an HTTP client (ureqwith rustls, whoseringcompiles 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.
| Name | Full name | Size | Languages | Output |
|---|---|---|---|---|
parakeet-v3 | parakeet-tdt-0.6b-v3 | 0.74 GB | 25 European languages | cased, punctuated |
parakeet-v2 | parakeet-tdt-0.6b-v2 | 0.73 GB | English | cased, punctuated |
gigaam-v3 | gigaam-v3-e2e-rnnt | 0.27 GB | Russian | cased, punctuated |
gigaam-v3-e2e-ctc | gigaam-v3-e2e-ctc | 0.27 GB | Russian | cased, punctuated |
gigaam-v3-rnnt | gigaam-v3-rnnt | 0.27 GB | Russian | lowercase, no punctuation |
gigaam-v3-ctc | gigaam-v3-ctc | 0.27 GB | Russian | lowercase, no punctuation |
whisper-turbo | whisper-large-v3-turbo | 0.89 GB | 100 languages | cased, punctuated |
whisper-tiny | whisper-tiny | 0.05 GB | 99 languages | cased, punctuated |
whisper-base | whisper-base | 0.08 GB | 99 languages | cased, punctuated |
whisper-small | whisper-small | 0.27 GB | 99 languages | cased, punctuated |
whisper-medium | whisper-medium | 0.83 GB | 99 languages | cased, punctuated |
whisper-large-v3 | whisper-large-v3 | 1.67 GB | 100 languages | cased, punctuated |
whisper-tiny.en | whisper-tiny.en | 0.05 GB | English | cased, punctuated |
whisper-base.en | whisper-base.en | 0.08 GB | English | cased, punctuated |
whisper-small.en | whisper-small.en | 0.27 GB | English | cased, punctuated |
whisper-medium.en | whisper-medium.en | 0.83 GB | English | cased, punctuated |
whisper-large | whisper-large | 1.67 GB | 99 languages | cased, punctuated |
whisper-large-v2 | whisper-large-v2 | 1.67 GB | 99 languages | cased, punctuated |
breeze-asr-25 | Breeze-ASR-25 | 1.67 GB | Taiwanese Mandarin and English | cased, punctuated |
moonshine-tiny | moonshine-tiny | 0.04 GB | English | cased, punctuated |
moonshine-base | moonshine-base | 0.08 GB | English | cased, 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.
transcribetakes 16 kHz monof32only. Decode other formats, downmix to mono and resample yourself; thewavoCLI usessymphoniaandrubato. - Long audio.
transcribetakes audio of any length (Whisper runs its own 30 s windows), but accuracy drops pastModel::max_audio_ms. Split longer audio at pauses, transcribe the pieces and shift their tokens’start_msby each piece’s offset, aswavo rundoes insrc/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§
- hub
hub - Download and manage the supported models in the Hugging Face cache (the
hubfeature).
Structs§
- Device
- The GPU a
Modelruns on, and the graphics API it reaches it through, as the driver reports them when the model loads. SeeModel::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
Deviceis reached through. - Device
Kind - The kind of adapter a
Deviceis, as the driver reports it. - Error
- Everything that can fail in wavo: loading a model, running it on the GPU and, with the
hubfeature, managing downloads.