From 91346db841eba23362dc6cf21b4f6ae9d91a0d36 Mon Sep 17 00:00:00 2001 From: nati2405 Date: Mon, 22 Jun 2026 01:44:39 -0400 Subject: [PATCH 1/6] Add Paraformer Rust API example --- rust-api-examples/examples/paraformer.rs | 100 +++++++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 rust-api-examples/examples/paraformer.rs diff --git a/rust-api-examples/examples/paraformer.rs b/rust-api-examples/examples/paraformer.rs new file mode 100644 index 0000000000..fed4865be9 --- /dev/null +++ b/rust-api-examples/examples/paraformer.rs @@ -0,0 +1,100 @@ +// Copyright (c) 2026 Xiaomi Corporation +// +// This file demonstrates how to use non-streaming Paraformer with +// sherpa-onnx's Rust API for offline speech recognition. +// +// See ../README.md for how to run it. + +use clap::Parser; +use sherpa_onnx::{ + OfflineParaformerModelConfig, OfflineRecognizer, OfflineRecognizerConfig, Wave, +}; +use std::time::Instant; + +/// Paraformer offline ASR example +#[derive(Parser, Debug)] +#[command(author, version, about, long_about = None)] +struct Args { + /// Path to WAV file + #[arg(long)] + wav: String, + + /// Path to Paraformer ONNX model + #[arg(long)] + model: 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; + + let mut recognizer_config = OfflineRecognizerConfig::default(); + + recognizer_config.model_config.paraformer = OfflineParaformerModelConfig { + model: Some(args.model.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; + + 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(); + + 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(); + + 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); + 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"); + } +} \ No newline at end of file From 2952bff957bc45a0fb872b67a34a2ee2a591321d Mon Sep 17 00:00:00 2001 From: nati2405 Date: Mon, 22 Jun 2026 02:07:55 -0400 Subject: [PATCH 2/6] Add Paraformer Rust example script --- rust-api-examples/run-paraformer.sh | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 rust-api-examples/run-paraformer.sh diff --git a/rust-api-examples/run-paraformer.sh b/rust-api-examples/run-paraformer.sh new file mode 100644 index 0000000000..cd106a7c9e --- /dev/null +++ b/rust-api-examples/run-paraformer.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash + +set -ex + +repo_url=https://github.com/k2-fsa/sherpa-onnx/releases/download/asr-models +model=sherpa-onnx-paraformer-zh-small-2024-03-09 + +if [ ! -d $model ]; then + wget $repo_url/$model.tar.bz2 + tar xvf $model.tar.bz2 + rm $model.tar.bz2 +fi + +cargo run --example paraformer -- \ + --model ./$model/model.int8.onnx \ + --tokens ./$model/tokens.txt \ + --wav ./$model/test_wavs/0.wav \ No newline at end of file From f09ebe565778db5a5502ec0b4ada1ebd54beca64 Mon Sep 17 00:00:00 2001 From: nati2405 Date: Mon, 29 Jun 2026 00:17:27 -0400 Subject: [PATCH 3/6] Make Paraformer run script executable --- rust-api-examples/run-paraformer.sh | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 rust-api-examples/run-paraformer.sh diff --git a/rust-api-examples/run-paraformer.sh b/rust-api-examples/run-paraformer.sh old mode 100644 new mode 100755 From 026c6ae95fcf9af22f0cd10dce39771c5e7b33fb Mon Sep 17 00:00:00 2001 From: nati2405 Date: Fri, 24 Jul 2026 18:43:40 -0400 Subject: [PATCH 4/6] Address review feedback for Paraformer example --- .github/scripts/test-rust.sh | 3 +++ rust-api-examples/README.md | 7 ++++-- rust-api-examples/examples/paraformer.rs | 22 ++++++++++++------ rust-api-examples/run-paraformer.sh | 29 ++++++++++++++++++------ 4 files changed, 45 insertions(+), 16 deletions(-) diff --git a/.github/scripts/test-rust.sh b/.github/scripts/test-rust.sh index bfc9d39155..8da649a268 100755 --- a/.github/scripts/test-rust.sh +++ b/.github/scripts/test-rust.sh @@ -82,6 +82,9 @@ rm -rf sherpa-onnx-punct-ct-transformer-zh-en-vocab272727-2024-04-12-int8 ./run-fire-red-asr-ctc.sh +./run-paraformer.sh +rm -rf sherpa-onnx-paraformer-zh-small-2024-03-09 + ./run-silero-vad-remove-silence.sh ./run-ten-vad-remove-silence.sh diff --git a/rust-api-examples/README.md b/rust-api-examples/README.md index d7c33aaf47..56105189c5 100644 --- a/rust-api-examples/README.md +++ b/rust-api-examples/README.md @@ -91,8 +91,6 @@ in your own Cargo project, see | 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) | -| 49 | [funasr_nano](#example-49-asr-with-non-streaming-funasr-nano) | Non-streaming ASR with FunASR Nano | -| 50 | [ten_vad_remove_silence](#example-50-remove-silences-from-a-file-using-ten-vad) | Remove silences from an audio file using ten-vad | ## Run it @@ -436,3 +434,8 @@ Qwen3 ASR recognizer on each detected segment. ```bash ./run-ten-vad-remove-silence.sh ``` + +### Example 49: ASR with non-streaming Paraformer + +```bash +./run-paraformer.sh \ No newline at end of file diff --git a/rust-api-examples/examples/paraformer.rs b/rust-api-examples/examples/paraformer.rs index fed4865be9..37cb1e3993 100644 --- a/rust-api-examples/examples/paraformer.rs +++ b/rust-api-examples/examples/paraformer.rs @@ -1,15 +1,14 @@ -// Copyright (c) 2026 Xiaomi Corporation -// -// This file demonstrates how to use non-streaming Paraformer with +// This example demonstrates how to use non-streaming Paraformer with // sherpa-onnx's Rust API for offline speech recognition. // -// See ../README.md for how to run it. +// Run it from the rust-api-examples directory with: +// ./run-paraformer.sh use clap::Parser; use sherpa_onnx::{ OfflineParaformerModelConfig, OfflineRecognizer, OfflineRecognizerConfig, Wave, }; -use std::time::Instant; +use std::{process, time::Instant}; /// Paraformer offline ASR example #[derive(Parser, Debug)] @@ -44,7 +43,11 @@ 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 audio_duration = if wave.sample_rate() > 0 && !wave.samples().is_empty() { + wave.samples().len() as f64 / wave.sample_rate() as f64 + } else { + 0.0 + }; let mut recognizer_config = OfflineRecognizerConfig::default(); @@ -79,7 +82,11 @@ fn main() { println!("Decoded text: {}", result.text); let total_time = creation_elapsed + recognition_elapsed; - let rtf = recognition_elapsed / audio_duration; + let rtf = if audio_duration > 0.0 { + recognition_elapsed / audio_duration + } else { + 0.0 + }; println!("\n=== Performance Summary ==="); println!("Audio duration : {:.3} seconds", audio_duration); @@ -96,5 +103,6 @@ fn main() { ); } else { eprintln!("Failed to get recognition result"); + process::exit(1); } } \ No newline at end of file diff --git a/rust-api-examples/run-paraformer.sh b/rust-api-examples/run-paraformer.sh index cd106a7c9e..40155c1a5c 100755 --- a/rust-api-examples/run-paraformer.sh +++ b/rust-api-examples/run-paraformer.sh @@ -2,16 +2,31 @@ set -ex +script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +cd "$script_dir" + repo_url=https://github.com/k2-fsa/sherpa-onnx/releases/download/asr-models model=sherpa-onnx-paraformer-zh-small-2024-03-09 +archive=$model.tar.bz2 + +model_dir="$script_dir/$model" +archive_path="$script_dir/$archive" + +if [ ! -d "$model_dir" ]; then + if command -v wget >/dev/null 2>&1; then + wget -O "$archive_path" "$repo_url/$archive" + elif command -v curl >/dev/null 2>&1; then + curl -L -o "$archive_path" "$repo_url/$archive" + else + echo "Error: Neither wget nor curl found. Please install one of them." + exit 1 + fi -if [ ! -d $model ]; then - wget $repo_url/$model.tar.bz2 - tar xvf $model.tar.bz2 - rm $model.tar.bz2 + tar xvf "$archive_path" -C "$script_dir" + rm "$archive_path" fi cargo run --example paraformer -- \ - --model ./$model/model.int8.onnx \ - --tokens ./$model/tokens.txt \ - --wav ./$model/test_wavs/0.wav \ No newline at end of file + --model "$model_dir/model.int8.onnx" \ + --tokens "$model_dir/tokens.txt" \ + --wav "$model_dir/test_wavs/0.wav" \ No newline at end of file From ed767b96e4e687e762c871c3675e589f1a9ca466 Mon Sep 17 00:00:00 2001 From: nati2405 Date: Fri, 24 Jul 2026 19:49:42 -0400 Subject: [PATCH 5/6] Fix README markdown formatting --- rust-api-examples/README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/rust-api-examples/README.md b/rust-api-examples/README.md index 56105189c5..3e5bed4584 100644 --- a/rust-api-examples/README.md +++ b/rust-api-examples/README.md @@ -91,6 +91,10 @@ in your own Cargo project, see | 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) | +<<<<<<< HEAD +======= +| 51 | [paraformer](#example-49-asr-with-non-streaming-paraformer) | Non-streaming ASR with Paraformer | +>>>>>>> ac045c4f (Fix README markdown formatting) ## Run it @@ -435,7 +439,7 @@ Qwen3 ASR recognizer on each detected segment. ./run-ten-vad-remove-silence.sh ``` -### Example 49: ASR with non-streaming Paraformer +### Example 51: ASR with non-streaming Paraformer ```bash ./run-paraformer.sh \ No newline at end of file From da4f4a22afae574aa49f8db451c2d29d797a2f3b Mon Sep 17 00:00:00 2001 From: nati2405 Date: Mon, 27 Jul 2026 19:02:28 -0400 Subject: [PATCH 6/6] Fix README Paraformer table entry --- rust-api-examples/README.md | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/rust-api-examples/README.md b/rust-api-examples/README.md index 3e5bed4584..5917ad5c5b 100644 --- a/rust-api-examples/README.md +++ b/rust-api-examples/README.md @@ -91,10 +91,7 @@ in your own Cargo project, see | 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) | -<<<<<<< HEAD -======= -| 51 | [paraformer](#example-49-asr-with-non-streaming-paraformer) | Non-streaming ASR with Paraformer | ->>>>>>> ac045c4f (Fix README markdown formatting) +| 51 | [paraformer](#example-51-asr-with-non-streaming-paraformer) | Non-streaming ASR with Paraformer | ## Run it