Add a Whisper example for the Rust API (#3661)

This commit is contained in:
SourMay authored and GitHub committed 2026-06-06 11:31:25 +08:00
1 parent f2991e2e36
commit 6a9965eedf
4 files changed
+145

No files matched your search

+1
View File
@@ -67,6 +67,7 @@ rm -rf sherpa-onnx-online-punct-*
rm -rf sherpa-onnx-kws-zipformer-wenetspeech-3.3M-2024-01-01-mobile
./run-spoken-language-identification.sh
./run-whisper.sh
rm -rf sherpa-onnx-whisper-tiny spoken-language-identification-test-wavs
./run-offline-punctuation.sh
+7
View File
@@ -90,6 +90,7 @@ in your own Cargo project, see
| 45 | [zipformer_transducer_simulate_streaming_microphone](#example-45-simulated-streaming-asr-with-zipformer-transducer-and-vad-from-microphone) | Simulated streaming ASR with Zipformer transducer and VAD from microphone |
| 46 | [zipformer_transducer_simulate_streaming_microphone](#example-46-simulated-streaming-asr-with-zipformer-transducer-japanese-and-vad-from-microphone) | Simulated streaming ASR with Zipformer transducer (Japanese) and VAD from microphone |
| 47 | [qwen3_asr_simulate_streaming_microphone](#example-47-simulated-streaming-asr-with-qwen3-asr-and-vad-from-microphone) | Simulated streaming ASR with Qwen3 ASR and VAD from microphone |
| 48 | [whisper](#example-48-asr-with-non-streaming-whisper) | Non-streaming ASR with Whisper (multilingual) |
## Run it
@@ -415,3 +416,9 @@ Qwen3 ASR recognizer on each detected segment.
```bash
./run-qwen3-asr-simulate-streaming-microphone.sh
```
### Example 48: ASR with non-streaming Whisper
```bash
./run-whisper.sh
```
+119
View File
@@ -0,0 +1,119 @@
// Copyright (c) 2026 Yujie Wu
//
// This file demonstrates how to use Whisper with sherpa-onnx's Rust API
// for offline speech recognition.
//
// See ../README.md for how to run it.
use clap::Parser;
use sherpa_onnx::{OfflineRecognizer, OfflineRecognizerConfig, OfflineWhisperModelConfig, Wave};
use std::time::Instant;
/// Whisper offline ASR example
#[derive(Parser, Debug)]
#[command(author, version, about, long_about = None)]
struct Args {
/// Path to encoder ONNX model
#[arg(long)]
encoder: String,
/// Path to decoder ONNX model
#[arg(long)]
decoder: String,
/// Path to tokens file
#[arg(long)]
tokens: String,
/// Path to input WAV file
#[arg(long)]
wav: String,
/// Recognition language, e.g. "en", "zh". Leave empty for auto-detection
#[arg(long, default_value = "")]
language: String,
/// Task type: "transcribe" or "translate" (translate to English)
#[arg(long, default_value = "transcribe")]
task: String,
/// Provider (default: cpu)
#[arg(long, default_value = "cpu")]
provider: String,
/// Enable debug logs
#[arg(long, default_value_t = false)]
debug: bool,
/// Number of threads
#[arg(long, default_value_t = 2)]
num_threads: i32,
}
fn main() {
let args = Args::parse();
let wave = Wave::read(&args.wav).expect("Failed to read WAV file");
let audio_duration = wave.samples().len() as f64 / wave.sample_rate() as f64;
// Create default recognizer config
let mut recognizer_config = OfflineRecognizerConfig::default();
// Set the Whisper model
recognizer_config.model_config.whisper = OfflineWhisperModelConfig {
encoder: Some(args.encoder.clone()),
decoder: Some(args.decoder.clone()),
language: Some(args.language.clone()),
task: Some(args.task.clone()),
tail_paddings: 0,
enable_token_timestamps: false,
enable_segment_timestamps: false,
};
recognizer_config.model_config.tokens = Some(args.tokens.clone());
recognizer_config.model_config.provider = Some(args.provider.clone());
recognizer_config.model_config.debug = args.debug;
recognizer_config.model_config.num_threads = args.num_threads;
// Measure recognizer creation time
println!("Creating recognizer ...");
let start_creation = Instant::now();
let recognizer =
OfflineRecognizer::create(&recognizer_config).expect("Failed to create OfflineRecognizer");
let creation_elapsed = start_creation.elapsed().as_secs_f64();
println!("Recognizer created in {:.3} seconds.", creation_elapsed);
let stream = recognizer.create_stream();
// Measure recognition time
let start_recognition = Instant::now();
stream.accept_waveform(wave.sample_rate(), wave.samples());
recognizer.decode(&stream);
let recognition_elapsed = start_recognition.elapsed().as_secs_f64();
// Get recognition result
if let Some(result) = stream.get_result() {
println!("Decoded text: {}", result.text);
let total_elapsed = creation_elapsed + recognition_elapsed;
let rtf = recognition_elapsed / audio_duration;
println!("\n=== Performance Summary ===");
println!("Audio duration : {:.3} seconds", audio_duration);
println!("Recognizer creation time: {:.3} seconds", creation_elapsed);
println!(
"Recognition time : {:.3} seconds",
recognition_elapsed
);
println!("Total elapsed time : {:.3} seconds", total_elapsed);
println!(
"Real-Time Factor (RTF) : {:.3} (recognition_elapsed / audio_duration = {:.3} / {:.3})",
rtf, recognition_elapsed, audio_duration
);
println!(
"Number of threads : {}",
recognizer_config.model_config.num_threads
);
} else {
eprintln!("Failed to get recognition result");
}
}
+18
View File
@@ -0,0 +1,18 @@
#!/usr/bin/env bash
set -ex
# see
# https://github.com/k2-fsa/sherpa-onnx/releases/tag/asr-models
if [ ! -f ./sherpa-onnx-whisper-tiny/tiny-encoder.onnx ]; then
curl -SL -O https://github.com/k2-fsa/sherpa-onnx/releases/download/asr-models/sherpa-onnx-whisper-tiny.tar.bz2
tar xvf sherpa-onnx-whisper-tiny.tar.bz2
rm sherpa-onnx-whisper-tiny.tar.bz2
fi
cargo run --example whisper -- \
--wav ./sherpa-onnx-whisper-tiny/test_wavs/0.wav \
--encoder ./sherpa-onnx-whisper-tiny/tiny-encoder.onnx \
--decoder ./sherpa-onnx-whisper-tiny/tiny-decoder.onnx \
--tokens ./sherpa-onnx-whisper-tiny/tiny-tokens.txt \
--language en \
--num-threads 2