Publish sherpa_onnx.har for HarmonyOS (#1572)
This commit is contained in:
181
.github/workflows/har.yaml
vendored
Normal file
181
.github/workflows/har.yaml
vendored
Normal file
@@ -0,0 +1,181 @@
|
||||
name: har
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
# - ohos-har
|
||||
tags:
|
||||
- 'v[0-9]+.[0-9]+.[0-9]+*'
|
||||
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
group: har-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
har:
|
||||
name: Har
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-latest]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: ccache
|
||||
uses: hendrikmuhs/ccache-action@v1.2
|
||||
with:
|
||||
key: har-linux
|
||||
|
||||
- name: cache-toolchain
|
||||
id: cache-toolchain-ohos
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: command-line-tools
|
||||
key: commandline-tools-linux-x64-5.0.5.200.zip
|
||||
|
||||
- name: Download toolchain
|
||||
if: steps.cache-toolchain-ohos.outputs.cache-hit != 'true'
|
||||
shell: bash
|
||||
run: |
|
||||
curl -SL -O https://huggingface.co/csukuangfj/harmonyos-commandline-tools/resolve/main/commandline-tools-linux-x64-5.0.5.200.zip
|
||||
unzip commandline-tools-linux-x64-5.0.5.200.zip
|
||||
rm commandline-tools-linux-x64-5.0.5.200.zip
|
||||
|
||||
- name: Set environment variable
|
||||
shell: bash
|
||||
run: |
|
||||
echo "$GITHUB_WORKSPACE/command-line-tools/sdk/default/openharmony/native/build-tools/cmake/bin" >> "$GITHUB_PATH"
|
||||
which cmake
|
||||
|
||||
cmake --version
|
||||
|
||||
ls -lh $GITHUB_WORKSPACE/command-line-tools/sdk/default/openharmony/native/build/cmake/ohos.toolchain.cmake
|
||||
|
||||
echo "===="
|
||||
cat $GITHUB_WORKSPACE/command-line-tools/sdk/default/openharmony/native/build/cmake/ohos.toolchain.cmake
|
||||
echo "===="
|
||||
|
||||
# echo "$GITHUB_WORKSPACE/command-line-tools/sdk/default/openharmony/native/llvm/bin" >> "$GITHUB_PATH"
|
||||
|
||||
ls -lh $GITHUB_WORKSPACE/command-line-tools/sdk/default/openharmony/native/llvm/bin/
|
||||
echo "--"
|
||||
ls -lh $GITHUB_WORKSPACE/command-line-tools/sdk/default/openharmony/native/llvm/bin/*unknown*
|
||||
|
||||
cat $GITHUB_PATH
|
||||
|
||||
# /home/runner/work/onnxruntime-libs/onnxruntime-libs/command-line-tools/sdk/default/openharmony/native/llvm/bin/aarch64-unknown-linux-ohos-clang -v || true
|
||||
export PATH=$PWD/command-line-tools/sdk/default/openharmony/native/llvm/bin:$PATH
|
||||
echo "path: $PATH"
|
||||
|
||||
which aarch64-unknown-linux-ohos-clang++ || true
|
||||
which aarch64-unknown-linux-ohos-clang || true
|
||||
|
||||
aarch64-unknown-linux-ohos-clang++ --version || true
|
||||
aarch64-unknown-linux-ohos-clang --version || true
|
||||
|
||||
which armv7-unknown-linux-ohos-clang++
|
||||
which armv7-unknown-linux-ohos-clang
|
||||
|
||||
armv7-unknown-linux-ohos-clang++ --version
|
||||
armv7-unknown-linux-ohos-clang --version
|
||||
|
||||
which x86_64-unknown-linux-ohos-clang++
|
||||
which x86_64-unknown-linux-ohos-clang
|
||||
|
||||
x86_64-unknown-linux-ohos-clang++ --version
|
||||
x86_64-unknown-linux-ohos-clang --version
|
||||
|
||||
- name: Build libraries
|
||||
shell: bash
|
||||
run: |
|
||||
export CMAKE_CXX_COMPILER_LAUNCHER=ccache
|
||||
export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH"
|
||||
cmake --version
|
||||
|
||||
export OHOS_SDK_NATIVE_DIR="$GITHUB_WORKSPACE/command-line-tools/sdk/default/openharmony/native"
|
||||
|
||||
./build-ohos-arm64-v8a.sh
|
||||
./build-ohos-x86-64.sh
|
||||
|
||||
- name: Build Har
|
||||
shell: bash
|
||||
run: |
|
||||
export PATH="$GITHUB_WORKSPACE/command-line-tools/bin:$PATH"
|
||||
|
||||
which hvigorw
|
||||
|
||||
pushd harmony-os/SherpaOnnxHar
|
||||
|
||||
hvigorw --mode module -p product=default -p module=sherpa_onnx@default assembleHar --analyze=normal --parallel --incremental --no-daemon
|
||||
ls -lh ./sherpa_onnx/build/default/outputs/default/sherpa_onnx.har
|
||||
cp -v ./sherpa_onnx/build/default/outputs/default/sherpa_onnx.har ../../
|
||||
|
||||
popd
|
||||
|
||||
ls -lh *.har
|
||||
|
||||
- name: Collect result
|
||||
shell: bash
|
||||
run: |
|
||||
SHERPA_ONNX_VERSION=v$(grep "SHERPA_ONNX_VERSION" ./CMakeLists.txt | cut -d " " -f 2 | cut -d '"' -f 2)
|
||||
echo "SHERPA_ONNX_VERSION=$SHERPA_ONNX_VERSION" >> "$GITHUB_ENV"
|
||||
|
||||
mv sherpa_onnx.har sherpa_onnx-$SHERPA_ONNX_VERSION.har
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: sherpa-onnx-har
|
||||
path: ./sherpa_onnx*.har
|
||||
|
||||
- name: Release jar
|
||||
if: (github.repository_owner == 'csukuangfj' || github.repository_owner == 'k2-fsa') && github.event_name == 'push' && contains(github.ref, 'refs/tags/')
|
||||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
file_glob: true
|
||||
overwrite: true
|
||||
file: ./*.har
|
||||
# repo_name: k2-fsa/sherpa-onnx
|
||||
# repo_token: ${{ secrets.UPLOAD_GH_SHERPA_ONNX_TOKEN }}
|
||||
# tag: v1.10.32
|
||||
|
||||
- name: Publish to huggingface
|
||||
if: (github.repository_owner == 'csukuangfj' || github.repository_owner == 'k2-fsa') && (github.event_name == 'push' || github.event_name == 'workflow_dispatch')
|
||||
env:
|
||||
HF_TOKEN: ${{ secrets.HF_TOKEN }}
|
||||
uses: nick-fields/retry@v3
|
||||
with:
|
||||
max_attempts: 20
|
||||
timeout_seconds: 200
|
||||
shell: bash
|
||||
command: |
|
||||
git config --global user.email "csukuangfj@gmail.com"
|
||||
git config --global user.name "Fangjun Kuang"
|
||||
|
||||
rm -rf huggingface
|
||||
export GIT_LFS_SKIP_SMUDGE=1
|
||||
export GIT_CLONE_PROTECTION_ACTIVE=false
|
||||
|
||||
SHERPA_ONNX_VERSION=$(grep "SHERPA_ONNX_VERSION" ./CMakeLists.txt | cut -d " " -f 2 | cut -d '"' -f 2)
|
||||
echo "SHERPA_ONNX_VERSION $SHERPA_ONNX_VERSION"
|
||||
|
||||
git clone https://csukuangfj:$HF_TOKEN@huggingface.co/csukuangfj/sherpa-onnx-harmony-os huggingface
|
||||
cd huggingface
|
||||
git fetch
|
||||
git pull
|
||||
git merge -m "merge remote" --ff origin main
|
||||
|
||||
d=har
|
||||
mkdir -p $d
|
||||
cp -v ../*.har $d/
|
||||
git status
|
||||
git lfs track "*.har"
|
||||
git add .
|
||||
git commit -m "add more hars"
|
||||
git push https://csukuangfj:$HF_TOKEN@huggingface.co/csukuangfj/sherpa-onnx-harmony-os main
|
||||
16
README.md
16
README.md
@@ -18,14 +18,13 @@
|
||||
|
||||
### Supported platforms
|
||||
|
||||
|Architecture| Android | iOS | Windows | macOS | linux |
|
||||
|------------|---------|---------|------------|-------|-------|
|
||||
| x64 | ✔️ | | ✔️ | ✔️ | ✔️ |
|
||||
| x86 | ✔️ | | ✔️ | | |
|
||||
| arm64 | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ |
|
||||
| arm32 | ✔️ | | | | ✔️ |
|
||||
| riscv64 | | | | | ✔️ |
|
||||
|
||||
|Architecture| Android | iOS | Windows | macOS | linux | HarmonyOS |
|
||||
|------------|---------|---------|------------|-------|-------|-----------|
|
||||
| x64 | ✔️ | | ✔️ | ✔️ | ✔️ | ✔️ |
|
||||
| x86 | ✔️ | | ✔️ | | | |
|
||||
| arm64 | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ |
|
||||
| arm32 | ✔️ | | | | ✔️ | ✔️ |
|
||||
| riscv64 | | | | | ✔️ | |
|
||||
|
||||
### Supported programming languages
|
||||
|
||||
@@ -65,6 +64,7 @@ on the following platforms and operating systems:
|
||||
- Linux, macOS, Windows, openKylin
|
||||
- Android, WearOS
|
||||
- iOS
|
||||
- HarmonyOS
|
||||
- NodeJS
|
||||
- WebAssembly
|
||||
- [Raspberry Pi][Raspberry Pi]
|
||||
|
||||
@@ -134,3 +134,9 @@ cp -fv $onnxruntime_dir/lib/libonnxruntime.so install/lib
|
||||
|
||||
rm -rf install/share
|
||||
rm -rf install/lib/pkgconfig
|
||||
|
||||
d=../harmony-os/SherpaOnnxHar/sherpa_onnx/src/main/cpp/libs/arm64-v8a
|
||||
if [ -d $d ]; then
|
||||
cp -v install/lib/libsherpa-onnx-c-api.so $d/
|
||||
cp -v install/lib/libonnxruntime.so $d/
|
||||
fi
|
||||
|
||||
@@ -134,3 +134,9 @@ cp -fv $onnxruntime_dir/lib/libonnxruntime.so install/lib
|
||||
|
||||
rm -rf install/share
|
||||
rm -rf install/lib/pkgconfig
|
||||
|
||||
d=../harmony-os/SherpaOnnxHar/sherpa_onnx/src/main/cpp/libs/x86_64
|
||||
if [ -d $d ]; then
|
||||
cp -v install/lib/libsherpa-onnx-c-api.so $d/
|
||||
cp -v install/lib/libonnxruntime.so $d/
|
||||
fi
|
||||
|
||||
1
harmony-os/.gitignore
vendored
Normal file
1
harmony-os/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
!build-profile.json5
|
||||
12
harmony-os/SherpaOnnxHar/.gitignore
vendored
Normal file
12
harmony-os/SherpaOnnxHar/.gitignore
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
/node_modules
|
||||
/oh_modules
|
||||
/local.properties
|
||||
/.idea
|
||||
**/build
|
||||
/.hvigor
|
||||
.cxx
|
||||
/.clangd
|
||||
/.clang-format
|
||||
/.clang-tidy
|
||||
**/.test
|
||||
/.appanalyzer
|
||||
10
harmony-os/SherpaOnnxHar/AppScope/app.json5
Normal file
10
harmony-os/SherpaOnnxHar/AppScope/app.json5
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"app": {
|
||||
"bundleName": "com.k2fsa.sherpa.onnx",
|
||||
"vendor": "example",
|
||||
"versionCode": 1000000,
|
||||
"versionName": "1.0.0",
|
||||
"icon": "$media:app_icon",
|
||||
"label": "$string:app_name"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"string": [
|
||||
{
|
||||
"name": "app_name",
|
||||
"value": "SherpaOnnxHar"
|
||||
}
|
||||
]
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 2.7 KiB |
18
harmony-os/SherpaOnnxHar/README.md
Normal file
18
harmony-os/SherpaOnnxHar/README.md
Normal file
@@ -0,0 +1,18 @@
|
||||
# Introduction
|
||||
|
||||
How to build `sherpa_onnx.har` from the command line:
|
||||
|
||||
```bash
|
||||
git clone https://github.com/k2-fsa/sherpa-onnx
|
||||
cd sherpa-onnx
|
||||
./build-ohos-arm64-v8a.sh
|
||||
./build-ohos-x86-64.sh
|
||||
|
||||
cd harmony-os/SherpaOnnxHar
|
||||
|
||||
hvigorw clean --no-daemon
|
||||
|
||||
hvigorw --mode module -p product=default -p module=sherpa_onnx@default assembleHar --analyze=normal --parallel --incremental --no-daemon
|
||||
|
||||
ls -lh ./sherpa_onnx/build/default/outputs/default/sherpa_onnx.har
|
||||
```
|
||||
44
harmony-os/SherpaOnnxHar/build-profile.json5
Normal file
44
harmony-os/SherpaOnnxHar/build-profile.json5
Normal file
@@ -0,0 +1,44 @@
|
||||
{
|
||||
"app": {
|
||||
"signingConfigs": [],
|
||||
"products": [
|
||||
{
|
||||
"name": "default",
|
||||
"signingConfig": "default",
|
||||
"compatibleSdkVersion": "4.0.0(10)",
|
||||
"runtimeOS": "HarmonyOS",
|
||||
"buildOption": {
|
||||
"strictMode": {
|
||||
"caseSensitiveCheck": true,
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"buildModeSet": [
|
||||
{
|
||||
"name": "debug",
|
||||
},
|
||||
{
|
||||
"name": "release"
|
||||
}
|
||||
]
|
||||
},
|
||||
"modules": [
|
||||
{
|
||||
"name": "entry",
|
||||
"srcPath": "./entry",
|
||||
"targets": [
|
||||
{
|
||||
"name": "default",
|
||||
"applyToProducts": [
|
||||
"default"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "sherpa_onnx",
|
||||
"srcPath": "./sherpa_onnx",
|
||||
}
|
||||
]
|
||||
}
|
||||
20
harmony-os/SherpaOnnxHar/code-linter.json5
Normal file
20
harmony-os/SherpaOnnxHar/code-linter.json5
Normal file
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"files": [
|
||||
"**/*.ets"
|
||||
],
|
||||
"ignore": [
|
||||
"**/src/ohosTest/**/*",
|
||||
"**/src/test/**/*",
|
||||
"**/src/mock/**/*",
|
||||
"**/node_modules/**/*",
|
||||
"**/oh_modules/**/*",
|
||||
"**/build/**/*",
|
||||
"**/.preview/**/*"
|
||||
],
|
||||
"ruleSet": [
|
||||
"plugin:@performance/recommended",
|
||||
"plugin:@typescript-eslint/recommended"
|
||||
],
|
||||
"rules": {
|
||||
}
|
||||
}
|
||||
6
harmony-os/SherpaOnnxHar/entry/.gitignore
vendored
Normal file
6
harmony-os/SherpaOnnxHar/entry/.gitignore
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
/node_modules
|
||||
/oh_modules
|
||||
/.preview
|
||||
/build
|
||||
/.cxx
|
||||
/.test
|
||||
28
harmony-os/SherpaOnnxHar/entry/build-profile.json5
Normal file
28
harmony-os/SherpaOnnxHar/entry/build-profile.json5
Normal file
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"apiType": "stageMode",
|
||||
"buildOption": {
|
||||
},
|
||||
"buildOptionSet": [
|
||||
{
|
||||
"name": "release",
|
||||
"arkOptions": {
|
||||
"obfuscation": {
|
||||
"ruleOptions": {
|
||||
"enable": false,
|
||||
"files": [
|
||||
"./obfuscation-rules.txt"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
],
|
||||
"targets": [
|
||||
{
|
||||
"name": "default"
|
||||
},
|
||||
{
|
||||
"name": "ohosTest",
|
||||
}
|
||||
]
|
||||
}
|
||||
6
harmony-os/SherpaOnnxHar/entry/hvigorfile.ts
Normal file
6
harmony-os/SherpaOnnxHar/entry/hvigorfile.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
import { hapTasks } from '@ohos/hvigor-ohos-plugin';
|
||||
|
||||
export default {
|
||||
system: hapTasks, /* Built-in plugin of Hvigor. It cannot be modified. */
|
||||
plugins:[] /* Custom plugin to extend the functionality of Hvigor. */
|
||||
}
|
||||
23
harmony-os/SherpaOnnxHar/entry/obfuscation-rules.txt
Normal file
23
harmony-os/SherpaOnnxHar/entry/obfuscation-rules.txt
Normal file
@@ -0,0 +1,23 @@
|
||||
# Define project specific obfuscation rules here.
|
||||
# You can include the obfuscation configuration files in the current module's build-profile.json5.
|
||||
#
|
||||
# For more details, see
|
||||
# https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/source-obfuscation-V5
|
||||
|
||||
# Obfuscation options:
|
||||
# -disable-obfuscation: disable all obfuscations
|
||||
# -enable-property-obfuscation: obfuscate the property names
|
||||
# -enable-toplevel-obfuscation: obfuscate the names in the global scope
|
||||
# -compact: remove unnecessary blank spaces and all line feeds
|
||||
# -remove-log: remove all console.* statements
|
||||
# -print-namecache: print the name cache that contains the mapping from the old names to new names
|
||||
# -apply-namecache: reuse the given cache file
|
||||
|
||||
# Keep options:
|
||||
# -keep-property-name: specifies property names that you want to keep
|
||||
# -keep-global-name: specifies names that you want to keep in the global scope
|
||||
|
||||
-enable-property-obfuscation
|
||||
-enable-toplevel-obfuscation
|
||||
-enable-filename-obfuscation
|
||||
-enable-export-obfuscation
|
||||
10
harmony-os/SherpaOnnxHar/entry/oh-package.json5
Normal file
10
harmony-os/SherpaOnnxHar/entry/oh-package.json5
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"name": "entry",
|
||||
"version": "1.0.0",
|
||||
"description": "Please describe the basic information.",
|
||||
"main": "",
|
||||
"author": "",
|
||||
"license": "",
|
||||
"dependencies": {}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
import AbilityConstant from '@ohos.app.ability.AbilityConstant';
|
||||
import hilog from '@ohos.hilog';
|
||||
import UIAbility from '@ohos.app.ability.UIAbility';
|
||||
import Want from '@ohos.app.ability.Want';
|
||||
import window from '@ohos.window';
|
||||
|
||||
export default class EntryAbility extends UIAbility {
|
||||
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
|
||||
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate');
|
||||
}
|
||||
|
||||
onDestroy(): void {
|
||||
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onDestroy');
|
||||
}
|
||||
|
||||
onWindowStageCreate(windowStage: window.WindowStage): void {
|
||||
// Main window is created, set main page for this ability
|
||||
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate');
|
||||
|
||||
windowStage.loadContent('pages/Index', (err) => {
|
||||
if (err.code) {
|
||||
hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? '');
|
||||
return;
|
||||
}
|
||||
hilog.info(0x0000, 'testTag', 'Succeeded in loading the content.');
|
||||
});
|
||||
}
|
||||
|
||||
onWindowStageDestroy(): void {
|
||||
// Main window is destroyed, release UI related resources
|
||||
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageDestroy');
|
||||
}
|
||||
|
||||
onForeground(): void {
|
||||
// Ability has brought to foreground
|
||||
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onForeground');
|
||||
}
|
||||
|
||||
onBackground(): void {
|
||||
// Ability has back to background
|
||||
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onBackground');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
import hilog from '@ohos.hilog';
|
||||
import BackupExtensionAbility, { BundleVersion } from '@ohos.application.BackupExtensionAbility';
|
||||
|
||||
export default class EntryBackupAbility extends BackupExtensionAbility {
|
||||
async onBackup() {
|
||||
hilog.info(0x0000, 'testTag', 'onBackup ok');
|
||||
}
|
||||
|
||||
async onRestore(bundleVersion: BundleVersion) {
|
||||
hilog.info(0x0000, 'testTag', 'onRestore ok %{public}s', JSON.stringify(bundleVersion));
|
||||
}
|
||||
}
|
||||
17
harmony-os/SherpaOnnxHar/entry/src/main/ets/pages/Index.ets
Normal file
17
harmony-os/SherpaOnnxHar/entry/src/main/ets/pages/Index.ets
Normal file
@@ -0,0 +1,17 @@
|
||||
@Entry
|
||||
@Component
|
||||
struct Index {
|
||||
@State message: string = 'Hello World';
|
||||
|
||||
build() {
|
||||
Row() {
|
||||
Column() {
|
||||
Text(this.message)
|
||||
.fontSize(50)
|
||||
.fontWeight(FontWeight.Bold)
|
||||
}
|
||||
.width('100%')
|
||||
}
|
||||
.height('100%')
|
||||
}
|
||||
}
|
||||
52
harmony-os/SherpaOnnxHar/entry/src/main/module.json5
Normal file
52
harmony-os/SherpaOnnxHar/entry/src/main/module.json5
Normal file
@@ -0,0 +1,52 @@
|
||||
{
|
||||
"module": {
|
||||
"name": "entry",
|
||||
"type": "entry",
|
||||
"description": "$string:module_desc",
|
||||
"mainElement": "EntryAbility",
|
||||
"deviceTypes": [
|
||||
"phone",
|
||||
"tablet",
|
||||
"2in1"
|
||||
],
|
||||
"deliveryWithInstall": true,
|
||||
"installationFree": false,
|
||||
"pages": "$profile:main_pages",
|
||||
"abilities": [
|
||||
{
|
||||
"name": "EntryAbility",
|
||||
"srcEntry": "./ets/entryability/EntryAbility.ets",
|
||||
"description": "$string:EntryAbility_desc",
|
||||
"icon": "$media:layered_image",
|
||||
"label": "$string:EntryAbility_label",
|
||||
"startWindowIcon": "$media:startIcon",
|
||||
"startWindowBackground": "$color:start_window_background",
|
||||
"exported": true,
|
||||
"skills": [
|
||||
{
|
||||
"entities": [
|
||||
"entity.system.home"
|
||||
],
|
||||
"actions": [
|
||||
"action.system.home"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"extensionAbilities": [
|
||||
{
|
||||
"name": "EntryBackupAbility",
|
||||
"srcEntry": "./ets/entrybackupability/EntryBackupAbility.ets",
|
||||
"type": "backup",
|
||||
"exported": false,
|
||||
"metadata": [
|
||||
{
|
||||
"name": "ohos.extension.backup",
|
||||
"resource": "$profile:backup_config"
|
||||
}
|
||||
],
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"color": [
|
||||
{
|
||||
"name": "start_window_background",
|
||||
"value": "#FFFFFF"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"string": [
|
||||
{
|
||||
"name": "module_desc",
|
||||
"value": "module description"
|
||||
},
|
||||
{
|
||||
"name": "EntryAbility_desc",
|
||||
"value": "description"
|
||||
},
|
||||
{
|
||||
"name": "EntryAbility_label",
|
||||
"value": "label"
|
||||
}
|
||||
]
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 56 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"layered-image":
|
||||
{
|
||||
"background" : "$media:background",
|
||||
"foreground" : "$media:foreground"
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 20 KiB |
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"allowToBackupRestore": true
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"src": [
|
||||
"pages/Index"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"string": [
|
||||
{
|
||||
"name": "module_desc",
|
||||
"value": "module description"
|
||||
},
|
||||
{
|
||||
"name": "EntryAbility_desc",
|
||||
"value": "description"
|
||||
},
|
||||
{
|
||||
"name": "EntryAbility_label",
|
||||
"value": "label"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"string": [
|
||||
{
|
||||
"name": "module_desc",
|
||||
"value": "模块描述"
|
||||
},
|
||||
{
|
||||
"name": "EntryAbility_desc",
|
||||
"value": "description"
|
||||
},
|
||||
{
|
||||
"name": "EntryAbility_label",
|
||||
"value": "label"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
import hilog from '@ohos.hilog';
|
||||
import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from '@ohos/hypium';
|
||||
|
||||
export default function abilityTest() {
|
||||
describe('ActsAbilityTest', () => {
|
||||
// Defines a test suite. Two parameters are supported: test suite name and test suite function.
|
||||
beforeAll(() => {
|
||||
// Presets an action, which is performed only once before all test cases of the test suite start.
|
||||
// This API supports only one parameter: preset action function.
|
||||
})
|
||||
beforeEach(() => {
|
||||
// Presets an action, which is performed before each unit test case starts.
|
||||
// The number of execution times is the same as the number of test cases defined by **it**.
|
||||
// This API supports only one parameter: preset action function.
|
||||
})
|
||||
afterEach(() => {
|
||||
// Presets a clear action, which is performed after each unit test case ends.
|
||||
// The number of execution times is the same as the number of test cases defined by **it**.
|
||||
// This API supports only one parameter: clear action function.
|
||||
})
|
||||
afterAll(() => {
|
||||
// Presets a clear action, which is performed after all test cases of the test suite end.
|
||||
// This API supports only one parameter: clear action function.
|
||||
})
|
||||
it('assertContain', 0, () => {
|
||||
// Defines a test case. This API supports three parameters: test case name, filter parameter, and test case function.
|
||||
hilog.info(0x0000, 'testTag', '%{public}s', 'it begin');
|
||||
let a = 'abc';
|
||||
let b = 'b';
|
||||
// Defines a variety of assertion methods, which are used to declare expected boolean conditions.
|
||||
expect(a).assertContain(b);
|
||||
expect(a).assertEqual(a);
|
||||
})
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
import abilityTest from './Ability.test';
|
||||
|
||||
export default function testsuite() {
|
||||
abilityTest();
|
||||
}
|
||||
13
harmony-os/SherpaOnnxHar/entry/src/ohosTest/module.json5
Normal file
13
harmony-os/SherpaOnnxHar/entry/src/ohosTest/module.json5
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"module": {
|
||||
"name": "entry_test",
|
||||
"type": "feature",
|
||||
"deviceTypes": [
|
||||
"phone",
|
||||
"tablet",
|
||||
"2in1"
|
||||
],
|
||||
"deliveryWithInstall": true,
|
||||
"installationFree": false
|
||||
}
|
||||
}
|
||||
5
harmony-os/SherpaOnnxHar/entry/src/test/List.test.ets
Normal file
5
harmony-os/SherpaOnnxHar/entry/src/test/List.test.ets
Normal file
@@ -0,0 +1,5 @@
|
||||
import localUnitTest from './LocalUnit.test';
|
||||
|
||||
export default function testsuite() {
|
||||
localUnitTest();
|
||||
}
|
||||
33
harmony-os/SherpaOnnxHar/entry/src/test/LocalUnit.test.ets
Normal file
33
harmony-os/SherpaOnnxHar/entry/src/test/LocalUnit.test.ets
Normal file
@@ -0,0 +1,33 @@
|
||||
import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from '@ohos/hypium';
|
||||
|
||||
export default function localUnitTest() {
|
||||
describe('localUnitTest', () => {
|
||||
// Defines a test suite. Two parameters are supported: test suite name and test suite function.
|
||||
beforeAll(() => {
|
||||
// Presets an action, which is performed only once before all test cases of the test suite start.
|
||||
// This API supports only one parameter: preset action function.
|
||||
});
|
||||
beforeEach(() => {
|
||||
// Presets an action, which is performed before each unit test case starts.
|
||||
// The number of execution times is the same as the number of test cases defined by **it**.
|
||||
// This API supports only one parameter: preset action function.
|
||||
});
|
||||
afterEach(() => {
|
||||
// Presets a clear action, which is performed after each unit test case ends.
|
||||
// The number of execution times is the same as the number of test cases defined by **it**.
|
||||
// This API supports only one parameter: clear action function.
|
||||
});
|
||||
afterAll(() => {
|
||||
// Presets a clear action, which is performed after all test cases of the test suite end.
|
||||
// This API supports only one parameter: clear action function.
|
||||
});
|
||||
it('assertContain', 0, () => {
|
||||
// Defines a test case. This API supports three parameters: test case name, filter parameter, and test case function.
|
||||
let a = 'abc';
|
||||
let b = 'b';
|
||||
// Defines a variety of assertion methods, which are used to declare expected boolean conditions.
|
||||
expect(a).assertContain(b);
|
||||
expect(a).assertEqual(a);
|
||||
});
|
||||
});
|
||||
}
|
||||
22
harmony-os/SherpaOnnxHar/hvigor/hvigor-config.json5
Normal file
22
harmony-os/SherpaOnnxHar/hvigor/hvigor-config.json5
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"modelVersion": "5.0.0",
|
||||
"dependencies": {
|
||||
},
|
||||
"execution": {
|
||||
// "analyze": "normal", /* Define the build analyze mode. Value: [ "normal" | "advanced" | false ]. Default: "normal" */
|
||||
// "daemon": true, /* Enable daemon compilation. Value: [ true | false ]. Default: true */
|
||||
// "incremental": true, /* Enable incremental compilation. Value: [ true | false ]. Default: true */
|
||||
// "parallel": true, /* Enable parallel compilation. Value: [ true | false ]. Default: true */
|
||||
// "typeCheck": false, /* Enable typeCheck. Value: [ true | false ]. Default: false */
|
||||
},
|
||||
"logging": {
|
||||
// "level": "info" /* Define the log level. Value: [ "debug" | "info" | "warn" | "error" ]. Default: "info" */
|
||||
},
|
||||
"debugging": {
|
||||
// "stacktrace": false /* Disable stacktrace compilation. Value: [ true | false ]. Default: false */
|
||||
},
|
||||
"nodeOptions": {
|
||||
// "maxOldSpaceSize": 8192 /* Enable nodeOptions maxOldSpaceSize compilation. Unit M. Used for the daemon process. Default: 8192*/
|
||||
// "exposeGC": true /* Enable to trigger garbage collection explicitly. Default: true*/
|
||||
}
|
||||
}
|
||||
6
harmony-os/SherpaOnnxHar/hvigorfile.ts
Normal file
6
harmony-os/SherpaOnnxHar/hvigorfile.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
import { appTasks } from '@ohos/hvigor-ohos-plugin';
|
||||
|
||||
export default {
|
||||
system: appTasks, /* Built-in plugin of Hvigor. It cannot be modified. */
|
||||
plugins:[] /* Custom plugin to extend the functionality of Hvigor. */
|
||||
}
|
||||
13
harmony-os/SherpaOnnxHar/notes.md
Normal file
13
harmony-os/SherpaOnnxHar/notes.md
Normal file
@@ -0,0 +1,13 @@
|
||||
# Notes
|
||||
|
||||
## How to publish a package
|
||||
|
||||
Please see
|
||||
- <https://ohpm.openharmony.cn/#/cn/help/publishrequirefile>
|
||||
- <https://ohpm.openharmony.cn/#/cn/help/createandpublish>
|
||||
- <https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/ide-har-publish-V5>
|
||||
|
||||
## How to sign the HAP file from commandline
|
||||
|
||||
Please see
|
||||
<https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/ide-command-line-building-app-V5>
|
||||
19
harmony-os/SherpaOnnxHar/oh-package-lock.json5
Normal file
19
harmony-os/SherpaOnnxHar/oh-package-lock.json5
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"meta": {
|
||||
"stableOrder": true
|
||||
},
|
||||
"lockfileVersion": 3,
|
||||
"ATTENTION": "THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.",
|
||||
"specifiers": {
|
||||
"@ohos/hypium@1.0.19": "@ohos/hypium@1.0.19"
|
||||
},
|
||||
"packages": {
|
||||
"@ohos/hypium@1.0.19": {
|
||||
"name": "@ohos/hypium",
|
||||
"version": "1.0.19",
|
||||
"integrity": "sha512-cEjDgLFCm3cWZDeRXk7agBUkPqjWxUo6AQeiu0gEkb3J8ESqlduQLSIXeo3cCsm8U/asL7iKjF85ZyOuufAGSQ==",
|
||||
"resolved": "https://ohpm.openharmony.cn/ohpm/@ohos/hypium/-/hypium-1.0.19.har",
|
||||
"registryType": "ohpm"
|
||||
}
|
||||
}
|
||||
}
|
||||
9
harmony-os/SherpaOnnxHar/oh-package.json5
Normal file
9
harmony-os/SherpaOnnxHar/oh-package.json5
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"modelVersion": "5.0.0",
|
||||
"description": "Please describe the basic information.",
|
||||
"dependencies": {
|
||||
},
|
||||
"devDependencies": {
|
||||
"@ohos/hypium": "1.0.19"
|
||||
}
|
||||
}
|
||||
6
harmony-os/SherpaOnnxHar/sherpa_onnx/.gitignore
vendored
Normal file
6
harmony-os/SherpaOnnxHar/sherpa_onnx/.gitignore
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
/node_modules
|
||||
/oh_modules
|
||||
/.preview
|
||||
/build
|
||||
/.cxx
|
||||
/.test
|
||||
17
harmony-os/SherpaOnnxHar/sherpa_onnx/BuildProfile.ets
Normal file
17
harmony-os/SherpaOnnxHar/sherpa_onnx/BuildProfile.ets
Normal file
@@ -0,0 +1,17 @@
|
||||
/**
|
||||
* Use these variables when you tailor your ArkTS code. They must be of the const type.
|
||||
*/
|
||||
export const HAR_VERSION = '1.0.0';
|
||||
export const BUILD_MODE_NAME = 'debug';
|
||||
export const DEBUG = true;
|
||||
export const TARGET_NAME = 'default';
|
||||
|
||||
/**
|
||||
* BuildProfile Class is used only for compatibility purposes.
|
||||
*/
|
||||
export default class BuildProfile {
|
||||
static readonly HAR_VERSION = HAR_VERSION;
|
||||
static readonly BUILD_MODE_NAME = BUILD_MODE_NAME;
|
||||
static readonly DEBUG = DEBUG;
|
||||
static readonly TARGET_NAME = TARGET_NAME;
|
||||
}
|
||||
40
harmony-os/SherpaOnnxHar/sherpa_onnx/Index.ets
Normal file
40
harmony-os/SherpaOnnxHar/sherpa_onnx/Index.ets
Normal file
@@ -0,0 +1,40 @@
|
||||
export { readWave, readWaveFromBinary } from "libsherpa_onnx.so";
|
||||
|
||||
export {
|
||||
CircularBuffer,
|
||||
SileroVadConfig,
|
||||
SpeechSegment,
|
||||
Vad,
|
||||
VadConfig,
|
||||
} from './src/main/ets/components/Vad';
|
||||
|
||||
|
||||
export {
|
||||
Samples,
|
||||
OfflineStream,
|
||||
FeatureConfig,
|
||||
OfflineTransducerModelConfig,
|
||||
OfflineParaformerModelConfig,
|
||||
OfflineNemoEncDecCtcModelConfig,
|
||||
OfflineWhisperModelConfig,
|
||||
OfflineTdnnModelConfig,
|
||||
OfflineSenseVoiceModelConfig,
|
||||
OfflineMoonshineModelConfig,
|
||||
OfflineModelConfig,
|
||||
OfflineLMConfig,
|
||||
OfflineRecognizerConfig,
|
||||
OfflineRecognizerResult,
|
||||
OfflineRecognizer,
|
||||
} from './src/main/ets/components/NonStreamingAsr';
|
||||
|
||||
export {
|
||||
OnlineStream,
|
||||
OnlineTransducerModelConfig,
|
||||
OnlineParaformerModelConfig,
|
||||
OnlineZipformer2CtcModelConfig,
|
||||
OnlineModelConfig,
|
||||
OnlineCtcFstDecoderConfig,
|
||||
OnlineRecognizerConfig,
|
||||
OnlineRecognizerResult,
|
||||
OnlineRecognizer,
|
||||
} from './src/main/ets/components/StreamingAsr';
|
||||
12
harmony-os/SherpaOnnxHar/sherpa_onnx/README.md
Normal file
12
harmony-os/SherpaOnnxHar/sherpa_onnx/README.md
Normal file
@@ -0,0 +1,12 @@
|
||||
# Introduction
|
||||
|
||||
[sherpa-onnx](https://github.com/k2-fsa/sherpa-onnx) is one of the deployment
|
||||
frameworks of [Next-gen Kaldi](https://github.com/k2-fsa).
|
||||
|
||||
It supports speech-to-text, text-to-speech, speaker diarization, and VAD using
|
||||
onnxruntime without Internet connection.
|
||||
|
||||
It also supports embedded systems, Android, iOS, HarmonyOS,
|
||||
Raspberry Pi, RISC-V, x86_64 servers, websocket server/client,
|
||||
C/C++, Python, Kotlin, C#, Go, NodeJS, Java, Swift, Dart, JavaScript,
|
||||
Flutter, Object Pascal, Lazarus, Rust, etc.
|
||||
46
harmony-os/SherpaOnnxHar/sherpa_onnx/build-profile.json5
Normal file
46
harmony-os/SherpaOnnxHar/sherpa_onnx/build-profile.json5
Normal file
@@ -0,0 +1,46 @@
|
||||
{
|
||||
"apiType": "stageMode",
|
||||
"buildOption": {
|
||||
"externalNativeOptions": {
|
||||
"path": "./src/main/cpp/CMakeLists.txt",
|
||||
"arguments": "",
|
||||
"cppFlags": "",
|
||||
"abiFilters": [
|
||||
"arm64-v8a",
|
||||
"x86_64",
|
||||
],
|
||||
},
|
||||
},
|
||||
"buildOptionSet": [
|
||||
{
|
||||
"name": "release",
|
||||
"arkOptions": {
|
||||
"obfuscation": {
|
||||
"ruleOptions": {
|
||||
"enable": false,
|
||||
"files": [
|
||||
"./obfuscation-rules.txt"
|
||||
]
|
||||
},
|
||||
"consumerFiles": [
|
||||
"./consumer-rules.txt"
|
||||
]
|
||||
}
|
||||
},
|
||||
"nativeLib": {
|
||||
"debugSymbol": {
|
||||
"strip": true,
|
||||
"exclude": []
|
||||
}
|
||||
}
|
||||
},
|
||||
],
|
||||
"targets": [
|
||||
{
|
||||
"name": "default"
|
||||
},
|
||||
{
|
||||
"name": "ohosTest"
|
||||
}
|
||||
]
|
||||
}
|
||||
6
harmony-os/SherpaOnnxHar/sherpa_onnx/hvigorfile.ts
Normal file
6
harmony-os/SherpaOnnxHar/sherpa_onnx/hvigorfile.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
import { harTasks } from '@ohos/hvigor-ohos-plugin';
|
||||
|
||||
export default {
|
||||
system: harTasks, /* Built-in plugin of Hvigor. It cannot be modified. */
|
||||
plugins:[] /* Custom plugin to extend the functionality of Hvigor. */
|
||||
}
|
||||
23
harmony-os/SherpaOnnxHar/sherpa_onnx/obfuscation-rules.txt
Normal file
23
harmony-os/SherpaOnnxHar/sherpa_onnx/obfuscation-rules.txt
Normal file
@@ -0,0 +1,23 @@
|
||||
# Define project specific obfuscation rules here.
|
||||
# You can include the obfuscation configuration files in the current module's build-profile.json5.
|
||||
#
|
||||
# For more details, see
|
||||
# https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/source-obfuscation-V5
|
||||
|
||||
# Obfuscation options:
|
||||
# -disable-obfuscation: disable all obfuscations
|
||||
# -enable-property-obfuscation: obfuscate the property names
|
||||
# -enable-toplevel-obfuscation: obfuscate the names in the global scope
|
||||
# -compact: remove unnecessary blank spaces and all line feeds
|
||||
# -remove-log: remove all console.* statements
|
||||
# -print-namecache: print the name cache that contains the mapping from the old names to new names
|
||||
# -apply-namecache: reuse the given cache file
|
||||
|
||||
# Keep options:
|
||||
# -keep-property-name: specifies property names that you want to keep
|
||||
# -keep-global-name: specifies names that you want to keep in the global scope
|
||||
|
||||
-enable-property-obfuscation
|
||||
-enable-toplevel-obfuscation
|
||||
-enable-filename-obfuscation
|
||||
-enable-export-obfuscation
|
||||
18
harmony-os/SherpaOnnxHar/sherpa_onnx/oh-package-lock.json5
Normal file
18
harmony-os/SherpaOnnxHar/sherpa_onnx/oh-package-lock.json5
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"meta": {
|
||||
"stableOrder": true
|
||||
},
|
||||
"lockfileVersion": 3,
|
||||
"ATTENTION": "THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.",
|
||||
"specifiers": {
|
||||
"libsherpa_onnx.so@src/main/cpp/types/libsherpa_onnx": "libsherpa_onnx.so@src/main/cpp/types/libsherpa_onnx"
|
||||
},
|
||||
"packages": {
|
||||
"libsherpa_onnx.so@src/main/cpp/types/libsherpa_onnx": {
|
||||
"name": "libsherpa_onnx.so",
|
||||
"version": "1.0.0",
|
||||
"resolved": "src/main/cpp/types/libsherpa_onnx",
|
||||
"registryType": "local"
|
||||
}
|
||||
}
|
||||
}
|
||||
25
harmony-os/SherpaOnnxHar/sherpa_onnx/oh-package.json5
Normal file
25
harmony-os/SherpaOnnxHar/sherpa_onnx/oh-package.json5
Normal file
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"name": "sherpa_onnx",
|
||||
"version": "1.0.0",
|
||||
"description": "Speech-to-text, text-to-speech, and speaker diarization using Next-gen Kaldi without internet connection",
|
||||
"main": "Index.ets",
|
||||
"author": "The next-gen Kaldi team",
|
||||
"license": "Apache-2.0",
|
||||
"homepage": "https://github.com/k2-fsa/sherpa-onnx",
|
||||
"repository": "https://github.com/k2-fsa/sherpa-onnx/tree/master/harmonyos-SherpaOnnxHar",
|
||||
"dependencies": {
|
||||
"libsherpa_onnx.so": "file:./src/main/cpp/types/libsherpa_onnx"
|
||||
},
|
||||
"keywords": [
|
||||
"tts",
|
||||
"asr",
|
||||
"locally",
|
||||
"diarization",
|
||||
"privacy",
|
||||
"open-source",
|
||||
"speaker",
|
||||
],
|
||||
"bugs": {
|
||||
"url": "https://github.com/k2-fsa/sherpa-onnx/issues"
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
# the minimum version of CMake.
|
||||
cmake_minimum_required(VERSION 3.13.0)
|
||||
project(myNpmLib)
|
||||
|
||||
# Disable warning about
|
||||
#
|
||||
# "The DOWNLOAD_EXTRACT_TIMESTAMP option was not given and policy CMP0135 is
|
||||
# not set.
|
||||
if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.24.0")
|
||||
cmake_policy(SET CMP0135 NEW)
|
||||
endif()
|
||||
|
||||
set(NATIVERENDER_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
|
||||
if(DEFINED PACKAGE_FIND_FILE)
|
||||
include(${PACKAGE_FIND_FILE})
|
||||
endif()
|
||||
|
||||
include_directories(${NATIVERENDER_ROOT_PATH}
|
||||
${NATIVERENDER_ROOT_PATH}/include)
|
||||
|
||||
include(FetchContent)
|
||||
FetchContent_Declare(node_addon_api
|
||||
GIT_REPOSITORY "https://github.com/nodejs/node-addon-api.git"
|
||||
GIT_TAG c679f6f4c9dc6bf9fc0d99cbe5982bd24a5e2c7b
|
||||
PATCH_COMMAND git checkout . && git apply --ignore-whitespace "${CMAKE_CURRENT_LIST_DIR}/my-patch.diff"
|
||||
)
|
||||
FetchContent_MakeAvailable(node_addon_api)
|
||||
FetchContent_GetProperties(node_addon_api)
|
||||
if(NOT node_addon_api_POPULATED)
|
||||
message(STATUS "Downloading node-addon-api from")
|
||||
FetchContent_Populate(node_addon_api)
|
||||
endif()
|
||||
|
||||
message(STATUS "node-addon-api is downloaded to ${node_addon_api_SOURCE_DIR}")
|
||||
include_directories(${node_addon_api_SOURCE_DIR})
|
||||
|
||||
add_library(sherpa_onnx SHARED
|
||||
audio-tagging.cc
|
||||
keyword-spotting.cc
|
||||
non-streaming-asr.cc
|
||||
non-streaming-speaker-diarization.cc
|
||||
non-streaming-tts.cc
|
||||
punctuation.cc
|
||||
sherpa-onnx-node-addon-api.cc
|
||||
speaker-identification.cc
|
||||
spoken-language-identification.cc
|
||||
streaming-asr.cc
|
||||
vad.cc
|
||||
wave-reader.cc
|
||||
wave-writer.cc
|
||||
)
|
||||
|
||||
add_library(sherpa_onnx_c_api SHARED IMPORTED)
|
||||
set_target_properties(sherpa_onnx_c_api
|
||||
PROPERTIES
|
||||
IMPORTED_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/libs/${OHOS_ARCH}/libsherpa-onnx-c-api.so)
|
||||
|
||||
add_library(onnxruntime SHARED IMPORTED)
|
||||
set_target_properties(onnxruntime
|
||||
PROPERTIES
|
||||
IMPORTED_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/libs/${OHOS_ARCH}/libonnxruntime.so)
|
||||
|
||||
|
||||
target_link_libraries(sherpa_onnx PUBLIC libace_napi.z.so
|
||||
libhilog_ndk.z.so # for hilog
|
||||
librawfile.z.so
|
||||
sherpa_onnx_c_api onnxruntime
|
||||
)
|
||||
@@ -0,0 +1,227 @@
|
||||
// scripts/node-addon-api/src/audio-tagging.cc
|
||||
//
|
||||
// Copyright (c) 2024 Xiaomi Corporation
|
||||
#include <sstream>
|
||||
|
||||
#include "macros.h" // NOLINT
|
||||
#include "napi.h" // NOLINT
|
||||
#include "sherpa-onnx/c-api/c-api.h"
|
||||
|
||||
static SherpaOnnxOfflineZipformerAudioTaggingModelConfig
|
||||
GetAudioTaggingZipformerModelConfig(Napi::Object obj) {
|
||||
SherpaOnnxOfflineZipformerAudioTaggingModelConfig c;
|
||||
memset(&c, 0, sizeof(c));
|
||||
|
||||
if (!obj.Has("zipformer") || !obj.Get("zipformer").IsObject()) {
|
||||
return c;
|
||||
}
|
||||
|
||||
Napi::Object o = obj.Get("zipformer").As<Napi::Object>();
|
||||
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(model, model);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
static SherpaOnnxAudioTaggingModelConfig GetAudioTaggingModelConfig(
|
||||
Napi::Object obj) {
|
||||
SherpaOnnxAudioTaggingModelConfig c;
|
||||
memset(&c, 0, sizeof(c));
|
||||
|
||||
if (!obj.Has("model") || !obj.Get("model").IsObject()) {
|
||||
return c;
|
||||
}
|
||||
|
||||
Napi::Object o = obj.Get("model").As<Napi::Object>();
|
||||
c.zipformer = GetAudioTaggingZipformerModelConfig(o);
|
||||
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(ced, ced);
|
||||
|
||||
SHERPA_ONNX_ASSIGN_ATTR_INT32(num_threads, numThreads);
|
||||
|
||||
if (o.Has("debug") &&
|
||||
(o.Get("debug").IsNumber() || o.Get("debug").IsBoolean())) {
|
||||
if (o.Get("debug").IsBoolean()) {
|
||||
c.debug = o.Get("debug").As<Napi::Boolean>().Value();
|
||||
} else {
|
||||
c.debug = o.Get("debug").As<Napi::Number>().Int32Value();
|
||||
}
|
||||
}
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(provider, provider);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
static Napi::External<SherpaOnnxAudioTagging> CreateAudioTaggingWrapper(
|
||||
const Napi::CallbackInfo &info) {
|
||||
Napi::Env env = info.Env();
|
||||
if (info.Length() != 1) {
|
||||
std::ostringstream os;
|
||||
os << "Expect only 1 argument. Given: " << info.Length();
|
||||
|
||||
Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!info[0].IsObject()) {
|
||||
Napi::TypeError::New(env, "You should pass an object as the only argument.")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
Napi::Object o = info[0].As<Napi::Object>();
|
||||
|
||||
SherpaOnnxAudioTaggingConfig c;
|
||||
memset(&c, 0, sizeof(c));
|
||||
c.model = GetAudioTaggingModelConfig(o);
|
||||
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(labels, labels);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_INT32(top_k, topK);
|
||||
|
||||
const SherpaOnnxAudioTagging *at = SherpaOnnxCreateAudioTagging(&c);
|
||||
|
||||
if (c.model.zipformer.model) {
|
||||
delete[] c.model.zipformer.model;
|
||||
}
|
||||
|
||||
if (c.model.ced) {
|
||||
delete[] c.model.ced;
|
||||
}
|
||||
|
||||
if (c.model.provider) {
|
||||
delete[] c.model.provider;
|
||||
}
|
||||
|
||||
if (c.labels) {
|
||||
delete[] c.labels;
|
||||
}
|
||||
|
||||
if (!at) {
|
||||
Napi::TypeError::New(env, "Please check your config!")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
return Napi::External<SherpaOnnxAudioTagging>::New(
|
||||
env, const_cast<SherpaOnnxAudioTagging *>(at),
|
||||
[](Napi::Env env, SherpaOnnxAudioTagging *at) {
|
||||
SherpaOnnxDestroyAudioTagging(at);
|
||||
});
|
||||
}
|
||||
|
||||
static Napi::External<SherpaOnnxOfflineStream>
|
||||
AudioTaggingCreateOfflineStreamWrapper(const Napi::CallbackInfo &info) {
|
||||
Napi::Env env = info.Env();
|
||||
if (info.Length() != 1) {
|
||||
std::ostringstream os;
|
||||
os << "Expect only 1 argument. Given: " << info.Length();
|
||||
|
||||
Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!info[0].IsExternal()) {
|
||||
Napi::TypeError::New(
|
||||
env, "You should pass an audio tagging pointer as the only argument")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
SherpaOnnxAudioTagging *at =
|
||||
info[0].As<Napi::External<SherpaOnnxAudioTagging>>().Data();
|
||||
|
||||
const SherpaOnnxOfflineStream *stream =
|
||||
SherpaOnnxAudioTaggingCreateOfflineStream(at);
|
||||
|
||||
return Napi::External<SherpaOnnxOfflineStream>::New(
|
||||
env, const_cast<SherpaOnnxOfflineStream *>(stream),
|
||||
[](Napi::Env env, SherpaOnnxOfflineStream *stream) {
|
||||
SherpaOnnxDestroyOfflineStream(stream);
|
||||
});
|
||||
}
|
||||
|
||||
static Napi::Object AudioTaggingComputeWrapper(const Napi::CallbackInfo &info) {
|
||||
Napi::Env env = info.Env();
|
||||
if (info.Length() != 3) {
|
||||
std::ostringstream os;
|
||||
os << "Expect only 3 arguments. Given: " << info.Length();
|
||||
|
||||
Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!info[0].IsExternal()) {
|
||||
Napi::TypeError::New(
|
||||
env, "You should pass an audio tagging pointer as the first argument")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!info[1].IsExternal()) {
|
||||
Napi::TypeError::New(
|
||||
env, "You should pass an offline stream pointer as the second argument")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!info[2].IsNumber()) {
|
||||
Napi::TypeError::New(env,
|
||||
"You should pass an integer as the third argument")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
SherpaOnnxAudioTagging *at =
|
||||
info[0].As<Napi::External<SherpaOnnxAudioTagging>>().Data();
|
||||
|
||||
SherpaOnnxOfflineStream *stream =
|
||||
info[1].As<Napi::External<SherpaOnnxOfflineStream>>().Data();
|
||||
|
||||
int32_t top_k = info[2].As<Napi::Number>().Int32Value();
|
||||
|
||||
const SherpaOnnxAudioEvent *const *events =
|
||||
SherpaOnnxAudioTaggingCompute(at, stream, top_k);
|
||||
|
||||
auto p = events;
|
||||
int32_t k = 0;
|
||||
while (p && *p) {
|
||||
++k;
|
||||
++p;
|
||||
}
|
||||
|
||||
Napi::Array ans = Napi::Array::New(env, k);
|
||||
for (uint32_t i = 0; i != k; ++i) {
|
||||
Napi::Object obj = Napi::Object::New(env);
|
||||
obj.Set(Napi::String::New(env, "name"),
|
||||
Napi::String::New(env, events[i]->name));
|
||||
obj.Set(Napi::String::New(env, "index"),
|
||||
Napi::Number::New(env, events[i]->index));
|
||||
obj.Set(Napi::String::New(env, "prob"),
|
||||
Napi::Number::New(env, events[i]->prob));
|
||||
ans[i] = obj;
|
||||
}
|
||||
|
||||
SherpaOnnxAudioTaggingFreeResults(events);
|
||||
|
||||
return ans;
|
||||
}
|
||||
|
||||
void InitAudioTagging(Napi::Env env, Napi::Object exports) {
|
||||
exports.Set(Napi::String::New(env, "createAudioTagging"),
|
||||
Napi::Function::New(env, CreateAudioTaggingWrapper));
|
||||
|
||||
exports.Set(Napi::String::New(env, "audioTaggingCreateOfflineStream"),
|
||||
Napi::Function::New(env, AudioTaggingCreateOfflineStreamWrapper));
|
||||
|
||||
exports.Set(Napi::String::New(env, "audioTaggingCompute"),
|
||||
Napi::Function::New(env, AudioTaggingComputeWrapper));
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
# Node
|
||||
|
||||
[./c-api.h](./c-api.h) is a symbolic link to
|
||||
https://github.com/k2-fsa/sherpa-onnx/blob/master/sherpa-onnx/c-api/c-api.h
|
||||
|
||||
If you are using Windows, then you need to manually replace this file with
|
||||
https://github.com/k2-fsa/sherpa-onnx/blob/master/sherpa-onnx/c-api/c-api.h
|
||||
since Windows does not support symbolic links.
|
||||
@@ -0,0 +1 @@
|
||||
../../../../../../../../../sherpa-onnx/c-api/c-api.h
|
||||
@@ -0,0 +1,266 @@
|
||||
// scripts/node-addon-api/src/keyword-spotting.cc
|
||||
//
|
||||
// Copyright (c) 2024 Xiaomi Corporation
|
||||
#include <sstream>
|
||||
|
||||
#include "macros.h" // NOLINT
|
||||
#include "napi.h" // NOLINT
|
||||
#include "sherpa-onnx/c-api/c-api.h"
|
||||
|
||||
// defined ./streaming-asr.cc
|
||||
SherpaOnnxFeatureConfig GetFeatureConfig(Napi::Object obj);
|
||||
|
||||
// defined ./streaming-asr.cc
|
||||
SherpaOnnxOnlineModelConfig GetOnlineModelConfig(Napi::Object obj);
|
||||
|
||||
static Napi::External<SherpaOnnxKeywordSpotter> CreateKeywordSpotterWrapper(
|
||||
const Napi::CallbackInfo &info) {
|
||||
Napi::Env env = info.Env();
|
||||
if (info.Length() != 1) {
|
||||
std::ostringstream os;
|
||||
os << "Expect only 1 argument. Given: " << info.Length();
|
||||
|
||||
Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!info[0].IsObject()) {
|
||||
Napi::TypeError::New(env, "Expect an object as the argument")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
Napi::Object o = info[0].As<Napi::Object>();
|
||||
SherpaOnnxKeywordSpotterConfig c;
|
||||
memset(&c, 0, sizeof(c));
|
||||
c.feat_config = GetFeatureConfig(o);
|
||||
c.model_config = GetOnlineModelConfig(o);
|
||||
|
||||
SHERPA_ONNX_ASSIGN_ATTR_INT32(max_active_paths, maxActivePaths);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_INT32(num_trailing_blanks, numTrailingBlanks);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_FLOAT(keywords_score, keywordsScore);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_FLOAT(keywords_threshold, keywordsThreshold);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(keywords_file, keywordsFile);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(keywords_buf, keywordsBuf);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_INT32(keywords_buf_size, keywordsBufSize);
|
||||
|
||||
SherpaOnnxKeywordSpotter *kws = SherpaOnnxCreateKeywordSpotter(&c);
|
||||
|
||||
if (c.model_config.transducer.encoder) {
|
||||
delete[] c.model_config.transducer.encoder;
|
||||
}
|
||||
|
||||
if (c.model_config.transducer.decoder) {
|
||||
delete[] c.model_config.transducer.decoder;
|
||||
}
|
||||
|
||||
if (c.model_config.transducer.joiner) {
|
||||
delete[] c.model_config.transducer.joiner;
|
||||
}
|
||||
|
||||
if (c.model_config.paraformer.encoder) {
|
||||
delete[] c.model_config.paraformer.encoder;
|
||||
}
|
||||
|
||||
if (c.model_config.paraformer.decoder) {
|
||||
delete[] c.model_config.paraformer.decoder;
|
||||
}
|
||||
|
||||
if (c.model_config.zipformer2_ctc.model) {
|
||||
delete[] c.model_config.zipformer2_ctc.model;
|
||||
}
|
||||
|
||||
if (c.model_config.tokens) {
|
||||
delete[] c.model_config.tokens;
|
||||
}
|
||||
|
||||
if (c.model_config.provider) {
|
||||
delete[] c.model_config.provider;
|
||||
}
|
||||
|
||||
if (c.model_config.model_type) {
|
||||
delete[] c.model_config.model_type;
|
||||
}
|
||||
|
||||
if (c.keywords_file) {
|
||||
delete[] c.keywords_file;
|
||||
}
|
||||
|
||||
if (c.keywords_buf) {
|
||||
delete[] c.keywords_buf;
|
||||
}
|
||||
|
||||
if (!kws) {
|
||||
Napi::TypeError::New(env, "Please check your config!")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
return Napi::External<SherpaOnnxKeywordSpotter>::New(
|
||||
env, kws, [](Napi::Env env, SherpaOnnxKeywordSpotter *kws) {
|
||||
SherpaOnnxDestroyKeywordSpotter(kws);
|
||||
});
|
||||
}
|
||||
|
||||
static Napi::External<SherpaOnnxOnlineStream> CreateKeywordStreamWrapper(
|
||||
const Napi::CallbackInfo &info) {
|
||||
Napi::Env env = info.Env();
|
||||
if (info.Length() != 1) {
|
||||
std::ostringstream os;
|
||||
os << "Expect only 1 argument. Given: " << info.Length();
|
||||
|
||||
Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!info[0].IsExternal()) {
|
||||
Napi::TypeError::New(
|
||||
env, "You should pass a keyword spotter pointer as the only argument")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
SherpaOnnxKeywordSpotter *kws =
|
||||
info[0].As<Napi::External<SherpaOnnxKeywordSpotter>>().Data();
|
||||
|
||||
SherpaOnnxOnlineStream *stream = SherpaOnnxCreateKeywordStream(kws);
|
||||
|
||||
return Napi::External<SherpaOnnxOnlineStream>::New(
|
||||
env, stream, [](Napi::Env env, SherpaOnnxOnlineStream *stream) {
|
||||
SherpaOnnxDestroyOnlineStream(stream);
|
||||
});
|
||||
}
|
||||
|
||||
static Napi::Boolean IsKeywordStreamReadyWrapper(
|
||||
const Napi::CallbackInfo &info) {
|
||||
Napi::Env env = info.Env();
|
||||
if (info.Length() != 2) {
|
||||
std::ostringstream os;
|
||||
os << "Expect only 2 arguments. Given: " << info.Length();
|
||||
|
||||
Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!info[0].IsExternal()) {
|
||||
Napi::TypeError::New(env, "Argument 0 should be a keyword spotter pointer.")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!info[1].IsExternal()) {
|
||||
Napi::TypeError::New(env, "Argument 1 should be an online stream pointer.")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
SherpaOnnxKeywordSpotter *kws =
|
||||
info[0].As<Napi::External<SherpaOnnxKeywordSpotter>>().Data();
|
||||
|
||||
SherpaOnnxOnlineStream *stream =
|
||||
info[1].As<Napi::External<SherpaOnnxOnlineStream>>().Data();
|
||||
|
||||
int32_t is_ready = SherpaOnnxIsKeywordStreamReady(kws, stream);
|
||||
|
||||
return Napi::Boolean::New(env, is_ready);
|
||||
}
|
||||
|
||||
static void DecodeKeywordStreamWrapper(const Napi::CallbackInfo &info) {
|
||||
Napi::Env env = info.Env();
|
||||
if (info.Length() != 2) {
|
||||
std::ostringstream os;
|
||||
os << "Expect only 2 arguments. Given: " << info.Length();
|
||||
|
||||
Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!info[0].IsExternal()) {
|
||||
Napi::TypeError::New(env, "Argument 0 should be a keyword spotter pointer.")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!info[1].IsExternal()) {
|
||||
Napi::TypeError::New(env, "Argument 1 should be an online stream pointer.")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
SherpaOnnxKeywordSpotter *kws =
|
||||
info[0].As<Napi::External<SherpaOnnxKeywordSpotter>>().Data();
|
||||
|
||||
SherpaOnnxOnlineStream *stream =
|
||||
info[1].As<Napi::External<SherpaOnnxOnlineStream>>().Data();
|
||||
|
||||
SherpaOnnxDecodeKeywordStream(kws, stream);
|
||||
}
|
||||
|
||||
static Napi::String GetKeywordResultAsJsonWrapper(
|
||||
const Napi::CallbackInfo &info) {
|
||||
Napi::Env env = info.Env();
|
||||
if (info.Length() != 2) {
|
||||
std::ostringstream os;
|
||||
os << "Expect only 2 arguments. Given: " << info.Length();
|
||||
|
||||
Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!info[0].IsExternal()) {
|
||||
Napi::TypeError::New(env, "Argument 0 should be a keyword spotter pointer.")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!info[1].IsExternal()) {
|
||||
Napi::TypeError::New(env, "Argument 1 should be an online stream pointer.")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
SherpaOnnxKeywordSpotter *kws =
|
||||
info[0].As<Napi::External<SherpaOnnxKeywordSpotter>>().Data();
|
||||
|
||||
SherpaOnnxOnlineStream *stream =
|
||||
info[1].As<Napi::External<SherpaOnnxOnlineStream>>().Data();
|
||||
|
||||
const char *json = SherpaOnnxGetKeywordResultAsJson(kws, stream);
|
||||
|
||||
Napi::String s = Napi::String::New(env, json);
|
||||
|
||||
SherpaOnnxFreeKeywordResultJson(json);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
void InitKeywordSpotting(Napi::Env env, Napi::Object exports) {
|
||||
exports.Set(Napi::String::New(env, "createKeywordSpotter"),
|
||||
Napi::Function::New(env, CreateKeywordSpotterWrapper));
|
||||
|
||||
exports.Set(Napi::String::New(env, "createKeywordStream"),
|
||||
Napi::Function::New(env, CreateKeywordStreamWrapper));
|
||||
|
||||
exports.Set(Napi::String::New(env, "isKeywordStreamReady"),
|
||||
Napi::Function::New(env, IsKeywordStreamReadyWrapper));
|
||||
|
||||
exports.Set(Napi::String::New(env, "decodeKeywordStream"),
|
||||
Napi::Function::New(env, DecodeKeywordStreamWrapper));
|
||||
|
||||
exports.Set(Napi::String::New(env, "getKeywordResultAsJson"),
|
||||
Napi::Function::New(env, GetKeywordResultAsJsonWrapper));
|
||||
}
|
||||
1
harmony-os/SherpaOnnxHar/sherpa_onnx/src/main/cpp/libs/.gitignore
vendored
Normal file
1
harmony-os/SherpaOnnxHar/sherpa_onnx/src/main/cpp/libs/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
*.so
|
||||
@@ -0,0 +1,17 @@
|
||||
# Introduction
|
||||
|
||||
You need to get the following four `.so` files using
|
||||
|
||||
- [build-ohos-arm64-v8a.sh](https://github.com/k2-fsa/sherpa-onnx/blob/master/build-ohos-arm64-v8a.sh)
|
||||
- [build-ohos-x86-64.sh](https://github.com/k2-fsa/sherpa-onnx/blob/master/build-ohos-x86-64.sh)
|
||||
|
||||
```
|
||||
.
|
||||
├── README.md
|
||||
├── arm64-v8a
|
||||
│ ├── libonnxruntime.so
|
||||
│ └── libsherpa-onnx-c-api.so
|
||||
└── x86_64
|
||||
├── libonnxruntime.so
|
||||
└── libsherpa-onnx-c-api.so
|
||||
```
|
||||
63
harmony-os/SherpaOnnxHar/sherpa_onnx/src/main/cpp/macros.h
Normal file
63
harmony-os/SherpaOnnxHar/sherpa_onnx/src/main/cpp/macros.h
Normal file
@@ -0,0 +1,63 @@
|
||||
// scripts/node-addon-api/src/macros.h
|
||||
//
|
||||
// Copyright (c) 2024 Xiaomi Corporation
|
||||
#ifndef SCRIPTS_NODE_ADDON_API_SRC_MACROS_H_
|
||||
#define SCRIPTS_NODE_ADDON_API_SRC_MACROS_H_
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
|
||||
#if __OHOS__
|
||||
#include "rawfile/raw_file_manager.h"
|
||||
#include "hilog/log.h"
|
||||
|
||||
#undef LOG_DOMAIN
|
||||
#undef LOG_TAG
|
||||
|
||||
// https://gitee.com/openharmony/docs/blob/145a084f0b742e4325915e32f8184817927d1251/en/contribute/OpenHarmony-Log-guide.md#hilog-api-usage-specifications
|
||||
#define LOG_DOMAIN 0x6666
|
||||
#define LOG_TAG "sherpa_onnx"
|
||||
#endif
|
||||
|
||||
#define SHERPA_ONNX_ASSIGN_ATTR_STR(c_name, js_name) \
|
||||
do { \
|
||||
if (o.Has(#js_name) && o.Get(#js_name).IsString()) { \
|
||||
Napi::String _str = o.Get(#js_name).As<Napi::String>(); \
|
||||
std::string s = _str.Utf8Value(); \
|
||||
char *p = new char[s.size() + 1]; \
|
||||
std::copy(s.begin(), s.end(), p); \
|
||||
p[s.size()] = 0; \
|
||||
\
|
||||
c.c_name = p; \
|
||||
} else if (o.Has(#js_name) && o.Get(#js_name).IsTypedArray()) { \
|
||||
Napi::Uint8Array _array = o.Get(#js_name).As<Napi::Uint8Array>(); \
|
||||
char *p = new char[_array.ElementLength() + 1]; \
|
||||
std::copy(_array.Data(), _array.Data() + _array.ElementLength(), p); \
|
||||
p[_array.ElementLength()] = '\0'; \
|
||||
\
|
||||
c.c_name = p; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define SHERPA_ONNX_ASSIGN_ATTR_INT32(c_name, js_name) \
|
||||
do { \
|
||||
if (o.Has(#js_name) && o.Get(#js_name).IsNumber()) { \
|
||||
c.c_name = o.Get(#js_name).As<Napi::Number>().Int32Value(); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define SHERPA_ONNX_ASSIGN_ATTR_FLOAT(c_name, js_name) \
|
||||
do { \
|
||||
if (o.Has(#js_name) && o.Get(#js_name).IsNumber()) { \
|
||||
c.c_name = o.Get(#js_name).As<Napi::Number>().FloatValue(); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define SHERPA_ONNX_DELETE_C_STR(p) \
|
||||
do { \
|
||||
if (p) { \
|
||||
delete[] p; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#endif // SCRIPTS_NODE_ADDON_API_SRC_MACROS_H_
|
||||
@@ -0,0 +1,14 @@
|
||||
diff --git a/napi-inl.h b/napi-inl.h
|
||||
index e7141c0..0fd90d8 100644
|
||||
--- a/napi-inl.h
|
||||
+++ b/napi-inl.h
|
||||
@@ -2156,7 +2156,8 @@ inline ArrayBuffer::ArrayBuffer(napi_env env, napi_value value)
|
||||
|
||||
inline void* ArrayBuffer::Data() {
|
||||
void* data;
|
||||
- napi_status status = napi_get_arraybuffer_info(_env, _value, &data, nullptr);
|
||||
+ size_t byte_length;
|
||||
+ napi_status status = napi_get_arraybuffer_info(_env, _value, &data, &byte_length);
|
||||
NAPI_THROW_IF_FAILED(_env, status, nullptr);
|
||||
return data;
|
||||
}
|
||||
@@ -0,0 +1,487 @@
|
||||
// scripts/node-addon-api/src/non-streaming-asr.cc
|
||||
//
|
||||
// Copyright (c) 2024 Xiaomi Corporation
|
||||
#include <sstream>
|
||||
|
||||
#include "macros.h" // NOLINT
|
||||
#include "napi.h" // NOLINT
|
||||
#include "sherpa-onnx/c-api/c-api.h"
|
||||
|
||||
// defined in ./streaming-asr.cc
|
||||
SherpaOnnxFeatureConfig GetFeatureConfig(Napi::Object obj);
|
||||
|
||||
static SherpaOnnxOfflineTransducerModelConfig GetOfflineTransducerModelConfig(
|
||||
Napi::Object obj) {
|
||||
SherpaOnnxOfflineTransducerModelConfig c;
|
||||
memset(&c, 0, sizeof(c));
|
||||
|
||||
if (!obj.Has("transducer") || !obj.Get("transducer").IsObject()) {
|
||||
return c;
|
||||
}
|
||||
|
||||
Napi::Object o = obj.Get("transducer").As<Napi::Object>();
|
||||
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(encoder, encoder);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(decoder, decoder);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(joiner, joiner);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
static SherpaOnnxOfflineParaformerModelConfig GetOfflineParaformerModelConfig(
|
||||
Napi::Object obj) {
|
||||
SherpaOnnxOfflineParaformerModelConfig c;
|
||||
memset(&c, 0, sizeof(c));
|
||||
|
||||
if (!obj.Has("paraformer") || !obj.Get("paraformer").IsObject()) {
|
||||
return c;
|
||||
}
|
||||
|
||||
Napi::Object o = obj.Get("paraformer").As<Napi::Object>();
|
||||
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(model, model);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
static SherpaOnnxOfflineNemoEncDecCtcModelConfig GetOfflineNeMoCtcModelConfig(
|
||||
Napi::Object obj) {
|
||||
SherpaOnnxOfflineNemoEncDecCtcModelConfig c;
|
||||
memset(&c, 0, sizeof(c));
|
||||
|
||||
if (!obj.Has("nemoCtc") || !obj.Get("nemoCtc").IsObject()) {
|
||||
return c;
|
||||
}
|
||||
|
||||
Napi::Object o = obj.Get("nemoCtc").As<Napi::Object>();
|
||||
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(model, model);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
static SherpaOnnxOfflineWhisperModelConfig GetOfflineWhisperModelConfig(
|
||||
Napi::Object obj) {
|
||||
SherpaOnnxOfflineWhisperModelConfig c;
|
||||
memset(&c, 0, sizeof(c));
|
||||
|
||||
if (!obj.Has("whisper") || !obj.Get("whisper").IsObject()) {
|
||||
return c;
|
||||
}
|
||||
|
||||
Napi::Object o = obj.Get("whisper").As<Napi::Object>();
|
||||
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(encoder, encoder);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(decoder, decoder);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(language, language);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(task, task);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_INT32(tail_paddings, tailPaddings);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
static SherpaOnnxOfflineMoonshineModelConfig GetOfflineMoonshineModelConfig(
|
||||
Napi::Object obj) {
|
||||
SherpaOnnxOfflineMoonshineModelConfig c;
|
||||
memset(&c, 0, sizeof(c));
|
||||
|
||||
if (!obj.Has("moonshine") || !obj.Get("moonshine").IsObject()) {
|
||||
return c;
|
||||
}
|
||||
|
||||
Napi::Object o = obj.Get("moonshine").As<Napi::Object>();
|
||||
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(preprocessor, preprocessor);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(encoder, encoder);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(uncached_decoder, uncachedDecoder);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(cached_decoder, cachedDecoder);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
static SherpaOnnxOfflineTdnnModelConfig GetOfflineTdnnModelConfig(
|
||||
Napi::Object obj) {
|
||||
SherpaOnnxOfflineTdnnModelConfig c;
|
||||
memset(&c, 0, sizeof(c));
|
||||
|
||||
if (!obj.Has("tdnn") || !obj.Get("tdnn").IsObject()) {
|
||||
return c;
|
||||
}
|
||||
|
||||
Napi::Object o = obj.Get("tdnn").As<Napi::Object>();
|
||||
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(model, model);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
static SherpaOnnxOfflineSenseVoiceModelConfig GetOfflineSenseVoiceModelConfig(
|
||||
Napi::Object obj) {
|
||||
SherpaOnnxOfflineSenseVoiceModelConfig c;
|
||||
memset(&c, 0, sizeof(c));
|
||||
|
||||
if (!obj.Has("senseVoice") || !obj.Get("senseVoice").IsObject()) {
|
||||
return c;
|
||||
}
|
||||
|
||||
Napi::Object o = obj.Get("senseVoice").As<Napi::Object>();
|
||||
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(model, model);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(language, language);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_INT32(use_itn, useInverseTextNormalization);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
static SherpaOnnxOfflineModelConfig GetOfflineModelConfig(Napi::Object obj) {
|
||||
SherpaOnnxOfflineModelConfig c;
|
||||
memset(&c, 0, sizeof(c));
|
||||
|
||||
if (!obj.Has("modelConfig") || !obj.Get("modelConfig").IsObject()) {
|
||||
return c;
|
||||
}
|
||||
|
||||
Napi::Object o = obj.Get("modelConfig").As<Napi::Object>();
|
||||
|
||||
c.transducer = GetOfflineTransducerModelConfig(o);
|
||||
c.paraformer = GetOfflineParaformerModelConfig(o);
|
||||
c.nemo_ctc = GetOfflineNeMoCtcModelConfig(o);
|
||||
c.whisper = GetOfflineWhisperModelConfig(o);
|
||||
c.tdnn = GetOfflineTdnnModelConfig(o);
|
||||
c.sense_voice = GetOfflineSenseVoiceModelConfig(o);
|
||||
c.moonshine = GetOfflineMoonshineModelConfig(o);
|
||||
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(tokens, tokens);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_INT32(num_threads, numThreads);
|
||||
|
||||
if (o.Has("debug") &&
|
||||
(o.Get("debug").IsNumber() || o.Get("debug").IsBoolean())) {
|
||||
if (o.Get("debug").IsBoolean()) {
|
||||
c.debug = o.Get("debug").As<Napi::Boolean>().Value();
|
||||
} else {
|
||||
c.debug = o.Get("debug").As<Napi::Number>().Int32Value();
|
||||
}
|
||||
}
|
||||
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(provider, provider);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(model_type, modelType);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(modeling_unit, modelingUnit);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(bpe_vocab, bpeVocab);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(telespeech_ctc, teleSpeechCtc);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
static SherpaOnnxOfflineLMConfig GetOfflineLMConfig(Napi::Object obj) {
|
||||
SherpaOnnxOfflineLMConfig c;
|
||||
memset(&c, 0, sizeof(c));
|
||||
|
||||
if (!obj.Has("lmConfig") || !obj.Get("lmConfig").IsObject()) {
|
||||
return c;
|
||||
}
|
||||
|
||||
Napi::Object o = obj.Get("lmConfig").As<Napi::Object>();
|
||||
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(model, model);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_FLOAT(scale, scale);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
static Napi::External<SherpaOnnxOfflineRecognizer>
|
||||
CreateOfflineRecognizerWrapper(const Napi::CallbackInfo &info) {
|
||||
Napi::Env env = info.Env();
|
||||
#if __OHOS__
|
||||
// the last argument is the NativeResourceManager
|
||||
if (info.Length() != 2) {
|
||||
std::ostringstream os;
|
||||
os << "Expect only 2 arguments. Given: " << info.Length();
|
||||
|
||||
Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
#else
|
||||
if (info.Length() != 1) {
|
||||
std::ostringstream os;
|
||||
os << "Expect only 1 argument. Given: " << info.Length();
|
||||
|
||||
Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!info[0].IsObject()) {
|
||||
Napi::TypeError::New(env, "Expect an object as the argument")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
Napi::Object o = info[0].As<Napi::Object>();
|
||||
|
||||
SherpaOnnxOfflineRecognizerConfig c;
|
||||
memset(&c, 0, sizeof(c));
|
||||
c.feat_config = GetFeatureConfig(o);
|
||||
c.model_config = GetOfflineModelConfig(o);
|
||||
c.lm_config = GetOfflineLMConfig(o);
|
||||
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(decoding_method, decodingMethod);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_INT32(max_active_paths, maxActivePaths);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(hotwords_file, hotwordsFile);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_FLOAT(hotwords_score, hotwordsScore);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(rule_fsts, ruleFsts);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(rule_fars, ruleFars);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_FLOAT(blank_penalty, blankPenalty);
|
||||
|
||||
#if __OHOS__
|
||||
std::unique_ptr<NativeResourceManager, decltype(&OH_ResourceManager_ReleaseNativeResourceManager)> mgr (OH_ResourceManager_InitNativeResourceManager(env, info[1]), &OH_ResourceManager_ReleaseNativeResourceManager);
|
||||
|
||||
const SherpaOnnxOfflineRecognizer *recognizer =
|
||||
SherpaOnnxCreateOfflineRecognizerOHOS(&c, mgr.get());
|
||||
#else
|
||||
const SherpaOnnxOfflineRecognizer *recognizer =
|
||||
SherpaOnnxCreateOfflineRecognizer(&c);
|
||||
#endif
|
||||
|
||||
SHERPA_ONNX_DELETE_C_STR(c.model_config.transducer.encoder);
|
||||
SHERPA_ONNX_DELETE_C_STR(c.model_config.transducer.decoder);
|
||||
SHERPA_ONNX_DELETE_C_STR(c.model_config.transducer.joiner);
|
||||
|
||||
SHERPA_ONNX_DELETE_C_STR(c.model_config.paraformer.model);
|
||||
|
||||
SHERPA_ONNX_DELETE_C_STR(c.model_config.nemo_ctc.model);
|
||||
|
||||
SHERPA_ONNX_DELETE_C_STR(c.model_config.whisper.encoder);
|
||||
SHERPA_ONNX_DELETE_C_STR(c.model_config.whisper.decoder);
|
||||
SHERPA_ONNX_DELETE_C_STR(c.model_config.whisper.language);
|
||||
SHERPA_ONNX_DELETE_C_STR(c.model_config.whisper.task);
|
||||
|
||||
SHERPA_ONNX_DELETE_C_STR(c.model_config.tdnn.model);
|
||||
|
||||
SHERPA_ONNX_DELETE_C_STR(c.model_config.sense_voice.model);
|
||||
SHERPA_ONNX_DELETE_C_STR(c.model_config.sense_voice.language);
|
||||
|
||||
SHERPA_ONNX_DELETE_C_STR(c.model_config.moonshine.preprocessor);
|
||||
SHERPA_ONNX_DELETE_C_STR(c.model_config.moonshine.encoder);
|
||||
SHERPA_ONNX_DELETE_C_STR(c.model_config.moonshine.uncached_decoder);
|
||||
SHERPA_ONNX_DELETE_C_STR(c.model_config.moonshine.cached_decoder);
|
||||
|
||||
SHERPA_ONNX_DELETE_C_STR(c.model_config.tokens);
|
||||
SHERPA_ONNX_DELETE_C_STR(c.model_config.provider);
|
||||
SHERPA_ONNX_DELETE_C_STR(c.model_config.model_type);
|
||||
SHERPA_ONNX_DELETE_C_STR(c.model_config.modeling_unit);
|
||||
SHERPA_ONNX_DELETE_C_STR(c.model_config.bpe_vocab);
|
||||
SHERPA_ONNX_DELETE_C_STR(c.model_config.telespeech_ctc);
|
||||
|
||||
SHERPA_ONNX_DELETE_C_STR(c.lm_config.model);
|
||||
|
||||
SHERPA_ONNX_DELETE_C_STR(c.decoding_method);
|
||||
SHERPA_ONNX_DELETE_C_STR(c.hotwords_file);
|
||||
SHERPA_ONNX_DELETE_C_STR(c.rule_fsts);
|
||||
SHERPA_ONNX_DELETE_C_STR(c.rule_fars);
|
||||
|
||||
if (!recognizer) {
|
||||
Napi::TypeError::New(env, "Please check your config!")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
return Napi::External<SherpaOnnxOfflineRecognizer>::New(
|
||||
env, const_cast<SherpaOnnxOfflineRecognizer *>(recognizer),
|
||||
[](Napi::Env env, SherpaOnnxOfflineRecognizer *recognizer) {
|
||||
SherpaOnnxDestroyOfflineRecognizer(recognizer);
|
||||
});
|
||||
}
|
||||
|
||||
static Napi::External<SherpaOnnxOfflineStream> CreateOfflineStreamWrapper(
|
||||
const Napi::CallbackInfo &info) {
|
||||
Napi::Env env = info.Env();
|
||||
if (info.Length() != 1) {
|
||||
std::ostringstream os;
|
||||
os << "Expect only 1 argument. Given: " << info.Length();
|
||||
|
||||
Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!info[0].IsExternal()) {
|
||||
Napi::TypeError::New(
|
||||
env,
|
||||
"You should pass an offline recognizer pointer as the only argument")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
SherpaOnnxOfflineRecognizer *recognizer =
|
||||
info[0].As<Napi::External<SherpaOnnxOfflineRecognizer>>().Data();
|
||||
|
||||
const SherpaOnnxOfflineStream *stream =
|
||||
SherpaOnnxCreateOfflineStream(recognizer);
|
||||
|
||||
return Napi::External<SherpaOnnxOfflineStream>::New(
|
||||
env, const_cast<SherpaOnnxOfflineStream *>(stream),
|
||||
[](Napi::Env env, SherpaOnnxOfflineStream *stream) {
|
||||
SherpaOnnxDestroyOfflineStream(stream);
|
||||
});
|
||||
}
|
||||
|
||||
static void AcceptWaveformOfflineWrapper(const Napi::CallbackInfo &info) {
|
||||
Napi::Env env = info.Env();
|
||||
|
||||
if (info.Length() != 2) {
|
||||
std::ostringstream os;
|
||||
os << "Expect only 2 arguments. Given: " << info.Length();
|
||||
|
||||
Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!info[0].IsExternal()) {
|
||||
Napi::TypeError::New(env, "Argument 0 should be an online stream pointer.")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
SherpaOnnxOfflineStream *stream =
|
||||
info[0].As<Napi::External<SherpaOnnxOfflineStream>>().Data();
|
||||
|
||||
if (!info[1].IsObject()) {
|
||||
Napi::TypeError::New(env, "Argument 1 should be an object")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Napi::Object obj = info[1].As<Napi::Object>();
|
||||
|
||||
if (!obj.Has("samples")) {
|
||||
Napi::TypeError::New(env, "The argument object should have a field samples")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!obj.Get("samples").IsTypedArray()) {
|
||||
Napi::TypeError::New(env, "The object['samples'] should be a typed array")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!obj.Has("sampleRate")) {
|
||||
Napi::TypeError::New(env,
|
||||
"The argument object should have a field sampleRate")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!obj.Get("sampleRate").IsNumber()) {
|
||||
Napi::TypeError::New(env, "The object['samples'] should be a number")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Napi::Float32Array samples = obj.Get("samples").As<Napi::Float32Array>();
|
||||
int32_t sample_rate = obj.Get("sampleRate").As<Napi::Number>().Int32Value();
|
||||
|
||||
#if __OHOS__
|
||||
// Note(fangjun): For unknown reasons on HarmonyOS, we need to divide it by
|
||||
// sizeof(float) here
|
||||
SherpaOnnxAcceptWaveformOffline(stream, sample_rate, samples.Data(),
|
||||
samples.ElementLength() / sizeof(float));
|
||||
#else
|
||||
SherpaOnnxAcceptWaveformOffline(stream, sample_rate, samples.Data(),
|
||||
samples.ElementLength());
|
||||
#endif
|
||||
}
|
||||
|
||||
static void DecodeOfflineStreamWrapper(const Napi::CallbackInfo &info) {
|
||||
Napi::Env env = info.Env();
|
||||
if (info.Length() != 2) {
|
||||
std::ostringstream os;
|
||||
os << "Expect only 2 arguments. Given: " << info.Length();
|
||||
|
||||
Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!info[0].IsExternal()) {
|
||||
Napi::TypeError::New(env,
|
||||
"Argument 0 should be an offline recognizer pointer.")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!info[1].IsExternal()) {
|
||||
Napi::TypeError::New(env, "Argument 1 should be an offline stream pointer.")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
SherpaOnnxOfflineRecognizer *recognizer =
|
||||
info[0].As<Napi::External<SherpaOnnxOfflineRecognizer>>().Data();
|
||||
|
||||
SherpaOnnxOfflineStream *stream =
|
||||
info[1].As<Napi::External<SherpaOnnxOfflineStream>>().Data();
|
||||
|
||||
SherpaOnnxDecodeOfflineStream(recognizer, stream);
|
||||
}
|
||||
|
||||
static Napi::String GetOfflineStreamResultAsJsonWrapper(
|
||||
const Napi::CallbackInfo &info) {
|
||||
Napi::Env env = info.Env();
|
||||
if (info.Length() != 1) {
|
||||
std::ostringstream os;
|
||||
os << "Expect only 1 argument. Given: " << info.Length();
|
||||
|
||||
Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!info[0].IsExternal()) {
|
||||
Napi::TypeError::New(env, "Argument 0 should be an online stream pointer.")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
SherpaOnnxOfflineStream *stream =
|
||||
info[0].As<Napi::External<SherpaOnnxOfflineStream>>().Data();
|
||||
|
||||
const char *json = SherpaOnnxGetOfflineStreamResultAsJson(stream);
|
||||
Napi::String s = Napi::String::New(env, json);
|
||||
|
||||
SherpaOnnxDestroyOfflineStreamResultJson(json);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
void InitNonStreamingAsr(Napi::Env env, Napi::Object exports) {
|
||||
exports.Set(Napi::String::New(env, "createOfflineRecognizer"),
|
||||
Napi::Function::New(env, CreateOfflineRecognizerWrapper));
|
||||
|
||||
exports.Set(Napi::String::New(env, "createOfflineStream"),
|
||||
Napi::Function::New(env, CreateOfflineStreamWrapper));
|
||||
|
||||
exports.Set(Napi::String::New(env, "acceptWaveformOffline"),
|
||||
Napi::Function::New(env, AcceptWaveformOfflineWrapper));
|
||||
|
||||
exports.Set(Napi::String::New(env, "decodeOfflineStream"),
|
||||
Napi::Function::New(env, DecodeOfflineStreamWrapper));
|
||||
|
||||
exports.Set(Napi::String::New(env, "getOfflineStreamResultAsJson"),
|
||||
Napi::Function::New(env, GetOfflineStreamResultAsJsonWrapper));
|
||||
}
|
||||
@@ -0,0 +1,310 @@
|
||||
// scripts/node-addon-api/src/non-streaming-speaker-diarization.cc
|
||||
//
|
||||
// Copyright (c) 2024 Xiaomi Corporation
|
||||
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
|
||||
#include "macros.h" // NOLINT
|
||||
#include "napi.h" // NOLINT
|
||||
#include "sherpa-onnx/c-api/c-api.h"
|
||||
|
||||
static SherpaOnnxOfflineSpeakerSegmentationPyannoteModelConfig
|
||||
GetOfflineSpeakerSegmentationPyannoteModelConfig(Napi::Object obj) {
|
||||
SherpaOnnxOfflineSpeakerSegmentationPyannoteModelConfig c;
|
||||
memset(&c, 0, sizeof(c));
|
||||
|
||||
if (!obj.Has("pyannote") || !obj.Get("pyannote").IsObject()) {
|
||||
return c;
|
||||
}
|
||||
|
||||
Napi::Object o = obj.Get("pyannote").As<Napi::Object>();
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(model, model);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
static SherpaOnnxOfflineSpeakerSegmentationModelConfig
|
||||
GetOfflineSpeakerSegmentationModelConfig(Napi::Object obj) {
|
||||
SherpaOnnxOfflineSpeakerSegmentationModelConfig c;
|
||||
memset(&c, 0, sizeof(c));
|
||||
|
||||
if (!obj.Has("segmentation") || !obj.Get("segmentation").IsObject()) {
|
||||
return c;
|
||||
}
|
||||
|
||||
Napi::Object o = obj.Get("segmentation").As<Napi::Object>();
|
||||
|
||||
c.pyannote = GetOfflineSpeakerSegmentationPyannoteModelConfig(o);
|
||||
|
||||
SHERPA_ONNX_ASSIGN_ATTR_INT32(num_threads, numThreads);
|
||||
|
||||
if (o.Has("debug") &&
|
||||
(o.Get("debug").IsNumber() || o.Get("debug").IsBoolean())) {
|
||||
if (o.Get("debug").IsBoolean()) {
|
||||
c.debug = o.Get("debug").As<Napi::Boolean>().Value();
|
||||
} else {
|
||||
c.debug = o.Get("debug").As<Napi::Number>().Int32Value();
|
||||
}
|
||||
}
|
||||
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(provider, provider);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
static SherpaOnnxSpeakerEmbeddingExtractorConfig
|
||||
GetSpeakerEmbeddingExtractorConfig(Napi::Object obj) {
|
||||
SherpaOnnxSpeakerEmbeddingExtractorConfig c;
|
||||
memset(&c, 0, sizeof(c));
|
||||
|
||||
if (!obj.Has("embedding") || !obj.Get("embedding").IsObject()) {
|
||||
return c;
|
||||
}
|
||||
|
||||
Napi::Object o = obj.Get("embedding").As<Napi::Object>();
|
||||
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(model, model);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_INT32(num_threads, numThreads);
|
||||
|
||||
if (o.Has("debug") &&
|
||||
(o.Get("debug").IsNumber() || o.Get("debug").IsBoolean())) {
|
||||
if (o.Get("debug").IsBoolean()) {
|
||||
c.debug = o.Get("debug").As<Napi::Boolean>().Value();
|
||||
} else {
|
||||
c.debug = o.Get("debug").As<Napi::Number>().Int32Value();
|
||||
}
|
||||
}
|
||||
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(provider, provider);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
static SherpaOnnxFastClusteringConfig GetFastClusteringConfig(
|
||||
Napi::Object obj) {
|
||||
SherpaOnnxFastClusteringConfig c;
|
||||
memset(&c, 0, sizeof(c));
|
||||
|
||||
if (!obj.Has("clustering") || !obj.Get("clustering").IsObject()) {
|
||||
return c;
|
||||
}
|
||||
|
||||
Napi::Object o = obj.Get("clustering").As<Napi::Object>();
|
||||
|
||||
SHERPA_ONNX_ASSIGN_ATTR_INT32(num_clusters, numClusters);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_FLOAT(threshold, threshold);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
static Napi::External<SherpaOnnxOfflineSpeakerDiarization>
|
||||
CreateOfflineSpeakerDiarizationWrapper(const Napi::CallbackInfo &info) {
|
||||
Napi::Env env = info.Env();
|
||||
if (info.Length() != 1) {
|
||||
std::ostringstream os;
|
||||
os << "Expect only 1 argument. Given: " << info.Length();
|
||||
|
||||
Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!info[0].IsObject()) {
|
||||
Napi::TypeError::New(env, "Expect an object as the argument")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
Napi::Object o = info[0].As<Napi::Object>();
|
||||
|
||||
SherpaOnnxOfflineSpeakerDiarizationConfig c;
|
||||
memset(&c, 0, sizeof(c));
|
||||
|
||||
c.segmentation = GetOfflineSpeakerSegmentationModelConfig(o);
|
||||
c.embedding = GetSpeakerEmbeddingExtractorConfig(o);
|
||||
c.clustering = GetFastClusteringConfig(o);
|
||||
|
||||
SHERPA_ONNX_ASSIGN_ATTR_FLOAT(min_duration_on, minDurationOn);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_FLOAT(min_duration_off, minDurationOff);
|
||||
|
||||
const SherpaOnnxOfflineSpeakerDiarization *sd =
|
||||
SherpaOnnxCreateOfflineSpeakerDiarization(&c);
|
||||
|
||||
if (c.segmentation.pyannote.model) {
|
||||
delete[] c.segmentation.pyannote.model;
|
||||
}
|
||||
|
||||
if (c.segmentation.provider) {
|
||||
delete[] c.segmentation.provider;
|
||||
}
|
||||
|
||||
if (c.embedding.model) {
|
||||
delete[] c.embedding.model;
|
||||
}
|
||||
|
||||
if (c.embedding.provider) {
|
||||
delete[] c.embedding.provider;
|
||||
}
|
||||
|
||||
if (!sd) {
|
||||
Napi::TypeError::New(env, "Please check your config!")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
return Napi::External<SherpaOnnxOfflineSpeakerDiarization>::New(
|
||||
env, const_cast<SherpaOnnxOfflineSpeakerDiarization *>(sd),
|
||||
[](Napi::Env env, SherpaOnnxOfflineSpeakerDiarization *sd) {
|
||||
SherpaOnnxDestroyOfflineSpeakerDiarization(sd);
|
||||
});
|
||||
}
|
||||
|
||||
static Napi::Number OfflineSpeakerDiarizationGetSampleRateWrapper(
|
||||
const Napi::CallbackInfo &info) {
|
||||
Napi::Env env = info.Env();
|
||||
|
||||
if (info.Length() != 1) {
|
||||
std::ostringstream os;
|
||||
os << "Expect only 1 argument. Given: " << info.Length();
|
||||
|
||||
Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!info[0].IsExternal()) {
|
||||
Napi::TypeError::New(
|
||||
env, "Argument 0 should be an offline speaker diarization pointer.")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
const SherpaOnnxOfflineSpeakerDiarization *sd =
|
||||
info[0].As<Napi::External<SherpaOnnxOfflineSpeakerDiarization>>().Data();
|
||||
|
||||
int32_t sample_rate = SherpaOnnxOfflineSpeakerDiarizationGetSampleRate(sd);
|
||||
|
||||
return Napi::Number::New(env, sample_rate);
|
||||
}
|
||||
|
||||
static Napi::Array OfflineSpeakerDiarizationProcessWrapper(
|
||||
const Napi::CallbackInfo &info) {
|
||||
Napi::Env env = info.Env();
|
||||
|
||||
if (info.Length() != 2) {
|
||||
std::ostringstream os;
|
||||
os << "Expect only 2 arguments. Given: " << info.Length();
|
||||
|
||||
Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!info[0].IsExternal()) {
|
||||
Napi::TypeError::New(
|
||||
env, "Argument 0 should be an offline speaker diarization pointer.")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
const SherpaOnnxOfflineSpeakerDiarization *sd =
|
||||
info[0].As<Napi::External<SherpaOnnxOfflineSpeakerDiarization>>().Data();
|
||||
|
||||
if (!info[1].IsTypedArray()) {
|
||||
Napi::TypeError::New(env, "Argument 1 should be a typed array")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
Napi::Float32Array samples = info[1].As<Napi::Float32Array>();
|
||||
|
||||
const SherpaOnnxOfflineSpeakerDiarizationResult *r =
|
||||
SherpaOnnxOfflineSpeakerDiarizationProcess(sd, samples.Data(),
|
||||
samples.ElementLength());
|
||||
|
||||
int32_t num_segments =
|
||||
SherpaOnnxOfflineSpeakerDiarizationResultGetNumSegments(r);
|
||||
|
||||
const SherpaOnnxOfflineSpeakerDiarizationSegment *segments =
|
||||
SherpaOnnxOfflineSpeakerDiarizationResultSortByStartTime(r);
|
||||
|
||||
Napi::Array ans = Napi::Array::New(env, num_segments);
|
||||
|
||||
for (int32_t i = 0; i != num_segments; ++i) {
|
||||
Napi::Object obj = Napi::Object::New(env);
|
||||
|
||||
obj.Set(Napi::String::New(env, "start"), segments[i].start);
|
||||
obj.Set(Napi::String::New(env, "end"), segments[i].end);
|
||||
obj.Set(Napi::String::New(env, "speaker"), segments[i].speaker);
|
||||
|
||||
ans.Set(i, obj);
|
||||
}
|
||||
|
||||
SherpaOnnxOfflineSpeakerDiarizationDestroySegment(segments);
|
||||
SherpaOnnxOfflineSpeakerDiarizationDestroyResult(r);
|
||||
|
||||
return ans;
|
||||
}
|
||||
|
||||
static void OfflineSpeakerDiarizationSetConfigWrapper(
|
||||
const Napi::CallbackInfo &info) {
|
||||
Napi::Env env = info.Env();
|
||||
|
||||
if (info.Length() != 2) {
|
||||
std::ostringstream os;
|
||||
os << "Expect only 2 arguments. Given: " << info.Length();
|
||||
|
||||
Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!info[0].IsExternal()) {
|
||||
Napi::TypeError::New(
|
||||
env, "Argument 0 should be an offline speaker diarization pointer.")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const SherpaOnnxOfflineSpeakerDiarization *sd =
|
||||
info[0].As<Napi::External<SherpaOnnxOfflineSpeakerDiarization>>().Data();
|
||||
|
||||
if (!info[1].IsObject()) {
|
||||
Napi::TypeError::New(env, "Expect an object as the argument")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Napi::Object o = info[0].As<Napi::Object>();
|
||||
|
||||
SherpaOnnxOfflineSpeakerDiarizationConfig c;
|
||||
memset(&c, 0, sizeof(c));
|
||||
|
||||
c.clustering = GetFastClusteringConfig(o);
|
||||
SherpaOnnxOfflineSpeakerDiarizationSetConfig(sd, &c);
|
||||
}
|
||||
|
||||
void InitNonStreamingSpeakerDiarization(Napi::Env env, Napi::Object exports) {
|
||||
exports.Set(Napi::String::New(env, "createOfflineSpeakerDiarization"),
|
||||
Napi::Function::New(env, CreateOfflineSpeakerDiarizationWrapper));
|
||||
|
||||
exports.Set(
|
||||
Napi::String::New(env, "getOfflineSpeakerDiarizationSampleRate"),
|
||||
Napi::Function::New(env, OfflineSpeakerDiarizationGetSampleRateWrapper));
|
||||
|
||||
exports.Set(
|
||||
Napi::String::New(env, "offlineSpeakerDiarizationProcess"),
|
||||
Napi::Function::New(env, OfflineSpeakerDiarizationProcessWrapper));
|
||||
|
||||
exports.Set(
|
||||
Napi::String::New(env, "offlineSpeakerDiarizationSetConfig"),
|
||||
Napi::Function::New(env, OfflineSpeakerDiarizationSetConfigWrapper));
|
||||
}
|
||||
@@ -0,0 +1,329 @@
|
||||
// scripts/node-addon-api/src/non-streaming-tts.cc
|
||||
//
|
||||
// Copyright (c) 2024 Xiaomi Corporation
|
||||
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
|
||||
#include "macros.h" // NOLINT
|
||||
#include "napi.h" // NOLINT
|
||||
#include "sherpa-onnx/c-api/c-api.h"
|
||||
|
||||
static SherpaOnnxOfflineTtsVitsModelConfig GetOfflineTtsVitsModelConfig(
|
||||
Napi::Object obj) {
|
||||
SherpaOnnxOfflineTtsVitsModelConfig c;
|
||||
memset(&c, 0, sizeof(c));
|
||||
|
||||
if (!obj.Has("vits") || !obj.Get("vits").IsObject()) {
|
||||
return c;
|
||||
}
|
||||
|
||||
Napi::Object o = obj.Get("vits").As<Napi::Object>();
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(model, model);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(lexicon, lexicon);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(tokens, tokens);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(data_dir, dataDir);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_FLOAT(noise_scale, noiseScale);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_FLOAT(noise_scale_w, noiseScaleW);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_FLOAT(length_scale, lengthScale);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(dict_dir, dictDir);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
static SherpaOnnxOfflineTtsModelConfig GetOfflineTtsModelConfig(
|
||||
Napi::Object obj) {
|
||||
SherpaOnnxOfflineTtsModelConfig c;
|
||||
memset(&c, 0, sizeof(c));
|
||||
|
||||
if (!obj.Has("model") || !obj.Get("model").IsObject()) {
|
||||
return c;
|
||||
}
|
||||
|
||||
Napi::Object o = obj.Get("model").As<Napi::Object>();
|
||||
|
||||
c.vits = GetOfflineTtsVitsModelConfig(o);
|
||||
|
||||
SHERPA_ONNX_ASSIGN_ATTR_INT32(num_threads, numThreads);
|
||||
|
||||
if (o.Has("debug") &&
|
||||
(o.Get("debug").IsNumber() || o.Get("debug").IsBoolean())) {
|
||||
if (o.Get("debug").IsBoolean()) {
|
||||
c.debug = o.Get("debug").As<Napi::Boolean>().Value();
|
||||
} else {
|
||||
c.debug = o.Get("debug").As<Napi::Number>().Int32Value();
|
||||
}
|
||||
}
|
||||
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(provider, provider);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
static Napi::External<SherpaOnnxOfflineTts> CreateOfflineTtsWrapper(
|
||||
const Napi::CallbackInfo &info) {
|
||||
Napi::Env env = info.Env();
|
||||
if (info.Length() != 1) {
|
||||
std::ostringstream os;
|
||||
os << "Expect only 1 argument. Given: " << info.Length();
|
||||
|
||||
Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!info[0].IsObject()) {
|
||||
Napi::TypeError::New(env, "Expect an object as the argument")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
Napi::Object o = info[0].As<Napi::Object>();
|
||||
|
||||
SherpaOnnxOfflineTtsConfig c;
|
||||
memset(&c, 0, sizeof(c));
|
||||
|
||||
c.model = GetOfflineTtsModelConfig(o);
|
||||
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(rule_fsts, ruleFsts);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_INT32(max_num_sentences, maxNumSentences);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(rule_fars, ruleFars);
|
||||
|
||||
SherpaOnnxOfflineTts *tts = SherpaOnnxCreateOfflineTts(&c);
|
||||
|
||||
if (c.model.vits.model) {
|
||||
delete[] c.model.vits.model;
|
||||
}
|
||||
|
||||
if (c.model.vits.lexicon) {
|
||||
delete[] c.model.vits.lexicon;
|
||||
}
|
||||
|
||||
if (c.model.vits.tokens) {
|
||||
delete[] c.model.vits.tokens;
|
||||
}
|
||||
|
||||
if (c.model.vits.data_dir) {
|
||||
delete[] c.model.vits.data_dir;
|
||||
}
|
||||
|
||||
if (c.model.vits.dict_dir) {
|
||||
delete[] c.model.vits.dict_dir;
|
||||
}
|
||||
|
||||
if (c.model.provider) {
|
||||
delete[] c.model.provider;
|
||||
}
|
||||
|
||||
if (c.rule_fsts) {
|
||||
delete[] c.rule_fsts;
|
||||
}
|
||||
|
||||
if (c.rule_fars) {
|
||||
delete[] c.rule_fars;
|
||||
}
|
||||
|
||||
if (!tts) {
|
||||
Napi::TypeError::New(env, "Please check your config!")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
return Napi::External<SherpaOnnxOfflineTts>::New(
|
||||
env, tts, [](Napi::Env env, SherpaOnnxOfflineTts *tts) {
|
||||
SherpaOnnxDestroyOfflineTts(tts);
|
||||
});
|
||||
}
|
||||
|
||||
static Napi::Number OfflineTtsSampleRateWrapper(
|
||||
const Napi::CallbackInfo &info) {
|
||||
Napi::Env env = info.Env();
|
||||
|
||||
if (info.Length() != 1) {
|
||||
std::ostringstream os;
|
||||
os << "Expect only 1 argument. Given: " << info.Length();
|
||||
|
||||
Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!info[0].IsExternal()) {
|
||||
Napi::TypeError::New(env, "Argument 0 should be an offline tts pointer.")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
SherpaOnnxOfflineTts *tts =
|
||||
info[0].As<Napi::External<SherpaOnnxOfflineTts>>().Data();
|
||||
|
||||
int32_t sample_rate = SherpaOnnxOfflineTtsSampleRate(tts);
|
||||
|
||||
return Napi::Number::New(env, sample_rate);
|
||||
}
|
||||
|
||||
static Napi::Number OfflineTtsNumSpeakersWrapper(
|
||||
const Napi::CallbackInfo &info) {
|
||||
Napi::Env env = info.Env();
|
||||
|
||||
if (info.Length() != 1) {
|
||||
std::ostringstream os;
|
||||
os << "Expect only 1 argument. Given: " << info.Length();
|
||||
|
||||
Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!info[0].IsExternal()) {
|
||||
Napi::TypeError::New(env, "Argument 0 should be an offline tts pointer.")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
SherpaOnnxOfflineTts *tts =
|
||||
info[0].As<Napi::External<SherpaOnnxOfflineTts>>().Data();
|
||||
|
||||
int32_t num_speakers = SherpaOnnxOfflineTtsNumSpeakers(tts);
|
||||
|
||||
return Napi::Number::New(env, num_speakers);
|
||||
}
|
||||
|
||||
static Napi::Object OfflineTtsGenerateWrapper(const Napi::CallbackInfo &info) {
|
||||
Napi::Env env = info.Env();
|
||||
|
||||
if (info.Length() != 2) {
|
||||
std::ostringstream os;
|
||||
os << "Expect only 1 argument. Given: " << info.Length();
|
||||
|
||||
Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!info[0].IsExternal()) {
|
||||
Napi::TypeError::New(env, "Argument 0 should be an offline tts pointer.")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
SherpaOnnxOfflineTts *tts =
|
||||
info[0].As<Napi::External<SherpaOnnxOfflineTts>>().Data();
|
||||
|
||||
if (!info[1].IsObject()) {
|
||||
Napi::TypeError::New(env, "Argument 1 should be an object")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
Napi::Object obj = info[1].As<Napi::Object>();
|
||||
|
||||
if (!obj.Has("text")) {
|
||||
Napi::TypeError::New(env, "The argument object should have a field text")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!obj.Get("text").IsString()) {
|
||||
Napi::TypeError::New(env, "The object['text'] should be a string")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!obj.Has("sid")) {
|
||||
Napi::TypeError::New(env, "The argument object should have a field sid")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!obj.Get("sid").IsNumber()) {
|
||||
Napi::TypeError::New(env, "The object['sid'] should be a number")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!obj.Has("speed")) {
|
||||
Napi::TypeError::New(env, "The argument object should have a field speed")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!obj.Get("speed").IsNumber()) {
|
||||
Napi::TypeError::New(env, "The object['speed'] should be a number")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
bool enable_external_buffer = true;
|
||||
if (obj.Has("enableExternalBuffer") &&
|
||||
obj.Get("enableExternalBuffer").IsBoolean()) {
|
||||
enable_external_buffer =
|
||||
obj.Get("enableExternalBuffer").As<Napi::Boolean>().Value();
|
||||
}
|
||||
|
||||
Napi::String _text = obj.Get("text").As<Napi::String>();
|
||||
std::string text = _text.Utf8Value();
|
||||
int32_t sid = obj.Get("sid").As<Napi::Number>().Int32Value();
|
||||
float speed = obj.Get("speed").As<Napi::Number>().FloatValue();
|
||||
|
||||
const SherpaOnnxGeneratedAudio *audio =
|
||||
SherpaOnnxOfflineTtsGenerate(tts, text.c_str(), sid, speed);
|
||||
|
||||
if (enable_external_buffer) {
|
||||
Napi::ArrayBuffer arrayBuffer = Napi::ArrayBuffer::New(
|
||||
env, const_cast<float *>(audio->samples), sizeof(float) * audio->n,
|
||||
[](Napi::Env /*env*/, void * /*data*/,
|
||||
const SherpaOnnxGeneratedAudio *hint) {
|
||||
SherpaOnnxDestroyOfflineTtsGeneratedAudio(hint);
|
||||
},
|
||||
audio);
|
||||
Napi::Float32Array float32Array =
|
||||
Napi::Float32Array::New(env, audio->n, arrayBuffer, 0);
|
||||
|
||||
Napi::Object ans = Napi::Object::New(env);
|
||||
ans.Set(Napi::String::New(env, "samples"), float32Array);
|
||||
ans.Set(Napi::String::New(env, "sampleRate"), audio->sample_rate);
|
||||
return ans;
|
||||
} else {
|
||||
// don't use external buffer
|
||||
Napi::ArrayBuffer arrayBuffer =
|
||||
Napi::ArrayBuffer::New(env, sizeof(float) * audio->n);
|
||||
|
||||
Napi::Float32Array float32Array =
|
||||
Napi::Float32Array::New(env, audio->n, arrayBuffer, 0);
|
||||
|
||||
std::copy(audio->samples, audio->samples + audio->n, float32Array.Data());
|
||||
|
||||
Napi::Object ans = Napi::Object::New(env);
|
||||
ans.Set(Napi::String::New(env, "samples"), float32Array);
|
||||
ans.Set(Napi::String::New(env, "sampleRate"), audio->sample_rate);
|
||||
SherpaOnnxDestroyOfflineTtsGeneratedAudio(audio);
|
||||
return ans;
|
||||
}
|
||||
}
|
||||
|
||||
void InitNonStreamingTts(Napi::Env env, Napi::Object exports) {
|
||||
exports.Set(Napi::String::New(env, "createOfflineTts"),
|
||||
Napi::Function::New(env, CreateOfflineTtsWrapper));
|
||||
|
||||
exports.Set(Napi::String::New(env, "getOfflineTtsSampleRate"),
|
||||
Napi::Function::New(env, OfflineTtsSampleRateWrapper));
|
||||
|
||||
exports.Set(Napi::String::New(env, "getOfflineTtsNumSpeakers"),
|
||||
Napi::Function::New(env, OfflineTtsNumSpeakersWrapper));
|
||||
|
||||
exports.Set(Napi::String::New(env, "offlineTtsGenerate"),
|
||||
Napi::Function::New(env, OfflineTtsGenerateWrapper));
|
||||
}
|
||||
135
harmony-os/SherpaOnnxHar/sherpa_onnx/src/main/cpp/punctuation.cc
Normal file
135
harmony-os/SherpaOnnxHar/sherpa_onnx/src/main/cpp/punctuation.cc
Normal file
@@ -0,0 +1,135 @@
|
||||
// scripts/node-addon-api/src/punctuation.cc
|
||||
//
|
||||
// Copyright (c) 2024 Xiaomi Corporation
|
||||
#include <sstream>
|
||||
|
||||
#include "macros.h" // NOLINT
|
||||
#include "napi.h" // NOLINT
|
||||
#include "sherpa-onnx/c-api/c-api.h"
|
||||
|
||||
static SherpaOnnxOfflinePunctuationModelConfig GetOfflinePunctuationModelConfig(
|
||||
Napi::Object obj) {
|
||||
SherpaOnnxOfflinePunctuationModelConfig c;
|
||||
memset(&c, 0, sizeof(c));
|
||||
|
||||
if (!obj.Has("model") || !obj.Get("model").IsObject()) {
|
||||
return c;
|
||||
}
|
||||
|
||||
Napi::Object o = obj.Get("model").As<Napi::Object>();
|
||||
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(ct_transformer, ctTransformer);
|
||||
|
||||
SHERPA_ONNX_ASSIGN_ATTR_INT32(num_threads, numThreads);
|
||||
|
||||
if (o.Has("debug") &&
|
||||
(o.Get("debug").IsNumber() || o.Get("debug").IsBoolean())) {
|
||||
if (o.Get("debug").IsBoolean()) {
|
||||
c.debug = o.Get("debug").As<Napi::Boolean>().Value();
|
||||
} else {
|
||||
c.debug = o.Get("debug").As<Napi::Number>().Int32Value();
|
||||
}
|
||||
}
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(provider, provider);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
static Napi::External<SherpaOnnxOfflinePunctuation>
|
||||
CreateOfflinePunctuationWrapper(const Napi::CallbackInfo &info) {
|
||||
Napi::Env env = info.Env();
|
||||
if (info.Length() != 1) {
|
||||
std::ostringstream os;
|
||||
os << "Expect only 1 argument. Given: " << info.Length();
|
||||
|
||||
Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!info[0].IsObject()) {
|
||||
Napi::TypeError::New(env, "You should pass an object as the only argument.")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
Napi::Object o = info[0].As<Napi::Object>();
|
||||
|
||||
SherpaOnnxOfflinePunctuationConfig c;
|
||||
memset(&c, 0, sizeof(c));
|
||||
c.model = GetOfflinePunctuationModelConfig(o);
|
||||
|
||||
const SherpaOnnxOfflinePunctuation *punct =
|
||||
SherpaOnnxCreateOfflinePunctuation(&c);
|
||||
|
||||
if (c.model.ct_transformer) {
|
||||
delete[] c.model.ct_transformer;
|
||||
}
|
||||
|
||||
if (c.model.provider) {
|
||||
delete[] c.model.provider;
|
||||
}
|
||||
|
||||
if (!punct) {
|
||||
Napi::TypeError::New(env, "Please check your config!")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
return Napi::External<SherpaOnnxOfflinePunctuation>::New(
|
||||
env, const_cast<SherpaOnnxOfflinePunctuation *>(punct),
|
||||
[](Napi::Env env, SherpaOnnxOfflinePunctuation *punct) {
|
||||
SherpaOnnxDestroyOfflinePunctuation(punct);
|
||||
});
|
||||
}
|
||||
|
||||
static Napi::String OfflinePunctuationAddPunctWraper(
|
||||
const Napi::CallbackInfo &info) {
|
||||
Napi::Env env = info.Env();
|
||||
if (info.Length() != 2) {
|
||||
std::ostringstream os;
|
||||
os << "Expect only 2 arguments. Given: " << info.Length();
|
||||
|
||||
Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!info[0].IsExternal()) {
|
||||
Napi::TypeError::New(
|
||||
env,
|
||||
"You should pass an offline punctuation pointer as the first argument")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!info[1].IsString()) {
|
||||
Napi::TypeError::New(env, "You should pass a string as the second argument")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
SherpaOnnxOfflinePunctuation *punct =
|
||||
info[0].As<Napi::External<SherpaOnnxOfflinePunctuation>>().Data();
|
||||
Napi::String js_text = info[1].As<Napi::String>();
|
||||
std::string text = js_text.Utf8Value();
|
||||
|
||||
const char *punct_text =
|
||||
SherpaOfflinePunctuationAddPunct(punct, text.c_str());
|
||||
|
||||
Napi::String ans = Napi::String::New(env, punct_text);
|
||||
SherpaOfflinePunctuationFreeText(punct_text);
|
||||
return ans;
|
||||
}
|
||||
|
||||
void InitPunctuation(Napi::Env env, Napi::Object exports) {
|
||||
exports.Set(Napi::String::New(env, "createOfflinePunctuation"),
|
||||
Napi::Function::New(env, CreateOfflinePunctuationWrapper));
|
||||
|
||||
exports.Set(Napi::String::New(env, "offlinePunctuationAddPunct"),
|
||||
Napi::Function::New(env, OfflinePunctuationAddPunctWraper));
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
// scripts/node-addon-api/src/sherpa-onnx-node-addon-api.cc
|
||||
//
|
||||
// Copyright (c) 2024 Xiaomi Corporation
|
||||
#include "napi.h" // NOLINT
|
||||
|
||||
void InitStreamingAsr(Napi::Env env, Napi::Object exports);
|
||||
|
||||
void InitNonStreamingAsr(Napi::Env env, Napi::Object exports);
|
||||
|
||||
void InitNonStreamingTts(Napi::Env env, Napi::Object exports);
|
||||
|
||||
void InitVad(Napi::Env env, Napi::Object exports);
|
||||
|
||||
void InitWaveReader(Napi::Env env, Napi::Object exports);
|
||||
|
||||
void InitWaveWriter(Napi::Env env, Napi::Object exports);
|
||||
|
||||
void InitSpokenLanguageID(Napi::Env env, Napi::Object exports);
|
||||
|
||||
void InitSpeakerID(Napi::Env env, Napi::Object exports);
|
||||
|
||||
void InitAudioTagging(Napi::Env env, Napi::Object exports);
|
||||
|
||||
void InitPunctuation(Napi::Env env, Napi::Object exports);
|
||||
|
||||
void InitKeywordSpotting(Napi::Env env, Napi::Object exports);
|
||||
|
||||
void InitNonStreamingSpeakerDiarization(Napi::Env env, Napi::Object exports);
|
||||
|
||||
Napi::Object Init(Napi::Env env, Napi::Object exports) {
|
||||
InitStreamingAsr(env, exports);
|
||||
InitNonStreamingAsr(env, exports);
|
||||
InitNonStreamingTts(env, exports);
|
||||
InitVad(env, exports);
|
||||
InitWaveReader(env, exports);
|
||||
InitWaveWriter(env, exports);
|
||||
InitSpokenLanguageID(env, exports);
|
||||
InitSpeakerID(env, exports);
|
||||
InitAudioTagging(env, exports);
|
||||
InitPunctuation(env, exports);
|
||||
InitKeywordSpotting(env, exports);
|
||||
InitNonStreamingSpeakerDiarization(env, exports);
|
||||
|
||||
return exports;
|
||||
}
|
||||
|
||||
NODE_API_MODULE(addon, Init)
|
||||
@@ -0,0 +1,808 @@
|
||||
// scripts/node-addon-api/src/speaker-identification.cc
|
||||
//
|
||||
// Copyright (c) 2024 Xiaomi Corporation
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
|
||||
#include "macros.h" // NOLINT
|
||||
#include "napi.h" // NOLINT
|
||||
#include "sherpa-onnx/c-api/c-api.h"
|
||||
|
||||
static Napi::External<SherpaOnnxSpeakerEmbeddingExtractor>
|
||||
CreateSpeakerEmbeddingExtractorWrapper(const Napi::CallbackInfo &info) {
|
||||
Napi::Env env = info.Env();
|
||||
if (info.Length() != 1) {
|
||||
std::ostringstream os;
|
||||
os << "Expect only 1 argument. Given: " << info.Length();
|
||||
|
||||
Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!info[0].IsObject()) {
|
||||
Napi::TypeError::New(env, "You should pass an object as the only argument.")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
Napi::Object o = info[0].As<Napi::Object>();
|
||||
|
||||
SherpaOnnxSpeakerEmbeddingExtractorConfig c;
|
||||
memset(&c, 0, sizeof(c));
|
||||
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(model, model);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_INT32(num_threads, numThreads);
|
||||
|
||||
if (o.Has("debug") &&
|
||||
(o.Get("debug").IsNumber() || o.Get("debug").IsBoolean())) {
|
||||
if (o.Get("debug").IsBoolean()) {
|
||||
c.debug = o.Get("debug").As<Napi::Boolean>().Value();
|
||||
} else {
|
||||
c.debug = o.Get("debug").As<Napi::Number>().Int32Value();
|
||||
}
|
||||
}
|
||||
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(provider, provider);
|
||||
|
||||
const SherpaOnnxSpeakerEmbeddingExtractor *extractor =
|
||||
SherpaOnnxCreateSpeakerEmbeddingExtractor(&c);
|
||||
|
||||
if (c.model) {
|
||||
delete[] c.model;
|
||||
}
|
||||
|
||||
if (c.provider) {
|
||||
delete[] c.provider;
|
||||
}
|
||||
|
||||
if (!extractor) {
|
||||
Napi::TypeError::New(env, "Please check your config!")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
return Napi::External<SherpaOnnxSpeakerEmbeddingExtractor>::New(
|
||||
env, const_cast<SherpaOnnxSpeakerEmbeddingExtractor *>(extractor),
|
||||
[](Napi::Env env, SherpaOnnxSpeakerEmbeddingExtractor *extractor) {
|
||||
SherpaOnnxDestroySpeakerEmbeddingExtractor(extractor);
|
||||
});
|
||||
}
|
||||
|
||||
static Napi::Number SpeakerEmbeddingExtractorDimWrapper(
|
||||
const Napi::CallbackInfo &info) {
|
||||
Napi::Env env = info.Env();
|
||||
|
||||
if (info.Length() != 1) {
|
||||
std::ostringstream os;
|
||||
os << "Expect only 1 argument. Given: " << info.Length();
|
||||
|
||||
Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!info[0].IsExternal()) {
|
||||
Napi::TypeError::New(
|
||||
env, "Argument 0 should be a speaker embedding extractor pointer.")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
SherpaOnnxSpeakerEmbeddingExtractor *extractor =
|
||||
info[0].As<Napi::External<SherpaOnnxSpeakerEmbeddingExtractor>>().Data();
|
||||
|
||||
int32_t dim = SherpaOnnxSpeakerEmbeddingExtractorDim(extractor);
|
||||
|
||||
return Napi::Number::New(env, dim);
|
||||
}
|
||||
|
||||
static Napi::External<SherpaOnnxOnlineStream>
|
||||
SpeakerEmbeddingExtractorCreateStreamWrapper(const Napi::CallbackInfo &info) {
|
||||
Napi::Env env = info.Env();
|
||||
if (info.Length() != 1) {
|
||||
std::ostringstream os;
|
||||
os << "Expect only 1 argument. Given: " << info.Length();
|
||||
|
||||
Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!info[0].IsExternal()) {
|
||||
Napi::TypeError::New(env,
|
||||
"You should pass a speaker embedding extractor "
|
||||
"pointer as the only argument")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
SherpaOnnxSpeakerEmbeddingExtractor *extractor =
|
||||
info[0].As<Napi::External<SherpaOnnxSpeakerEmbeddingExtractor>>().Data();
|
||||
|
||||
const SherpaOnnxOnlineStream *stream =
|
||||
SherpaOnnxSpeakerEmbeddingExtractorCreateStream(extractor);
|
||||
|
||||
return Napi::External<SherpaOnnxOnlineStream>::New(
|
||||
env, const_cast<SherpaOnnxOnlineStream *>(stream),
|
||||
[](Napi::Env env, SherpaOnnxOnlineStream *stream) {
|
||||
SherpaOnnxDestroyOnlineStream(stream);
|
||||
});
|
||||
}
|
||||
|
||||
static Napi::Boolean SpeakerEmbeddingExtractorIsReadyWrapper(
|
||||
const Napi::CallbackInfo &info) {
|
||||
Napi::Env env = info.Env();
|
||||
if (info.Length() != 2) {
|
||||
std::ostringstream os;
|
||||
os << "Expect only 2 arguments. Given: " << info.Length();
|
||||
|
||||
Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!info[0].IsExternal()) {
|
||||
Napi::TypeError::New(
|
||||
env, "Argument 0 should be a speaker embedding extractor pointer.")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!info[1].IsExternal()) {
|
||||
Napi::TypeError::New(env, "Argument 1 should be an online stream pointer.")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
SherpaOnnxSpeakerEmbeddingExtractor *extractor =
|
||||
info[0].As<Napi::External<SherpaOnnxSpeakerEmbeddingExtractor>>().Data();
|
||||
|
||||
SherpaOnnxOnlineStream *stream =
|
||||
info[1].As<Napi::External<SherpaOnnxOnlineStream>>().Data();
|
||||
|
||||
int32_t is_ready =
|
||||
SherpaOnnxSpeakerEmbeddingExtractorIsReady(extractor, stream);
|
||||
|
||||
return Napi::Boolean::New(env, is_ready);
|
||||
}
|
||||
|
||||
static Napi::Float32Array SpeakerEmbeddingExtractorComputeEmbeddingWrapper(
|
||||
const Napi::CallbackInfo &info) {
|
||||
Napi::Env env = info.Env();
|
||||
if (info.Length() != 2 && info.Length() != 3) {
|
||||
std::ostringstream os;
|
||||
os << "Expect only 2 or 3 arguments. Given: " << info.Length();
|
||||
|
||||
Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!info[0].IsExternal()) {
|
||||
Napi::TypeError::New(
|
||||
env, "Argument 0 should be a speaker embedding extractor pointer.")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!info[1].IsExternal()) {
|
||||
Napi::TypeError::New(env, "Argument 1 should be an online stream pointer.")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
bool enable_external_buffer = true;
|
||||
if (info.Length() == 3) {
|
||||
if (info[2].IsBoolean()) {
|
||||
enable_external_buffer = info[2].As<Napi::Boolean>().Value();
|
||||
} else {
|
||||
Napi::TypeError::New(env, "Argument 2 should be a boolean.")
|
||||
.ThrowAsJavaScriptException();
|
||||
}
|
||||
}
|
||||
|
||||
SherpaOnnxSpeakerEmbeddingExtractor *extractor =
|
||||
info[0].As<Napi::External<SherpaOnnxSpeakerEmbeddingExtractor>>().Data();
|
||||
|
||||
SherpaOnnxOnlineStream *stream =
|
||||
info[1].As<Napi::External<SherpaOnnxOnlineStream>>().Data();
|
||||
|
||||
const float *v =
|
||||
SherpaOnnxSpeakerEmbeddingExtractorComputeEmbedding(extractor, stream);
|
||||
|
||||
int32_t dim = SherpaOnnxSpeakerEmbeddingExtractorDim(extractor);
|
||||
|
||||
if (enable_external_buffer) {
|
||||
Napi::ArrayBuffer arrayBuffer = Napi::ArrayBuffer::New(
|
||||
env, const_cast<float *>(v), sizeof(float) * dim,
|
||||
[](Napi::Env /*env*/, void *data) {
|
||||
SherpaOnnxSpeakerEmbeddingExtractorDestroyEmbedding(
|
||||
reinterpret_cast<float *>(data));
|
||||
});
|
||||
|
||||
return Napi::Float32Array::New(env, dim, arrayBuffer, 0);
|
||||
} else {
|
||||
// don't use external buffer
|
||||
Napi::ArrayBuffer arrayBuffer =
|
||||
Napi::ArrayBuffer::New(env, sizeof(float) * dim);
|
||||
|
||||
Napi::Float32Array float32Array =
|
||||
Napi::Float32Array::New(env, dim, arrayBuffer, 0);
|
||||
|
||||
std::copy(v, v + dim, float32Array.Data());
|
||||
|
||||
SherpaOnnxSpeakerEmbeddingExtractorDestroyEmbedding(v);
|
||||
|
||||
return float32Array;
|
||||
}
|
||||
}
|
||||
|
||||
static Napi::External<SherpaOnnxSpeakerEmbeddingManager>
|
||||
CreateSpeakerEmbeddingManagerWrapper(const Napi::CallbackInfo &info) {
|
||||
Napi::Env env = info.Env();
|
||||
if (info.Length() != 1) {
|
||||
std::ostringstream os;
|
||||
os << "Expect only 1 argument. Given: " << info.Length();
|
||||
|
||||
Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!info[0].IsNumber()) {
|
||||
Napi::TypeError::New(env,
|
||||
"You should pass an integer as the only argument.")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
int32_t dim = info[0].As<Napi::Number>().Int32Value();
|
||||
|
||||
const SherpaOnnxSpeakerEmbeddingManager *manager =
|
||||
SherpaOnnxCreateSpeakerEmbeddingManager(dim);
|
||||
|
||||
if (!manager) {
|
||||
Napi::TypeError::New(env, "Please check your input dim!")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
return Napi::External<SherpaOnnxSpeakerEmbeddingManager>::New(
|
||||
env, const_cast<SherpaOnnxSpeakerEmbeddingManager *>(manager),
|
||||
[](Napi::Env env, SherpaOnnxSpeakerEmbeddingManager *manager) {
|
||||
SherpaOnnxDestroySpeakerEmbeddingManager(manager);
|
||||
});
|
||||
}
|
||||
|
||||
static Napi::Boolean SpeakerEmbeddingManagerAddWrapper(
|
||||
const Napi::CallbackInfo &info) {
|
||||
Napi::Env env = info.Env();
|
||||
if (info.Length() != 2) {
|
||||
std::ostringstream os;
|
||||
os << "Expect only 2 arguments. Given: " << info.Length();
|
||||
|
||||
Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!info[0].IsExternal()) {
|
||||
Napi::TypeError::New(env,
|
||||
"You should pass a speaker embedding manager pointer "
|
||||
"as the first argument.")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!info[1].IsObject()) {
|
||||
Napi::TypeError::New(env, "Argument 1 should be an object")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
SherpaOnnxSpeakerEmbeddingManager *manager =
|
||||
info[0].As<Napi::External<SherpaOnnxSpeakerEmbeddingManager>>().Data();
|
||||
|
||||
Napi::Object obj = info[1].As<Napi::Object>();
|
||||
|
||||
if (!obj.Has("v")) {
|
||||
Napi::TypeError::New(env, "The argument object should have a field v")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!obj.Get("v").IsTypedArray()) {
|
||||
Napi::TypeError::New(env, "The object['v'] should be a typed array")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!obj.Has("name")) {
|
||||
Napi::TypeError::New(env, "The argument object should have a field name")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!obj.Get("name").IsString()) {
|
||||
Napi::TypeError::New(env, "The object['name'] should be a string")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
Napi::Float32Array v = obj.Get("v").As<Napi::Float32Array>();
|
||||
Napi::String js_name = obj.Get("name").As<Napi::String>();
|
||||
std::string name = js_name.Utf8Value();
|
||||
|
||||
int32_t ok =
|
||||
SherpaOnnxSpeakerEmbeddingManagerAdd(manager, name.c_str(), v.Data());
|
||||
return Napi::Boolean::New(env, ok);
|
||||
}
|
||||
|
||||
static Napi::Boolean SpeakerEmbeddingManagerAddListFlattenedWrapper(
|
||||
const Napi::CallbackInfo &info) {
|
||||
Napi::Env env = info.Env();
|
||||
if (info.Length() != 2) {
|
||||
std::ostringstream os;
|
||||
os << "Expect only 2 arguments. Given: " << info.Length();
|
||||
|
||||
Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!info[0].IsExternal()) {
|
||||
Napi::TypeError::New(env,
|
||||
"You should pass a speaker embedding manager pointer "
|
||||
"as the first argument.")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!info[1].IsObject()) {
|
||||
Napi::TypeError::New(env, "Argument 1 should be an object")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
SherpaOnnxSpeakerEmbeddingManager *manager =
|
||||
info[0].As<Napi::External<SherpaOnnxSpeakerEmbeddingManager>>().Data();
|
||||
|
||||
Napi::Object obj = info[1].As<Napi::Object>();
|
||||
|
||||
if (!obj.Has("vv")) {
|
||||
Napi::TypeError::New(env, "The argument object should have a field vv")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!obj.Get("vv").IsTypedArray()) {
|
||||
Napi::TypeError::New(env, "The object['vv'] should be a typed array")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!obj.Has("name")) {
|
||||
Napi::TypeError::New(env, "The argument object should have a field name")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!obj.Get("name").IsString()) {
|
||||
Napi::TypeError::New(env, "The object['name'] should be a string")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!obj.Has("n")) {
|
||||
Napi::TypeError::New(env, "The argument object should have a field n")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!obj.Get("n").IsNumber()) {
|
||||
Napi::TypeError::New(env, "The object['n'] should be an integer")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
Napi::Float32Array v = obj.Get("vv").As<Napi::Float32Array>();
|
||||
Napi::String js_name = obj.Get("name").As<Napi::String>();
|
||||
int32_t n = obj.Get("n").As<Napi::Number>().Int32Value();
|
||||
|
||||
std::string name = js_name.Utf8Value();
|
||||
|
||||
int32_t ok = SherpaOnnxSpeakerEmbeddingManagerAddListFlattened(
|
||||
manager, name.c_str(), v.Data(), n);
|
||||
|
||||
return Napi::Boolean::New(env, ok);
|
||||
}
|
||||
|
||||
static Napi::Boolean SpeakerEmbeddingManagerRemoveWrapper(
|
||||
const Napi::CallbackInfo &info) {
|
||||
Napi::Env env = info.Env();
|
||||
if (info.Length() != 2) {
|
||||
std::ostringstream os;
|
||||
os << "Expect only 2 arguments. Given: " << info.Length();
|
||||
|
||||
Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!info[0].IsExternal()) {
|
||||
Napi::TypeError::New(env,
|
||||
"You should pass a speaker embedding manager pointer "
|
||||
"as the first argument.")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!info[1].IsString()) {
|
||||
Napi::TypeError::New(env, "Argument 1 should be string")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
SherpaOnnxSpeakerEmbeddingManager *manager =
|
||||
info[0].As<Napi::External<SherpaOnnxSpeakerEmbeddingManager>>().Data();
|
||||
|
||||
Napi::String js_name = info[1].As<Napi::String>();
|
||||
std::string name = js_name.Utf8Value();
|
||||
|
||||
int32_t ok = SherpaOnnxSpeakerEmbeddingManagerRemove(manager, name.c_str());
|
||||
|
||||
return Napi::Boolean::New(env, ok);
|
||||
}
|
||||
|
||||
static Napi::String SpeakerEmbeddingManagerSearchWrapper(
|
||||
const Napi::CallbackInfo &info) {
|
||||
Napi::Env env = info.Env();
|
||||
if (info.Length() != 2) {
|
||||
std::ostringstream os;
|
||||
os << "Expect only 2 arguments. Given: " << info.Length();
|
||||
|
||||
Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!info[0].IsExternal()) {
|
||||
Napi::TypeError::New(env,
|
||||
"You should pass a speaker embedding manager pointer "
|
||||
"as the first argument.")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!info[1].IsObject()) {
|
||||
Napi::TypeError::New(env, "Argument 1 should be an object")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
SherpaOnnxSpeakerEmbeddingManager *manager =
|
||||
info[0].As<Napi::External<SherpaOnnxSpeakerEmbeddingManager>>().Data();
|
||||
|
||||
Napi::Object obj = info[1].As<Napi::Object>();
|
||||
|
||||
if (!obj.Has("v")) {
|
||||
Napi::TypeError::New(env, "The argument object should have a field v")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!obj.Get("v").IsTypedArray()) {
|
||||
Napi::TypeError::New(env, "The object['v'] should be a typed array")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!obj.Has("threshold")) {
|
||||
Napi::TypeError::New(env,
|
||||
"The argument object should have a field threshold")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!obj.Get("threshold").IsNumber()) {
|
||||
Napi::TypeError::New(env, "The object['threshold'] should be a float")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
Napi::Float32Array v = obj.Get("v").As<Napi::Float32Array>();
|
||||
float threshold = obj.Get("threshold").As<Napi::Number>().FloatValue();
|
||||
|
||||
const char *name =
|
||||
SherpaOnnxSpeakerEmbeddingManagerSearch(manager, v.Data(), threshold);
|
||||
const char *p = name;
|
||||
if (!p) {
|
||||
p = "";
|
||||
}
|
||||
|
||||
Napi::String js_name = Napi::String::New(env, p);
|
||||
SherpaOnnxSpeakerEmbeddingManagerFreeSearch(name);
|
||||
|
||||
return js_name;
|
||||
}
|
||||
|
||||
static Napi::Boolean SpeakerEmbeddingManagerVerifyWrapper(
|
||||
const Napi::CallbackInfo &info) {
|
||||
Napi::Env env = info.Env();
|
||||
if (info.Length() != 2) {
|
||||
std::ostringstream os;
|
||||
os << "Expect only 2 arguments. Given: " << info.Length();
|
||||
|
||||
Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!info[0].IsExternal()) {
|
||||
Napi::TypeError::New(env,
|
||||
"You should pass a speaker embedding manager pointer "
|
||||
"as the first argument.")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!info[1].IsObject()) {
|
||||
Napi::TypeError::New(env, "Argument 1 should be an object")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
SherpaOnnxSpeakerEmbeddingManager *manager =
|
||||
info[0].As<Napi::External<SherpaOnnxSpeakerEmbeddingManager>>().Data();
|
||||
|
||||
Napi::Object obj = info[1].As<Napi::Object>();
|
||||
|
||||
if (!obj.Has("v")) {
|
||||
Napi::TypeError::New(env, "The argument object should have a field v")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!obj.Get("v").IsTypedArray()) {
|
||||
Napi::TypeError::New(env, "The object['v'] should be a typed array")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!obj.Has("threshold")) {
|
||||
Napi::TypeError::New(env,
|
||||
"The argument object should have a field threshold")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!obj.Get("threshold").IsNumber()) {
|
||||
Napi::TypeError::New(env, "The object['threshold'] should be a float")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!obj.Has("name")) {
|
||||
Napi::TypeError::New(env, "The argument object should have a field name")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!obj.Get("name").IsString()) {
|
||||
Napi::TypeError::New(env, "The object['name'] should be a string")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
Napi::Float32Array v = obj.Get("v").As<Napi::Float32Array>();
|
||||
float threshold = obj.Get("threshold").As<Napi::Number>().FloatValue();
|
||||
|
||||
Napi::String js_name = obj.Get("name").As<Napi::String>();
|
||||
std::string name = js_name.Utf8Value();
|
||||
|
||||
int32_t found = SherpaOnnxSpeakerEmbeddingManagerVerify(manager, name.c_str(),
|
||||
v.Data(), threshold);
|
||||
|
||||
return Napi::Boolean::New(env, found);
|
||||
}
|
||||
|
||||
static Napi::Boolean SpeakerEmbeddingManagerContainsWrapper(
|
||||
const Napi::CallbackInfo &info) {
|
||||
Napi::Env env = info.Env();
|
||||
if (info.Length() != 2) {
|
||||
std::ostringstream os;
|
||||
os << "Expect only 2 arguments. Given: " << info.Length();
|
||||
|
||||
Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!info[0].IsExternal()) {
|
||||
Napi::TypeError::New(env,
|
||||
"You should pass a speaker embedding manager pointer "
|
||||
"as the first argument.")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!info[1].IsString()) {
|
||||
Napi::TypeError::New(env, "Argument 1 should be a string")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
SherpaOnnxSpeakerEmbeddingManager *manager =
|
||||
info[0].As<Napi::External<SherpaOnnxSpeakerEmbeddingManager>>().Data();
|
||||
|
||||
Napi::String js_name = info[1].As<Napi::String>();
|
||||
std::string name = js_name.Utf8Value();
|
||||
|
||||
int32_t exists =
|
||||
SherpaOnnxSpeakerEmbeddingManagerContains(manager, name.c_str());
|
||||
|
||||
return Napi::Boolean::New(env, exists);
|
||||
}
|
||||
|
||||
static Napi::Number SpeakerEmbeddingManagerNumSpeakersWrapper(
|
||||
const Napi::CallbackInfo &info) {
|
||||
Napi::Env env = info.Env();
|
||||
if (info.Length() != 1) {
|
||||
std::ostringstream os;
|
||||
os << "Expect only 1 argument. Given: " << info.Length();
|
||||
|
||||
Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!info[0].IsExternal()) {
|
||||
Napi::TypeError::New(env,
|
||||
"You should pass a speaker embedding manager pointer "
|
||||
"as the first argument.")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
SherpaOnnxSpeakerEmbeddingManager *manager =
|
||||
info[0].As<Napi::External<SherpaOnnxSpeakerEmbeddingManager>>().Data();
|
||||
|
||||
int32_t num_speakers = SherpaOnnxSpeakerEmbeddingManagerNumSpeakers(manager);
|
||||
|
||||
return Napi::Number::New(env, num_speakers);
|
||||
}
|
||||
|
||||
static Napi::Array SpeakerEmbeddingManagerGetAllSpeakersWrapper(
|
||||
const Napi::CallbackInfo &info) {
|
||||
Napi::Env env = info.Env();
|
||||
if (info.Length() != 1) {
|
||||
std::ostringstream os;
|
||||
os << "Expect only 1 argument. Given: " << info.Length();
|
||||
|
||||
Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!info[0].IsExternal()) {
|
||||
Napi::TypeError::New(env,
|
||||
"You should pass a speaker embedding manager pointer "
|
||||
"as the first argument.")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
SherpaOnnxSpeakerEmbeddingManager *manager =
|
||||
info[0].As<Napi::External<SherpaOnnxSpeakerEmbeddingManager>>().Data();
|
||||
|
||||
int32_t num_speakers = SherpaOnnxSpeakerEmbeddingManagerNumSpeakers(manager);
|
||||
if (num_speakers == 0) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const char *const *all_speaker_names =
|
||||
SherpaOnnxSpeakerEmbeddingManagerGetAllSpeakers(manager);
|
||||
|
||||
Napi::Array ans = Napi::Array::New(env, num_speakers);
|
||||
for (uint32_t i = 0; i != num_speakers; ++i) {
|
||||
ans[i] = Napi::String::New(env, all_speaker_names[i]);
|
||||
}
|
||||
SherpaOnnxSpeakerEmbeddingManagerFreeAllSpeakers(all_speaker_names);
|
||||
return ans;
|
||||
}
|
||||
|
||||
void InitSpeakerID(Napi::Env env, Napi::Object exports) {
|
||||
exports.Set(Napi::String::New(env, "createSpeakerEmbeddingExtractor"),
|
||||
Napi::Function::New(env, CreateSpeakerEmbeddingExtractorWrapper));
|
||||
|
||||
exports.Set(Napi::String::New(env, "speakerEmbeddingExtractorDim"),
|
||||
Napi::Function::New(env, SpeakerEmbeddingExtractorDimWrapper));
|
||||
|
||||
exports.Set(
|
||||
Napi::String::New(env, "speakerEmbeddingExtractorCreateStream"),
|
||||
Napi::Function::New(env, SpeakerEmbeddingExtractorCreateStreamWrapper));
|
||||
|
||||
exports.Set(
|
||||
Napi::String::New(env, "speakerEmbeddingExtractorIsReady"),
|
||||
Napi::Function::New(env, SpeakerEmbeddingExtractorIsReadyWrapper));
|
||||
|
||||
exports.Set(
|
||||
Napi::String::New(env, "speakerEmbeddingExtractorComputeEmbedding"),
|
||||
Napi::Function::New(env,
|
||||
SpeakerEmbeddingExtractorComputeEmbeddingWrapper));
|
||||
|
||||
exports.Set(Napi::String::New(env, "createSpeakerEmbeddingManager"),
|
||||
Napi::Function::New(env, CreateSpeakerEmbeddingManagerWrapper));
|
||||
|
||||
exports.Set(Napi::String::New(env, "speakerEmbeddingManagerAdd"),
|
||||
Napi::Function::New(env, SpeakerEmbeddingManagerAddWrapper));
|
||||
|
||||
exports.Set(
|
||||
Napi::String::New(env, "speakerEmbeddingManagerAddListFlattened"),
|
||||
Napi::Function::New(env, SpeakerEmbeddingManagerAddListFlattenedWrapper));
|
||||
|
||||
exports.Set(Napi::String::New(env, "speakerEmbeddingManagerRemove"),
|
||||
Napi::Function::New(env, SpeakerEmbeddingManagerRemoveWrapper));
|
||||
|
||||
exports.Set(Napi::String::New(env, "speakerEmbeddingManagerSearch"),
|
||||
Napi::Function::New(env, SpeakerEmbeddingManagerSearchWrapper));
|
||||
|
||||
exports.Set(Napi::String::New(env, "speakerEmbeddingManagerVerify"),
|
||||
Napi::Function::New(env, SpeakerEmbeddingManagerVerifyWrapper));
|
||||
|
||||
exports.Set(Napi::String::New(env, "speakerEmbeddingManagerContains"),
|
||||
Napi::Function::New(env, SpeakerEmbeddingManagerContainsWrapper));
|
||||
|
||||
exports.Set(
|
||||
Napi::String::New(env, "speakerEmbeddingManagerNumSpeakers"),
|
||||
Napi::Function::New(env, SpeakerEmbeddingManagerNumSpeakersWrapper));
|
||||
|
||||
exports.Set(
|
||||
Napi::String::New(env, "speakerEmbeddingManagerGetAllSpeakers"),
|
||||
Napi::Function::New(env, SpeakerEmbeddingManagerGetAllSpeakersWrapper));
|
||||
}
|
||||
@@ -0,0 +1,188 @@
|
||||
// scripts/node-addon-api/src/spoken-language-identification.cc
|
||||
//
|
||||
// Copyright (c) 2024 Xiaomi Corporation
|
||||
|
||||
#include <sstream>
|
||||
|
||||
#include "macros.h" // NOLINT
|
||||
#include "napi.h" // NOLINT
|
||||
#include "sherpa-onnx/c-api/c-api.h"
|
||||
|
||||
static SherpaOnnxSpokenLanguageIdentificationWhisperConfig
|
||||
GetSpokenLanguageIdentificationWhisperConfig(Napi::Object obj) {
|
||||
SherpaOnnxSpokenLanguageIdentificationWhisperConfig c;
|
||||
memset(&c, 0, sizeof(c));
|
||||
|
||||
if (!obj.Has("whisper") || !obj.Get("whisper").IsObject()) {
|
||||
return c;
|
||||
}
|
||||
|
||||
Napi::Object o = obj.Get("whisper").As<Napi::Object>();
|
||||
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(encoder, encoder);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(decoder, decoder);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_INT32(tail_paddings, tailPaddings);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
static Napi::External<SherpaOnnxSpokenLanguageIdentification>
|
||||
CreateSpokenLanguageIdentificationWrapper(const Napi::CallbackInfo &info) {
|
||||
Napi::Env env = info.Env();
|
||||
if (info.Length() != 1) {
|
||||
std::ostringstream os;
|
||||
os << "Expect only 1 argument. Given: " << info.Length();
|
||||
|
||||
Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!info[0].IsObject()) {
|
||||
Napi::TypeError::New(env, "You should pass an object as the only argument.")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
Napi::Object o = info[0].As<Napi::Object>();
|
||||
|
||||
SherpaOnnxSpokenLanguageIdentificationConfig c;
|
||||
memset(&c, 0, sizeof(c));
|
||||
c.whisper = GetSpokenLanguageIdentificationWhisperConfig(o);
|
||||
|
||||
SHERPA_ONNX_ASSIGN_ATTR_INT32(num_threads, numThreads);
|
||||
|
||||
if (o.Has("debug") &&
|
||||
(o.Get("debug").IsNumber() || o.Get("debug").IsBoolean())) {
|
||||
if (o.Get("debug").IsBoolean()) {
|
||||
c.debug = o.Get("debug").As<Napi::Boolean>().Value();
|
||||
} else {
|
||||
c.debug = o.Get("debug").As<Napi::Number>().Int32Value();
|
||||
}
|
||||
}
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(provider, provider);
|
||||
|
||||
const SherpaOnnxSpokenLanguageIdentification *slid =
|
||||
SherpaOnnxCreateSpokenLanguageIdentification(&c);
|
||||
|
||||
if (c.whisper.encoder) {
|
||||
delete[] c.whisper.encoder;
|
||||
}
|
||||
|
||||
if (c.whisper.decoder) {
|
||||
delete[] c.whisper.decoder;
|
||||
}
|
||||
|
||||
if (c.provider) {
|
||||
delete[] c.provider;
|
||||
}
|
||||
|
||||
if (!slid) {
|
||||
Napi::TypeError::New(env, "Please check your config!")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
return Napi::External<SherpaOnnxSpokenLanguageIdentification>::New(
|
||||
env, const_cast<SherpaOnnxSpokenLanguageIdentification *>(slid),
|
||||
[](Napi::Env env, SherpaOnnxSpokenLanguageIdentification *slid) {
|
||||
SherpaOnnxDestroySpokenLanguageIdentification(slid);
|
||||
});
|
||||
}
|
||||
|
||||
static Napi::External<SherpaOnnxOfflineStream>
|
||||
SpokenLanguageIdentificationCreateOfflineStreamWrapper(
|
||||
const Napi::CallbackInfo &info) {
|
||||
Napi::Env env = info.Env();
|
||||
if (info.Length() != 1) {
|
||||
std::ostringstream os;
|
||||
os << "Expect only 1 argument. Given: " << info.Length();
|
||||
|
||||
Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!info[0].IsExternal()) {
|
||||
Napi::TypeError::New(
|
||||
env,
|
||||
"You should pass an offline language ID pointer as the only argument")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
SherpaOnnxSpokenLanguageIdentification *slid =
|
||||
info[0]
|
||||
.As<Napi::External<SherpaOnnxSpokenLanguageIdentification>>()
|
||||
.Data();
|
||||
|
||||
SherpaOnnxOfflineStream *stream =
|
||||
SherpaOnnxSpokenLanguageIdentificationCreateOfflineStream(slid);
|
||||
|
||||
return Napi::External<SherpaOnnxOfflineStream>::New(
|
||||
env, stream, [](Napi::Env env, SherpaOnnxOfflineStream *stream) {
|
||||
SherpaOnnxDestroyOfflineStream(stream);
|
||||
});
|
||||
}
|
||||
|
||||
static Napi::String SpokenLanguageIdentificationComputeWrapper(
|
||||
const Napi::CallbackInfo &info) {
|
||||
Napi::Env env = info.Env();
|
||||
if (info.Length() != 2) {
|
||||
std::ostringstream os;
|
||||
os << "Expect only 2 arguments. Given: " << info.Length();
|
||||
|
||||
Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!info[0].IsExternal()) {
|
||||
Napi::TypeError::New(
|
||||
env, "Argument 0 should be an offline spoken language ID pointer.")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!info[1].IsExternal()) {
|
||||
Napi::TypeError::New(env, "Argument 1 should be an offline stream pointer.")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
SherpaOnnxSpokenLanguageIdentification *slid =
|
||||
info[0]
|
||||
.As<Napi::External<SherpaOnnxSpokenLanguageIdentification>>()
|
||||
.Data();
|
||||
|
||||
SherpaOnnxOfflineStream *stream =
|
||||
info[1].As<Napi::External<SherpaOnnxOfflineStream>>().Data();
|
||||
|
||||
const SherpaOnnxSpokenLanguageIdentificationResult *r =
|
||||
SherpaOnnxSpokenLanguageIdentificationCompute(slid, stream);
|
||||
|
||||
std::string lang = r->lang;
|
||||
SherpaOnnxDestroySpokenLanguageIdentificationResult(r);
|
||||
|
||||
return Napi::String::New(env, lang);
|
||||
}
|
||||
|
||||
void InitSpokenLanguageID(Napi::Env env, Napi::Object exports) {
|
||||
exports.Set(
|
||||
Napi::String::New(env, "createSpokenLanguageIdentification"),
|
||||
Napi::Function::New(env, CreateSpokenLanguageIdentificationWrapper));
|
||||
|
||||
exports.Set(
|
||||
Napi::String::New(env, "createSpokenLanguageIdentificationOfflineStream"),
|
||||
Napi::Function::New(
|
||||
env, SpokenLanguageIdentificationCreateOfflineStreamWrapper));
|
||||
|
||||
exports.Set(
|
||||
Napi::String::New(env, "spokenLanguageIdentificationCompute"),
|
||||
Napi::Function::New(env, SpokenLanguageIdentificationComputeWrapper));
|
||||
}
|
||||
@@ -0,0 +1,731 @@
|
||||
// scripts/node-addon-api/src/streaming-asr.cc
|
||||
//
|
||||
// Copyright (c) 2024 Xiaomi Corporation
|
||||
#include <sstream>
|
||||
|
||||
#include "macros.h" // NOLINT
|
||||
#include "napi.h" // NOLINT
|
||||
#include "sherpa-onnx/c-api/c-api.h"
|
||||
/*
|
||||
{
|
||||
'featConfig': {
|
||||
'sampleRate': 16000,
|
||||
'featureDim': 80,
|
||||
}
|
||||
};
|
||||
*/
|
||||
SherpaOnnxFeatureConfig GetFeatureConfig(Napi::Object obj) {
|
||||
SherpaOnnxFeatureConfig c;
|
||||
memset(&c, 0, sizeof(c));
|
||||
|
||||
if (!obj.Has("featConfig") || !obj.Get("featConfig").IsObject()) {
|
||||
return c;
|
||||
}
|
||||
|
||||
Napi::Object o = obj.Get("featConfig").As<Napi::Object>();
|
||||
|
||||
SHERPA_ONNX_ASSIGN_ATTR_INT32(sample_rate, sampleRate);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_INT32(feature_dim, featureDim);
|
||||
|
||||
return c;
|
||||
}
|
||||
/*
|
||||
{
|
||||
'transducer': {
|
||||
'encoder': './encoder.onnx',
|
||||
'decoder': './decoder.onnx',
|
||||
'joiner': './joiner.onnx',
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
static SherpaOnnxOnlineTransducerModelConfig GetOnlineTransducerModelConfig(
|
||||
Napi::Object obj) {
|
||||
SherpaOnnxOnlineTransducerModelConfig c;
|
||||
memset(&c, 0, sizeof(c));
|
||||
|
||||
if (!obj.Has("transducer") || !obj.Get("transducer").IsObject()) {
|
||||
return c;
|
||||
}
|
||||
|
||||
Napi::Object o = obj.Get("transducer").As<Napi::Object>();
|
||||
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(encoder, encoder);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(decoder, decoder);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(joiner, joiner);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
static SherpaOnnxOnlineZipformer2CtcModelConfig
|
||||
GetOnlineZipformer2CtcModelConfig(Napi::Object obj) {
|
||||
SherpaOnnxOnlineZipformer2CtcModelConfig c;
|
||||
memset(&c, 0, sizeof(c));
|
||||
|
||||
if (!obj.Has("zipformer2Ctc") || !obj.Get("zipformer2Ctc").IsObject()) {
|
||||
return c;
|
||||
}
|
||||
|
||||
Napi::Object o = obj.Get("zipformer2Ctc").As<Napi::Object>();
|
||||
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(model, model);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
static SherpaOnnxOnlineParaformerModelConfig GetOnlineParaformerModelConfig(
|
||||
Napi::Object obj) {
|
||||
SherpaOnnxOnlineParaformerModelConfig c;
|
||||
memset(&c, 0, sizeof(c));
|
||||
|
||||
if (!obj.Has("paraformer") || !obj.Get("paraformer").IsObject()) {
|
||||
return c;
|
||||
}
|
||||
|
||||
Napi::Object o = obj.Get("paraformer").As<Napi::Object>();
|
||||
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(encoder, encoder);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(decoder, decoder);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
SherpaOnnxOnlineModelConfig GetOnlineModelConfig(Napi::Object obj) {
|
||||
SherpaOnnxOnlineModelConfig c;
|
||||
memset(&c, 0, sizeof(c));
|
||||
|
||||
if (!obj.Has("modelConfig") || !obj.Get("modelConfig").IsObject()) {
|
||||
return c;
|
||||
}
|
||||
|
||||
Napi::Object o = obj.Get("modelConfig").As<Napi::Object>();
|
||||
|
||||
c.transducer = GetOnlineTransducerModelConfig(o);
|
||||
c.paraformer = GetOnlineParaformerModelConfig(o);
|
||||
c.zipformer2_ctc = GetOnlineZipformer2CtcModelConfig(o);
|
||||
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(tokens, tokens);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_INT32(num_threads, numThreads);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(provider, provider);
|
||||
|
||||
if (o.Has("debug") &&
|
||||
(o.Get("debug").IsNumber() || o.Get("debug").IsBoolean())) {
|
||||
if (o.Get("debug").IsBoolean()) {
|
||||
c.debug = o.Get("debug").As<Napi::Boolean>().Value();
|
||||
} else {
|
||||
c.debug = o.Get("debug").As<Napi::Number>().Int32Value();
|
||||
}
|
||||
}
|
||||
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(model_type, modelType);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(modeling_unit, modelingUnit);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(bpe_vocab, bpeVocab);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(tokens_buf, tokensBuf);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_INT32(tokens_buf_size, tokensBufSize);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
static SherpaOnnxOnlineCtcFstDecoderConfig GetCtcFstDecoderConfig(
|
||||
Napi::Object obj) {
|
||||
SherpaOnnxOnlineCtcFstDecoderConfig c;
|
||||
memset(&c, 0, sizeof(c));
|
||||
|
||||
if (!obj.Has("ctcFstDecoderConfig") ||
|
||||
!obj.Get("ctcFstDecoderConfig").IsObject()) {
|
||||
return c;
|
||||
}
|
||||
|
||||
Napi::Object o = obj.Get("ctcFstDecoderConfig").As<Napi::Object>();
|
||||
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(graph, graph);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_INT32(max_active, maxActive);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
static Napi::External<SherpaOnnxOnlineRecognizer> CreateOnlineRecognizerWrapper(
|
||||
const Napi::CallbackInfo &info) {
|
||||
Napi::Env env = info.Env();
|
||||
#if __OHOS__
|
||||
if (info.Length() != 2) {
|
||||
std::ostringstream os;
|
||||
os << "Expect only 2 arguments. Given: " << info.Length();
|
||||
|
||||
Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
#else
|
||||
if (info.Length() != 1) {
|
||||
std::ostringstream os;
|
||||
os << "Expect only 1 argument. Given: " << info.Length();
|
||||
|
||||
Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!info[0].IsObject()) {
|
||||
Napi::TypeError::New(env, "Expect an object as the argument")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
Napi::Object o = info[0].As<Napi::Object>();
|
||||
SherpaOnnxOnlineRecognizerConfig c;
|
||||
memset(&c, 0, sizeof(c));
|
||||
c.feat_config = GetFeatureConfig(o);
|
||||
c.model_config = GetOnlineModelConfig(o);
|
||||
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(decoding_method, decodingMethod);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_INT32(max_active_paths, maxActivePaths);
|
||||
|
||||
// enableEndpoint can be either a boolean or an integer
|
||||
if (o.Has("enableEndpoint") && (o.Get("enableEndpoint").IsNumber() ||
|
||||
o.Get("enableEndpoint").IsBoolean())) {
|
||||
if (o.Get("enableEndpoint").IsNumber()) {
|
||||
c.enable_endpoint =
|
||||
o.Get("enableEndpoint").As<Napi::Number>().Int32Value();
|
||||
} else {
|
||||
c.enable_endpoint = o.Get("enableEndpoint").As<Napi::Boolean>().Value();
|
||||
}
|
||||
}
|
||||
|
||||
SHERPA_ONNX_ASSIGN_ATTR_FLOAT(rule1_min_trailing_silence,
|
||||
rule1MinTrailingSilence);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_FLOAT(rule2_min_trailing_silence,
|
||||
rule2MinTrailingSilence);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_FLOAT(rule3_min_utterance_length,
|
||||
rule3MinUtteranceLength);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(hotwords_file, hotwordsFile);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_FLOAT(hotwords_score, hotwordsScore);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(rule_fsts, ruleFsts);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(rule_fars, ruleFars);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_FLOAT(blank_penalty, blankPenalty);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(hotwords_buf, hotwordsBuf);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_INT32(hotwords_buf_size, hotwordsBufSize);
|
||||
|
||||
c.ctc_fst_decoder_config = GetCtcFstDecoderConfig(o);
|
||||
|
||||
#if __OHOS__
|
||||
std::unique_ptr<NativeResourceManager, decltype(&OH_ResourceManager_ReleaseNativeResourceManager)> mgr (OH_ResourceManager_InitNativeResourceManager(env, info[1]), &OH_ResourceManager_ReleaseNativeResourceManager);
|
||||
|
||||
const SherpaOnnxOnlineRecognizer *recognizer =
|
||||
SherpaOnnxCreateOnlineRecognizerOHOS(&c, mgr.get());
|
||||
#else
|
||||
const SherpaOnnxOnlineRecognizer *recognizer =
|
||||
SherpaOnnxCreateOnlineRecognizer(&c);
|
||||
#endif
|
||||
|
||||
if (c.model_config.transducer.encoder) {
|
||||
delete[] c.model_config.transducer.encoder;
|
||||
}
|
||||
|
||||
if (c.model_config.transducer.decoder) {
|
||||
delete[] c.model_config.transducer.decoder;
|
||||
}
|
||||
|
||||
if (c.model_config.transducer.joiner) {
|
||||
delete[] c.model_config.transducer.joiner;
|
||||
}
|
||||
|
||||
if (c.model_config.paraformer.encoder) {
|
||||
delete[] c.model_config.paraformer.encoder;
|
||||
}
|
||||
|
||||
if (c.model_config.paraformer.decoder) {
|
||||
delete[] c.model_config.paraformer.decoder;
|
||||
}
|
||||
|
||||
if (c.model_config.zipformer2_ctc.model) {
|
||||
delete[] c.model_config.zipformer2_ctc.model;
|
||||
}
|
||||
|
||||
if (c.model_config.tokens) {
|
||||
delete[] c.model_config.tokens;
|
||||
}
|
||||
|
||||
if (c.model_config.provider) {
|
||||
delete[] c.model_config.provider;
|
||||
}
|
||||
|
||||
if (c.model_config.model_type) {
|
||||
delete[] c.model_config.model_type;
|
||||
}
|
||||
|
||||
if (c.model_config.modeling_unit) {
|
||||
delete[] c.model_config.modeling_unit;
|
||||
}
|
||||
|
||||
if (c.model_config.bpe_vocab) {
|
||||
delete[] c.model_config.bpe_vocab;
|
||||
}
|
||||
|
||||
if (c.model_config.tokens_buf) {
|
||||
delete[] c.model_config.tokens_buf;
|
||||
}
|
||||
|
||||
if (c.decoding_method) {
|
||||
delete[] c.decoding_method;
|
||||
}
|
||||
|
||||
if (c.hotwords_file) {
|
||||
delete[] c.hotwords_file;
|
||||
}
|
||||
|
||||
if (c.rule_fsts) {
|
||||
delete[] c.rule_fsts;
|
||||
}
|
||||
|
||||
if (c.rule_fars) {
|
||||
delete[] c.rule_fars;
|
||||
}
|
||||
|
||||
if (c.hotwords_buf) {
|
||||
delete[] c.hotwords_buf;
|
||||
}
|
||||
|
||||
if (c.ctc_fst_decoder_config.graph) {
|
||||
delete[] c.ctc_fst_decoder_config.graph;
|
||||
}
|
||||
|
||||
if (!recognizer) {
|
||||
Napi::TypeError::New(env, "Please check your config!")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
return Napi::External<SherpaOnnxOnlineRecognizer>::New(
|
||||
env, const_cast<SherpaOnnxOnlineRecognizer *>(recognizer),
|
||||
[](Napi::Env env, SherpaOnnxOnlineRecognizer *recognizer) {
|
||||
SherpaOnnxDestroyOnlineRecognizer(recognizer);
|
||||
});
|
||||
}
|
||||
|
||||
static Napi::External<SherpaOnnxOnlineStream> CreateOnlineStreamWrapper(
|
||||
const Napi::CallbackInfo &info) {
|
||||
Napi::Env env = info.Env();
|
||||
if (info.Length() != 1) {
|
||||
std::ostringstream os;
|
||||
os << "Expect only 1 argument. Given: " << info.Length();
|
||||
|
||||
Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!info[0].IsExternal()) {
|
||||
Napi::TypeError::New(
|
||||
env,
|
||||
"You should pass an online recognizer pointer as the only argument")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
SherpaOnnxOnlineRecognizer *recognizer =
|
||||
info[0].As<Napi::External<SherpaOnnxOnlineRecognizer>>().Data();
|
||||
|
||||
const SherpaOnnxOnlineStream *stream =
|
||||
SherpaOnnxCreateOnlineStream(recognizer);
|
||||
|
||||
return Napi::External<SherpaOnnxOnlineStream>::New(
|
||||
env, const_cast<SherpaOnnxOnlineStream *>(stream),
|
||||
[](Napi::Env env, SherpaOnnxOnlineStream *stream) {
|
||||
SherpaOnnxDestroyOnlineStream(stream);
|
||||
});
|
||||
}
|
||||
|
||||
static void AcceptWaveformWrapper(const Napi::CallbackInfo &info) {
|
||||
Napi::Env env = info.Env();
|
||||
|
||||
if (info.Length() != 2) {
|
||||
std::ostringstream os;
|
||||
os << "Expect only 2 arguments. Given: " << info.Length();
|
||||
|
||||
Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!info[0].IsExternal()) {
|
||||
Napi::TypeError::New(env, "Argument 0 should be an online stream pointer.")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
SherpaOnnxOnlineStream *stream =
|
||||
info[0].As<Napi::External<SherpaOnnxOnlineStream>>().Data();
|
||||
|
||||
if (!info[1].IsObject()) {
|
||||
Napi::TypeError::New(env, "Argument 1 should be an object")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Napi::Object obj = info[1].As<Napi::Object>();
|
||||
|
||||
if (!obj.Has("samples")) {
|
||||
Napi::TypeError::New(env, "The argument object should have a field samples")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!obj.Get("samples").IsTypedArray()) {
|
||||
Napi::TypeError::New(env, "The object['samples'] should be a typed array")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!obj.Has("sampleRate")) {
|
||||
Napi::TypeError::New(env,
|
||||
"The argument object should have a field sampleRate")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!obj.Get("sampleRate").IsNumber()) {
|
||||
Napi::TypeError::New(env, "The object['samples'] should be a number")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Napi::Float32Array samples = obj.Get("samples").As<Napi::Float32Array>();
|
||||
int32_t sample_rate = obj.Get("sampleRate").As<Napi::Number>().Int32Value();
|
||||
|
||||
#if __OHOS__
|
||||
SherpaOnnxOnlineStreamAcceptWaveform(stream, sample_rate, samples.Data(),
|
||||
samples.ElementLength() / sizeof(float));
|
||||
#else
|
||||
SherpaOnnxOnlineStreamAcceptWaveform(stream, sample_rate, samples.Data(),
|
||||
samples.ElementLength());
|
||||
#endif
|
||||
}
|
||||
|
||||
static Napi::Boolean IsOnlineStreamReadyWrapper(
|
||||
const Napi::CallbackInfo &info) {
|
||||
Napi::Env env = info.Env();
|
||||
if (info.Length() != 2) {
|
||||
std::ostringstream os;
|
||||
os << "Expect only 2 arguments. Given: " << info.Length();
|
||||
|
||||
Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!info[0].IsExternal()) {
|
||||
Napi::TypeError::New(env,
|
||||
"Argument 0 should be an online recognizer pointer.")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!info[1].IsExternal()) {
|
||||
Napi::TypeError::New(env, "Argument 1 should be an online stream pointer.")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
SherpaOnnxOnlineRecognizer *recognizer =
|
||||
info[0].As<Napi::External<SherpaOnnxOnlineRecognizer>>().Data();
|
||||
|
||||
SherpaOnnxOnlineStream *stream =
|
||||
info[1].As<Napi::External<SherpaOnnxOnlineStream>>().Data();
|
||||
|
||||
int32_t is_ready = SherpaOnnxIsOnlineStreamReady(recognizer, stream);
|
||||
|
||||
return Napi::Boolean::New(env, is_ready);
|
||||
}
|
||||
|
||||
static void DecodeOnlineStreamWrapper(const Napi::CallbackInfo &info) {
|
||||
Napi::Env env = info.Env();
|
||||
if (info.Length() != 2) {
|
||||
std::ostringstream os;
|
||||
os << "Expect only 2 arguments. Given: " << info.Length();
|
||||
|
||||
Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!info[0].IsExternal()) {
|
||||
Napi::TypeError::New(env,
|
||||
"Argument 0 should be an online recognizer pointer.")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!info[1].IsExternal()) {
|
||||
Napi::TypeError::New(env, "Argument 1 should be an online stream pointer.")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
SherpaOnnxOnlineRecognizer *recognizer =
|
||||
info[0].As<Napi::External<SherpaOnnxOnlineRecognizer>>().Data();
|
||||
|
||||
SherpaOnnxOnlineStream *stream =
|
||||
info[1].As<Napi::External<SherpaOnnxOnlineStream>>().Data();
|
||||
|
||||
SherpaOnnxDecodeOnlineStream(recognizer, stream);
|
||||
}
|
||||
|
||||
static Napi::String GetOnlineStreamResultAsJsonWrapper(
|
||||
const Napi::CallbackInfo &info) {
|
||||
Napi::Env env = info.Env();
|
||||
if (info.Length() != 2) {
|
||||
std::ostringstream os;
|
||||
os << "Expect only 2 arguments. Given: " << info.Length();
|
||||
|
||||
Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!info[0].IsExternal()) {
|
||||
Napi::TypeError::New(env,
|
||||
"Argument 0 should be an online recognizer pointer.")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!info[1].IsExternal()) {
|
||||
Napi::TypeError::New(env, "Argument 1 should be an online stream pointer.")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
SherpaOnnxOnlineRecognizer *recognizer =
|
||||
info[0].As<Napi::External<SherpaOnnxOnlineRecognizer>>().Data();
|
||||
|
||||
SherpaOnnxOnlineStream *stream =
|
||||
info[1].As<Napi::External<SherpaOnnxOnlineStream>>().Data();
|
||||
|
||||
const char *json = SherpaOnnxGetOnlineStreamResultAsJson(recognizer, stream);
|
||||
Napi::String s = Napi::String::New(env, json);
|
||||
|
||||
SherpaOnnxDestroyOnlineStreamResultJson(json);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
static void InputFinishedWrapper(const Napi::CallbackInfo &info) {
|
||||
Napi::Env env = info.Env();
|
||||
|
||||
if (info.Length() != 1) {
|
||||
std::ostringstream os;
|
||||
os << "Expect only 1 argument. Given: " << info.Length();
|
||||
|
||||
Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!info[0].IsExternal()) {
|
||||
Napi::TypeError::New(env, "Argument 0 should be an online stream pointer.")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
SherpaOnnxOnlineStream *stream =
|
||||
info[0].As<Napi::External<SherpaOnnxOnlineStream>>().Data();
|
||||
|
||||
SherpaOnnxOnlineStreamInputFinished(stream);
|
||||
}
|
||||
|
||||
static void ResetOnlineStreamWrapper(const Napi::CallbackInfo &info) {
|
||||
Napi::Env env = info.Env();
|
||||
if (info.Length() != 2) {
|
||||
std::ostringstream os;
|
||||
os << "Expect only 2 arguments. Given: " << info.Length();
|
||||
|
||||
Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!info[0].IsExternal()) {
|
||||
Napi::TypeError::New(env,
|
||||
"Argument 0 should be an online recognizer pointer.")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!info[1].IsExternal()) {
|
||||
Napi::TypeError::New(env, "Argument 1 should be an online stream pointer.")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
SherpaOnnxOnlineRecognizer *recognizer =
|
||||
info[0].As<Napi::External<SherpaOnnxOnlineRecognizer>>().Data();
|
||||
|
||||
SherpaOnnxOnlineStream *stream =
|
||||
info[1].As<Napi::External<SherpaOnnxOnlineStream>>().Data();
|
||||
|
||||
SherpaOnnxOnlineStreamReset(recognizer, stream);
|
||||
}
|
||||
|
||||
static Napi::Boolean IsEndpointWrapper(const Napi::CallbackInfo &info) {
|
||||
Napi::Env env = info.Env();
|
||||
if (info.Length() != 2) {
|
||||
std::ostringstream os;
|
||||
os << "Expect only 2 arguments. Given: " << info.Length();
|
||||
|
||||
Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!info[0].IsExternal()) {
|
||||
Napi::TypeError::New(env,
|
||||
"Argument 0 should be an online recognizer pointer.")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!info[1].IsExternal()) {
|
||||
Napi::TypeError::New(env, "Argument 1 should be an online stream pointer.")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
SherpaOnnxOnlineRecognizer *recognizer =
|
||||
info[0].As<Napi::External<SherpaOnnxOnlineRecognizer>>().Data();
|
||||
|
||||
SherpaOnnxOnlineStream *stream =
|
||||
info[1].As<Napi::External<SherpaOnnxOnlineStream>>().Data();
|
||||
|
||||
int32_t is_endpoint = SherpaOnnxOnlineStreamIsEndpoint(recognizer, stream);
|
||||
|
||||
return Napi::Boolean::New(env, is_endpoint);
|
||||
}
|
||||
|
||||
static Napi::External<SherpaOnnxDisplay> CreateDisplayWrapper(
|
||||
const Napi::CallbackInfo &info) {
|
||||
Napi::Env env = info.Env();
|
||||
if (info.Length() != 1) {
|
||||
std::ostringstream os;
|
||||
os << "Expect only 1 argument. Given: " << info.Length();
|
||||
|
||||
Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!info[0].IsNumber()) {
|
||||
Napi::TypeError::New(env, "Expect a number as the argument")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
int32_t max_word_per_line = info[0].As<Napi::Number>().Int32Value();
|
||||
|
||||
const SherpaOnnxDisplay *display = SherpaOnnxCreateDisplay(max_word_per_line);
|
||||
|
||||
return Napi::External<SherpaOnnxDisplay>::New(
|
||||
env, const_cast<SherpaOnnxDisplay *>(display),
|
||||
[](Napi::Env env, SherpaOnnxDisplay *display) {
|
||||
SherpaOnnxDestroyDisplay(display);
|
||||
});
|
||||
}
|
||||
|
||||
static void PrintWrapper(const Napi::CallbackInfo &info) {
|
||||
Napi::Env env = info.Env();
|
||||
|
||||
if (info.Length() != 3) {
|
||||
std::ostringstream os;
|
||||
os << "Expect only 3 arguments. Given: " << info.Length();
|
||||
|
||||
Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!info[0].IsExternal()) {
|
||||
Napi::TypeError::New(env, "Argument 0 should be an online stream pointer.")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!info[1].IsNumber()) {
|
||||
Napi::TypeError::New(env, "Argument 1 should be a number.")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!info[2].IsString()) {
|
||||
Napi::TypeError::New(env, "Argument 2 should be a string.")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
SherpaOnnxDisplay *display =
|
||||
info[0].As<Napi::External<SherpaOnnxDisplay>>().Data();
|
||||
|
||||
int32_t idx = info[1].As<Napi::Number>().Int32Value();
|
||||
|
||||
Napi::String text = info[2].As<Napi::String>();
|
||||
std::string s = text.Utf8Value();
|
||||
SherpaOnnxPrint(display, idx, s.c_str());
|
||||
}
|
||||
|
||||
void InitStreamingAsr(Napi::Env env, Napi::Object exports) {
|
||||
exports.Set(Napi::String::New(env, "createOnlineRecognizer"),
|
||||
Napi::Function::New(env, CreateOnlineRecognizerWrapper));
|
||||
|
||||
exports.Set(Napi::String::New(env, "createOnlineStream"),
|
||||
Napi::Function::New(env, CreateOnlineStreamWrapper));
|
||||
|
||||
exports.Set(Napi::String::New(env, "acceptWaveformOnline"),
|
||||
Napi::Function::New(env, AcceptWaveformWrapper));
|
||||
|
||||
exports.Set(Napi::String::New(env, "isOnlineStreamReady"),
|
||||
Napi::Function::New(env, IsOnlineStreamReadyWrapper));
|
||||
|
||||
exports.Set(Napi::String::New(env, "decodeOnlineStream"),
|
||||
Napi::Function::New(env, DecodeOnlineStreamWrapper));
|
||||
|
||||
exports.Set(Napi::String::New(env, "getOnlineStreamResultAsJson"),
|
||||
Napi::Function::New(env, GetOnlineStreamResultAsJsonWrapper));
|
||||
|
||||
exports.Set(Napi::String::New(env, "inputFinished"),
|
||||
Napi::Function::New(env, InputFinishedWrapper));
|
||||
|
||||
exports.Set(Napi::String::New(env, "reset"),
|
||||
Napi::Function::New(env, ResetOnlineStreamWrapper));
|
||||
|
||||
exports.Set(Napi::String::New(env, "isEndpoint"),
|
||||
Napi::Function::New(env, IsEndpointWrapper));
|
||||
|
||||
exports.Set(Napi::String::New(env, "createDisplay"),
|
||||
Napi::Function::New(env, CreateDisplayWrapper));
|
||||
|
||||
exports.Set(Napi::String::New(env, "print"),
|
||||
Napi::Function::New(env, PrintWrapper));
|
||||
}
|
||||
35
harmony-os/SherpaOnnxHar/sherpa_onnx/src/main/cpp/types/libsherpa_onnx/Index.d.ts
vendored
Normal file
35
harmony-os/SherpaOnnxHar/sherpa_onnx/src/main/cpp/types/libsherpa_onnx/Index.d.ts
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
export const readWave: (filename: string, enableExternalBuffer: boolean = true) => {samples: Float32Array, sampleRate: number};
|
||||
export const readWaveFromBinary: (data: Uint8Array, enableExternalBuffer: boolean = true) => {samples: Float32Array, sampleRate: number};
|
||||
export const createCircularBuffer: (capacity: number) => object;
|
||||
export const circularBufferPush: (handle: object, samples: Float32Array) => void;
|
||||
export const circularBufferGet: (handle: object, index: number, n: number, enableExternalBuffer: boolean = true) => Float32Array;
|
||||
export const circularBufferPop: (handle: object, n: number) => void;
|
||||
export const circularBufferSize: (handle: object) => number;
|
||||
export const circularBufferHead: (handle: object) => number;
|
||||
export const circularBufferReset: (handle: object) => void;
|
||||
|
||||
export const createVoiceActivityDetector: (config: object, bufferSizeInSeconds: number, mgr?: object) => object;
|
||||
export const voiceActivityDetectorAcceptWaveform: (handle: object, samples: Float32Array) => void;
|
||||
export const voiceActivityDetectorIsEmpty: (handle: object) => boolean;
|
||||
export const voiceActivityDetectorIsDetected: (handle: object) => boolean;
|
||||
export const voiceActivityDetectorPop: (handle: object) => void;
|
||||
export const voiceActivityDetectorClear: (handle: object) => void;
|
||||
export const voiceActivityDetectorFront: (handle: object, enableExternalBuffer: boolean = true) => {samples: Float32Array, start: number};
|
||||
export const voiceActivityDetectorReset: (handle: object) => void;
|
||||
export const voiceActivityDetectorFlush: (handle: object) => void;
|
||||
|
||||
export const createOfflineRecognizer: (config: object, mgr?: object) => object;
|
||||
export const createOfflineStream: (handle: object) => object;
|
||||
export const acceptWaveformOffline: (handle: object, audio: object) => void;
|
||||
export const decodeOfflineStream: (handle: object, streamHandle: object) => void;
|
||||
export const getOfflineStreamResultAsJson: (streamHandle: object) => string;
|
||||
|
||||
export const createOnlineRecognizer: (config: object, mgr?: object) => object;
|
||||
export const createOnlineStream: (handle: object) => object;
|
||||
export const acceptWaveformOnline: (handle: object, audio: object) => void;
|
||||
export const inputFinished: (streamHandle: object) => void;
|
||||
export const isOnlineStreamReady: (handle: object, streamHandle: object) => boolean;
|
||||
export const decodeOnlineStream: (handle: object, streamHandle: object) => void;
|
||||
export const isEndpoint: (handle: object, streamHandle: object) => boolean;
|
||||
export const reset: (handle: object, streamHandle: object) => void;
|
||||
export const getOnlineStreamResultAsJson: (handle: object, streamHandle: object) => string;
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"name": "libsherpa_onnx.so",
|
||||
"types": "./Index.d.ts",
|
||||
"version": "1.0.0",
|
||||
"description": "Please describe the basic information."
|
||||
}
|
||||
700
harmony-os/SherpaOnnxHar/sherpa_onnx/src/main/cpp/vad.cc
Normal file
700
harmony-os/SherpaOnnxHar/sherpa_onnx/src/main/cpp/vad.cc
Normal file
@@ -0,0 +1,700 @@
|
||||
// scripts/node-addon-api/src/vad.cc
|
||||
//
|
||||
// Copyright (c) 2024 Xiaomi Corporation
|
||||
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
|
||||
#include "macros.h" // NOLINT
|
||||
#include "napi.h" // NOLINT
|
||||
#include "sherpa-onnx/c-api/c-api.h"
|
||||
|
||||
static Napi::External<SherpaOnnxCircularBuffer> CreateCircularBufferWrapper(
|
||||
const Napi::CallbackInfo &info) {
|
||||
Napi::Env env = info.Env();
|
||||
if (info.Length() != 1) {
|
||||
std::ostringstream os;
|
||||
os << "Expect only 1 argument. Given: " << info.Length();
|
||||
|
||||
Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!info[0].IsNumber()) {
|
||||
Napi::TypeError::New(env, "You should pass an integer as the argument.")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
SherpaOnnxCircularBuffer *buf =
|
||||
SherpaOnnxCreateCircularBuffer(info[0].As<Napi::Number>().Int32Value());
|
||||
|
||||
return Napi::External<SherpaOnnxCircularBuffer>::New(
|
||||
env, buf, [](Napi::Env env, SherpaOnnxCircularBuffer *p) {
|
||||
SherpaOnnxDestroyCircularBuffer(p);
|
||||
});
|
||||
}
|
||||
|
||||
static void CircularBufferPushWrapper(const Napi::CallbackInfo &info) {
|
||||
Napi::Env env = info.Env();
|
||||
|
||||
if (info.Length() != 2) {
|
||||
std::ostringstream os;
|
||||
os << "Expect only 2 arguments. Given: " << info.Length();
|
||||
|
||||
Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!info[0].IsExternal()) {
|
||||
Napi::TypeError::New(env, "Argument 0 should be an CircularBuffer pointer.")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
SherpaOnnxCircularBuffer *buf =
|
||||
info[0].As<Napi::External<SherpaOnnxCircularBuffer>>().Data();
|
||||
|
||||
if (!info[1].IsTypedArray()) {
|
||||
Napi::TypeError::New(env, "Argument 1 should be a Float32Array.")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Napi::Float32Array data = info[1].As<Napi::Float32Array>();
|
||||
|
||||
#if __OHOS__
|
||||
// Note(fangjun): Normally, we don't need to divied it by sizeof(float).
|
||||
// However, data.ElementLength() here returns number of bytes, not number of elements.
|
||||
SherpaOnnxCircularBufferPush(buf, data.Data(), data.ElementLength() / sizeof(float));
|
||||
#else
|
||||
SherpaOnnxCircularBufferPush(buf, data.Data(), data.ElementLength());
|
||||
#endif
|
||||
}
|
||||
|
||||
// see https://github.com/nodejs/node-addon-api/blob/main/doc/typed_array.md
|
||||
// https://github.com/nodejs/node-addon-examples/blob/main/src/2-js-to-native-conversion/typed_array_to_native/node-addon-api/typed_array_to_native.cc
|
||||
static Napi::Float32Array CircularBufferGetWrapper(
|
||||
const Napi::CallbackInfo &info) {
|
||||
Napi::Env env = info.Env();
|
||||
|
||||
if (info.Length() != 3 && info.Length() != 4) {
|
||||
std::ostringstream os;
|
||||
os << "Expect only 3 or 4 arguments. Given: " << info.Length();
|
||||
|
||||
Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!info[0].IsExternal()) {
|
||||
Napi::TypeError::New(env, "Argument 0 should be an CircularBuffer pointer.")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
SherpaOnnxCircularBuffer *buf =
|
||||
info[0].As<Napi::External<SherpaOnnxCircularBuffer>>().Data();
|
||||
|
||||
if (!info[1].IsNumber()) {
|
||||
Napi::TypeError::New(env, "Argument 1 should be an integer (startIndex).")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!info[2].IsNumber()) {
|
||||
Napi::TypeError::New(env, "Argument 2 should be an integer (n).")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
bool enable_external_buffer = true;
|
||||
if (info.Length() == 4) {
|
||||
if (info[3].IsBoolean()) {
|
||||
enable_external_buffer = info[3].As<Napi::Boolean>().Value();
|
||||
} else {
|
||||
Napi::TypeError::New(env, "Argument 3 should be a boolean.")
|
||||
.ThrowAsJavaScriptException();
|
||||
}
|
||||
}
|
||||
|
||||
int32_t start_index = info[1].As<Napi::Number>().Int32Value();
|
||||
int32_t n = info[2].As<Napi::Number>().Int32Value();
|
||||
|
||||
const float *data = SherpaOnnxCircularBufferGet(buf, start_index, n);
|
||||
|
||||
if (enable_external_buffer) {
|
||||
Napi::ArrayBuffer arrayBuffer = Napi::ArrayBuffer::New(
|
||||
env, const_cast<float *>(data), sizeof(float) * n,
|
||||
[](Napi::Env /*env*/, void *p) {
|
||||
SherpaOnnxCircularBufferFree(reinterpret_cast<const float *>(p));
|
||||
});
|
||||
|
||||
Napi::Float32Array float32Array =
|
||||
Napi::Float32Array::New(env, n, arrayBuffer, 0);
|
||||
|
||||
return float32Array;
|
||||
} else {
|
||||
// don't use external buffer
|
||||
Napi::ArrayBuffer arrayBuffer =
|
||||
Napi::ArrayBuffer::New(env, sizeof(float) * n);
|
||||
|
||||
Napi::Float32Array float32Array =
|
||||
Napi::Float32Array::New(env, n, arrayBuffer, 0);
|
||||
|
||||
std::copy(data, data + n, float32Array.Data());
|
||||
|
||||
SherpaOnnxCircularBufferFree(data);
|
||||
|
||||
return float32Array;
|
||||
}
|
||||
}
|
||||
|
||||
static void CircularBufferPopWrapper(const Napi::CallbackInfo &info) {
|
||||
Napi::Env env = info.Env();
|
||||
|
||||
if (info.Length() != 2) {
|
||||
std::ostringstream os;
|
||||
os << "Expect only 2 arguments. Given: " << info.Length();
|
||||
|
||||
Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!info[0].IsExternal()) {
|
||||
Napi::TypeError::New(env, "Argument 0 should be an CircularBuffer pointer.")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
SherpaOnnxCircularBuffer *buf =
|
||||
info[0].As<Napi::External<SherpaOnnxCircularBuffer>>().Data();
|
||||
|
||||
if (!info[1].IsNumber()) {
|
||||
Napi::TypeError::New(env, "Argument 1 should be an integer (n).")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
int32_t n = info[1].As<Napi::Number>().Int32Value();
|
||||
|
||||
SherpaOnnxCircularBufferPop(buf, n);
|
||||
}
|
||||
|
||||
static Napi::Number CircularBufferSizeWrapper(const Napi::CallbackInfo &info) {
|
||||
Napi::Env env = info.Env();
|
||||
|
||||
if (info.Length() != 1) {
|
||||
std::ostringstream os;
|
||||
os << "Expect only 1 argument. Given: " << info.Length();
|
||||
|
||||
Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!info[0].IsExternal()) {
|
||||
Napi::TypeError::New(env, "Argument 0 should be an CircularBuffer pointer.")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
SherpaOnnxCircularBuffer *buf =
|
||||
info[0].As<Napi::External<SherpaOnnxCircularBuffer>>().Data();
|
||||
|
||||
int32_t size = SherpaOnnxCircularBufferSize(buf);
|
||||
|
||||
return Napi::Number::New(env, size);
|
||||
}
|
||||
|
||||
static Napi::Number CircularBufferHeadWrapper(const Napi::CallbackInfo &info) {
|
||||
Napi::Env env = info.Env();
|
||||
|
||||
if (info.Length() != 1) {
|
||||
std::ostringstream os;
|
||||
os << "Expect only 1 argument. Given: " << info.Length();
|
||||
|
||||
Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!info[0].IsExternal()) {
|
||||
Napi::TypeError::New(env, "Argument 0 should be an CircularBuffer pointer.")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
SherpaOnnxCircularBuffer *buf =
|
||||
info[0].As<Napi::External<SherpaOnnxCircularBuffer>>().Data();
|
||||
|
||||
int32_t size = SherpaOnnxCircularBufferHead(buf);
|
||||
|
||||
return Napi::Number::New(env, size);
|
||||
}
|
||||
|
||||
static void CircularBufferResetWrapper(const Napi::CallbackInfo &info) {
|
||||
Napi::Env env = info.Env();
|
||||
|
||||
if (info.Length() != 1) {
|
||||
std::ostringstream os;
|
||||
os << "Expect only 1 argument. Given: " << info.Length();
|
||||
|
||||
Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!info[0].IsExternal()) {
|
||||
Napi::TypeError::New(env, "Argument 0 should be an CircularBuffer pointer.")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
SherpaOnnxCircularBuffer *buf =
|
||||
info[0].As<Napi::External<SherpaOnnxCircularBuffer>>().Data();
|
||||
|
||||
SherpaOnnxCircularBufferReset(buf);
|
||||
}
|
||||
|
||||
static SherpaOnnxSileroVadModelConfig GetSileroVadConfig(
|
||||
const Napi::Object &obj) {
|
||||
SherpaOnnxSileroVadModelConfig c;
|
||||
memset(&c, 0, sizeof(c));
|
||||
|
||||
if (!obj.Has("sileroVad") || !obj.Get("sileroVad").IsObject()) {
|
||||
return c;
|
||||
}
|
||||
|
||||
Napi::Object o = obj.Get("sileroVad").As<Napi::Object>();
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(model, model);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_FLOAT(threshold, threshold);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_FLOAT(min_silence_duration, minSilenceDuration);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_FLOAT(min_speech_duration, minSpeechDuration);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_INT32(window_size, windowSize);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_FLOAT(max_speech_duration, maxSpeechDuration);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
static Napi::External<SherpaOnnxVoiceActivityDetector>
|
||||
CreateVoiceActivityDetectorWrapper(const Napi::CallbackInfo &info) {
|
||||
Napi::Env env = info.Env();
|
||||
#if __OHOS__
|
||||
// the last argument is a NativeResourceManager
|
||||
if (info.Length() != 3) {
|
||||
std::ostringstream os;
|
||||
os << "Expect only 3 arguments. Given: " << info.Length();
|
||||
|
||||
Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
#else
|
||||
if (info.Length() != 2) {
|
||||
std::ostringstream os;
|
||||
os << "Expect only 2 arguments. Given: " << info.Length();
|
||||
|
||||
Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!info[0].IsObject()) {
|
||||
Napi::TypeError::New(env,
|
||||
"You should pass an object as the first argument.")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!info[1].IsNumber()) {
|
||||
Napi::TypeError::New(env,
|
||||
"You should pass an integer as the second argument.")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
Napi::Object o = info[0].As<Napi::Object>();
|
||||
|
||||
SherpaOnnxVadModelConfig c;
|
||||
memset(&c, 0, sizeof(c));
|
||||
c.silero_vad = GetSileroVadConfig(o);
|
||||
|
||||
SHERPA_ONNX_ASSIGN_ATTR_INT32(sample_rate, sampleRate);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_INT32(num_threads, numThreads);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(provider, provider);
|
||||
|
||||
if (o.Has("debug") &&
|
||||
(o.Get("debug").IsNumber() || o.Get("debug").IsBoolean())) {
|
||||
if (o.Get("debug").IsBoolean()) {
|
||||
c.debug = o.Get("debug").As<Napi::Boolean>().Value();
|
||||
} else {
|
||||
c.debug = o.Get("debug").As<Napi::Number>().Int32Value();
|
||||
}
|
||||
}
|
||||
|
||||
float buffer_size_in_seconds = info[1].As<Napi::Number>().FloatValue();
|
||||
|
||||
#if __OHOS__
|
||||
std::unique_ptr<NativeResourceManager, decltype(&OH_ResourceManager_ReleaseNativeResourceManager)> mgr(OH_ResourceManager_InitNativeResourceManager(env, info[2]), &OH_ResourceManager_ReleaseNativeResourceManager);
|
||||
|
||||
SherpaOnnxVoiceActivityDetector *vad =
|
||||
SherpaOnnxCreateVoiceActivityDetectorOHOS(&c, buffer_size_in_seconds, mgr.get());
|
||||
#else
|
||||
SherpaOnnxVoiceActivityDetector *vad =
|
||||
SherpaOnnxCreateVoiceActivityDetector(&c, buffer_size_in_seconds);
|
||||
#endif
|
||||
|
||||
if (c.silero_vad.model) {
|
||||
delete[] c.silero_vad.model;
|
||||
}
|
||||
|
||||
if (c.provider) {
|
||||
delete[] c.provider;
|
||||
}
|
||||
|
||||
return Napi::External<SherpaOnnxVoiceActivityDetector>::New(
|
||||
env, vad, [](Napi::Env env, SherpaOnnxVoiceActivityDetector *p) {
|
||||
SherpaOnnxDestroyVoiceActivityDetector(p);
|
||||
});
|
||||
}
|
||||
|
||||
static void VoiceActivityDetectorAcceptWaveformWrapper(
|
||||
const Napi::CallbackInfo &info) {
|
||||
Napi::Env env = info.Env();
|
||||
|
||||
if (info.Length() != 2) {
|
||||
std::ostringstream os;
|
||||
os << "Expect only 2 arguments. Given: " << info.Length();
|
||||
|
||||
Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!info[0].IsExternal()) {
|
||||
Napi::TypeError::New(env, "Argument 0 should be a VAD pointer.")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
SherpaOnnxVoiceActivityDetector *vad =
|
||||
info[0].As<Napi::External<SherpaOnnxVoiceActivityDetector>>().Data();
|
||||
|
||||
if (!info[1].IsTypedArray()) {
|
||||
Napi::TypeError::New(
|
||||
env, "Argument 1 should be a Float32Array containing samples")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Napi::Float32Array samples = info[1].As<Napi::Float32Array>();
|
||||
|
||||
#if __OHOS__
|
||||
// Note(fangjun): For unknown reasons, we need to use `/sizeof(float)` here for Huawei
|
||||
SherpaOnnxVoiceActivityDetectorAcceptWaveform(vad, samples.Data(),
|
||||
samples.ElementLength() / sizeof(float));
|
||||
#else
|
||||
SherpaOnnxVoiceActivityDetectorAcceptWaveform(vad, samples.Data(),
|
||||
samples.ElementLength());
|
||||
#endif
|
||||
}
|
||||
|
||||
static Napi::Boolean VoiceActivityDetectorEmptyWrapper(
|
||||
const Napi::CallbackInfo &info) {
|
||||
Napi::Env env = info.Env();
|
||||
|
||||
if (info.Length() != 1) {
|
||||
std::ostringstream os;
|
||||
os << "Expect only 1 argument. Given: " << info.Length();
|
||||
|
||||
Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!info[0].IsExternal()) {
|
||||
Napi::TypeError::New(env, "Argument 0 should be a VAD pointer.")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
SherpaOnnxVoiceActivityDetector *vad =
|
||||
info[0].As<Napi::External<SherpaOnnxVoiceActivityDetector>>().Data();
|
||||
|
||||
int32_t is_empty = SherpaOnnxVoiceActivityDetectorEmpty(vad);
|
||||
|
||||
return Napi::Boolean::New(env, is_empty);
|
||||
}
|
||||
|
||||
static Napi::Boolean VoiceActivityDetectorDetectedWrapper(
|
||||
const Napi::CallbackInfo &info) {
|
||||
Napi::Env env = info.Env();
|
||||
|
||||
if (info.Length() != 1) {
|
||||
std::ostringstream os;
|
||||
os << "Expect only 1 argument. Given: " << info.Length();
|
||||
|
||||
Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!info[0].IsExternal()) {
|
||||
Napi::TypeError::New(env, "Argument 0 should be a VAD pointer.")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
SherpaOnnxVoiceActivityDetector *vad =
|
||||
info[0].As<Napi::External<SherpaOnnxVoiceActivityDetector>>().Data();
|
||||
|
||||
int32_t is_detected = SherpaOnnxVoiceActivityDetectorDetected(vad);
|
||||
|
||||
return Napi::Boolean::New(env, is_detected);
|
||||
}
|
||||
|
||||
static void VoiceActivityDetectorPopWrapper(const Napi::CallbackInfo &info) {
|
||||
Napi::Env env = info.Env();
|
||||
|
||||
if (info.Length() != 1) {
|
||||
std::ostringstream os;
|
||||
os << "Expect only 1 argument. Given: " << info.Length();
|
||||
|
||||
Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!info[0].IsExternal()) {
|
||||
Napi::TypeError::New(env, "Argument 0 should be a VAD pointer.")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
SherpaOnnxVoiceActivityDetector *vad =
|
||||
info[0].As<Napi::External<SherpaOnnxVoiceActivityDetector>>().Data();
|
||||
|
||||
SherpaOnnxVoiceActivityDetectorPop(vad);
|
||||
}
|
||||
|
||||
static void VoiceActivityDetectorClearWrapper(const Napi::CallbackInfo &info) {
|
||||
Napi::Env env = info.Env();
|
||||
|
||||
if (info.Length() != 1) {
|
||||
std::ostringstream os;
|
||||
os << "Expect only 1 argument. Given: " << info.Length();
|
||||
|
||||
Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!info[0].IsExternal()) {
|
||||
Napi::TypeError::New(env, "Argument 0 should be a VAD pointer.")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
SherpaOnnxVoiceActivityDetector *vad =
|
||||
info[0].As<Napi::External<SherpaOnnxVoiceActivityDetector>>().Data();
|
||||
|
||||
SherpaOnnxVoiceActivityDetectorClear(vad);
|
||||
}
|
||||
|
||||
static Napi::Object VoiceActivityDetectorFrontWrapper(
|
||||
const Napi::CallbackInfo &info) {
|
||||
Napi::Env env = info.Env();
|
||||
|
||||
if (info.Length() != 1 && info.Length() != 2) {
|
||||
std::ostringstream os;
|
||||
os << "Expect only 1 or 2 arguments. Given: " << info.Length();
|
||||
|
||||
Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!info[0].IsExternal()) {
|
||||
Napi::TypeError::New(env, "Argument 0 should be a VAD pointer.")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
bool enable_external_buffer = true;
|
||||
if (info.Length() == 2) {
|
||||
if (info[1].IsBoolean()) {
|
||||
enable_external_buffer = info[1].As<Napi::Boolean>().Value();
|
||||
} else {
|
||||
Napi::TypeError::New(env, "Argument 1 should be a boolean.")
|
||||
.ThrowAsJavaScriptException();
|
||||
}
|
||||
}
|
||||
|
||||
SherpaOnnxVoiceActivityDetector *vad =
|
||||
info[0].As<Napi::External<SherpaOnnxVoiceActivityDetector>>().Data();
|
||||
|
||||
const SherpaOnnxSpeechSegment *segment =
|
||||
SherpaOnnxVoiceActivityDetectorFront(vad);
|
||||
|
||||
if (enable_external_buffer) {
|
||||
Napi::ArrayBuffer arrayBuffer = Napi::ArrayBuffer::New(
|
||||
env, const_cast<float *>(segment->samples), sizeof(float) * segment->n,
|
||||
[](Napi::Env /*env*/, void * /*data*/,
|
||||
const SherpaOnnxSpeechSegment *hint) {
|
||||
SherpaOnnxDestroySpeechSegment(hint);
|
||||
},
|
||||
segment);
|
||||
|
||||
Napi::Float32Array float32Array =
|
||||
Napi::Float32Array::New(env, segment->n, arrayBuffer, 0);
|
||||
|
||||
Napi::Object obj = Napi::Object::New(env);
|
||||
obj.Set(Napi::String::New(env, "start"), segment->start);
|
||||
obj.Set(Napi::String::New(env, "samples"), float32Array);
|
||||
|
||||
return obj;
|
||||
} else {
|
||||
Napi::ArrayBuffer arrayBuffer =
|
||||
Napi::ArrayBuffer::New(env, sizeof(float) * segment->n);
|
||||
|
||||
Napi::Float32Array float32Array =
|
||||
Napi::Float32Array::New(env, segment->n, arrayBuffer, 0);
|
||||
|
||||
std::copy(segment->samples, segment->samples + segment->n,
|
||||
float32Array.Data());
|
||||
|
||||
Napi::Object obj = Napi::Object::New(env);
|
||||
obj.Set(Napi::String::New(env, "start"), segment->start);
|
||||
obj.Set(Napi::String::New(env, "samples"), float32Array);
|
||||
|
||||
SherpaOnnxDestroySpeechSegment(segment);
|
||||
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
|
||||
static void VoiceActivityDetectorResetWrapper(const Napi::CallbackInfo &info) {
|
||||
Napi::Env env = info.Env();
|
||||
|
||||
if (info.Length() != 1) {
|
||||
std::ostringstream os;
|
||||
os << "Expect only 1 argument. Given: " << info.Length();
|
||||
|
||||
Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!info[0].IsExternal()) {
|
||||
Napi::TypeError::New(env, "Argument 0 should be a VAD pointer.")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
SherpaOnnxVoiceActivityDetector *vad =
|
||||
info[0].As<Napi::External<SherpaOnnxVoiceActivityDetector>>().Data();
|
||||
|
||||
SherpaOnnxVoiceActivityDetectorReset(vad);
|
||||
}
|
||||
|
||||
static void VoiceActivityDetectorFlushWrapper(const Napi::CallbackInfo &info) {
|
||||
Napi::Env env = info.Env();
|
||||
|
||||
if (info.Length() != 1) {
|
||||
std::ostringstream os;
|
||||
os << "Expect only 1 argument. Given: " << info.Length();
|
||||
|
||||
Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!info[0].IsExternal()) {
|
||||
Napi::TypeError::New(env, "Argument 0 should be a VAD pointer.")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
SherpaOnnxVoiceActivityDetector *vad =
|
||||
info[0].As<Napi::External<SherpaOnnxVoiceActivityDetector>>().Data();
|
||||
|
||||
SherpaOnnxVoiceActivityDetectorFlush(vad);
|
||||
}
|
||||
|
||||
void InitVad(Napi::Env env, Napi::Object exports) {
|
||||
exports.Set(Napi::String::New(env, "createCircularBuffer"),
|
||||
Napi::Function::New(env, CreateCircularBufferWrapper));
|
||||
|
||||
exports.Set(Napi::String::New(env, "circularBufferPush"),
|
||||
Napi::Function::New(env, CircularBufferPushWrapper));
|
||||
|
||||
exports.Set(Napi::String::New(env, "circularBufferGet"),
|
||||
Napi::Function::New(env, CircularBufferGetWrapper));
|
||||
|
||||
exports.Set(Napi::String::New(env, "circularBufferPop"),
|
||||
Napi::Function::New(env, CircularBufferPopWrapper));
|
||||
|
||||
exports.Set(Napi::String::New(env, "circularBufferSize"),
|
||||
Napi::Function::New(env, CircularBufferSizeWrapper));
|
||||
|
||||
exports.Set(Napi::String::New(env, "circularBufferHead"),
|
||||
Napi::Function::New(env, CircularBufferHeadWrapper));
|
||||
|
||||
exports.Set(Napi::String::New(env, "circularBufferReset"),
|
||||
Napi::Function::New(env, CircularBufferResetWrapper));
|
||||
|
||||
exports.Set(Napi::String::New(env, "createVoiceActivityDetector"),
|
||||
Napi::Function::New(env, CreateVoiceActivityDetectorWrapper));
|
||||
|
||||
exports.Set(
|
||||
Napi::String::New(env, "voiceActivityDetectorAcceptWaveform"),
|
||||
Napi::Function::New(env, VoiceActivityDetectorAcceptWaveformWrapper));
|
||||
|
||||
exports.Set(Napi::String::New(env, "voiceActivityDetectorIsEmpty"),
|
||||
Napi::Function::New(env, VoiceActivityDetectorEmptyWrapper));
|
||||
|
||||
exports.Set(Napi::String::New(env, "voiceActivityDetectorIsDetected"),
|
||||
Napi::Function::New(env, VoiceActivityDetectorDetectedWrapper));
|
||||
|
||||
exports.Set(Napi::String::New(env, "voiceActivityDetectorPop"),
|
||||
Napi::Function::New(env, VoiceActivityDetectorPopWrapper));
|
||||
|
||||
exports.Set(Napi::String::New(env, "voiceActivityDetectorClear"),
|
||||
Napi::Function::New(env, VoiceActivityDetectorClearWrapper));
|
||||
|
||||
exports.Set(Napi::String::New(env, "voiceActivityDetectorFront"),
|
||||
Napi::Function::New(env, VoiceActivityDetectorFrontWrapper));
|
||||
|
||||
exports.Set(Napi::String::New(env, "voiceActivityDetectorReset"),
|
||||
Napi::Function::New(env, VoiceActivityDetectorResetWrapper));
|
||||
|
||||
exports.Set(Napi::String::New(env, "voiceActivityDetectorFlush"),
|
||||
Napi::Function::New(env, VoiceActivityDetectorFlushWrapper));
|
||||
}
|
||||
171
harmony-os/SherpaOnnxHar/sherpa_onnx/src/main/cpp/wave-reader.cc
Normal file
171
harmony-os/SherpaOnnxHar/sherpa_onnx/src/main/cpp/wave-reader.cc
Normal file
@@ -0,0 +1,171 @@
|
||||
// scripts/node-addon-api/src/wave-reader.cc
|
||||
//
|
||||
// Copyright (c) 2024 Xiaomi Corporation
|
||||
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
|
||||
#include "napi.h" // NOLINT
|
||||
#include "sherpa-onnx/c-api/c-api.h"
|
||||
|
||||
static Napi::Object ReadWaveWrapper(const Napi::CallbackInfo &info) {
|
||||
Napi::Env env = info.Env();
|
||||
if (info.Length() > 2) {
|
||||
std::ostringstream os;
|
||||
os << "Expect only 2 arguments. Given: " << info.Length();
|
||||
|
||||
Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!info[0].IsString()) {
|
||||
Napi::TypeError::New(env, "Argument 0 should be a string")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
std::string filename = info[0].As<Napi::String>().Utf8Value();
|
||||
|
||||
bool enable_external_buffer = true;
|
||||
if (info.Length() == 2) {
|
||||
if (info[1].IsBoolean()) {
|
||||
enable_external_buffer = info[1].As<Napi::Boolean>().Value();
|
||||
} else {
|
||||
Napi::TypeError::New(env, "Argument 1 should be a boolean")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
const SherpaOnnxWave *wave = SherpaOnnxReadWave(filename.c_str());
|
||||
if (!wave) {
|
||||
std::ostringstream os;
|
||||
os << "Failed to read '" << filename << "'";
|
||||
Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (enable_external_buffer) {
|
||||
Napi::ArrayBuffer arrayBuffer = Napi::ArrayBuffer::New(
|
||||
env, const_cast<float *>(wave->samples),
|
||||
sizeof(float) * wave->num_samples,
|
||||
[](Napi::Env /*env*/, void * /*data*/, const SherpaOnnxWave *hint) {
|
||||
SherpaOnnxFreeWave(hint);
|
||||
},
|
||||
wave);
|
||||
Napi::Float32Array float32Array =
|
||||
Napi::Float32Array::New(env, wave->num_samples, arrayBuffer, 0);
|
||||
|
||||
Napi::Object obj = Napi::Object::New(env);
|
||||
obj.Set(Napi::String::New(env, "samples"), float32Array);
|
||||
obj.Set(Napi::String::New(env, "sampleRate"), wave->sample_rate);
|
||||
return obj;
|
||||
} else {
|
||||
// don't use external buffer
|
||||
Napi::ArrayBuffer arrayBuffer =
|
||||
Napi::ArrayBuffer::New(env, sizeof(float) * wave->num_samples);
|
||||
|
||||
Napi::Float32Array float32Array =
|
||||
Napi::Float32Array::New(env, wave->num_samples, arrayBuffer, 0);
|
||||
|
||||
std::copy(wave->samples, wave->samples + wave->num_samples,
|
||||
float32Array.Data());
|
||||
|
||||
Napi::Object obj = Napi::Object::New(env);
|
||||
obj.Set(Napi::String::New(env, "samples"), float32Array);
|
||||
obj.Set(Napi::String::New(env, "sampleRate"), wave->sample_rate);
|
||||
|
||||
SherpaOnnxFreeWave(wave);
|
||||
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
|
||||
static Napi::Object ReadWaveFromBinaryWrapper(const Napi::CallbackInfo &info) {
|
||||
Napi::Env env = info.Env();
|
||||
if (info.Length() > 2) {
|
||||
std::ostringstream os;
|
||||
os << "Expect only 1 or 2 arguments. Given: " << info.Length();
|
||||
|
||||
Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!info[0].IsTypedArray()) {
|
||||
Napi::TypeError::New(env, "Argument 0 should be a float32 array")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
Napi::Uint8Array data = info[0].As<Napi::Uint8Array>();
|
||||
int32_t n = data.ElementLength();
|
||||
const SherpaOnnxWave *wave = SherpaOnnxReadWaveFromBinaryData(reinterpret_cast<const char*>(data.Data()), n);
|
||||
if (!wave) {
|
||||
std::ostringstream os;
|
||||
os << "Failed to read wave";
|
||||
Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
bool enable_external_buffer = true;
|
||||
if (info.Length() == 2) {
|
||||
if (info[1].IsBoolean()) {
|
||||
enable_external_buffer = info[1].As<Napi::Boolean>().Value();
|
||||
} else {
|
||||
Napi::TypeError::New(env, "Argument 1 should be a boolean")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
if (enable_external_buffer) {
|
||||
Napi::ArrayBuffer arrayBuffer = Napi::ArrayBuffer::New(
|
||||
env, const_cast<float *>(wave->samples),
|
||||
sizeof(float) * wave->num_samples,
|
||||
[](Napi::Env /*env*/, void * /*data*/, const SherpaOnnxWave *hint) {
|
||||
SherpaOnnxFreeWave(hint);
|
||||
},
|
||||
wave);
|
||||
Napi::Float32Array float32Array =
|
||||
Napi::Float32Array::New(env, wave->num_samples, arrayBuffer, 0);
|
||||
|
||||
Napi::Object obj = Napi::Object::New(env);
|
||||
obj.Set(Napi::String::New(env, "samples"), float32Array);
|
||||
obj.Set(Napi::String::New(env, "sampleRate"), wave->sample_rate);
|
||||
return obj;
|
||||
} else {
|
||||
// don't use external buffer
|
||||
Napi::ArrayBuffer arrayBuffer =
|
||||
Napi::ArrayBuffer::New(env, sizeof(float) * wave->num_samples);
|
||||
|
||||
Napi::Float32Array float32Array =
|
||||
Napi::Float32Array::New(env, wave->num_samples, arrayBuffer, 0);
|
||||
|
||||
std::copy(wave->samples, wave->samples + wave->num_samples,
|
||||
float32Array.Data());
|
||||
|
||||
Napi::Object obj = Napi::Object::New(env);
|
||||
obj.Set(Napi::String::New(env, "samples"), float32Array);
|
||||
obj.Set(Napi::String::New(env, "sampleRate"), wave->sample_rate);
|
||||
|
||||
SherpaOnnxFreeWave(wave);
|
||||
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
|
||||
void InitWaveReader(Napi::Env env, Napi::Object exports) {
|
||||
exports.Set(Napi::String::New(env, "readWave"),
|
||||
Napi::Function::New(env, ReadWaveWrapper));
|
||||
|
||||
exports.Set(Napi::String::New(env, "readWaveFromBinary"),
|
||||
Napi::Function::New(env, ReadWaveFromBinaryWrapper));
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
// scripts/node-addon-api/src/wave-writer.cc
|
||||
//
|
||||
// Copyright (c) 2024 Xiaomi Corporation
|
||||
|
||||
#include <sstream>
|
||||
|
||||
#include "napi.h" // NOLINT
|
||||
#include "sherpa-onnx/c-api/c-api.h"
|
||||
|
||||
// (filename, {samples: samples, sampleRate: sampleRate}
|
||||
static Napi::Boolean WriteWaveWrapper(const Napi::CallbackInfo &info) {
|
||||
Napi::Env env = info.Env();
|
||||
|
||||
if (info.Length() != 2) {
|
||||
std::ostringstream os;
|
||||
os << "Expect only 2 arguments. Given: " << info.Length();
|
||||
|
||||
Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!info[0].IsString()) {
|
||||
Napi::TypeError::New(env, "Argument 0 should be a string")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!info[1].IsObject()) {
|
||||
Napi::TypeError::New(env, "Argument 1 should be an object")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
Napi::Object obj = info[1].As<Napi::Object>();
|
||||
|
||||
if (!obj.Has("samples")) {
|
||||
Napi::TypeError::New(env, "The argument object should have a field samples")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!obj.Get("samples").IsTypedArray()) {
|
||||
Napi::TypeError::New(env, "The object['samples'] should be a typed array")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!obj.Has("sampleRate")) {
|
||||
Napi::TypeError::New(env,
|
||||
"The argument object should have a field sampleRate")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!obj.Get("sampleRate").IsNumber()) {
|
||||
Napi::TypeError::New(env, "The object['samples'] should be a number")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
Napi::Float32Array samples = obj.Get("samples").As<Napi::Float32Array>();
|
||||
int32_t sample_rate = obj.Get("sampleRate").As<Napi::Number>().Int32Value();
|
||||
|
||||
int32_t ok =
|
||||
SherpaOnnxWriteWave(samples.Data(), samples.ElementLength(), sample_rate,
|
||||
info[0].As<Napi::String>().Utf8Value().c_str());
|
||||
|
||||
return Napi::Boolean::New(env, ok);
|
||||
}
|
||||
|
||||
void InitWaveWriter(Napi::Env env, Napi::Object exports) {
|
||||
exports.Set(Napi::String::New(env, "writeWave"),
|
||||
Napi::Function::New(env, WriteWaveWrapper));
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
import hilog from '@ohos.hilog';
|
||||
import testNapi from 'libsherpa_onnx.so';
|
||||
|
||||
@Component
|
||||
export struct MainPage {
|
||||
@State message: string = 'Hello World';
|
||||
|
||||
build() {
|
||||
Row() {
|
||||
Column() {
|
||||
Text(this.message)
|
||||
.fontSize(50)
|
||||
.fontWeight(FontWeight.Bold)
|
||||
.onClick(() => {
|
||||
})
|
||||
}
|
||||
.width('100%')
|
||||
}
|
||||
.height('100%')
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,162 @@
|
||||
import {
|
||||
acceptWaveformOffline,
|
||||
createOfflineRecognizer,
|
||||
createOfflineStream,
|
||||
decodeOfflineStream,
|
||||
getOfflineStreamResultAsJson,
|
||||
} from 'libsherpa_onnx.so';
|
||||
|
||||
export interface Samples {
|
||||
samples: Float32Array;
|
||||
sampleRate: number;
|
||||
}
|
||||
|
||||
export class OfflineStream {
|
||||
public handle: object;
|
||||
|
||||
constructor(handle: object) {
|
||||
this.handle = handle;
|
||||
}
|
||||
|
||||
// obj is {samples: samples, sampleRate: sampleRate}
|
||||
// samples is a float32 array containing samples in the range [-1, 1]
|
||||
// sampleRate is a number
|
||||
acceptWaveform(obj: Samples) {
|
||||
acceptWaveformOffline(this.handle, obj)
|
||||
}
|
||||
}
|
||||
|
||||
export class FeatureConfig {
|
||||
public sampleRate: number = 16000;
|
||||
public featureDim: number = 80;
|
||||
}
|
||||
|
||||
export class OfflineTransducerModelConfig {
|
||||
public encoder: string = '';
|
||||
public decoder: string = '';
|
||||
public joiner: string = '';
|
||||
}
|
||||
|
||||
export class OfflineParaformerModelConfig {
|
||||
public model: string = '';
|
||||
}
|
||||
|
||||
export class OfflineNemoEncDecCtcModelConfig {
|
||||
public model: string = '';
|
||||
}
|
||||
|
||||
export class OfflineWhisperModelConfig {
|
||||
public encoder: string = '';
|
||||
public decoder: string = '';
|
||||
public language: string = '';
|
||||
public task: string = 'transcribe';
|
||||
public tailPaddings: number = -1;
|
||||
}
|
||||
|
||||
export class OfflineTdnnModelConfig {
|
||||
public model: string = '';
|
||||
}
|
||||
|
||||
export class OfflineSenseVoiceModelConfig {
|
||||
public model: string = '';
|
||||
public language: string = '';
|
||||
public useItn: boolean = false;
|
||||
}
|
||||
|
||||
export class OfflineMoonshineModelConfig {
|
||||
public preprocessor: string = '';
|
||||
public encoder: string = '';
|
||||
public uncachedDecoder: string = '';
|
||||
public cachedDecoder: string = '';
|
||||
}
|
||||
|
||||
export class OfflineModelConfig {
|
||||
public transducer: OfflineTransducerModelConfig = new OfflineTransducerModelConfig();
|
||||
public paraformer: OfflineParaformerModelConfig = new OfflineParaformerModelConfig();
|
||||
public nemoCtc: OfflineNemoEncDecCtcModelConfig = new OfflineNemoEncDecCtcModelConfig();
|
||||
public whisper: OfflineWhisperModelConfig = new OfflineWhisperModelConfig();
|
||||
public tdnn: OfflineTdnnModelConfig = new OfflineTdnnModelConfig();
|
||||
public tokens: string = '';
|
||||
public numThreads: number = 1;
|
||||
public debug: boolean = false;
|
||||
public provider: string = "cpu";
|
||||
public modelType: string = '';
|
||||
public modelingUnit: string = "cjkchar";
|
||||
public bpeVocab: string = '';
|
||||
public telespeechCtc: string = '';
|
||||
public senseVoice: OfflineSenseVoiceModelConfig = new OfflineSenseVoiceModelConfig();
|
||||
public moonshine: OfflineMoonshineModelConfig = new OfflineMoonshineModelConfig();
|
||||
}
|
||||
|
||||
export class OfflineLMConfig {
|
||||
public model: string = '';
|
||||
public scale: number = 1.0;
|
||||
}
|
||||
|
||||
export class OfflineRecognizerConfig {
|
||||
public featConfig: FeatureConfig = new FeatureConfig();
|
||||
public modelConfig: OfflineModelConfig = new OfflineModelConfig();
|
||||
public lmConfig: OfflineLMConfig = new OfflineLMConfig();
|
||||
public decodingMethod: string = "greedy_search";
|
||||
public maxActivePaths: number = 4;
|
||||
public hotwordsFfile: string = '';
|
||||
public hotwordsScore: number = 1.5;
|
||||
public ruleFsts: string = '';
|
||||
public ruleFars: string = '';
|
||||
public blankPenalty: number = 0;
|
||||
}
|
||||
|
||||
export class OfflineRecognizerResult {
|
||||
public text: string = '';
|
||||
public timestamps: number[] = [];
|
||||
public tokens: string[] = [];
|
||||
public json = '';
|
||||
public lang: string = '';
|
||||
public emotion: string = '';
|
||||
public event: string = '';
|
||||
}
|
||||
|
||||
interface OfflineRecognizerResultJson {
|
||||
text: string;
|
||||
timestamps: number[];
|
||||
tokens: string[];
|
||||
lang: string;
|
||||
emotion: string;
|
||||
event: string;
|
||||
}
|
||||
|
||||
export class OfflineRecognizer {
|
||||
public handle: object;
|
||||
public config: OfflineRecognizerConfig;
|
||||
|
||||
constructor(config: OfflineRecognizerConfig, mgr?: object) {
|
||||
this.handle = createOfflineRecognizer(config, mgr);
|
||||
this.config = config
|
||||
}
|
||||
|
||||
createStream(): OfflineStream {
|
||||
const handle: object = createOfflineStream(this.handle);
|
||||
return new OfflineStream(handle);
|
||||
}
|
||||
|
||||
decode(stream: OfflineStream) {
|
||||
decodeOfflineStream(this.handle, stream.handle);
|
||||
}
|
||||
|
||||
getResult(stream: OfflineStream): OfflineRecognizerResult {
|
||||
const jsonStr: string = getOfflineStreamResultAsJson(stream.handle);
|
||||
|
||||
let o = JSON.parse(jsonStr) as OfflineRecognizerResultJson;
|
||||
|
||||
const r = new OfflineRecognizerResult()
|
||||
r.text = o.text
|
||||
r.timestamps = o.timestamps;
|
||||
r.tokens = o.tokens;
|
||||
r.json = jsonStr;
|
||||
r.lang = o.lang;
|
||||
r.emotion = o.emotion;
|
||||
r.event = o.event;
|
||||
|
||||
return r;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,141 @@
|
||||
import {
|
||||
acceptWaveformOnline,
|
||||
createOnlineRecognizer,
|
||||
createOnlineStream,
|
||||
decodeOnlineStream,
|
||||
getOnlineStreamResultAsJson,
|
||||
inputFinished,
|
||||
isEndpoint,
|
||||
isOnlineStreamReady,
|
||||
reset,
|
||||
} from 'libsherpa_onnx.so';
|
||||
|
||||
import { FeatureConfig, Samples } from './NonStreamingAsr';
|
||||
|
||||
export class OnlineStream {
|
||||
public handle: object;
|
||||
|
||||
constructor(handle: object) {
|
||||
this.handle = handle;
|
||||
}
|
||||
|
||||
// obj is {samples: samples, sampleRate: sampleRate}
|
||||
// samples is a float32 array containing samples in the range [-1, 1]
|
||||
// sampleRate is a number
|
||||
acceptWaveform(obj: Samples) {
|
||||
acceptWaveformOnline(this.handle, obj)
|
||||
}
|
||||
|
||||
inputFinished() {
|
||||
inputFinished(this.handle)
|
||||
}
|
||||
}
|
||||
|
||||
export class OnlineTransducerModelConfig {
|
||||
public encoder: string = '';
|
||||
public decoder: string = '';
|
||||
public joiner: string = '';
|
||||
}
|
||||
|
||||
export class OnlineParaformerModelConfig {
|
||||
public encoder: string = '';
|
||||
public decoder: string = '';
|
||||
}
|
||||
|
||||
export class OnlineZipformer2CtcModelConfig {
|
||||
public model: string = '';
|
||||
}
|
||||
|
||||
export class OnlineModelConfig {
|
||||
public transducer: OnlineTransducerModelConfig = new OnlineTransducerModelConfig();
|
||||
public paraformer: OnlineParaformerModelConfig = new OnlineParaformerModelConfig();
|
||||
public zipformer2_ctc: OnlineZipformer2CtcModelConfig = new OnlineZipformer2CtcModelConfig();
|
||||
public tokens: string = '';
|
||||
public numThreads: number = 1;
|
||||
public provider: string = "cpu";
|
||||
public debug: boolean = false;
|
||||
public modelType: string = '';
|
||||
public modelingUnit: string = "cjkchar";
|
||||
public bpeVocab: string = '';
|
||||
}
|
||||
|
||||
export class OnlineCtcFstDecoderConfig {
|
||||
public graph: string = '';
|
||||
public maxActive: number = 3000;
|
||||
}
|
||||
|
||||
export class OnlineRecognizerConfig {
|
||||
public featConfig: FeatureConfig = new FeatureConfig();
|
||||
public modelConfig: OnlineModelConfig = new OnlineModelConfig();
|
||||
public decodingMethod: string = "greedy_search";
|
||||
public maxActivePaths: number = 4;
|
||||
public enableEndpoint: boolean = false;
|
||||
public rule1MinTrailingSilence: number = 2.4;
|
||||
public rule2MinTrailingSilence: number = 1.2;
|
||||
public rule3MinUtteranceLength: number = 20;
|
||||
public hotwordsFile: string = '';
|
||||
public hotwordsScore: number = 1.5;
|
||||
public ctcFstDecoderConfig: OnlineCtcFstDecoderConfig = new OnlineCtcFstDecoderConfig();
|
||||
public ruleFsts: string = '';
|
||||
public ruleFars: string = '';
|
||||
public blankPenalty: number = 0;
|
||||
}
|
||||
|
||||
interface OnlineRecognizerResultJson {
|
||||
text: string;
|
||||
timestamps: number[];
|
||||
tokens: string[];
|
||||
}
|
||||
|
||||
export class OnlineRecognizerResult {
|
||||
public text: string = '';
|
||||
public tokens: string[] = [];
|
||||
public timestamps: number[] = [];
|
||||
public json: string = '';
|
||||
}
|
||||
|
||||
export class OnlineRecognizer {
|
||||
public handle: object;
|
||||
public config: OnlineRecognizerConfig
|
||||
|
||||
constructor(config: OnlineRecognizerConfig, mgr?: object) {
|
||||
this.handle = createOnlineRecognizer(config, mgr);
|
||||
this.config = config
|
||||
}
|
||||
|
||||
createStream(): OnlineStream {
|
||||
const handle: object = createOnlineStream(this.handle);
|
||||
return new OnlineStream(handle);
|
||||
}
|
||||
|
||||
isReady(stream: OnlineStream): boolean {
|
||||
return isOnlineStreamReady(this.handle, stream.handle);
|
||||
}
|
||||
|
||||
decode(stream: OnlineStream) {
|
||||
decodeOnlineStream(this.handle, stream.handle);
|
||||
}
|
||||
|
||||
isEndpoint(stream: OnlineStream): boolean {
|
||||
return isEndpoint(this.handle, stream.handle);
|
||||
}
|
||||
|
||||
reset(stream: OnlineStream) {
|
||||
reset(this.handle, stream.handle);
|
||||
}
|
||||
|
||||
getResult(stream: OnlineStream): OnlineRecognizerResult {
|
||||
const jsonStr: string =
|
||||
getOnlineStreamResultAsJson(this.handle, stream.handle);
|
||||
|
||||
let o = JSON.parse(jsonStr) as OnlineRecognizerResultJson;
|
||||
|
||||
const r = new OnlineRecognizerResult()
|
||||
r.text = o.text
|
||||
r.timestamps = o.timestamps;
|
||||
r.tokens = o.tokens;
|
||||
r.json = jsonStr;
|
||||
|
||||
return r;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
import {
|
||||
circularBufferGet,
|
||||
circularBufferHead,
|
||||
circularBufferPop,
|
||||
circularBufferPush,
|
||||
circularBufferReset,
|
||||
circularBufferSize,
|
||||
createCircularBuffer,
|
||||
createVoiceActivityDetector,
|
||||
voiceActivityDetectorAcceptWaveform,
|
||||
voiceActivityDetectorClear,
|
||||
voiceActivityDetectorFlush,
|
||||
voiceActivityDetectorFront,
|
||||
voiceActivityDetectorIsDetected,
|
||||
voiceActivityDetectorIsEmpty,
|
||||
voiceActivityDetectorPop,
|
||||
voiceActivityDetectorReset,
|
||||
} from 'libsherpa_onnx.so';
|
||||
|
||||
export class SileroVadConfig {
|
||||
public model: string;
|
||||
public threshold: number;
|
||||
public minSpeechDuration: number;
|
||||
public minSilenceDuration: number;
|
||||
public windowSize: number;
|
||||
|
||||
public constructor(model: string, threshold: number, minSpeechDuration: number, minSilenceDuration: number,
|
||||
windowSize: number) {
|
||||
this.model = model;
|
||||
this.threshold = threshold;
|
||||
this.minSpeechDuration = minSpeechDuration;
|
||||
this.minSilenceDuration = minSilenceDuration;
|
||||
this.windowSize = windowSize;
|
||||
}
|
||||
}
|
||||
|
||||
export class VadConfig {
|
||||
public sileroVad: SileroVadConfig;
|
||||
public sampleRate: number;
|
||||
public debug: boolean;
|
||||
public numThreads: number;
|
||||
|
||||
public constructor(sileroVad: SileroVadConfig, sampleRate: number, debug: boolean, numThreads: number) {
|
||||
this.sileroVad = sileroVad;
|
||||
this.sampleRate = sampleRate;
|
||||
this.debug = debug;
|
||||
this.numThreads = numThreads;
|
||||
}
|
||||
}
|
||||
|
||||
export class CircularBuffer {
|
||||
private handle: object;
|
||||
|
||||
constructor(capacity: number) {
|
||||
this.handle = createCircularBuffer(capacity);
|
||||
}
|
||||
|
||||
// samples is a float32 array
|
||||
push(samples: Float32Array) {
|
||||
console.log(`here samples: ${samples}`);
|
||||
circularBufferPush(this.handle, samples);
|
||||
}
|
||||
|
||||
// return a float32 array
|
||||
get(startIndex: number, n: number, enableExternalBuffer: boolean = true): Float32Array {
|
||||
return circularBufferGet(
|
||||
this.handle, startIndex, n, enableExternalBuffer);
|
||||
}
|
||||
|
||||
pop(n: number) {
|
||||
circularBufferPop(this.handle, n);
|
||||
}
|
||||
|
||||
size(): number {
|
||||
return circularBufferSize(this.handle);
|
||||
}
|
||||
|
||||
head(): number {
|
||||
return circularBufferHead(this.handle);
|
||||
}
|
||||
|
||||
reset() {
|
||||
circularBufferReset(this.handle);
|
||||
}
|
||||
}
|
||||
|
||||
export interface SpeechSegment {
|
||||
samples: Float32Array;
|
||||
start: number;
|
||||
}
|
||||
|
||||
export class Vad {
|
||||
public config: VadConfig;
|
||||
private handle: object;
|
||||
|
||||
constructor(config: VadConfig, bufferSizeInSeconds?: number, mgr?: object) {
|
||||
this.handle =
|
||||
createVoiceActivityDetector(config, bufferSizeInSeconds, mgr);
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
acceptWaveform(samples: Float32Array): void {
|
||||
voiceActivityDetectorAcceptWaveform(this.handle, samples);
|
||||
}
|
||||
|
||||
isEmpty(): boolean {
|
||||
return voiceActivityDetectorIsEmpty(this.handle);
|
||||
}
|
||||
|
||||
isDetected(): boolean {
|
||||
return voiceActivityDetectorIsDetected(this.handle);
|
||||
}
|
||||
|
||||
pop(): void {
|
||||
voiceActivityDetectorPop(this.handle);
|
||||
}
|
||||
|
||||
clear(): void {
|
||||
voiceActivityDetectorClear(this.handle);
|
||||
}
|
||||
|
||||
front(enableExternalBuffer = true): SpeechSegment {
|
||||
return voiceActivityDetectorFront(this.handle, enableExternalBuffer);
|
||||
}
|
||||
|
||||
reset(): void {
|
||||
voiceActivityDetectorReset(this.handle);
|
||||
}
|
||||
|
||||
flush(): void {
|
||||
voiceActivityDetectorFlush(this.handle);
|
||||
}
|
||||
}
|
||||
11
harmony-os/SherpaOnnxHar/sherpa_onnx/src/main/module.json5
Normal file
11
harmony-os/SherpaOnnxHar/sherpa_onnx/src/main/module.json5
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"module": {
|
||||
"name": "sherpa_onnx",
|
||||
"type": "har",
|
||||
"deviceTypes": [
|
||||
"default",
|
||||
"tablet",
|
||||
"2in1"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"string": [
|
||||
{
|
||||
"name": "page_show",
|
||||
"value": "page from package"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"string": [
|
||||
{
|
||||
"name": "page_show",
|
||||
"value": "page from package"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"string": [
|
||||
{
|
||||
"name": "page_show",
|
||||
"value": "page from package"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
import hilog from '@ohos.hilog';
|
||||
import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from '@ohos/hypium';
|
||||
|
||||
export default function abilityTest() {
|
||||
describe('ActsAbilityTest', () => {
|
||||
// Defines a test suite. Two parameters are supported: test suite name and test suite function.
|
||||
beforeAll(() => {
|
||||
// Presets an action, which is performed only once before all test cases of the test suite start.
|
||||
// This API supports only one parameter: preset action function.
|
||||
})
|
||||
beforeEach(() => {
|
||||
// Presets an action, which is performed before each unit test case starts.
|
||||
// The number of execution times is the same as the number of test cases defined by **it**.
|
||||
// This API supports only one parameter: preset action function.
|
||||
})
|
||||
afterEach(() => {
|
||||
// Presets a clear action, which is performed after each unit test case ends.
|
||||
// The number of execution times is the same as the number of test cases defined by **it**.
|
||||
// This API supports only one parameter: clear action function.
|
||||
})
|
||||
afterAll(() => {
|
||||
// Presets a clear action, which is performed after all test cases of the test suite end.
|
||||
// This API supports only one parameter: clear action function.
|
||||
})
|
||||
it('assertContain', 0, () => {
|
||||
// Defines a test case. This API supports three parameters: test case name, filter parameter, and test case function.
|
||||
hilog.info(0x0000, 'testTag', '%{public}s', 'it begin');
|
||||
let a = 'abc';
|
||||
let b = 'b';
|
||||
// Defines a variety of assertion methods, which are used to declare expected boolean conditions.
|
||||
expect(a).assertContain(b);
|
||||
expect(a).assertEqual(a);
|
||||
})
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
import abilityTest from './Ability.test';
|
||||
|
||||
export default function testsuite() {
|
||||
abilityTest();
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"module": {
|
||||
"name": "sherpa_onnx_test",
|
||||
"type": "feature",
|
||||
"deviceTypes": [
|
||||
"default",
|
||||
"tablet",
|
||||
"2in1"
|
||||
],
|
||||
"deliveryWithInstall": true,
|
||||
"installationFree": false
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
import localUnitTest from './LocalUnit.test';
|
||||
|
||||
export default function testsuite() {
|
||||
localUnitTest();
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from '@ohos/hypium';
|
||||
|
||||
export default function localUnitTest() {
|
||||
describe('localUnitTest', () => {
|
||||
// Defines a test suite. Two parameters are supported: test suite name and test suite function.
|
||||
beforeAll(() => {
|
||||
// Presets an action, which is performed only once before all test cases of the test suite start.
|
||||
// This API supports only one parameter: preset action function.
|
||||
});
|
||||
beforeEach(() => {
|
||||
// Presets an action, which is performed before each unit test case starts.
|
||||
// The number of execution times is the same as the number of test cases defined by **it**.
|
||||
// This API supports only one parameter: preset action function.
|
||||
});
|
||||
afterEach(() => {
|
||||
// Presets a clear action, which is performed after each unit test case ends.
|
||||
// The number of execution times is the same as the number of test cases defined by **it**.
|
||||
// This API supports only one parameter: clear action function.
|
||||
});
|
||||
afterAll(() => {
|
||||
// Presets a clear action, which is performed after all test cases of the test suite end.
|
||||
// This API supports only one parameter: clear action function.
|
||||
});
|
||||
it('assertContain', 0, () => {
|
||||
// Defines a test case. This API supports three parameters: test case name, filter parameter, and test case function.
|
||||
let a = 'abc';
|
||||
let b = 'b';
|
||||
// Defines a variety of assertion methods, which are used to declare expected boolean conditions.
|
||||
expect(a).assertContain(b);
|
||||
expect(a).assertEqual(a);
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -1,227 +0,0 @@
|
||||
// scripts/node-addon-api/src/audio-tagging.cc
|
||||
//
|
||||
// Copyright (c) 2024 Xiaomi Corporation
|
||||
#include <sstream>
|
||||
|
||||
#include "macros.h" // NOLINT
|
||||
#include "napi.h" // NOLINT
|
||||
#include "sherpa-onnx/c-api/c-api.h"
|
||||
|
||||
static SherpaOnnxOfflineZipformerAudioTaggingModelConfig
|
||||
GetAudioTaggingZipformerModelConfig(Napi::Object obj) {
|
||||
SherpaOnnxOfflineZipformerAudioTaggingModelConfig c;
|
||||
memset(&c, 0, sizeof(c));
|
||||
|
||||
if (!obj.Has("zipformer") || !obj.Get("zipformer").IsObject()) {
|
||||
return c;
|
||||
}
|
||||
|
||||
Napi::Object o = obj.Get("zipformer").As<Napi::Object>();
|
||||
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(model, model);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
static SherpaOnnxAudioTaggingModelConfig GetAudioTaggingModelConfig(
|
||||
Napi::Object obj) {
|
||||
SherpaOnnxAudioTaggingModelConfig c;
|
||||
memset(&c, 0, sizeof(c));
|
||||
|
||||
if (!obj.Has("model") || !obj.Get("model").IsObject()) {
|
||||
return c;
|
||||
}
|
||||
|
||||
Napi::Object o = obj.Get("model").As<Napi::Object>();
|
||||
c.zipformer = GetAudioTaggingZipformerModelConfig(o);
|
||||
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(ced, ced);
|
||||
|
||||
SHERPA_ONNX_ASSIGN_ATTR_INT32(num_threads, numThreads);
|
||||
|
||||
if (o.Has("debug") &&
|
||||
(o.Get("debug").IsNumber() || o.Get("debug").IsBoolean())) {
|
||||
if (o.Get("debug").IsBoolean()) {
|
||||
c.debug = o.Get("debug").As<Napi::Boolean>().Value();
|
||||
} else {
|
||||
c.debug = o.Get("debug").As<Napi::Number>().Int32Value();
|
||||
}
|
||||
}
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(provider, provider);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
static Napi::External<SherpaOnnxAudioTagging> CreateAudioTaggingWrapper(
|
||||
const Napi::CallbackInfo &info) {
|
||||
Napi::Env env = info.Env();
|
||||
if (info.Length() != 1) {
|
||||
std::ostringstream os;
|
||||
os << "Expect only 1 argument. Given: " << info.Length();
|
||||
|
||||
Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!info[0].IsObject()) {
|
||||
Napi::TypeError::New(env, "You should pass an object as the only argument.")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
Napi::Object o = info[0].As<Napi::Object>();
|
||||
|
||||
SherpaOnnxAudioTaggingConfig c;
|
||||
memset(&c, 0, sizeof(c));
|
||||
c.model = GetAudioTaggingModelConfig(o);
|
||||
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(labels, labels);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_INT32(top_k, topK);
|
||||
|
||||
const SherpaOnnxAudioTagging *at = SherpaOnnxCreateAudioTagging(&c);
|
||||
|
||||
if (c.model.zipformer.model) {
|
||||
delete[] c.model.zipformer.model;
|
||||
}
|
||||
|
||||
if (c.model.ced) {
|
||||
delete[] c.model.ced;
|
||||
}
|
||||
|
||||
if (c.model.provider) {
|
||||
delete[] c.model.provider;
|
||||
}
|
||||
|
||||
if (c.labels) {
|
||||
delete[] c.labels;
|
||||
}
|
||||
|
||||
if (!at) {
|
||||
Napi::TypeError::New(env, "Please check your config!")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
return Napi::External<SherpaOnnxAudioTagging>::New(
|
||||
env, const_cast<SherpaOnnxAudioTagging *>(at),
|
||||
[](Napi::Env env, SherpaOnnxAudioTagging *at) {
|
||||
SherpaOnnxDestroyAudioTagging(at);
|
||||
});
|
||||
}
|
||||
|
||||
static Napi::External<SherpaOnnxOfflineStream>
|
||||
AudioTaggingCreateOfflineStreamWrapper(const Napi::CallbackInfo &info) {
|
||||
Napi::Env env = info.Env();
|
||||
if (info.Length() != 1) {
|
||||
std::ostringstream os;
|
||||
os << "Expect only 1 argument. Given: " << info.Length();
|
||||
|
||||
Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!info[0].IsExternal()) {
|
||||
Napi::TypeError::New(
|
||||
env, "You should pass an audio tagging pointer as the only argument")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
SherpaOnnxAudioTagging *at =
|
||||
info[0].As<Napi::External<SherpaOnnxAudioTagging>>().Data();
|
||||
|
||||
const SherpaOnnxOfflineStream *stream =
|
||||
SherpaOnnxAudioTaggingCreateOfflineStream(at);
|
||||
|
||||
return Napi::External<SherpaOnnxOfflineStream>::New(
|
||||
env, const_cast<SherpaOnnxOfflineStream *>(stream),
|
||||
[](Napi::Env env, SherpaOnnxOfflineStream *stream) {
|
||||
SherpaOnnxDestroyOfflineStream(stream);
|
||||
});
|
||||
}
|
||||
|
||||
static Napi::Object AudioTaggingComputeWrapper(const Napi::CallbackInfo &info) {
|
||||
Napi::Env env = info.Env();
|
||||
if (info.Length() != 3) {
|
||||
std::ostringstream os;
|
||||
os << "Expect only 3 arguments. Given: " << info.Length();
|
||||
|
||||
Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!info[0].IsExternal()) {
|
||||
Napi::TypeError::New(
|
||||
env, "You should pass an audio tagging pointer as the first argument")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!info[1].IsExternal()) {
|
||||
Napi::TypeError::New(
|
||||
env, "You should pass an offline stream pointer as the second argument")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!info[2].IsNumber()) {
|
||||
Napi::TypeError::New(env,
|
||||
"You should pass an integer as the third argument")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
SherpaOnnxAudioTagging *at =
|
||||
info[0].As<Napi::External<SherpaOnnxAudioTagging>>().Data();
|
||||
|
||||
SherpaOnnxOfflineStream *stream =
|
||||
info[1].As<Napi::External<SherpaOnnxOfflineStream>>().Data();
|
||||
|
||||
int32_t top_k = info[2].As<Napi::Number>().Int32Value();
|
||||
|
||||
const SherpaOnnxAudioEvent *const *events =
|
||||
SherpaOnnxAudioTaggingCompute(at, stream, top_k);
|
||||
|
||||
auto p = events;
|
||||
int32_t k = 0;
|
||||
while (p && *p) {
|
||||
++k;
|
||||
++p;
|
||||
}
|
||||
|
||||
Napi::Array ans = Napi::Array::New(env, k);
|
||||
for (uint32_t i = 0; i != k; ++i) {
|
||||
Napi::Object obj = Napi::Object::New(env);
|
||||
obj.Set(Napi::String::New(env, "name"),
|
||||
Napi::String::New(env, events[i]->name));
|
||||
obj.Set(Napi::String::New(env, "index"),
|
||||
Napi::Number::New(env, events[i]->index));
|
||||
obj.Set(Napi::String::New(env, "prob"),
|
||||
Napi::Number::New(env, events[i]->prob));
|
||||
ans[i] = obj;
|
||||
}
|
||||
|
||||
SherpaOnnxAudioTaggingFreeResults(events);
|
||||
|
||||
return ans;
|
||||
}
|
||||
|
||||
void InitAudioTagging(Napi::Env env, Napi::Object exports) {
|
||||
exports.Set(Napi::String::New(env, "createAudioTagging"),
|
||||
Napi::Function::New(env, CreateAudioTaggingWrapper));
|
||||
|
||||
exports.Set(Napi::String::New(env, "audioTaggingCreateOfflineStream"),
|
||||
Napi::Function::New(env, AudioTaggingCreateOfflineStreamWrapper));
|
||||
|
||||
exports.Set(Napi::String::New(env, "audioTaggingCompute"),
|
||||
Napi::Function::New(env, AudioTaggingComputeWrapper));
|
||||
}
|
||||
1
scripts/node-addon-api/src/audio-tagging.cc
Symbolic link
1
scripts/node-addon-api/src/audio-tagging.cc
Symbolic link
@@ -0,0 +1 @@
|
||||
../../../harmony-os/SherpaOnnxHar/sherpa_onnx/src/main/cpp/audio-tagging.cc
|
||||
@@ -1,266 +0,0 @@
|
||||
// scripts/node-addon-api/src/keyword-spotting.cc
|
||||
//
|
||||
// Copyright (c) 2024 Xiaomi Corporation
|
||||
#include <sstream>
|
||||
|
||||
#include "macros.h" // NOLINT
|
||||
#include "napi.h" // NOLINT
|
||||
#include "sherpa-onnx/c-api/c-api.h"
|
||||
|
||||
// defined ./streaming-asr.cc
|
||||
SherpaOnnxFeatureConfig GetFeatureConfig(Napi::Object obj);
|
||||
|
||||
// defined ./streaming-asr.cc
|
||||
SherpaOnnxOnlineModelConfig GetOnlineModelConfig(Napi::Object obj);
|
||||
|
||||
static Napi::External<SherpaOnnxKeywordSpotter> CreateKeywordSpotterWrapper(
|
||||
const Napi::CallbackInfo &info) {
|
||||
Napi::Env env = info.Env();
|
||||
if (info.Length() != 1) {
|
||||
std::ostringstream os;
|
||||
os << "Expect only 1 argument. Given: " << info.Length();
|
||||
|
||||
Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!info[0].IsObject()) {
|
||||
Napi::TypeError::New(env, "Expect an object as the argument")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
Napi::Object o = info[0].As<Napi::Object>();
|
||||
SherpaOnnxKeywordSpotterConfig c;
|
||||
memset(&c, 0, sizeof(c));
|
||||
c.feat_config = GetFeatureConfig(o);
|
||||
c.model_config = GetOnlineModelConfig(o);
|
||||
|
||||
SHERPA_ONNX_ASSIGN_ATTR_INT32(max_active_paths, maxActivePaths);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_INT32(num_trailing_blanks, numTrailingBlanks);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_FLOAT(keywords_score, keywordsScore);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_FLOAT(keywords_threshold, keywordsThreshold);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(keywords_file, keywordsFile);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(keywords_buf, keywordsBuf);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_INT32(keywords_buf_size, keywordsBufSize);
|
||||
|
||||
SherpaOnnxKeywordSpotter *kws = SherpaOnnxCreateKeywordSpotter(&c);
|
||||
|
||||
if (c.model_config.transducer.encoder) {
|
||||
delete[] c.model_config.transducer.encoder;
|
||||
}
|
||||
|
||||
if (c.model_config.transducer.decoder) {
|
||||
delete[] c.model_config.transducer.decoder;
|
||||
}
|
||||
|
||||
if (c.model_config.transducer.joiner) {
|
||||
delete[] c.model_config.transducer.joiner;
|
||||
}
|
||||
|
||||
if (c.model_config.paraformer.encoder) {
|
||||
delete[] c.model_config.paraformer.encoder;
|
||||
}
|
||||
|
||||
if (c.model_config.paraformer.decoder) {
|
||||
delete[] c.model_config.paraformer.decoder;
|
||||
}
|
||||
|
||||
if (c.model_config.zipformer2_ctc.model) {
|
||||
delete[] c.model_config.zipformer2_ctc.model;
|
||||
}
|
||||
|
||||
if (c.model_config.tokens) {
|
||||
delete[] c.model_config.tokens;
|
||||
}
|
||||
|
||||
if (c.model_config.provider) {
|
||||
delete[] c.model_config.provider;
|
||||
}
|
||||
|
||||
if (c.model_config.model_type) {
|
||||
delete[] c.model_config.model_type;
|
||||
}
|
||||
|
||||
if (c.keywords_file) {
|
||||
delete[] c.keywords_file;
|
||||
}
|
||||
|
||||
if (c.keywords_buf) {
|
||||
delete[] c.keywords_buf;
|
||||
}
|
||||
|
||||
if (!kws) {
|
||||
Napi::TypeError::New(env, "Please check your config!")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
return Napi::External<SherpaOnnxKeywordSpotter>::New(
|
||||
env, kws, [](Napi::Env env, SherpaOnnxKeywordSpotter *kws) {
|
||||
SherpaOnnxDestroyKeywordSpotter(kws);
|
||||
});
|
||||
}
|
||||
|
||||
static Napi::External<SherpaOnnxOnlineStream> CreateKeywordStreamWrapper(
|
||||
const Napi::CallbackInfo &info) {
|
||||
Napi::Env env = info.Env();
|
||||
if (info.Length() != 1) {
|
||||
std::ostringstream os;
|
||||
os << "Expect only 1 argument. Given: " << info.Length();
|
||||
|
||||
Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!info[0].IsExternal()) {
|
||||
Napi::TypeError::New(
|
||||
env, "You should pass a keyword spotter pointer as the only argument")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
SherpaOnnxKeywordSpotter *kws =
|
||||
info[0].As<Napi::External<SherpaOnnxKeywordSpotter>>().Data();
|
||||
|
||||
SherpaOnnxOnlineStream *stream = SherpaOnnxCreateKeywordStream(kws);
|
||||
|
||||
return Napi::External<SherpaOnnxOnlineStream>::New(
|
||||
env, stream, [](Napi::Env env, SherpaOnnxOnlineStream *stream) {
|
||||
SherpaOnnxDestroyOnlineStream(stream);
|
||||
});
|
||||
}
|
||||
|
||||
static Napi::Boolean IsKeywordStreamReadyWrapper(
|
||||
const Napi::CallbackInfo &info) {
|
||||
Napi::Env env = info.Env();
|
||||
if (info.Length() != 2) {
|
||||
std::ostringstream os;
|
||||
os << "Expect only 2 arguments. Given: " << info.Length();
|
||||
|
||||
Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!info[0].IsExternal()) {
|
||||
Napi::TypeError::New(env, "Argument 0 should be a keyword spotter pointer.")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!info[1].IsExternal()) {
|
||||
Napi::TypeError::New(env, "Argument 1 should be an online stream pointer.")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
SherpaOnnxKeywordSpotter *kws =
|
||||
info[0].As<Napi::External<SherpaOnnxKeywordSpotter>>().Data();
|
||||
|
||||
SherpaOnnxOnlineStream *stream =
|
||||
info[1].As<Napi::External<SherpaOnnxOnlineStream>>().Data();
|
||||
|
||||
int32_t is_ready = SherpaOnnxIsKeywordStreamReady(kws, stream);
|
||||
|
||||
return Napi::Boolean::New(env, is_ready);
|
||||
}
|
||||
|
||||
static void DecodeKeywordStreamWrapper(const Napi::CallbackInfo &info) {
|
||||
Napi::Env env = info.Env();
|
||||
if (info.Length() != 2) {
|
||||
std::ostringstream os;
|
||||
os << "Expect only 2 arguments. Given: " << info.Length();
|
||||
|
||||
Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!info[0].IsExternal()) {
|
||||
Napi::TypeError::New(env, "Argument 0 should be a keyword spotter pointer.")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!info[1].IsExternal()) {
|
||||
Napi::TypeError::New(env, "Argument 1 should be an online stream pointer.")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
SherpaOnnxKeywordSpotter *kws =
|
||||
info[0].As<Napi::External<SherpaOnnxKeywordSpotter>>().Data();
|
||||
|
||||
SherpaOnnxOnlineStream *stream =
|
||||
info[1].As<Napi::External<SherpaOnnxOnlineStream>>().Data();
|
||||
|
||||
SherpaOnnxDecodeKeywordStream(kws, stream);
|
||||
}
|
||||
|
||||
static Napi::String GetKeywordResultAsJsonWrapper(
|
||||
const Napi::CallbackInfo &info) {
|
||||
Napi::Env env = info.Env();
|
||||
if (info.Length() != 2) {
|
||||
std::ostringstream os;
|
||||
os << "Expect only 2 arguments. Given: " << info.Length();
|
||||
|
||||
Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!info[0].IsExternal()) {
|
||||
Napi::TypeError::New(env, "Argument 0 should be a keyword spotter pointer.")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!info[1].IsExternal()) {
|
||||
Napi::TypeError::New(env, "Argument 1 should be an online stream pointer.")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
SherpaOnnxKeywordSpotter *kws =
|
||||
info[0].As<Napi::External<SherpaOnnxKeywordSpotter>>().Data();
|
||||
|
||||
SherpaOnnxOnlineStream *stream =
|
||||
info[1].As<Napi::External<SherpaOnnxOnlineStream>>().Data();
|
||||
|
||||
const char *json = SherpaOnnxGetKeywordResultAsJson(kws, stream);
|
||||
|
||||
Napi::String s = Napi::String::New(env, json);
|
||||
|
||||
SherpaOnnxFreeKeywordResultJson(json);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
void InitKeywordSpotting(Napi::Env env, Napi::Object exports) {
|
||||
exports.Set(Napi::String::New(env, "createKeywordSpotter"),
|
||||
Napi::Function::New(env, CreateKeywordSpotterWrapper));
|
||||
|
||||
exports.Set(Napi::String::New(env, "createKeywordStream"),
|
||||
Napi::Function::New(env, CreateKeywordStreamWrapper));
|
||||
|
||||
exports.Set(Napi::String::New(env, "isKeywordStreamReady"),
|
||||
Napi::Function::New(env, IsKeywordStreamReadyWrapper));
|
||||
|
||||
exports.Set(Napi::String::New(env, "decodeKeywordStream"),
|
||||
Napi::Function::New(env, DecodeKeywordStreamWrapper));
|
||||
|
||||
exports.Set(Napi::String::New(env, "getKeywordResultAsJson"),
|
||||
Napi::Function::New(env, GetKeywordResultAsJsonWrapper));
|
||||
}
|
||||
1
scripts/node-addon-api/src/keyword-spotting.cc
Symbolic link
1
scripts/node-addon-api/src/keyword-spotting.cc
Symbolic link
@@ -0,0 +1 @@
|
||||
../../../harmony-os/SherpaOnnxHar/sherpa_onnx/src/main/cpp/keyword-spotting.cc
|
||||
@@ -1,51 +0,0 @@
|
||||
// scripts/node-addon-api/src/macros.h
|
||||
//
|
||||
// Copyright (c) 2024 Xiaomi Corporation
|
||||
#ifndef SCRIPTS_NODE_ADDON_API_SRC_MACROS_H_
|
||||
#define SCRIPTS_NODE_ADDON_API_SRC_MACROS_H_
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
|
||||
#define SHERPA_ONNX_ASSIGN_ATTR_STR(c_name, js_name) \
|
||||
do { \
|
||||
if (o.Has(#js_name) && o.Get(#js_name).IsString()) { \
|
||||
Napi::String _str = o.Get(#js_name).As<Napi::String>(); \
|
||||
std::string s = _str.Utf8Value(); \
|
||||
char *p = new char[s.size() + 1]; \
|
||||
std::copy(s.begin(), s.end(), p); \
|
||||
p[s.size()] = 0; \
|
||||
\
|
||||
c.c_name = p; \
|
||||
} else if (o.Has(#js_name) && o.Get(#js_name).IsTypedArray()) { \
|
||||
Napi::Uint8Array _array = o.Get(#js_name).As<Napi::Uint8Array>(); \
|
||||
char *p = new char[_array.ElementLength() + 1]; \
|
||||
std::copy(_array.Data(), _array.Data() + _array.ElementLength(), p); \
|
||||
p[_array.ElementLength()] = '\0'; \
|
||||
\
|
||||
c.c_name = p; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define SHERPA_ONNX_ASSIGN_ATTR_INT32(c_name, js_name) \
|
||||
do { \
|
||||
if (o.Has(#js_name) && o.Get(#js_name).IsNumber()) { \
|
||||
c.c_name = o.Get(#js_name).As<Napi::Number>().Int32Value(); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define SHERPA_ONNX_ASSIGN_ATTR_FLOAT(c_name, js_name) \
|
||||
do { \
|
||||
if (o.Has(#js_name) && o.Get(#js_name).IsNumber()) { \
|
||||
c.c_name = o.Get(#js_name).As<Napi::Number>().FloatValue(); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define SHERPA_ONNX_DELETE_C_STR(p) \
|
||||
do { \
|
||||
if (p) { \
|
||||
delete[] p; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#endif // SCRIPTS_NODE_ADDON_API_SRC_MACROS_H_
|
||||
1
scripts/node-addon-api/src/macros.h
Symbolic link
1
scripts/node-addon-api/src/macros.h
Symbolic link
@@ -0,0 +1 @@
|
||||
../../../harmony-os/SherpaOnnxHar/sherpa_onnx/src/main/cpp/macros.h
|
||||
@@ -1,461 +0,0 @@
|
||||
// scripts/node-addon-api/src/non-streaming-asr.cc
|
||||
//
|
||||
// Copyright (c) 2024 Xiaomi Corporation
|
||||
#include <sstream>
|
||||
|
||||
#include "macros.h" // NOLINT
|
||||
#include "napi.h" // NOLINT
|
||||
#include "sherpa-onnx/c-api/c-api.h"
|
||||
|
||||
// defined in ./streaming-asr.cc
|
||||
SherpaOnnxFeatureConfig GetFeatureConfig(Napi::Object obj);
|
||||
|
||||
static SherpaOnnxOfflineTransducerModelConfig GetOfflineTransducerModelConfig(
|
||||
Napi::Object obj) {
|
||||
SherpaOnnxOfflineTransducerModelConfig c;
|
||||
memset(&c, 0, sizeof(c));
|
||||
|
||||
if (!obj.Has("transducer") || !obj.Get("transducer").IsObject()) {
|
||||
return c;
|
||||
}
|
||||
|
||||
Napi::Object o = obj.Get("transducer").As<Napi::Object>();
|
||||
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(encoder, encoder);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(decoder, decoder);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(joiner, joiner);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
static SherpaOnnxOfflineParaformerModelConfig GetOfflineParaformerModelConfig(
|
||||
Napi::Object obj) {
|
||||
SherpaOnnxOfflineParaformerModelConfig c;
|
||||
memset(&c, 0, sizeof(c));
|
||||
|
||||
if (!obj.Has("paraformer") || !obj.Get("paraformer").IsObject()) {
|
||||
return c;
|
||||
}
|
||||
|
||||
Napi::Object o = obj.Get("paraformer").As<Napi::Object>();
|
||||
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(model, model);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
static SherpaOnnxOfflineNemoEncDecCtcModelConfig GetOfflineNeMoCtcModelConfig(
|
||||
Napi::Object obj) {
|
||||
SherpaOnnxOfflineNemoEncDecCtcModelConfig c;
|
||||
memset(&c, 0, sizeof(c));
|
||||
|
||||
if (!obj.Has("nemoCtc") || !obj.Get("nemoCtc").IsObject()) {
|
||||
return c;
|
||||
}
|
||||
|
||||
Napi::Object o = obj.Get("nemoCtc").As<Napi::Object>();
|
||||
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(model, model);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
static SherpaOnnxOfflineWhisperModelConfig GetOfflineWhisperModelConfig(
|
||||
Napi::Object obj) {
|
||||
SherpaOnnxOfflineWhisperModelConfig c;
|
||||
memset(&c, 0, sizeof(c));
|
||||
|
||||
if (!obj.Has("whisper") || !obj.Get("whisper").IsObject()) {
|
||||
return c;
|
||||
}
|
||||
|
||||
Napi::Object o = obj.Get("whisper").As<Napi::Object>();
|
||||
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(encoder, encoder);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(decoder, decoder);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(language, language);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(task, task);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_INT32(tail_paddings, tailPaddings);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
static SherpaOnnxOfflineMoonshineModelConfig GetOfflineMoonshineModelConfig(
|
||||
Napi::Object obj) {
|
||||
SherpaOnnxOfflineMoonshineModelConfig c;
|
||||
memset(&c, 0, sizeof(c));
|
||||
|
||||
if (!obj.Has("moonshine") || !obj.Get("moonshine").IsObject()) {
|
||||
return c;
|
||||
}
|
||||
|
||||
Napi::Object o = obj.Get("moonshine").As<Napi::Object>();
|
||||
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(preprocessor, preprocessor);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(encoder, encoder);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(uncached_decoder, uncachedDecoder);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(cached_decoder, cachedDecoder);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
static SherpaOnnxOfflineTdnnModelConfig GetOfflineTdnnModelConfig(
|
||||
Napi::Object obj) {
|
||||
SherpaOnnxOfflineTdnnModelConfig c;
|
||||
memset(&c, 0, sizeof(c));
|
||||
|
||||
if (!obj.Has("tdnn") || !obj.Get("tdnn").IsObject()) {
|
||||
return c;
|
||||
}
|
||||
|
||||
Napi::Object o = obj.Get("tdnn").As<Napi::Object>();
|
||||
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(model, model);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
static SherpaOnnxOfflineSenseVoiceModelConfig GetOfflineSenseVoiceModelConfig(
|
||||
Napi::Object obj) {
|
||||
SherpaOnnxOfflineSenseVoiceModelConfig c;
|
||||
memset(&c, 0, sizeof(c));
|
||||
|
||||
if (!obj.Has("senseVoice") || !obj.Get("senseVoice").IsObject()) {
|
||||
return c;
|
||||
}
|
||||
|
||||
Napi::Object o = obj.Get("senseVoice").As<Napi::Object>();
|
||||
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(model, model);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(language, language);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_INT32(use_itn, useInverseTextNormalization);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
static SherpaOnnxOfflineModelConfig GetOfflineModelConfig(Napi::Object obj) {
|
||||
SherpaOnnxOfflineModelConfig c;
|
||||
memset(&c, 0, sizeof(c));
|
||||
|
||||
if (!obj.Has("modelConfig") || !obj.Get("modelConfig").IsObject()) {
|
||||
return c;
|
||||
}
|
||||
|
||||
Napi::Object o = obj.Get("modelConfig").As<Napi::Object>();
|
||||
|
||||
c.transducer = GetOfflineTransducerModelConfig(o);
|
||||
c.paraformer = GetOfflineParaformerModelConfig(o);
|
||||
c.nemo_ctc = GetOfflineNeMoCtcModelConfig(o);
|
||||
c.whisper = GetOfflineWhisperModelConfig(o);
|
||||
c.tdnn = GetOfflineTdnnModelConfig(o);
|
||||
c.sense_voice = GetOfflineSenseVoiceModelConfig(o);
|
||||
c.moonshine = GetOfflineMoonshineModelConfig(o);
|
||||
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(tokens, tokens);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_INT32(num_threads, numThreads);
|
||||
|
||||
if (o.Has("debug") &&
|
||||
(o.Get("debug").IsNumber() || o.Get("debug").IsBoolean())) {
|
||||
if (o.Get("debug").IsBoolean()) {
|
||||
c.debug = o.Get("debug").As<Napi::Boolean>().Value();
|
||||
} else {
|
||||
c.debug = o.Get("debug").As<Napi::Number>().Int32Value();
|
||||
}
|
||||
}
|
||||
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(provider, provider);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(model_type, modelType);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(modeling_unit, modelingUnit);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(bpe_vocab, bpeVocab);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(telespeech_ctc, teleSpeechCtc);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
static SherpaOnnxOfflineLMConfig GetOfflineLMConfig(Napi::Object obj) {
|
||||
SherpaOnnxOfflineLMConfig c;
|
||||
memset(&c, 0, sizeof(c));
|
||||
|
||||
if (!obj.Has("lmConfig") || !obj.Get("lmConfig").IsObject()) {
|
||||
return c;
|
||||
}
|
||||
|
||||
Napi::Object o = obj.Get("lmConfig").As<Napi::Object>();
|
||||
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(model, model);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_FLOAT(scale, scale);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
static Napi::External<SherpaOnnxOfflineRecognizer>
|
||||
CreateOfflineRecognizerWrapper(const Napi::CallbackInfo &info) {
|
||||
Napi::Env env = info.Env();
|
||||
if (info.Length() != 1) {
|
||||
std::ostringstream os;
|
||||
os << "Expect only 1 argument. Given: " << info.Length();
|
||||
|
||||
Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!info[0].IsObject()) {
|
||||
Napi::TypeError::New(env, "Expect an object as the argument")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
Napi::Object o = info[0].As<Napi::Object>();
|
||||
|
||||
SherpaOnnxOfflineRecognizerConfig c;
|
||||
memset(&c, 0, sizeof(c));
|
||||
c.feat_config = GetFeatureConfig(o);
|
||||
c.model_config = GetOfflineModelConfig(o);
|
||||
c.lm_config = GetOfflineLMConfig(o);
|
||||
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(decoding_method, decodingMethod);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_INT32(max_active_paths, maxActivePaths);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(hotwords_file, hotwordsFile);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_FLOAT(hotwords_score, hotwordsScore);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(rule_fsts, ruleFsts);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(rule_fars, ruleFars);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_FLOAT(blank_penalty, blankPenalty);
|
||||
|
||||
const SherpaOnnxOfflineRecognizer *recognizer =
|
||||
SherpaOnnxCreateOfflineRecognizer(&c);
|
||||
|
||||
SHERPA_ONNX_DELETE_C_STR(c.model_config.transducer.encoder);
|
||||
SHERPA_ONNX_DELETE_C_STR(c.model_config.transducer.decoder);
|
||||
SHERPA_ONNX_DELETE_C_STR(c.model_config.transducer.joiner);
|
||||
|
||||
SHERPA_ONNX_DELETE_C_STR(c.model_config.paraformer.model);
|
||||
|
||||
SHERPA_ONNX_DELETE_C_STR(c.model_config.nemo_ctc.model);
|
||||
|
||||
SHERPA_ONNX_DELETE_C_STR(c.model_config.whisper.encoder);
|
||||
SHERPA_ONNX_DELETE_C_STR(c.model_config.whisper.decoder);
|
||||
SHERPA_ONNX_DELETE_C_STR(c.model_config.whisper.language);
|
||||
SHERPA_ONNX_DELETE_C_STR(c.model_config.whisper.task);
|
||||
|
||||
SHERPA_ONNX_DELETE_C_STR(c.model_config.tdnn.model);
|
||||
|
||||
SHERPA_ONNX_DELETE_C_STR(c.model_config.sense_voice.model);
|
||||
SHERPA_ONNX_DELETE_C_STR(c.model_config.sense_voice.language);
|
||||
|
||||
SHERPA_ONNX_DELETE_C_STR(c.model_config.moonshine.preprocessor);
|
||||
SHERPA_ONNX_DELETE_C_STR(c.model_config.moonshine.encoder);
|
||||
SHERPA_ONNX_DELETE_C_STR(c.model_config.moonshine.uncached_decoder);
|
||||
SHERPA_ONNX_DELETE_C_STR(c.model_config.moonshine.cached_decoder);
|
||||
|
||||
SHERPA_ONNX_DELETE_C_STR(c.model_config.tokens);
|
||||
SHERPA_ONNX_DELETE_C_STR(c.model_config.provider);
|
||||
SHERPA_ONNX_DELETE_C_STR(c.model_config.model_type);
|
||||
SHERPA_ONNX_DELETE_C_STR(c.model_config.modeling_unit);
|
||||
SHERPA_ONNX_DELETE_C_STR(c.model_config.bpe_vocab);
|
||||
SHERPA_ONNX_DELETE_C_STR(c.model_config.telespeech_ctc);
|
||||
|
||||
SHERPA_ONNX_DELETE_C_STR(c.lm_config.model);
|
||||
|
||||
SHERPA_ONNX_DELETE_C_STR(c.decoding_method);
|
||||
SHERPA_ONNX_DELETE_C_STR(c.hotwords_file);
|
||||
SHERPA_ONNX_DELETE_C_STR(c.rule_fsts);
|
||||
SHERPA_ONNX_DELETE_C_STR(c.rule_fars);
|
||||
|
||||
if (!recognizer) {
|
||||
Napi::TypeError::New(env, "Please check your config!")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
return Napi::External<SherpaOnnxOfflineRecognizer>::New(
|
||||
env, const_cast<SherpaOnnxOfflineRecognizer *>(recognizer),
|
||||
[](Napi::Env env, SherpaOnnxOfflineRecognizer *recognizer) {
|
||||
SherpaOnnxDestroyOfflineRecognizer(recognizer);
|
||||
});
|
||||
}
|
||||
|
||||
static Napi::External<SherpaOnnxOfflineStream> CreateOfflineStreamWrapper(
|
||||
const Napi::CallbackInfo &info) {
|
||||
Napi::Env env = info.Env();
|
||||
if (info.Length() != 1) {
|
||||
std::ostringstream os;
|
||||
os << "Expect only 1 argument. Given: " << info.Length();
|
||||
|
||||
Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!info[0].IsExternal()) {
|
||||
Napi::TypeError::New(
|
||||
env,
|
||||
"You should pass an offline recognizer pointer as the only argument")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
SherpaOnnxOfflineRecognizer *recognizer =
|
||||
info[0].As<Napi::External<SherpaOnnxOfflineRecognizer>>().Data();
|
||||
|
||||
const SherpaOnnxOfflineStream *stream =
|
||||
SherpaOnnxCreateOfflineStream(recognizer);
|
||||
|
||||
return Napi::External<SherpaOnnxOfflineStream>::New(
|
||||
env, const_cast<SherpaOnnxOfflineStream *>(stream),
|
||||
[](Napi::Env env, SherpaOnnxOfflineStream *stream) {
|
||||
SherpaOnnxDestroyOfflineStream(stream);
|
||||
});
|
||||
}
|
||||
|
||||
static void AcceptWaveformOfflineWrapper(const Napi::CallbackInfo &info) {
|
||||
Napi::Env env = info.Env();
|
||||
|
||||
if (info.Length() != 2) {
|
||||
std::ostringstream os;
|
||||
os << "Expect only 2 arguments. Given: " << info.Length();
|
||||
|
||||
Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!info[0].IsExternal()) {
|
||||
Napi::TypeError::New(env, "Argument 0 should be an online stream pointer.")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
SherpaOnnxOfflineStream *stream =
|
||||
info[0].As<Napi::External<SherpaOnnxOfflineStream>>().Data();
|
||||
|
||||
if (!info[1].IsObject()) {
|
||||
Napi::TypeError::New(env, "Argument 1 should be an object")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Napi::Object obj = info[1].As<Napi::Object>();
|
||||
|
||||
if (!obj.Has("samples")) {
|
||||
Napi::TypeError::New(env, "The argument object should have a field samples")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!obj.Get("samples").IsTypedArray()) {
|
||||
Napi::TypeError::New(env, "The object['samples'] should be a typed array")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!obj.Has("sampleRate")) {
|
||||
Napi::TypeError::New(env,
|
||||
"The argument object should have a field sampleRate")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!obj.Get("sampleRate").IsNumber()) {
|
||||
Napi::TypeError::New(env, "The object['samples'] should be a number")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Napi::Float32Array samples = obj.Get("samples").As<Napi::Float32Array>();
|
||||
int32_t sample_rate = obj.Get("sampleRate").As<Napi::Number>().Int32Value();
|
||||
|
||||
SherpaOnnxAcceptWaveformOffline(stream, sample_rate, samples.Data(),
|
||||
samples.ElementLength());
|
||||
}
|
||||
|
||||
static void DecodeOfflineStreamWrapper(const Napi::CallbackInfo &info) {
|
||||
Napi::Env env = info.Env();
|
||||
if (info.Length() != 2) {
|
||||
std::ostringstream os;
|
||||
os << "Expect only 2 arguments. Given: " << info.Length();
|
||||
|
||||
Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!info[0].IsExternal()) {
|
||||
Napi::TypeError::New(env,
|
||||
"Argument 0 should be an offline recognizer pointer.")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!info[1].IsExternal()) {
|
||||
Napi::TypeError::New(env, "Argument 1 should be an offline stream pointer.")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
SherpaOnnxOfflineRecognizer *recognizer =
|
||||
info[0].As<Napi::External<SherpaOnnxOfflineRecognizer>>().Data();
|
||||
|
||||
SherpaOnnxOfflineStream *stream =
|
||||
info[1].As<Napi::External<SherpaOnnxOfflineStream>>().Data();
|
||||
|
||||
SherpaOnnxDecodeOfflineStream(recognizer, stream);
|
||||
}
|
||||
|
||||
static Napi::String GetOfflineStreamResultAsJsonWrapper(
|
||||
const Napi::CallbackInfo &info) {
|
||||
Napi::Env env = info.Env();
|
||||
if (info.Length() != 1) {
|
||||
std::ostringstream os;
|
||||
os << "Expect only 1 argument. Given: " << info.Length();
|
||||
|
||||
Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!info[0].IsExternal()) {
|
||||
Napi::TypeError::New(env, "Argument 0 should be an online stream pointer.")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
SherpaOnnxOfflineStream *stream =
|
||||
info[0].As<Napi::External<SherpaOnnxOfflineStream>>().Data();
|
||||
|
||||
const char *json = SherpaOnnxGetOfflineStreamResultAsJson(stream);
|
||||
Napi::String s = Napi::String::New(env, json);
|
||||
|
||||
SherpaOnnxDestroyOfflineStreamResultJson(json);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
void InitNonStreamingAsr(Napi::Env env, Napi::Object exports) {
|
||||
exports.Set(Napi::String::New(env, "createOfflineRecognizer"),
|
||||
Napi::Function::New(env, CreateOfflineRecognizerWrapper));
|
||||
|
||||
exports.Set(Napi::String::New(env, "createOfflineStream"),
|
||||
Napi::Function::New(env, CreateOfflineStreamWrapper));
|
||||
|
||||
exports.Set(Napi::String::New(env, "acceptWaveformOffline"),
|
||||
Napi::Function::New(env, AcceptWaveformOfflineWrapper));
|
||||
|
||||
exports.Set(Napi::String::New(env, "decodeOfflineStream"),
|
||||
Napi::Function::New(env, DecodeOfflineStreamWrapper));
|
||||
|
||||
exports.Set(Napi::String::New(env, "getOfflineStreamResultAsJson"),
|
||||
Napi::Function::New(env, GetOfflineStreamResultAsJsonWrapper));
|
||||
}
|
||||
1
scripts/node-addon-api/src/non-streaming-asr.cc
Symbolic link
1
scripts/node-addon-api/src/non-streaming-asr.cc
Symbolic link
@@ -0,0 +1 @@
|
||||
../../../harmony-os/SherpaOnnxHar/sherpa_onnx/src/main/cpp/non-streaming-asr.cc
|
||||
@@ -1,310 +0,0 @@
|
||||
// scripts/node-addon-api/src/non-streaming-speaker-diarization.cc
|
||||
//
|
||||
// Copyright (c) 2024 Xiaomi Corporation
|
||||
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
|
||||
#include "macros.h" // NOLINT
|
||||
#include "napi.h" // NOLINT
|
||||
#include "sherpa-onnx/c-api/c-api.h"
|
||||
|
||||
static SherpaOnnxOfflineSpeakerSegmentationPyannoteModelConfig
|
||||
GetOfflineSpeakerSegmentationPyannoteModelConfig(Napi::Object obj) {
|
||||
SherpaOnnxOfflineSpeakerSegmentationPyannoteModelConfig c;
|
||||
memset(&c, 0, sizeof(c));
|
||||
|
||||
if (!obj.Has("pyannote") || !obj.Get("pyannote").IsObject()) {
|
||||
return c;
|
||||
}
|
||||
|
||||
Napi::Object o = obj.Get("pyannote").As<Napi::Object>();
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(model, model);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
static SherpaOnnxOfflineSpeakerSegmentationModelConfig
|
||||
GetOfflineSpeakerSegmentationModelConfig(Napi::Object obj) {
|
||||
SherpaOnnxOfflineSpeakerSegmentationModelConfig c;
|
||||
memset(&c, 0, sizeof(c));
|
||||
|
||||
if (!obj.Has("segmentation") || !obj.Get("segmentation").IsObject()) {
|
||||
return c;
|
||||
}
|
||||
|
||||
Napi::Object o = obj.Get("segmentation").As<Napi::Object>();
|
||||
|
||||
c.pyannote = GetOfflineSpeakerSegmentationPyannoteModelConfig(o);
|
||||
|
||||
SHERPA_ONNX_ASSIGN_ATTR_INT32(num_threads, numThreads);
|
||||
|
||||
if (o.Has("debug") &&
|
||||
(o.Get("debug").IsNumber() || o.Get("debug").IsBoolean())) {
|
||||
if (o.Get("debug").IsBoolean()) {
|
||||
c.debug = o.Get("debug").As<Napi::Boolean>().Value();
|
||||
} else {
|
||||
c.debug = o.Get("debug").As<Napi::Number>().Int32Value();
|
||||
}
|
||||
}
|
||||
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(provider, provider);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
static SherpaOnnxSpeakerEmbeddingExtractorConfig
|
||||
GetSpeakerEmbeddingExtractorConfig(Napi::Object obj) {
|
||||
SherpaOnnxSpeakerEmbeddingExtractorConfig c;
|
||||
memset(&c, 0, sizeof(c));
|
||||
|
||||
if (!obj.Has("embedding") || !obj.Get("embedding").IsObject()) {
|
||||
return c;
|
||||
}
|
||||
|
||||
Napi::Object o = obj.Get("embedding").As<Napi::Object>();
|
||||
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(model, model);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_INT32(num_threads, numThreads);
|
||||
|
||||
if (o.Has("debug") &&
|
||||
(o.Get("debug").IsNumber() || o.Get("debug").IsBoolean())) {
|
||||
if (o.Get("debug").IsBoolean()) {
|
||||
c.debug = o.Get("debug").As<Napi::Boolean>().Value();
|
||||
} else {
|
||||
c.debug = o.Get("debug").As<Napi::Number>().Int32Value();
|
||||
}
|
||||
}
|
||||
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(provider, provider);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
static SherpaOnnxFastClusteringConfig GetFastClusteringConfig(
|
||||
Napi::Object obj) {
|
||||
SherpaOnnxFastClusteringConfig c;
|
||||
memset(&c, 0, sizeof(c));
|
||||
|
||||
if (!obj.Has("clustering") || !obj.Get("clustering").IsObject()) {
|
||||
return c;
|
||||
}
|
||||
|
||||
Napi::Object o = obj.Get("clustering").As<Napi::Object>();
|
||||
|
||||
SHERPA_ONNX_ASSIGN_ATTR_INT32(num_clusters, numClusters);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_FLOAT(threshold, threshold);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
static Napi::External<SherpaOnnxOfflineSpeakerDiarization>
|
||||
CreateOfflineSpeakerDiarizationWrapper(const Napi::CallbackInfo &info) {
|
||||
Napi::Env env = info.Env();
|
||||
if (info.Length() != 1) {
|
||||
std::ostringstream os;
|
||||
os << "Expect only 1 argument. Given: " << info.Length();
|
||||
|
||||
Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!info[0].IsObject()) {
|
||||
Napi::TypeError::New(env, "Expect an object as the argument")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
Napi::Object o = info[0].As<Napi::Object>();
|
||||
|
||||
SherpaOnnxOfflineSpeakerDiarizationConfig c;
|
||||
memset(&c, 0, sizeof(c));
|
||||
|
||||
c.segmentation = GetOfflineSpeakerSegmentationModelConfig(o);
|
||||
c.embedding = GetSpeakerEmbeddingExtractorConfig(o);
|
||||
c.clustering = GetFastClusteringConfig(o);
|
||||
|
||||
SHERPA_ONNX_ASSIGN_ATTR_FLOAT(min_duration_on, minDurationOn);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_FLOAT(min_duration_off, minDurationOff);
|
||||
|
||||
const SherpaOnnxOfflineSpeakerDiarization *sd =
|
||||
SherpaOnnxCreateOfflineSpeakerDiarization(&c);
|
||||
|
||||
if (c.segmentation.pyannote.model) {
|
||||
delete[] c.segmentation.pyannote.model;
|
||||
}
|
||||
|
||||
if (c.segmentation.provider) {
|
||||
delete[] c.segmentation.provider;
|
||||
}
|
||||
|
||||
if (c.embedding.model) {
|
||||
delete[] c.embedding.model;
|
||||
}
|
||||
|
||||
if (c.embedding.provider) {
|
||||
delete[] c.embedding.provider;
|
||||
}
|
||||
|
||||
if (!sd) {
|
||||
Napi::TypeError::New(env, "Please check your config!")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
return Napi::External<SherpaOnnxOfflineSpeakerDiarization>::New(
|
||||
env, const_cast<SherpaOnnxOfflineSpeakerDiarization *>(sd),
|
||||
[](Napi::Env env, SherpaOnnxOfflineSpeakerDiarization *sd) {
|
||||
SherpaOnnxDestroyOfflineSpeakerDiarization(sd);
|
||||
});
|
||||
}
|
||||
|
||||
static Napi::Number OfflineSpeakerDiarizationGetSampleRateWrapper(
|
||||
const Napi::CallbackInfo &info) {
|
||||
Napi::Env env = info.Env();
|
||||
|
||||
if (info.Length() != 1) {
|
||||
std::ostringstream os;
|
||||
os << "Expect only 1 argument. Given: " << info.Length();
|
||||
|
||||
Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!info[0].IsExternal()) {
|
||||
Napi::TypeError::New(
|
||||
env, "Argument 0 should be an offline speaker diarization pointer.")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
const SherpaOnnxOfflineSpeakerDiarization *sd =
|
||||
info[0].As<Napi::External<SherpaOnnxOfflineSpeakerDiarization>>().Data();
|
||||
|
||||
int32_t sample_rate = SherpaOnnxOfflineSpeakerDiarizationGetSampleRate(sd);
|
||||
|
||||
return Napi::Number::New(env, sample_rate);
|
||||
}
|
||||
|
||||
static Napi::Array OfflineSpeakerDiarizationProcessWrapper(
|
||||
const Napi::CallbackInfo &info) {
|
||||
Napi::Env env = info.Env();
|
||||
|
||||
if (info.Length() != 2) {
|
||||
std::ostringstream os;
|
||||
os << "Expect only 2 arguments. Given: " << info.Length();
|
||||
|
||||
Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!info[0].IsExternal()) {
|
||||
Napi::TypeError::New(
|
||||
env, "Argument 0 should be an offline speaker diarization pointer.")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
const SherpaOnnxOfflineSpeakerDiarization *sd =
|
||||
info[0].As<Napi::External<SherpaOnnxOfflineSpeakerDiarization>>().Data();
|
||||
|
||||
if (!info[1].IsTypedArray()) {
|
||||
Napi::TypeError::New(env, "Argument 1 should be a typed array")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
Napi::Float32Array samples = info[1].As<Napi::Float32Array>();
|
||||
|
||||
const SherpaOnnxOfflineSpeakerDiarizationResult *r =
|
||||
SherpaOnnxOfflineSpeakerDiarizationProcess(sd, samples.Data(),
|
||||
samples.ElementLength());
|
||||
|
||||
int32_t num_segments =
|
||||
SherpaOnnxOfflineSpeakerDiarizationResultGetNumSegments(r);
|
||||
|
||||
const SherpaOnnxOfflineSpeakerDiarizationSegment *segments =
|
||||
SherpaOnnxOfflineSpeakerDiarizationResultSortByStartTime(r);
|
||||
|
||||
Napi::Array ans = Napi::Array::New(env, num_segments);
|
||||
|
||||
for (int32_t i = 0; i != num_segments; ++i) {
|
||||
Napi::Object obj = Napi::Object::New(env);
|
||||
|
||||
obj.Set(Napi::String::New(env, "start"), segments[i].start);
|
||||
obj.Set(Napi::String::New(env, "end"), segments[i].end);
|
||||
obj.Set(Napi::String::New(env, "speaker"), segments[i].speaker);
|
||||
|
||||
ans.Set(i, obj);
|
||||
}
|
||||
|
||||
SherpaOnnxOfflineSpeakerDiarizationDestroySegment(segments);
|
||||
SherpaOnnxOfflineSpeakerDiarizationDestroyResult(r);
|
||||
|
||||
return ans;
|
||||
}
|
||||
|
||||
static void OfflineSpeakerDiarizationSetConfigWrapper(
|
||||
const Napi::CallbackInfo &info) {
|
||||
Napi::Env env = info.Env();
|
||||
|
||||
if (info.Length() != 2) {
|
||||
std::ostringstream os;
|
||||
os << "Expect only 2 arguments. Given: " << info.Length();
|
||||
|
||||
Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!info[0].IsExternal()) {
|
||||
Napi::TypeError::New(
|
||||
env, "Argument 0 should be an offline speaker diarization pointer.")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const SherpaOnnxOfflineSpeakerDiarization *sd =
|
||||
info[0].As<Napi::External<SherpaOnnxOfflineSpeakerDiarization>>().Data();
|
||||
|
||||
if (!info[1].IsObject()) {
|
||||
Napi::TypeError::New(env, "Expect an object as the argument")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Napi::Object o = info[0].As<Napi::Object>();
|
||||
|
||||
SherpaOnnxOfflineSpeakerDiarizationConfig c;
|
||||
memset(&c, 0, sizeof(c));
|
||||
|
||||
c.clustering = GetFastClusteringConfig(o);
|
||||
SherpaOnnxOfflineSpeakerDiarizationSetConfig(sd, &c);
|
||||
}
|
||||
|
||||
void InitNonStreamingSpeakerDiarization(Napi::Env env, Napi::Object exports) {
|
||||
exports.Set(Napi::String::New(env, "createOfflineSpeakerDiarization"),
|
||||
Napi::Function::New(env, CreateOfflineSpeakerDiarizationWrapper));
|
||||
|
||||
exports.Set(
|
||||
Napi::String::New(env, "getOfflineSpeakerDiarizationSampleRate"),
|
||||
Napi::Function::New(env, OfflineSpeakerDiarizationGetSampleRateWrapper));
|
||||
|
||||
exports.Set(
|
||||
Napi::String::New(env, "offlineSpeakerDiarizationProcess"),
|
||||
Napi::Function::New(env, OfflineSpeakerDiarizationProcessWrapper));
|
||||
|
||||
exports.Set(
|
||||
Napi::String::New(env, "offlineSpeakerDiarizationSetConfig"),
|
||||
Napi::Function::New(env, OfflineSpeakerDiarizationSetConfigWrapper));
|
||||
}
|
||||
1
scripts/node-addon-api/src/non-streaming-speaker-diarization.cc
Symbolic link
1
scripts/node-addon-api/src/non-streaming-speaker-diarization.cc
Symbolic link
@@ -0,0 +1 @@
|
||||
../../../harmony-os/SherpaOnnxHar/sherpa_onnx/src/main/cpp/non-streaming-speaker-diarization.cc
|
||||
@@ -1,329 +0,0 @@
|
||||
// scripts/node-addon-api/src/non-streaming-tts.cc
|
||||
//
|
||||
// Copyright (c) 2024 Xiaomi Corporation
|
||||
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
|
||||
#include "macros.h" // NOLINT
|
||||
#include "napi.h" // NOLINT
|
||||
#include "sherpa-onnx/c-api/c-api.h"
|
||||
|
||||
static SherpaOnnxOfflineTtsVitsModelConfig GetOfflineTtsVitsModelConfig(
|
||||
Napi::Object obj) {
|
||||
SherpaOnnxOfflineTtsVitsModelConfig c;
|
||||
memset(&c, 0, sizeof(c));
|
||||
|
||||
if (!obj.Has("vits") || !obj.Get("vits").IsObject()) {
|
||||
return c;
|
||||
}
|
||||
|
||||
Napi::Object o = obj.Get("vits").As<Napi::Object>();
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(model, model);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(lexicon, lexicon);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(tokens, tokens);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(data_dir, dataDir);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_FLOAT(noise_scale, noiseScale);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_FLOAT(noise_scale_w, noiseScaleW);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_FLOAT(length_scale, lengthScale);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(dict_dir, dictDir);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
static SherpaOnnxOfflineTtsModelConfig GetOfflineTtsModelConfig(
|
||||
Napi::Object obj) {
|
||||
SherpaOnnxOfflineTtsModelConfig c;
|
||||
memset(&c, 0, sizeof(c));
|
||||
|
||||
if (!obj.Has("model") || !obj.Get("model").IsObject()) {
|
||||
return c;
|
||||
}
|
||||
|
||||
Napi::Object o = obj.Get("model").As<Napi::Object>();
|
||||
|
||||
c.vits = GetOfflineTtsVitsModelConfig(o);
|
||||
|
||||
SHERPA_ONNX_ASSIGN_ATTR_INT32(num_threads, numThreads);
|
||||
|
||||
if (o.Has("debug") &&
|
||||
(o.Get("debug").IsNumber() || o.Get("debug").IsBoolean())) {
|
||||
if (o.Get("debug").IsBoolean()) {
|
||||
c.debug = o.Get("debug").As<Napi::Boolean>().Value();
|
||||
} else {
|
||||
c.debug = o.Get("debug").As<Napi::Number>().Int32Value();
|
||||
}
|
||||
}
|
||||
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(provider, provider);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
static Napi::External<SherpaOnnxOfflineTts> CreateOfflineTtsWrapper(
|
||||
const Napi::CallbackInfo &info) {
|
||||
Napi::Env env = info.Env();
|
||||
if (info.Length() != 1) {
|
||||
std::ostringstream os;
|
||||
os << "Expect only 1 argument. Given: " << info.Length();
|
||||
|
||||
Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!info[0].IsObject()) {
|
||||
Napi::TypeError::New(env, "Expect an object as the argument")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
Napi::Object o = info[0].As<Napi::Object>();
|
||||
|
||||
SherpaOnnxOfflineTtsConfig c;
|
||||
memset(&c, 0, sizeof(c));
|
||||
|
||||
c.model = GetOfflineTtsModelConfig(o);
|
||||
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(rule_fsts, ruleFsts);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_INT32(max_num_sentences, maxNumSentences);
|
||||
SHERPA_ONNX_ASSIGN_ATTR_STR(rule_fars, ruleFars);
|
||||
|
||||
SherpaOnnxOfflineTts *tts = SherpaOnnxCreateOfflineTts(&c);
|
||||
|
||||
if (c.model.vits.model) {
|
||||
delete[] c.model.vits.model;
|
||||
}
|
||||
|
||||
if (c.model.vits.lexicon) {
|
||||
delete[] c.model.vits.lexicon;
|
||||
}
|
||||
|
||||
if (c.model.vits.tokens) {
|
||||
delete[] c.model.vits.tokens;
|
||||
}
|
||||
|
||||
if (c.model.vits.data_dir) {
|
||||
delete[] c.model.vits.data_dir;
|
||||
}
|
||||
|
||||
if (c.model.vits.dict_dir) {
|
||||
delete[] c.model.vits.dict_dir;
|
||||
}
|
||||
|
||||
if (c.model.provider) {
|
||||
delete[] c.model.provider;
|
||||
}
|
||||
|
||||
if (c.rule_fsts) {
|
||||
delete[] c.rule_fsts;
|
||||
}
|
||||
|
||||
if (c.rule_fars) {
|
||||
delete[] c.rule_fars;
|
||||
}
|
||||
|
||||
if (!tts) {
|
||||
Napi::TypeError::New(env, "Please check your config!")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
return Napi::External<SherpaOnnxOfflineTts>::New(
|
||||
env, tts, [](Napi::Env env, SherpaOnnxOfflineTts *tts) {
|
||||
SherpaOnnxDestroyOfflineTts(tts);
|
||||
});
|
||||
}
|
||||
|
||||
static Napi::Number OfflineTtsSampleRateWrapper(
|
||||
const Napi::CallbackInfo &info) {
|
||||
Napi::Env env = info.Env();
|
||||
|
||||
if (info.Length() != 1) {
|
||||
std::ostringstream os;
|
||||
os << "Expect only 1 argument. Given: " << info.Length();
|
||||
|
||||
Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!info[0].IsExternal()) {
|
||||
Napi::TypeError::New(env, "Argument 0 should be an offline tts pointer.")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
SherpaOnnxOfflineTts *tts =
|
||||
info[0].As<Napi::External<SherpaOnnxOfflineTts>>().Data();
|
||||
|
||||
int32_t sample_rate = SherpaOnnxOfflineTtsSampleRate(tts);
|
||||
|
||||
return Napi::Number::New(env, sample_rate);
|
||||
}
|
||||
|
||||
static Napi::Number OfflineTtsNumSpeakersWrapper(
|
||||
const Napi::CallbackInfo &info) {
|
||||
Napi::Env env = info.Env();
|
||||
|
||||
if (info.Length() != 1) {
|
||||
std::ostringstream os;
|
||||
os << "Expect only 1 argument. Given: " << info.Length();
|
||||
|
||||
Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!info[0].IsExternal()) {
|
||||
Napi::TypeError::New(env, "Argument 0 should be an offline tts pointer.")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
SherpaOnnxOfflineTts *tts =
|
||||
info[0].As<Napi::External<SherpaOnnxOfflineTts>>().Data();
|
||||
|
||||
int32_t num_speakers = SherpaOnnxOfflineTtsNumSpeakers(tts);
|
||||
|
||||
return Napi::Number::New(env, num_speakers);
|
||||
}
|
||||
|
||||
static Napi::Object OfflineTtsGenerateWrapper(const Napi::CallbackInfo &info) {
|
||||
Napi::Env env = info.Env();
|
||||
|
||||
if (info.Length() != 2) {
|
||||
std::ostringstream os;
|
||||
os << "Expect only 1 argument. Given: " << info.Length();
|
||||
|
||||
Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!info[0].IsExternal()) {
|
||||
Napi::TypeError::New(env, "Argument 0 should be an offline tts pointer.")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
SherpaOnnxOfflineTts *tts =
|
||||
info[0].As<Napi::External<SherpaOnnxOfflineTts>>().Data();
|
||||
|
||||
if (!info[1].IsObject()) {
|
||||
Napi::TypeError::New(env, "Argument 1 should be an object")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
Napi::Object obj = info[1].As<Napi::Object>();
|
||||
|
||||
if (!obj.Has("text")) {
|
||||
Napi::TypeError::New(env, "The argument object should have a field text")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!obj.Get("text").IsString()) {
|
||||
Napi::TypeError::New(env, "The object['text'] should be a string")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!obj.Has("sid")) {
|
||||
Napi::TypeError::New(env, "The argument object should have a field sid")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!obj.Get("sid").IsNumber()) {
|
||||
Napi::TypeError::New(env, "The object['sid'] should be a number")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!obj.Has("speed")) {
|
||||
Napi::TypeError::New(env, "The argument object should have a field speed")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!obj.Get("speed").IsNumber()) {
|
||||
Napi::TypeError::New(env, "The object['speed'] should be a number")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
bool enable_external_buffer = true;
|
||||
if (obj.Has("enableExternalBuffer") &&
|
||||
obj.Get("enableExternalBuffer").IsBoolean()) {
|
||||
enable_external_buffer =
|
||||
obj.Get("enableExternalBuffer").As<Napi::Boolean>().Value();
|
||||
}
|
||||
|
||||
Napi::String _text = obj.Get("text").As<Napi::String>();
|
||||
std::string text = _text.Utf8Value();
|
||||
int32_t sid = obj.Get("sid").As<Napi::Number>().Int32Value();
|
||||
float speed = obj.Get("speed").As<Napi::Number>().FloatValue();
|
||||
|
||||
const SherpaOnnxGeneratedAudio *audio =
|
||||
SherpaOnnxOfflineTtsGenerate(tts, text.c_str(), sid, speed);
|
||||
|
||||
if (enable_external_buffer) {
|
||||
Napi::ArrayBuffer arrayBuffer = Napi::ArrayBuffer::New(
|
||||
env, const_cast<float *>(audio->samples), sizeof(float) * audio->n,
|
||||
[](Napi::Env /*env*/, void * /*data*/,
|
||||
const SherpaOnnxGeneratedAudio *hint) {
|
||||
SherpaOnnxDestroyOfflineTtsGeneratedAudio(hint);
|
||||
},
|
||||
audio);
|
||||
Napi::Float32Array float32Array =
|
||||
Napi::Float32Array::New(env, audio->n, arrayBuffer, 0);
|
||||
|
||||
Napi::Object ans = Napi::Object::New(env);
|
||||
ans.Set(Napi::String::New(env, "samples"), float32Array);
|
||||
ans.Set(Napi::String::New(env, "sampleRate"), audio->sample_rate);
|
||||
return ans;
|
||||
} else {
|
||||
// don't use external buffer
|
||||
Napi::ArrayBuffer arrayBuffer =
|
||||
Napi::ArrayBuffer::New(env, sizeof(float) * audio->n);
|
||||
|
||||
Napi::Float32Array float32Array =
|
||||
Napi::Float32Array::New(env, audio->n, arrayBuffer, 0);
|
||||
|
||||
std::copy(audio->samples, audio->samples + audio->n, float32Array.Data());
|
||||
|
||||
Napi::Object ans = Napi::Object::New(env);
|
||||
ans.Set(Napi::String::New(env, "samples"), float32Array);
|
||||
ans.Set(Napi::String::New(env, "sampleRate"), audio->sample_rate);
|
||||
SherpaOnnxDestroyOfflineTtsGeneratedAudio(audio);
|
||||
return ans;
|
||||
}
|
||||
}
|
||||
|
||||
void InitNonStreamingTts(Napi::Env env, Napi::Object exports) {
|
||||
exports.Set(Napi::String::New(env, "createOfflineTts"),
|
||||
Napi::Function::New(env, CreateOfflineTtsWrapper));
|
||||
|
||||
exports.Set(Napi::String::New(env, "getOfflineTtsSampleRate"),
|
||||
Napi::Function::New(env, OfflineTtsSampleRateWrapper));
|
||||
|
||||
exports.Set(Napi::String::New(env, "getOfflineTtsNumSpeakers"),
|
||||
Napi::Function::New(env, OfflineTtsNumSpeakersWrapper));
|
||||
|
||||
exports.Set(Napi::String::New(env, "offlineTtsGenerate"),
|
||||
Napi::Function::New(env, OfflineTtsGenerateWrapper));
|
||||
}
|
||||
1
scripts/node-addon-api/src/non-streaming-tts.cc
Symbolic link
1
scripts/node-addon-api/src/non-streaming-tts.cc
Symbolic link
@@ -0,0 +1 @@
|
||||
../../../harmony-os/SherpaOnnxHar/sherpa_onnx/src/main/cpp/non-streaming-tts.cc
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user