From 26556f9785d0334bf83705b494e4b8c865fc6b0a Mon Sep 17 00:00:00 2001 From: Fangjun Kuang Date: Thu, 13 Nov 2025 12:38:52 +0800 Subject: [PATCH] Add C API for Omnilingual ASR CTC models --- .github/workflows/c-api.yaml | 30 ++++++++ c-api-examples/CMakeLists.txt | 3 + c-api-examples/omnilingual-asr-ctc-c-api.c | 82 ++++++++++++++++++++++ sherpa-onnx/c-api/c-api.cc | 3 + sherpa-onnx/c-api/c-api.h | 5 ++ 5 files changed, 123 insertions(+) create mode 100644 c-api-examples/omnilingual-asr-ctc-c-api.c diff --git a/.github/workflows/c-api.yaml b/.github/workflows/c-api.yaml index 561d1d2070..b8e1adead5 100644 --- a/.github/workflows/c-api.yaml +++ b/.github/workflows/c-api.yaml @@ -75,6 +75,36 @@ jobs: otool -L ./install/lib/libsherpa-onnx-c-api.dylib fi + - name: Test Omnilingual ASR CTC + shell: bash + run: | + name=omnilingual-asr-ctc-c-api + gcc -o $name ./c-api-examples/$name.c \ + -I ./build/install/include \ + -L ./build/install/lib/ \ + -l sherpa-onnx-c-api \ + -l onnxruntime + + ls -lh $name + + if [[ ${{ matrix.os }} == ubuntu-latest || ${{ matrix.os }} == ubuntu-22.04-arm ]]; then + ldd ./$name + echo "----" + readelf -d ./$name + fi + + curl -SL -O https://github.com/k2-fsa/sherpa-onnx/releases/download/asr-models/sherpa-onnx-omnilingual-asr-1600-languages-300M-ctc-int8-2025-11-12.tar.bz2 + tar xvf sherpa-onnx-omnilingual-asr-1600-languages-300M-ctc-int8-2025-11-12.tar.bz2 + rm sherpa-onnx-omnilingual-asr-1600-languages-300M-ctc-int8-2025-11-12.tar.bz2 + + export LD_LIBRARY_PATH=$PWD/build/install/lib:$LD_LIBRARY_PATH + export DYLD_LIBRARY_PATH=$PWD/build/install/lib:$DYLD_LIBRARY_PATH + + ./$name + + rm $name + rm -rf sherpa-onnx-omnilingual-* + - name: Test Wenet CTC shell: bash run: | diff --git a/c-api-examples/CMakeLists.txt b/c-api-examples/CMakeLists.txt index cd3d9d4ab9..b3baed3ac3 100644 --- a/c-api-examples/CMakeLists.txt +++ b/c-api-examples/CMakeLists.txt @@ -83,6 +83,9 @@ target_link_libraries(zipformer-c-api sherpa-onnx-c-api) add_executable(wenet-ctc-c-api wenet-ctc-c-api.c) target_link_libraries(wenet-ctc-c-api sherpa-onnx-c-api) +add_executable(omnilingual-asr-ctc-c-api omnilingual-asr-ctc-c-api.c) +target_link_libraries(omnilingual-asr-ctc-c-api sherpa-onnx-c-api) + add_executable(streaming-zipformer-c-api streaming-zipformer-c-api.c) target_link_libraries(streaming-zipformer-c-api sherpa-onnx-c-api) diff --git a/c-api-examples/omnilingual-asr-ctc-c-api.c b/c-api-examples/omnilingual-asr-ctc-c-api.c new file mode 100644 index 0000000000..eabd3c2f24 --- /dev/null +++ b/c-api-examples/omnilingual-asr-ctc-c-api.c @@ -0,0 +1,82 @@ +// c-api-examples/omnilingual-asr-ctc-c-api.c +// +// Copyright (c) 2025 Xiaomi Corporation + +// +// This file demonstrates how to use Omnilingual ASR with sherpa-onnx's C API. +// clang-format off +/* +wget https://github.com/k2-fsa/sherpa-onnx/releases/download/asr-models/sherpa-onnx-omnilingual-asr-1600-languages-300M-ctc-int8-2025-11-12.tar.bz2 +tar xvf sherpa-onnx-omnilingual-asr-1600-languages-300M-ctc-int8-2025-11-12.tar.bz2 +rm sherpa-onnx-omnilingual-asr-1600-languages-300M-ctc-int8-2025-11-12.tar.bz2 +*/ +// +// clang-format on + +#include +#include +#include + +#include "sherpa-onnx/c-api/c-api.h" + +int32_t main() { + // clang-format off + const char *wav_filename = "./sherpa-onnx-omnilingual-asr-1600-languages-300M-ctc-int8-2025-11-12/test_wavs/en.wav"; + const char *model_filename = "./sherpa-onnx-omnilingual-asr-1600-languages-300M-ctc-int8-2025-11-12/model.int8.onnx"; + const char *tokens_filename = "./sherpa-onnx-omnilingual-asr-1600-languages-300M-ctc-int8-2025-11-12/tokens.txt"; + // clang-format on + + const char *provider = "cpu"; + + const SherpaOnnxWave *wave = SherpaOnnxReadWave(wav_filename); + if (wave == NULL) { + fprintf(stderr, "Failed to read %s\n", wav_filename); + return -1; + } + + SherpaOnnxOfflineOmnilingualAsrCtcModelConfig omnilingual; + memset(&omnilingual, 0, sizeof(omnilingual)); + omnilingual.model = model_filename; + + // Offline model config + SherpaOnnxOfflineModelConfig offline_model_config; + memset(&offline_model_config, 0, sizeof(offline_model_config)); + offline_model_config.debug = 1; + offline_model_config.num_threads = 1; + offline_model_config.provider = provider; + offline_model_config.tokens = tokens_filename; + offline_model_config.omnilingual = omnilingual; + + // Recognizer config + SherpaOnnxOfflineRecognizerConfig recognizer_config; + memset(&recognizer_config, 0, sizeof(recognizer_config)); + recognizer_config.decoding_method = "greedy_search"; + recognizer_config.model_config = offline_model_config; + + const SherpaOnnxOfflineRecognizer *recognizer = + SherpaOnnxCreateOfflineRecognizer(&recognizer_config); + + if (recognizer == NULL) { + fprintf(stderr, "Please check your config!\n"); + SherpaOnnxFreeWave(wave); + return -1; + } + + const SherpaOnnxOfflineStream *stream = + SherpaOnnxCreateOfflineStream(recognizer); + + SherpaOnnxAcceptWaveformOffline(stream, wave->sample_rate, wave->samples, + wave->num_samples); + SherpaOnnxDecodeOfflineStream(recognizer, stream); + const SherpaOnnxOfflineRecognizerResult *result = + SherpaOnnxGetOfflineStreamResult(stream); + + fprintf(stderr, "Decoded text: %s\n", result->text); + + SherpaOnnxDestroyOfflineRecognizerResult(result); + SherpaOnnxDestroyOfflineStream(stream); + SherpaOnnxDestroyOfflineRecognizer(recognizer); + SherpaOnnxFreeWave(wave); + + return 0; +} diff --git a/sherpa-onnx/c-api/c-api.cc b/sherpa-onnx/c-api/c-api.cc index 75d6356984..4d612ae193 100644 --- a/sherpa-onnx/c-api/c-api.cc +++ b/sherpa-onnx/c-api/c-api.cc @@ -508,6 +508,9 @@ static sherpa_onnx::OfflineRecognizerConfig GetOfflineRecognizerConfig( recognizer_config.model_config.wenet_ctc.model = SHERPA_ONNX_OR(config->model_config.wenet_ctc.model, ""); + recognizer_config.model_config.omnilingual.model = + SHERPA_ONNX_OR(config->model_config.omnilingual.model, ""); + recognizer_config.lm_config.model = SHERPA_ONNX_OR(config->lm_config.model, ""); recognizer_config.lm_config.scale = diff --git a/sherpa-onnx/c-api/c-api.h b/sherpa-onnx/c-api/c-api.h index 2f22a449a1..36731e66e1 100644 --- a/sherpa-onnx/c-api/c-api.h +++ b/sherpa-onnx/c-api/c-api.h @@ -480,6 +480,10 @@ SHERPA_ONNX_API typedef struct SherpaOnnxOfflineWenetCtcModelConfig { const char *model; } SherpaOnnxOfflineWenetCtcModelConfig; +SHERPA_ONNX_API typedef struct SherpaOnnxOfflineOmnilingualAsrCtcModelConfig { + const char *model; +} SherpaOnnxOfflineOmnilingualAsrCtcModelConfig; + SHERPA_ONNX_API typedef struct SherpaOnnxOfflineModelConfig { SherpaOnnxOfflineTransducerModelConfig transducer; SherpaOnnxOfflineParaformerModelConfig paraformer; @@ -506,6 +510,7 @@ SHERPA_ONNX_API typedef struct SherpaOnnxOfflineModelConfig { SherpaOnnxOfflineZipformerCtcModelConfig zipformer_ctc; SherpaOnnxOfflineCanaryModelConfig canary; SherpaOnnxOfflineWenetCtcModelConfig wenet_ctc; + SherpaOnnxOfflineOmnilingualAsrCtcModelConfig omnilingual; } SherpaOnnxOfflineModelConfig; SHERPA_ONNX_API typedef struct SherpaOnnxOfflineRecognizerConfig {