Files
sherpa-onnx/rust-api-examples/examples/sense_voice.rs
T
Fangjun Kuang 66c722584e 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.
2026-02-24 18:31:29 +08:00

114 lines
3.6 KiB
Rust

// Copyright (c) 2026 Xiaomi Corporation
//
// This file demonstrates how to use SenseVoice 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, OfflineSenseVoiceModelConfig, Wave};
use std::time::Instant;
/// SenseVoice offline example
#[derive(Parser, Debug)]
#[command(author, version, about, long_about = None)]
struct Args {
/// Path to WAV file
#[arg(long)]
wav: String,
/// Path to SenseVoice ONNX model
#[arg(long)]
model: String,
/// Path to tokens file
#[arg(long)]
tokens: String,
/// Language, e.g., "auto", "en", "zh"
#[arg(long, default_value = "auto")]
language: String,
/// Provider (default: cpu)
#[arg(long, default_value = "cpu")]
provider: String,
/// Enable debug logs
#[arg(long, default_value_t = false)]
debug: bool,
/// 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() {
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;
let mut recognizer_config = OfflineRecognizerConfig::default();
recognizer_config.model_config.sense_voice = OfflineSenseVoiceModelConfig {
model: Some(args.model.clone()),
language: Some(args.language.clone()),
use_itn: args.use_itn,
};
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_time = 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_time);
// Detailed RTF computation log
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");
}
}