Fangjun Kuang
Committed by GitHub

C api example for sense voice (#1165)

  1 +name: c-api
  2 +
  3 +on:
  4 + push:
  5 + branches:
  6 + - master
  7 + tags:
  8 + - 'v[0-9]+.[0-9]+.[0-9]+*'
  9 + paths:
  10 + - '.github/workflows/c-api.yaml'
  11 + - 'CMakeLists.txt'
  12 + - 'cmake/**'
  13 + - 'sherpa-onnx/csrc/*'
  14 + - 'sherpa-onnx/c-api/*'
  15 + - 'c-api-examples/**'
  16 + pull_request:
  17 + branches:
  18 + - master
  19 + paths:
  20 + - '.github/workflows/c-api.yaml'
  21 + - 'CMakeLists.txt'
  22 + - 'cmake/**'
  23 + - 'sherpa-onnx/csrc/*'
  24 + - 'sherpa-onnx/c-api/*'
  25 + - 'c-api-examples/**'
  26 +
  27 + workflow_dispatch:
  28 +
  29 +concurrency:
  30 + group: c-api-${{ github.ref }}
  31 + cancel-in-progress: true
  32 +
  33 +jobs:
  34 + c_api:
  35 + name: ${{ matrix.os }}
  36 + runs-on: ${{ matrix.os }}
  37 + strategy:
  38 + fail-fast: false
  39 + matrix:
  40 + os: [ubuntu-latest, macos-latest]
  41 +
  42 + steps:
  43 + - uses: actions/checkout@v4
  44 + with:
  45 + fetch-depth: 0
  46 +
  47 + - name: ccache
  48 + uses: hendrikmuhs/ccache-action@v1.2
  49 + with:
  50 + key: ${{ matrix.os }}-c-api-shared
  51 +
  52 + - name: Build sherpa-onnx
  53 + shell: bash
  54 + run: |
  55 + export CMAKE_CXX_COMPILER_LAUNCHER=ccache
  56 + export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH"
  57 + cmake --version
  58 +
  59 + mkdir build
  60 + cd build
  61 +
  62 + cmake \
  63 + -D CMAKE_BUILD_TYPE=Release \
  64 + -D BUILD_SHARED_LIBS=ON \
  65 + -D CMAKE_INSTALL_PREFIX=./install \
  66 + -D SHERPA_ONNX_ENABLE_BINARY=OFF \
  67 + ..
  68 +
  69 + make -j2 install
  70 +
  71 + ls -lh install/lib
  72 + ls -lh install/include
  73 +
  74 + if [[ ${{ matrix.os }} == ubuntu-latest ]]; then
  75 + ldd ./install/lib/libsherpa-onnx-c-api.so
  76 + echo "---"
  77 + readelf -d ./install/lib/libsherpa-onnx-c-api.so
  78 + fi
  79 +
  80 + if [[ ${{ matrix.os }} == macos-latest ]]; then
  81 + otool -L ./install/lib/libsherpa-onnx-c-api.dylib
  82 + fi
  83 +
  84 + - name: Test sense-voice
  85 + shell: bash
  86 + run: |
  87 + gcc -o sense-voice-c-api ./c-api-examples/sense-voice-c-api.c \
  88 + -I ./build/install/include \
  89 + -L ./build/install/lib/ \
  90 + -l sherpa-onnx-c-api \
  91 + -l onnxruntime
  92 +
  93 + ls -lh sense-voice-c-api
  94 +
  95 + if [[ ${{ matrix.os }} == ubuntu-latest ]]; then
  96 + ldd ./sense-voice-c-api
  97 + echo "----"
  98 + readelf -d ./sense-voice-c-api
  99 + fi
  100 +
  101 + # Now download models
  102 + curl -SL -O https://github.com/k2-fsa/sherpa-onnx/releases/download/asr-models/sherpa-onnx-sense-voice-zh-en-ja-ko-yue-2024-07-17.tar.bz2
  103 + tar xvf sherpa-onnx-sense-voice-zh-en-ja-ko-yue-2024-07-17.tar.bz2
  104 + rm sherpa-onnx-sense-voice-zh-en-ja-ko-yue-2024-07-17.tar.bz2
  105 +
  106 + ls -lh sherpa-onnx-sense-voice-zh-en-ja-ko-yue-2024-07-17
  107 + echo "---"
  108 + ls -lh sherpa-onnx-sense-voice-zh-en-ja-ko-yue-2024-07-17/test_wavs
  109 +
  110 + export LD_LIBRARY_PATH=$PWD/build/install/lib:$LD_LIBRARY_PATH
  111 + export DYLD_LIBRARY_PATH=$PWD/build/install/lib:$DYLD_LIBRARY_PATH
  112 +
  113 + ./sense-voice-c-api
  114 +
  115 + rm -rf sherpa-onnx-sense-voice-*
  116 +
  117 + - name: Test whisper
  118 + shell: bash
  119 + run: |
  120 + gcc -o whisper-c-api ./c-api-examples/whisper-c-api.c \
  121 + -I ./build/install/include \
  122 + -L ./build/install/lib/ \
  123 + -l sherpa-onnx-c-api \
  124 + -l onnxruntime
  125 +
  126 + ls -lh whisper-c-api
  127 +
  128 + if [[ ${{ matrix.os }} == ubuntu-latest ]]; then
  129 + ldd ./whisper-c-api
  130 + echo "----"
  131 + readelf -d ./whisper-c-api
  132 + fi
  133 +
  134 + curl -SL -O https://github.com/k2-fsa/sherpa-onnx/releases/download/asr-models/sherpa-onnx-whisper-tiny.tar.bz2
  135 + tar xvf sherpa-onnx-whisper-tiny.tar.bz2
  136 + rm sherpa-onnx-whisper-tiny.tar.bz2
  137 +
  138 + ls -lh sherpa-onnx-whisper-tiny
  139 + echo "---"
  140 + ls -lh sherpa-onnx-whisper-tiny/test_wavs
  141 +
  142 + export LD_LIBRARY_PATH=$PWD/build/install/lib:$LD_LIBRARY_PATH
  143 + export DYLD_LIBRARY_PATH=$PWD/build/install/lib:$DYLD_LIBRARY_PATH
  144 +
  145 + ./whisper-c-api
  146 +
  147 + rm -rf sherpa-onnx-whisper-*
@@ -24,8 +24,11 @@ target_link_libraries(audio-tagging-c-api sherpa-onnx-c-api) @@ -24,8 +24,11 @@ target_link_libraries(audio-tagging-c-api sherpa-onnx-c-api)
24 add_executable(add-punctuation-c-api add-punctuation-c-api.c) 24 add_executable(add-punctuation-c-api add-punctuation-c-api.c)
25 target_link_libraries(add-punctuation-c-api sherpa-onnx-c-api) 25 target_link_libraries(add-punctuation-c-api sherpa-onnx-c-api)
26 26
27 -add_executable(offline-stt-c-api offline-stt-c-api.c)  
28 -target_link_libraries(offline-stt-c-api sherpa-onnx-c-api) 27 +add_executable(whisper-c-api whisper-c-api.c)
  28 +target_link_libraries(whisper-c-api sherpa-onnx-c-api)
  29 +
  30 +add_executable(sense-voice-c-api sense-voice-c-api.c)
  31 +target_link_libraries(sense-voice-c-api sherpa-onnx-c-api)
29 32
30 if(SHERPA_ONNX_HAS_ALSA) 33 if(SHERPA_ONNX_HAS_ALSA)
31 add_subdirectory(./asr-microphone-example) 34 add_subdirectory(./asr-microphone-example)
  1 +// c-api-examples/sense-voice-c-api.c
  2 +//
  3 +// Copyright (c) 2024 Xiaomi Corporation
  4 +
  5 +//
  6 +// This file demonstrates how to use SenseVoice with sherpa-onnx's C API.
  7 +// clang-format off
  8 +//
  9 +// wget https://github.com/k2-fsa/sherpa-onnx/releases/download/asr-models/sherpa-onnx-sense-voice-zh-en-ja-ko-yue-2024-07-17.tar.bz2
  10 +// tar xvf sherpa-onnx-sense-voice-zh-en-ja-ko-yue-2024-07-17.tar.bz2
  11 +// rm sherpa-onnx-sense-voice-zh-en-ja-ko-yue-2024-07-17.tar.bz2
  12 +//
  13 +// clang-format on
  14 +
  15 +#include <stdio.h>
  16 +#include <stdlib.h>
  17 +#include <string.h>
  18 +
  19 +#include "sherpa-onnx/c-api/c-api.h"
  20 +
  21 +int32_t main() {
  22 + // You can find more test waves from
  23 + // https://hf-mirror.com/spaces/k2-fsa/spoken-language-identification/tree/main/test_wavs
  24 + const char *wav_filename =
  25 + "./sherpa-onnx-sense-voice-zh-en-ja-ko-yue-2024-07-17/test_wavs/en.wav";
  26 + const char *model_filename =
  27 + "./sherpa-onnx-sense-voice-zh-en-ja-ko-yue-2024-07-17/model.int8.onnx";
  28 + const char *tokens_filename =
  29 + "./sherpa-onnx-sense-voice-zh-en-ja-ko-yue-2024-07-17/tokens.txt";
  30 + const char *language = "auto";
  31 + const char *provider = "cpu";
  32 + int32_t use_inverse_text_normalization = 1;
  33 +
  34 + const SherpaOnnxWave *wave = SherpaOnnxReadWave(wav_filename);
  35 + if (wave == NULL) {
  36 + fprintf(stderr, "Failed to read %s\n", wav_filename);
  37 + return -1;
  38 + }
  39 +
  40 + SherpaOnnxOfflineSenseVoiceModelConfig sense_voice_config;
  41 + memset(&sense_voice_config, 0, sizeof(sense_voice_config));
  42 + sense_voice_config.model = model_filename;
  43 + sense_voice_config.language = language;
  44 + sense_voice_config.use_itn = use_inverse_text_normalization;
  45 +
  46 + // Offline model config
  47 + SherpaOnnxOfflineModelConfig offline_model_config;
  48 + memset(&offline_model_config, 0, sizeof(offline_model_config));
  49 + offline_model_config.debug = 1;
  50 + offline_model_config.num_threads = 1;
  51 + offline_model_config.provider = provider;
  52 + offline_model_config.tokens = tokens_filename;
  53 + offline_model_config.sense_voice = sense_voice_config;
  54 +
  55 + // Recognizer config
  56 + SherpaOnnxOfflineRecognizerConfig recognizer_config;
  57 + memset(&recognizer_config, 0, sizeof(recognizer_config));
  58 + recognizer_config.decoding_method = "greedy_search";
  59 + recognizer_config.model_config = offline_model_config;
  60 +
  61 + SherpaOnnxOfflineRecognizer *recognizer =
  62 + CreateOfflineRecognizer(&recognizer_config);
  63 +
  64 + if (recognizer == NULL) {
  65 + fprintf(stderr, "Please check your config!\n");
  66 + SherpaOnnxFreeWave(wave);
  67 + return -1;
  68 + }
  69 +
  70 + SherpaOnnxOfflineStream *stream = CreateOfflineStream(recognizer);
  71 +
  72 + AcceptWaveformOffline(stream, wave->sample_rate, wave->samples,
  73 + wave->num_samples);
  74 + DecodeOfflineStream(recognizer, stream);
  75 + const SherpaOnnxOfflineRecognizerResult *result =
  76 + GetOfflineStreamResult(stream);
  77 +
  78 + fprintf(stderr, "Decoded text: %s\n", result->text);
  79 +
  80 + DestroyOfflineRecognizerResult(result);
  81 + DestroyOfflineStream(stream);
  82 + DestroyOfflineRecognizer(recognizer);
  83 + SherpaOnnxFreeWave(wave);
  84 +
  85 + return 0;
  86 +}
@@ -21,8 +21,6 @@ @@ -21,8 +21,6 @@
21 #include "sherpa-onnx/c-api/c-api.h" 21 #include "sherpa-onnx/c-api/c-api.h"
22 22
23 int32_t main() { 23 int32_t main() {
24 - // You can find more test waves from  
25 - // https://hf-mirror.com/spaces/k2-fsa/spoken-language-identification/tree/main/test_wavs  
26 const char *wav_filename = "./sherpa-onnx-whisper-tiny/test_wavs/0.wav"; 24 const char *wav_filename = "./sherpa-onnx-whisper-tiny/test_wavs/0.wav";
27 const char *encoder_filename = "sherpa-onnx-whisper-tiny/tiny-encoder.onnx"; 25 const char *encoder_filename = "sherpa-onnx-whisper-tiny/tiny-encoder.onnx";
28 const char *decoder_filename = "sherpa-onnx-whisper-tiny/tiny-decoder.onnx"; 26 const char *decoder_filename = "sherpa-onnx-whisper-tiny/tiny-decoder.onnx";
@@ -48,31 +46,36 @@ int32_t main() { @@ -48,31 +46,36 @@ int32_t main() {
48 // Offline model config 46 // Offline model config
49 SherpaOnnxOfflineModelConfig offline_model_config; 47 SherpaOnnxOfflineModelConfig offline_model_config;
50 memset(&offline_model_config, 0, sizeof(offline_model_config)); 48 memset(&offline_model_config, 0, sizeof(offline_model_config));
51 - offline_model_config.bpe_vocab = "";  
52 offline_model_config.debug = 1; 49 offline_model_config.debug = 1;
53 offline_model_config.num_threads = 1; 50 offline_model_config.num_threads = 1;
54 offline_model_config.provider = provider; 51 offline_model_config.provider = provider;
55 offline_model_config.tokens = tokens_filename; 52 offline_model_config.tokens = tokens_filename;
56 offline_model_config.whisper = whisper_config; 53 offline_model_config.whisper = whisper_config;
57 - offline_model_config.sense_voice =  
58 - (SherpaOnnxOfflineSenseVoiceModelConfig){"", "", 0};  
59 54
60 // Recognizer config 55 // Recognizer config
61 SherpaOnnxOfflineRecognizerConfig recognizer_config; 56 SherpaOnnxOfflineRecognizerConfig recognizer_config;
62 memset(&recognizer_config, 0, sizeof(recognizer_config)); 57 memset(&recognizer_config, 0, sizeof(recognizer_config));
63 recognizer_config.decoding_method = "greedy_search"; 58 recognizer_config.decoding_method = "greedy_search";
64 - recognizer_config.feat_config = (SherpaOnnxFeatureConfig){16000, 512};  
65 recognizer_config.model_config = offline_model_config; 59 recognizer_config.model_config = offline_model_config;
66 60
67 SherpaOnnxOfflineRecognizer *recognizer = 61 SherpaOnnxOfflineRecognizer *recognizer =
68 CreateOfflineRecognizer(&recognizer_config); 62 CreateOfflineRecognizer(&recognizer_config);
69 63
  64 + if (recognizer == NULL) {
  65 + fprintf(stderr, "Please check your config!\n");
  66 +
  67 + SherpaOnnxFreeWave(wave);
  68 +
  69 + return -1;
  70 + }
  71 +
70 SherpaOnnxOfflineStream *stream = CreateOfflineStream(recognizer); 72 SherpaOnnxOfflineStream *stream = CreateOfflineStream(recognizer);
71 73
72 AcceptWaveformOffline(stream, wave->sample_rate, wave->samples, 74 AcceptWaveformOffline(stream, wave->sample_rate, wave->samples,
73 wave->num_samples); 75 wave->num_samples);
74 DecodeOfflineStream(recognizer, stream); 76 DecodeOfflineStream(recognizer, stream);
75 - SherpaOnnxOfflineRecognizerResult *result = GetOfflineStreamResult(stream); 77 + const SherpaOnnxOfflineRecognizerResult *result =
  78 + GetOfflineStreamResult(stream);
76 79
77 fprintf(stderr, "Decoded text: %s\n", result->text); 80 fprintf(stderr, "Decoded text: %s\n", result->text);
78 81