Fangjun Kuang
Committed by GitHub

Publish `sherpa_onnx.har` for HarmonyOS (#1572)

正在显示 104 个修改的文件 包含 1887 行增加8 行删除
  1 +name: har
  2 +
  3 +on:
  4 + push:
  5 + branches:
  6 + - master
  7 + # - ohos-har
  8 + tags:
  9 + - 'v[0-9]+.[0-9]+.[0-9]+*'
  10 +
  11 + workflow_dispatch:
  12 +
  13 +concurrency:
  14 + group: har-${{ github.ref }}
  15 + cancel-in-progress: true
  16 +
  17 +jobs:
  18 + har:
  19 + name: Har
  20 + runs-on: ${{ matrix.os }}
  21 + strategy:
  22 + fail-fast: false
  23 + matrix:
  24 + os: [ubuntu-latest]
  25 +
  26 + steps:
  27 + - uses: actions/checkout@v4
  28 + with:
  29 + fetch-depth: 0
  30 +
  31 + - name: ccache
  32 + uses: hendrikmuhs/ccache-action@v1.2
  33 + with:
  34 + key: har-linux
  35 +
  36 + - name: cache-toolchain
  37 + id: cache-toolchain-ohos
  38 + uses: actions/cache@v4
  39 + with:
  40 + path: command-line-tools
  41 + key: commandline-tools-linux-x64-5.0.5.200.zip
  42 +
  43 + - name: Download toolchain
  44 + if: steps.cache-toolchain-ohos.outputs.cache-hit != 'true'
  45 + shell: bash
  46 + run: |
  47 + curl -SL -O https://huggingface.co/csukuangfj/harmonyos-commandline-tools/resolve/main/commandline-tools-linux-x64-5.0.5.200.zip
  48 + unzip commandline-tools-linux-x64-5.0.5.200.zip
  49 + rm commandline-tools-linux-x64-5.0.5.200.zip
  50 +
  51 + - name: Set environment variable
  52 + shell: bash
  53 + run: |
  54 + echo "$GITHUB_WORKSPACE/command-line-tools/sdk/default/openharmony/native/build-tools/cmake/bin" >> "$GITHUB_PATH"
  55 + which cmake
  56 +
  57 + cmake --version
  58 +
  59 + ls -lh $GITHUB_WORKSPACE/command-line-tools/sdk/default/openharmony/native/build/cmake/ohos.toolchain.cmake
  60 +
  61 + echo "===="
  62 + cat $GITHUB_WORKSPACE/command-line-tools/sdk/default/openharmony/native/build/cmake/ohos.toolchain.cmake
  63 + echo "===="
  64 +
  65 + # echo "$GITHUB_WORKSPACE/command-line-tools/sdk/default/openharmony/native/llvm/bin" >> "$GITHUB_PATH"
  66 +
  67 + ls -lh $GITHUB_WORKSPACE/command-line-tools/sdk/default/openharmony/native/llvm/bin/
  68 + echo "--"
  69 + ls -lh $GITHUB_WORKSPACE/command-line-tools/sdk/default/openharmony/native/llvm/bin/*unknown*
  70 +
  71 + cat $GITHUB_PATH
  72 +
  73 + # /home/runner/work/onnxruntime-libs/onnxruntime-libs/command-line-tools/sdk/default/openharmony/native/llvm/bin/aarch64-unknown-linux-ohos-clang -v || true
  74 + export PATH=$PWD/command-line-tools/sdk/default/openharmony/native/llvm/bin:$PATH
  75 + echo "path: $PATH"
  76 +
  77 + which aarch64-unknown-linux-ohos-clang++ || true
  78 + which aarch64-unknown-linux-ohos-clang || true
  79 +
  80 + aarch64-unknown-linux-ohos-clang++ --version || true
  81 + aarch64-unknown-linux-ohos-clang --version || true
  82 +
  83 + which armv7-unknown-linux-ohos-clang++
  84 + which armv7-unknown-linux-ohos-clang
  85 +
  86 + armv7-unknown-linux-ohos-clang++ --version
  87 + armv7-unknown-linux-ohos-clang --version
  88 +
  89 + which x86_64-unknown-linux-ohos-clang++
  90 + which x86_64-unknown-linux-ohos-clang
  91 +
  92 + x86_64-unknown-linux-ohos-clang++ --version
  93 + x86_64-unknown-linux-ohos-clang --version
  94 +
  95 + - name: Build libraries
  96 + shell: bash
  97 + run: |
  98 + export CMAKE_CXX_COMPILER_LAUNCHER=ccache
  99 + export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH"
  100 + cmake --version
  101 +
  102 + export OHOS_SDK_NATIVE_DIR="$GITHUB_WORKSPACE/command-line-tools/sdk/default/openharmony/native"
  103 +
  104 + ./build-ohos-arm64-v8a.sh
  105 + ./build-ohos-x86-64.sh
  106 +
  107 + - name: Build Har
  108 + shell: bash
  109 + run: |
  110 + export PATH="$GITHUB_WORKSPACE/command-line-tools/bin:$PATH"
  111 +
  112 + which hvigorw
  113 +
  114 + pushd harmony-os/SherpaOnnxHar
  115 +
  116 + hvigorw --mode module -p product=default -p module=sherpa_onnx@default assembleHar --analyze=normal --parallel --incremental --no-daemon
  117 + ls -lh ./sherpa_onnx/build/default/outputs/default/sherpa_onnx.har
  118 + cp -v ./sherpa_onnx/build/default/outputs/default/sherpa_onnx.har ../../
  119 +
  120 + popd
  121 +
  122 + ls -lh *.har
  123 +
  124 + - name: Collect result
  125 + shell: bash
  126 + run: |
  127 + SHERPA_ONNX_VERSION=v$(grep "SHERPA_ONNX_VERSION" ./CMakeLists.txt | cut -d " " -f 2 | cut -d '"' -f 2)
  128 + echo "SHERPA_ONNX_VERSION=$SHERPA_ONNX_VERSION" >> "$GITHUB_ENV"
  129 +
  130 + mv sherpa_onnx.har sherpa_onnx-$SHERPA_ONNX_VERSION.har
  131 +
  132 + - uses: actions/upload-artifact@v4
  133 + with:
  134 + name: sherpa-onnx-har
  135 + path: ./sherpa_onnx*.har
  136 +
  137 + - name: Release jar
  138 + if: (github.repository_owner == 'csukuangfj' || github.repository_owner == 'k2-fsa') && github.event_name == 'push' && contains(github.ref, 'refs/tags/')
  139 + uses: svenstaro/upload-release-action@v2
  140 + with:
  141 + file_glob: true
  142 + overwrite: true
  143 + file: ./*.har
  144 + # repo_name: k2-fsa/sherpa-onnx
  145 + # repo_token: ${{ secrets.UPLOAD_GH_SHERPA_ONNX_TOKEN }}
  146 + # tag: v1.10.32
  147 +
  148 + - name: Publish to huggingface
  149 + if: (github.repository_owner == 'csukuangfj' || github.repository_owner == 'k2-fsa') && (github.event_name == 'push' || github.event_name == 'workflow_dispatch')
  150 + env:
  151 + HF_TOKEN: ${{ secrets.HF_TOKEN }}
  152 + uses: nick-fields/retry@v3
  153 + with:
  154 + max_attempts: 20
  155 + timeout_seconds: 200
  156 + shell: bash
  157 + command: |
  158 + git config --global user.email "csukuangfj@gmail.com"
  159 + git config --global user.name "Fangjun Kuang"
  160 +
  161 + rm -rf huggingface
  162 + export GIT_LFS_SKIP_SMUDGE=1
  163 + export GIT_CLONE_PROTECTION_ACTIVE=false
  164 +
  165 + SHERPA_ONNX_VERSION=$(grep "SHERPA_ONNX_VERSION" ./CMakeLists.txt | cut -d " " -f 2 | cut -d '"' -f 2)
  166 + echo "SHERPA_ONNX_VERSION $SHERPA_ONNX_VERSION"
  167 +
  168 + git clone https://csukuangfj:$HF_TOKEN@huggingface.co/csukuangfj/sherpa-onnx-harmony-os huggingface
  169 + cd huggingface
  170 + git fetch
  171 + git pull
  172 + git merge -m "merge remote" --ff origin main
  173 +
  174 + d=har
  175 + mkdir -p $d
  176 + cp -v ../*.har $d/
  177 + git status
  178 + git lfs track "*.har"
  179 + git add .
  180 + git commit -m "add more hars"
  181 + git push https://csukuangfj:$HF_TOKEN@huggingface.co/csukuangfj/sherpa-onnx-harmony-os main
@@ -18,14 +18,13 @@ @@ -18,14 +18,13 @@
18 18
19 ### Supported platforms 19 ### Supported platforms
20 20
21 -|Architecture| Android | iOS | Windows | macOS | linux |  
22 -|------------|---------|---------|------------|-------|-------|  
23 -| x64 | ✔️ | | ✔️ | ✔️ | ✔️ |  
24 -| x86 | ✔️ | | ✔️ | | |  
25 -| arm64 | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ |  
26 -| arm32 | ✔️ | | | | ✔️ |  
27 -| riscv64 | | | | | ✔️ |  
28 - 21 +|Architecture| Android | iOS | Windows | macOS | linux | HarmonyOS |
  22 +|------------|---------|---------|------------|-------|-------|-----------|
  23 +| x64 | ✔️ | | ✔️ | ✔️ | ✔️ | ✔️ |
  24 +| x86 | ✔️ | | ✔️ | | | |
  25 +| arm64 | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ |
  26 +| arm32 | ✔️ | | | | ✔️ | ✔️ |
  27 +| riscv64 | | | | | ✔️ | |
29 28
30 ### Supported programming languages 29 ### Supported programming languages
31 30
@@ -65,6 +64,7 @@ on the following platforms and operating systems: @@ -65,6 +64,7 @@ on the following platforms and operating systems:
65 - Linux, macOS, Windows, openKylin 64 - Linux, macOS, Windows, openKylin
66 - Android, WearOS 65 - Android, WearOS
67 - iOS 66 - iOS
  67 + - HarmonyOS
68 - NodeJS 68 - NodeJS
69 - WebAssembly 69 - WebAssembly
70 - [Raspberry Pi][Raspberry Pi] 70 - [Raspberry Pi][Raspberry Pi]
@@ -134,3 +134,9 @@ cp -fv $onnxruntime_dir/lib/libonnxruntime.so install/lib @@ -134,3 +134,9 @@ cp -fv $onnxruntime_dir/lib/libonnxruntime.so install/lib
134 134
135 rm -rf install/share 135 rm -rf install/share
136 rm -rf install/lib/pkgconfig 136 rm -rf install/lib/pkgconfig
  137 +
  138 +d=../harmony-os/SherpaOnnxHar/sherpa_onnx/src/main/cpp/libs/arm64-v8a
  139 +if [ -d $d ]; then
  140 + cp -v install/lib/libsherpa-onnx-c-api.so $d/
  141 + cp -v install/lib/libonnxruntime.so $d/
  142 +fi
@@ -134,3 +134,9 @@ cp -fv $onnxruntime_dir/lib/libonnxruntime.so install/lib @@ -134,3 +134,9 @@ cp -fv $onnxruntime_dir/lib/libonnxruntime.so install/lib
134 134
135 rm -rf install/share 135 rm -rf install/share
136 rm -rf install/lib/pkgconfig 136 rm -rf install/lib/pkgconfig
  137 +
  138 +d=../harmony-os/SherpaOnnxHar/sherpa_onnx/src/main/cpp/libs/x86_64
  139 +if [ -d $d ]; then
  140 + cp -v install/lib/libsherpa-onnx-c-api.so $d/
  141 + cp -v install/lib/libonnxruntime.so $d/
  142 +fi
  1 +!build-profile.json5
  1 +/node_modules
  2 +/oh_modules
  3 +/local.properties
  4 +/.idea
  5 +**/build
  6 +/.hvigor
  7 +.cxx
  8 +/.clangd
  9 +/.clang-format
  10 +/.clang-tidy
  11 +**/.test
  12 +/.appanalyzer
  1 +{
  2 + "app": {
  3 + "bundleName": "com.k2fsa.sherpa.onnx",
  4 + "vendor": "example",
  5 + "versionCode": 1000000,
  6 + "versionName": "1.0.0",
  7 + "icon": "$media:app_icon",
  8 + "label": "$string:app_name"
  9 + }
  10 +}
  1 +{
  2 + "string": [
  3 + {
  4 + "name": "app_name",
  5 + "value": "SherpaOnnxHar"
  6 + }
  7 + ]
  8 +}
  1 +# Introduction
  2 +
  3 +How to build `sherpa_onnx.har` from the command line:
  4 +
  5 +```bash
  6 +git clone https://github.com/k2-fsa/sherpa-onnx
  7 +cd sherpa-onnx
  8 +./build-ohos-arm64-v8a.sh
  9 +./build-ohos-x86-64.sh
  10 +
  11 +cd harmony-os/SherpaOnnxHar
  12 +
  13 +hvigorw clean --no-daemon
  14 +
  15 +hvigorw --mode module -p product=default -p module=sherpa_onnx@default assembleHar --analyze=normal --parallel --incremental --no-daemon
  16 +
  17 +ls -lh ./sherpa_onnx/build/default/outputs/default/sherpa_onnx.har
  18 +```
  1 +{
  2 + "app": {
  3 + "signingConfigs": [],
  4 + "products": [
  5 + {
  6 + "name": "default",
  7 + "signingConfig": "default",
  8 + "compatibleSdkVersion": "4.0.0(10)",
  9 + "runtimeOS": "HarmonyOS",
  10 + "buildOption": {
  11 + "strictMode": {
  12 + "caseSensitiveCheck": true,
  13 + }
  14 + }
  15 + }
  16 + ],
  17 + "buildModeSet": [
  18 + {
  19 + "name": "debug",
  20 + },
  21 + {
  22 + "name": "release"
  23 + }
  24 + ]
  25 + },
  26 + "modules": [
  27 + {
  28 + "name": "entry",
  29 + "srcPath": "./entry",
  30 + "targets": [
  31 + {
  32 + "name": "default",
  33 + "applyToProducts": [
  34 + "default"
  35 + ]
  36 + }
  37 + ]
  38 + },
  39 + {
  40 + "name": "sherpa_onnx",
  41 + "srcPath": "./sherpa_onnx",
  42 + }
  43 + ]
  44 +}
  1 +{
  2 + "files": [
  3 + "**/*.ets"
  4 + ],
  5 + "ignore": [
  6 + "**/src/ohosTest/**/*",
  7 + "**/src/test/**/*",
  8 + "**/src/mock/**/*",
  9 + "**/node_modules/**/*",
  10 + "**/oh_modules/**/*",
  11 + "**/build/**/*",
  12 + "**/.preview/**/*"
  13 + ],
  14 + "ruleSet": [
  15 + "plugin:@performance/recommended",
  16 + "plugin:@typescript-eslint/recommended"
  17 + ],
  18 + "rules": {
  19 + }
  20 +}
  1 +/node_modules
  2 +/oh_modules
  3 +/.preview
  4 +/build
  5 +/.cxx
  6 +/.test
  1 +{
  2 + "apiType": "stageMode",
  3 + "buildOption": {
  4 + },
  5 + "buildOptionSet": [
  6 + {
  7 + "name": "release",
  8 + "arkOptions": {
  9 + "obfuscation": {
  10 + "ruleOptions": {
  11 + "enable": false,
  12 + "files": [
  13 + "./obfuscation-rules.txt"
  14 + ]
  15 + }
  16 + }
  17 + }
  18 + },
  19 + ],
  20 + "targets": [
  21 + {
  22 + "name": "default"
  23 + },
  24 + {
  25 + "name": "ohosTest",
  26 + }
  27 + ]
  28 +}
  1 +import { hapTasks } from '@ohos/hvigor-ohos-plugin';
  2 +
  3 +export default {
  4 + system: hapTasks, /* Built-in plugin of Hvigor. It cannot be modified. */
  5 + plugins:[] /* Custom plugin to extend the functionality of Hvigor. */
  6 +}
  1 +# Define project specific obfuscation rules here.
  2 +# You can include the obfuscation configuration files in the current module's build-profile.json5.
  3 +#
  4 +# For more details, see
  5 +# https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/source-obfuscation-V5
  6 +
  7 +# Obfuscation options:
  8 +# -disable-obfuscation: disable all obfuscations
  9 +# -enable-property-obfuscation: obfuscate the property names
  10 +# -enable-toplevel-obfuscation: obfuscate the names in the global scope
  11 +# -compact: remove unnecessary blank spaces and all line feeds
  12 +# -remove-log: remove all console.* statements
  13 +# -print-namecache: print the name cache that contains the mapping from the old names to new names
  14 +# -apply-namecache: reuse the given cache file
  15 +
  16 +# Keep options:
  17 +# -keep-property-name: specifies property names that you want to keep
  18 +# -keep-global-name: specifies names that you want to keep in the global scope
  19 +
  20 +-enable-property-obfuscation
  21 +-enable-toplevel-obfuscation
  22 +-enable-filename-obfuscation
  23 +-enable-export-obfuscation
  1 +{
  2 + "name": "entry",
  3 + "version": "1.0.0",
  4 + "description": "Please describe the basic information.",
  5 + "main": "",
  6 + "author": "",
  7 + "license": "",
  8 + "dependencies": {}
  9 +}
  10 +
  1 +import AbilityConstant from '@ohos.app.ability.AbilityConstant';
  2 +import hilog from '@ohos.hilog';
  3 +import UIAbility from '@ohos.app.ability.UIAbility';
  4 +import Want from '@ohos.app.ability.Want';
  5 +import window from '@ohos.window';
  6 +
  7 +export default class EntryAbility extends UIAbility {
  8 + onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
  9 + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate');
  10 + }
  11 +
  12 + onDestroy(): void {
  13 + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onDestroy');
  14 + }
  15 +
  16 + onWindowStageCreate(windowStage: window.WindowStage): void {
  17 + // Main window is created, set main page for this ability
  18 + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate');
  19 +
  20 + windowStage.loadContent('pages/Index', (err) => {
  21 + if (err.code) {
  22 + hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? '');
  23 + return;
  24 + }
  25 + hilog.info(0x0000, 'testTag', 'Succeeded in loading the content.');
  26 + });
  27 + }
  28 +
  29 + onWindowStageDestroy(): void {
  30 + // Main window is destroyed, release UI related resources
  31 + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageDestroy');
  32 + }
  33 +
  34 + onForeground(): void {
  35 + // Ability has brought to foreground
  36 + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onForeground');
  37 + }
  38 +
  39 + onBackground(): void {
  40 + // Ability has back to background
  41 + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onBackground');
  42 + }
  43 +}
  1 +import hilog from '@ohos.hilog';
  2 +import BackupExtensionAbility, { BundleVersion } from '@ohos.application.BackupExtensionAbility';
  3 +
  4 +export default class EntryBackupAbility extends BackupExtensionAbility {
  5 + async onBackup() {
  6 + hilog.info(0x0000, 'testTag', 'onBackup ok');
  7 + }
  8 +
  9 + async onRestore(bundleVersion: BundleVersion) {
  10 + hilog.info(0x0000, 'testTag', 'onRestore ok %{public}s', JSON.stringify(bundleVersion));
  11 + }
  12 +}
  1 +@Entry
  2 +@Component
  3 +struct Index {
  4 + @State message: string = 'Hello World';
  5 +
  6 + build() {
  7 + Row() {
  8 + Column() {
  9 + Text(this.message)
  10 + .fontSize(50)
  11 + .fontWeight(FontWeight.Bold)
  12 + }
  13 + .width('100%')
  14 + }
  15 + .height('100%')
  16 + }
  17 +}
  1 +{
  2 + "module": {
  3 + "name": "entry",
  4 + "type": "entry",
  5 + "description": "$string:module_desc",
  6 + "mainElement": "EntryAbility",
  7 + "deviceTypes": [
  8 + "phone",
  9 + "tablet",
  10 + "2in1"
  11 + ],
  12 + "deliveryWithInstall": true,
  13 + "installationFree": false,
  14 + "pages": "$profile:main_pages",
  15 + "abilities": [
  16 + {
  17 + "name": "EntryAbility",
  18 + "srcEntry": "./ets/entryability/EntryAbility.ets",
  19 + "description": "$string:EntryAbility_desc",
  20 + "icon": "$media:layered_image",
  21 + "label": "$string:EntryAbility_label",
  22 + "startWindowIcon": "$media:startIcon",
  23 + "startWindowBackground": "$color:start_window_background",
  24 + "exported": true,
  25 + "skills": [
  26 + {
  27 + "entities": [
  28 + "entity.system.home"
  29 + ],
  30 + "actions": [
  31 + "action.system.home"
  32 + ]
  33 + }
  34 + ]
  35 + }
  36 + ],
  37 + "extensionAbilities": [
  38 + {
  39 + "name": "EntryBackupAbility",
  40 + "srcEntry": "./ets/entrybackupability/EntryBackupAbility.ets",
  41 + "type": "backup",
  42 + "exported": false,
  43 + "metadata": [
  44 + {
  45 + "name": "ohos.extension.backup",
  46 + "resource": "$profile:backup_config"
  47 + }
  48 + ],
  49 + }
  50 + ]
  51 + }
  52 +}
  1 +{
  2 + "color": [
  3 + {
  4 + "name": "start_window_background",
  5 + "value": "#FFFFFF"
  6 + }
  7 + ]
  8 +}
  1 +{
  2 + "string": [
  3 + {
  4 + "name": "module_desc",
  5 + "value": "module description"
  6 + },
  7 + {
  8 + "name": "EntryAbility_desc",
  9 + "value": "description"
  10 + },
  11 + {
  12 + "name": "EntryAbility_label",
  13 + "value": "label"
  14 + }
  15 + ]
  16 +}
  1 +{
  2 + "layered-image":
  3 + {
  4 + "background" : "$media:background",
  5 + "foreground" : "$media:foreground"
  6 + }
  7 +}
  1 +{
  2 + "string": [
  3 + {
  4 + "name": "module_desc",
  5 + "value": "module description"
  6 + },
  7 + {
  8 + "name": "EntryAbility_desc",
  9 + "value": "description"
  10 + },
  11 + {
  12 + "name": "EntryAbility_label",
  13 + "value": "label"
  14 + }
  15 + ]
  16 +}
  1 +{
  2 + "string": [
  3 + {
  4 + "name": "module_desc",
  5 + "value": "模块描述"
  6 + },
  7 + {
  8 + "name": "EntryAbility_desc",
  9 + "value": "description"
  10 + },
  11 + {
  12 + "name": "EntryAbility_label",
  13 + "value": "label"
  14 + }
  15 + ]
  16 +}
  1 +import hilog from '@ohos.hilog';
  2 +import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from '@ohos/hypium';
  3 +
  4 +export default function abilityTest() {
  5 + describe('ActsAbilityTest', () => {
  6 + // Defines a test suite. Two parameters are supported: test suite name and test suite function.
  7 + beforeAll(() => {
  8 + // Presets an action, which is performed only once before all test cases of the test suite start.
  9 + // This API supports only one parameter: preset action function.
  10 + })
  11 + beforeEach(() => {
  12 + // Presets an action, which is performed before each unit test case starts.
  13 + // The number of execution times is the same as the number of test cases defined by **it**.
  14 + // This API supports only one parameter: preset action function.
  15 + })
  16 + afterEach(() => {
  17 + // Presets a clear action, which is performed after each unit test case ends.
  18 + // The number of execution times is the same as the number of test cases defined by **it**.
  19 + // This API supports only one parameter: clear action function.
  20 + })
  21 + afterAll(() => {
  22 + // Presets a clear action, which is performed after all test cases of the test suite end.
  23 + // This API supports only one parameter: clear action function.
  24 + })
  25 + it('assertContain', 0, () => {
  26 + // Defines a test case. This API supports three parameters: test case name, filter parameter, and test case function.
  27 + hilog.info(0x0000, 'testTag', '%{public}s', 'it begin');
  28 + let a = 'abc';
  29 + let b = 'b';
  30 + // Defines a variety of assertion methods, which are used to declare expected boolean conditions.
  31 + expect(a).assertContain(b);
  32 + expect(a).assertEqual(a);
  33 + })
  34 + })
  35 +}
  1 +import abilityTest from './Ability.test';
  2 +
  3 +export default function testsuite() {
  4 + abilityTest();
  5 +}
  1 +{
  2 + "module": {
  3 + "name": "entry_test",
  4 + "type": "feature",
  5 + "deviceTypes": [
  6 + "phone",
  7 + "tablet",
  8 + "2in1"
  9 + ],
  10 + "deliveryWithInstall": true,
  11 + "installationFree": false
  12 + }
  13 +}
  1 +import localUnitTest from './LocalUnit.test';
  2 +
  3 +export default function testsuite() {
  4 + localUnitTest();
  5 +}
  1 +import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from '@ohos/hypium';
  2 +
  3 +export default function localUnitTest() {
  4 + describe('localUnitTest', () => {
  5 + // Defines a test suite. Two parameters are supported: test suite name and test suite function.
  6 + beforeAll(() => {
  7 + // Presets an action, which is performed only once before all test cases of the test suite start.
  8 + // This API supports only one parameter: preset action function.
  9 + });
  10 + beforeEach(() => {
  11 + // Presets an action, which is performed before each unit test case starts.
  12 + // The number of execution times is the same as the number of test cases defined by **it**.
  13 + // This API supports only one parameter: preset action function.
  14 + });
  15 + afterEach(() => {
  16 + // Presets a clear action, which is performed after each unit test case ends.
  17 + // The number of execution times is the same as the number of test cases defined by **it**.
  18 + // This API supports only one parameter: clear action function.
  19 + });
  20 + afterAll(() => {
  21 + // Presets a clear action, which is performed after all test cases of the test suite end.
  22 + // This API supports only one parameter: clear action function.
  23 + });
  24 + it('assertContain', 0, () => {
  25 + // Defines a test case. This API supports three parameters: test case name, filter parameter, and test case function.
  26 + let a = 'abc';
  27 + let b = 'b';
  28 + // Defines a variety of assertion methods, which are used to declare expected boolean conditions.
  29 + expect(a).assertContain(b);
  30 + expect(a).assertEqual(a);
  31 + });
  32 + });
  33 +}
  1 +{
  2 + "modelVersion": "5.0.0",
  3 + "dependencies": {
  4 + },
  5 + "execution": {
  6 + // "analyze": "normal", /* Define the build analyze mode. Value: [ "normal" | "advanced" | false ]. Default: "normal" */
  7 + // "daemon": true, /* Enable daemon compilation. Value: [ true | false ]. Default: true */
  8 + // "incremental": true, /* Enable incremental compilation. Value: [ true | false ]. Default: true */
  9 + // "parallel": true, /* Enable parallel compilation. Value: [ true | false ]. Default: true */
  10 + // "typeCheck": false, /* Enable typeCheck. Value: [ true | false ]. Default: false */
  11 + },
  12 + "logging": {
  13 + // "level": "info" /* Define the log level. Value: [ "debug" | "info" | "warn" | "error" ]. Default: "info" */
  14 + },
  15 + "debugging": {
  16 + // "stacktrace": false /* Disable stacktrace compilation. Value: [ true | false ]. Default: false */
  17 + },
  18 + "nodeOptions": {
  19 + // "maxOldSpaceSize": 8192 /* Enable nodeOptions maxOldSpaceSize compilation. Unit M. Used for the daemon process. Default: 8192*/
  20 + // "exposeGC": true /* Enable to trigger garbage collection explicitly. Default: true*/
  21 + }
  22 +}
  1 +import { appTasks } from '@ohos/hvigor-ohos-plugin';
  2 +
  3 +export default {
  4 + system: appTasks, /* Built-in plugin of Hvigor. It cannot be modified. */
  5 + plugins:[] /* Custom plugin to extend the functionality of Hvigor. */
  6 +}
  1 +# Notes
  2 +
  3 +## How to publish a package
  4 +
  5 +Please see
  6 + - <https://ohpm.openharmony.cn/#/cn/help/publishrequirefile>
  7 + - <https://ohpm.openharmony.cn/#/cn/help/createandpublish>
  8 + - <https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/ide-har-publish-V5>
  9 +
  10 +## How to sign the HAP file from commandline
  11 +
  12 +Please see
  13 +<https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/ide-command-line-building-app-V5>
  1 +{
  2 + "meta": {
  3 + "stableOrder": true
  4 + },
  5 + "lockfileVersion": 3,
  6 + "ATTENTION": "THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.",
  7 + "specifiers": {
  8 + "@ohos/hypium@1.0.19": "@ohos/hypium@1.0.19"
  9 + },
  10 + "packages": {
  11 + "@ohos/hypium@1.0.19": {
  12 + "name": "@ohos/hypium",
  13 + "version": "1.0.19",
  14 + "integrity": "sha512-cEjDgLFCm3cWZDeRXk7agBUkPqjWxUo6AQeiu0gEkb3J8ESqlduQLSIXeo3cCsm8U/asL7iKjF85ZyOuufAGSQ==",
  15 + "resolved": "https://ohpm.openharmony.cn/ohpm/@ohos/hypium/-/hypium-1.0.19.har",
  16 + "registryType": "ohpm"
  17 + }
  18 + }
  19 +}
  1 +{
  2 + "modelVersion": "5.0.0",
  3 + "description": "Please describe the basic information.",
  4 + "dependencies": {
  5 + },
  6 + "devDependencies": {
  7 + "@ohos/hypium": "1.0.19"
  8 + }
  9 +}
  1 +/node_modules
  2 +/oh_modules
  3 +/.preview
  4 +/build
  5 +/.cxx
  6 +/.test
  1 +/**
  2 + * Use these variables when you tailor your ArkTS code. They must be of the const type.
  3 + */
  4 +export const HAR_VERSION = '1.0.0';
  5 +export const BUILD_MODE_NAME = 'debug';
  6 +export const DEBUG = true;
  7 +export const TARGET_NAME = 'default';
  8 +
  9 +/**
  10 + * BuildProfile Class is used only for compatibility purposes.
  11 + */
  12 +export default class BuildProfile {
  13 + static readonly HAR_VERSION = HAR_VERSION;
  14 + static readonly BUILD_MODE_NAME = BUILD_MODE_NAME;
  15 + static readonly DEBUG = DEBUG;
  16 + static readonly TARGET_NAME = TARGET_NAME;
  17 +}
  1 +export { readWave, readWaveFromBinary } from "libsherpa_onnx.so";
  2 +
  3 +export {
  4 + CircularBuffer,
  5 + SileroVadConfig,
  6 + SpeechSegment,
  7 + Vad,
  8 + VadConfig,
  9 +} from './src/main/ets/components/Vad';
  10 +
  11 +
  12 +export {
  13 + Samples,
  14 + OfflineStream,
  15 + FeatureConfig,
  16 + OfflineTransducerModelConfig,
  17 + OfflineParaformerModelConfig,
  18 + OfflineNemoEncDecCtcModelConfig,
  19 + OfflineWhisperModelConfig,
  20 + OfflineTdnnModelConfig,
  21 + OfflineSenseVoiceModelConfig,
  22 + OfflineMoonshineModelConfig,
  23 + OfflineModelConfig,
  24 + OfflineLMConfig,
  25 + OfflineRecognizerConfig,
  26 + OfflineRecognizerResult,
  27 + OfflineRecognizer,
  28 +} from './src/main/ets/components/NonStreamingAsr';
  29 +
  30 +export {
  31 + OnlineStream,
  32 + OnlineTransducerModelConfig,
  33 + OnlineParaformerModelConfig,
  34 + OnlineZipformer2CtcModelConfig,
  35 + OnlineModelConfig,
  36 + OnlineCtcFstDecoderConfig,
  37 + OnlineRecognizerConfig,
  38 + OnlineRecognizerResult,
  39 + OnlineRecognizer,
  40 +} from './src/main/ets/components/StreamingAsr';
  1 +# Introduction
  2 +
  3 +[sherpa-onnx](https://github.com/k2-fsa/sherpa-onnx) is one of the deployment
  4 +frameworks of [Next-gen Kaldi](https://github.com/k2-fsa).
  5 +
  6 +It supports speech-to-text, text-to-speech, speaker diarization, and VAD using
  7 +onnxruntime without Internet connection.
  8 +
  9 +It also supports embedded systems, Android, iOS, HarmonyOS,
  10 +Raspberry Pi, RISC-V, x86_64 servers, websocket server/client,
  11 +C/C++, Python, Kotlin, C#, Go, NodeJS, Java, Swift, Dart, JavaScript,
  12 +Flutter, Object Pascal, Lazarus, Rust, etc.
  1 +{
  2 + "apiType": "stageMode",
  3 + "buildOption": {
  4 + "externalNativeOptions": {
  5 + "path": "./src/main/cpp/CMakeLists.txt",
  6 + "arguments": "",
  7 + "cppFlags": "",
  8 + "abiFilters": [
  9 + "arm64-v8a",
  10 + "x86_64",
  11 + ],
  12 + },
  13 + },
  14 + "buildOptionSet": [
  15 + {
  16 + "name": "release",
  17 + "arkOptions": {
  18 + "obfuscation": {
  19 + "ruleOptions": {
  20 + "enable": false,
  21 + "files": [
  22 + "./obfuscation-rules.txt"
  23 + ]
  24 + },
  25 + "consumerFiles": [
  26 + "./consumer-rules.txt"
  27 + ]
  28 + }
  29 + },
  30 + "nativeLib": {
  31 + "debugSymbol": {
  32 + "strip": true,
  33 + "exclude": []
  34 + }
  35 + }
  36 + },
  37 + ],
  38 + "targets": [
  39 + {
  40 + "name": "default"
  41 + },
  42 + {
  43 + "name": "ohosTest"
  44 + }
  45 + ]
  46 +}
  1 +import { harTasks } from '@ohos/hvigor-ohos-plugin';
  2 +
  3 +export default {
  4 + system: harTasks, /* Built-in plugin of Hvigor. It cannot be modified. */
  5 + plugins:[] /* Custom plugin to extend the functionality of Hvigor. */
  6 +}
  1 +# Define project specific obfuscation rules here.
  2 +# You can include the obfuscation configuration files in the current module's build-profile.json5.
  3 +#
  4 +# For more details, see
  5 +# https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/source-obfuscation-V5
  6 +
  7 +# Obfuscation options:
  8 +# -disable-obfuscation: disable all obfuscations
  9 +# -enable-property-obfuscation: obfuscate the property names
  10 +# -enable-toplevel-obfuscation: obfuscate the names in the global scope
  11 +# -compact: remove unnecessary blank spaces and all line feeds
  12 +# -remove-log: remove all console.* statements
  13 +# -print-namecache: print the name cache that contains the mapping from the old names to new names
  14 +# -apply-namecache: reuse the given cache file
  15 +
  16 +# Keep options:
  17 +# -keep-property-name: specifies property names that you want to keep
  18 +# -keep-global-name: specifies names that you want to keep in the global scope
  19 +
  20 +-enable-property-obfuscation
  21 +-enable-toplevel-obfuscation
  22 +-enable-filename-obfuscation
  23 +-enable-export-obfuscation
  1 +{
  2 + "meta": {
  3 + "stableOrder": true
  4 + },
  5 + "lockfileVersion": 3,
  6 + "ATTENTION": "THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.",
  7 + "specifiers": {
  8 + "libsherpa_onnx.so@src/main/cpp/types/libsherpa_onnx": "libsherpa_onnx.so@src/main/cpp/types/libsherpa_onnx"
  9 + },
  10 + "packages": {
  11 + "libsherpa_onnx.so@src/main/cpp/types/libsherpa_onnx": {
  12 + "name": "libsherpa_onnx.so",
  13 + "version": "1.0.0",
  14 + "resolved": "src/main/cpp/types/libsherpa_onnx",
  15 + "registryType": "local"
  16 + }
  17 + }
  18 +}
  1 +{
  2 + "name": "sherpa_onnx",
  3 + "version": "1.0.0",
  4 + "description": "Speech-to-text, text-to-speech, and speaker diarization using Next-gen Kaldi without internet connection",
  5 + "main": "Index.ets",
  6 + "author": "The next-gen Kaldi team",
  7 + "license": "Apache-2.0",
  8 + "homepage": "https://github.com/k2-fsa/sherpa-onnx",
  9 + "repository": "https://github.com/k2-fsa/sherpa-onnx/tree/master/harmonyos-SherpaOnnxHar",
  10 + "dependencies": {
  11 + "libsherpa_onnx.so": "file:./src/main/cpp/types/libsherpa_onnx"
  12 + },
  13 + "keywords": [
  14 + "tts",
  15 + "asr",
  16 + "locally",
  17 + "diarization",
  18 + "privacy",
  19 + "open-source",
  20 + "speaker",
  21 + ],
  22 + "bugs": {
  23 + "url": "https://github.com/k2-fsa/sherpa-onnx/issues"
  24 + },
  25 +}
  1 +# the minimum version of CMake.
  2 +cmake_minimum_required(VERSION 3.13.0)
  3 +project(myNpmLib)
  4 +
  5 +# Disable warning about
  6 +#
  7 +# "The DOWNLOAD_EXTRACT_TIMESTAMP option was not given and policy CMP0135 is
  8 +# not set.
  9 +if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.24.0")
  10 + cmake_policy(SET CMP0135 NEW)
  11 +endif()
  12 +
  13 +set(NATIVERENDER_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR})
  14 +
  15 +if(DEFINED PACKAGE_FIND_FILE)
  16 + include(${PACKAGE_FIND_FILE})
  17 +endif()
  18 +
  19 +include_directories(${NATIVERENDER_ROOT_PATH}
  20 + ${NATIVERENDER_ROOT_PATH}/include)
  21 +
  22 +include(FetchContent)
  23 +FetchContent_Declare(node_addon_api
  24 + GIT_REPOSITORY "https://github.com/nodejs/node-addon-api.git"
  25 + GIT_TAG c679f6f4c9dc6bf9fc0d99cbe5982bd24a5e2c7b
  26 + PATCH_COMMAND git checkout . && git apply --ignore-whitespace "${CMAKE_CURRENT_LIST_DIR}/my-patch.diff"
  27 +)
  28 +FetchContent_MakeAvailable(node_addon_api)
  29 +FetchContent_GetProperties(node_addon_api)
  30 +if(NOT node_addon_api_POPULATED)
  31 + message(STATUS "Downloading node-addon-api from")
  32 + FetchContent_Populate(node_addon_api)
  33 +endif()
  34 +
  35 +message(STATUS "node-addon-api is downloaded to ${node_addon_api_SOURCE_DIR}")
  36 +include_directories(${node_addon_api_SOURCE_DIR})
  37 +
  38 +add_library(sherpa_onnx SHARED
  39 + audio-tagging.cc
  40 + keyword-spotting.cc
  41 + non-streaming-asr.cc
  42 + non-streaming-speaker-diarization.cc
  43 + non-streaming-tts.cc
  44 + punctuation.cc
  45 + sherpa-onnx-node-addon-api.cc
  46 + speaker-identification.cc
  47 + spoken-language-identification.cc
  48 + streaming-asr.cc
  49 + vad.cc
  50 + wave-reader.cc
  51 + wave-writer.cc
  52 +)
  53 +
  54 +add_library(sherpa_onnx_c_api SHARED IMPORTED)
  55 +set_target_properties(sherpa_onnx_c_api
  56 + PROPERTIES
  57 + IMPORTED_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/libs/${OHOS_ARCH}/libsherpa-onnx-c-api.so)
  58 +
  59 +add_library(onnxruntime SHARED IMPORTED)
  60 +set_target_properties(onnxruntime
  61 + PROPERTIES
  62 + IMPORTED_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/libs/${OHOS_ARCH}/libonnxruntime.so)
  63 +
  64 +
  65 +target_link_libraries(sherpa_onnx PUBLIC libace_napi.z.so
  66 + libhilog_ndk.z.so # for hilog
  67 + librawfile.z.so
  68 + sherpa_onnx_c_api onnxruntime
  69 +)
  1 +# Node
  2 +
  3 +[./c-api.h](./c-api.h) is a symbolic link to
  4 +https://github.com/k2-fsa/sherpa-onnx/blob/master/sherpa-onnx/c-api/c-api.h
  5 +
  6 +If you are using Windows, then you need to manually replace this file with
  7 +https://github.com/k2-fsa/sherpa-onnx/blob/master/sherpa-onnx/c-api/c-api.h
  8 +since Windows does not support symbolic links.
  1 +# Introduction
  2 +
  3 +You need to get the following four `.so` files using
  4 +
  5 + - [build-ohos-arm64-v8a.sh](https://github.com/k2-fsa/sherpa-onnx/blob/master/build-ohos-arm64-v8a.sh)
  6 + - [build-ohos-x86-64.sh](https://github.com/k2-fsa/sherpa-onnx/blob/master/build-ohos-x86-64.sh)
  7 +
  8 +```
  9 +.
  10 +├── README.md
  11 +├── arm64-v8a
  12 +│   ├── libonnxruntime.so
  13 +│   └── libsherpa-onnx-c-api.so
  14 +└── x86_64
  15 + ├── libonnxruntime.so
  16 + └── libsherpa-onnx-c-api.so
  17 +```
@@ -7,6 +7,18 @@ @@ -7,6 +7,18 @@
7 #include <algorithm> 7 #include <algorithm>
8 #include <string> 8 #include <string>
9 9
  10 +#if __OHOS__
  11 +#include "rawfile/raw_file_manager.h"
  12 +#include "hilog/log.h"
  13 +
  14 +#undef LOG_DOMAIN
  15 +#undef LOG_TAG
  16 +
  17 +// https://gitee.com/openharmony/docs/blob/145a084f0b742e4325915e32f8184817927d1251/en/contribute/OpenHarmony-Log-guide.md#hilog-api-usage-specifications
  18 +#define LOG_DOMAIN 0x6666
  19 +#define LOG_TAG "sherpa_onnx"
  20 +#endif
  21 +
10 #define SHERPA_ONNX_ASSIGN_ATTR_STR(c_name, js_name) \ 22 #define SHERPA_ONNX_ASSIGN_ATTR_STR(c_name, js_name) \
11 do { \ 23 do { \
12 if (o.Has(#js_name) && o.Get(#js_name).IsString()) { \ 24 if (o.Has(#js_name) && o.Get(#js_name).IsString()) { \
  1 +diff --git a/napi-inl.h b/napi-inl.h
  2 +index e7141c0..0fd90d8 100644
  3 +--- a/napi-inl.h
  4 ++++ b/napi-inl.h
  5 +@@ -2156,7 +2156,8 @@ inline ArrayBuffer::ArrayBuffer(napi_env env, napi_value value)
  6 +
  7 + inline void* ArrayBuffer::Data() {
  8 + void* data;
  9 +- napi_status status = napi_get_arraybuffer_info(_env, _value, &data, nullptr);
  10 ++ size_t byte_length;
  11 ++ napi_status status = napi_get_arraybuffer_info(_env, _value, &data, &byte_length);
  12 + NAPI_THROW_IF_FAILED(_env, status, nullptr);
  13 + return data;
  14 + }
@@ -191,6 +191,17 @@ static SherpaOnnxOfflineLMConfig GetOfflineLMConfig(Napi::Object obj) { @@ -191,6 +191,17 @@ static SherpaOnnxOfflineLMConfig GetOfflineLMConfig(Napi::Object obj) {
191 static Napi::External<SherpaOnnxOfflineRecognizer> 191 static Napi::External<SherpaOnnxOfflineRecognizer>
192 CreateOfflineRecognizerWrapper(const Napi::CallbackInfo &info) { 192 CreateOfflineRecognizerWrapper(const Napi::CallbackInfo &info) {
193 Napi::Env env = info.Env(); 193 Napi::Env env = info.Env();
  194 +#if __OHOS__
  195 + // the last argument is the NativeResourceManager
  196 + if (info.Length() != 2) {
  197 + std::ostringstream os;
  198 + os << "Expect only 2 arguments. Given: " << info.Length();
  199 +
  200 + Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
  201 +
  202 + return {};
  203 + }
  204 +#else
194 if (info.Length() != 1) { 205 if (info.Length() != 1) {
195 std::ostringstream os; 206 std::ostringstream os;
196 os << "Expect only 1 argument. Given: " << info.Length(); 207 os << "Expect only 1 argument. Given: " << info.Length();
@@ -199,6 +210,7 @@ CreateOfflineRecognizerWrapper(const Napi::CallbackInfo &info) { @@ -199,6 +210,7 @@ CreateOfflineRecognizerWrapper(const Napi::CallbackInfo &info) {
199 210
200 return {}; 211 return {};
201 } 212 }
  213 +#endif
202 214
203 if (!info[0].IsObject()) { 215 if (!info[0].IsObject()) {
204 Napi::TypeError::New(env, "Expect an object as the argument") 216 Napi::TypeError::New(env, "Expect an object as the argument")
@@ -223,8 +235,15 @@ CreateOfflineRecognizerWrapper(const Napi::CallbackInfo &info) { @@ -223,8 +235,15 @@ CreateOfflineRecognizerWrapper(const Napi::CallbackInfo &info) {
223 SHERPA_ONNX_ASSIGN_ATTR_STR(rule_fars, ruleFars); 235 SHERPA_ONNX_ASSIGN_ATTR_STR(rule_fars, ruleFars);
224 SHERPA_ONNX_ASSIGN_ATTR_FLOAT(blank_penalty, blankPenalty); 236 SHERPA_ONNX_ASSIGN_ATTR_FLOAT(blank_penalty, blankPenalty);
225 237
  238 +#if __OHOS__
  239 + std::unique_ptr<NativeResourceManager, decltype(&OH_ResourceManager_ReleaseNativeResourceManager)> mgr (OH_ResourceManager_InitNativeResourceManager(env, info[1]), &OH_ResourceManager_ReleaseNativeResourceManager);
  240 +
  241 + const SherpaOnnxOfflineRecognizer *recognizer =
  242 + SherpaOnnxCreateOfflineRecognizerOHOS(&c, mgr.get());
  243 +#else
226 const SherpaOnnxOfflineRecognizer *recognizer = 244 const SherpaOnnxOfflineRecognizer *recognizer =
227 SherpaOnnxCreateOfflineRecognizer(&c); 245 SherpaOnnxCreateOfflineRecognizer(&c);
  246 +#endif
228 247
229 SHERPA_ONNX_DELETE_C_STR(c.model_config.transducer.encoder); 248 SHERPA_ONNX_DELETE_C_STR(c.model_config.transducer.encoder);
230 SHERPA_ONNX_DELETE_C_STR(c.model_config.transducer.decoder); 249 SHERPA_ONNX_DELETE_C_STR(c.model_config.transducer.decoder);
@@ -374,8 +393,15 @@ static void AcceptWaveformOfflineWrapper(const Napi::CallbackInfo &info) { @@ -374,8 +393,15 @@ static void AcceptWaveformOfflineWrapper(const Napi::CallbackInfo &info) {
374 Napi::Float32Array samples = obj.Get("samples").As<Napi::Float32Array>(); 393 Napi::Float32Array samples = obj.Get("samples").As<Napi::Float32Array>();
375 int32_t sample_rate = obj.Get("sampleRate").As<Napi::Number>().Int32Value(); 394 int32_t sample_rate = obj.Get("sampleRate").As<Napi::Number>().Int32Value();
376 395
  396 +#if __OHOS__
  397 + // Note(fangjun): For unknown reasons on HarmonyOS, we need to divide it by
  398 + // sizeof(float) here
  399 + SherpaOnnxAcceptWaveformOffline(stream, sample_rate, samples.Data(),
  400 + samples.ElementLength() / sizeof(float));
  401 +#else
377 SherpaOnnxAcceptWaveformOffline(stream, sample_rate, samples.Data(), 402 SherpaOnnxAcceptWaveformOffline(stream, sample_rate, samples.Data(),
378 samples.ElementLength()); 403 samples.ElementLength());
  404 +#endif
379 } 405 }
380 406
381 static void DecodeOfflineStreamWrapper(const Napi::CallbackInfo &info) { 407 static void DecodeOfflineStreamWrapper(const Napi::CallbackInfo &info) {
@@ -147,6 +147,16 @@ static SherpaOnnxOnlineCtcFstDecoderConfig GetCtcFstDecoderConfig( @@ -147,6 +147,16 @@ static SherpaOnnxOnlineCtcFstDecoderConfig GetCtcFstDecoderConfig(
147 static Napi::External<SherpaOnnxOnlineRecognizer> CreateOnlineRecognizerWrapper( 147 static Napi::External<SherpaOnnxOnlineRecognizer> CreateOnlineRecognizerWrapper(
148 const Napi::CallbackInfo &info) { 148 const Napi::CallbackInfo &info) {
149 Napi::Env env = info.Env(); 149 Napi::Env env = info.Env();
  150 +#if __OHOS__
  151 + if (info.Length() != 2) {
  152 + std::ostringstream os;
  153 + os << "Expect only 2 arguments. Given: " << info.Length();
  154 +
  155 + Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
  156 +
  157 + return {};
  158 + }
  159 +#else
150 if (info.Length() != 1) { 160 if (info.Length() != 1) {
151 std::ostringstream os; 161 std::ostringstream os;
152 os << "Expect only 1 argument. Given: " << info.Length(); 162 os << "Expect only 1 argument. Given: " << info.Length();
@@ -155,6 +165,7 @@ static Napi::External<SherpaOnnxOnlineRecognizer> CreateOnlineRecognizerWrapper( @@ -155,6 +165,7 @@ static Napi::External<SherpaOnnxOnlineRecognizer> CreateOnlineRecognizerWrapper(
155 165
156 return {}; 166 return {};
157 } 167 }
  168 +#endif
158 169
159 if (!info[0].IsObject()) { 170 if (!info[0].IsObject()) {
160 Napi::TypeError::New(env, "Expect an object as the argument") 171 Napi::TypeError::New(env, "Expect an object as the argument")
@@ -199,8 +210,15 @@ static Napi::External<SherpaOnnxOnlineRecognizer> CreateOnlineRecognizerWrapper( @@ -199,8 +210,15 @@ static Napi::External<SherpaOnnxOnlineRecognizer> CreateOnlineRecognizerWrapper(
199 210
200 c.ctc_fst_decoder_config = GetCtcFstDecoderConfig(o); 211 c.ctc_fst_decoder_config = GetCtcFstDecoderConfig(o);
201 212
  213 +#if __OHOS__
  214 + std::unique_ptr<NativeResourceManager, decltype(&OH_ResourceManager_ReleaseNativeResourceManager)> mgr (OH_ResourceManager_InitNativeResourceManager(env, info[1]), &OH_ResourceManager_ReleaseNativeResourceManager);
  215 +
  216 + const SherpaOnnxOnlineRecognizer *recognizer =
  217 + SherpaOnnxCreateOnlineRecognizerOHOS(&c, mgr.get());
  218 +#else
202 const SherpaOnnxOnlineRecognizer *recognizer = 219 const SherpaOnnxOnlineRecognizer *recognizer =
203 SherpaOnnxCreateOnlineRecognizer(&c); 220 SherpaOnnxCreateOnlineRecognizer(&c);
  221 +#endif
204 222
205 if (c.model_config.transducer.encoder) { 223 if (c.model_config.transducer.encoder) {
206 delete[] c.model_config.transducer.encoder; 224 delete[] c.model_config.transducer.encoder;
@@ -385,8 +403,13 @@ static void AcceptWaveformWrapper(const Napi::CallbackInfo &info) { @@ -385,8 +403,13 @@ static void AcceptWaveformWrapper(const Napi::CallbackInfo &info) {
385 Napi::Float32Array samples = obj.Get("samples").As<Napi::Float32Array>(); 403 Napi::Float32Array samples = obj.Get("samples").As<Napi::Float32Array>();
386 int32_t sample_rate = obj.Get("sampleRate").As<Napi::Number>().Int32Value(); 404 int32_t sample_rate = obj.Get("sampleRate").As<Napi::Number>().Int32Value();
387 405
  406 +#if __OHOS__
  407 + SherpaOnnxOnlineStreamAcceptWaveform(stream, sample_rate, samples.Data(),
  408 + samples.ElementLength() / sizeof(float));
  409 +#else
388 SherpaOnnxOnlineStreamAcceptWaveform(stream, sample_rate, samples.Data(), 410 SherpaOnnxOnlineStreamAcceptWaveform(stream, sample_rate, samples.Data(),
389 samples.ElementLength()); 411 samples.ElementLength());
  412 +#endif
390 } 413 }
391 414
392 static Napi::Boolean IsOnlineStreamReadyWrapper( 415 static Napi::Boolean IsOnlineStreamReadyWrapper(
  1 +export const readWave: (filename: string, enableExternalBuffer: boolean = true) => {samples: Float32Array, sampleRate: number};
  2 +export const readWaveFromBinary: (data: Uint8Array, enableExternalBuffer: boolean = true) => {samples: Float32Array, sampleRate: number};
  3 +export const createCircularBuffer: (capacity: number) => object;
  4 +export const circularBufferPush: (handle: object, samples: Float32Array) => void;
  5 +export const circularBufferGet: (handle: object, index: number, n: number, enableExternalBuffer: boolean = true) => Float32Array;
  6 +export const circularBufferPop: (handle: object, n: number) => void;
  7 +export const circularBufferSize: (handle: object) => number;
  8 +export const circularBufferHead: (handle: object) => number;
  9 +export const circularBufferReset: (handle: object) => void;
  10 +
  11 +export const createVoiceActivityDetector: (config: object, bufferSizeInSeconds: number, mgr?: object) => object;
  12 +export const voiceActivityDetectorAcceptWaveform: (handle: object, samples: Float32Array) => void;
  13 +export const voiceActivityDetectorIsEmpty: (handle: object) => boolean;
  14 +export const voiceActivityDetectorIsDetected: (handle: object) => boolean;
  15 +export const voiceActivityDetectorPop: (handle: object) => void;
  16 +export const voiceActivityDetectorClear: (handle: object) => void;
  17 +export const voiceActivityDetectorFront: (handle: object, enableExternalBuffer: boolean = true) => {samples: Float32Array, start: number};
  18 +export const voiceActivityDetectorReset: (handle: object) => void;
  19 +export const voiceActivityDetectorFlush: (handle: object) => void;
  20 +
  21 +export const createOfflineRecognizer: (config: object, mgr?: object) => object;
  22 +export const createOfflineStream: (handle: object) => object;
  23 +export const acceptWaveformOffline: (handle: object, audio: object) => void;
  24 +export const decodeOfflineStream: (handle: object, streamHandle: object) => void;
  25 +export const getOfflineStreamResultAsJson: (streamHandle: object) => string;
  26 +
  27 +export const createOnlineRecognizer: (config: object, mgr?: object) => object;
  28 +export const createOnlineStream: (handle: object) => object;
  29 +export const acceptWaveformOnline: (handle: object, audio: object) => void;
  30 +export const inputFinished: (streamHandle: object) => void;
  31 +export const isOnlineStreamReady: (handle: object, streamHandle: object) => boolean;
  32 +export const decodeOnlineStream: (handle: object, streamHandle: object) => void;
  33 +export const isEndpoint: (handle: object, streamHandle: object) => boolean;
  34 +export const reset: (handle: object, streamHandle: object) => void;
  35 +export const getOnlineStreamResultAsJson: (handle: object, streamHandle: object) => string;
  1 +{
  2 + "name": "libsherpa_onnx.so",
  3 + "types": "./Index.d.ts",
  4 + "version": "1.0.0",
  5 + "description": "Please describe the basic information."
  6 +}
@@ -67,7 +67,14 @@ static void CircularBufferPushWrapper(const Napi::CallbackInfo &info) { @@ -67,7 +67,14 @@ static void CircularBufferPushWrapper(const Napi::CallbackInfo &info) {
67 } 67 }
68 68
69 Napi::Float32Array data = info[1].As<Napi::Float32Array>(); 69 Napi::Float32Array data = info[1].As<Napi::Float32Array>();
  70 +
  71 +#if __OHOS__
  72 + // Note(fangjun): Normally, we don't need to divied it by sizeof(float).
  73 + // However, data.ElementLength() here returns number of bytes, not number of elements.
  74 + SherpaOnnxCircularBufferPush(buf, data.Data(), data.ElementLength() / sizeof(float));
  75 +#else
70 SherpaOnnxCircularBufferPush(buf, data.Data(), data.ElementLength()); 76 SherpaOnnxCircularBufferPush(buf, data.Data(), data.ElementLength());
  77 +#endif
71 } 78 }
72 79
73 // see https://github.com/nodejs/node-addon-api/blob/main/doc/typed_array.md 80 // see https://github.com/nodejs/node-addon-api/blob/main/doc/typed_array.md
@@ -287,6 +294,17 @@ static SherpaOnnxSileroVadModelConfig GetSileroVadConfig( @@ -287,6 +294,17 @@ static SherpaOnnxSileroVadModelConfig GetSileroVadConfig(
287 static Napi::External<SherpaOnnxVoiceActivityDetector> 294 static Napi::External<SherpaOnnxVoiceActivityDetector>
288 CreateVoiceActivityDetectorWrapper(const Napi::CallbackInfo &info) { 295 CreateVoiceActivityDetectorWrapper(const Napi::CallbackInfo &info) {
289 Napi::Env env = info.Env(); 296 Napi::Env env = info.Env();
  297 +#if __OHOS__
  298 + // the last argument is a NativeResourceManager
  299 + if (info.Length() != 3) {
  300 + std::ostringstream os;
  301 + os << "Expect only 3 arguments. Given: " << info.Length();
  302 +
  303 + Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
  304 +
  305 + return {};
  306 + }
  307 +#else
290 if (info.Length() != 2) { 308 if (info.Length() != 2) {
291 std::ostringstream os; 309 std::ostringstream os;
292 os << "Expect only 2 arguments. Given: " << info.Length(); 310 os << "Expect only 2 arguments. Given: " << info.Length();
@@ -295,6 +313,7 @@ CreateVoiceActivityDetectorWrapper(const Napi::CallbackInfo &info) { @@ -295,6 +313,7 @@ CreateVoiceActivityDetectorWrapper(const Napi::CallbackInfo &info) {
295 313
296 return {}; 314 return {};
297 } 315 }
  316 +#endif
298 317
299 if (!info[0].IsObject()) { 318 if (!info[0].IsObject()) {
300 Napi::TypeError::New(env, 319 Napi::TypeError::New(env,
@@ -333,8 +352,15 @@ CreateVoiceActivityDetectorWrapper(const Napi::CallbackInfo &info) { @@ -333,8 +352,15 @@ CreateVoiceActivityDetectorWrapper(const Napi::CallbackInfo &info) {
333 352
334 float buffer_size_in_seconds = info[1].As<Napi::Number>().FloatValue(); 353 float buffer_size_in_seconds = info[1].As<Napi::Number>().FloatValue();
335 354
  355 +#if __OHOS__
  356 + std::unique_ptr<NativeResourceManager, decltype(&OH_ResourceManager_ReleaseNativeResourceManager)> mgr(OH_ResourceManager_InitNativeResourceManager(env, info[2]), &OH_ResourceManager_ReleaseNativeResourceManager);
  357 +
  358 + SherpaOnnxVoiceActivityDetector *vad =
  359 + SherpaOnnxCreateVoiceActivityDetectorOHOS(&c, buffer_size_in_seconds, mgr.get());
  360 +#else
336 SherpaOnnxVoiceActivityDetector *vad = 361 SherpaOnnxVoiceActivityDetector *vad =
337 SherpaOnnxCreateVoiceActivityDetector(&c, buffer_size_in_seconds); 362 SherpaOnnxCreateVoiceActivityDetector(&c, buffer_size_in_seconds);
  363 +#endif
338 364
339 if (c.silero_vad.model) { 365 if (c.silero_vad.model) {
340 delete[] c.silero_vad.model; 366 delete[] c.silero_vad.model;
@@ -383,8 +409,14 @@ static void VoiceActivityDetectorAcceptWaveformWrapper( @@ -383,8 +409,14 @@ static void VoiceActivityDetectorAcceptWaveformWrapper(
383 409
384 Napi::Float32Array samples = info[1].As<Napi::Float32Array>(); 410 Napi::Float32Array samples = info[1].As<Napi::Float32Array>();
385 411
  412 +#if __OHOS__
  413 + // Note(fangjun): For unknown reasons, we need to use `/sizeof(float)` here for Huawei
  414 + SherpaOnnxVoiceActivityDetectorAcceptWaveform(vad, samples.Data(),
  415 + samples.ElementLength() / sizeof(float));
  416 +#else
386 SherpaOnnxVoiceActivityDetectorAcceptWaveform(vad, samples.Data(), 417 SherpaOnnxVoiceActivityDetectorAcceptWaveform(vad, samples.Data(),
387 samples.ElementLength()); 418 samples.ElementLength());
  419 +#endif
388 } 420 }
389 421
390 static Napi::Boolean VoiceActivityDetectorEmptyWrapper( 422 static Napi::Boolean VoiceActivityDetectorEmptyWrapper(
@@ -85,7 +85,87 @@ static Napi::Object ReadWaveWrapper(const Napi::CallbackInfo &info) { @@ -85,7 +85,87 @@ static Napi::Object ReadWaveWrapper(const Napi::CallbackInfo &info) {
85 } 85 }
86 } 86 }
87 87
  88 +static Napi::Object ReadWaveFromBinaryWrapper(const Napi::CallbackInfo &info) {
  89 + Napi::Env env = info.Env();
  90 + if (info.Length() > 2) {
  91 + std::ostringstream os;
  92 + os << "Expect only 1 or 2 arguments. Given: " << info.Length();
  93 +
  94 + Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
  95 +
  96 + return {};
  97 + }
  98 +
  99 + if (!info[0].IsTypedArray()) {
  100 + Napi::TypeError::New(env, "Argument 0 should be a float32 array")
  101 + .ThrowAsJavaScriptException();
  102 +
  103 + return {};
  104 + }
  105 +
  106 + Napi::Uint8Array data = info[0].As<Napi::Uint8Array>();
  107 + int32_t n = data.ElementLength();
  108 + const SherpaOnnxWave *wave = SherpaOnnxReadWaveFromBinaryData(reinterpret_cast<const char*>(data.Data()), n);
  109 + if (!wave) {
  110 + std::ostringstream os;
  111 + os << "Failed to read wave";
  112 + Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
  113 +
  114 + return {};
  115 + }
  116 +
  117 + bool enable_external_buffer = true;
  118 + if (info.Length() == 2) {
  119 + if (info[1].IsBoolean()) {
  120 + enable_external_buffer = info[1].As<Napi::Boolean>().Value();
  121 + } else {
  122 + Napi::TypeError::New(env, "Argument 1 should be a boolean")
  123 + .ThrowAsJavaScriptException();
  124 +
  125 + return {};
  126 + }
  127 + }
  128 +
  129 + if (enable_external_buffer) {
  130 + Napi::ArrayBuffer arrayBuffer = Napi::ArrayBuffer::New(
  131 + env, const_cast<float *>(wave->samples),
  132 + sizeof(float) * wave->num_samples,
  133 + [](Napi::Env /*env*/, void * /*data*/, const SherpaOnnxWave *hint) {
  134 + SherpaOnnxFreeWave(hint);
  135 + },
  136 + wave);
  137 + Napi::Float32Array float32Array =
  138 + Napi::Float32Array::New(env, wave->num_samples, arrayBuffer, 0);
  139 +
  140 + Napi::Object obj = Napi::Object::New(env);
  141 + obj.Set(Napi::String::New(env, "samples"), float32Array);
  142 + obj.Set(Napi::String::New(env, "sampleRate"), wave->sample_rate);
  143 + return obj;
  144 + } else {
  145 + // don't use external buffer
  146 + Napi::ArrayBuffer arrayBuffer =
  147 + Napi::ArrayBuffer::New(env, sizeof(float) * wave->num_samples);
  148 +
  149 + Napi::Float32Array float32Array =
  150 + Napi::Float32Array::New(env, wave->num_samples, arrayBuffer, 0);
  151 +
  152 + std::copy(wave->samples, wave->samples + wave->num_samples,
  153 + float32Array.Data());
  154 +
  155 + Napi::Object obj = Napi::Object::New(env);
  156 + obj.Set(Napi::String::New(env, "samples"), float32Array);
  157 + obj.Set(Napi::String::New(env, "sampleRate"), wave->sample_rate);
  158 +
  159 + SherpaOnnxFreeWave(wave);
  160 +
  161 + return obj;
  162 + }
  163 +}
  164 +
88 void InitWaveReader(Napi::Env env, Napi::Object exports) { 165 void InitWaveReader(Napi::Env env, Napi::Object exports) {
89 exports.Set(Napi::String::New(env, "readWave"), 166 exports.Set(Napi::String::New(env, "readWave"),
90 Napi::Function::New(env, ReadWaveWrapper)); 167 Napi::Function::New(env, ReadWaveWrapper));
  168 +
  169 + exports.Set(Napi::String::New(env, "readWaveFromBinary"),
  170 + Napi::Function::New(env, ReadWaveFromBinaryWrapper));
91 } 171 }
  1 +import hilog from '@ohos.hilog';
  2 +import testNapi from 'libsherpa_onnx.so';
  3 +
  4 +@Component
  5 +export struct MainPage {
  6 + @State message: string = 'Hello World';
  7 +
  8 + build() {
  9 + Row() {
  10 + Column() {
  11 + Text(this.message)
  12 + .fontSize(50)
  13 + .fontWeight(FontWeight.Bold)
  14 + .onClick(() => {
  15 + })
  16 + }
  17 + .width('100%')
  18 + }
  19 + .height('100%')
  20 + }
  21 +}
  1 +import {
  2 + acceptWaveformOffline,
  3 + createOfflineRecognizer,
  4 + createOfflineStream,
  5 + decodeOfflineStream,
  6 + getOfflineStreamResultAsJson,
  7 +} from 'libsherpa_onnx.so';
  8 +
  9 +export interface Samples {
  10 + samples: Float32Array;
  11 + sampleRate: number;
  12 +}
  13 +
  14 +export class OfflineStream {
  15 + public handle: object;
  16 +
  17 + constructor(handle: object) {
  18 + this.handle = handle;
  19 + }
  20 +
  21 + // obj is {samples: samples, sampleRate: sampleRate}
  22 + // samples is a float32 array containing samples in the range [-1, 1]
  23 + // sampleRate is a number
  24 + acceptWaveform(obj: Samples) {
  25 + acceptWaveformOffline(this.handle, obj)
  26 + }
  27 +}
  28 +
  29 +export class FeatureConfig {
  30 + public sampleRate: number = 16000;
  31 + public featureDim: number = 80;
  32 +}
  33 +
  34 +export class OfflineTransducerModelConfig {
  35 + public encoder: string = '';
  36 + public decoder: string = '';
  37 + public joiner: string = '';
  38 +}
  39 +
  40 +export class OfflineParaformerModelConfig {
  41 + public model: string = '';
  42 +}
  43 +
  44 +export class OfflineNemoEncDecCtcModelConfig {
  45 + public model: string = '';
  46 +}
  47 +
  48 +export class OfflineWhisperModelConfig {
  49 + public encoder: string = '';
  50 + public decoder: string = '';
  51 + public language: string = '';
  52 + public task: string = 'transcribe';
  53 + public tailPaddings: number = -1;
  54 +}
  55 +
  56 +export class OfflineTdnnModelConfig {
  57 + public model: string = '';
  58 +}
  59 +
  60 +export class OfflineSenseVoiceModelConfig {
  61 + public model: string = '';
  62 + public language: string = '';
  63 + public useItn: boolean = false;
  64 +}
  65 +
  66 +export class OfflineMoonshineModelConfig {
  67 + public preprocessor: string = '';
  68 + public encoder: string = '';
  69 + public uncachedDecoder: string = '';
  70 + public cachedDecoder: string = '';
  71 +}
  72 +
  73 +export class OfflineModelConfig {
  74 + public transducer: OfflineTransducerModelConfig = new OfflineTransducerModelConfig();
  75 + public paraformer: OfflineParaformerModelConfig = new OfflineParaformerModelConfig();
  76 + public nemoCtc: OfflineNemoEncDecCtcModelConfig = new OfflineNemoEncDecCtcModelConfig();
  77 + public whisper: OfflineWhisperModelConfig = new OfflineWhisperModelConfig();
  78 + public tdnn: OfflineTdnnModelConfig = new OfflineTdnnModelConfig();
  79 + public tokens: string = '';
  80 + public numThreads: number = 1;
  81 + public debug: boolean = false;
  82 + public provider: string = "cpu";
  83 + public modelType: string = '';
  84 + public modelingUnit: string = "cjkchar";
  85 + public bpeVocab: string = '';
  86 + public telespeechCtc: string = '';
  87 + public senseVoice: OfflineSenseVoiceModelConfig = new OfflineSenseVoiceModelConfig();
  88 + public moonshine: OfflineMoonshineModelConfig = new OfflineMoonshineModelConfig();
  89 +}
  90 +
  91 +export class OfflineLMConfig {
  92 + public model: string = '';
  93 + public scale: number = 1.0;
  94 +}
  95 +
  96 +export class OfflineRecognizerConfig {
  97 + public featConfig: FeatureConfig = new FeatureConfig();
  98 + public modelConfig: OfflineModelConfig = new OfflineModelConfig();
  99 + public lmConfig: OfflineLMConfig = new OfflineLMConfig();
  100 + public decodingMethod: string = "greedy_search";
  101 + public maxActivePaths: number = 4;
  102 + public hotwordsFfile: string = '';
  103 + public hotwordsScore: number = 1.5;
  104 + public ruleFsts: string = '';
  105 + public ruleFars: string = '';
  106 + public blankPenalty: number = 0;
  107 +}
  108 +
  109 +export class OfflineRecognizerResult {
  110 + public text: string = '';
  111 + public timestamps: number[] = [];
  112 + public tokens: string[] = [];
  113 + public json = '';
  114 + public lang: string = '';
  115 + public emotion: string = '';
  116 + public event: string = '';
  117 +}
  118 +
  119 +interface OfflineRecognizerResultJson {
  120 + text: string;
  121 + timestamps: number[];
  122 + tokens: string[];
  123 + lang: string;
  124 + emotion: string;
  125 + event: string;
  126 +}
  127 +
  128 +export class OfflineRecognizer {
  129 + public handle: object;
  130 + public config: OfflineRecognizerConfig;
  131 +
  132 + constructor(config: OfflineRecognizerConfig, mgr?: object) {
  133 + this.handle = createOfflineRecognizer(config, mgr);
  134 + this.config = config
  135 + }
  136 +
  137 + createStream(): OfflineStream {
  138 + const handle: object = createOfflineStream(this.handle);
  139 + return new OfflineStream(handle);
  140 + }
  141 +
  142 + decode(stream: OfflineStream) {
  143 + decodeOfflineStream(this.handle, stream.handle);
  144 + }
  145 +
  146 + getResult(stream: OfflineStream): OfflineRecognizerResult {
  147 + const jsonStr: string = getOfflineStreamResultAsJson(stream.handle);
  148 +
  149 + let o = JSON.parse(jsonStr) as OfflineRecognizerResultJson;
  150 +
  151 + const r = new OfflineRecognizerResult()
  152 + r.text = o.text
  153 + r.timestamps = o.timestamps;
  154 + r.tokens = o.tokens;
  155 + r.json = jsonStr;
  156 + r.lang = o.lang;
  157 + r.emotion = o.emotion;
  158 + r.event = o.event;
  159 +
  160 + return r;
  161 + }
  162 +}
  1 +import {
  2 + acceptWaveformOnline,
  3 + createOnlineRecognizer,
  4 + createOnlineStream,
  5 + decodeOnlineStream,
  6 + getOnlineStreamResultAsJson,
  7 + inputFinished,
  8 + isEndpoint,
  9 + isOnlineStreamReady,
  10 + reset,
  11 +} from 'libsherpa_onnx.so';
  12 +
  13 +import { FeatureConfig, Samples } from './NonStreamingAsr';
  14 +
  15 +export class OnlineStream {
  16 + public handle: object;
  17 +
  18 + constructor(handle: object) {
  19 + this.handle = handle;
  20 + }
  21 +
  22 + // obj is {samples: samples, sampleRate: sampleRate}
  23 + // samples is a float32 array containing samples in the range [-1, 1]
  24 + // sampleRate is a number
  25 + acceptWaveform(obj: Samples) {
  26 + acceptWaveformOnline(this.handle, obj)
  27 + }
  28 +
  29 + inputFinished() {
  30 + inputFinished(this.handle)
  31 + }
  32 +}
  33 +
  34 +export class OnlineTransducerModelConfig {
  35 + public encoder: string = '';
  36 + public decoder: string = '';
  37 + public joiner: string = '';
  38 +}
  39 +
  40 +export class OnlineParaformerModelConfig {
  41 + public encoder: string = '';
  42 + public decoder: string = '';
  43 +}
  44 +
  45 +export class OnlineZipformer2CtcModelConfig {
  46 + public model: string = '';
  47 +}
  48 +
  49 +export class OnlineModelConfig {
  50 + public transducer: OnlineTransducerModelConfig = new OnlineTransducerModelConfig();
  51 + public paraformer: OnlineParaformerModelConfig = new OnlineParaformerModelConfig();
  52 + public zipformer2_ctc: OnlineZipformer2CtcModelConfig = new OnlineZipformer2CtcModelConfig();
  53 + public tokens: string = '';
  54 + public numThreads: number = 1;
  55 + public provider: string = "cpu";
  56 + public debug: boolean = false;
  57 + public modelType: string = '';
  58 + public modelingUnit: string = "cjkchar";
  59 + public bpeVocab: string = '';
  60 +}
  61 +
  62 +export class OnlineCtcFstDecoderConfig {
  63 + public graph: string = '';
  64 + public maxActive: number = 3000;
  65 +}
  66 +
  67 +export class OnlineRecognizerConfig {
  68 + public featConfig: FeatureConfig = new FeatureConfig();
  69 + public modelConfig: OnlineModelConfig = new OnlineModelConfig();
  70 + public decodingMethod: string = "greedy_search";
  71 + public maxActivePaths: number = 4;
  72 + public enableEndpoint: boolean = false;
  73 + public rule1MinTrailingSilence: number = 2.4;
  74 + public rule2MinTrailingSilence: number = 1.2;
  75 + public rule3MinUtteranceLength: number = 20;
  76 + public hotwordsFile: string = '';
  77 + public hotwordsScore: number = 1.5;
  78 + public ctcFstDecoderConfig: OnlineCtcFstDecoderConfig = new OnlineCtcFstDecoderConfig();
  79 + public ruleFsts: string = '';
  80 + public ruleFars: string = '';
  81 + public blankPenalty: number = 0;
  82 +}
  83 +
  84 +interface OnlineRecognizerResultJson {
  85 + text: string;
  86 + timestamps: number[];
  87 + tokens: string[];
  88 +}
  89 +
  90 +export class OnlineRecognizerResult {
  91 + public text: string = '';
  92 + public tokens: string[] = [];
  93 + public timestamps: number[] = [];
  94 + public json: string = '';
  95 +}
  96 +
  97 +export class OnlineRecognizer {
  98 + public handle: object;
  99 + public config: OnlineRecognizerConfig
  100 +
  101 + constructor(config: OnlineRecognizerConfig, mgr?: object) {
  102 + this.handle = createOnlineRecognizer(config, mgr);
  103 + this.config = config
  104 + }
  105 +
  106 + createStream(): OnlineStream {
  107 + const handle: object = createOnlineStream(this.handle);
  108 + return new OnlineStream(handle);
  109 + }
  110 +
  111 + isReady(stream: OnlineStream): boolean {
  112 + return isOnlineStreamReady(this.handle, stream.handle);
  113 + }
  114 +
  115 + decode(stream: OnlineStream) {
  116 + decodeOnlineStream(this.handle, stream.handle);
  117 + }
  118 +
  119 + isEndpoint(stream: OnlineStream): boolean {
  120 + return isEndpoint(this.handle, stream.handle);
  121 + }
  122 +
  123 + reset(stream: OnlineStream) {
  124 + reset(this.handle, stream.handle);
  125 + }
  126 +
  127 + getResult(stream: OnlineStream): OnlineRecognizerResult {
  128 + const jsonStr: string =
  129 + getOnlineStreamResultAsJson(this.handle, stream.handle);
  130 +
  131 + let o = JSON.parse(jsonStr) as OnlineRecognizerResultJson;
  132 +
  133 + const r = new OnlineRecognizerResult()
  134 + r.text = o.text
  135 + r.timestamps = o.timestamps;
  136 + r.tokens = o.tokens;
  137 + r.json = jsonStr;
  138 +
  139 + return r;
  140 + }
  141 +}
  1 +import {
  2 + circularBufferGet,
  3 + circularBufferHead,
  4 + circularBufferPop,
  5 + circularBufferPush,
  6 + circularBufferReset,
  7 + circularBufferSize,
  8 + createCircularBuffer,
  9 + createVoiceActivityDetector,
  10 + voiceActivityDetectorAcceptWaveform,
  11 + voiceActivityDetectorClear,
  12 + voiceActivityDetectorFlush,
  13 + voiceActivityDetectorFront,
  14 + voiceActivityDetectorIsDetected,
  15 + voiceActivityDetectorIsEmpty,
  16 + voiceActivityDetectorPop,
  17 + voiceActivityDetectorReset,
  18 +} from 'libsherpa_onnx.so';
  19 +
  20 +export class SileroVadConfig {
  21 + public model: string;
  22 + public threshold: number;
  23 + public minSpeechDuration: number;
  24 + public minSilenceDuration: number;
  25 + public windowSize: number;
  26 +
  27 + public constructor(model: string, threshold: number, minSpeechDuration: number, minSilenceDuration: number,
  28 + windowSize: number) {
  29 + this.model = model;
  30 + this.threshold = threshold;
  31 + this.minSpeechDuration = minSpeechDuration;
  32 + this.minSilenceDuration = minSilenceDuration;
  33 + this.windowSize = windowSize;
  34 + }
  35 +}
  36 +
  37 +export class VadConfig {
  38 + public sileroVad: SileroVadConfig;
  39 + public sampleRate: number;
  40 + public debug: boolean;
  41 + public numThreads: number;
  42 +
  43 + public constructor(sileroVad: SileroVadConfig, sampleRate: number, debug: boolean, numThreads: number) {
  44 + this.sileroVad = sileroVad;
  45 + this.sampleRate = sampleRate;
  46 + this.debug = debug;
  47 + this.numThreads = numThreads;
  48 + }
  49 +}
  50 +
  51 +export class CircularBuffer {
  52 + private handle: object;
  53 +
  54 + constructor(capacity: number) {
  55 + this.handle = createCircularBuffer(capacity);
  56 + }
  57 +
  58 + // samples is a float32 array
  59 + push(samples: Float32Array) {
  60 + console.log(`here samples: ${samples}`);
  61 + circularBufferPush(this.handle, samples);
  62 + }
  63 +
  64 + // return a float32 array
  65 + get(startIndex: number, n: number, enableExternalBuffer: boolean = true): Float32Array {
  66 + return circularBufferGet(
  67 + this.handle, startIndex, n, enableExternalBuffer);
  68 + }
  69 +
  70 + pop(n: number) {
  71 + circularBufferPop(this.handle, n);
  72 + }
  73 +
  74 + size(): number {
  75 + return circularBufferSize(this.handle);
  76 + }
  77 +
  78 + head(): number {
  79 + return circularBufferHead(this.handle);
  80 + }
  81 +
  82 + reset() {
  83 + circularBufferReset(this.handle);
  84 + }
  85 +}
  86 +
  87 +export interface SpeechSegment {
  88 + samples: Float32Array;
  89 + start: number;
  90 +}
  91 +
  92 +export class Vad {
  93 + public config: VadConfig;
  94 + private handle: object;
  95 +
  96 + constructor(config: VadConfig, bufferSizeInSeconds?: number, mgr?: object) {
  97 + this.handle =
  98 + createVoiceActivityDetector(config, bufferSizeInSeconds, mgr);
  99 + this.config = config;
  100 + }
  101 +
  102 + acceptWaveform(samples: Float32Array): void {
  103 + voiceActivityDetectorAcceptWaveform(this.handle, samples);
  104 + }
  105 +
  106 + isEmpty(): boolean {
  107 + return voiceActivityDetectorIsEmpty(this.handle);
  108 + }
  109 +
  110 + isDetected(): boolean {
  111 + return voiceActivityDetectorIsDetected(this.handle);
  112 + }
  113 +
  114 + pop(): void {
  115 + voiceActivityDetectorPop(this.handle);
  116 + }
  117 +
  118 + clear(): void {
  119 + voiceActivityDetectorClear(this.handle);
  120 + }
  121 +
  122 + front(enableExternalBuffer = true): SpeechSegment {
  123 + return voiceActivityDetectorFront(this.handle, enableExternalBuffer);
  124 + }
  125 +
  126 + reset(): void {
  127 + voiceActivityDetectorReset(this.handle);
  128 + }
  129 +
  130 + flush(): void {
  131 + voiceActivityDetectorFlush(this.handle);
  132 + }
  133 +}
  1 +{
  2 + "module": {
  3 + "name": "sherpa_onnx",
  4 + "type": "har",
  5 + "deviceTypes": [
  6 + "default",
  7 + "tablet",
  8 + "2in1"
  9 + ]
  10 + }
  11 +}
  1 +{
  2 + "string": [
  3 + {
  4 + "name": "page_show",
  5 + "value": "page from package"
  6 + }
  7 + ]
  8 +}
  1 +{
  2 + "string": [
  3 + {
  4 + "name": "page_show",
  5 + "value": "page from package"
  6 + }
  7 + ]
  8 +}
  1 +{
  2 + "string": [
  3 + {
  4 + "name": "page_show",
  5 + "value": "page from package"
  6 + }
  7 + ]
  8 +}
  1 +import hilog from '@ohos.hilog';
  2 +import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from '@ohos/hypium';
  3 +
  4 +export default function abilityTest() {
  5 + describe('ActsAbilityTest', () => {
  6 + // Defines a test suite. Two parameters are supported: test suite name and test suite function.
  7 + beforeAll(() => {
  8 + // Presets an action, which is performed only once before all test cases of the test suite start.
  9 + // This API supports only one parameter: preset action function.
  10 + })
  11 + beforeEach(() => {
  12 + // Presets an action, which is performed before each unit test case starts.
  13 + // The number of execution times is the same as the number of test cases defined by **it**.
  14 + // This API supports only one parameter: preset action function.
  15 + })
  16 + afterEach(() => {
  17 + // Presets a clear action, which is performed after each unit test case ends.
  18 + // The number of execution times is the same as the number of test cases defined by **it**.
  19 + // This API supports only one parameter: clear action function.
  20 + })
  21 + afterAll(() => {
  22 + // Presets a clear action, which is performed after all test cases of the test suite end.
  23 + // This API supports only one parameter: clear action function.
  24 + })
  25 + it('assertContain', 0, () => {
  26 + // Defines a test case. This API supports three parameters: test case name, filter parameter, and test case function.
  27 + hilog.info(0x0000, 'testTag', '%{public}s', 'it begin');
  28 + let a = 'abc';
  29 + let b = 'b';
  30 + // Defines a variety of assertion methods, which are used to declare expected boolean conditions.
  31 + expect(a).assertContain(b);
  32 + expect(a).assertEqual(a);
  33 + })
  34 + })
  35 +}
  1 +import abilityTest from './Ability.test';
  2 +
  3 +export default function testsuite() {
  4 + abilityTest();
  5 +}
  1 +{
  2 + "module": {
  3 + "name": "sherpa_onnx_test",
  4 + "type": "feature",
  5 + "deviceTypes": [
  6 + "default",
  7 + "tablet",
  8 + "2in1"
  9 + ],
  10 + "deliveryWithInstall": true,
  11 + "installationFree": false
  12 + }
  13 +}
  1 +import localUnitTest from './LocalUnit.test';
  2 +
  3 +export default function testsuite() {
  4 + localUnitTest();
  5 +}
  1 +import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from '@ohos/hypium';
  2 +
  3 +export default function localUnitTest() {
  4 + describe('localUnitTest', () => {
  5 + // Defines a test suite. Two parameters are supported: test suite name and test suite function.
  6 + beforeAll(() => {
  7 + // Presets an action, which is performed only once before all test cases of the test suite start.
  8 + // This API supports only one parameter: preset action function.
  9 + });
  10 + beforeEach(() => {
  11 + // Presets an action, which is performed before each unit test case starts.
  12 + // The number of execution times is the same as the number of test cases defined by **it**.
  13 + // This API supports only one parameter: preset action function.
  14 + });
  15 + afterEach(() => {
  16 + // Presets a clear action, which is performed after each unit test case ends.
  17 + // The number of execution times is the same as the number of test cases defined by **it**.
  18 + // This API supports only one parameter: clear action function.
  19 + });
  20 + afterAll(() => {
  21 + // Presets a clear action, which is performed after all test cases of the test suite end.
  22 + // This API supports only one parameter: clear action function.
  23 + });
  24 + it('assertContain', 0, () => {
  25 + // Defines a test case. This API supports three parameters: test case name, filter parameter, and test case function.
  26 + let a = 'abc';
  27 + let b = 'b';
  28 + // Defines a variety of assertion methods, which are used to declare expected boolean conditions.
  29 + expect(a).assertContain(b);
  30 + expect(a).assertEqual(a);
  31 + });
  32 + });
  33 +}
  1 +../../../harmony-os/SherpaOnnxHar/sherpa_onnx/src/main/cpp/audio-tagging.cc
  1 +../../../harmony-os/SherpaOnnxHar/sherpa_onnx/src/main/cpp/keyword-spotting.cc
  1 +../../../harmony-os/SherpaOnnxHar/sherpa_onnx/src/main/cpp/macros.h
  1 +../../../harmony-os/SherpaOnnxHar/sherpa_onnx/src/main/cpp/non-streaming-asr.cc
  1 +../../../harmony-os/SherpaOnnxHar/sherpa_onnx/src/main/cpp/non-streaming-speaker-diarization.cc
  1 +../../../harmony-os/SherpaOnnxHar/sherpa_onnx/src/main/cpp/non-streaming-tts.cc
  1 +../../../harmony-os/SherpaOnnxHar/sherpa_onnx/src/main/cpp/punctuation.cc
  1 +../../../harmony-os/SherpaOnnxHar/sherpa_onnx/src/main/cpp/sherpa-onnx-node-addon-api.cc
  1 +../../../harmony-os/SherpaOnnxHar/sherpa_onnx/src/main/cpp/speaker-identification.cc
  1 +../../../harmony-os/SherpaOnnxHar/sherpa_onnx/src/main/cpp/spoken-language-identification.cc
  1 +../../../harmony-os/SherpaOnnxHar/sherpa_onnx/src/main/cpp/streaming-asr.cc
  1 +../../../harmony-os/SherpaOnnxHar/sherpa_onnx/src/main/cpp/vad.cc
  1 +../../../harmony-os/SherpaOnnxHar/sherpa_onnx/src/main/cpp/wave-reader.cc
  1 +../../../harmony-os/SherpaOnnxHar/sherpa_onnx/src/main/cpp/wave-writer.cc
@@ -8,6 +8,7 @@ @@ -8,6 +8,7 @@
8 #include <cstring> 8 #include <cstring>
9 #include <memory> 9 #include <memory>
10 #include <string> 10 #include <string>
  11 +#include <strstream>
11 #include <utility> 12 #include <utility>
12 #include <vector> 13 #include <vector>
13 14
@@ -1201,6 +1202,28 @@ const SherpaOnnxWave *SherpaOnnxReadWave(const char *filename) { @@ -1201,6 +1202,28 @@ const SherpaOnnxWave *SherpaOnnxReadWave(const char *filename) {
1201 return wave; 1202 return wave;
1202 } 1203 }
1203 1204
  1205 +const SherpaOnnxWave *SherpaOnnxReadWaveFromBinaryData(const char *data,
  1206 + int32_t n) {
  1207 + int32_t sample_rate = -1;
  1208 + bool is_ok = false;
  1209 +
  1210 + std::istrstream is(data, n);
  1211 +
  1212 + std::vector<float> samples = sherpa_onnx::ReadWave(is, &sample_rate, &is_ok);
  1213 + if (!is_ok) {
  1214 + return nullptr;
  1215 + }
  1216 +
  1217 + float *c_samples = new float[samples.size()];
  1218 + std::copy(samples.begin(), samples.end(), c_samples);
  1219 +
  1220 + SherpaOnnxWave *wave = new SherpaOnnxWave;
  1221 + wave->samples = c_samples;
  1222 + wave->sample_rate = sample_rate;
  1223 + wave->num_samples = samples.size();
  1224 + return wave;
  1225 +}
  1226 +
1204 void SherpaOnnxFreeWave(const SherpaOnnxWave *wave) { 1227 void SherpaOnnxFreeWave(const SherpaOnnxWave *wave) {
1205 if (wave) { 1228 if (wave) {
1206 delete[] wave->samples; 1229 delete[] wave->samples;
@@ -1001,6 +1001,14 @@ SHERPA_ONNX_API typedef struct SherpaOnnxWave { @@ -1001,6 +1001,14 @@ SHERPA_ONNX_API typedef struct SherpaOnnxWave {
1001 // SherpaOnnxFreeWave() to free the returned pointer to avoid memory leak. 1001 // SherpaOnnxFreeWave() to free the returned pointer to avoid memory leak.
1002 SHERPA_ONNX_API const SherpaOnnxWave *SherpaOnnxReadWave(const char *filename); 1002 SHERPA_ONNX_API const SherpaOnnxWave *SherpaOnnxReadWave(const char *filename);
1003 1003
  1004 +// Similar to SherpaOnnxReadWave(), it has read the content of `filename`
  1005 +// into the array `data`.
  1006 +//
  1007 +// If the returned pointer is not NULL, the user has to invoke
  1008 +// SherpaOnnxFreeWave() to free the returned pointer to avoid memory leak.
  1009 +SHERPA_ONNX_API const SherpaOnnxWave *SherpaOnnxReadWaveFromBinaryData(
  1010 + const char *data, int32_t n);
  1011 +
1004 SHERPA_ONNX_API void SherpaOnnxFreeWave(const SherpaOnnxWave *wave); 1012 SHERPA_ONNX_API void SherpaOnnxFreeWave(const SherpaOnnxWave *wave);
1005 1013
1006 // ============================================================ 1014 // ============================================================