Repository navigation
Add JavaScript API for FunASR Nano (node-addon) #3026
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -127,6 +127,7 @@ The following tables list the examples in this folder. | |
| |[./test_asr_non_streaming_wenet_ctc.js](./test_asr_non_streaming_wenet_ctc.js)|Non-streaming speech recognition from a file using a [u2pp_conformer_yue](https://huggingface.co/ASLP-lab/WSYue-ASR/tree/main/u2pp_conformer_yue) CTC model with greedy search| | ||
| |[./test_asr_non_streaming_omnilingual_asr_ctc.js](./test_asr_non_streaming_omnilingual_asr_ctc.js)|Non-streaming speech recognition from a file using a [Omnilingual-ASR](https://github.com/facebookresearch/omnilingual-asr) CTC model with greedy search| | ||
| |[./test_asr_non_streaming_medasr_ctc.js](./test_asr_non_streaming_medasr_ctc.js)|Non-streaming speech recognition from a file using a [Google MedASR](https://github.com/google-health/medasr) CTC model with greedy search| | ||
| |[./test_asr_non_streaming_funasr_nano.js](./test_asr_non_streaming_funasr_nano.js)|Non-streaming speech recognition from a file using a [FunASR Nano](https://modelscope.cn/models/FunAudioLLM/Fun-ASR-Nano-2512) model| | ||
| |[./test_asr_non_streaming_nemo_canary.js](./test_asr_non_streaming_nemo_canary.js)|Non-streaming speech recognition from a file using a [NeMo](https://github.com/NVIDIA/NeMo) [Canary](https://k2-fsa.github.io/sherpa/onnx/nemo/canary.html#sherpa-onnx-nemo-canary-180m-flash-en-es-de-fr-int8-english-spanish-german-french) model| | ||
| |[./test_asr_non_streaming_zipformer_ctc.js](./test_asr_non_streaming_zipformer_ctc.js)|Non-streaming speech recognition from a file using a Zipformer CTC model with greedy search| | ||
| |[./test_asr_non_streaming_nemo_parakeet_tdt_v2.js](./test_asr_non_streaming_nemo_parakeet_tdt_v2.js)|Non-streaming speech recognition from a file using a [NeMo](https://github.com/NVIDIA/NeMo) [parakeet-tdt-0.6b-v2](https://k2-fsa.github.io/sherpa/onnx/pretrained_models/offline-transducer/nemo-transducer-models.html#sherpa-onnx-nemo-parakeet-tdt-0-6b-v2-int8-english) model with greedy search| | ||
|
|
@@ -429,6 +430,16 @@ npm install naudiodon2 | |
| node ./test_vad_asr_non_streaming_nemo_ctc_microphone.js | ||
| ``` | ||
|
|
||
| ### Non-streaming speech recognition with FunASR Nano models | ||
|
|
||
| ```bash | ||
| wget https://github.com/k2-fsa/sherpa-onnx/releases/download/asr-models/sherpa-onnx-funasr-nano-int8-2025-12-30.tar.bz2 | ||
| tar xvf sherpa-onnx-funasr-nano-int8-2025-12-30.tar.bz2 | ||
| rm sherpa-onnx-funasr-nano-int8-2025-12-30.tar.bz2 | ||
|
|
||
| node ./test_asr_non_streaming_funasr_nano.js | ||
|
Comment on lines
+436
to
+440
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For better maintainability and to avoid repeating the long model filename, consider introducing a variable in this example script. This makes it easier to update the model version in the future. For example: MODEL_NAME="sherpa-onnx-funasr-nano-int8-2025-12-30"
wget https://github.com/k2-fsa/sherpa-onnx/releases/download/asr-models/${MODEL_NAME}.tar.bz2
tar xvf "${MODEL_NAME}.tar.bz2"
rm "${MODEL_NAME}.tar.bz2"
node ./test_asr_non_streaming_funasr_nano.js |
||
| ``` | ||
|
|
||
| ### Non-streaming speech recognition with Google MedASR CTC models | ||
|
|
||
| ```bash | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,51 @@ | ||
| // Copyright (c) 2026 Xiaomi Corporation | ||
| const sherpa_onnx = require('sherpa-onnx-node'); | ||
|
|
||
| // Please download test files from | ||
| // https://github.com/k2-fsa/sherpa-onnx/releases/tag/asr-models | ||
| const config = { | ||
| 'featConfig': { | ||
| 'sampleRate': 16000, | ||
| 'featureDim': 80, | ||
| }, | ||
| 'modelConfig': { | ||
| 'funasrNano': { | ||
| 'encoderAdaptor': | ||
| './sherpa-onnx-funasr-nano-int8-2025-12-30/encoder_adaptor.int8.onnx', | ||
| 'llm': './sherpa-onnx-funasr-nano-int8-2025-12-30/llm.int8.onnx', | ||
| 'embedding': | ||
| './sherpa-onnx-funasr-nano-int8-2025-12-30/embedding.int8.onnx', | ||
| 'tokenizer': './sherpa-onnx-funasr-nano-int8-2025-12-30/Qwen3-0.6B', | ||
| }, | ||
| 'tokens': '', | ||
| 'numThreads': 2, | ||
| 'provider': 'cpu', | ||
| 'debug': 1, | ||
| } | ||
| }; | ||
|
|
||
| const waveFilename = | ||
| './sherpa-onnx-funasr-nano-int8-2025-12-30/test_wavs/lyrics.wav'; | ||
|
Comment on lines
+6
to
+28
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The model directory path is hardcoded in multiple places. To improve maintainability, it's a good practice to define it as a constant and reuse it. This makes it much easier to update the model version in the future. For example: const modelDir = './sherpa-onnx-funasr-nano-int8-2025-12-30';
const config = {
'featConfig': {
'sampleRate': 16000,
'featureDim': 80,
},
'modelConfig': {
'funasrNano': {
'encoderAdaptor': `${modelDir}/encoder_adaptor.int8.onnx`,
'llm': `${modelDir}/llm.int8.onnx`,
'embedding': `${modelDir}/embedding.int8.onnx`,
'tokenizer': `${modelDir}/Qwen3-0.6B`,
},
'tokens': '',
'numThreads': 2,
'provider': 'cpu',
'debug': 1,
}
};
const waveFilename = `${modelDir}/test_wavs/lyrics.wav`; |
||
|
|
||
| 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); | ||
| const result = recognizer.getResult(stream); | ||
| let stop = Date.now(); | ||
| console.log('Done') | ||
|
|
||
| const elapsed_seconds = (stop - start) / 1000; | ||
| const duration = wave.samples.length / wave.sampleRate; | ||
| const real_time_factor = elapsed_seconds / duration; | ||
| console.log('Wave duration', duration.toFixed(3), 'seconds') | ||
| console.log('Elapsed', elapsed_seconds.toFixed(3), 'seconds') | ||
| console.log( | ||
| `RTF = ${elapsed_seconds.toFixed(3)}/${duration.toFixed(3)} =`, | ||
| real_time_factor.toFixed(3)) | ||
| console.log(waveFilename) | ||
| console.log('result\n', result) | ||
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.
To improve script robustness and maintainability, it's better to chain commands that depend on each other with
&&. This ensures that the script will stop if a command fails. Also, using a variable for the model name avoids repetition and makes it easier to update.Consider adding
set -eat the top of your script to make it exit immediately if a command exits with a non-zero status.