diff --git a/.github/workflows/cxx-api.yaml b/.github/workflows/cxx-api.yaml index e5a99fb0..bb94e00c 100644 --- a/.github/workflows/cxx-api.yaml +++ b/.github/workflows/cxx-api.yaml @@ -34,7 +34,7 @@ jobs: strategy: fail-fast: false matrix: - os: [ubuntu-latest, macos-latest] + os: [ubuntu-latest, macos-latest, ubuntu-22.04-arm] steps: - uses: actions/checkout@v4 @@ -68,7 +68,7 @@ jobs: ls -lh install/lib ls -lh install/include - if [[ ${{ matrix.os }} == ubuntu-latest ]]; then + if [[ ${{ matrix.os }} == ubuntu-latest || ${{ matrix.os }} == ubuntu-22.04-arm ]]; then ldd ./install/lib/libsherpa-onnx-c-api.so ldd ./install/lib/libsherpa-onnx-cxx-api.so echo "---" @@ -81,6 +81,39 @@ jobs: otool -L ./install/lib/libsherpa-onnx-cxx-api.dylib fi + - name: Test FireRedAsr + shell: bash + run: | + g++ -std=c++17 -o fire-red-asr-cxx-api ./cxx-api-examples/fire-red-asr-cxx-api.cc \ + -I ./build/install/include \ + -L ./build/install/lib/ \ + -l sherpa-onnx-cxx-api \ + -l sherpa-onnx-c-api \ + -l onnxruntime + + ls -lh fire-red-asr-cxx-api + + export LD_LIBRARY_PATH=$PWD/build/install/lib:$LD_LIBRARY_PATH + export DYLD_LIBRARY_PATH=$PWD/build/install/lib:$DYLD_LIBRARY_PATH + + if [[ ${{ matrix.os }} == ubuntu-latest || ${{ matrix.os }} == ubuntu-22.04-arm ]]; then + ldd ./fire-red-asr-cxx-api + echo "----" + readelf -d ./fire-red-asr-cxx-api + fi + + curl -SL -O https://github.com/k2-fsa/sherpa-onnx/releases/download/asr-models/sherpa-onnx-fire-red-asr-large-zh_en-2025-02-16.tar.bz2 + tar xvf sherpa-onnx-fire-red-asr-large-zh_en-2025-02-16.tar.bz2 + rm sherpa-onnx-fire-red-asr-large-zh_en-2025-02-16.tar.bz2 + + ls -lh sherpa-onnx-fire-red-asr-large-zh_en-2025-02-16 + echo "---" + ls -lh sherpa-onnx-fire-red-asr-large-zh_en-2025-02-16/test_wavs + + ./fire-red-asr-cxx-api + + rm -rf sherpa-onnx-fire-red-asr-* + - name: Test KWS (zh) shell: bash run: | @@ -241,7 +274,7 @@ jobs: ls -lh whisper-cxx-api - if [[ ${{ matrix.os }} == ubuntu-latest ]]; then + if [[ ${{ matrix.os }} == ubuntu-latest || ${{ matrix.os }} == ubuntu-22.04-arm ]]; then ldd ./whisper-cxx-api echo "----" readelf -d ./whisper-cxx-api @@ -275,7 +308,7 @@ jobs: ls -lh sense-voice-cxx-api - if [[ ${{ matrix.os }} == ubuntu-latest ]]; then + if [[ ${{ matrix.os }} == ubuntu-latest || ${{ matrix.os }} == ubuntu-22.04-arm ]]; then ldd ./sense-voice-cxx-api echo "----" readelf -d ./sense-voice-cxx-api @@ -309,7 +342,7 @@ jobs: ls -lh streaming-zipformer-cxx-api - if [[ ${{ matrix.os }} == ubuntu-latest ]]; then + if [[ ${{ matrix.os }} == ubuntu-latest || ${{ matrix.os }} == ubuntu-22.04-arm ]]; then ldd ./streaming-zipformer-cxx-api echo "----" readelf -d ./streaming-zipformer-cxx-api diff --git a/cxx-api-examples/CMakeLists.txt b/cxx-api-examples/CMakeLists.txt index fe21d580..90052893 100644 --- a/cxx-api-examples/CMakeLists.txt +++ b/cxx-api-examples/CMakeLists.txt @@ -12,6 +12,9 @@ target_link_libraries(streaming-zipformer-rtf-cxx-api sherpa-onnx-cxx-api) add_executable(whisper-cxx-api ./whisper-cxx-api.cc) target_link_libraries(whisper-cxx-api sherpa-onnx-cxx-api) +add_executable(fire-red-asr-cxx-api ./fire-red-asr-cxx-api.cc) +target_link_libraries(fire-red-asr-cxx-api sherpa-onnx-cxx-api) + add_executable(moonshine-cxx-api ./moonshine-cxx-api.cc) target_link_libraries(moonshine-cxx-api sherpa-onnx-cxx-api) diff --git a/cxx-api-examples/fire-red-asr-cxx-api.cc b/cxx-api-examples/fire-red-asr-cxx-api.cc new file mode 100644 index 00000000..cd363cee --- /dev/null +++ b/cxx-api-examples/fire-red-asr-cxx-api.cc @@ -0,0 +1,77 @@ +// cxx-api-examples/fire-red-asr-cxx-api.cc +// Copyright (c) 2025 Xiaomi Corporation + +// +// This file demonstrates how to use FireRedAsr AED with sherpa-onnx's C++ API. +// +// clang-format off +// +// wget https://github.com/k2-fsa/sherpa-onnx/releases/download/asr-models/sherpa-onnx-fire-red-asr-large-zh_en-2025-02-16.tar.bz2 +// tar xvf sherpa-onnx-fire-red-asr-large-zh_en-2025-02-16.tar.bz2 +// rm sherpa-onnx-fire-red-asr-large-zh_en-2025-02-16.tar.bz2 +// +// clang-format on + +#include // NOLINT +#include +#include + +#include "sherpa-onnx/c-api/cxx-api.h" + +int32_t main() { + using namespace sherpa_onnx::cxx; // NOLINT + OfflineRecognizerConfig config; + + config.model_config.fire_red_asr.encoder = + "./sherpa-onnx-fire-red-asr-large-zh_en-2025-02-16/encoder.int8.onnx"; + config.model_config.fire_red_asr.decoder = + "./sherpa-onnx-fire-red-asr-large-zh_en-2025-02-16/decoder.int8.onnx"; + config.model_config.tokens = + "./sherpa-onnx-fire-red-asr-large-zh_en-2025-02-16/tokens.txt"; + + config.model_config.num_threads = 1; + + std::cout << "Loading model\n"; + OfflineRecognizer recongizer = OfflineRecognizer::Create(config); + if (!recongizer.Get()) { + std::cerr << "Please check your config\n"; + return -1; + } + std::cout << "Loading model done\n"; + + std::string wave_filename = + "./sherpa-onnx-fire-red-asr-large-zh_en-2025-02-16/test_wavs/0.wav"; + Wave wave = ReadWave(wave_filename); + if (wave.samples.empty()) { + std::cerr << "Failed to read: '" << wave_filename << "'\n"; + return -1; + } + + std::cout << "Start recognition\n"; + const auto begin = std::chrono::steady_clock::now(); + + OfflineStream stream = recongizer.CreateStream(); + stream.AcceptWaveform(wave.sample_rate, wave.samples.data(), + wave.samples.size()); + + recongizer.Decode(&stream); + + OfflineRecognizerResult result = recongizer.GetResult(&stream); + + const auto end = std::chrono::steady_clock::now(); + const float elapsed_seconds = + std::chrono::duration_cast(end - begin) + .count() / + 1000.; + float duration = wave.samples.size() / static_cast(wave.sample_rate); + float rtf = elapsed_seconds / duration; + + std::cout << "text: " << result.text << "\n"; + printf("Number of threads: %d\n", config.model_config.num_threads); + printf("Duration: %.3fs\n", duration); + printf("Elapsed seconds: %.3fs\n", elapsed_seconds); + printf("(Real time factor) RTF = %.3f / %.3f = %.3f\n", elapsed_seconds, + duration, rtf); + + return 0; +} diff --git a/sherpa-onnx/c-api/cxx-api.cc b/sherpa-onnx/c-api/cxx-api.cc index d3c52213..a6b96aae 100644 --- a/sherpa-onnx/c-api/cxx-api.cc +++ b/sherpa-onnx/c-api/cxx-api.cc @@ -241,6 +241,11 @@ OfflineRecognizer OfflineRecognizer::Create( c.model_config.moonshine.cached_decoder = config.model_config.moonshine.cached_decoder.c_str(); + c.model_config.fire_red_asr.encoder = + config.model_config.fire_red_asr.encoder.c_str(); + c.model_config.fire_red_asr.decoder = + config.model_config.fire_red_asr.decoder.c_str(); + c.lm_config.model = config.lm_config.model.c_str(); c.lm_config.scale = config.lm_config.scale; diff --git a/sherpa-onnx/c-api/cxx-api.h b/sherpa-onnx/c-api/cxx-api.h index 372b6357..ccc6f832 100644 --- a/sherpa-onnx/c-api/cxx-api.h +++ b/sherpa-onnx/c-api/cxx-api.h @@ -214,6 +214,11 @@ struct SHERPA_ONNX_API OfflineWhisperModelConfig { int32_t tail_paddings = -1; }; +struct SHERPA_ONNX_API OfflineFireRedAsrModelConfig { + std::string encoder; + std::string decoder; +}; + struct SHERPA_ONNX_API OfflineTdnnModelConfig { std::string model; }; @@ -248,6 +253,7 @@ struct SHERPA_ONNX_API OfflineModelConfig { std::string telespeech_ctc; OfflineSenseVoiceModelConfig sense_voice; OfflineMoonshineModelConfig moonshine; + OfflineFireRedAsrModelConfig fire_red_asr; }; struct SHERPA_ONNX_API OfflineLMConfig {