Add more examples for offline ASR models with Rust API. (#3209)

This PR adds additional Rust API examples for offline ASR (Automatic Speech Recognition) models, expanding coverage to include Nemo Parakeet, Zipformer variants for different languages (Vietnamese, Chinese-English, English), and updates configuration options.
This commit is contained in:
Fangjun Kuang authored and GitHub committed 2026-02-24 18:31:29 +08:00
1 parent 5570bac3cf
commit 66c722584e
9 files changed
+217 -2

No files matched your search

+5
View File
@@ -6,6 +6,11 @@ cd rust-api-examples
./run-version.sh
./run-nemo-parakeet-en.sh
./run-zipformer-vi.sh
./run-zipformer-zh-en.sh
./run-zipformer-en.sh
./run-sense-voice.sh
./run-streaming-zipformer-en.sh
+114
View File
@@ -0,0 +1,114 @@
// Copyright (c) 2026 Xiaomi Corporation
//
// This file demonstrates how to use Nemo Parakeet 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, OfflineTransducerModelConfig, Wave};
use std::time::Instant;
/// Nemo Parakeet offline example
#[derive(Parser, Debug)]
#[command(author, version, about, long_about = None)]
struct Args {
/// Path to WAV file
#[arg(long)]
wav: String,
/// Path to encoder ONNX model
#[arg(long)]
encoder: String,
/// Path to decoder ONNX model
#[arg(long)]
decoder: String,
/// Path to joiner ONNX model
#[arg(long)]
joiner: String,
/// Path to tokens file
#[arg(long)]
tokens: 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 transducer model
recognizer_config.model_config.transducer = OfflineTransducerModelConfig {
encoder: Some(args.encoder.clone()),
decoder: Some(args.decoder.clone()),
joiner: Some(args.joiner.clone()),
};
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");
}
}
+5 -1
View File
@@ -40,6 +40,10 @@ struct Args {
/// Enable inverse text normalization
#[arg(long, default_value_t = true)]
use_itn: bool,
/// Number of threads
#[arg(long, default_value_t = 2)]
num_threads: i32,
}
fn main() {
@@ -59,7 +63,7 @@ fn main() {
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 = 2;
recognizer_config.model_config.num_threads = args.num_threads;
// Measure recognizer creation time
println!("Creating recognizer ...");
+1
View File
@@ -0,0 +1 @@
nemo_parakeet.rs
+22
View File
@@ -0,0 +1,22 @@
#!/usr/bin/env bash
set -ex
# See also
# https://k2-fsa.github.io/sherpa/onnx/pretrained_models/offline-transducer/nemo-transducer-models.html#sherpa-onnx-nemo-parakeet-tdt-0-6b-v2-int8-english
if [ ! -f "./sherpa-onnx-nemo-parakeet-tdt-0.6b-v2-int8/encoder.int8.onnx" ]; then
curl -SL -O https://github.com/k2-fsa/sherpa-onnx/releases/download/asr-models/sherpa-onnx-nemo-parakeet-tdt-0.6b-v2-int8.tar.bz2
tar xvf sherpa-onnx-nemo-parakeet-tdt-0.6b-v2-int8.tar.bz2
rm sherpa-onnx-nemo-parakeet-tdt-0.6b-v2-int8.tar.bz2
ls -lh sherpa-onnx-nemo-parakeet-tdt-0.6b-v2-int8
fi
# Run Rust Nemo Parakeet example
cargo run --example nemo_parakeet -- \
--wav "./sherpa-onnx-nemo-parakeet-tdt-0.6b-v2-int8/test_wavs/0.wav" \
--encoder "./sherpa-onnx-nemo-parakeet-tdt-0.6b-v2-int8/encoder.int8.onnx" \
--decoder "./sherpa-onnx-nemo-parakeet-tdt-0.6b-v2-int8/decoder.int8.onnx" \
--joiner "./sherpa-onnx-nemo-parakeet-tdt-0.6b-v2-int8/joiner.int8.onnx" \
--tokens "./sherpa-onnx-nemo-parakeet-tdt-0.6b-v2-int8/tokens.txt" \
--provider cpu \
--num-threads 2 \
--debug
+3 -1
View File
@@ -14,4 +14,6 @@ fi
cargo run --example sense_voice -- \
--wav ./sherpa-onnx-sense-voice-zh-en-ja-ko-yue-int8-2024-07-17/test_wavs/en.wav \
--model ./sherpa-onnx-sense-voice-zh-en-ja-ko-yue-int8-2024-07-17/model.int8.onnx \
--tokens ./sherpa-onnx-sense-voice-zh-en-ja-ko-yue-int8-2024-07-17/tokens.txt
--tokens ./sherpa-onnx-sense-voice-zh-en-ja-ko-yue-int8-2024-07-17/tokens.txt \
--num-threads 2 \
--debug
+23
View File
@@ -0,0 +1,23 @@
#!/usr/bin/env bash
set -ex
# see also
# https://k2-fsa.github.io/sherpa/onnx/pretrained_models/offline-transducer/zipformer-transducer-models.html#icefall-asr-multidataset-pruned-transducer-stateless7-2023-05-04-english
if [ ! -f "./icefall-asr-multidataset-pruned_transducer_stateless7-2023-05-04/data/lang_bpe_500/tokens.txt" ]; then
curl -SL -O https://github.com/k2-fsa/sherpa-onnx/releases/download/asr-models/icefall-asr-multidataset-pruned_transducer_stateless7-2023-05-04.tar.bz2
tar xvf icefall-asr-multidataset-pruned_transducer_stateless7-2023-05-04.tar.bz2
rm icefall-asr-multidataset-pruned_transducer_stateless7-2023-05-04.tar.bz2
ls -lh icefall-asr-multidataset-pruned_transducer_stateless7-2023-05-04
fi
# Run Zipformer transducer
cargo run --example zipformer -- \
--wav "./icefall-asr-multidataset-pruned_transducer_stateless7-2023-05-04/test_wavs/1089-134686-0001.wav" \
--tokens=./icefall-asr-multidataset-pruned_transducer_stateless7-2023-05-04/data/lang_bpe_500/tokens.txt \
--encoder=./icefall-asr-multidataset-pruned_transducer_stateless7-2023-05-04/exp/encoder-epoch-30-avg-4.int8.onnx \
--decoder=./icefall-asr-multidataset-pruned_transducer_stateless7-2023-05-04/exp/decoder-epoch-30-avg-4.onnx \
--joiner=./icefall-asr-multidataset-pruned_transducer_stateless7-2023-05-04/exp/joiner-epoch-30-avg-4.int8.onnx \
--provider cpu \
--num-threads 2 \
--debug
+22
View File
@@ -0,0 +1,22 @@
#!/usr/bin/env bash
set -ex
# see also
# https://k2-fsa.github.io/sherpa/onnx/pretrained_models/offline-transducer/zipformer-transducer-models.html#sherpa-onnx-zipformer-vi-30m-int8-2026-02-09-vietnamese
if [ ! -f "./sherpa-onnx-zipformer-vi-30M-int8-2026-02-09/encoder.int8.onnx" ]; then
curl -SL -O https://github.com/k2-fsa/sherpa-onnx/releases/download/asr-models/sherpa-onnx-zipformer-vi-30M-int8-2026-02-09.tar.bz2
tar xvf sherpa-onnx-zipformer-vi-30M-int8-2026-02-09.tar.bz2
rm sherpa-onnx-zipformer-vi-30M-int8-2026-02-09.tar.bz2
ls -lh sherpa-onnx-zipformer-vi-30M-int8-2026-02-09
fi
# Run Zipformer transducer
cargo run --example zipformer -- \
--wav "./sherpa-onnx-zipformer-vi-30M-int8-2026-02-09/test_wavs/0.wav" \
--encoder "./sherpa-onnx-zipformer-vi-30M-int8-2026-02-09/encoder.int8.onnx" \
--decoder "./sherpa-onnx-zipformer-vi-30M-int8-2026-02-09/decoder.onnx" \
--joiner "./sherpa-onnx-zipformer-vi-30M-int8-2026-02-09/joiner.int8.onnx" \
--tokens "./sherpa-onnx-zipformer-vi-30M-int8-2026-02-09/tokens.txt" \
--provider cpu \
--num-threads 2 \
--debug
+22
View File
@@ -0,0 +1,22 @@
#!/usr/bin/env bash
set -ex
# see also
# https://k2-fsa.github.io/sherpa/onnx/pretrained_models/offline-transducer/zipformer-transducer-models.html#sherpa-onnx-zipformer-zh-en-2023-11-22-chinese-english
if [ ! -f "./sherpa-onnx-zipformer-zh-en-2023-11-22/encoder-epoch-34-avg-19.int8.onnx" ]; then
curl -SL -O https://github.com/k2-fsa/sherpa-onnx/releases/download/asr-models/sherpa-onnx-zipformer-zh-en-2023-11-22.tar.bz2
tar xvf sherpa-onnx-zipformer-zh-en-2023-11-22.tar.bz2
rm sherpa-onnx-zipformer-zh-en-2023-11-22.tar.bz2
ls -lh sherpa-onnx-zipformer-zh-en-2023-11-22
fi
# Run Zipformer transducer
cargo run --example zipformer -- \
--wav "./sherpa-onnx-zipformer-zh-en-2023-11-22/test_wavs/0.wav" \
--encoder "./sherpa-onnx-zipformer-zh-en-2023-11-22/encoder-epoch-34-avg-19.int8.onnx" \
--decoder "./sherpa-onnx-zipformer-zh-en-2023-11-22/decoder-epoch-34-avg-19.onnx" \
--joiner "./sherpa-onnx-zipformer-zh-en-2023-11-22/joiner-epoch-34-avg-19.int8.onnx" \
--tokens "./sherpa-onnx-zipformer-zh-en-2023-11-22/tokens.txt" \
--provider cpu \
--num-threads 2 \
--debug