diff --git a/harmony-os/README.md b/harmony-os/README.md index 566e1a74c..5c1fb9ed7 100644 --- a/harmony-os/README.md +++ b/harmony-os/README.md @@ -13,5 +13,8 @@ - [./SherpaOnnxStreamingAsr](./SherpaOnnxStreamingAsr) It shows how to use streaming ASR models for real-time on-device speech recognition. +- [./SherpaOnnxSpeakerIdentification](./SherpaOnnxSpeakerIdentification) It shows how to use + speaker embedding models for on-device speaker identification. + - [./SherpaOnnxTts](./SherpaOnnxTts) It shows how to run on-device text-to-speech. Please see the doc at diff --git a/harmony-os/SherpaOnnxHar/sherpa_onnx/src/main/cpp/speaker-identification.cc b/harmony-os/SherpaOnnxHar/sherpa_onnx/src/main/cpp/speaker-identification.cc index 21c9a89e7..bf49fef9a 100644 --- a/harmony-os/SherpaOnnxHar/sherpa_onnx/src/main/cpp/speaker-identification.cc +++ b/harmony-os/SherpaOnnxHar/sherpa_onnx/src/main/cpp/speaker-identification.cc @@ -764,7 +764,7 @@ static Napi::Array SpeakerEmbeddingManagerGetAllSpeakersWrapper( int32_t num_speakers = SherpaOnnxSpeakerEmbeddingManagerNumSpeakers(manager); if (num_speakers == 0) { - return {}; + return Napi::Array::New(env, num_speakers); } const char *const *all_speaker_names = diff --git a/harmony-os/SherpaOnnxSpeakerIdentification/.gitignore b/harmony-os/SherpaOnnxSpeakerIdentification/.gitignore new file mode 100644 index 000000000..d2ff20141 --- /dev/null +++ b/harmony-os/SherpaOnnxSpeakerIdentification/.gitignore @@ -0,0 +1,12 @@ +/node_modules +/oh_modules +/local.properties +/.idea +**/build +/.hvigor +.cxx +/.clangd +/.clang-format +/.clang-tidy +**/.test +/.appanalyzer \ No newline at end of file diff --git a/harmony-os/SherpaOnnxSpeakerIdentification/AppScope/app.json5 b/harmony-os/SherpaOnnxSpeakerIdentification/AppScope/app.json5 new file mode 100644 index 000000000..650f50349 --- /dev/null +++ b/harmony-os/SherpaOnnxSpeakerIdentification/AppScope/app.json5 @@ -0,0 +1,10 @@ +{ + "app": { + "bundleName": "com.k2fsa.sherpa.onnx.speaker.identification", + "vendor": "example", + "versionCode": 1000000, + "versionName": "1.0.0", + "icon": "$media:app_icon", + "label": "$string:app_name" + } +} diff --git a/harmony-os/SherpaOnnxSpeakerIdentification/AppScope/resources/base/element/string.json b/harmony-os/SherpaOnnxSpeakerIdentification/AppScope/resources/base/element/string.json new file mode 100644 index 000000000..6204133f2 --- /dev/null +++ b/harmony-os/SherpaOnnxSpeakerIdentification/AppScope/resources/base/element/string.json @@ -0,0 +1,8 @@ +{ + "string": [ + { + "name": "app_name", + "value": "SherpaOnnxSpeakerIdentification" + } + ] +} diff --git a/harmony-os/SherpaOnnxSpeakerIdentification/AppScope/resources/base/media/app_icon.png b/harmony-os/SherpaOnnxSpeakerIdentification/AppScope/resources/base/media/app_icon.png new file mode 100644 index 000000000..a39445dc8 Binary files /dev/null and b/harmony-os/SherpaOnnxSpeakerIdentification/AppScope/resources/base/media/app_icon.png differ diff --git a/harmony-os/SherpaOnnxSpeakerIdentification/build-profile.json5 b/harmony-os/SherpaOnnxSpeakerIdentification/build-profile.json5 new file mode 100644 index 000000000..8e63d9768 --- /dev/null +++ b/harmony-os/SherpaOnnxSpeakerIdentification/build-profile.json5 @@ -0,0 +1,40 @@ +{ + "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" + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/harmony-os/SherpaOnnxSpeakerIdentification/code-linter.json5 b/harmony-os/SherpaOnnxSpeakerIdentification/code-linter.json5 new file mode 100644 index 000000000..77b31b517 --- /dev/null +++ b/harmony-os/SherpaOnnxSpeakerIdentification/code-linter.json5 @@ -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": { + } +} \ No newline at end of file diff --git a/harmony-os/SherpaOnnxSpeakerIdentification/entry/.gitignore b/harmony-os/SherpaOnnxSpeakerIdentification/entry/.gitignore new file mode 100644 index 000000000..e2713a277 --- /dev/null +++ b/harmony-os/SherpaOnnxSpeakerIdentification/entry/.gitignore @@ -0,0 +1,6 @@ +/node_modules +/oh_modules +/.preview +/build +/.cxx +/.test \ No newline at end of file diff --git a/harmony-os/SherpaOnnxSpeakerIdentification/entry/build-profile.json5 b/harmony-os/SherpaOnnxSpeakerIdentification/entry/build-profile.json5 new file mode 100644 index 000000000..572de83dc --- /dev/null +++ b/harmony-os/SherpaOnnxSpeakerIdentification/entry/build-profile.json5 @@ -0,0 +1,33 @@ +{ + "apiType": "stageMode", + "buildOption": { + "sourceOption": { + "workers": [ + './src/main/ets/workers/SpeakerIdentificationWorker.ets' + ] + } + }, + "buildOptionSet": [ + { + "name": "release", + "arkOptions": { + "obfuscation": { + "ruleOptions": { + "enable": false, + "files": [ + "./obfuscation-rules.txt" + ] + } + } + } + }, + ], + "targets": [ + { + "name": "default" + }, + { + "name": "ohosTest", + } + ] +} \ No newline at end of file diff --git a/harmony-os/SherpaOnnxSpeakerIdentification/entry/hvigorfile.ts b/harmony-os/SherpaOnnxSpeakerIdentification/entry/hvigorfile.ts new file mode 100644 index 000000000..c6edcd904 --- /dev/null +++ b/harmony-os/SherpaOnnxSpeakerIdentification/entry/hvigorfile.ts @@ -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. */ +} diff --git a/harmony-os/SherpaOnnxSpeakerIdentification/entry/obfuscation-rules.txt b/harmony-os/SherpaOnnxSpeakerIdentification/entry/obfuscation-rules.txt new file mode 100644 index 000000000..272efb6ca --- /dev/null +++ b/harmony-os/SherpaOnnxSpeakerIdentification/entry/obfuscation-rules.txt @@ -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 \ No newline at end of file diff --git a/harmony-os/SherpaOnnxSpeakerIdentification/entry/oh-package.json5 b/harmony-os/SherpaOnnxSpeakerIdentification/entry/oh-package.json5 new file mode 100644 index 000000000..e57a8e40e --- /dev/null +++ b/harmony-os/SherpaOnnxSpeakerIdentification/entry/oh-package.json5 @@ -0,0 +1,12 @@ +{ + "name": "entry", + "version": "1.0.0", + "description": "Please describe the basic information.", + "main": "", + "author": "", + "license": "", + "dependencies": { + "sherpa_onnx": "1.10.33", + } +} + diff --git a/harmony-os/SherpaOnnxSpeakerIdentification/entry/src/main/ets/entryability/EntryAbility.ets b/harmony-os/SherpaOnnxSpeakerIdentification/entry/src/main/ets/entryability/EntryAbility.ets new file mode 100644 index 000000000..679d91453 --- /dev/null +++ b/harmony-os/SherpaOnnxSpeakerIdentification/entry/src/main/ets/entryability/EntryAbility.ets @@ -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'); + } +} diff --git a/harmony-os/SherpaOnnxSpeakerIdentification/entry/src/main/ets/entrybackupability/EntryBackupAbility.ets b/harmony-os/SherpaOnnxSpeakerIdentification/entry/src/main/ets/entrybackupability/EntryBackupAbility.ets new file mode 100644 index 000000000..d2c48b421 --- /dev/null +++ b/harmony-os/SherpaOnnxSpeakerIdentification/entry/src/main/ets/entrybackupability/EntryBackupAbility.ets @@ -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)); + } +} \ No newline at end of file diff --git a/harmony-os/SherpaOnnxSpeakerIdentification/entry/src/main/ets/pages/Index.ets b/harmony-os/SherpaOnnxSpeakerIdentification/entry/src/main/ets/pages/Index.ets new file mode 100644 index 000000000..ec12f51a6 --- /dev/null +++ b/harmony-os/SherpaOnnxSpeakerIdentification/entry/src/main/ets/pages/Index.ets @@ -0,0 +1,357 @@ +import worker, { MessageEvents } from '@ohos.worker'; +import { audio } from '@kit.AudioKit'; +import { allAllowed, requestPermissions } from './Permission'; +import { Permissions } from '@kit.AbilityKit'; +import { picker } from '@kit.CoreFileKit'; +import fs from '@ohos.file.fs'; + + + +function flatten(samples: Float32Array[]): Float32Array { + let n = 0; + for (let i = 0; i < samples.length; ++i) { + n += samples[i].length; + } + + const ans: Float32Array = new Float32Array(n); + let offset: number = 0; + for (let i = 0; i < samples.length; ++i) { + ans.set(samples[i], offset); + offset += samples[i].length; + } + + return ans; +} + +function savePcmToWav(filename: string, samples: Int16Array, sampleRate: number) { + const fp = fs.openSync(filename, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE); + + const header = new ArrayBuffer(44); + const view = new DataView(header); + + // http://soundfile.sapp.org/doc/WaveFormat/ + // F F I R + view.setUint32(0, 0x46464952, true); // chunkID + view.setUint32(4, 36 + samples.length * 2, true); // chunkSize // E V A W + view.setUint32(8, 0x45564157, true); // format // // t m f + view.setUint32(12, 0x20746d66, true); // subchunk1ID + view.setUint32(16, 16, true); // subchunk1Size, 16 for PCM + view.setUint32(20, 1, true); // audioFormat, 1 for PCM + view.setUint16(22, 1, true); // numChannels: 1 channel + view.setUint32(24, sampleRate, true); // sampleRate + view.setUint32(28, sampleRate * 2, true); // byteRate + view.setUint16(32, 2, true); // blockAlign + view.setUint16(34, 16, true); // bitsPerSample + view.setUint32(36, 0x61746164, true); // Subchunk2ID + view.setUint32(40, samples.length * 2, true); // subchunk2Size + + fs.writeSync(fp.fd, new Uint8Array(header).buffer, { length: header.byteLength }); + fs.writeSync(fp.fd, samples.buffer, { length: samples.buffer.byteLength }); + + fs.closeSync(fp.fd); +} + +function toInt16Samples(samples: Float32Array): Int16Array { + const int16Samples = new Int16Array(samples.length); + for (let i = 0; i < samples.length; ++i) { + let s = samples[i] * 32767; + s = s > 32767 ? 32767 : s; + s = s < -32768 ? -32768 : s; + int16Samples[i] = s; + } + + return int16Samples; +} + +@Entry +@Component +struct Index { + @State title: string = 'Next-gen Kaldi: Speaker Identification'; + @State titleFontSize: number = 18; + private controller: TabsController = new TabsController(); + + @State currentIndex: number = 0; + + @State message: string = 'Hello World'; + + private workerInstance?: worker.ThreadWorker + private readonly scriptURL: string = 'entry/ets/workers/SpeakerIdentificationWorker.ets' + + @State allSpeakerNames: string[] = []; + private inputSpeakerName: string = ''; + + @State btnSaveAudioEnabled: boolean = false; + @State btnAddEnabled: boolean = false; + + private sampleRate: number = 16000; + private sampleList: Float32Array[] = [] + private mic?: audio.AudioCapturer; + + @State infoHome: string = ''; + @State infoAdd: string = ''; + + @State micBtnCaption: string = 'Start recording'; + @State micStarted: boolean = false; + + async initMic() { + const permissions: Permissions[] = ["ohos.permission.MICROPHONE"]; + let allowed: boolean = await allAllowed(permissions); + if (!allowed) { + console.log("request to access the microphone"); + const status: boolean = await requestPermissions(permissions); + + if (!status) { + console.error('access to microphone is denied') + this.infoHome = "Failed to get microphone permission. Please retry"; + this.infoAdd = this.infoHome; + return; + } + + allowed = await allAllowed(permissions); + if (!allowed) { + console.error('failed to get microphone permission'); + this.infoHome = "Failed to get microphone permission. Please retry"; + this.infoAdd = this.infoHome; + return; + } + } else { + console.log("allowed to access microphone"); + } + + const audioStreamInfo: audio.AudioStreamInfo = { + samplingRate: this.sampleRate, + channels: audio.AudioChannel.CHANNEL_1, + sampleFormat: audio.AudioSampleFormat.SAMPLE_FORMAT_S16LE, + encodingType: audio.AudioEncodingType.ENCODING_TYPE_RAW, + }; + + const audioCapturerInfo: audio.AudioCapturerInfo = { + source: audio.SourceType.SOURCE_TYPE_MIC, capturerFlags: 0 + }; + + const audioCapturerOptions: audio.AudioCapturerOptions = { + streamInfo: audioStreamInfo, capturerInfo: audioCapturerInfo + + }; + audio.createAudioCapturer(audioCapturerOptions, (err, data) => { + if (err) { + console.error(`error code is ${err.code}, error message is ${err.message}`); + this.infoHome = 'Failed to init microphone'; + this.infoAdd = this.infoHome; + } else { + console.info(`init mic successfully`); + this.mic = data; + this.mic.on('readData', this.micCallback); + } + }); + } + + async aboutToAppear() { + this.workerInstance = new worker.ThreadWorker(this.scriptURL, { + name: 'Speaker identification worker' + }); + + this.workerInstance.onmessage = (e: MessageEvents) => { + const msgType = e.data['msgType'] as string; + console.log(`received msg from worker: ${msgType}`); + + if (msgType == 'manager-all-speaker-names') { + this.allSpeakerNames = e.data['allSpeakers'] as string[]; + } + }; + + this.workerInstance.postMessage({ msgType: 'init-extractor', context: getContext()}); + + await this.initMic(); + } + + @Builder + TabBuilder(title: string, targetIndex: number, selectedImg: Resource, normalImg: Resource) { + Column() { + Image(this.currentIndex == targetIndex ? selectedImg : normalImg).size({ width: 25, height: 25 }) + Text(title).fontColor(this.currentIndex == targetIndex ? '#28bff1' : '#8a8a8a') + }.width('100%').height(50).justifyContent(FlexAlign.Center).onClick(() => { + this.currentIndex = targetIndex; + this.controller.changeIndex(this.currentIndex); + }) + } + + build() { + Column() { + Tabs({ barPosition: BarPosition.End, controller: this.controller }) { + TabContent() { + Column({ space: 10 }) { + Button('Home') + } + }.tabBar(this.TabBuilder('Home', 0, $r('app.media.icon_home'), $r('app.media.icon_home'))) + + TabContent() { + Column({ space: 10 }) { + Text(this.title).fontSize(this.titleFontSize).fontWeight(FontWeight.Bold); + + if (this.allSpeakerNames.length == 0) { + Text('Please add speakers first') + } else { + List({ space: 10, initialIndex: 0 }) { + ForEach(this.allSpeakerNames, (item: string, index: number) => { + ListItem() { + Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center }) { + Text(item) + .width('100%') + .height(80) + .fontSize(20) + .textAlign(TextAlign.Center) + .borderRadius(10) + .flexShrink(1) + + Button('Delete') + .width('30%') + .height(40) + .onClick(() => { + if (index != undefined) { + const name = this.allSpeakerNames[index]; + console.log(`Deleting speaker ${name}`); + if (this.workerInstance) { + this.workerInstance.postMessage({ + msgType: 'manager-delete-speaker', + name: name + }); + } + } + }).stateEffect(true) + + Text('') + .width('15%') + .height(80) + } + } + }, (item: string) => item) + } + } + } + }.tabBar(this.TabBuilder('View', 1, $r('app.media.icon_view'), $r('app.media.icon_view'))) + + TabContent() { + Column({ space: 10 }) { + Text(this.title).fontSize(this.titleFontSize).fontWeight(FontWeight.Bold); + + Row({space: 10}) { + Text('Speaker name') + TextInput({placeholder: 'Input speaker name'}) + .onChange((value: string)=>{ + this.inputSpeakerName = value.trim(); + }); + }.width('100%') + + Row({space: 10}) { + Button(this.micBtnCaption) + .onClick(()=> { + if (this.mic) { + if (this.micStarted) { + this.micStarted = false; + this.micBtnCaption = 'Start recording'; + this.mic.stop(); + this.infoAdd = ''; + if (this.sampleList.length > 0) { + this.btnAddEnabled = true; + this.btnSaveAudioEnabled = true; + } + } else { + this.micStarted = true; + this.micBtnCaption = 'Stop recording'; + this.sampleList = []; + this.mic.start(); + this.infoAdd = ''; + + this.btnAddEnabled = false; + this.btnSaveAudioEnabled = false; + } + } + + }) + + Button('Add') + .enabled(this.btnAddEnabled) + .onClick(()=>{ + if (this.inputSpeakerName.trim() == '') { + this.infoAdd += 'Please input a speaker name first'; + return; + } + + const samples = flatten(this.sampleList); + console.log(`number of samples: ${samples.length}, ${samples.length / this.sampleRate}`); + }) + + Button('Save audio') + .enabled(this.btnSaveAudioEnabled) + .onClick(()=>{ + if (this.sampleList.length == 0) { + this.btnSaveAudioEnabled = false; + return; + } + + const samples = flatten(this.sampleList); + + if (samples.length == 0) { + this.btnSaveAudioEnabled = false; + return; + } + + let uri: string = ''; + + + const audioOptions = new picker.AudioSaveOptions(); // audioOptions.newFileNames = ['o.wav']; + + const audioViewPicker = new picker.AudioViewPicker(); + + audioViewPicker.save(audioOptions).then((audioSelectResult: Array) => { + uri = audioSelectResult[0]; + savePcmToWav(uri, toInt16Samples(samples), this.sampleRate); + console.log(`Saved to ${uri}`); + this.infoAdd += `\nSaved to ${uri}`; + }); + }) + } + TextArea({text: this.infoAdd}) + .height('100%') + .width('100%') + .focusable(false) + } + }.tabBar(this.TabBuilder('Add', 2, $r('app.media.icon_add'), $r('app.media.icon_add'))) + + TabContent() { + Column({ space: 10 }) { + Text(this.title).fontSize(this.titleFontSize).fontWeight(FontWeight.Bold); + TextArea({ + text: ` +Everyting is open-sourced. + +It runs locally, without accessing the network + +See also https://github.com/k2-fsa/sherpa-onnx + +新一代 Kaldi QQ 和微信交流群: 请看 + +https://k2-fsa.github.io/sherpa/social-groups.html + +微信公众号: 新一代 Kaldi + ` + }).width('100%').height('100%').focusable(false) + } + }.tabBar(this.TabBuilder('Help', 3, $r('app.media.icon_info'), $r('app.media.icon_info'))) + + }.scrollable(false) + }.width('100%') + } + + private micCallback = (buffer: ArrayBuffer) => { + const view: Int16Array = new Int16Array(buffer); + + const samplesFloat: Float32Array = new Float32Array(view.length); + for (let i = 0; i < view.length; ++i) { + samplesFloat[i] = view[i] / 32768.0; + } + + this.sampleList.push(samplesFloat); + } +} \ No newline at end of file diff --git a/harmony-os/SherpaOnnxSpeakerIdentification/entry/src/main/ets/pages/Permission.ets b/harmony-os/SherpaOnnxSpeakerIdentification/entry/src/main/ets/pages/Permission.ets new file mode 100644 index 000000000..40ef391ad --- /dev/null +++ b/harmony-os/SherpaOnnxSpeakerIdentification/entry/src/main/ets/pages/Permission.ets @@ -0,0 +1,26 @@ +// This file is modified from +// https://gitee.com/ukSir/hmchat2/blob/master/entry/src/main/ets/utils/permissionMananger.ets +import { abilityAccessCtrl, bundleManager, common, Permissions } from '@kit.AbilityKit'; + +export function allAllowed(permissions: Permissions[]): boolean { + if (permissions.length == 0) { + return false; + } + + const mgr: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager(); + + const bundleInfo = bundleManager.getBundleInfoForSelfSync(bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION); + + let tokenID: number = bundleInfo.appInfo.accessTokenId; + + return permissions.every(permission => abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED == + mgr.checkAccessTokenSync(tokenID, permission)); +} + +export async function requestPermissions(permissions: Permissions[]): Promise { + const mgr: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager(); + const context: Context = getContext() as common.UIAbilityContext; + + const result = await mgr.requestPermissionsFromUser(context, permissions); + return result.authResults.length > 0 && result.authResults.every(authResults => authResults == 0); +} \ No newline at end of file diff --git a/harmony-os/SherpaOnnxSpeakerIdentification/entry/src/main/ets/workers/SpeakerIdentificationWorker.ets b/harmony-os/SherpaOnnxSpeakerIdentification/entry/src/main/ets/workers/SpeakerIdentificationWorker.ets new file mode 100644 index 000000000..9dd97d108 --- /dev/null +++ b/harmony-os/SherpaOnnxSpeakerIdentification/entry/src/main/ets/workers/SpeakerIdentificationWorker.ets @@ -0,0 +1,113 @@ +import worker, { ThreadWorkerGlobalScope, MessageEvents, ErrorEvent } from '@ohos.worker'; +import { + readWaveFromBinary, + Samples, + SpeakerEmbeddingExtractor, + SpeakerEmbeddingExtractorConfig, + SpeakerEmbeddingManager +} from 'sherpa_onnx'; +import { fileIo } from '@kit.CoreFileKit'; + +const workerPort: ThreadWorkerGlobalScope = worker.workerPort; + +let extractor: SpeakerEmbeddingExtractor; +let manager: SpeakerEmbeddingManager; + +function readWaveFromRawfile(filename: string, context: Context): Samples { + const data: Uint8Array = context.resourceManager.getRawFileContentSync(filename); + return readWaveFromBinary(data) as Samples; +} + +function initExtractor(context: Context): SpeakerEmbeddingExtractor { + const config = new SpeakerEmbeddingExtractorConfig(); + config.model = '3dspeaker_speech_eres2net_base_sv_zh-cn_3dspeaker_16k.onnx'; + config.numThreads = 2; + config.debug = true; + + return new SpeakerEmbeddingExtractor(config, context.resourceManager); +} + +function extractEmbedding(samples: Samples): Float32Array { + const stream = extractor.createStream(); + stream.acceptWaveform(samples); + return extractor.compute(stream); +} + +/** + * Defines the event handler to be called when the worker thread receives a message sent by the host thread. + * The event handler is executed in the worker thread. + * + * @param e message data + */ +workerPort.onmessage = (e: MessageEvents) => { + const msgType = e.data['msgType'] as string; + + console.log(`from the main thread, msg-type: ${msgType}`); + + if (msgType == 'init-extractor' && !extractor) { + const context: Context = e.data['context'] as Context; + extractor = initExtractor(context); + manager = new SpeakerEmbeddingManager(extractor.dim); + + const filename1 = 'sr-data/enroll/fangjun-sr-1.wav'; + const samples1 = readWaveFromRawfile(filename1, context); + console.log(`sample rate: ${samples1.sampleRate}`); + let ok = manager.add({ name: 'fangjun0', v: extractEmbedding(samples1) }); + ok = manager.add({ name: 'fangjun1', v: extractEmbedding(samples1) }); + /* + ok = manager.add({ name: 'fangjun2', v: extractEmbedding(samples1) }); + ok = manager.add({ name: 'fangjun3', v: extractEmbedding(samples1) }); + ok = manager.add({ name: 'fangjun4', v: extractEmbedding(samples1) }); + ok = manager.add({ name: 'fangjun5', v: extractEmbedding(samples1) }); + ok = manager.add({ name: 'fangjun6', v: extractEmbedding(samples1) }); + ok = manager.add({ name: 'fangjun7', v: extractEmbedding(samples1) }); + ok = manager.add({ name: 'fangjun8', v: extractEmbedding(samples1) }); + ok = manager.add({ name: 'fangjun9', v: extractEmbedding(samples1) }); + ok = manager.add({ name: 'fangjun10', v: extractEmbedding(samples1) }); + */ + + if (ok) { + console.log(`Added fangjun`); + let n = manager.getNumSpeakers(); + console.log(`number of speakers: ${n}`); + console.log(`speaker names: ${manager.getAllSpeakerNames().join('\n')}`); + } + + workerPort.postMessage({ + msgType: 'manager-all-speaker-names', allSpeakers: manager.getAllSpeakerNames(), + }); + } + + if (msgType == 'manager-delete-speaker') { + const name = e.data['name'] as string; + const ok = manager.remove(name); + if (ok) { + console.log(`Removed ${name}.`); + + console.log(`Number of speakers: ${manager.getNumSpeakers()}`); + console.log(`Number of speakers2: ${manager.getAllSpeakerNames().length}`); + console.log(JSON.stringify(manager.getAllSpeakerNames())); + workerPort.postMessage({ + msgType: 'manager-all-speaker-names', allSpeakers: manager.getAllSpeakerNames(), + }); + } + } +} + +/** + * Defines the event handler to be called when the worker receives a message that cannot be deserialized. + * The event handler is executed in the worker thread. + * + * @param e message data + */ +workerPort.onmessageerror = (e: MessageEvents) => { +} + +/** + * Defines the event handler to be called when an exception occurs during worker execution. + * The event handler is executed in the worker thread. + * + * @param e error message + */ +workerPort.onerror = (e: ErrorEvent) => { +} \ No newline at end of file diff --git a/harmony-os/SherpaOnnxSpeakerIdentification/entry/src/main/module.json5 b/harmony-os/SherpaOnnxSpeakerIdentification/entry/src/main/module.json5 new file mode 100644 index 000000000..80e93ca6a --- /dev/null +++ b/harmony-os/SherpaOnnxSpeakerIdentification/entry/src/main/module.json5 @@ -0,0 +1,64 @@ +{ + "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" + } + ], + } + ], + "requestPermissions": [ + { + "name": "ohos.permission.MICROPHONE", + "reason": "$string:mic_reason", + "usedScene": { + "abilities": [ + "EntryAbility", + ], + "when": "inuse", + } + } + ] + } +} \ No newline at end of file diff --git a/harmony-os/SherpaOnnxSpeakerIdentification/entry/src/main/resources/base/element/color.json b/harmony-os/SherpaOnnxSpeakerIdentification/entry/src/main/resources/base/element/color.json new file mode 100644 index 000000000..3c712962d --- /dev/null +++ b/harmony-os/SherpaOnnxSpeakerIdentification/entry/src/main/resources/base/element/color.json @@ -0,0 +1,8 @@ +{ + "color": [ + { + "name": "start_window_background", + "value": "#FFFFFF" + } + ] +} \ No newline at end of file diff --git a/harmony-os/SherpaOnnxSpeakerIdentification/entry/src/main/resources/base/element/string.json b/harmony-os/SherpaOnnxSpeakerIdentification/entry/src/main/resources/base/element/string.json new file mode 100644 index 000000000..d2ba01212 --- /dev/null +++ b/harmony-os/SherpaOnnxSpeakerIdentification/entry/src/main/resources/base/element/string.json @@ -0,0 +1,20 @@ +{ + "string": [ + { + "name": "module_desc", + "value": "On-device speaker identification with Next-gen Kaldi" + }, + { + "name": "EntryAbility_desc", + "value": "On-device speaker identification with Next-gen Kaldi" + }, + { + "name": "EntryAbility_label", + "value": "Speaker identification" + }, + { + "name": "mic_reason", + "value": "access the microphone for on-device speaker identification with Next-gen Kaldi" + } + ] +} \ No newline at end of file diff --git a/harmony-os/SherpaOnnxSpeakerIdentification/entry/src/main/resources/base/media/background.png b/harmony-os/SherpaOnnxSpeakerIdentification/entry/src/main/resources/base/media/background.png new file mode 100644 index 000000000..f939c9fa8 Binary files /dev/null and b/harmony-os/SherpaOnnxSpeakerIdentification/entry/src/main/resources/base/media/background.png differ diff --git a/harmony-os/SherpaOnnxSpeakerIdentification/entry/src/main/resources/base/media/foreground.png b/harmony-os/SherpaOnnxSpeakerIdentification/entry/src/main/resources/base/media/foreground.png new file mode 100644 index 000000000..4483ddad1 Binary files /dev/null and b/harmony-os/SherpaOnnxSpeakerIdentification/entry/src/main/resources/base/media/foreground.png differ diff --git a/harmony-os/SherpaOnnxSpeakerIdentification/entry/src/main/resources/base/media/icon_add.svg b/harmony-os/SherpaOnnxSpeakerIdentification/entry/src/main/resources/base/media/icon_add.svg new file mode 100644 index 000000000..6ddbb59df --- /dev/null +++ b/harmony-os/SherpaOnnxSpeakerIdentification/entry/src/main/resources/base/media/icon_add.svg @@ -0,0 +1,10 @@ + + + + Public/ic_public_list_add_light + Created with Sketch. + + + + + \ No newline at end of file diff --git a/harmony-os/SherpaOnnxSpeakerIdentification/entry/src/main/resources/base/media/icon_home.svg b/harmony-os/SherpaOnnxSpeakerIdentification/entry/src/main/resources/base/media/icon_home.svg new file mode 100644 index 000000000..504af3400 --- /dev/null +++ b/harmony-os/SherpaOnnxSpeakerIdentification/entry/src/main/resources/base/media/icon_home.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/harmony-os/SherpaOnnxSpeakerIdentification/entry/src/main/resources/base/media/icon_info.svg b/harmony-os/SherpaOnnxSpeakerIdentification/entry/src/main/resources/base/media/icon_info.svg new file mode 100644 index 000000000..2210223f4 --- /dev/null +++ b/harmony-os/SherpaOnnxSpeakerIdentification/entry/src/main/resources/base/media/icon_info.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/harmony-os/SherpaOnnxSpeakerIdentification/entry/src/main/resources/base/media/icon_view.svg b/harmony-os/SherpaOnnxSpeakerIdentification/entry/src/main/resources/base/media/icon_view.svg new file mode 100644 index 000000000..b7958b5ed --- /dev/null +++ b/harmony-os/SherpaOnnxSpeakerIdentification/entry/src/main/resources/base/media/icon_view.svg @@ -0,0 +1,13 @@ + + + Public/ic_public_view_list_filled + + + + + + + + + + \ No newline at end of file diff --git a/harmony-os/SherpaOnnxSpeakerIdentification/entry/src/main/resources/base/media/layered_image.json b/harmony-os/SherpaOnnxSpeakerIdentification/entry/src/main/resources/base/media/layered_image.json new file mode 100644 index 000000000..fb4992044 --- /dev/null +++ b/harmony-os/SherpaOnnxSpeakerIdentification/entry/src/main/resources/base/media/layered_image.json @@ -0,0 +1,7 @@ +{ + "layered-image": + { + "background" : "$media:background", + "foreground" : "$media:foreground" + } +} \ No newline at end of file diff --git a/harmony-os/SherpaOnnxSpeakerIdentification/entry/src/main/resources/base/media/startIcon.png b/harmony-os/SherpaOnnxSpeakerIdentification/entry/src/main/resources/base/media/startIcon.png new file mode 100644 index 000000000..205ad8b5a Binary files /dev/null and b/harmony-os/SherpaOnnxSpeakerIdentification/entry/src/main/resources/base/media/startIcon.png differ diff --git a/harmony-os/SherpaOnnxSpeakerIdentification/entry/src/main/resources/base/profile/backup_config.json b/harmony-os/SherpaOnnxSpeakerIdentification/entry/src/main/resources/base/profile/backup_config.json new file mode 100644 index 000000000..78f40ae7c --- /dev/null +++ b/harmony-os/SherpaOnnxSpeakerIdentification/entry/src/main/resources/base/profile/backup_config.json @@ -0,0 +1,3 @@ +{ + "allowToBackupRestore": true +} \ No newline at end of file diff --git a/harmony-os/SherpaOnnxSpeakerIdentification/entry/src/main/resources/base/profile/main_pages.json b/harmony-os/SherpaOnnxSpeakerIdentification/entry/src/main/resources/base/profile/main_pages.json new file mode 100644 index 000000000..1898d94f5 --- /dev/null +++ b/harmony-os/SherpaOnnxSpeakerIdentification/entry/src/main/resources/base/profile/main_pages.json @@ -0,0 +1,5 @@ +{ + "src": [ + "pages/Index" + ] +} diff --git a/harmony-os/SherpaOnnxSpeakerIdentification/entry/src/main/resources/en_US/element/string.json b/harmony-os/SherpaOnnxSpeakerIdentification/entry/src/main/resources/en_US/element/string.json new file mode 100644 index 000000000..d2ba01212 --- /dev/null +++ b/harmony-os/SherpaOnnxSpeakerIdentification/entry/src/main/resources/en_US/element/string.json @@ -0,0 +1,20 @@ +{ + "string": [ + { + "name": "module_desc", + "value": "On-device speaker identification with Next-gen Kaldi" + }, + { + "name": "EntryAbility_desc", + "value": "On-device speaker identification with Next-gen Kaldi" + }, + { + "name": "EntryAbility_label", + "value": "Speaker identification" + }, + { + "name": "mic_reason", + "value": "access the microphone for on-device speaker identification with Next-gen Kaldi" + } + ] +} \ No newline at end of file diff --git a/harmony-os/SherpaOnnxSpeakerIdentification/entry/src/main/resources/rawfile/.gitkeep b/harmony-os/SherpaOnnxSpeakerIdentification/entry/src/main/resources/rawfile/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/harmony-os/SherpaOnnxSpeakerIdentification/entry/src/main/resources/zh_CN/element/string.json b/harmony-os/SherpaOnnxSpeakerIdentification/entry/src/main/resources/zh_CN/element/string.json new file mode 100644 index 000000000..0a580accd --- /dev/null +++ b/harmony-os/SherpaOnnxSpeakerIdentification/entry/src/main/resources/zh_CN/element/string.json @@ -0,0 +1,20 @@ +{ + "string": [ + { + "name": "module_desc", + "value": "新一代Kaldi: 本地说话人识别" + }, + { + "name": "EntryAbility_desc", + "value": "新一代Kaldi: 本地说话人识别" + }, + { + "name": "EntryAbility_label", + "value": "说话人识别" + }, + { + "name": "mic_reason", + "value": "使用新一代Kaldi, 访问麦克风进行本地说话人识别 (不需要联网)" + } + ] +} \ No newline at end of file diff --git a/harmony-os/SherpaOnnxSpeakerIdentification/entry/src/ohosTest/ets/test/Ability.test.ets b/harmony-os/SherpaOnnxSpeakerIdentification/entry/src/ohosTest/ets/test/Ability.test.ets new file mode 100644 index 000000000..8aa374977 --- /dev/null +++ b/harmony-os/SherpaOnnxSpeakerIdentification/entry/src/ohosTest/ets/test/Ability.test.ets @@ -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); + }) + }) +} \ No newline at end of file diff --git a/harmony-os/SherpaOnnxSpeakerIdentification/entry/src/ohosTest/ets/test/List.test.ets b/harmony-os/SherpaOnnxSpeakerIdentification/entry/src/ohosTest/ets/test/List.test.ets new file mode 100644 index 000000000..794c7dc4e --- /dev/null +++ b/harmony-os/SherpaOnnxSpeakerIdentification/entry/src/ohosTest/ets/test/List.test.ets @@ -0,0 +1,5 @@ +import abilityTest from './Ability.test'; + +export default function testsuite() { + abilityTest(); +} \ No newline at end of file diff --git a/harmony-os/SherpaOnnxSpeakerIdentification/entry/src/ohosTest/module.json5 b/harmony-os/SherpaOnnxSpeakerIdentification/entry/src/ohosTest/module.json5 new file mode 100644 index 000000000..55725a929 --- /dev/null +++ b/harmony-os/SherpaOnnxSpeakerIdentification/entry/src/ohosTest/module.json5 @@ -0,0 +1,13 @@ +{ + "module": { + "name": "entry_test", + "type": "feature", + "deviceTypes": [ + "phone", + "tablet", + "2in1" + ], + "deliveryWithInstall": true, + "installationFree": false + } +} diff --git a/harmony-os/SherpaOnnxSpeakerIdentification/entry/src/test/List.test.ets b/harmony-os/SherpaOnnxSpeakerIdentification/entry/src/test/List.test.ets new file mode 100644 index 000000000..bb5b5c373 --- /dev/null +++ b/harmony-os/SherpaOnnxSpeakerIdentification/entry/src/test/List.test.ets @@ -0,0 +1,5 @@ +import localUnitTest from './LocalUnit.test'; + +export default function testsuite() { + localUnitTest(); +} \ No newline at end of file diff --git a/harmony-os/SherpaOnnxSpeakerIdentification/entry/src/test/LocalUnit.test.ets b/harmony-os/SherpaOnnxSpeakerIdentification/entry/src/test/LocalUnit.test.ets new file mode 100644 index 000000000..165fc1615 --- /dev/null +++ b/harmony-os/SherpaOnnxSpeakerIdentification/entry/src/test/LocalUnit.test.ets @@ -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); + }); + }); +} \ No newline at end of file diff --git a/harmony-os/SherpaOnnxSpeakerIdentification/hvigor/hvigor-config.json5 b/harmony-os/SherpaOnnxSpeakerIdentification/hvigor/hvigor-config.json5 new file mode 100644 index 000000000..06b278367 --- /dev/null +++ b/harmony-os/SherpaOnnxSpeakerIdentification/hvigor/hvigor-config.json5 @@ -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*/ + } +} diff --git a/harmony-os/SherpaOnnxSpeakerIdentification/hvigorfile.ts b/harmony-os/SherpaOnnxSpeakerIdentification/hvigorfile.ts new file mode 100644 index 000000000..f3cb9f1a8 --- /dev/null +++ b/harmony-os/SherpaOnnxSpeakerIdentification/hvigorfile.ts @@ -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. */ +} diff --git a/harmony-os/SherpaOnnxSpeakerIdentification/oh-package-lock.json5 b/harmony-os/SherpaOnnxSpeakerIdentification/oh-package-lock.json5 new file mode 100644 index 000000000..f538ae290 --- /dev/null +++ b/harmony-os/SherpaOnnxSpeakerIdentification/oh-package-lock.json5 @@ -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" + } + } +} \ No newline at end of file diff --git a/harmony-os/SherpaOnnxSpeakerIdentification/oh-package.json5 b/harmony-os/SherpaOnnxSpeakerIdentification/oh-package.json5 new file mode 100644 index 000000000..a79d5300e --- /dev/null +++ b/harmony-os/SherpaOnnxSpeakerIdentification/oh-package.json5 @@ -0,0 +1,9 @@ +{ + "modelVersion": "5.0.0", + "description": "Please describe the basic information.", + "dependencies": { + }, + "devDependencies": { + "@ohos/hypium": "1.0.19" + } +} diff --git a/harmony-os/SherpaOnnxStreamingAsr/entry/src/main/resources/base/element/string.json b/harmony-os/SherpaOnnxStreamingAsr/entry/src/main/resources/base/element/string.json index 8679134da..207a99982 100644 --- a/harmony-os/SherpaOnnxStreamingAsr/entry/src/main/resources/base/element/string.json +++ b/harmony-os/SherpaOnnxStreamingAsr/entry/src/main/resources/base/element/string.json @@ -14,7 +14,7 @@ }, { "name": "mic_reason", - "value": "access the microhone for on-device real-time speech recognition with Next-gen Kaldi" + "value": "access the microphone for on-device real-time speech recognition with Next-gen Kaldi" } ] -} \ No newline at end of file +} diff --git a/harmony-os/SherpaOnnxStreamingAsr/entry/src/main/resources/en_US/element/string.json b/harmony-os/SherpaOnnxStreamingAsr/entry/src/main/resources/en_US/element/string.json index 8679134da..207a99982 100644 --- a/harmony-os/SherpaOnnxStreamingAsr/entry/src/main/resources/en_US/element/string.json +++ b/harmony-os/SherpaOnnxStreamingAsr/entry/src/main/resources/en_US/element/string.json @@ -14,7 +14,7 @@ }, { "name": "mic_reason", - "value": "access the microhone for on-device real-time speech recognition with Next-gen Kaldi" + "value": "access the microphone for on-device real-time speech recognition with Next-gen Kaldi" } ] -} \ No newline at end of file +} diff --git a/harmony-os/SherpaOnnxVadAsr/entry/src/main/resources/base/element/string.json b/harmony-os/SherpaOnnxVadAsr/entry/src/main/resources/base/element/string.json index 652fac4cc..a47ca31cc 100644 --- a/harmony-os/SherpaOnnxVadAsr/entry/src/main/resources/base/element/string.json +++ b/harmony-os/SherpaOnnxVadAsr/entry/src/main/resources/base/element/string.json @@ -14,7 +14,7 @@ }, { "name": "mic_reason", - "value": "access the microhone for on-device speech recognition with Next-gen Kaldi" + "value": "access the microphone for on-device speech recognition with Next-gen Kaldi" } ] -} \ No newline at end of file +} diff --git a/harmony-os/SherpaOnnxVadAsr/entry/src/main/resources/en_US/element/string.json b/harmony-os/SherpaOnnxVadAsr/entry/src/main/resources/en_US/element/string.json index 652fac4cc..a47ca31cc 100644 --- a/harmony-os/SherpaOnnxVadAsr/entry/src/main/resources/en_US/element/string.json +++ b/harmony-os/SherpaOnnxVadAsr/entry/src/main/resources/en_US/element/string.json @@ -14,7 +14,7 @@ }, { "name": "mic_reason", - "value": "access the microhone for on-device speech recognition with Next-gen Kaldi" + "value": "access the microphone for on-device speech recognition with Next-gen Kaldi" } ] -} \ No newline at end of file +}