-
Notifications
You must be signed in to change notification settings - Fork 1k
Add various languge bindings for Wenet non-streaming CTC models #2584
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
Note Other AI code review bot(s) detectedCodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review. Caution Review failedThe pull request is closed. WalkthroughAdds Wenet CTC offline-model support across core C/C++ APIs, language bindings, examples, CI scripts, and tooling. Introduces new Wenet CTC config structs/fields, wiring and memory management in bindings, example programs and runners, model download entries, and related gitignore/docs updates. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor User
participant App as Language App / Example
participant Binding as Language Binding
participant Native as Native C/C++ API
participant Rec as OfflineRecognizer
participant Model as Wenet CTC ONNX
User->>App: supply model, tokens, WAV
App->>Binding: build OfflineModelConfig (wenetCtc.model)
Binding->>Native: Convert config (set wenet_ctc.model pointer)
Native->>Rec: create OfflineRecognizer with model config
App->>Rec: create OfflineStream
App->>Rec: acceptWaveform(samples, sr)
Rec->>Model: run greedy_search decode
Model-->>Rec: return text
Rec-->>App: getResult(text)
App-->>User: print transcription
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested labels
Suggested reviewers
Poem
Tip 👮 Agentic pre-merge checks are now available in preview!Pro plan users can now enable pre-merge checks in their settings to enforce checklists before merging PRs.
Please see the documentation for more information. Example: reviews:
pre_merge_checks:
custom_checks:
- name: "Undocumented Breaking Changes"
mode: "warning"
instructions: |
Pass/fail criteria: All breaking changes to public APIs, CLI flags, environment variables, configuration keys, database schemas, or HTTP/GraphQL endpoints must be documented in the "Breaking Change" section of the PR description and in CHANGELOG.md. Exclude purely internal or private changes (e.g., code not exported from package entry points or explicitly marked as internal).Please share your feedback with us on this Discord post. 📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro 📒 Files selected for processing (2)
✨ Finishing Touches🧪 Generate unit tests
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. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR adds support for Wenet non-streaming CTC models to sherpa-onnx by introducing the SherpaOnnxOfflineWenetCtcModelConfig struct and integrating it across all language bindings and APIs. The implementation follows the same pattern as other CTC model types like Zipformer CTC.
- Introduces
SherpaOnnxOfflineWenetCtcModelConfigstruct with a singlemodelfield for the ONNX model path - Adds the new config to
SherpaOnnxOfflineModelConfigand updates all language bindings (C++, Pascal, Kotlin, Java, Go, C#, Swift, JavaScript, etc.) - Provides comprehensive examples and tests across all supported platforms and languages
Reviewed Changes
Copilot reviewed 56 out of 58 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
wasm/nodejs/sherpa-onnx-wasm-nodejs.cc |
Adds static assertions and debug output for Wenet CTC config |
wasm/asr/sherpa-onnx-asr.js |
Implements JavaScript initialization and memory management for Wenet CTC |
swift-api-examples/wenet-ctc-asr.swift |
Swift example demonstrating Wenet CTC usage |
swift-api-examples/SherpaOnnx.swift |
Swift API bindings for Wenet CTC configuration |
sherpa-onnx/pascal-api/sherpa_onnx.pas |
Pascal language bindings and type definitions |
sherpa-onnx/kotlin-api/OfflineRecognizer.kt |
Kotlin data classes and model configuration |
sherpa-onnx/jni/offline-recognizer.cc |
JNI implementation for Android/Java integration |
sherpa-onnx/java-api/src/main/java/com/k2fsa/sherpa/onnx/OfflineWenetCtcModelConfig.java |
Java model configuration class |
sherpa-onnx/c-api/c-api.h |
C API struct definition for Wenet CTC |
scripts/go/sherpa_onnx.go |
Go language bindings and configuration |
| Various example files | Comprehensive examples across all supported languages and platforms |
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
| // now output text in German | ||
| val config = recognizer.config.copy(modelConfig=recognizer.config.modelConfig.copy( | ||
| canary=recognizer.config.modelConfig.canary.copy( | ||
| tgtLang="de" | ||
| ) | ||
| )) | ||
| recognizer.setConfig(config) | ||
|
|
||
| stream = recognizer.createStream() | ||
| stream.acceptWaveform(samples, sampleRate=sampleRate) | ||
| recognizer.decode(stream) | ||
|
|
||
| result = recognizer.getResult(stream) | ||
| println("German: $result") | ||
|
|
||
| stream.release() |
Copilot
AI
Sep 10, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This code is attempting to use Canary model configuration with a Wenet CTC model, which is incorrect. Wenet CTC models don't support language switching like Canary models. This section should be removed or modified to demonstrate proper Wenet CTC functionality.
| // now output text in German | |
| val config = recognizer.config.copy(modelConfig=recognizer.config.modelConfig.copy( | |
| canary=recognizer.config.modelConfig.canary.copy( | |
| tgtLang="de" | |
| ) | |
| )) | |
| recognizer.setConfig(config) | |
| stream = recognizer.createStream() | |
| stream.acceptWaveform(samples, sampleRate=sampleRate) | |
| recognizer.decode(stream) | |
| result = recognizer.getResult(stream) | |
| println("German: $result") | |
| stream.release() |
| rm -fv *.py | ||
| ls -lh | ||
| popd | ||
| """, | ||
| ), | ||
| Model( |
Copilot
AI
Sep 10, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are missing lines in the cmd section. The removal of model.onnx and *.py files appears to be left over from a previous model configuration and should be removed since this is for Wenet CTC which uses model.int8.onnx.
| OfflineMoonshineModelConfig, | ||
| OfflineSenseVoiceModelConfig, | ||
| OfflineWenetCtcModelConfig, |
Copilot
AI
Sep 10, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nitpick] The export order is inconsistent. OfflineMoonshineModelConfig and OfflineSenseVoiceModelConfig should be moved after OfflineWenetCtcModelConfig to maintain alphabetical ordering of the CTC model configs.
| OfflineMoonshineModelConfig, | |
| OfflineSenseVoiceModelConfig, | |
| OfflineWenetCtcModelConfig, | |
| OfflineWenetCtcModelConfig, | |
| OfflineMoonshineModelConfig, | |
| OfflineSenseVoiceModelConfig, |
|
@coderabbitai please review. |
|
@csukuangfj I'll review the changes in this PR that adds various language bindings for Wenet non-streaming CTC models. ✅ Actions performedReview triggered.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 16
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (5)
scripts/go/_internal/non-streaming-decode-files/run-wenet-ctc.sh (1)
1-19: Resolve duplicate execution path and add a shebang.
This file both (a) tries to delegate to the example script and (b) re-implements the workflow inline. Keep a single source of truth and make this a thin wrapper with a proper shebang.Apply:
-../../../../go-api-examples/non-streaming-decode-files/run-wenet-ctc.sh - -set -ex - -if [ ! -f sherpa-onnx-wenetspeech-yue-u2pp-conformer-ctc-zh-en-cantonese-int8-2025-09-10/model.int8.onnx ]; then - curl -SL -O https://github.com/k2-fsa/sherpa-onnx/releases/download/asr-models/sherpa-onnx-wenetspeech-yue-u2pp-conformer-ctc-zh-en-cantonese-int8-2025-09-10.tar.bz2 - tar xvf sherpa-onnx-wenetspeech-yue-u2pp-conformer-ctc-zh-en-cantonese-int8-2025-09-10.tar.bz2 - rm sherpa-onnx-wenetspeech-yue-u2pp-conformer-ctc-zh-en-cantonese-int8-2025-09-10.tar.bz2 -fi - -go mod tidy -go build - -./non-streaming-decode-files \ - --wenet-ctc ./sherpa-onnx-wenetspeech-yue-u2pp-conformer-ctc-zh-en-cantonese-int8-2025-09-10/model.int8.onnx \ - --tokens ./sherpa-onnx-wenetspeech-yue-u2pp-conformer-ctc-zh-en-cantonese-int8-2025-09-10/tokens.txt \ - --debug 0 \ - ./sherpa-onnx-wenetspeech-yue-u2pp-conformer-ctc-zh-en-cantonese-int8-2025-09-10/test_wavs/yue-0.wav +#!/usr/bin/env bash +set -Eeuo pipefail +set -x +exec bash ../../../../go-api-examples/non-streaming-decode-files/run-wenet-ctc.shsherpa-onnx/c-api/cxx-api.cc (4)
152-155: Fix index increment bug in multi-stream decode (online).
The loop increments n instead of i, causing a logic error/possible hang.Apply:
- for (int32_t i = 0; i != n; ++n) { + for (int32_t i = 0; i != n; ++i) { streams[i] = ss[i].Get(); }
306-308: Destroy uses p_ instead of the provided pointer.
This bypasses MoveOnly’s handoff and risks double-free or leak patterns in edge cases.Apply:
-void OfflineRecognizer::Destroy(const SherpaOnnxOfflineRecognizer *p) const { - SherpaOnnxDestroyOfflineRecognizer(p_); -} +void OfflineRecognizer::Destroy(const SherpaOnnxOfflineRecognizer *p) const { + SherpaOnnxDestroyOfflineRecognizer(p); +}
564-566: Remove invalid return in a void function.
Returning a value from a void function is ill-formed in C++.Apply:
-void KeywordSpotter::Decode(const OnlineStream *s) const { - return SherpaOnnxDecodeKeywordStream(p_, s->Get()); -} +void KeywordSpotter::Decode(const OnlineStream *s) const { + SherpaOnnxDecodeKeywordStream(p_, s->Get()); +}
573-576: Fix index increment bug in multi-stream decode (keyword spotter).
Same issue as the online decode path.Apply:
- for (int32_t i = 0; i != n; ++n) { + for (int32_t i = 0; i != n; ++i) { streams[i] = ss[i].Get(); }
♻️ Duplicate comments (3)
scripts/apk/generate-asr-2pass-apk-script.py (1)
191-192: Resolved: cmd block now closes properly with popdThis addresses the earlier “missing lines in the cmd section” note. One follow-up: since the 2025-09-09 SenseVoice tarball may still ship a float model alongside int8, consider keeping a harmless
rm -fv model.onnxhere to avoid bloating the APK if present.Would you confirm whether that archive contains a float
model.onnx?harmony-os/SherpaOnnxHar/sherpa_onnx/Index.ets (1)
18-20: Export list reordering — pick and document a rule.This reorders exports and adds OfflineWenetCtcModelConfig. Please confirm the reordering is intentional and adopt a consistent rule (e.g., alphabetical or minimal-diff) to reduce churn.
flutter/sherpa_onnx/lib/src/offline_recognizer.dart (1)
447-447: Make toString maintainable and readable (previous feedback still applies)This very long single-line toString is brittle and easy to forget updating when new fields (like wenetCtc) are added. Prefer serializing to JSON or formatting multi-line.
Apply:
- @override - String toString() { - return 'OfflineModelConfig(transducer: $transducer, paraformer: $paraformer, nemoCtc: $nemoCtc, whisper: $whisper, tdnn: $tdnn, senseVoice: $senseVoice, moonshine: $moonshine, fireRedAsr: $fireRedAsr, dolphin: $dolphin, zipformerCtc: $zipformerCtc, canary: $canary, wenetCtc: $wenetCtc, tokens: $tokens, numThreads: $numThreads, debug: $debug, provider: $provider, modelType: $modelType, modelingUnit: $modelingUnit, bpeVocab: $bpeVocab, telespeechCtc: $telespeechCtc)'; - } + @override + String toString() => 'OfflineModelConfig(${jsonEncode(toJson())})';
🧹 Nitpick comments (41)
scripts/apk/generate-asr-2pass-apk-script.py (2)
195-199: Short name typo: missing ‘p’ in u2ppModel name uses u2pp, but short_name says u2p. Align to avoid confusion and accidental collisions in artifacts.
- short_name="wenetspeech_yue_u2pconformer_ctc_2025_09_10_int8", + short_name="wenetspeech_yue_u2pp_conformer_ctc_2025_09_10_int8",Please check any downstream usage expecting the short_name string.
199-205: Quote model_name in pushd for safetyModel names are long and could contain shell-sensitive chars in future. Quoting is a low-risk hardening.
- pushd $model_name + pushd "$model_name".gitignore (1)
154-154: Prefer a wildcard for model folders to avoid date churnUse a pattern so future date-stamped drops are ignored without editing .gitignore again.
Apply:
-sherpa-onnx-wenetspeech-yue-u2pp-conformer-ctc-zh-en-cantonese-int8-2025-09-10 +sherpa-onnx-wenetspeech-yue-u2pp-conformer-ctc-zh-en-cantonese-int8-*go-api-examples/non-streaming-decode-files/main.go (1)
32-32: New --wenet-ctc flag wiring — LGTM; add guards to avoid conflicting model flagsFlag works, but multiple model flags can be set simultaneously, causing ambiguous config. Add a check after
flag.Parse()to ensure exactly one offline model is provided (and that--tokensis set) to fail-fast with a clear message.Example snippet to add after flag.Parse():
models := []string{ config.ModelConfig.ZipformerCtc.Model, config.ModelConfig.WenetCtc.Model, config.ModelConfig.NemoCTC.Model, config.ModelConfig.Paraformer.Model, config.ModelConfig.Dolphin.Model, config.ModelConfig.FireRedAsr.Encoder, // paired with Decoder } nonEmpty := 0 for _, m := range models { if m != "" { nonEmpty++ } } if nonEmpty != 1 { log.Fatalf("Specify exactly one offline model (use one of --zipformer-ctc, --wenet-ctc, --nemo-ctc, --paraformer, --dolphin-model or FireRedAsr pair). Got %d.", nonEmpty) } if config.ModelConfig.Tokens == "" { log.Fatalf("Please provide --tokens for the selected model") }nodejs-examples/test-offline-wenet-ctc.js (1)
3-6: Remove unused imports
fs,stream.Readable, andwavaren’t used. Trim to keep the sample minimal.-const fs = require('fs'); -const {Readable} = require('stream'); -const wav = require('wav'); +// No extra imports needednodejs-examples/README.md (1)
206-221: Add Wenet CTC example docs — LGTMInstructions match the test script and model naming. Consider mirroring the download style used elsewhere (wget vs curl) for consistency, but not required.
.github/scripts/test-nodejs-npm.sh (1)
12-18: Harden downloads with curl --fail for early exitsIf the asset URL 404s,
curlmay still exit 0; add--failto fail fast.-curl -SL -O https://github.com/k2-fsa/sherpa-onnx/releases/download/asr-models/sherpa-onnx-wenetspeech-yue-u2pp-conformer-ctc-zh-en-cantonese-int8-2025-09-10.tar.bz2 +curl -fSL -O https://github.com/k2-fsa/sherpa-onnx/releases/download/asr-models/sherpa-onnx-wenetspeech-yue-u2pp-conformer-ctc-zh-en-cantonese-int8-2025-09-10.tar.bz2 tar xvf sherpa-onnx-wenetspeech-yue-u2pp-conformer-ctc-zh-en-cantonese-int8-2025-09-10.tar.bz2 rm sherpa-onnx-wenetspeech-yue-u2pp-conformer-ctc-zh-en-cantonese-int8-2025-09-10.tar.bz2 node ./test-offline-wenet-ctc.js rm -rf sherpa-onnx-wenetspeech-yue-u2pp-conformer-ctc-zh-en-cantonese-int8-2025-09-10sherpa-onnx/c-api/c-api.h (1)
479-482: New Wenet CTC config type looks good; consider adding a short doc comment.Add a brief comment (download link / expected files) like other model config structs for consistency and discoverability.
go-api-examples/non-streaming-decode-files/run-wenet-ctc.sh (1)
1-19: Harden the script (quoting and stricter bash options).
- Use stricter shell options and quote paths/URLs.
Apply:
-#!/usr/bin/env bash -set -ex +#!/usr/bin/env bash +set -Eeuo pipefail +IFS=$'\n\t' @@ -if [ ! -f sherpa-onnx-wenetspeech-yue-u2pp-conformer-ctc-zh-en-cantonese-int8-2025-09-10/model.int8.onnx ]; then - curl -SL -O https://github.com/k2-fsa/sherpa-onnx/releases/download/asr-models/sherpa-onnx-wenetspeech-yue-u2pp-conformer-ctc-zh-en-cantonese-int8-2025-09-10.tar.bz2 - tar xvf sherpa-onnx-wenetspeech-yue-u2pp-conformer-ctc-zh-en-cantonese-int8-2025-09-10.tar.bz2 - rm sherpa-onnx-wenetspeech-yue-u2pp-conformer-ctc-zh-en-cantonese-int8-2025-09-10.tar.bz2 +if [ ! -f "sherpa-onnx-wenetspeech-yue-u2pp-conformer-ctc-zh-en-cantonese-int8-2025-09-10/model.int8.onnx" ]; then + curl -fSL -O "https://github.com/k2-fsa/sherpa-onnx/releases/download/asr-models/sherpa-onnx-wenetspeech-yue-u2pp-conformer-ctc-zh-en-cantonese-int8-2025-09-10.tar.bz2" + tar xvf "sherpa-onnx-wenetspeech-yue-u2pp-conformer-ctc-zh-en-cantonese-int8-2025-09-10.tar.bz2" + rm -f "sherpa-onnx-wenetspeech-yue-u2pp-conformer-ctc-zh-en-cantonese-int8-2025-09-10.tar.bz2" fi @@ -./non-streaming-decode-files \ - --wenet-ctc ./sherpa-onnx-wenetspeech-yue-u2pp-conformer-ctc-zh-en-cantonese-int8-2025-09-10/model.int8.onnx \ - --tokens ./sherpa-onnx-wenetspeech-yue-u2pp-conformer-ctc-zh-en-cantonese-int8-2025-09-10/tokens.txt \ +./non-streaming-decode-files \ + --wenet-ctc "./sherpa-onnx-wenetspeech-yue-u2pp-conformer-ctc-zh-en-cantonese-int8-2025-09-10/model.int8.onnx" \ + --tokens "./sherpa-onnx-wenetspeech-yue-u2pp-conformer-ctc-zh-en-cantonese-int8-2025-09-10/tokens.txt" \ --debug 0 \ - ./sherpa-onnx-wenetspeech-yue-u2pp-conformer-ctc-zh-en-cantonese-int8-2025-09-10/test_wavs/yue-0.wav + "./sherpa-onnx-wenetspeech-yue-u2pp-conformer-ctc-zh-en-cantonese-int8-2025-09-10/test_wavs/yue-0.wav"scripts/go/sherpa_onnx.go (1)
587-588: Populates C config for wenet_ctc — LGTM; consider nil vs empty semantics.If empty path is meaningful, you may pass nil instead of empty string for some C callers. Current pattern uses empty strings elsewhere, so keeping consistent is fine.
scripts/dotnet/OfflineWenetCtcModelConfig.cs (1)
1-19: Prefer UTF-8 marshalling and avoid struct ctor if targeting older C#/.NET.
- File paths can contain non-ASCII; use UTF-8 to match C side expectations.
- Parameterless struct constructors require modern C#; not strictly needed here.
Apply:
- [StructLayout(LayoutKind.Sequential)] + [StructLayout(LayoutKind.Sequential)] public struct OfflineWenetCtcModelConfig { - public OfflineWenetCtcModelConfig() - { - Model = ""; - } - [MarshalAs(UnmanagedType.LPStr)] + // NOTE: Switch to LPUTF8Str if other structs already use UTF-8. + [MarshalAs(UnmanagedType.LPUTF8Str)] public string Model; }If the rest of the binding uses LPStr intentionally, keep it consistent and skip the change.
pascal-api-examples/non-streaming-asr/wenet_ctc.pas (1)
35-76: Add basic error handling and guaranteed cleanup.
- Check that the wave loaded successfully before decoding.
- Use try/finally to always free Stream/Recognizer.
Apply:
Wave := SherpaOnnxReadWave(WaveFilename); - Recognizer := TSherpaOnnxOfflineRecognizer.Create(Config); - Stream := Recognizer.CreateStream(); - Start := Now; + if (Wave.SampleRate = 0) or (Length(Wave.Samples) = 0) then + begin + WriteLn('Failed to read wave or empty audio: ', WaveFilename); + Exit; + end; + + Recognizer := TSherpaOnnxOfflineRecognizer.Create(Config); + try + Stream := Recognizer.CreateStream(); + try + Start := Now; @@ - FreeAndNil(Stream); - FreeAndNil(Recognizer); + finally + FreeAndNil(Stream); + end; + finally + FreeAndNil(Recognizer); + end;If
TSherpaOnnxWaverequires explicit disposal in your wrapper, free it as well.pascal-api-examples/non-streaming-asr/run-wenet-ctc.sh (1)
1-43: Tighten script robustness and portability.
- Use stricter shell options; quote paths; parallelize build.
Apply:
-#!/usr/bin/env bash -set -ex +#!/usr/bin/env bash +set -Eeuo pipefail +IFS=$'\n\t' @@ -SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) -SHERPA_ONNX_DIR=$(cd $SCRIPT_DIR/../.. && pwd) +SCRIPT_DIR="$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )" +SHERPA_ONNX_DIR="$(cd "$SCRIPT_DIR"/../.. && pwd)" @@ -if [[ ! -f ../../build/install/lib/libsherpa-onnx-c-api.dylib && ! -f ../../build/install/lib/libsherpa-onnx-c-api.so && ! -f ../../build/install/lib/sherpa-onnx-c-api.dll ]]; then - mkdir -p ../../build - pushd ../../build +if [[ ! -f ../../build/install/lib/libsherpa-onnx-c-api.dylib && ! -f ../../build/install/lib/libsherpa-onnx-c-api.so && ! -f ../../build/install/lib/sherpa-onnx-c-api.dll ]]; then + mkdir -p ../../build + pushd ../../build cmake \ -DCMAKE_INSTALL_PREFIX=./install \ @@ - cmake --build . --target install --config Release + cmake --build . --target install --config Release -- -j"$(getconf _NPROCESSORS_ONLN 2>/dev/null || echo 2)" ls -lh lib popd fi @@ -if [ ! -f sherpa-onnx-wenetspeech-yue-u2pp-conformer-ctc-zh-en-cantonese-int8-2025-09-10/model.int8.onnx ]; then - curl -SL -O https://github.com/k2-fsa/sherpa-onnx/releases/download/asr-models/sherpa-onnx-wenetspeech-yue-u2pp-conformer-ctc-zh-en-cantonese-int8-2025-09-10.tar.bz2 - tar xvf sherpa-onnx-wenetspeech-yue-u2pp-conformer-ctc-zh-en-cantonese-int8-2025-09-10.tar.bz2 - rm sherpa-onnx-wenetspeech-yue-u2pp-conformer-ctc-zh-en-cantonese-int8-2025-09-10.tar.bz2 +if [ ! -f "sherpa-onnx-wenetspeech-yue-u2pp-conformer-ctc-zh-en-cantonese-int8-2025-09-10/model.int8.onnx" ]; then + curl -fSL -O "https://github.com/k2-fsa/sherpa-onnx/releases/download/asr-models/sherpa-onnx-wenetspeech-yue-u2pp-conformer-ctc-zh-en-cantonese-int8-2025-09-10.tar.bz2" + tar xvf "sherpa-onnx-wenetspeech-yue-u2pp-conformer-ctc-zh-en-cantonese-int8-2025-09-10.tar.bz2" + rm -f "sherpa-onnx-wenetspeech-yue-u2pp-conformer-ctc-zh-en-cantonese-int8-2025-09-10.tar.bz2" fi @@ -fpc \ +fpc \ -dSHERPA_ONNX_USE_SHARED_LIBS \ - -Fu$SHERPA_ONNX_DIR/sherpa-onnx/pascal-api \ - -Fl$SHERPA_ONNX_DIR/build/install/lib \ + -Fu"$SHERPA_ONNX_DIR/sherpa-onnx/pascal-api" \ + -Fl"$SHERPA_ONNX_DIR/build/install/lib" \ ./wenet_ctc.pas @@ -export LD_LIBRARY_PATH=$SHERPA_ONNX_DIR/build/install/lib:$LD_LIBRARY_PATH -export DYLD_LIBRARY_PATH=$SHERPA_ONNX_DIR/build/install/lib:$DYLD_LIBRARY_PATH +export LD_LIBRARY_PATH="$SHERPA_ONNX_DIR/build/install/lib:${LD_LIBRARY_PATH:-}" +export DYLD_LIBRARY_PATH="$SHERPA_ONNX_DIR/build/install/lib:${DYLD_LIBRARY_PATH:-}".github/scripts/test-dart.sh (1)
73-76: Narrow cleanup to model-specific artifacts to avoid collateral deletions.
Safer to avoid removing unrelated “sherpa-onnx-*” files that may be needed later.Apply:
-rm -rf sherpa-onnx-* +rm -rf sherpa-onnx-wenetspeech-*.github/workflows/c-api.yaml (1)
78-107: Harden the step with strict bash flagsUse -euo pipefail early to fail fast on errors.
- - name: Test Wenet CTC - shell: bash - run: | + - name: Test Wenet CTC + shell: bash + run: | + set -euo pipefail name=wenet-ctc-c-api.github/scripts/test-dot-net.sh (1)
30-32: Narrow cleanup to reduce re-downloadsLimit deletion to the Wenet model to save CI time/bandwidth.
-./run-wenet-ctc.sh -rm -rf sherpa-onnx-* +./run-wenet-ctc.sh +rm -rf sherpa-onnx-wenetspeech-*.github/workflows/cxx-api.yaml (1)
81-114: Harden the step with strict bash flagsAdd -euo pipefail at the start of the run block.
- - name: Test Wenet CTC - shell: bash - run: | + - name: Test Wenet CTC + shell: bash + run: | + set -euo pipefail name=wenet-ctc-cxx-apikotlin-api-examples/run.sh (1)
492-511: Kotlin Wenet CTC test — LGTM; add cleanup to keep workspace tidyOptional: remove the extracted model after the run.
ls -lh $out_filename java -Djava.library.path=../build/lib -jar $out_filename + + rm -rf sherpa-onnx-wenetspeech-* }cxx-api-examples/wenet-ctc-cxx-api.cc (2)
1-1: Fix file header path typo.Header says wenet-cxx-api.cc but the file is wenet-ctc-cxx-api.cc.
-// cxx-api-examples/wenet-cxx-api.cc +// cxx-api-examples/wenet-ctc-cxx-api.cc
52-53: Avoid implicit narrowing when passing sample count.AcceptWaveform usually takes int32_t for num_samples; passing size_t may trigger narrowing. Cast explicitly.
- stream.AcceptWaveform(wave.sample_rate, wave.samples.data(), - wave.samples.size()); + stream.AcceptWaveform(wave.sample_rate, wave.samples.data(), + static_cast<int32_t>(wave.samples.size()));.github/scripts/test-nodejs-addon-npm.sh (1)
15-17: Harden downloads with fail-fast and retries.Use curl --fail and retries to reduce flakiness.
-curl -SL -O https://github.com/k2-fsa/sherpa-onnx/releases/download/asr-models/sherpa-onnx-wenetspeech-yue-u2pp-conformer-ctc-zh-en-cantonese-int8-2025-09-10.tar.bz2 +curl -fSL --retry 3 --retry-delay 2 -O https://github.com/k2-fsa/sherpa-onnx/releases/download/asr-models/sherpa-onnx-wenetspeech-yue-u2pp-conformer-ctc-zh-en-cantonese-int8-2025-09-10.tar.bz2dotnet-examples/offline-decode-files/Program.cs (1)
87-89: Add usage snippet for --wenet-ctc in DisplayHelp.Helps users discover the new mode.
Example to append to the usage string (outside the changed lines):
# Wenet CTC dotnet run \ --tokens=./sherpa-onnx-wenetspeech-yue-u2pp-conformer-ctc-zh-en-cantonese-int8-2025-09-10/tokens.txt \ --wenet-ctc=./sherpa-onnx-wenetspeech-yue-u2pp-conformer-ctc-zh-en-cantonese-int8-2025-09-10/model.int8.onnx \ --files ./sherpa-onnx-wenetspeech-yue-u2pp-conformer-ctc-zh-en-cantonese-int8-2025-09-10/test_wavs/yue-0.wavswift-api-examples/run-wenet-ctc-asr.sh (2)
10-14: Improve curl robustness.Add fail-fast and retries to cut CI flakes.
- curl -SL -O https://github.com/k2-fsa/sherpa-onnx/releases/download/asr-models/sherpa-onnx-wenetspeech-yue-u2pp-conformer-ctc-zh-en-cantonese-int8-2025-09-10.tar.bz2 + curl -fSL --retry 3 --retry-delay 2 -O https://github.com/k2-fsa/sherpa-onnx/releases/download/asr-models/sherpa-onnx-wenetspeech-yue-u2pp-conformer-ctc-zh-en-cantonese-int8-2025-09-10.tar.bz2
33-34: Quote DYLD_LIBRARY_PATH to avoid word-splitting.-export DYLD_LIBRARY_PATH=$PWD/../build-swift-macos/install/lib:$DYLD_LIBRARY_PATH +export DYLD_LIBRARY_PATH="$PWD/../build-swift-macos/install/lib:${DYLD_LIBRARY_PATH:-}"dart-api-examples/non-streaming-asr/bin/wenet-ctc.dart (1)
25-28: Validate inputs early for clearer errors.Check file existence before attempting load to provide actionable messages.
final model = res['model'] as String; final tokens = res['tokens'] as String; final inputWav = res['input-wav'] as String; +for (final p in [model, tokens, inputWav]) { + if (!File(p).existsSync()) { + stderr.writeln('Not found: $p'); + exit(2); + } +}nodejs-addon-examples/test_asr_non_streaming_wenet_ctc.js (1)
47-48: Log only the transcription text.Printing the whole object is noisy; print result.text.
-console.log('result\n', result) +console.log('text:', result.text)sherpa-onnx/kotlin-api/OfflineRecognizer.kt (2)
192-223: Update the type documentation block.
The comment enumerating types (0–41) isn’t updated to include type 42 (Wenet CTC). Add an entry to prevent drift between code and docs.-223 */ +223 42 - sherpa-onnx-wenetspeech-yue-u2pp-conformer-ctc-zh-en-cantonese-int8-2025-09-10 (Cantonese) +224 Wenet CTC, model int8 +225 */
714-722: Consider setting modelType for Wenet CTC.
Some callers branch onmodelType. If applicable, set it (e.g.,"wenet_ctc") for parity with other entries that tag their type.return OfflineModelConfig( wenetCtc = OfflineWenetCtcModelConfig( model = "$modelDir/model.int8.onnx", ), tokens = "$modelDir/tokens.txt", + modelType = "wenet_ctc", )swift-api-examples/wenet-ctc-asr.swift (1)
15-41: Minor: make local paths configurable.
Optional: accept model/tokens/wav via env or args to ease CI reuse.dart-api-examples/non-streaming-asr/run-wenet-ctc.sh (1)
1-19: Make script path-stable and stricter.
Addcdto script dir and-u -o pipefailfor robustness, especially in CI.-#!/usr/bin/env bash -set -ex +#!/usr/bin/env bash +set -euo pipefail +set -x +cd "$(dirname "$0")"c-api-examples/wenet-ctc-c-api.c (2)
36-41: Comment nit: not Zipformer.
Rename to “Wenet CTC config” to avoid confusion.- // Zipformer config + // Wenet CTC config
30-35: Add sample rate validation.
Most models expect 16 kHz. Warn early to avoid misleading results.const SherpaOnnxWave *wave = SherpaOnnxReadWave(wav_filename); if (wave == NULL) { fprintf(stderr, "Failed to read %s\n", wav_filename); return -1; } + if (wave->sample_rate != 16000) { + fprintf(stderr, "Warning: expected 16000 Hz, got %d Hz\n", wave->sample_rate); + }dotnet-examples/offline-decode-files/run-wenet-ctc.sh (1)
1-15: Optional: make script path-stable.
Addcdto script dir for reliable relative paths.-#!/usr/bin/env bash -set -ex +#!/usr/bin/env bash +set -ex +cd "$(dirname "$0")"kotlin-api-examples/test_offline_wenet_ctc.kt (2)
5-5: Avoid hard-coded, date-stamped paths in examples.Consider deriving
waveFilenamefrom a base dir or CLI arg to reduce churn.- val waveFilename = "./sherpa-onnx-wenetspeech-yue-u2pp-conformer-ctc-zh-en-cantonese-int8-2025-09-10/test_wavs/yue-0.wav" + val baseDir = System.getenv("WENET_CTC_DIR") ?: "./sherpa-onnx-wenetspeech-yue-u2pp-conformer-ctc-zh-en-cantonese-int8-2025-09-10" + val waveFilename = "$baseDir/test_wavs/yue-0.wav"
17-18: Print only the recognized text
In test_offline_wenet_ctc.kt (around line 17),getResult(stream)returns anOfflineRecognizerResultwith atextfield. Replaceprintln(result)with
println(result.text)to match other examples.
java-api-examples/NonStreamingDecodeFileWenetCtc.java (1)
13-21: Minor: reduce duplication with a base directory.- String model = - "sherpa-onnx-wenetspeech-yue-u2pp-conformer-ctc-zh-en-cantonese-int8-2025-09-10/model.int8.onnx"; - String tokens = - "sherpa-onnx-wenetspeech-yue-u2pp-conformer-ctc-zh-en-cantonese-int8-2025-09-10/tokens.txt"; - String waveFilename = - "sherpa-onnx-wenetspeech-yue-u2pp-conformer-ctc-zh-en-cantonese-int8-2025-09-10/test_wavs/yue-0.wav"; + String base = "sherpa-onnx-wenetspeech-yue-u2pp-conformer-ctc-zh-en-cantonese-int8-2025-09-10"; + String model = base + "/model.int8.onnx"; + String tokens = base + "/tokens.txt"; + String waveFilename = base + "/test_wavs/yue-0.wav";wasm/nodejs/sherpa-onnx-wasm-nodejs.cc (1)
39-41: Keep size assert in sync with the C API struct order.If fields are added/removed in
SherpaOnnxOfflineModelConfig, this sum must be updated.Consider adding a comment mirroring the exact field order from
c-api.habove this assert to reduce drift.cxx-api-examples/wenet-ctc-simulate-streaming-microphone-cxx-api.cc (3)
127-131: Log the requested mic sample rate after parsingYou print the old value (16000) before parsing the env var.
- if (sample_rate_str) { - fprintf(stderr, "Use sample rate %f for mic\n", mic_sample_rate); - mic_sample_rate = atof(sample_rate_str); - } + if (sample_rate_str) { + mic_sample_rate = static_cast<float>(atof(sample_rate_str)); + fprintf(stderr, "Use sample rate %f for mic\n", mic_sample_rate); + }
38-42: Signal-safety: avoid non-async-signal-safe ops in SIGINT handler
condition_variable.notify_one()andfprintfaren’t signal-safe. Prefer setting an atomic flag and let the main thread handle logging/notify.-std::condition_variable condition_variable; -std::mutex mutex; -bool stop = false; +std::condition_variable condition_variable; +std::mutex mutex; +std::atomic<bool> stop{false}; static void Handler(int32_t /*sig*/) { - stop = true; - condition_variable.notify_one(); - fprintf(stderr, "\nCaught Ctrl + C. Exiting...\n"); + stop.store(true, std::memory_order_relaxed); }Then print and notify in the main loop when
stop.load()becomes true.
111-116: Handle PortAudio errors and update guidance text
Microphone()callsPa_Initialize()beforePa_GetDeviceCount(), so ordering is correct.- Change the check to
<= 0to catch negative error codes.- Update the Linux guidance to reference
wenet-ctc-simulate-streaming-alsa-cxx-api.PaDeviceIndex num_devices = Pa_GetDeviceCount(); - if (num_devices == 0) { + if (num_devices <= 0) { std::cerr << " If you are using Linux, please try " - "./build/bin/sense-voice-simulate-streaming-alsa-cxx-api\n"; + "./build/bin/wenet-ctc-simulate-streaming-alsa-cxx-api\n"; return -1; }wasm/asr/sherpa-onnx-asr.js (1)
740-756: init offline Wenet CTC config — LGTM; consider deduping 1-field initializersImplementation matches other single-string model configs. To reduce duplication across zipformerCtc/nemo/dolphin/tdnn/wenetCtc, consider a small helper (e.g., initSinglePathModelConfig) to return {buffer, ptr, len}.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (58)
.github/scripts/test-dart.sh(1 hunks).github/scripts/test-dot-net.sh(2 hunks).github/scripts/test-nodejs-addon-npm.sh(1 hunks).github/scripts/test-nodejs-npm.sh(1 hunks).github/scripts/test-swift.sh(1 hunks).github/workflows/c-api.yaml(1 hunks).github/workflows/cxx-api.yaml(1 hunks).github/workflows/test-go.yaml(1 hunks).gitignore(1 hunks)c-api-examples/CMakeLists.txt(1 hunks)c-api-examples/wenet-ctc-c-api.c(1 hunks)cxx-api-examples/CMakeLists.txt(2 hunks)cxx-api-examples/wenet-ctc-cxx-api.cc(1 hunks)cxx-api-examples/wenet-ctc-simulate-streaming-microphone-cxx-api.cc(1 hunks)dart-api-examples/non-streaming-asr/bin/wenet-ctc.dart(1 hunks)dart-api-examples/non-streaming-asr/run-wenet-ctc.sh(1 hunks)dotnet-examples/offline-decode-files/Program.cs(2 hunks)dotnet-examples/offline-decode-files/run-wenet-ctc.sh(1 hunks)flutter/sherpa_onnx/lib/src/offline_recognizer.dart(8 hunks)flutter/sherpa_onnx/lib/src/sherpa_onnx_bindings.dart(2 hunks)go-api-examples/non-streaming-decode-files/main.go(1 hunks)go-api-examples/non-streaming-decode-files/run-wenet-ctc.sh(1 hunks)harmony-os/SherpaOnnxHar/sherpa_onnx/Index.ets(1 hunks)harmony-os/SherpaOnnxHar/sherpa_onnx/src/main/cpp/non-streaming-asr.cc(3 hunks)harmony-os/SherpaOnnxHar/sherpa_onnx/src/main/ets/components/NonStreamingAsr.ets(2 hunks)java-api-examples/NonStreamingDecodeFileWenetCtc.java(1 hunks)java-api-examples/run-non-streaming-decode-file-wenet-ctc.sh(1 hunks)kotlin-api-examples/run.sh(1 hunks)kotlin-api-examples/test_offline_wenet_ctc.kt(1 hunks)nodejs-addon-examples/README.md(2 hunks)nodejs-addon-examples/test_asr_non_streaming_wenet_ctc.js(1 hunks)nodejs-examples/README.md(1 hunks)nodejs-examples/test-offline-wenet-ctc.js(1 hunks)pascal-api-examples/non-streaming-asr/.gitignore(1 hunks)pascal-api-examples/non-streaming-asr/run-wenet-ctc.sh(1 hunks)pascal-api-examples/non-streaming-asr/wenet_ctc.pas(1 hunks)scripts/apk/generate-asr-2pass-apk-script.py(3 hunks)scripts/apk/generate-vad-asr-apk-script.py(1 hunks)scripts/dotnet/OfflineModelConfig.cs(2 hunks)scripts/dotnet/OfflineWenetCtcModelConfig.cs(1 hunks)scripts/go/_internal/non-streaming-decode-files/run-wenet-ctc.sh(1 hunks)scripts/go/sherpa_onnx.go(4 hunks)sherpa-onnx/c-api/c-api.cc(1 hunks)sherpa-onnx/c-api/c-api.h(2 hunks)sherpa-onnx/c-api/cxx-api.cc(1 hunks)sherpa-onnx/c-api/cxx-api.h(2 hunks)sherpa-onnx/java-api/Makefile(1 hunks)sherpa-onnx/java-api/src/main/java/com/k2fsa/sherpa/onnx/OfflineModelConfig.java(5 hunks)sherpa-onnx/java-api/src/main/java/com/k2fsa/sherpa/onnx/OfflineWenetCtcModelConfig.java(1 hunks)sherpa-onnx/jni/offline-recognizer.cc(1 hunks)sherpa-onnx/kotlin-api/OfflineRecognizer.kt(3 hunks)sherpa-onnx/pascal-api/sherpa_onnx.pas(7 hunks)swift-api-examples/.gitignore(1 hunks)swift-api-examples/SherpaOnnx.swift(3 hunks)swift-api-examples/run-wenet-ctc-asr.sh(1 hunks)swift-api-examples/wenet-ctc-asr.swift(1 hunks)wasm/asr/sherpa-onnx-asr.js(5 hunks)wasm/nodejs/sherpa-onnx-wasm-nodejs.cc(4 hunks)
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-08-06T04:18:47.981Z
Learnt from: litongjava
PR: k2-fsa/sherpa-onnx#2440
File: sherpa-onnx/java-api/src/main/java/com/k2fsa/sherpa/onnx/core/Core.java:4-6
Timestamp: 2025-08-06T04:18:47.981Z
Learning: In sherpa-onnx Java API, the native library names in Core.java (WIN_NATIVE_LIBRARY_NAME = "sherpa-onnx-jni.dll", UNIX_NATIVE_LIBRARY_NAME = "libsherpa-onnx-jni.so", MACOS_NATIVE_LIBRARY_NAME = "libsherpa-onnx-jni.dylib") are copied directly from the compiled binary filenames and should not be changed to match other libraries' naming conventions.
Applied to files:
java-api-examples/run-non-streaming-decode-file-wenet-ctc.sh
📚 Learning: 2025-08-06T04:23:50.237Z
Learnt from: litongjava
PR: k2-fsa/sherpa-onnx#2440
File: sherpa-onnx/java-api/src/main/java/com/k2fsa/sherpa/onnx/core/Core.java:4-6
Timestamp: 2025-08-06T04:23:50.237Z
Learning: The sherpa-onnx JNI library files are stored in Hugging Face repository at https://huggingface.co/csukuangfj/sherpa-onnx-libs under versioned directories like jni/1.12.7/, and the actual Windows JNI library filename is "sherpa-onnx-jni.dll" as defined in Core.java constants.
Applied to files:
java-api-examples/run-non-streaming-decode-file-wenet-ctc.sh.gitignore
🧬 Code graph analysis (14)
java-api-examples/NonStreamingDecodeFileWenetCtc.java (2)
cxx-api-examples/wenet-ctc-cxx-api.cc (2)
main(21-75)main(21-21)sherpa-onnx/java-api/src/main/java/com/k2fsa/sherpa/onnx/OfflineModelConfig.java (1)
OfflineModelConfig(5-245)
sherpa-onnx/c-api/cxx-api.h (4)
scripts/go/sherpa_onnx.go (1)
OfflineWenetCtcModelConfig(421-423)sherpa-onnx/java-api/src/main/java/com/k2fsa/sherpa/onnx/OfflineWenetCtcModelConfig.java (1)
OfflineWenetCtcModelConfig(3-30)wasm/asr/sherpa-onnx-asr.js (2)
model(436-436)model(1257-1257)sherpa-onnx/kotlin-api/OfflineRecognizer.kt (6)
model(23-25)model(27-29)model(31-33)model(35-37)model(39-41)model(71-75)
scripts/go/sherpa_onnx.go (1)
sherpa-onnx/c-api/cxx-api.h (1)
OfflineWenetCtcModelConfig(267-269)
c-api-examples/wenet-ctc-c-api.c (1)
cxx-api-examples/wenet-ctc-cxx-api.cc (2)
main(21-75)main(21-21)
sherpa-onnx/kotlin-api/OfflineRecognizer.kt (5)
scripts/go/sherpa_onnx.go (2)
OfflineWenetCtcModelConfig(421-423)OfflineModelConfig(473-503)sherpa-onnx/c-api/cxx-api.h (2)
OfflineWenetCtcModelConfig(267-269)OfflineModelConfig(278-300)sherpa-onnx/java-api/src/main/java/com/k2fsa/sherpa/onnx/OfflineWenetCtcModelConfig.java (1)
OfflineWenetCtcModelConfig(3-30)sherpa-onnx/java-api/src/main/java/com/k2fsa/sherpa/onnx/OfflineModelConfig.java (1)
OfflineModelConfig(5-245)scripts/dotnet/OfflineModelConfig.cs (1)
OfflineModelConfig(11-33)
scripts/dotnet/OfflineModelConfig.cs (3)
scripts/go/sherpa_onnx.go (1)
OfflineWenetCtcModelConfig(421-423)scripts/dotnet/OfflineWenetCtcModelConfig.cs (1)
OfflineWenetCtcModelConfig(11-14)sherpa-onnx/c-api/cxx-api.h (1)
OfflineWenetCtcModelConfig(267-269)
swift-api-examples/wenet-ctc-asr.swift (1)
swift-api-examples/SherpaOnnx.swift (4)
sherpaOnnxOfflineWenetCtcModelConfig(363-369)sherpaOnnxOfflineModelConfig(473-519)sherpaOnnxFeatureConfig(133-140)sherpaOnnxOfflineRecognizerConfig(521-547)
sherpa-onnx/java-api/src/main/java/com/k2fsa/sherpa/onnx/OfflineModelConfig.java (2)
sherpa-onnx/c-api/cxx-api.h (1)
OfflineWenetCtcModelConfig(267-269)sherpa-onnx/java-api/src/main/java/com/k2fsa/sherpa/onnx/OfflineWenetCtcModelConfig.java (1)
OfflineWenetCtcModelConfig(3-30)
sherpa-onnx/java-api/src/main/java/com/k2fsa/sherpa/onnx/OfflineWenetCtcModelConfig.java (3)
sherpa-onnx/c-api/cxx-api.h (1)
OfflineWenetCtcModelConfig(267-269)sherpa-onnx/kotlin-api/OfflineRecognizer.kt (6)
model(23-25)model(27-29)model(31-33)model(35-37)model(39-41)model(71-75)sherpa-onnx/java-api/src/main/java/com/k2fsa/sherpa/onnx/OfflineModelConfig.java (1)
Builder(125-244)
swift-api-examples/SherpaOnnx.swift (2)
wasm/asr/sherpa-onnx-asr.js (3)
model(436-436)model(1257-1257)wenetCtc(1108-1109)sherpa-onnx/kotlin-api/OfflineRecognizer.kt (6)
model(23-25)model(27-29)model(31-33)model(35-37)model(39-41)model(71-75)
scripts/apk/generate-vad-asr-apk-script.py (1)
scripts/hap/generate-vad-asr-hap-script.py (1)
Model(28-48)
scripts/apk/generate-asr-2pass-apk-script.py (1)
scripts/apk/generate-asr-apk-script.py (1)
Model(27-44)
wasm/asr/sherpa-onnx-asr.js (1)
sherpa-onnx/kotlin-api/OfflineRecognizer.kt (1)
transducer(77-97)
harmony-os/SherpaOnnxHar/sherpa_onnx/src/main/cpp/non-streaming-asr.cc (2)
wasm/asr/sherpa-onnx-asr.js (2)
model(436-436)model(1257-1257)sherpa-onnx/kotlin-api/OfflineRecognizer.kt (6)
model(23-25)model(27-29)model(31-33)model(35-37)model(39-41)model(71-75)
🪛 SwiftLint (0.57.0)
swift-api-examples/wenet-ctc-asr.swift
[Error] 45-45: Force tries should be avoided
(force_try)
[Error] 54-54: Force tries should be avoided
(force_try)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (20)
- GitHub Check: ubuntu-latest Release static tts-OFF
- GitHub Check: ubuntu-latest Debug shared tts-ON
- GitHub Check: ubuntu-latest Debug static tts-ON
- GitHub Check: ubuntu-latest Release shared tts-OFF
- GitHub Check: ubuntu-latest Release shared tts-ON
- GitHub Check: rknn shared OFF
- GitHub Check: rknn shared ON
- GitHub Check: Debug shared-ON tts-OFF
- GitHub Check: Debug shared-OFF tts-ON
- GitHub Check: Debug shared-ON tts-ON
- GitHub Check: Debug shared-OFF tts-OFF
- GitHub Check: Release shared-OFF tts-OFF
- GitHub Check: Release shared-OFF tts-ON
- GitHub Check: Release shared-ON tts-ON
- GitHub Check: Release shared-ON tts-OFF
- GitHub Check: swift (macos-13)
- GitHub Check: swift (macos-latest)
- GitHub Check: Debug static tts-OFF
- GitHub Check: Release static tts-ON
- GitHub Check: Release shared tts-OFF
🔇 Additional comments (63)
scripts/apk/generate-asr-2pass-apk-script.py (2)
416-417: Good: new 2nd-model listed for zh combosThe Cantonese Wenet CTC model is now included in second_zh; name matches the object defined above.
443-446: Resolved: Kotlin mapping for idx 42 is present
Thewhen (type)block inOfflineRecognizer.ktincludes a42 ->case that returns the new Wenet CTC model config (lines 714–719), so no further changes are needed.swift-api-examples/.gitignore (1)
22-22: Add ignore for generated Swift example binary — LGTMIgnoring
wenet-ctc-asraligns with the new Swift example. No issues.pascal-api-examples/non-streaming-asr/.gitignore (1)
13-13: Add ignore for Pascal Wenet CTC artifact — LGTM
wenet_ctcmatches the example naming; good hygiene.sherpa-onnx/c-api/c-api.cc (1)
509-511: Wire Wenet CTC into offline recognizer config — LGTMThe field mirrors other offline CTC entries and uses the existing defaulting macro. Ensure corresponding headers/structs (c_api.h / cxx-api.*) already expose
wenet_ctc.modelto keep ABI surface consistent.nodejs-examples/test-offline-wenet-ctc.js (1)
9-22: Config and recognizer creation — LGTMPaths and object wiring look correct for offline Wenet CTC.
sherpa-onnx/c-api/c-api.h (1)
508-509: Bindings updated — ABI change verified. All first-party bindings (Go/Java/Kotlin/.NET/Swift/Dart/WASM/Pascal/C++) now include the newwenet_ctcfield. Release the C API with a bumped minor/ABI version for external consumers (or note the break) and consider adding padding fields in future to minimize layout churn.scripts/apk/generate-vad-asr-apk-script.py (2)
714-716: Good catch adding the missing popd.Prevents directory context leaks in subsequent steps.
717-731: Quotemodel_nameand verifyidxmapping- pushd $model_name + pushd "$model_name"No occurrences of
idx = 42were found in the Kotlin/Java code paths; ensure your switch/case (or equivalent) handling includes42so this model is selectable.scripts/go/sherpa_onnx.go (3)
421-424: Go: New OfflineWenetCtcModelConfig type — LGTM.Matches C/C++ shape and naming; minimal and consistent.
485-485: Wires WenetCtc into OfflineModelConfig — LGTM.Field placement aligns with C struct (after Canary).
737-740: Frees wenet_ctc.model — LGTM.Balances allocation in newCOfflineRecognizerConfig; avoids leaks.
swift-api-examples/SherpaOnnx.swift (2)
363-369: Adds helper for OfflineWenetCtcModelConfig — LGTM.Consistent with other config builder helpers.
494-519: Offline model config now includes wenet_ctc — LGTM.Ordering matches the C struct; no issues spotted.
sherpa-onnx/java-api/Makefile (1)
39-39: Wires OfflineWenetCtcModelConfig into the build — looks good.
The new Java config class will be compiled and packaged with the jar. No further action here.sherpa-onnx/c-api/cxx-api.cc (1)
268-269: Correct propagation of wenet_ctc model path.
The new field is mapped as expected in Convert(). Good..github/scripts/test-swift.sh (1)
22-24: Adds Wenet CTC test stage before Zipformer — looks good.
Sequence and cleanup are consistent with the rest of the script.sherpa-onnx/c-api/cxx-api.h (2)
267-270: New OfflineWenetCtcModelConfig — OK.
Matches patterns of other offline single-file CTC configs.
299-300: Confirmed C struct matches C++ field order
The C structSherpaOnnxOfflineModelConfigdefineswenet_ctcas its final field (line 508), exactly matching the C++OfflineModelConfiglayout—no ABI mismatches.sherpa-onnx/jni/offline-recognizer.cc (1)
287-299: JNI: Reads wenetCtc.model correctly.
Field/class lookups and string lifetimes are handled consistently with other configs.c-api-examples/CMakeLists.txt (1)
83-85: Add Wenet CTC example target — LGTMConsistent with surrounding examples and linkage.
scripts/dotnet/OfflineModelConfig.cs (2)
32-33: Constructor init — LGTMInitializing WenetCtc keeps default layout well-defined.
68-69: Remove suggestion: attributes already present – TheOfflineWenetCtcModelConfigstruct is already annotated with[StructLayout(LayoutKind.Sequential)]and itsModelfield has[MarshalAs(UnmanagedType.LPStr)], so no changes are needed.Likely an incorrect or invalid review comment.
.github/scripts/test-dot-net.sh (1)
114-116: Add T-one online test — LGTMPlacement and cleanup are consistent with other steps.
flutter/sherpa_onnx/lib/src/sherpa_onnx_bindings.dart (1)
284-287: New FFI config struct — LGTMPointer matches C char* expectation.
kotlin-api-examples/run.sh (1)
515-516: Invocation order — LGTMRuns early, before other offline ASR tests.
nodejs-addon-examples/README.md (1)
127-128: README table entry for Wenet CTC — LGTMMatches the new example filename and model link.
.github/scripts/test-nodejs-addon-npm.sh (1)
13-21: LGTM — adds non-streaming Wenet CTC test step.Sequence and cleanup look correct; runs from the expected cwd.
dotnet-examples/offline-decode-files/Program.cs (2)
87-89: Option wiring looks correct.New --wenet-ctc option name, help text, and default align with the pattern used elsewhere.
257-260: Correct model selection branch.Sets config.ModelConfig.WenetCtc.Model when --wenet-ctc is provided. Consistent with other CTC branches.
harmony-os/SherpaOnnxHar/sherpa_onnx/src/main/ets/components/NonStreamingAsr.ets (2)
63-66: LGTM — new OfflineWenetCtcModelConfig type.Name and shape match other offline single-file CTC configs.
119-119: LGTM — plumbs wenetCtc into OfflineModelConfig.Keeps parity with other bindings.
sherpa-onnx/kotlin-api/OfflineRecognizer.kt (2)
39-41: New Wenet CTC config looks good.
Simple, consistent with other model config data classes.
77-97: OfflineModelConfig: field wiring is consistent.
wenetCtcdefault and placement align with other fields. JNI side should already read it.swift-api-examples/wenet-ctc-asr.swift (1)
47-50: Validate sample format more robustly.
Also guard sampleRate==16000 expected by examples to avoid silent quality issues.- assert(audioFormat.channelCount == 1) - assert(audioFormat.commonFormat == AVAudioCommonFormat.pcmFormatFloat32) + guard audioFormat.channelCount == 1, + audioFormat.commonFormat == .pcmFormatFloat32 else { + fputs("Expect mono 32-bit float WAV\n", stderr) + return + } + if Int(audioFormat.sampleRate) != 16000 { + fputs("Warning: sampleRate \(Int(audioFormat.sampleRate)) != 16000; results may degrade\n", stderr) + }java-api-examples/run-non-streaming-decode-file-wenet-ctc.sh (1)
5-20: Build guard is OK.
CMake/JNI flags and fallback build logic look fine.c-api-examples/wenet-ctc-c-api.c (1)
56-82: C example lifecycle/cleanup LGTM.
Config zeroing, decode, result retrieval, and frees are correct.sherpa-onnx/java-api/src/main/java/com/k2fsa/sherpa/onnx/OfflineModelConfig.java (1)
15-16: Wenet CTC field integration is correct.
New field, getter, builder default, and setter are consistent with existing patterns.Also applies to: 36-37, 85-87, 135-136, 175-178
sherpa-onnx/java-api/src/main/java/com/k2fsa/sherpa/onnx/OfflineWenetCtcModelConfig.java (1)
3-30: Minimal, immutable config class LGTM.
Builder pattern and accessor match the project’s style.java-api-examples/NonStreamingDecodeFileWenetCtc.java (2)
24-40: Config wiring looks correct for Wenet CTC + greedy decode.
10-13: Fix documentation link for WeNet CTC model download
Replace the SenseVoice URL with the correct WeNet CTC download page.File: java-api-examples/NonStreamingDecodeFileWenetCtc.java
Lines: 10–13- // https://k2-fsa.github.io/sherpa/onnx/sense-voice/index.html - // to download model files + // Refer to https://k2-fsa.github.io/sherpa/onnx/pretrained_models/wenet/index.html to download offline WeNet CTC model files.cxx-api-examples/CMakeLists.txt (2)
33-35: Add Wenet CTC C++ example target — looks good.
52-60: PortAudio microphone example for Wenet CTC — wiring is consistent with others.wasm/nodejs/sherpa-onnx-wasm-nodejs.cc (2)
88-89: LGTM: newwenet_ctcfield plumbed into the printer.
17-17: ConfirmedSherpaOnnxOfflineWenetCtcModelConfigstruct size: the C API defines it with exactly oneconst char *modelfield, sostatic_assert(sizeof(...)=4)is valid.harmony-os/SherpaOnnxHar/sherpa_onnx/src/main/cpp/non-streaming-asr.cc (3)
64-78: Add Wenet CTC parsing helper — LGTMZero-init, presence checks, and SHERPA_ONNX_ASSIGN_ATTR_STR usage are consistent with other model parsers.
244-244: Wire wenet_ctc into OfflineModelConfig — LGTMIntegration mirrors the ordering used for other sub-configs.
337-338: Free newly added wenet_ctc strings — LGTMCleanup matches allocation sites. No leaks observed for wenet_ctc.model.
wasm/asr/sherpa-onnx-asr.js (4)
54-56: Add free path for wenetCtc — LGTMRecursively freeing wenetCtc matches other sub-configs and prevents leaks.
1021-1026: Default wenetCtc block — LGTMEnsures stable shape when callers omit wenetCtc.
1221-1230: Copy wenetCtc into aggregate buffer and expose handle — LGTMOffset math and return object are consistent with previous sections.
1108-1114: No struct layout issue: wenet_ctc follows canary Verified in sherpa-onnx/c-api/c-api.h (lines 507–508) thatSherpaOnnxOfflineWenetCtcModelConfig wenet_ctc;immediately follows...CanaryModelConfig canary;, so offsets match.flutter/sherpa_onnx/lib/src/offline_recognizer.dart (3)
128-147: OfflineWenetCtcModelConfig: consistent and minimalMatches existing config patterns (const ctor, fromJson/toJson, toString). No issues.
373-373: Wire wenetCtc through OfflineModelConfig — LGTMConstructor default, JSON (in/out), and field are correctly added and consistent with other model configs.
Also applies to: 430-433, 462-462, 484-484
721-722: FFI allocation forwenetCtc.modelis correct
toNativeUtf8()is used at line 721 and the matchingcalloc.free()at line 769 mirrors the pattern for all other model fields, so no changes needed.sherpa-onnx/pascal-api/sherpa_onnx.pas (8)
316-320: New Wenet CTC config record is well-formed.Type mirrors existing model-config patterns and is consistent in naming.
395-395: OfflineModelConfig now exposes WenetCtc.Plumbed at the right level alongside other model families.
803-805: FFI record for Wenet CTC added correctly.Field type (PAnsiChar) matches convention used elsewhere.
862-862: FFI OfflineModelConfig includes WenetCtc.Placement aligns with the Pascal-side record.
1671-1676: ToString for Wenet CTC config looks good.Matches formatting used by sibling configs.
1766-1768: ModelConfig.ToString extended with Canary and WenetCtc—good coverage.Format specifiers and parameter ordering are consistent.
Also applies to: 1775-1776
1854-1855: Config conversion wires WenetCtc to the C struct.Correct PAnsiChar conversion; aligns with the rest of ConvertOfflineRecognizerConfig.
803-805: ABI/layout parity confirmed for SherpaOnnxOfflineWenetCtcModelConfig
The Pascal FFI recordSherpaOnnxOfflineWenetCtcModelConfig(Model: PAnsiChar) exactly matches the C header’s singleconst char *modelfield, and withinSherpaOnnxOfflineModelConfigthe fieldsZipformerCtc,Canary,WenetCtcappear in the same order aszipformer_ctc,canary,wenet_ctcin the C struct.
| curl -SL -O https://github.com/k2-fsa/sherpa-onnx/releases/download/asr-models/sherpa-onnx-wenetspeech-yue-u2pp-conformer-ctc-zh-en-cantonese-int8-2025-09-10.tar.bz2 | ||
| tar xvf sherpa-onnx-wenetspeech-yue-u2pp-conformer-ctc-zh-en-cantonese-int8-2025-09-10.tar.bz2 | ||
| rm sherpa-onnx-wenetspeech-yue-u2pp-conformer-ctc-zh-en-cantonese-int8-2025-09-10.tar.bz2 | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Verify model asset availability to avoid flaky CI
The dated tarball may not exist immediately; preflight the URL.
🏁 Script executed:
#!/usr/bin/env bash
# Expect HTTP 200
url="https://github.com/k2-fsa/sherpa-onnx/releases/download/asr-models/sherpa-onnx-wenetspeech-yue-u2pp-conformer-ctc-zh-en-cantonese-int8-2025-09-10.tar.bz2"
code=$(curl -sI "$url" | awk 'NR==1{print $2}')
echo "HTTP $code for $url"
test "$code" = "200"Length of output: 166
Preflight model download URL with redirects and fail on missing asset
Replace the simple curl -SL check with a preflight that follows redirects and errors on HTTP >= 400, for example:
- name: Verify model asset availability
run: |
url=https://github.com/k2-fsa/sherpa-onnx/releases/download/asr-models/sherpa-onnx-wenetspeech-yue-u2pp-conformer-ctc-zh-en-cantonese-int8-2025-09-10.tar.bz2
curl -sSfLI "$url"🤖 Prompt for AI Agents
.github/workflows/c-api.yaml around lines 96 to 99: the current steps use a
plain `curl -SL` download which doesn't preflight the URL for HTTP errors;
replace it with a preflight check that follows redirects and fails on HTTP
status >= 400 (e.g., use curl -sSfLI "$url"), then only proceed to download
(with -L -O) and extract; ensure the workflow step exits non-zero on missing
asset so CI fails early.
| curl -SL -O https://github.com/k2-fsa/sherpa-onnx/releases/download/asr-models/sherpa-onnx-wenetspeech-yue-u2pp-conformer-ctc-zh-en-cantonese-int8-2025-09-10.tar.bz2 | ||
| tar xvf sherpa-onnx-wenetspeech-yue-u2pp-conformer-ctc-zh-en-cantonese-int8-2025-09-10.tar.bz2 | ||
| rm sherpa-onnx-wenetspeech-yue-u2pp-conformer-ctc-zh-en-cantonese-int8-2025-09-10.tar.bz2 | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Preflight the release asset to avoid CI flakiness
Check the tarball URL returns 200 before proceeding.
🏁 Script executed:
#!/usr/bin/env bash
url="https://github.com/k2-fsa/sherpa-onnx/releases/download/asr-models/sherpa-onnx-wenetspeech-yue-u2pp-conformer-ctc-zh-en-cantonese-int8-2025-09-10.tar.bz2"
code=$(curl -sI "$url" | awk 'NR==1{print $2}')
echo "HTTP $code for $url"
test "$code" = "200"Length of output: 166
Use a HEAD request that follows redirects and fails on errors before downloading
Replace the simple curl -sI check with a preflight that follows redirects and exits non-zero on HTTP ≥400, for example:
- name: Preflight release asset
run: |
url="https://github.com/k2-fsa/sherpa-onnx/releases/download/asr-models/sherpa-onnx-wenetspeech-yue-u2pp-conformer-ctc-zh-en-cantonese-int8-2025-09-10.tar.bz2"
curl --head --silent --fail --location "$url" > /dev/null🤖 Prompt for AI Agents
.github/workflows/cxx-api.yaml lines 101 to 104: the workflow downloads a
release asset without a preflight check; add a HEAD preflight that follows
redirects and fails on HTTP errors before the download (use curl with
--head/--head or -I plus --location and --fail), then proceed with the existing
curl -SL -O and extraction only if the preflight succeeds; ensure the job exits
non‑zero on HTTP >=400 by using curl --head --silent --fail --location "$url" >
/dev/null before the download step.
| static int32_t RecordCallback(const void *input_buffer, | ||
| void * /*output_buffer*/, | ||
| unsigned long frames_per_buffer, // NOLINT | ||
| const PaStreamCallbackTimeInfo * /*time_info*/, | ||
| PaStreamCallbackFlags /*status_flags*/, | ||
| void * /*user_data*/) { | ||
| std::lock_guard<std::mutex> lock(mutex); | ||
| samples_queue.emplace( | ||
| reinterpret_cast<const float *>(input_buffer), | ||
| reinterpret_cast<const float *>(input_buffer) + frames_per_buffer); | ||
| condition_variable.notify_one(); | ||
|
|
||
| return stop ? paComplete : paContinue; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Guard against null input_buffer in PortAudio callback
PortAudio may pass a null input buffer; current code dereferences it and can crash.
Apply:
static int32_t RecordCallback(const void *input_buffer,
void * /*output_buffer*/,
unsigned long frames_per_buffer, // NOLINT
const PaStreamCallbackTimeInfo * /*time_info*/,
PaStreamCallbackFlags /*status_flags*/,
void * /*user_data*/) {
- std::lock_guard<std::mutex> lock(mutex);
- samples_queue.emplace(
- reinterpret_cast<const float *>(input_buffer),
- reinterpret_cast<const float *>(input_buffer) + frames_per_buffer);
+ std::lock_guard<std::mutex> lock(mutex);
+ if (!input_buffer) {
+ samples_queue.emplace(frames_per_buffer, 0.0f); // silence
+ } else {
+ samples_queue.emplace(
+ reinterpret_cast<const float *>(input_buffer),
+ reinterpret_cast<const float *>(input_buffer) + frames_per_buffer);
+ }
condition_variable.notify_one();
return stop ? paComplete : paContinue;
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| static int32_t RecordCallback(const void *input_buffer, | |
| void * /*output_buffer*/, | |
| unsigned long frames_per_buffer, // NOLINT | |
| const PaStreamCallbackTimeInfo * /*time_info*/, | |
| PaStreamCallbackFlags /*status_flags*/, | |
| void * /*user_data*/) { | |
| std::lock_guard<std::mutex> lock(mutex); | |
| samples_queue.emplace( | |
| reinterpret_cast<const float *>(input_buffer), | |
| reinterpret_cast<const float *>(input_buffer) + frames_per_buffer); | |
| condition_variable.notify_one(); | |
| return stop ? paComplete : paContinue; | |
| } | |
| static int32_t RecordCallback(const void *input_buffer, | |
| void * /*output_buffer*/, | |
| unsigned long frames_per_buffer, // NOLINT | |
| const PaStreamCallbackTimeInfo * /*time_info*/, | |
| PaStreamCallbackFlags /*status_flags*/, | |
| void * /*user_data*/) { | |
| std::lock_guard<std::mutex> lock(mutex); | |
| if (!input_buffer) { | |
| // PortAudio indicates input underflow by passing NULL; | |
| // push silence so downstream still sees frames_per_buffer samples. | |
| samples_queue.emplace(frames_per_buffer, 0.0f); | |
| } else { | |
| // Normal case: copy the incoming audio samples | |
| samples_queue.emplace( | |
| reinterpret_cast<const float *>(input_buffer), | |
| reinterpret_cast<const float *>(input_buffer) + frames_per_buffer); | |
| } | |
| condition_variable.notify_one(); | |
| return stop ? paComplete : paContinue; | |
| } |
| if (buffer.size() > 10 * window_size) { | ||
| offset -= buffer.size() - 10 * window_size; | ||
| buffer = {buffer.end() - 10 * window_size, buffer.end()}; | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix vector slicing (current code won’t compile)
buffer = {buffer.end() - 10 * window_size, buffer.end()}; creates an initializer_list of iterators. Use assign or range constructor.
- offset -= buffer.size() - 10 * window_size;
- buffer = {buffer.end() - 10 * window_size, buffer.end()};
+ offset -= static_cast<int32_t>(buffer.size() - 10 * window_size);
+ buffer.assign(buffer.end() - 10 * window_size, buffer.end());📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| if (buffer.size() > 10 * window_size) { | |
| offset -= buffer.size() - 10 * window_size; | |
| buffer = {buffer.end() - 10 * window_size, buffer.end()}; | |
| } | |
| } | |
| if (buffer.size() > 10 * window_size) { | |
| - offset -= buffer.size() - 10 * window_size; | |
| offset -= static_cast<int32_t>(buffer.size() - 10 * window_size); | |
| buffer.assign(buffer.end() - 10 * window_size, buffer.end()); | |
| } |
🤖 Prompt for AI Agents
In cxx-api-examples/wenet-ctc-simulate-streaming-microphone-cxx-api.cc around
lines 190-194, the slice operation uses brace-initialization with iterators
which creates an initializer_list and won’t compile; replace the assignment with
a proper vector range copy by either calling buffer.assign(buffer.end() - 10 *
window_size, buffer.end()) or constructing a new vector from the iterator range
and assigning that (e.g., buffer =
std::vector<decltype(buffer)::value_type>(buffer.end() - 10 * window_size,
buffer.end())); ensure you use the correct element type when constructing the
temporary vector.
| const recognizer = new sherpa_onnx.OfflineRecognizer(config); | ||
| console.log('Started') | ||
| let start = Date.now(); | ||
| const stream = recognizer.createStream(); | ||
| const wave = sherpa_onnx.readWave(waveFilename); | ||
| stream.acceptWaveform({sampleRate: wave.sampleRate, samples: wave.samples}); | ||
|
|
||
| recognizer.decode(stream); | ||
| result = recognizer.getResult(stream) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Free resources after use.
Release native handles to avoid leaks.
const recognizer = new sherpa_onnx.OfflineRecognizer(config);
@@
recognizer.decode(stream);
-const result = recognizer.getResult(stream);
+const result = recognizer.getResult(stream);
+stream.free?.();
+recognizer.free?.();Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In nodejs-addon-examples/test_asr_non_streaming_wenet_ctc.js around lines 27 to
35, the OfflineRecognizer and Stream native handles are not released after use;
modify the flow to free native resources by calling the appropriate teardown
methods (e.g., stream.delete() and recognizer.delete(), and if getResult()
returns a native object free it too with result.delete() or result.dispose()
depending on the binding) in a finally block so resources are always released
even on errors.
| stream.acceptWaveform({sampleRate: wave.sampleRate, samples: wave.samples}); | ||
|
|
||
| recognizer.decode(stream); | ||
| result = recognizer.getResult(stream) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Undeclared global ‘result’.
Assigning without const/let creates a global; strict mode would throw. Declare it.
-recognizer.decode(stream);
-result = recognizer.getResult(stream)
+recognizer.decode(stream);
+const result = recognizer.getResult(stream);📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| result = recognizer.getResult(stream) | |
| recognizer.decode(stream); | |
| const result = recognizer.getResult(stream); |
🤖 Prompt for AI Agents
In nodejs-addon-examples/test_asr_non_streaming_wenet_ctc.js around line 35, the
variable result is assigned without declaration which creates a global; change
the assignment to declare the variable (use const if value won't change or let
if it will) so it is block-scoped and compatible with strict mode.
| extension AudioBuffer { | ||
| func array() -> [Float] { | ||
| return Array(UnsafeBufferPointer(self)) | ||
| } | ||
| } | ||
|
|
||
| extension AVAudioPCMBuffer { | ||
| func array() -> [Float] { | ||
| return self.audioBufferList.pointee.mBuffers.array() | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix AudioBuffer/AVAudioPCMBuffer to Float[] conversion.
Current AudioBuffer.array() won’t compile and AVAudioPCMBuffer.array() is unsafe. Use floatChannelData and frameLength.
-extension AudioBuffer {
- func array() -> [Float] {
- return Array(UnsafeBufferPointer(self))
- }
-}
-
-extension AVAudioPCMBuffer {
- func array() -> [Float] {
- return self.audioBufferList.pointee.mBuffers.array()
- }
-}
+extension AVAudioPCMBuffer {
+ func array() -> [Float] {
+ guard let ch0 = self.floatChannelData?.pointee else { return [] }
+ let count = Int(self.frameLength)
+ return Array(UnsafeBufferPointer(start: ch0, count: count))
+ }
+}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| extension AudioBuffer { | |
| func array() -> [Float] { | |
| return Array(UnsafeBufferPointer(self)) | |
| } | |
| } | |
| extension AVAudioPCMBuffer { | |
| func array() -> [Float] { | |
| return self.audioBufferList.pointee.mBuffers.array() | |
| } | |
| } | |
| extension AVAudioPCMBuffer { | |
| func array() -> [Float] { | |
| guard let ch0 = self.floatChannelData?.pointee else { return [] } | |
| let count = Int(self.frameLength) | |
| return Array(UnsafeBufferPointer(start: ch0, count: count)) | |
| } | |
| } |
🤖 Prompt for AI Agents
In swift-api-examples/wenet-ctc-asr.swift around lines 3 to 13, the current
AudioBuffer.array() implementation won't compile and the
AVAudioPCMBuffer.array() uses audioBufferList unsafely; replace both to use
AVAudioPCMBuffer.floatChannelData and frameLength safely: implement
AVAudioPCMBuffer.array() to guard let floatChannelData = self.floatChannelData,
read the first channel pointer floatChannelData[0], and construct a [Float] from
UnsafeBufferPointer(start: floatChannelData[0], count: Int(self.frameLength));
remove or update the AudioBuffer.array() extension to either be omitted or, if
needed, read its mData by safely binding it to Float and using mDataByteSize /
MemoryLayout<Float>.size as the count, guarding for nil pointers and zero
lengths to avoid unsafe access.
| let audioFile = try! AVAudioFile(forReading: fileURL as URL) | ||
|
|
||
| let audioFormat = audioFile.processingFormat | ||
| assert(audioFormat.channelCount == 1) | ||
| assert(audioFormat.commonFormat == AVAudioCommonFormat.pcmFormatFloat32) | ||
|
|
||
| let audioFrameCount = UInt32(audioFile.length) | ||
| let audioFileBuffer = AVAudioPCMBuffer(pcmFormat: audioFormat, frameCapacity: audioFrameCount) | ||
|
|
||
| try! audioFile.read(into: audioFileBuffer!) | ||
| let array: [Float]! = audioFileBuffer?.array() | ||
| let result = recognizer.decode(samples: array, sampleRate: Int(audioFormat.sampleRate)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Avoid force-try/implicitly unwrapped optionals; handle errors.
Replace try! and ! with guarded unwrapping and error handling. Also satisfy SwiftLint.
- let audioFile = try! AVAudioFile(forReading: fileURL as URL)
+ let audioFile: AVAudioFile
+ do {
+ audioFile = try AVAudioFile(forReading: fileURL as URL)
+ } catch {
+ fputs("Failed to open WAV: \(error)\n", stderr)
+ return
+ }
@@
- let audioFileBuffer = AVAudioPCMBuffer(pcmFormat: audioFormat, frameCapacity: audioFrameCount)
-
- try! audioFile.read(into: audioFileBuffer!)
- let array: [Float]! = audioFileBuffer?.array()
+ guard let audioFileBuffer = AVAudioPCMBuffer(pcmFormat: audioFormat, frameCapacity: audioFrameCount) else {
+ fputs("Failed to allocate audio buffer\n", stderr)
+ return
+ }
+ do {
+ try audioFile.read(into: audioFileBuffer)
+ } catch {
+ fputs("Failed to read audio: \(error)\n", stderr)
+ return
+ }
+ let array: [Float] = audioFileBuffer.array()📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| let audioFile = try! AVAudioFile(forReading: fileURL as URL) | |
| let audioFormat = audioFile.processingFormat | |
| assert(audioFormat.channelCount == 1) | |
| assert(audioFormat.commonFormat == AVAudioCommonFormat.pcmFormatFloat32) | |
| let audioFrameCount = UInt32(audioFile.length) | |
| let audioFileBuffer = AVAudioPCMBuffer(pcmFormat: audioFormat, frameCapacity: audioFrameCount) | |
| try! audioFile.read(into: audioFileBuffer!) | |
| let array: [Float]! = audioFileBuffer?.array() | |
| let result = recognizer.decode(samples: array, sampleRate: Int(audioFormat.sampleRate)) | |
| // Safely open the audio file | |
| let audioFile: AVAudioFile | |
| do { | |
| audioFile = try AVAudioFile(forReading: fileURL as URL) | |
| } catch { | |
| fputs("Failed to open WAV: \(error)\n", stderr) | |
| return | |
| } | |
| let audioFormat = audioFile.processingFormat | |
| assert(audioFormat.channelCount == 1) | |
| assert(audioFormat.commonFormat == AVAudioCommonFormat.pcmFormatFloat32) | |
| let audioFrameCount = UInt32(audioFile.length) | |
| // Safely allocate the audio buffer | |
| guard let audioFileBuffer = AVAudioPCMBuffer(pcmFormat: audioFormat, frameCapacity: audioFrameCount) else { | |
| fputs("Failed to allocate audio buffer\n", stderr) | |
| return | |
| } | |
| // Safely read into the buffer | |
| do { | |
| try audioFile.read(into: audioFileBuffer) | |
| } catch { | |
| fputs("Failed to read audio: \(error)\n", stderr) | |
| return | |
| } | |
| // Directly extract the samples array | |
| let array: [Float] = audioFileBuffer.array() | |
| let result = recognizer.decode(samples: array, sampleRate: Int(audioFormat.sampleRate)) |
🧰 Tools
🪛 SwiftLint (0.57.0)
[Error] 45-45: Force tries should be avoided
(force_try)
[Error] 54-54: Force tries should be avoided
(force_try)
🤖 Prompt for AI Agents
swift-api-examples/wenet-ctc-asr.swift lines 45-56: the code uses try! and
implicitly unwrapped optionals (audioFile, audioFileBuffer, array) and assert
for runtime checks; replace these with safe error handling and guarded
unwrapping to satisfy SwiftLint. Wrap the file-reading calls in a do/catch and
handle or rethrow errors from AVAudioFile(forReading:) and read(into:), use
guard let to validate audioFile.processingFormat properties (channelCount == 1
and commonFormat == .pcmFormatFloat32) and to unwrap AVAudioPCMBuffer and its
sample array, and log/return/throw on failure instead of force-unwrapping;
ensure sampleRate is converted safely and propagate errors or return a Result so
no force-try or implicitly unwrapped optionals remain.
| fprintf(stdout, "----------offline wenet ctc model config----------\n"); | ||
| fprintf(stdout, "model: %s\n", wenet_ctc->model); | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Null-safe print to avoid UB when model is unset.
Printing %s with a null pointer can crash. Apply a safe fallback.
- fprintf(stdout, "model: %s\n", wenet_ctc->model);
+ fprintf(stdout, "model: %s\n", wenet_ctc->model ? wenet_ctc->model : "");📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| fprintf(stdout, "----------offline wenet ctc model config----------\n"); | |
| fprintf(stdout, "model: %s\n", wenet_ctc->model); | |
| fprintf(stdout, "----------offline wenet ctc model config----------\n"); | |
| fprintf(stdout, "model: %s\n", wenet_ctc->model ? wenet_ctc->model : ""); |
🤖 Prompt for AI Agents
In wasm/nodejs/sherpa-onnx-wasm-nodejs.cc around lines 139 to 141, the code
prints wenet_ctc->model using "%s" which is undefined behavior if the pointer is
null; update the printing to be null-safe by checking wenet_ctc->model and using
a fallback string (e.g., "(null)" or "") when it's NULL, then pass that safe
string to fprintf so the log never receives a null pointer.
Summary by CodeRabbit
New Features
Documentation
Tests
Chores