Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions .github/workflows/c-api.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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: |
Expand Down
3 changes: 3 additions & 0 deletions c-api-examples/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
82 changes: 82 additions & 0 deletions c-api-examples/omnilingual-asr-ctc-c-api.c
Original file line number Diff line number Diff line change
@@ -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 <stdio.h>
#include <stdlib.h>
#include <string.h>

#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";
Comment on lines +24 to +26

Copilot AI Nov 13, 2025

Copy link

Choose a reason for hiding this comment

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

The directory path sherpa-onnx-omnilingual-asr-1600-languages-300M-ctc-int8-2025-11-12 is repeated three times. Consider extracting this as a constant to improve maintainability and reduce the chance of inconsistencies if the path needs to be updated.

Suggested change
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";
const char *model_dir = "./sherpa-onnx-omnilingual-asr-1600-languages-300M-ctc-int8-2025-11-12";
char wav_filename[512];
char model_filename[512];
char tokens_filename[512];
snprintf(wav_filename, sizeof(wav_filename), "%s/test_wavs/en.wav", model_dir);
snprintf(model_filename, sizeof(model_filename), "%s/model.int8.onnx", model_dir);
snprintf(tokens_filename, sizeof(tokens_filename), "%s/tokens.txt", model_dir);

Copilot uses AI. Check for mistakes.
// 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;
Comment on lines +37 to +39

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

Using memset to zero-initialize structs is a C-style pattern. For better readability and type safety, it's recommended to use C99 designated initializers. This makes the code cleaner and less prone to errors if the struct definition changes.

Suggested change
SherpaOnnxOfflineOmnilingualAsrCtcModelConfig omnilingual;
memset(&omnilingual, 0, sizeof(omnilingual));
omnilingual.model = model_filename;
SherpaOnnxOfflineOmnilingualAsrCtcModelConfig 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;
Comment on lines +42 to +48

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

For better readability and safety, consider using C99 designated initializers instead of memset followed by member assignments. This approach ensures that all other members are correctly zero-initialized and makes the initialization code more concise.

Suggested change
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;
SherpaOnnxOfflineModelConfig offline_model_config = {
.debug = 1,
.num_threads = 1,
.provider = provider,
.tokens = tokens_filename,
.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;
Comment on lines +51 to +54

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

Similar to previous comments, using C99 designated initializers here would make the code more modern, readable, and safe.

Suggested change
SherpaOnnxOfflineRecognizerConfig recognizer_config;
memset(&recognizer_config, 0, sizeof(recognizer_config));
recognizer_config.decoding_method = "greedy_search";
recognizer_config.model_config = offline_model_config;
SherpaOnnxOfflineRecognizerConfig recognizer_config = {
.decoding_method = "greedy_search",
.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);
Comment on lines +65 to +66

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

high

It's good practice to check the return value of SherpaOnnxCreateOfflineStream for NULL to handle potential allocation failures gracefully. While it might not fail in typical scenarios, adding this check improves the robustness of the example code. You could add the following check after creating the stream:

if (stream == NULL) {
  fprintf(stderr, "Failed to create offline stream\n");
  SherpaOnnxDestroyOfflineRecognizer(recognizer);
  SherpaOnnxFreeWave(wave);
  return -1;
}


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;
}
3 changes: 3 additions & 0 deletions sherpa-onnx/c-api/c-api.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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 =
Expand Down
5 changes: 5 additions & 0 deletions sherpa-onnx/c-api/c-api.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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 {
Expand Down
Loading