Skip to content

Add support for Meta Omnilingual ASR v2 models - #3138

Merged
csukuangfj merged 1 commit into
k2-fsa:masterfrom
Edison2ST:add-omnilingual-v2
Feb 5, 2026
Merged

csukuangfj merged 1 commit into
k2-fsa:masterfrom
Edison2ST:add-omnilingual-v2

Conversation

@Edison2ST

@Edison2ST Edison2ST commented Feb 5, 2026 •

Copy link
Copy Markdown
Contributor

Description

This model uses the existing CTC architecture, so no changes to the C++ core or CMakeLists are required. It is fully compatible with the current implementation. The only difference: going from Omnilingual v1 to Omnilingual v2 (December 2025 update).

Tested it on Python and with sherpa-onnx-offline, it works.

This is my first PR to the project, so please let me know if I've missed any specific formatting or project conventions!

Model Source

https://huggingface.co/Edison2ST/sherpa-onnx-omnilingual-asr-1600-languages-ctc-v2

4-bit Quantization (MatMulNBits) Investigation

I have also developed a quantization pipeline for these V2 models using MatMulNBits (4-bit). Used block_size=32 (due to the 128-bit registers and it aligns with the cache line and SIMD processing of 4-bit values) and is_symmetric=True to balance accuracy and performance on consumer CPUs/ARM, and the script bypasses an AssertionError in _infer_Reshape.

