react-native-sherpa-onnx 0.3.8 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +20 -5
- package/SherpaOnnx.podspec +5 -1
- package/android/prebuilt-download.gradle +89 -49
- package/android/prebuilt-versions.gradle +1 -1
- package/android/src/main/assets/model_licenses/asr-models-license-status.csv +1 -0
- package/android/src/main/assets/model_licenses/speech-enhancement-models-license-status.csv +7 -0
- package/android/src/main/cpp/CMakeLists.txt +3 -0
- package/android/src/main/cpp/jni/model_detect/sherpa-onnx-enhancement-wrapper.cpp +68 -0
- package/android/src/main/cpp/jni/model_detect/sherpa-onnx-enhancement-wrapper.h +17 -0
- package/android/src/main/cpp/jni/model_detect/sherpa-onnx-model-detect-enhancement.cpp +119 -0
- package/android/src/main/cpp/jni/model_detect/sherpa-onnx-model-detect-helper.cpp +23 -0
- package/android/src/main/cpp/jni/model_detect/sherpa-onnx-model-detect-helper.h +9 -0
- package/android/src/main/cpp/jni/model_detect/sherpa-onnx-model-detect-stt.cpp +51 -8
- package/android/src/main/cpp/jni/model_detect/sherpa-onnx-model-detect.h +41 -0
- package/android/src/main/cpp/jni/model_detect/sherpa-onnx-stt-wrapper.cpp +5 -0
- package/android/src/main/cpp/jni/model_detect/sherpa-onnx-validate-enhancement.cpp +68 -0
- package/android/src/main/cpp/jni/model_detect/sherpa-onnx-validate-enhancement.h +30 -0
- package/android/src/main/cpp/jni/model_detect/sherpa-onnx-validate-stt.cpp +11 -0
- package/android/src/main/cpp/jni/module/sherpa-onnx-module-jni.cpp +21 -0
- package/android/src/main/java/com/sherpaonnx/SherpaOnnxArchiveHelper.kt +110 -35
- package/android/src/main/java/com/sherpaonnx/SherpaOnnxAssetHelper.kt +6 -0
- package/android/src/main/java/com/sherpaonnx/SherpaOnnxEnhancementHelper.kt +377 -0
- package/android/src/main/java/com/sherpaonnx/SherpaOnnxExtractionNotificationHelper.kt +102 -0
- package/android/src/main/java/com/sherpaonnx/SherpaOnnxModule.kt +198 -18
- package/android/src/main/java/com/sherpaonnx/SherpaOnnxSttHelper.kt +22 -0
- package/ios/Resources/model_licenses/asr-models-license-status.csv +1 -0
- package/ios/Resources/model_licenses/speech-enhancement-models-license-status.csv +7 -0
- package/ios/SherpaOnnx+Assets.mm +5 -0
- package/ios/SherpaOnnx+Enhancement.mm +435 -0
- package/ios/SherpaOnnx+STT.mm +13 -1
- package/ios/SherpaOnnx.mm +87 -17
- package/ios/enhancement/sherpa-onnx-enhancement-wrapper.h +85 -0
- package/ios/enhancement/sherpa-onnx-enhancement-wrapper.mm +218 -0
- package/ios/model_detect/sherpa-onnx-model-detect-enhancement.mm +92 -0
- package/ios/model_detect/sherpa-onnx-model-detect-helper.h +5 -0
- package/ios/model_detect/sherpa-onnx-model-detect-helper.mm +23 -0
- package/ios/model_detect/sherpa-onnx-model-detect-stt.mm +51 -7
- package/ios/model_detect/sherpa-onnx-model-detect.h +33 -0
- package/ios/model_detect/sherpa-onnx-validate-enhancement.h +30 -0
- package/ios/model_detect/sherpa-onnx-validate-enhancement.mm +69 -0
- package/ios/model_detect/sherpa-onnx-validate-stt.mm +11 -0
- package/ios/stt/sherpa-onnx-stt-wrapper.h +11 -1
- package/ios/stt/sherpa-onnx-stt-wrapper.mm +30 -2
- package/ios/tts/sherpa-onnx-tts-wrapper.mm +16 -0
- package/lib/module/NativeSherpaOnnx.js.map +1 -1
- package/lib/module/download/localModels.js +2 -3
- package/lib/module/download/localModels.js.map +1 -1
- package/lib/module/download/paths.js +2 -1
- package/lib/module/download/paths.js.map +1 -1
- package/lib/module/download/postDownloadProcessing.js +17 -4
- package/lib/module/download/postDownloadProcessing.js.map +1 -1
- package/lib/module/enhancement/index.js +63 -48
- package/lib/module/enhancement/index.js.map +1 -1
- package/lib/module/enhancement/streaming.js +60 -0
- package/lib/module/enhancement/streaming.js.map +1 -0
- package/lib/module/enhancement/streamingTypes.js +4 -0
- package/lib/module/enhancement/streamingTypes.js.map +1 -0
- package/lib/module/enhancement/types.js +4 -0
- package/lib/module/enhancement/types.js.map +1 -0
- package/lib/module/extraction/extractTarBz2.js +2 -2
- package/lib/module/extraction/extractTarBz2.js.map +1 -1
- package/lib/module/extraction/extractTarZst.js +2 -2
- package/lib/module/extraction/extractTarZst.js.map +1 -1
- package/lib/module/extraction/index.js +10 -5
- package/lib/module/extraction/index.js.map +1 -1
- package/lib/module/licenses.js +9 -3
- package/lib/module/licenses.js.map +1 -1
- package/lib/module/stt/index.js +4 -2
- package/lib/module/stt/index.js.map +1 -1
- package/lib/module/stt/streaming.js +2 -1
- package/lib/module/stt/streaming.js.map +1 -1
- package/lib/module/stt/types.js +3 -1
- package/lib/module/stt/types.js.map +1 -1
- package/lib/module/tts/index.js +4 -2
- package/lib/module/tts/index.js.map +1 -1
- package/lib/module/tts/streaming.js +3 -1
- package/lib/module/tts/streaming.js.map +1 -1
- package/lib/typescript/src/NativeSherpaOnnx.d.ts +70 -9
- package/lib/typescript/src/NativeSherpaOnnx.d.ts.map +1 -1
- package/lib/typescript/src/download/localModels.d.ts.map +1 -1
- package/lib/typescript/src/download/paths.d.ts +2 -1
- package/lib/typescript/src/download/paths.d.ts.map +1 -1
- package/lib/typescript/src/download/postDownloadProcessing.d.ts +9 -0
- package/lib/typescript/src/download/postDownloadProcessing.d.ts.map +1 -1
- package/lib/typescript/src/enhancement/index.d.ts +9 -46
- package/lib/typescript/src/enhancement/index.d.ts.map +1 -1
- package/lib/typescript/src/enhancement/streaming.d.ts +6 -0
- package/lib/typescript/src/enhancement/streaming.d.ts.map +1 -0
- package/lib/typescript/src/enhancement/streamingTypes.d.ts +12 -0
- package/lib/typescript/src/enhancement/streamingTypes.d.ts.map +1 -0
- package/lib/typescript/src/enhancement/types.d.ts +31 -0
- package/lib/typescript/src/enhancement/types.d.ts.map +1 -0
- package/lib/typescript/src/extraction/extractTarBz2.d.ts +2 -1
- package/lib/typescript/src/extraction/extractTarBz2.d.ts.map +1 -1
- package/lib/typescript/src/extraction/extractTarZst.d.ts +2 -1
- package/lib/typescript/src/extraction/extractTarZst.d.ts.map +1 -1
- package/lib/typescript/src/extraction/index.d.ts +1 -1
- package/lib/typescript/src/extraction/index.d.ts.map +1 -1
- package/lib/typescript/src/extraction/types.d.ts +12 -0
- package/lib/typescript/src/extraction/types.d.ts.map +1 -1
- package/lib/typescript/src/licenses.d.ts.map +1 -1
- package/lib/typescript/src/stt/index.d.ts +1 -1
- package/lib/typescript/src/stt/index.d.ts.map +1 -1
- package/lib/typescript/src/stt/streaming.d.ts.map +1 -1
- package/lib/typescript/src/stt/types.d.ts +16 -1
- package/lib/typescript/src/stt/types.d.ts.map +1 -1
- package/lib/typescript/src/tts/index.d.ts.map +1 -1
- package/lib/typescript/src/tts/streaming.d.ts.map +1 -1
- package/package.json +1 -1
- package/scripts/ci/check-model-csvs.sh +27 -2
- package/scripts/ci/collect_all_sherpa_model_streams.sh +3 -1
- package/scripts/ci/collect_one_sherpa_release_stream.sh +3 -1
- package/scripts/ci/sherpa_speech_enhancement_model_release_streams.json +13 -0
- package/scripts/ci/update_model_license_csv.sh +17 -17
- package/src/NativeSherpaOnnx.ts +108 -10
- package/src/download/localModels.ts +1 -3
- package/src/download/paths.ts +2 -1
- package/src/download/postDownloadProcessing.ts +24 -1
- package/src/enhancement/index.ts +120 -58
- package/src/enhancement/streaming.ts +105 -0
- package/src/enhancement/streamingTypes.ts +14 -0
- package/src/enhancement/types.ts +36 -0
- package/src/extraction/extractTarBz2.ts +7 -2
- package/src/extraction/extractTarZst.ts +7 -2
- package/src/extraction/index.ts +29 -6
- package/src/extraction/types.ts +16 -0
- package/src/licenses.ts +13 -2
- package/src/stt/index.ts +8 -7
- package/src/stt/streaming.ts +7 -1
- package/src/stt/types.ts +18 -0
- package/src/tts/index.ts +7 -7
- package/src/tts/streaming.ts +6 -3
- package/third_party/sherpa-onnx-prebuilt/ANDROID_RELEASE_TAG +1 -1
- package/third_party/sherpa-onnx-prebuilt/IOS_RELEASE_TAG +1 -1
package/src/download/paths.ts
CHANGED
|
@@ -122,7 +122,8 @@ export function getExtractionStatePath(
|
|
|
122
122
|
/**
|
|
123
123
|
* Directory where native `resolveAssetPath` materializes a bundled model folder
|
|
124
124
|
* (`DocumentDirectoryPath/models/{modelId}` — Android internal `files/models/...`).
|
|
125
|
-
* Separate from {@link getModelDir}.
|
|
125
|
+
* Separate from {@link getModelDir}. `deleteModelByCategory` does not remove this tree; it
|
|
126
|
+
* only deletes download-manager installs under `sherpa-onnx/models/`.
|
|
126
127
|
*/
|
|
127
128
|
export function getNativeAssetExtractedModelDir(modelId: string): string {
|
|
128
129
|
const safeId = modelId.replace(/[/\\]/g, '');
|
|
@@ -43,6 +43,15 @@ export type RunPostDownloadProcessingOptions = {
|
|
|
43
43
|
onChecksumIssue?: (issue: ChecksumIssue) => Promise<boolean>;
|
|
44
44
|
deleteArchiveAfterExtract?: boolean;
|
|
45
45
|
onProgress?: (progress: DownloadProgress) => void;
|
|
46
|
+
/**
|
|
47
|
+
* **Android:** Native extraction progress notification (default true), aligned with the download-manager flow.
|
|
48
|
+
* **iOS:** No effect.
|
|
49
|
+
*/
|
|
50
|
+
showExtractionNotifications?: boolean;
|
|
51
|
+
/** **Android:** Optional notification title (default: SDK/native default title). */
|
|
52
|
+
extractionNotificationTitle?: string;
|
|
53
|
+
/** **Android:** Optional notification body prefix (progress percent is appended natively). */
|
|
54
|
+
extractionNotificationText?: string;
|
|
46
55
|
/** Called to get current list of downloaded models for emitModelsListUpdated. */
|
|
47
56
|
getDownloadedList: () => Promise<ModelMetaBase[]>;
|
|
48
57
|
};
|
|
@@ -63,6 +72,9 @@ export async function runPostDownloadProcessing(
|
|
|
63
72
|
deleteArchiveAfterExtract,
|
|
64
73
|
onProgress,
|
|
65
74
|
getDownloadedList,
|
|
75
|
+
showExtractionNotifications,
|
|
76
|
+
extractionNotificationTitle,
|
|
77
|
+
extractionNotificationText,
|
|
66
78
|
} = options;
|
|
67
79
|
|
|
68
80
|
registerActivePostProcess(category, id);
|
|
@@ -80,6 +92,9 @@ export async function runPostDownloadProcessing(
|
|
|
80
92
|
deleteArchiveAfterExtract,
|
|
81
93
|
onProgress,
|
|
82
94
|
getDownloadedList,
|
|
95
|
+
showExtractionNotifications,
|
|
96
|
+
extractionNotificationTitle,
|
|
97
|
+
extractionNotificationText,
|
|
83
98
|
});
|
|
84
99
|
} finally {
|
|
85
100
|
unregisterActivePostProcess(category, id);
|
|
@@ -102,6 +117,9 @@ async function runPostDownloadProcessingBody(
|
|
|
102
117
|
deleteArchiveAfterExtract,
|
|
103
118
|
onProgress,
|
|
104
119
|
getDownloadedList,
|
|
120
|
+
showExtractionNotifications,
|
|
121
|
+
extractionNotificationTitle,
|
|
122
|
+
extractionNotificationText,
|
|
105
123
|
} = options;
|
|
106
124
|
|
|
107
125
|
const isAborted = () => Boolean(signal?.aborted);
|
|
@@ -164,7 +182,12 @@ async function runPostDownloadProcessingBody(
|
|
|
164
182
|
onProgress?.(progress);
|
|
165
183
|
emitDownloadProgress(category, id, progress);
|
|
166
184
|
},
|
|
167
|
-
signal
|
|
185
|
+
signal,
|
|
186
|
+
{
|
|
187
|
+
showNotificationsEnabled: showExtractionNotifications !== false,
|
|
188
|
+
notificationTitle: extractionNotificationTitle,
|
|
189
|
+
notificationText: extractionNotificationText,
|
|
190
|
+
}
|
|
168
191
|
);
|
|
169
192
|
}
|
|
170
193
|
|
package/src/enhancement/index.ts
CHANGED
|
@@ -1,69 +1,131 @@
|
|
|
1
|
-
|
|
2
|
-
* Speech Enhancement feature module
|
|
3
|
-
*
|
|
4
|
-
* @remarks
|
|
5
|
-
* This feature is not yet implemented. This module serves as a placeholder
|
|
6
|
-
* for future speech enhancement functionality.
|
|
7
|
-
*
|
|
8
|
-
* @example
|
|
9
|
-
* ```typescript
|
|
10
|
-
* // Future usage:
|
|
11
|
-
* import { initializeEnhancement, enhanceAudio } from 'react-native-sherpa-onnx/enhancement';
|
|
12
|
-
*
|
|
13
|
-
* await initializeEnhancement({ modelPath: { type: 'auto', path: 'models/enhancement-model' } });
|
|
14
|
-
* const enhancedPath = await enhanceAudio('path/to/noisy-audio.wav');
|
|
15
|
-
* ```
|
|
16
|
-
*/
|
|
17
|
-
|
|
1
|
+
import SherpaOnnx from '../NativeSherpaOnnx';
|
|
18
2
|
import type { ModelPathConfig } from '../types';
|
|
3
|
+
import { resolveModelPath } from '../utils';
|
|
4
|
+
import type {
|
|
5
|
+
EnhancedAudio,
|
|
6
|
+
EnhancementDetectResult,
|
|
7
|
+
EnhancementEngine,
|
|
8
|
+
EnhancementInitializeOptions,
|
|
9
|
+
} from './types';
|
|
19
10
|
|
|
20
|
-
|
|
21
|
-
* Enhancement initialization options (placeholder)
|
|
22
|
-
*/
|
|
23
|
-
export interface EnhancementInitializeOptions {
|
|
24
|
-
modelPath: ModelPathConfig;
|
|
25
|
-
// Additional enhancement-specific options will be added here
|
|
26
|
-
}
|
|
11
|
+
let enhancementInstanceCounter = 0;
|
|
27
12
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
13
|
+
function normalizeEnhancedAudio(raw: {
|
|
14
|
+
samples?: number[] | Float32Array;
|
|
15
|
+
sampleRate?: number;
|
|
16
|
+
}): EnhancedAudio {
|
|
17
|
+
const samplesArray = Array.isArray(raw.samples)
|
|
18
|
+
? raw.samples
|
|
19
|
+
: Array.from(raw.samples ?? []);
|
|
20
|
+
return {
|
|
21
|
+
samples: Float32Array.from(samplesArray),
|
|
22
|
+
sampleRate: Number(raw.sampleRate ?? 0),
|
|
23
|
+
};
|
|
34
24
|
}
|
|
35
25
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
throw new Error(
|
|
45
|
-
'Speech Enhancement feature is not yet implemented. This is a placeholder module.'
|
|
26
|
+
export async function detectEnhancementModel(
|
|
27
|
+
modelPath: ModelPathConfig,
|
|
28
|
+
options?: { modelType?: EnhancementInitializeOptions['modelType'] }
|
|
29
|
+
): Promise<EnhancementDetectResult> {
|
|
30
|
+
const resolvedPath = await resolveModelPath(modelPath);
|
|
31
|
+
const raw = await SherpaOnnx.detectEnhancementModel(
|
|
32
|
+
resolvedPath,
|
|
33
|
+
options?.modelType
|
|
46
34
|
);
|
|
35
|
+
const err = typeof raw.error === 'string' ? raw.error.trim() : '';
|
|
36
|
+
return {
|
|
37
|
+
success: raw.success,
|
|
38
|
+
...(err.length > 0 ? { error: err } : {}),
|
|
39
|
+
detectedModels: raw.detectedModels ?? [],
|
|
40
|
+
...(raw.modelType != null && raw.modelType !== ''
|
|
41
|
+
? { modelType: raw.modelType }
|
|
42
|
+
: {}),
|
|
43
|
+
};
|
|
47
44
|
}
|
|
48
45
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
46
|
+
export async function createEnhancement(
|
|
47
|
+
options: EnhancementInitializeOptions
|
|
48
|
+
): Promise<EnhancementEngine> {
|
|
49
|
+
const instanceId = `enhancement_${++enhancementInstanceCounter}`;
|
|
50
|
+
const resolvedPath = await resolveModelPath(options.modelPath);
|
|
51
|
+
const init = await SherpaOnnx.initializeEnhancement(
|
|
52
|
+
instanceId,
|
|
53
|
+
resolvedPath,
|
|
54
|
+
options.modelType ?? 'auto',
|
|
55
|
+
options.numThreads,
|
|
56
|
+
options.provider,
|
|
57
|
+
options.debug
|
|
57
58
|
);
|
|
58
|
-
}
|
|
59
59
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
60
|
+
if (!init.success) {
|
|
61
|
+
const nativeError = typeof init.error === 'string' ? init.error.trim() : '';
|
|
62
|
+
throw new Error(
|
|
63
|
+
nativeError.length > 0
|
|
64
|
+
? `Enhancement initialization failed: ${nativeError}`
|
|
65
|
+
: `Enhancement initialization failed for ${instanceId}`
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
let destroyed = false;
|
|
70
|
+
const guard = () => {
|
|
71
|
+
if (destroyed) {
|
|
72
|
+
throw new Error(
|
|
73
|
+
`Enhancement instance ${instanceId} has been destroyed; cannot call methods on it.`
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
return {
|
|
79
|
+
get instanceId() {
|
|
80
|
+
return instanceId;
|
|
81
|
+
},
|
|
82
|
+
async enhanceFile(
|
|
83
|
+
inputPath: string,
|
|
84
|
+
outputPath?: string
|
|
85
|
+
): Promise<EnhancedAudio> {
|
|
86
|
+
guard();
|
|
87
|
+
const raw = await SherpaOnnx.enhanceFile(
|
|
88
|
+
instanceId,
|
|
89
|
+
inputPath,
|
|
90
|
+
outputPath
|
|
91
|
+
);
|
|
92
|
+
return normalizeEnhancedAudio(raw);
|
|
93
|
+
},
|
|
94
|
+
async enhanceSamples(
|
|
95
|
+
samples: number[],
|
|
96
|
+
sampleRate: number
|
|
97
|
+
): Promise<EnhancedAudio> {
|
|
98
|
+
guard();
|
|
99
|
+
const raw = await SherpaOnnx.enhanceSamples(
|
|
100
|
+
instanceId,
|
|
101
|
+
samples,
|
|
102
|
+
sampleRate
|
|
103
|
+
);
|
|
104
|
+
return normalizeEnhancedAudio(raw);
|
|
105
|
+
},
|
|
106
|
+
async getSampleRate(): Promise<number> {
|
|
107
|
+
guard();
|
|
108
|
+
return SherpaOnnx.getEnhancementSampleRate(instanceId);
|
|
109
|
+
},
|
|
110
|
+
async destroy(): Promise<void> {
|
|
111
|
+
if (destroyed) return;
|
|
112
|
+
destroyed = true;
|
|
113
|
+
await SherpaOnnx.unloadEnhancement(instanceId);
|
|
114
|
+
},
|
|
115
|
+
};
|
|
69
116
|
}
|
|
117
|
+
|
|
118
|
+
export { createStreamingEnhancement } from './streaming';
|
|
119
|
+
export type {
|
|
120
|
+
OnlineEnhancementEngine,
|
|
121
|
+
StreamingEnhancementInitializeOptions,
|
|
122
|
+
} from './streamingTypes';
|
|
123
|
+
|
|
124
|
+
export type {
|
|
125
|
+
EnhancementModelType,
|
|
126
|
+
EnhancedAudio,
|
|
127
|
+
EnhancementInitializeOptions,
|
|
128
|
+
EnhancementDetectResult,
|
|
129
|
+
EnhancementEngine,
|
|
130
|
+
} from './types';
|
|
131
|
+
export { ENHANCEMENT_MODEL_TYPES } from './types';
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import SherpaOnnx from '../NativeSherpaOnnx';
|
|
2
|
+
import { resolveModelPath } from '../utils';
|
|
3
|
+
import type { EnhancedAudio, EnhancementModelType } from './types';
|
|
4
|
+
import type {
|
|
5
|
+
OnlineEnhancementEngine,
|
|
6
|
+
StreamingEnhancementInitializeOptions,
|
|
7
|
+
} from './streamingTypes';
|
|
8
|
+
|
|
9
|
+
let streamingEnhancementInstanceCounter = 0;
|
|
10
|
+
|
|
11
|
+
function normalizeEnhancedAudio(raw: {
|
|
12
|
+
samples?: number[] | Float32Array;
|
|
13
|
+
sampleRate?: number;
|
|
14
|
+
}): EnhancedAudio {
|
|
15
|
+
const samplesArray = Array.isArray(raw.samples)
|
|
16
|
+
? raw.samples
|
|
17
|
+
: Array.from(raw.samples ?? []);
|
|
18
|
+
return {
|
|
19
|
+
samples: Float32Array.from(samplesArray),
|
|
20
|
+
sampleRate: Number(raw.sampleRate ?? 0),
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export async function createStreamingEnhancement(
|
|
25
|
+
options: StreamingEnhancementInitializeOptions
|
|
26
|
+
): Promise<OnlineEnhancementEngine> {
|
|
27
|
+
const instanceId = `streaming_enhancement_${++streamingEnhancementInstanceCounter}`;
|
|
28
|
+
const resolvedPath = await resolveModelPath(options.modelPath);
|
|
29
|
+
const result = await SherpaOnnx.initializeOnlineEnhancement(
|
|
30
|
+
instanceId,
|
|
31
|
+
resolvedPath,
|
|
32
|
+
options.modelType ?? 'auto',
|
|
33
|
+
options.numThreads,
|
|
34
|
+
options.provider,
|
|
35
|
+
options.debug
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
if (!result.success) {
|
|
39
|
+
const nativeError =
|
|
40
|
+
typeof result.error === 'string' ? result.error.trim() : '';
|
|
41
|
+
throw new Error(
|
|
42
|
+
nativeError.length > 0
|
|
43
|
+
? `Streaming enhancement initialization failed: ${nativeError}`
|
|
44
|
+
: `Streaming enhancement initialization failed for ${instanceId}`
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
let destroyed = false;
|
|
49
|
+
const guard = () => {
|
|
50
|
+
if (destroyed) {
|
|
51
|
+
throw new Error(
|
|
52
|
+
`Streaming enhancement instance ${instanceId} has been destroyed; cannot call methods on it.`
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
return {
|
|
58
|
+
get instanceId() {
|
|
59
|
+
return instanceId;
|
|
60
|
+
},
|
|
61
|
+
|
|
62
|
+
async feedSamples(
|
|
63
|
+
samples: number[],
|
|
64
|
+
sampleRate: number
|
|
65
|
+
): Promise<EnhancedAudio> {
|
|
66
|
+
guard();
|
|
67
|
+
const raw = await SherpaOnnx.feedEnhancementSamples(
|
|
68
|
+
instanceId,
|
|
69
|
+
samples,
|
|
70
|
+
sampleRate
|
|
71
|
+
);
|
|
72
|
+
return normalizeEnhancedAudio(raw);
|
|
73
|
+
},
|
|
74
|
+
|
|
75
|
+
async flush(): Promise<EnhancedAudio> {
|
|
76
|
+
guard();
|
|
77
|
+
const raw = await SherpaOnnx.flushOnlineEnhancement(instanceId);
|
|
78
|
+
return normalizeEnhancedAudio(raw);
|
|
79
|
+
},
|
|
80
|
+
|
|
81
|
+
async reset(): Promise<void> {
|
|
82
|
+
guard();
|
|
83
|
+
await SherpaOnnx.resetOnlineEnhancement(instanceId);
|
|
84
|
+
},
|
|
85
|
+
|
|
86
|
+
async getSampleRate(): Promise<number> {
|
|
87
|
+
guard();
|
|
88
|
+
return SherpaOnnx.getEnhancementSampleRate(instanceId);
|
|
89
|
+
},
|
|
90
|
+
|
|
91
|
+
async getFrameShiftInSamples(): Promise<number> {
|
|
92
|
+
guard();
|
|
93
|
+
return Number(result.frameShiftInSamples ?? 0);
|
|
94
|
+
},
|
|
95
|
+
|
|
96
|
+
async destroy(): Promise<void> {
|
|
97
|
+
if (destroyed) return;
|
|
98
|
+
destroyed = true;
|
|
99
|
+
await SherpaOnnx.unloadOnlineEnhancement(instanceId);
|
|
100
|
+
},
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export type { OnlineEnhancementEngine } from './streamingTypes';
|
|
105
|
+
export type { EnhancementModelType };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { EnhancedAudio, EnhancementInitializeOptions } from './types';
|
|
2
|
+
|
|
3
|
+
export type StreamingEnhancementInitializeOptions =
|
|
4
|
+
EnhancementInitializeOptions;
|
|
5
|
+
|
|
6
|
+
export interface OnlineEnhancementEngine {
|
|
7
|
+
readonly instanceId: string;
|
|
8
|
+
feedSamples(samples: number[], sampleRate: number): Promise<EnhancedAudio>;
|
|
9
|
+
flush(): Promise<EnhancedAudio>;
|
|
10
|
+
reset(): Promise<void>;
|
|
11
|
+
getSampleRate(): Promise<number>;
|
|
12
|
+
getFrameShiftInSamples(): Promise<number>;
|
|
13
|
+
destroy(): Promise<void>;
|
|
14
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { ModelPathConfig } from '../types';
|
|
2
|
+
|
|
3
|
+
export type EnhancementModelType = 'gtcrn' | 'dpdfnet';
|
|
4
|
+
|
|
5
|
+
export const ENHANCEMENT_MODEL_TYPES: readonly EnhancementModelType[] = [
|
|
6
|
+
'gtcrn',
|
|
7
|
+
'dpdfnet',
|
|
8
|
+
] as const;
|
|
9
|
+
|
|
10
|
+
export type EnhancedAudio = {
|
|
11
|
+
samples: Float32Array;
|
|
12
|
+
sampleRate: number;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export interface EnhancementInitializeOptions {
|
|
16
|
+
modelPath: ModelPathConfig;
|
|
17
|
+
modelType?: EnhancementModelType | 'auto';
|
|
18
|
+
numThreads?: number;
|
|
19
|
+
provider?: string;
|
|
20
|
+
debug?: boolean;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export type EnhancementDetectResult = {
|
|
24
|
+
success: boolean;
|
|
25
|
+
error?: string;
|
|
26
|
+
detectedModels: Array<{ type: string; modelDir: string }>;
|
|
27
|
+
modelType?: string;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export interface EnhancementEngine {
|
|
31
|
+
readonly instanceId: string;
|
|
32
|
+
enhanceFile(inputPath: string, outputPath?: string): Promise<EnhancedAudio>;
|
|
33
|
+
enhanceSamples(samples: number[], sampleRate: number): Promise<EnhancedAudio>;
|
|
34
|
+
getSampleRate(): Promise<number>;
|
|
35
|
+
destroy(): Promise<void>;
|
|
36
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { DeviceEventEmitter } from 'react-native';
|
|
2
2
|
import SherpaOnnx from '../NativeSherpaOnnx';
|
|
3
|
+
import type { ExtractNotificationArgs } from './types';
|
|
3
4
|
|
|
4
5
|
export type ExtractProgressEvent = {
|
|
5
6
|
bytes: number;
|
|
@@ -19,7 +20,8 @@ export async function extractTarBz2(
|
|
|
19
20
|
targetPath: string,
|
|
20
21
|
force = true,
|
|
21
22
|
onProgress?: (event: ExtractProgressEvent) => void,
|
|
22
|
-
signal?: AbortSignal
|
|
23
|
+
signal?: AbortSignal,
|
|
24
|
+
notification?: ExtractNotificationArgs
|
|
23
25
|
): Promise<ExtractResult> {
|
|
24
26
|
let subscription: { remove: () => void } | null = null;
|
|
25
27
|
let removeAbortListener: (() => void) | null = null;
|
|
@@ -62,7 +64,10 @@ export async function extractTarBz2(
|
|
|
62
64
|
const result = await SherpaOnnx.extractTarBz2(
|
|
63
65
|
sourcePath,
|
|
64
66
|
targetPath,
|
|
65
|
-
force
|
|
67
|
+
force,
|
|
68
|
+
notification?.showNotificationsEnabled,
|
|
69
|
+
notification?.notificationTitle,
|
|
70
|
+
notification?.notificationText
|
|
66
71
|
);
|
|
67
72
|
if (!result.success) {
|
|
68
73
|
const message = result.reason || 'Extraction failed';
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { DeviceEventEmitter } from 'react-native';
|
|
2
2
|
import SherpaOnnx from '../NativeSherpaOnnx';
|
|
3
|
+
import type { ExtractNotificationArgs } from './types';
|
|
3
4
|
|
|
4
5
|
export type ExtractProgressEvent = {
|
|
5
6
|
bytes: number;
|
|
@@ -19,7 +20,8 @@ export async function extractTarZst(
|
|
|
19
20
|
targetPath: string,
|
|
20
21
|
force = true,
|
|
21
22
|
onProgress?: (event: ExtractProgressEvent) => void,
|
|
22
|
-
signal?: AbortSignal
|
|
23
|
+
signal?: AbortSignal,
|
|
24
|
+
notification?: ExtractNotificationArgs
|
|
23
25
|
): Promise<ExtractResult> {
|
|
24
26
|
let subscription: { remove: () => void } | null = null;
|
|
25
27
|
let removeAbortListener: (() => void) | null = null;
|
|
@@ -61,7 +63,10 @@ export async function extractTarZst(
|
|
|
61
63
|
const result = await SherpaOnnx.extractTarZst(
|
|
62
64
|
sourcePath,
|
|
63
65
|
targetPath,
|
|
64
|
-
force
|
|
66
|
+
force,
|
|
67
|
+
notification?.showNotificationsEnabled,
|
|
68
|
+
notification?.notificationTitle,
|
|
69
|
+
notification?.notificationText
|
|
65
70
|
);
|
|
66
71
|
if (!result.success) {
|
|
67
72
|
const message = result.reason || 'Extraction failed';
|
package/src/extraction/index.ts
CHANGED
|
@@ -17,6 +17,7 @@ import { extractTarBz2 } from './extractTarBz2';
|
|
|
17
17
|
import type {
|
|
18
18
|
BundledArchive,
|
|
19
19
|
ExtractArchiveOptions,
|
|
20
|
+
ExtractNotificationArgs,
|
|
20
21
|
ExtractResult,
|
|
21
22
|
ExtractProgressEvent,
|
|
22
23
|
} from './types';
|
|
@@ -24,6 +25,7 @@ import type {
|
|
|
24
25
|
export type {
|
|
25
26
|
BundledArchive,
|
|
26
27
|
ExtractArchiveOptions,
|
|
28
|
+
ExtractNotificationArgs,
|
|
27
29
|
ExtractResult,
|
|
28
30
|
ExtractProgressEvent,
|
|
29
31
|
} from './types';
|
|
@@ -160,6 +162,11 @@ export async function extractArchive(
|
|
|
160
162
|
const force = options?.force !== false;
|
|
161
163
|
const onProgress = options?.onProgress;
|
|
162
164
|
const signal = options?.signal;
|
|
165
|
+
const notification = {
|
|
166
|
+
showNotificationsEnabled: options?.showNotificationsEnabled,
|
|
167
|
+
notificationTitle: options?.notificationTitle,
|
|
168
|
+
notificationText: options?.notificationText,
|
|
169
|
+
};
|
|
163
170
|
|
|
164
171
|
if (signal?.aborted) {
|
|
165
172
|
const err = new Error('Extraction aborted');
|
|
@@ -173,7 +180,14 @@ export async function extractArchive(
|
|
|
173
180
|
archive.archivePath.startsWith('asset_packs/'));
|
|
174
181
|
|
|
175
182
|
if (useAssetStream) {
|
|
176
|
-
return extractFromAsset(
|
|
183
|
+
return extractFromAsset(
|
|
184
|
+
archive,
|
|
185
|
+
targetPath,
|
|
186
|
+
force,
|
|
187
|
+
onProgress,
|
|
188
|
+
signal,
|
|
189
|
+
notification
|
|
190
|
+
);
|
|
177
191
|
}
|
|
178
192
|
|
|
179
193
|
if (archive.format === 'tar.zst') {
|
|
@@ -182,7 +196,8 @@ export async function extractArchive(
|
|
|
182
196
|
targetPath,
|
|
183
197
|
force,
|
|
184
198
|
onProgress,
|
|
185
|
-
signal
|
|
199
|
+
signal,
|
|
200
|
+
notification
|
|
186
201
|
);
|
|
187
202
|
}
|
|
188
203
|
return extractTarBz2(
|
|
@@ -190,7 +205,8 @@ export async function extractArchive(
|
|
|
190
205
|
targetPath,
|
|
191
206
|
force,
|
|
192
207
|
onProgress,
|
|
193
|
-
signal
|
|
208
|
+
signal,
|
|
209
|
+
notification
|
|
194
210
|
);
|
|
195
211
|
}
|
|
196
212
|
|
|
@@ -201,7 +217,8 @@ async function extractFromAsset(
|
|
|
201
217
|
targetPath: string,
|
|
202
218
|
force: boolean,
|
|
203
219
|
onProgress?: (event: ExtractProgressEvent) => void,
|
|
204
|
-
signal?: AbortSignal
|
|
220
|
+
signal?: AbortSignal,
|
|
221
|
+
notification?: ExtractNotificationArgs
|
|
205
222
|
): Promise<ExtractResult> {
|
|
206
223
|
const eventName =
|
|
207
224
|
archive.format === 'tar.zst'
|
|
@@ -245,12 +262,18 @@ async function extractFromAsset(
|
|
|
245
262
|
? await SherpaOnnx.extractTarZstFromAsset(
|
|
246
263
|
archive.archivePath,
|
|
247
264
|
targetPath,
|
|
248
|
-
force
|
|
265
|
+
force,
|
|
266
|
+
notification?.showNotificationsEnabled,
|
|
267
|
+
notification?.notificationTitle,
|
|
268
|
+
notification?.notificationText
|
|
249
269
|
)
|
|
250
270
|
: await SherpaOnnx.extractTarBz2FromAsset(
|
|
251
271
|
archive.archivePath,
|
|
252
272
|
targetPath,
|
|
253
|
-
force
|
|
273
|
+
force,
|
|
274
|
+
notification?.showNotificationsEnabled,
|
|
275
|
+
notification?.notificationTitle,
|
|
276
|
+
notification?.notificationText
|
|
254
277
|
);
|
|
255
278
|
|
|
256
279
|
if (!result.success) {
|
package/src/extraction/types.ts
CHANGED
|
@@ -60,4 +60,20 @@ export type ExtractArchiveOptions = {
|
|
|
60
60
|
onProgress?: (event: ExtractProgressEvent) => void;
|
|
61
61
|
/** AbortSignal to cancel the extraction. */
|
|
62
62
|
signal?: AbortSignal;
|
|
63
|
+
/**
|
|
64
|
+
* **Android:** When true (default), the native layer posts a system notification with extraction
|
|
65
|
+
* progress. Set to false to disable (e.g. first-run bundled-model prep with in-app UI only).
|
|
66
|
+
* **iOS:** Accepted for API parity; no notification is shown.
|
|
67
|
+
*/
|
|
68
|
+
showNotificationsEnabled?: boolean;
|
|
69
|
+
/** **Android:** Notification title. Default: generic “unpacking” title. Ignored on iOS. */
|
|
70
|
+
notificationTitle?: string;
|
|
71
|
+
/** **Android:** Notification body (progress text is appended). Default: generic. Ignored on iOS. */
|
|
72
|
+
notificationText?: string;
|
|
63
73
|
};
|
|
74
|
+
|
|
75
|
+
/** Subset of `ExtractArchiveOptions` passed through to path- and asset-stream extractors. */
|
|
76
|
+
export type ExtractNotificationArgs = Pick<
|
|
77
|
+
ExtractArchiveOptions,
|
|
78
|
+
'showNotificationsEnabled' | 'notificationTitle' | 'notificationText'
|
|
79
|
+
>;
|
package/src/licenses.ts
CHANGED
|
@@ -13,14 +13,17 @@ export async function getModelLicenses(): Promise<ModelLicense[]> {
|
|
|
13
13
|
const asrPath = 'model_licenses/asr-models-license-status.csv';
|
|
14
14
|
const qnnPath = 'model_licenses/qnn-asr-models-license-status.csv';
|
|
15
15
|
const ttsPath = 'model_licenses/tts-models-license-status.csv';
|
|
16
|
+
const speechEnhancementPath =
|
|
17
|
+
'model_licenses/speech-enhancement-models-license-status.csv';
|
|
16
18
|
|
|
17
19
|
const results = await Promise.allSettled([
|
|
18
20
|
SherpaOnnx.readAssetFileAsUtf8(asrPath),
|
|
19
21
|
SherpaOnnx.readAssetFileAsUtf8(qnnPath),
|
|
20
22
|
SherpaOnnx.readAssetFileAsUtf8(ttsPath),
|
|
23
|
+
SherpaOnnx.readAssetFileAsUtf8(speechEnhancementPath),
|
|
21
24
|
]);
|
|
22
25
|
|
|
23
|
-
const [asrResult, qnnResult, ttsResult] = results;
|
|
26
|
+
const [asrResult, qnnResult, ttsResult, enhancementResult] = results;
|
|
24
27
|
|
|
25
28
|
const licenses: ModelLicense[] = [];
|
|
26
29
|
|
|
@@ -48,6 +51,14 @@ export async function getModelLicenses(): Promise<ModelLicense[]> {
|
|
|
48
51
|
);
|
|
49
52
|
}
|
|
50
53
|
|
|
54
|
+
if (enhancementResult.status === 'fulfilled') {
|
|
55
|
+
licenses.push(...parseCsv(enhancementResult.value));
|
|
56
|
+
} else {
|
|
57
|
+
console.warn(
|
|
58
|
+
`[SherpaOnnx] Failed to load speech enhancement model licenses: ${enhancementResult.reason}`
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
|
|
51
62
|
return licenses;
|
|
52
63
|
}
|
|
53
64
|
|
|
@@ -91,7 +102,7 @@ function parseCsv(csvString: string): ModelLicense[] {
|
|
|
91
102
|
}
|
|
92
103
|
}
|
|
93
104
|
|
|
94
|
-
if (entry
|
|
105
|
+
if (entry.asset_name) {
|
|
95
106
|
results.push(entry as unknown as ModelLicense);
|
|
96
107
|
}
|
|
97
108
|
}
|
package/src/stt/index.ts
CHANGED
|
@@ -67,10 +67,7 @@ export async function detectSttModel(
|
|
|
67
67
|
options?.preferInt8,
|
|
68
68
|
options?.modelType
|
|
69
69
|
);
|
|
70
|
-
const err =
|
|
71
|
-
typeof (raw as { error?: unknown }).error === 'string'
|
|
72
|
-
? String((raw as { error: string }).error).trim()
|
|
73
|
-
: '';
|
|
70
|
+
const err = typeof raw.error === 'string' ? raw.error.trim() : '';
|
|
74
71
|
return {
|
|
75
72
|
success: raw.success,
|
|
76
73
|
...(err.length > 0 ? { error: err } : {}),
|
|
@@ -170,10 +167,13 @@ export async function createSTT(
|
|
|
170
167
|
);
|
|
171
168
|
|
|
172
169
|
if (!result.success) {
|
|
170
|
+
const nativeError =
|
|
171
|
+
typeof result.error === 'string' ? result.error.trim() : '';
|
|
172
|
+
const detected = JSON.stringify(result.detectedModels ?? []);
|
|
173
173
|
throw new Error(
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
174
|
+
nativeError.length > 0
|
|
175
|
+
? `STT initialization failed: ${nativeError}`
|
|
176
|
+
: `STT initialization failed: ${detected}`
|
|
177
177
|
);
|
|
178
178
|
}
|
|
179
179
|
|
|
@@ -259,6 +259,7 @@ export type {
|
|
|
259
259
|
STTInitializeOptions,
|
|
260
260
|
STTModelType,
|
|
261
261
|
SttModelOptions,
|
|
262
|
+
SttQwen3AsrModelOptions,
|
|
262
263
|
SttRecognitionResult,
|
|
263
264
|
SttRuntimeConfig,
|
|
264
265
|
SttEngine,
|
package/src/stt/streaming.ts
CHANGED
|
@@ -231,7 +231,13 @@ export async function createStreamingSTT(
|
|
|
231
231
|
);
|
|
232
232
|
|
|
233
233
|
if (!result.success) {
|
|
234
|
-
|
|
234
|
+
const nativeError =
|
|
235
|
+
typeof result.error === 'string' ? result.error.trim() : '';
|
|
236
|
+
throw new Error(
|
|
237
|
+
nativeError.length > 0
|
|
238
|
+
? `Streaming STT initialization failed: ${nativeError}`
|
|
239
|
+
: `Streaming STT initialization failed for ${instanceId}`
|
|
240
|
+
);
|
|
235
241
|
}
|
|
236
242
|
|
|
237
243
|
const enableInputNormalization = options.enableInputNormalization !== false;
|