Files
sherpa-onnx/rust-api-examples/examples/qwen3_asr.rs
T
Fangjun Kuang 7d42579edc Add Rust API for Qwen3 ASR (#3423)
This pull request expands the Rust API by integrating support for Qwen3 Automatic Speech Recognition (ASR). It provides developers with new capabilities to perform both offline and simulated streaming speech recognition using the Qwen3 model, complete with practical examples and necessary infrastructure updates. This enhancement broadens the range of ASR models available through the Rust API.
2026-03-26 19:14:01 +08:00

118 lines
3.6 KiB
Rust

// Copyright (c) 2026 Xiaomi Corporation
//
// This file demonstrates how to use Qwen3 ASR with sherpa-onnx's Rust API
// for offline speech recognition.
//
// See ../README.md for how to run it.
use clap::Parser;
use sherpa_onnx::{
OfflineQwen3ASRModelConfig, OfflineRecognizer, OfflineRecognizerConfig, Wave,
};
use std::time::Instant;
/// Qwen3 ASR offline example
#[derive(Parser, Debug)]
#[command(author, version, about, long_about = None)]
struct Args {
/// Path to WAV file
#[arg(long)]
wav: String,
/// Path to conv_frontend ONNX model
#[arg(long)]
conv_frontend: String,
/// Path to encoder ONNX model
#[arg(long)]
encoder: String,
/// Path to decoder ONNX model
#[arg(long)]
decoder: String,
/// Path to tokenizer directory
#[arg(long)]
tokenizer: 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;
let mut recognizer_config = OfflineRecognizerConfig::default();
recognizer_config.model_config.qwen3_asr = OfflineQwen3ASRModelConfig {
conv_frontend: Some(args.conv_frontend.clone()),
encoder: Some(args.encoder.clone()),
decoder: Some(args.decoder.clone()),
tokenizer: Some(args.tokenizer.clone()),
..Default::default()
};
recognizer_config.model_config.tokens = Some(String::new());
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");
}
}