I didn't include these models because I'm leading with the INT8 version to match the current project standards for accuracy (they're not on the v1 nor saw any Q4 model on releases). Would you be interested in these Q4 versions to further reduce the memory footprint for mobile/edge deployments?

The 300M model had low CER (1.77%) against clean LibriSpeech and 0.5x RTF on a Dimensity 6300. And more importantly, it doesn't break the C++ core at all. The 1B Q4 model is about 641 MB (ONNX file), so roughly 30% reduction.

Note: I measured it using a logit mask to constrain decoding to the English alphabet/space tokens, demonstrating high stability for English-specific tasks. But it seems to be good in other languages as well, I just haven't benchmarked it.

Bash

300M, int8, AMD Ryzen 7 7435HS. RTF 0.111.

Click to expand full bash logs (Note: show some encoding artifacts due to Windows console environment)
sherpa-onnx-offline --omnilingual-asr-model=model.int8.onnx --tokens=tokens.txt --num-threads=4 ./test_wavs/de.wav ./test_wavs/en.wav ./test_wavs/es.wav ./test_wavs/fr.wav
D:\a\sherpa-onnx\sherpa-onnx\sherpa-onnx\csrc\parse-options.cc:Read:373 sherpa-onnx-offline --omnilingual-asr-model=model.int8.onnx --tokens=tokens.txt --num-threads=4 ./test_wavs/de.wav ./test_wavs/en.wav ./test_wavs/es.wav ./test_wavs/fr.wav

OfflineRecognizerConfig(feat_config=FeatureExtractorConfig(sampling_rate=16000, feature_dim=80, low_freq=20, high_freq=-400, dither=0, normalize_samples=True, snip_edges=False), model_config=OfflineModelConfig(transducer=OfflineTransducerModelConfig(encoder_filename="", decoder_filename="", joiner_filename=""), paraformer=OfflineParaformerModelConfig(model=""), nemo_ctc=OfflineNemoEncDecCtcModelConfig(model=""), whisper=OfflineWhisperModelConfig(encoder="", decoder="", language="", task="transcribe", tail_paddings=-1), fire_red_asr=OfflineFireRedAsrModelConfig(encoder="", decoder=""), tdnn=OfflineTdnnModelConfig(model=""), zipformer_ctc=OfflineZipformerCtcModelConfig(model=""), wenet_ctc=OfflineWenetCtcModelConfig(model=""), sense_voice=OfflineSenseVoiceModelConfig(model="", language="auto", use_itn=False), moonshine=OfflineMoonshineModelConfig(preprocessor="", encoder="", uncached_decoder="", cached_decoder=""), dolphin=OfflineDolphinModelConfig(model=""), canary=OfflineCanaryModelConfig(encoder="", decoder="", src_lang="", tgt_lang="", use_pnc=True), omnilingual=OfflineOmnilingualAsrCtcModelConfig(model="model.int8.onnx"), funasr_nano=OfflineFunASRNanoModelConfig(encoder_adaptor="", llm="", embedding="", tokenizer="", system_prompt="You are a helpful assistant.", user_prompt="Þ»¡Úƒ│Þ¢¼ÕåÖ´╝Ü", max_new_tokens=512, temperature=1e-06, top_p=0.8, seed=42), medasr=OfflineMedAsrCtcModelConfig(model=""), telespeech_ctc="", tokens="tokens.txt", num_threads=4, debug=False, provider="cpu", model_type="", modeling_unit="cjkchar", bpe_vocab=""), lm_config=OfflineLMConfig(model="", scale=0.5, lodr_scale=0.01, lodr_fst="", lodr_backoff_id=-1), ctc_fst_decoder_config=OfflineCtcFstDecoderConfig(graph="", max_active=3000), decoding_method="greedy_search", max_active_paths=4, hotwords_file="", hotwords_score=1.5, blank_penalty=0, rule_fsts="", rule_fars="", hr=HomophoneReplacerConfig(lexicon="", rule_fsts=""))
Creating recognizer ...
recognizer created in 0.713 s
Started
D:\a\sherpa-onnx\sherpa-onnx\sherpa-onnx\csrc\offline-stream.cc:AcceptWaveformImpl:133 Creating a resampler:
   in_sample_rate: 22050
   output_sample_rate: 16000

D:\a\sherpa-onnx\sherpa-onnx\sherpa-onnx\csrc\offline-stream.cc:AcceptWaveformImpl:133 Creating a resampler:
   in_sample_rate: 24000
   output_sample_rate: 16000

D:\a\sherpa-onnx\sherpa-onnx\sherpa-onnx\csrc\offline-stream.cc:AcceptWaveformImpl:133 Creating a resampler:
   in_sample_rate: 22050
   output_sample_rate: 16000

D:\a\sherpa-onnx\sherpa-onnx\sherpa-onnx\csrc\offline-stream.cc:AcceptWaveformImpl:133 Creating a resampler:
   in_sample_rate: 22050
   output_sample_rate: 16000

Done!

./test_wavs/de.wav
{"lang": "", "emotion": "", "event": "", "text": "alles hat ein ende nur die wurst hat zwei", "timestamps": [0.08, 0.10, 0.16, 0.20, 0.28, 0.36, 0.38, 0.42, 0.50, 0.58, 0.64, 0.66, 0.70, 0.80, 0.86, 0.94, 1.00, 1.08, 1.28, 1.34, 1.38, 1.44, 1.52, 1.54, 1.60, 1.64, 1.68, 1.72, 1.78, 1.82, 1.90, 1.96, 1.98, 2.02, 2.06, 2.12, 2.20, 2.26, 2.34, 2.44, 2.52], "durations": [], "tokens":["a", "l", "l", "e", "s", " ", "h", "a", "t", " ", "e", "i", "n", " ", "e", "n", "d", "e", " ", "n", "u", "r", " ", "d", "i", "e", " ", "w", "u", "r", "s", "t", " ", "h", "a", "t", " ", "z", "w", "e", "i"], "ys_log_probs": [], "words": []}
----
./test_wavs/en.wav
{"lang": "", "emotion": "", "event": "", "text": "ask not what your country can do for you ask what you can do for your country", "timestamps": [0.16, 0.28, 0.34, 0.46, 0.50, 0.54, 0.58, 0.62, 0.64, 0.66, 0.68, 0.70, 0.74, 0.76, 0.80, 0.82, 0.84, 0.88, 0.94, 0.96, 0.98, 1.02, 1.06, 1.12, 1.16, 1.22, 1.28, 1.30, 1.36, 1.40, 1.44, 1.48, 1.56, 1.60, 1.64, 1.68, 1.72, 1.74, 1.78, 1.80, 2.04, 2.14, 2.26, 2.30, 2.40, 2.42, 2.46, 2.48, 2.50, 2.52, 2.56, 2.58, 2.60, 2.66, 2.70, 2.72, 2.76, 2.82, 2.86, 2.90, 2.98, 3.00, 3.04, 3.06, 3.10, 3.14, 3.16, 3.18, 3.20, 3.24, 3.30, 3.34, 3.36, 3.40, 3.46, 3.54, 3.60], "durations": [], "tokens":["a", "s", "k", " ", "n", "o", "t", " ", "w", "h", "a", "t", " ", "y", "o", "u", "r", " ", "c", "o", "u", "n", "t", "r", "y", " ", "c", "a", "n", " ", "d", "o", " ", "f", "o", "r", " ", "y", "o", "u", " ", "a", "s", "k", " ", "w", "h", "a", "t", " ", "y", "o", "u", " ", "c", "a", "n", " ", "d", "o", " ", "f", "o", "r", " ", "y", "o", "u", "r", " ", "c", "o", "u", "n", "t", "r", "y"], "ys_log_probs": [], "words": []}
----
./test_wavs/es.wav
{"lang": "", "emotion": "", "event": "", "text": "no preguntes que puede hacer tu país por ti pregunta que puedes hacer te un puerto país", "timestamps": [0.12, 0.16, 0.22, 0.26, 0.30, 0.34, 0.40, 0.46, 0.50, 0.56, 0.62, 0.70, 0.78, 0.84, 0.86, 0.90, 0.98, 1.02, 1.04, 1.10, 1.16, 1.20, 1.26, 1.28, 1.32, 1.36, 1.40, 1.46, 1.52, 1.56, 1.60, 1.68, 1.72, 1.78, 1.88, 1.96, 2.04, 2.08, 2.14, 2.20, 2.24, 2.30, 2.38, 2.72, 2.78, 2.82, 2.86, 2.92, 2.96, 3.02, 3.08, 3.14, 3.20, 3.24, 3.26, 3.30, 3.36, 3.40, 3.44, 3.46, 3.52, 3.56, 3.64, 3.66, 3.70, 3.74, 3.78, 3.84, 3.90, 3.96, 3.98, 4.04, 4.06, 4.10, 4.14, 4.18, 4.22, 4.26, 4.30, 4.36, 4.46, 4.54, 4.58, 4.66, 4.76, 4.88, 5.02], "durations": [], "tokens":["n", "o", " ", "p", "r", "e", "g", "u", "n", "t", "e", "s", " ", "q", "u", "e", " ", "p", "u", "e", "d", "e", " ", "h", "a", "c", "e", "r", " ", "t", "u", " ", "p", "a", "í", "s", " ", "p", "o", "r", " ", "t", "i", " ", "p", "r", "e", "g", "u", "n", "t", "a", " ", "q", "u", "e", " ", "p", "u", "e", "d", "e", "s", " ", "h", "a", "c", "e", "r", " ", "t", "e", " ", "u", "n", " ", "p", "u", "e", "r", "t", "o", " ", "p", "a", "í", "s"], "ys_log_probs": [], "words": []}
----
./test_wavs/fr.wav
{"lang": "", "emotion": "", "event": "", "text": "ne vous demandez pas ce que votre pays peut faire pour vous demandez-vous plut├┤t ce que vous pouvez faire pour lui", "timestamps": [0.12, 0.14, 0.18, 0.22, 0.24, 0.26, 0.28, 0.32, 0.36, 0.38, 0.44, 0.46, 0.48, 0.52, 0.58, 0.64, 0.68, 0.70, 0.72, 0.76, 0.78, 0.80, 0.82, 0.84, 0.88, 0.90, 0.92, 0.96, 1.00, 1.02, 1.08, 1.10, 1.14, 1.20, 1.22, 1.26, 1.34, 1.36, 1.40, 1.44, 1.48, 1.50, 1.54, 1.60, 1.66, 1.74, 1.76, 1.80, 1.84, 1.90, 1.94, 1.98, 2.00, 2.06, 2.14, 2.18, 2.20, 2.24, 2.26, 2.62, 2.70, 2.72, 2.80, 2.84, 2.88, 2.92, 2.98, 3.04, 3.06, 3.08, 3.10, 3.14, 3.16, 3.22, 3.26, 3.30, 3.34, 3.40, 3.46, 3.48, 3.52, 3.56, 3.60, 3.64, 3.68, 3.70, 3.72, 3.76, 3.80, 3.82, 3.84, 3.86, 3.90, 3.94, 3.96, 3.98, 4.02, 4.06, 4.14, 4.22, 4.26, 4.34, 4.36, 4.40, 4.44, 4.50, 4.54, 4.56, 4.58, 4.62, 4.68, 4.72, 4.76, 4.80], "durations": [], "tokens":["n", "e", " ", "v", "o", "u", "s", " ", "d", "e", "m", "a", "n", "d", "e", "z", " ", "p", "a", "s", " ", "c", "e", " ", "q", "u", "e", " ", "v", "o", "t", "r", "e", " ", "p", "a", "y", "s", " ", "p", "e", "u", "t", " ", "f", "a", "i", "r", "e", " ", "p", "o", "u", "r", " ", "v", "o", "u", "s", " ", "d", "e", "m", "a", "n", "d", "e", "z", "-", "v", "o", "u", "s", " ", "p", "l", "u", "t", "├┤", "t", " ", "c", "e", " ", "q", "u", "e", " ", "v", "o", "u", "s", " ", "p", "o", "u", "v", "e", "z", " ", "f", "a", "i", "r", "e", " ", "p", "o", "u", "r", " ", "l", "u", "i"], "ys_log_probs": [], "words": []}
----
num threads: 4
decoding method: greedy_search
Elapsed seconds: 1.876 s
Real time factor (RTF): 1.876 / 16.895 = 0.111

Summary by CodeRabbit

  • Documentation
    • Added example demonstrating offline Omnilingual ASR CTC v2 decoding with audio validation, single-file and batch processing capabilities, and performance metrics reporting.

@dosubot dosubot Bot added the size:L This PR changes 100-499 lines, ignoring generated files. label Feb 5, 2026
@gemini-code-assist

Copy link
Copy Markdown

Summary of Changes

Hello @Edison2ST, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request integrates support for the latest Meta Omnilingual ASR v2 models, enhancing the project's multilingual speech recognition capabilities without requiring modifications to the core C++ codebase. It introduces a dedicated Python example to facilitate usage and demonstrates the model's performance and compatibility.

Highlights

  • New Model Support: Adds support for Meta Omnilingual ASR v2 models, specifically the December 2025 update, which are fully compatible with the existing CTC architecture.
  • Core Compatibility: No changes to the C++ core or CMakeLists are required, as the new models utilize the existing CTC architecture.
  • New Example Script: A new Python example script (offline-omnilingual-asr-ctc-v2-decode-files.py) has been added to demonstrate how to use these new models for decoding audio files.
  • Quantization Investigation: The author investigated 4-bit quantization using MatMulNBits for these V2 models, noting significant memory reduction and good performance, but opted to include only the INT8 version in this PR to align with current project standards.
Changelog
  • python-api-examples/offline-omnilingual-asr-ctc-v2-decode-files.py
    • Added a new Python example script to demonstrate decoding with non-streaming Omnilingual ASR CTC v2 models.
Activity
  • The author, Edison2ST, has introduced support for Meta Omnilingual ASR v2 models, noting their compatibility with the existing CTC architecture.
  • Extensive testing was performed by the author on Python and with sherpa-onnx-offline, including detailed bash logs demonstrating multi-language transcription.
  • The author proactively investigated 4-bit quantization for these models, providing insights into potential future memory optimizations, though the INT8 version is included in this PR.
  • As a first-time contributor, the author has requested feedback on project conventions and formatting.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution. ↩

@coderabbitai

coderabbitai Bot commented Feb 5, 2026 •

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

A new Python example script is added that demonstrates non-streaming Omnilingual ASR CTC v2 decoding using sherpa-onnx, including functions for recognizer initialization, audio loading, single and batch file decoding, with timing metrics and error handling.

Changes

Cohort / File(s) Summary
Omnilingual ASR Decoding Example
python-api-examples/offline-omnilingual-asr-ctc-v2-decode-files.py
New example script with functions for creating an OfflineRecognizer, loading audio files with resampling, decoding single and multiple audio files, and reporting performance metrics (elapsed time, RTF). Includes validation of required model and token files with download guidance.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Suggested labels

size:M

Poem

🐰 Hark! A new example hops to life,
Decoding voices, sans the strife,
Audio files transcribed with cheer,
Omnilingual whispers crystal clear!
sherpa-onnx guides the way,
Performance metrics bright display! ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately reflects the main change: adding Python example scripts for Meta Omnilingual ASR v2 model support in sherpa-onnx.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request adds a Python example for the new Meta Omnilingual ASR v2 models. The changes are clear and the example is helpful. I've provided a few suggestions to improve code style and maintainability, mainly around refactoring hardcoded paths and adhering to standard Python import conventions. These changes will make the example script cleaner and more aligned with best practices. Great first contribution!

Comment on lines +27 to +32
model = "./sherpa-onnx-omnilingual-asr-1600-languages-300M-ctc-v2-int8-2026-02-05/model.int8.onnx"
tokens = "./sherpa-onnx-omnilingual-asr-1600-languages-300M-ctc-v2-int8-2026-02-05/tokens.txt"
test_wav_en = "./sherpa-onnx-omnilingual-asr-1600-languages-300M-ctc-v2-int8-2026-02-05/test_wavs/en.wav"
test_wav_de = "./sherpa-onnx-omnilingual-asr-1600-languages-300M-ctc-v2-int8-2026-02-05/test_wavs/de.wav"
test_wav_fr = "./sherpa-onnx-omnilingual-asr-1600-languages-300M-ctc-v2-int8-2026-02-05/test_wavs/fr.wav"
test_wav_es = "./sherpa-onnx-omnilingual-asr-1600-languages-300M-ctc-v2-int8-2026-02-05/test_wavs/es.wav"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The file paths for the model, tokens, and test waves are long and repetitive. To improve readability and maintainability, you can define a base directory path using pathlib.Path. This makes it easier to update the model version in the future.

Suggested change
model = "./sherpa-onnx-omnilingual-asr-1600-languages-300M-ctc-v2-int8-2026-02-05/model.int8.onnx"
tokens = "./sherpa-onnx-omnilingual-asr-1600-languages-300M-ctc-v2-int8-2026-02-05/tokens.txt"
test_wav_en = "./sherpa-onnx-omnilingual-asr-1600-languages-300M-ctc-v2-int8-2026-02-05/test_wavs/en.wav"
test_wav_de = "./sherpa-onnx-omnilingual-asr-1600-languages-300M-ctc-v2-int8-2026-02-05/test_wavs/de.wav"
test_wav_fr = "./sherpa-onnx-omnilingual-asr-1600-languages-300M-ctc-v2-int8-2026-02-05/test_wavs/fr.wav"
test_wav_es = "./sherpa-onnx-omnilingual-asr-1600-languages-300M-ctc-v2-int8-2026-02-05/test_wavs/es.wav"
repo_dir = Path("./sherpa-onnx-omnilingual-asr-1600-languages-300M-ctc-v2-int8-2026-02-05")
model = str(repo_dir / "model.int8.onnx")
tokens = str(repo_dir / "tokens.txt")
test_wav_en = str(repo_dir / "test_wavs/en.wav")
test_wav_de = str(repo_dir / "test_wavs/de.wav")
test_wav_fr = str(repo_dir / "test_wavs/fr.wav")
test_wav_es = str(repo_dir / "test_wavs/es.wav")

Comment on lines +38 to +40
raise ValueError("""Please download model files from
https://huggingface.co/Edison2ST/sherpa-onnx-omnilingual-asr-1600-languages-ctc-v2
""")

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The multi-line string for the error message includes leading whitespace from the source code indentation, which might not be intended. Using standard string literal concatenation results in a cleaner error message.

            raise ValueError(
                "Please download model files from "
                "https://huggingface.co/Edison2ST/sherpa-onnx-omnilingual-asr-1600-languages-ctc-v2"
            )

Comment on lines +57 to +60
if sample_rate != 16000:
import librosa

audio = librosa.resample(audio, orig_sr=sample_rate, target_sr=16000)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

According to PEP 8, imports should be at the top of the file. This makes dependencies clear and avoids re-importing librosa every time load_audio is called. Please move import librosa to the top of the script with the other imports.

    if sample_rate != 16000:
        audio = librosa.resample(audio, orig_sr=sample_rate, target_sr=16000)

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@python-api-examples/offline-omnilingual-asr-ctc-v2-decode-files.py`:
- Around line 65-85: The decode_single_file function can divide by zero when the
loaded audio has zero samples; modify decode_single_file to check samples (or
audio_duration) after load_audio and handle the empty case—e.g., if len(samples)
== 0: log/print a clear message including filename and return early (or set
audio_duration to a safe nonzero value) so computing real_time_factor =
elapsed_seconds / audio_duration and the formatted prints cannot raise
ZeroDivisionError; ensure the guard covers both the real_time_factor computation
and any prints that use audio_duration or derived values.
- Around line 88-119: The decode_multiple_files function can divide by zero if
audio_duration is 0 and should use strict zip to catch mismatched lists; update
decode_multiple_files to guard the real_time_factor calculation by checking if
audio_duration > 0 (or set real_time_factor to float("inf")/0.0-safe value)
before computing elapsed_seconds / audio_duration, and change the for loop that
iterates filenames and streams to use zip(filenames, streams, strict=True) so
length mismatches raise immediately; reference symbols: decode_multiple_files,
audio_duration, real_time_factor, filenames, streams, and the zip(...) call.

Comment on lines +65 to +85
def decode_single_file(recognizer, filename):
samples = load_audio(filename)

start_time = time.time()

stream = recognizer.create_stream()
stream.accept_waveform(sample_rate=16000, waveform=samples)
recognizer.decode_stream(stream)

end_time = time.time()
elapsed_seconds = end_time - start_time
audio_duration = len(samples) / 16000
real_time_factor = elapsed_seconds / audio_duration

print("---")
print(filename)
print(stream.result)
print(f"Elapsed seconds: {elapsed_seconds:.3f}")
print(f"Audio duration in seconds: {audio_duration:.3f}")
print(f"RTF: {elapsed_seconds:.3f}/{audio_duration:.3f} = {real_time_factor:.3f}")
print()

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Potential division by zero if audio file is empty.

If the audio file exists but contains no samples, audio_duration will be 0, causing a ZeroDivisionError on line 77. For an example script this is a minor edge case, but consider adding a guard.

🛡️ Suggested fix
     audio_duration = len(samples) / 16000
-    real_time_factor = elapsed_seconds / audio_duration
+    real_time_factor = elapsed_seconds / audio_duration if audio_duration > 0 else float('inf')
🤖 Prompt for AI Agents
In `@python-api-examples/offline-omnilingual-asr-ctc-v2-decode-files.py` around
lines 65 - 85, The decode_single_file function can divide by zero when the
loaded audio has zero samples; modify decode_single_file to check samples (or
audio_duration) after load_audio and handle the empty case—e.g., if len(samples)
== 0: log/print a clear message including filename and return early (or set
audio_duration to a safe nonzero value) so computing real_time_factor =
elapsed_seconds / audio_duration and the formatted prints cannot raise
ZeroDivisionError; ensure the guard covers both the real_time_factor computation
and any prints that use audio_duration or derived values.

Comment on lines +88 to +119
def decode_multiple_files(recognizer, filenames):
streams = []

start_time = time.time()

audio_duration = 0

for filename in filenames:
samples = load_audio(filename)
audio_duration += len(samples) / 16000

stream = recognizer.create_stream()
stream.accept_waveform(sample_rate=16000, waveform=samples)
streams.append(stream)

recognizer.decode_streams(streams)

end_time = time.time()
elapsed_seconds = end_time - start_time
real_time_factor = elapsed_seconds / audio_duration

for name, stream in zip(filenames, streams):
print("---")
print(name)
print(stream.result)
print()

print(f"Elapsed seconds: {elapsed_seconds:.3f}")
print(f"Audio duration in seconds: {audio_duration:.3f}")
print(f"RTF: {elapsed_seconds:.3f}/{audio_duration:.3f} = {real_time_factor:.3f}")
print()
print()

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Same division by zero risk; consider strict=True for zip().

  1. Line 107 has the same potential division by zero issue as decode_single_file() if all audio files are empty.

  2. Per static analysis, adding strict=True to zip() (Python 3.10+) helps catch length mismatches early.

,

♻️ Suggested improvements
-    real_time_factor = elapsed_seconds / audio_duration
+    real_time_factor = elapsed_seconds / audio_duration if audio_duration > 0 else float('inf')

-    for name, stream in zip(filenames, streams):
+    for name, stream in zip(filenames, streams, strict=True):
🧰 Tools
🪛 Ruff (0.14.14)

[warning] 109-109: zip() without an explicit strict= parameter

Add explicit value for parameter strict=

(B905)

🤖 Prompt for AI Agents
In `@python-api-examples/offline-omnilingual-asr-ctc-v2-decode-files.py` around
lines 88 - 119, The decode_multiple_files function can divide by zero if
audio_duration is 0 and should use strict zip to catch mismatched lists; update
decode_multiple_files to guard the real_time_factor calculation by checking if
audio_duration > 0 (or set real_time_factor to float("inf")/0.0-safe value)
before computing elapsed_seconds / audio_duration, and change the for loop that
iterates filenames and streams to use zip(filenames, streams, strict=True) so
length mismatches raise immediately; reference symbols: decode_multiple_files,
audio_duration, real_time_factor, filenames, streams, and the zip(...) call.

@csukuangfj

Copy link
Copy Markdown
Collaborator

Thank you for your contribution!

Regarding 4-bit Quantization:

Is it compatible with the current ONNX Runtime version v1.23.2? Do users need to take any special steps to run 4-bit quantized ONNX models?

@csukuangfj
csukuangfj merged commit 67b53a0 into k2-fsa:master Feb 5, 2026
1 check passed
@Edison2ST

Copy link
Copy Markdown
Contributor Author

@csukuangfj It works just as good as the int8 or fp32 versions, meaning it doesn't require any extensions or modifications to the C++ core, just change the path from model.int8.onnx to model.int4.onnx. The model has minor phonetic shifts in some cases (e.g., 'wurst' becoming 'worst' in German in the example), which is expected with 4-bit quantization, but the overall results remain high-quality across languages.

I updated the model source with the .tar.bz2 and the scripts files to generate those models, I used the native matmul_nbits_quantizer from onnxruntime.quantization (the official ORT pipeline) here's the Bash for 300M, int4 (Python and sherpa-onnx-offline):

Bash

ONNX Runtime Version
python -c "import onnxruntime; print(f'onnxruntime version: {onnxruntime.__version__}')"
onnxruntime version: 1.23.2
sherpa-onnx-offline
sherpa-onnx-offline --omnilingual-asr-model=model.int4.onnx --tokens=tokens.txt --num-threads=4 ./test_wavs/de.wav ./test_wavs/en.wav ./test_wavs/es.wav ./test_wavs/fr.wav
D:\a\sherpa-onnx\sherpa-onnx\sherpa-onnx\csrc\parse-options.cc:Read:373 sherpa-onnx-offline --omnilingual-asr-model=model.int4.onnx --tokens=tokens.txt --num-threads=4 ./test_wavs/de.wav ./test_wavs/en.wav ./test_wavs/es.wav ./test_wavs/fr.wav

OfflineRecognizerConfig(feat_config=FeatureExtractorConfig(sampling_rate=16000, feature_dim=80, low_freq=20, high_freq=-400, dither=0, normalize_samples=True, snip_edges=False), model_config=OfflineModelConfig(transducer=OfflineTransducerModelConfig(encoder_filename="", decoder_filename="", joiner_filename=""), paraformer=OfflineParaformerModelConfig(model=""), nemo_ctc=OfflineNemoEncDecCtcModelConfig(model=""), whisper=OfflineWhisperModelConfig(encoder="", decoder="", language="", task="transcribe", tail_paddings=-1), fire_red_asr=OfflineFireRedAsrModelConfig(encoder="", decoder=""), tdnn=OfflineTdnnModelConfig(model=""), zipformer_ctc=OfflineZipformerCtcModelConfig(model=""), wenet_ctc=OfflineWenetCtcModelConfig(model=""), sense_voice=OfflineSenseVoiceModelConfig(model="", language="auto", use_itn=False), moonshine=OfflineMoonshineModelConfig(preprocessor="", encoder="", uncached_decoder="", cached_decoder=""), dolphin=OfflineDolphinModelConfig(model=""), canary=OfflineCanaryModelConfig(encoder="", decoder="", src_lang="", tgt_lang="", use_pnc=True), omnilingual=OfflineOmnilingualAsrCtcModelConfig(model="model.int4.onnx"), funasr_nano=OfflineFunASRNanoModelConfig(encoder_adaptor="", llm="", embedding="", tokenizer="", system_prompt="You are a helpful assistant.", user_prompt="Þ»¡Úƒ│Þ¢¼ÕåÖ´╝Ü", max_new_tokens=512, temperature=1e-06, top_p=0.8, seed=42), medasr=OfflineMedAsrCtcModelConfig(model=""), telespeech_ctc="", tokens="tokens.txt", num_threads=4, debug=False, provider="cpu", model_type="", modeling_unit="cjkchar", bpe_vocab=""), lm_config=OfflineLMConfig(model="", scale=0.5, lodr_scale=0.01, lodr_fst="", lodr_backoff_id=-1), ctc_fst_decoder_config=OfflineCtcFstDecoderConfig(graph="", max_active=3000), decoding_method="greedy_search", max_active_paths=4, hotwords_file="", hotwords_score=1.5, blank_penalty=0, rule_fsts="", rule_fars="", hr=HomophoneReplacerConfig(lexicon="", rule_fsts=""))
Creating recognizer ...
recognizer created in 0.758 s
Started
D:\a\sherpa-onnx\sherpa-onnx\sherpa-onnx\csrc\offline-stream.cc:AcceptWaveformImpl:133 Creating a resampler:
   in_sample_rate: 22050
   output_sample_rate: 16000

D:\a\sherpa-onnx\sherpa-onnx\sherpa-onnx\csrc\offline-stream.cc:AcceptWaveformImpl:133 Creating a resampler:
   in_sample_rate: 24000
   output_sample_rate: 16000

D:\a\sherpa-onnx\sherpa-onnx\sherpa-onnx\csrc\offline-stream.cc:AcceptWaveformImpl:133 Creating a resampler:
   in_sample_rate: 22050
   output_sample_rate: 16000

D:\a\sherpa-onnx\sherpa-onnx\sherpa-onnx\csrc\offline-stream.cc:AcceptWaveformImpl:133 Creating a resampler:
   in_sample_rate: 22050
   output_sample_rate: 16000

Done!

./test_wavs/de.wav
{"lang": "", "emotion": "", "event": "", "text": "alles hat ein ende nur die worst hat zwei", "timestamps": [0.08, 0.10, 0.16, 0.20, 0.28, 0.36, 0.38, 0.42, 0.50, 0.58, 0.62, 0.66, 0.70, 0.80, 0.86, 0.94, 1.00, 1.08, 1.28, 1.34, 1.38, 1.44, 1.52, 1.54, 1.60, 1.64, 1.68, 1.72, 1.78, 1.82, 1.90, 1.96, 1.98, 2.02, 2.06, 2.12, 2.20, 2.26, 2.34, 2.44, 2.52], "durations": [], "tokens":["a", "l", "l", "e", "s", " ", "h", "a", "t", " ", "e", "i", "n", " ", "e", "n", "d", "e", " ", "n", "u", "r", " ", "d", "i", "e", " ", "w", "o", "r", "s", "t", " ", "h", "a", "t", " ", "z", "w", "e", "i"], "ys_log_probs": [], "words": []}
----
./test_wavs/en.wav
{"lang": "", "emotion": "", "event": "", "text": "ask not what your country can do for you ask what you can do for your country", "timestamps": [0.16, 0.28, 0.34, 0.46, 0.50, 0.54, 0.58, 0.62, 0.64, 0.66, 0.68, 0.72, 0.74, 0.76, 0.78, 0.82, 0.84, 0.88, 0.92, 0.96, 0.98, 1.02, 1.06, 1.12, 1.16, 1.22, 1.28, 1.30, 1.36, 1.40, 1.44, 1.48, 1.56, 1.60, 1.64, 1.66, 1.72, 1.74, 1.78, 1.80, 2.04, 2.16, 2.26, 2.30, 2.40, 2.42, 2.46, 2.48, 2.50, 2.52, 2.56, 2.58, 2.60, 2.66, 2.70, 2.72, 2.76, 2.82, 2.86, 2.90, 2.98, 3.00, 3.04, 3.06, 3.10, 3.12, 3.16, 3.18, 3.20, 3.24, 3.30, 3.34, 3.36, 3.40, 3.46, 3.54, 3.60], "durations": [], "tokens":["a", "s", "k", " ", "n", "o", "t", " ", "w", "h", "a", "t", " ", "y", "o", "u", "r", " ", "c", "o", "u", "n", "t", "r", "y", " ", "c", "a", "n", " ", "d", "o", " ", "f", "o", "r", " ", "y", "o", "u", " ", "a", "s", "k", " ", "w", "h", "a", "t", " ", "y", "o", "u", " ", "c", "a", "n", " ", "d", "o", " ", "f", "o", "r", " ", "y", "o", "u", "r", " ", "c", "o", "u", "n", "t", "r", "y"], "ys_log_probs": [], "words": []}
----
./test_wavs/es.wav
{"lang": "", "emotion": "", "event": "", "text": "no preguntes que puede hacer tu país por ti pregunta que puedes hacer te un puerto país", "timestamps": [0.12, 0.16, 0.22, 0.26, 0.30, 0.34, 0.40, 0.46, 0.50, 0.56, 0.62, 0.70, 0.78, 0.84, 0.86, 0.90, 0.98, 1.02, 1.04, 1.10, 1.16, 1.20, 1.26, 1.28, 1.32, 1.36, 1.40, 1.46, 1.52, 1.56, 1.60, 1.66, 1.72, 1.78, 1.88, 1.96, 2.04, 2.08, 2.14, 2.18, 2.26, 2.30, 2.38, 2.72, 2.78, 2.82, 2.86, 2.92, 2.96, 3.02, 3.08, 3.16, 3.20, 3.24, 3.26, 3.30, 3.36, 3.40, 3.44, 3.46, 3.52, 3.56, 3.64, 3.66, 3.70, 3.74, 3.78, 3.84, 3.90, 3.96, 4.00, 4.04, 4.08, 4.10, 4.14, 4.18, 4.22, 4.26, 4.30, 4.36, 4.46, 4.54, 4.56, 4.66, 4.76, 4.90, 5.02], "durations": [], "tokens":["n", "o", " ", "p", "r", "e", "g", "u", "n", "t", "e", "s", " ", "q", "u", "e", " ", "p", "u", "e", "d", "e", " ", "h", "a", "c", "e", "r", " ", "t", "u", " ", "p", "a", "í", "s", " ", "p", "o", "r", " ", "t", "i", " ", "p", "r", "e", "g", "u", "n", "t", "a", " ", "q", "u", "e", " ", "p", "u", "e", "d", "e", "s", " ", "h", "a", "c", "e", "r", " ", "t", "e", " ", "u", "n", " ", "p", "u", "e", "r", "t", "o", " ", "p", "a", "í", "s"], "ys_log_probs": [], "words": []}
----
./test_wavs/fr.wav
{"lang": "", "emotion": "", "event": "", "text": "ne vous demandez pas ce que votre pays peut faire pour vous demandez-vous plut├┤t ce que vous pouvez faire pour lui", "timestamps": [0.10, 0.14, 0.18, 0.22, 0.24, 0.26, 0.28, 0.32, 0.36, 0.38, 0.44, 0.46, 0.48, 0.52, 0.58, 0.64, 0.68, 0.70, 0.72, 0.76, 0.78, 0.80, 0.82, 0.84, 0.88, 0.90, 0.92, 0.96, 0.98, 1.02, 1.08, 1.10, 1.14, 1.18, 1.22, 1.26, 1.34, 1.36, 1.40, 1.44, 1.48, 1.50, 1.54, 1.60, 1.64, 1.74, 1.76, 1.80, 1.84, 1.90, 1.94, 1.98, 2.00, 2.06, 2.14, 2.18, 2.22, 2.24, 2.28, 2.60, 2.70, 2.72, 2.82, 2.84, 2.88, 2.92, 2.98, 3.02, 3.06, 3.08, 3.12, 3.14, 3.16, 3.22, 3.26, 3.30, 3.34, 3.40, 3.46, 3.50, 3.54, 3.58, 3.60, 3.64, 3.68, 3.70, 3.72, 3.76, 3.80, 3.82, 3.84, 3.86, 3.90, 3.94, 3.96, 3.98, 4.02, 4.06, 4.14, 4.22, 4.26, 4.34, 4.36, 4.40, 4.44, 4.50, 4.54, 4.56, 4.58, 4.62, 4.68, 4.72, 4.76, 4.80], "durations": [], "tokens":["n", "e", " ", "v", "o", "u", "s", " ", "d", "e", "m", "a", "n", "d", "e", "z", " ", "p", "a", "s", " ", "c", "e", " ", "q", "u", "e", " ", "v", "o", "t", "r", "e", " ", "p", "a", "y", "s", " ", "p", "e", "u", "t", " ", "f", "a", "i", "r", "e", " ", "p", "o", "u", "r", " ", "v", "o", "u", "s", " ", "d", "e", "m", "a", "n", "d", "e", "z", "-", "v", "o", "u", "s", " ", "p", "l", "u", "t", "├┤", "t", " ", "c", "e", " ", "q", "u", "e", " ", "v", "o", "u", "s", " ", "p", "o", "u", "v", "e", "z", " ", "f", "a", "i", "r", "e", " ", "p", "o", "u", "r", " ", "l", "u", "i"], "ys_log_probs": [], "words": []}
----
num threads: 4
decoding method: greedy_search
Elapsed seconds: 1.725 s
Real time factor (RTF): 1.725 / 16.895 = 0.102
python
python offline-omnilingual-asr-ctc-v2-decode-files.py
---
test_wavs/en.wav
{"lang": "", "emotion": "", "event": "", "text": "ask not what your country can do for you ask what you can do for your country", "timestamps": [0.16, 0.28, 0.34, 0.46, 0.50, 0.54, 0.58, 0.62, 0.64, 0.66, 0.68, 0.72, 0.74, 0.76, 0.78, 0.82, 0.84, 0.88, 0.92, 0.96, 0.98, 1.02, 1.06, 1.12, 1.16, 1.22, 1.28, 1.30, 1.36, 1.40, 1.44, 1.48, 1.56, 1.60, 1.64, 1.66, 1.72, 1.76, 1.78, 1.80, 2.04, 2.16, 2.26, 2.30, 2.40, 2.42, 2.46, 2.48, 2.50, 2.52, 2.56, 2.58, 2.60, 2.66, 2.70, 2.72, 2.76, 2.82, 2.86, 2.90, 2.98, 3.00, 3.04, 3.06, 3.10, 3.12, 3.16, 3.18, 3.20, 3.24, 3.30, 3.34, 3.36, 3.40, 3.46, 3.54, 3.60], "durations": [], "tokens":["a", "s", "k", " ", "n", "o", "t", " ", "w", "h", "a", "t", " ", "y", "o", "u", "r", " ", "c", "o", "u", "n", "t", "r", "y", " ", "c", "a", "n", " ", "d", "o", " ", "f", "o", "r", " ", "y", "o", "u", " ", "a", "s", "k", " ", "w", "h", "a", "t", " ", "y", "o", "u", " ", "c", "a", "n", " ", "d", "o", " ", "f", "o", "r", " ", "y", "o", "u", "r", " ", "c", "o", "u", "n", "t", "r", "y"], "ys_log_probs": [], "words": []}
Elapsed seconds: 1.355
Audio duration in seconds: 3.845
RTF: 1.355/3.845 = 0.352

---
test_wavs/de.wav
{"lang": "", "emotion": "", "event": "", "text": "alles hat ein ende nur die worst hat zwei", "timestamps": [0.08, 0.10, 0.16, 0.20, 0.28, 0.34, 0.38, 0.42, 0.50, 0.58, 0.62, 0.66, 0.70, 0.80, 0.86, 0.94, 1.00, 1.08, 1.28, 1.34, 1.38, 1.44, 1.52, 1.54, 1.60, 1.64, 1.68, 1.72, 1.78, 1.82, 1.90, 1.96, 1.98, 2.02, 2.06, 2.12, 2.20, 2.26, 2.34, 2.44, 2.52], "durations": [], "tokens":["a", "l", "l", "e", "s", " ", "h", "a", "t", " ", "e", "i", "n", " ", "e", "n", "d", "e", " ", "n", "u", "r", " ", "d", "i", "e", " ", "w", "o", "r", "s", "t", " ", "h", "a", "t", " ", "z", "w", "e", "i"], "ys_log_probs": [], "words": []}
Elapsed seconds: 0.974
Audio duration in seconds: 2.752
RTF: 0.974/2.752 = 0.354

---
test_wavs/fr.wav
{"lang": "", "emotion": "", "event": "", "text": "ne vous demandez pas ce que votre pays peut faire pour vous demandez-vous plutôt ce que vous pouvez faire pour lui", "timestamps": [0.10, 0.14, 0.18, 0.22, 0.24, 0.26, 0.28, 0.32, 0.36, 0.38, 0.44, 0.46, 0.48, 0.52, 0.58, 0.64, 0.68, 0.70, 0.72, 0.76, 0.78, 0.80, 0.82, 0.84, 0.88, 0.90, 0.92, 0.96, 0.98, 1.02, 1.08, 1.10, 1.14, 1.18, 1.22, 1.26, 1.34, 1.36, 1.42, 1.44, 1.48, 1.50, 1.54, 1.60, 1.64, 1.74, 1.76, 1.80, 1.84, 1.90, 1.94, 1.98, 2.00, 2.06, 2.14, 2.18, 2.22, 2.24, 2.28, 2.60, 2.70, 2.72, 2.82, 2.84, 2.88, 2.92, 2.98, 3.02, 3.06, 3.08, 3.10, 3.14, 3.16, 3.22, 3.26, 3.30, 3.34, 3.40, 3.46, 3.50, 3.52, 3.58, 3.60, 3.64, 3.68, 3.70, 3.72, 3.76, 3.80, 3.82, 3.84, 3.86, 3.90, 3.94, 3.96, 3.98, 4.02, 4.06, 4.14, 4.22, 4.26, 4.34, 4.36, 4.40, 4.44, 4.50, 4.54, 4.56, 4.58, 4.62, 4.68, 4.72, 4.76, 4.80], "durations": [], "tokens":["n", "e", " ", "v", "o", "u", "s", " ", "d", "e", "m", "a", "n", "d", "e", "z", " ", "p", "a", "s", " ", "c", "e", " ", "q", "u", "e", " ", "v", "o", "t", "r", "e", " ", "p", "a", "y", "s", " ", "p", "e", "u", "t", " ", "f", "a", "i", "r", "e", " ", "p", "o", "u", "r", " ", "v", "o", "u", "s", " ", "d", "e", "m", "a", "n", "d", "e", "z", "-", "v", "o", "u", "s", " ", "p", "l", "u", "t", "ô", "t", " ", "c", "e", " ", "q", "u", "e", " ", "v", "o", "u", "s", " ", "p", "o", "u", "v", "e", "z", " ", "f", "a", "i", "r", "e", " ", "p", "o", "u", "r", " ", "l", "u", "i"], "ys_log_probs": [], "words": []}

---
test_wavs/es.wav
{"lang": "", "emotion": "", "event": "", "text": "no preguntes que puede hacer tu país por ti pregunta que puedes hacer te un puerto país", "timestamps": [0.12, 0.16, 0.22, 0.26, 0.30, 0.34, 0.40, 0.46, 0.50, 0.56, 0.62, 0.70, 0.78, 0.84, 0.86, 0.90, 0.98, 1.02, 1.04, 1.10, 1.16, 1.20, 1.26, 1.28, 1.32, 1.36, 1.40, 1.44, 1.52, 1.56, 1.60, 1.68, 1.72, 1.78, 1.88, 1.96, 2.04, 2.08, 2.14, 2.18, 2.26, 2.30, 2.38, 2.74, 2.78, 2.82, 2.88, 2.92, 2.96, 3.02, 3.08, 3.16, 3.20, 3.24, 3.26, 3.30, 3.36, 3.40, 3.44, 3.46, 3.52, 3.56, 3.64, 3.66, 3.70, 3.74, 3.78, 3.84, 3.90, 3.96, 4.00, 4.04, 4.08, 4.10, 4.14, 4.18, 4.22, 4.26, 4.30, 4.36, 4.46, 4.54, 4.56, 4.66, 4.76, 4.88, 5.02], "durations": [], "tokens":["n", "o", " ", "p", "r", "e", "g", "u", "n", "t", "e", "s", " ", "q", "u", "e", " ", "p", "u", "e", "d", "e", " ", "h", "a", "c", "e", "r", " ", "t", "u", " ", "p", "a", "í", "s", " ", "p", "o", "r", " ", "t", "i", " ", "p", "r", "e", "g", "u", "n", "t", "a", " ", "q", "u", "e", " ", "p", "u", "e", "d", "e", "s", " ", "h", "a", "c", "e", "r", " ", "t", "e", " ", "u", "n", " ", "p", "u", "e", "r", "t", "o", " ", "p", "a", "í", "s"], "ys_log_probs": [], "words": []}

Elapsed seconds: 3.608
Audio duration in seconds: 10.298
RTF: 3.608/10.298 = 0.350

@csukuangfj

Copy link
Copy Markdown
Collaborator

model source

Thank you for sharing the detailed information!

I found your export script at
https://huggingface.co/Edison2ST/sherpa-onnx-omnilingual-asr-1600-languages-ctc-v2/blob/main/scripts/300M_int4/omniQ4.py

Will try it with our other models.

zhaohm1 pushed a commit to zhaohm1/sherpa-onnx that referenced this pull request Oct 20, 2026
This pull request integrates support for the latest Meta Omnilingual ASR v2 models, enhancing the project's multilingual speech recognition capabilities without requiring modifications to the core C++ codebase. It introduces a dedicated Python example to facilitate usage and demonstrates the model's performance and compatibility.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L This PR changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants