react-native-sherpa-onnx 0.3.6 → 0.3.7
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/LICENSE +1 -0
- package/README.md +89 -21
- package/SherpaOnnx.podspec +3 -0
- package/THIRD_PARTY_LICENSES/README.md +62 -0
- package/THIRD_PARTY_LICENSES/ffmpeg.txt +502 -0
- package/THIRD_PARTY_LICENSES/libarchive.txt +65 -0
- package/THIRD_PARTY_LICENSES/nvidia_omla.txt +181 -0
- package/THIRD_PARTY_LICENSES/onnxruntime.txt +21 -0
- package/THIRD_PARTY_LICENSES/opus.txt +44 -0
- package/THIRD_PARTY_LICENSES/sherpa-onnx.txt +201 -0
- package/THIRD_PARTY_LICENSES/shine.txt +482 -0
- package/THIRD_PARTY_LICENSES/zstd.txt +30 -0
- package/android/build.gradle +7 -3
- package/android/prebuilt-download.gradle +344 -152
- package/android/prebuilt-versions.gradle +1 -1
- package/android/src/main/assets/model_licenses/asr-models-license-status.csv +409 -0
- package/android/src/main/assets/model_licenses/qnn-asr-models-license-status.csv +695 -0
- package/android/src/main/assets/model_licenses/tts-models-license-status.csv +596 -0
- package/android/src/main/cpp/CMakeLists.txt +28 -10
- package/android/src/main/cpp/jni/archive/sherpa-onnx-archive-helper.cpp +2 -2
- package/android/src/main/cpp/jni/audio/sherpa-onnx-audio-convert-jni.cpp +268 -2
- package/android/src/main/cpp/jni/model_detect/sherpa-onnx-model-detect-tts.cpp +6 -2
- package/android/src/main/cpp/jni/model_detect/sherpa-onnx-validate-tts.cpp +4 -2
- package/android/src/main/java/com/sherpaonnx/SherpaOnnxArchiveHelper.kt +40 -10
- package/android/src/main/java/com/sherpaonnx/SherpaOnnxModule.kt +99 -0
- package/android/src/main/java/com/sherpaonnx/SherpaOnnxOnlineSttHelper.kt +4 -1
- package/android/src/main/java/com/sherpaonnx/SherpaOnnxTtsHelper.kt +112 -97
- package/ios/Resources/model_licenses/asr-models-license-status.csv +409 -0
- package/ios/Resources/model_licenses/qnn-asr-models-license-status.csv +695 -0
- package/ios/Resources/model_licenses/tts-models-license-status.csv +596 -0
- package/ios/SherpaOnnx+OnlineSTT.mm +2 -0
- package/ios/SherpaOnnx+PcmLiveStream.mm +2 -29
- package/ios/SherpaOnnx+TTS.mm +178 -20
- package/ios/SherpaOnnx.mm +54 -0
- package/ios/SherpaOnnxAudioConvert.h +10 -0
- package/ios/SherpaOnnxAudioConvert.mm +257 -1
- package/ios/archive/sherpa-onnx-archive-helper.h +3 -0
- package/ios/archive/sherpa-onnx-archive-helper.mm +39 -6
- package/ios/model_detect/sherpa-onnx-model-detect-tts.mm +13 -2
- package/ios/model_detect/sherpa-onnx-validate-tts.mm +4 -2
- package/ios/online_stt/sherpa-onnx-online-stt-wrapper.h +1 -0
- package/ios/online_stt/sherpa-onnx-online-stt-wrapper.mm +4 -0
- package/ios/tts/sherpa-onnx-tts-wrapper.h +37 -0
- package/ios/tts/sherpa-onnx-tts-wrapper.mm +149 -3
- package/lib/module/NativeSherpaOnnx.js.map +1 -1
- package/lib/module/audio/index.js +8 -0
- package/lib/module/audio/index.js.map +1 -1
- package/lib/module/download/ModelDownloadManager.js +10 -929
- package/lib/module/download/ModelDownloadManager.js.map +1 -1
- package/lib/module/download/activeModelOperations.js +26 -0
- package/lib/module/download/activeModelOperations.js.map +1 -0
- package/lib/module/download/background-downloader.d.js +2 -0
- package/lib/module/download/background-downloader.d.js.map +1 -0
- package/lib/module/download/bulkPurge.js +72 -0
- package/lib/module/download/bulkPurge.js.map +1 -0
- package/lib/module/download/checksumPrompt.js +19 -0
- package/lib/module/download/checksumPrompt.js.map +1 -0
- package/lib/module/download/constants.js +7 -0
- package/lib/module/download/constants.js.map +1 -0
- package/lib/module/download/downloadEvents.js +35 -0
- package/lib/module/download/downloadEvents.js.map +1 -0
- package/lib/module/download/downloadTask.js +385 -0
- package/lib/module/download/downloadTask.js.map +1 -0
- package/lib/module/download/ensureModel.js +89 -0
- package/lib/module/download/ensureModel.js.map +1 -0
- package/lib/module/download/index.js +4 -4
- package/lib/module/download/index.js.map +1 -1
- package/lib/module/download/localModels.js +151 -0
- package/lib/module/download/localModels.js.map +1 -0
- package/lib/module/download/modelExtraction.js +174 -0
- package/lib/module/download/modelExtraction.js.map +1 -0
- package/lib/module/download/paths.js +98 -0
- package/lib/module/download/paths.js.map +1 -0
- package/lib/module/download/postDownloadProcessing.js +206 -0
- package/lib/module/download/postDownloadProcessing.js.map +1 -0
- package/lib/module/download/protectedModelKeys.js +31 -0
- package/lib/module/download/protectedModelKeys.js.map +1 -0
- package/lib/module/download/registry.js +267 -0
- package/lib/module/download/registry.js.map +1 -0
- package/lib/module/download/retry.js +59 -0
- package/lib/module/download/retry.js.map +1 -0
- package/lib/module/download/types.js +17 -0
- package/lib/module/download/types.js.map +1 -0
- package/lib/module/download/validation.js +101 -5
- package/lib/module/download/validation.js.map +1 -1
- package/lib/module/{download → extraction}/extractTarBz2.js +3 -1
- package/lib/module/extraction/extractTarBz2.js.map +1 -0
- package/lib/module/{download → extraction}/extractTarZst.js +3 -1
- package/lib/module/extraction/extractTarZst.js.map +1 -0
- package/lib/module/extraction/index.js +3 -4
- package/lib/module/extraction/index.js.map +1 -1
- package/lib/module/index.js +1 -1
- package/lib/module/index.js.map +1 -1
- package/lib/module/licenses.js +63 -0
- package/lib/module/licenses.js.map +1 -0
- package/lib/module/stt/index.js +16 -2
- package/lib/module/stt/index.js.map +1 -1
- package/lib/module/stt/streaming.js +2 -0
- package/lib/module/stt/streaming.js.map +1 -1
- package/lib/module/stt/streamingTypes.js.map +1 -1
- package/lib/module/stt/types.js.map +1 -1
- package/lib/module/tts/index.js +20 -2
- package/lib/module/tts/index.js.map +1 -1
- package/lib/module/tts/streaming.js +4 -0
- package/lib/module/tts/streaming.js.map +1 -1
- package/lib/module/tts/types.js.map +1 -1
- package/lib/module/utils.js +16 -1
- package/lib/module/utils.js.map +1 -1
- package/lib/typescript/src/NativeSherpaOnnx.d.ts +33 -5
- package/lib/typescript/src/NativeSherpaOnnx.d.ts.map +1 -1
- package/lib/typescript/src/audio/index.d.ts +10 -0
- package/lib/typescript/src/audio/index.d.ts.map +1 -1
- package/lib/typescript/src/download/ModelDownloadManager.d.ts +10 -108
- package/lib/typescript/src/download/ModelDownloadManager.d.ts.map +1 -1
- package/lib/typescript/src/download/activeModelOperations.d.ts +6 -0
- package/lib/typescript/src/download/activeModelOperations.d.ts.map +1 -0
- package/lib/typescript/src/download/bulkPurge.d.ts +14 -0
- package/lib/typescript/src/download/bulkPurge.d.ts.map +1 -0
- package/lib/typescript/src/download/checksumPrompt.d.ts +3 -0
- package/lib/typescript/src/download/checksumPrompt.d.ts.map +1 -0
- package/lib/typescript/src/download/constants.d.ts +5 -0
- package/lib/typescript/src/download/constants.d.ts.map +1 -0
- package/lib/typescript/src/download/downloadEvents.d.ts +6 -0
- package/lib/typescript/src/download/downloadEvents.d.ts.map +1 -0
- package/lib/typescript/src/download/downloadTask.d.ts +20 -0
- package/lib/typescript/src/download/downloadTask.d.ts.map +1 -0
- package/lib/typescript/src/download/ensureModel.d.ts +26 -0
- package/lib/typescript/src/download/ensureModel.d.ts.map +1 -0
- package/lib/typescript/src/download/index.d.ts +7 -7
- package/lib/typescript/src/download/index.d.ts.map +1 -1
- package/lib/typescript/src/download/localModels.d.ts +15 -0
- package/lib/typescript/src/download/localModels.d.ts.map +1 -0
- package/lib/typescript/src/download/modelExtraction.d.ts +36 -0
- package/lib/typescript/src/download/modelExtraction.d.ts.map +1 -0
- package/lib/typescript/src/download/paths.d.ts +28 -0
- package/lib/typescript/src/download/paths.d.ts.map +1 -0
- package/lib/typescript/src/download/postDownloadProcessing.d.ts +19 -0
- package/lib/typescript/src/download/postDownloadProcessing.d.ts.map +1 -0
- package/lib/typescript/src/download/protectedModelKeys.d.ts +6 -0
- package/lib/typescript/src/download/protectedModelKeys.d.ts.map +1 -0
- package/lib/typescript/src/download/registry.d.ts +14 -0
- package/lib/typescript/src/download/registry.d.ts.map +1 -0
- package/lib/typescript/src/download/retry.d.ts +15 -0
- package/lib/typescript/src/download/retry.d.ts.map +1 -0
- package/lib/typescript/src/download/types.d.ts +96 -0
- package/lib/typescript/src/download/types.d.ts.map +1 -0
- package/lib/typescript/src/download/validation.d.ts +19 -0
- package/lib/typescript/src/download/validation.d.ts.map +1 -1
- package/lib/typescript/src/extraction/extractTarBz2.d.ts.map +1 -0
- package/lib/typescript/src/extraction/extractTarZst.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +1 -0
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/licenses.d.ts +10 -0
- package/lib/typescript/src/licenses.d.ts.map +1 -0
- package/lib/typescript/src/stt/index.d.ts +4 -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/streamingTypes.d.ts +5 -0
- package/lib/typescript/src/stt/streamingTypes.d.ts.map +1 -1
- package/lib/typescript/src/stt/types.d.ts +3 -1
- package/lib/typescript/src/stt/types.d.ts.map +1 -1
- package/lib/typescript/src/tts/index.d.ts +3 -1
- package/lib/typescript/src/tts/index.d.ts.map +1 -1
- package/lib/typescript/src/tts/streaming.d.ts.map +1 -1
- package/lib/typescript/src/tts/types.d.ts +6 -5
- package/lib/typescript/src/tts/types.d.ts.map +1 -1
- package/lib/typescript/src/utils.d.ts +5 -0
- package/lib/typescript/src/utils.d.ts.map +1 -1
- package/package.json +6 -1
- package/scripts/{check-model-csvs.sh → ci/check-model-csvs.sh} +9 -2
- package/scripts/ci/collect_all_sherpa_model_streams.sh +101 -0
- package/scripts/ci/collect_one_sherpa_release_stream.sh +189 -0
- package/scripts/ci/sherpa_asr_model_release_streams.json +21 -0
- package/scripts/ci/sherpa_tts_model_release_streams.json +13 -0
- package/scripts/ci/update_model_license_csv.sh +765 -0
- package/scripts/setup-ios-framework.sh +14 -11
- package/scripts/update_commercial_use.js +73 -0
- package/src/NativeSherpaOnnx.ts +36 -5
- package/src/audio/index.ts +20 -0
- package/src/download/ModelDownloadManager.ts +55 -1343
- package/src/download/activeModelOperations.ts +38 -0
- package/src/download/background-downloader.d.ts +43 -0
- package/src/download/bulkPurge.ts +102 -0
- package/src/download/checksumPrompt.ts +25 -0
- package/src/download/constants.ts +5 -0
- package/src/download/downloadEvents.ts +55 -0
- package/src/download/downloadTask.ts +497 -0
- package/src/download/ensureModel.ts +124 -0
- package/src/download/index.ts +19 -4
- package/src/download/localModels.ts +234 -0
- package/src/download/modelExtraction.ts +244 -0
- package/src/download/paths.ts +134 -0
- package/src/download/postDownloadProcessing.ts +292 -0
- package/src/download/protectedModelKeys.ts +30 -0
- package/src/download/registry.ts +404 -0
- package/src/download/retry.ts +76 -0
- package/src/download/types.ts +120 -0
- package/src/download/validation.ts +114 -8
- package/src/{download → extraction}/extractTarBz2.ts +3 -1
- package/src/{download → extraction}/extractTarZst.ts +3 -1
- package/src/extraction/index.ts +3 -7
- package/src/index.tsx +1 -0
- package/src/licenses.ts +100 -0
- package/src/stt/index.ts +20 -2
- package/src/stt/streaming.ts +3 -0
- package/src/stt/streamingTypes.ts +5 -0
- package/src/stt/types.ts +3 -1
- package/src/tts/index.ts +30 -2
- package/src/tts/streaming.ts +10 -0
- package/src/tts/types.ts +6 -5
- package/src/utils.ts +22 -1
- package/third_party/sherpa-onnx-prebuilt/ANDROID_RELEASE_TAG +1 -1
- package/third_party/sherpa-onnx-prebuilt/IOS_RELEASE_TAG +1 -1
- package/android/src/main/cpp/jni/tts/sherpa-onnx-tts-zipvoice-jni.cpp +0 -301
- package/android/src/main/java/com/sherpaonnx/ZipvoiceTtsWrapper.kt +0 -187
- package/lib/module/download/extractTarBz2.js.map +0 -1
- package/lib/module/download/extractTarZst.js.map +0 -1
- package/lib/typescript/src/download/extractTarBz2.d.ts.map +0 -1
- package/lib/typescript/src/download/extractTarZst.d.ts.map +0 -1
- package/scripts/check-qnn-support.sh +0 -78
- /package/lib/typescript/src/{download → extraction}/extractTarBz2.d.ts +0 -0
- /package/lib/typescript/src/{download → extraction}/extractTarZst.d.ts +0 -0
|
@@ -3,6 +3,7 @@ import {
|
|
|
3
3
|
stat,
|
|
4
4
|
exists,
|
|
5
5
|
readDir,
|
|
6
|
+
unlink,
|
|
6
7
|
type ReadDirResItemT,
|
|
7
8
|
} from '@dr.pogodin/react-native-fs';
|
|
8
9
|
import SherpaOnnx from '../NativeSherpaOnnx';
|
|
@@ -25,6 +26,37 @@ export class ValidationResult {
|
|
|
25
26
|
}
|
|
26
27
|
}
|
|
27
28
|
|
|
29
|
+
/**
|
|
30
|
+
* Delete a directory and all contents. No-op if the path is missing.
|
|
31
|
+
* Best-effort: continues on per-entry errors (permissions, race).
|
|
32
|
+
*/
|
|
33
|
+
export async function removeDirectoryRecursive(dirPath: string): Promise<void> {
|
|
34
|
+
if (!(await exists(dirPath))) return;
|
|
35
|
+
let entries: ReadDirResItemT[];
|
|
36
|
+
try {
|
|
37
|
+
entries = await readDir(dirPath);
|
|
38
|
+
} catch {
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
for (const entry of entries) {
|
|
42
|
+
const childPath = `${dirPath}/${entry.name}`.replace(/\/+/g, '/');
|
|
43
|
+
try {
|
|
44
|
+
if (entry.isDirectory()) {
|
|
45
|
+
await removeDirectoryRecursive(childPath);
|
|
46
|
+
} else {
|
|
47
|
+
await unlink(childPath);
|
|
48
|
+
}
|
|
49
|
+
} catch {
|
|
50
|
+
// ignore
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
try {
|
|
54
|
+
await unlink(dirPath);
|
|
55
|
+
} catch {
|
|
56
|
+
// ignore
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
28
60
|
/**
|
|
29
61
|
* Parse checksum.txt format into a Map of filename -> hash
|
|
30
62
|
* Expected format:
|
|
@@ -148,12 +180,15 @@ export async function validateExtractedFiles(
|
|
|
148
180
|
|
|
149
181
|
for (const entry of entries) {
|
|
150
182
|
if (entry.isDirectory()) {
|
|
151
|
-
const
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
183
|
+
const subPath = entry.path;
|
|
184
|
+
if (subPath != null) {
|
|
185
|
+
const nested = await collectFilesRecursive(
|
|
186
|
+
subPath,
|
|
187
|
+
depth + 1,
|
|
188
|
+
maxDepth
|
|
189
|
+
);
|
|
190
|
+
files.push(...nested);
|
|
191
|
+
}
|
|
157
192
|
} else {
|
|
158
193
|
files.push(entry);
|
|
159
194
|
}
|
|
@@ -175,13 +210,13 @@ export async function validateExtractedFiles(
|
|
|
175
210
|
}
|
|
176
211
|
|
|
177
212
|
let hasModelLikeFiles = actualFiles.some((file) =>
|
|
178
|
-
isModelLikeFile(file.name)
|
|
213
|
+
isModelLikeFile(file.name ?? '')
|
|
179
214
|
);
|
|
180
215
|
|
|
181
216
|
if (!hasModelLikeFiles) {
|
|
182
217
|
const nestedFiles = await collectFilesRecursive(modelDir);
|
|
183
218
|
hasModelLikeFiles = nestedFiles.some((file) =>
|
|
184
|
-
isModelLikeFile(file.name)
|
|
219
|
+
isModelLikeFile(file.name ?? '')
|
|
185
220
|
);
|
|
186
221
|
}
|
|
187
222
|
|
|
@@ -203,6 +238,77 @@ export async function validateExtractedFiles(
|
|
|
203
238
|
}
|
|
204
239
|
}
|
|
205
240
|
|
|
241
|
+
/** True if the file is a native sherpa-onnx model file (e.g. encoder.onnx). Excludes our metadata (.ready, manifest.json). */
|
|
242
|
+
function isNativeModelFileName(name: string): boolean {
|
|
243
|
+
const lower = name.toLowerCase();
|
|
244
|
+
return lower.endsWith('.onnx') || lower.endsWith('.bin');
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Check if a directory contains native model files (.onnx or .bin) at the top level or one level of subdirectories.
|
|
249
|
+
* Used to find the actual model dir; ignores our metadata (manifest.json, .ready).
|
|
250
|
+
*/
|
|
251
|
+
async function dirContainsModelFiles(dir: string): Promise<boolean> {
|
|
252
|
+
const entries = await readDir(dir);
|
|
253
|
+
const files = entries.filter((e) => !e.isDirectory());
|
|
254
|
+
if (files.some((f) => isNativeModelFileName(f.name ?? ''))) return true;
|
|
255
|
+
const subdirs = entries.filter((e) => e.isDirectory());
|
|
256
|
+
for (const sub of subdirs) {
|
|
257
|
+
const subPath = sub?.path;
|
|
258
|
+
if (subPath == null) continue;
|
|
259
|
+
const subEntries = await readDir(subPath);
|
|
260
|
+
const subFiles = subEntries.filter((e) => !e.isDirectory());
|
|
261
|
+
if (subFiles.some((f) => isNativeModelFileName(f.name ?? ''))) return true;
|
|
262
|
+
}
|
|
263
|
+
return false;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* Resolve the directory that actually contains model files.
|
|
268
|
+
* After extracting a tarball, model files often end up in a single top-level subdirectory
|
|
269
|
+
* (e.g. installDir/modelId/encoder.onnx). Native APIs expect the path to the folder
|
|
270
|
+
* that directly contains encoder.onnx, decoder.onnx, etc.
|
|
271
|
+
*
|
|
272
|
+
* - If installDir itself contains native model files (.onnx/.bin), returns installDir.
|
|
273
|
+
* - If installDir has exactly one subdirectory that contains native model files, returns that subdirectory path.
|
|
274
|
+
* (Ignores our metadata: .ready, manifest.json.) This can produce paths like
|
|
275
|
+
* .../tts/vits-piper-de_DE-thorsten-medium-int8/vits-piper-de_DE-thorsten-medium-int8 when the
|
|
276
|
+
* archive extracts a top-level folder with the same name as the model id; that is intentional.
|
|
277
|
+
* - Otherwise returns installDir unchanged.
|
|
278
|
+
*/
|
|
279
|
+
export async function resolveActualModelDir(
|
|
280
|
+
installDir: string
|
|
281
|
+
): Promise<string> {
|
|
282
|
+
try {
|
|
283
|
+
const dirExists = await exists(installDir);
|
|
284
|
+
if (!dirExists) return installDir;
|
|
285
|
+
|
|
286
|
+
const entries = await readDir(installDir);
|
|
287
|
+
const topLevelFiles = entries.filter((e) => !e.isDirectory());
|
|
288
|
+
if (topLevelFiles.some((f) => isNativeModelFileName(f.name ?? ''))) {
|
|
289
|
+
return installDir;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
const subdirs = entries.filter((e) => e.isDirectory());
|
|
293
|
+
const firstSubdir = subdirs[0];
|
|
294
|
+
const singleSubdir = subdirs.length === 1 ? firstSubdir : undefined;
|
|
295
|
+
|
|
296
|
+
if (singleSubdir != null) {
|
|
297
|
+
const candidatePath = singleSubdir.path;
|
|
298
|
+
if (
|
|
299
|
+
candidatePath != null &&
|
|
300
|
+
(await dirContainsModelFiles(candidatePath))
|
|
301
|
+
) {
|
|
302
|
+
return candidatePath;
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
return installDir;
|
|
307
|
+
} catch {
|
|
308
|
+
return installDir;
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
|
|
206
312
|
/**
|
|
207
313
|
* Get available disk space (in bytes)
|
|
208
314
|
* This is a simplified version. For accurate values on Android/iOS, use native modules.
|
|
@@ -47,7 +47,9 @@ export async function extractTarBz2(
|
|
|
47
47
|
if (signal) {
|
|
48
48
|
const onAbort = () => {
|
|
49
49
|
try {
|
|
50
|
-
|
|
50
|
+
// Use per-path cancel so aborting this extraction doesn't affect
|
|
51
|
+
// other extractions that may be running in parallel.
|
|
52
|
+
SherpaOnnx.cancelExtractBySourcePath(sourcePath);
|
|
51
53
|
} catch {
|
|
52
54
|
// Ignore cancel errors to avoid crashing on abort.
|
|
53
55
|
}
|
|
@@ -46,7 +46,9 @@ export async function extractTarZst(
|
|
|
46
46
|
if (signal) {
|
|
47
47
|
const onAbort = () => {
|
|
48
48
|
try {
|
|
49
|
-
|
|
49
|
+
// Use per-path cancel so aborting this extraction doesn't affect
|
|
50
|
+
// other extractions that may be running in parallel.
|
|
51
|
+
SherpaOnnx.cancelExtractBySourcePath(sourcePath);
|
|
50
52
|
} catch {
|
|
51
53
|
// Ignore cancel errors to avoid crashing on abort.
|
|
52
54
|
}
|
package/src/extraction/index.ts
CHANGED
|
@@ -12,8 +12,8 @@
|
|
|
12
12
|
import { DeviceEventEmitter, Platform } from 'react-native';
|
|
13
13
|
import { readDir, stat, exists } from '@dr.pogodin/react-native-fs';
|
|
14
14
|
import SherpaOnnx from '../NativeSherpaOnnx';
|
|
15
|
-
import { extractTarZst } from '
|
|
16
|
-
import { extractTarBz2 } from '
|
|
15
|
+
import { extractTarZst } from './extractTarZst';
|
|
16
|
+
import { extractTarBz2 } from './extractTarBz2';
|
|
17
17
|
import type {
|
|
18
18
|
BundledArchive,
|
|
19
19
|
ExtractArchiveOptions,
|
|
@@ -228,13 +228,9 @@ async function extractFromAsset(
|
|
|
228
228
|
}
|
|
229
229
|
|
|
230
230
|
if (signal) {
|
|
231
|
-
const cancel =
|
|
232
|
-
archive.format === 'tar.zst'
|
|
233
|
-
? SherpaOnnx.cancelExtractTarZst
|
|
234
|
-
: SherpaOnnx.cancelExtractTarBz2;
|
|
235
231
|
const onAbort = () => {
|
|
236
232
|
try {
|
|
237
|
-
|
|
233
|
+
SherpaOnnx.cancelExtractBySourcePath(archive.archivePath);
|
|
238
234
|
} catch {
|
|
239
235
|
// ignore
|
|
240
236
|
}
|
package/src/index.tsx
CHANGED
|
@@ -18,6 +18,7 @@ export {
|
|
|
18
18
|
|
|
19
19
|
export { copyFileToContentUri } from './tts';
|
|
20
20
|
|
|
21
|
+
export { getModelLicenses, type ModelLicense } from './licenses';
|
|
21
22
|
// Note: Feature-specific exports are available via subpath imports:
|
|
22
23
|
// - import { createSTT, createStreamingSTT, ... } from 'react-native-sherpa-onnx/stt'
|
|
23
24
|
// - import { createTTS, ... } from 'react-native-sherpa-onnx/tts'
|
package/src/licenses.ts
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import SherpaOnnx from './NativeSherpaOnnx';
|
|
2
|
+
|
|
3
|
+
export interface ModelLicense {
|
|
4
|
+
asset_name: string;
|
|
5
|
+
license_type: string;
|
|
6
|
+
commercial_use: 'yes' | 'no' | 'conditional' | 'restricted' | 'unknown';
|
|
7
|
+
confidence: string;
|
|
8
|
+
detection_source: string;
|
|
9
|
+
license_file: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export async function getModelLicenses(): Promise<ModelLicense[]> {
|
|
13
|
+
const asrPath = 'model_licenses/asr-models-license-status.csv';
|
|
14
|
+
const qnnPath = 'model_licenses/qnn-asr-models-license-status.csv';
|
|
15
|
+
const ttsPath = 'model_licenses/tts-models-license-status.csv';
|
|
16
|
+
|
|
17
|
+
const results = await Promise.allSettled([
|
|
18
|
+
SherpaOnnx.readAssetFileAsUtf8(asrPath),
|
|
19
|
+
SherpaOnnx.readAssetFileAsUtf8(qnnPath),
|
|
20
|
+
SherpaOnnx.readAssetFileAsUtf8(ttsPath),
|
|
21
|
+
]);
|
|
22
|
+
|
|
23
|
+
const [asrResult, qnnResult, ttsResult] = results;
|
|
24
|
+
|
|
25
|
+
const licenses: ModelLicense[] = [];
|
|
26
|
+
|
|
27
|
+
if (asrResult.status === 'fulfilled') {
|
|
28
|
+
licenses.push(...parseCsv(asrResult.value));
|
|
29
|
+
} else {
|
|
30
|
+
console.warn(
|
|
31
|
+
`[SherpaOnnx] Failed to load ASR model licenses: ${asrResult.reason}`
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (qnnResult.status === 'fulfilled') {
|
|
36
|
+
licenses.push(...parseCsv(qnnResult.value));
|
|
37
|
+
} else {
|
|
38
|
+
console.warn(
|
|
39
|
+
`[SherpaOnnx] Failed to load QNN model licenses: ${qnnResult.reason}`
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (ttsResult.status === 'fulfilled') {
|
|
44
|
+
licenses.push(...parseCsv(ttsResult.value));
|
|
45
|
+
} else {
|
|
46
|
+
console.warn(
|
|
47
|
+
`[SherpaOnnx] Failed to load TTS model licenses: ${ttsResult.reason}`
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return licenses;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function parseCsv(csvString: string): ModelLicense[] {
|
|
55
|
+
const lines = csvString.split(/\r?\n/);
|
|
56
|
+
if (lines.length === 0) {
|
|
57
|
+
return [];
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// The first line is the header
|
|
61
|
+
const headerLine = lines[0];
|
|
62
|
+
if (!headerLine) return [];
|
|
63
|
+
|
|
64
|
+
const headers = headerLine.split(',').map((h) => h.trim());
|
|
65
|
+
|
|
66
|
+
const results: ModelLicense[] = [];
|
|
67
|
+
|
|
68
|
+
for (let i = 1; i < lines.length; i++) {
|
|
69
|
+
const line = lines[i];
|
|
70
|
+
if (!line || line.trim() === '') continue;
|
|
71
|
+
|
|
72
|
+
// The CSV has 6 columns: asset_name, license_type, commercial_use,
|
|
73
|
+
// confidence, detection_source, license_file. The last column
|
|
74
|
+
// (license_file) may itself contain commas (e.g. URLs with query strings),
|
|
75
|
+
// so split into at most 6 parts and join any excess back into the last field.
|
|
76
|
+
const COLUMN_COUNT = 6;
|
|
77
|
+
const rawParts = line.split(',');
|
|
78
|
+
const parts =
|
|
79
|
+
rawParts.length <= COLUMN_COUNT
|
|
80
|
+
? rawParts
|
|
81
|
+
: [
|
|
82
|
+
...rawParts.slice(0, COLUMN_COUNT - 1),
|
|
83
|
+
rawParts.slice(COLUMN_COUNT - 1).join(','),
|
|
84
|
+
];
|
|
85
|
+
|
|
86
|
+
const entry: Record<string, string> = {};
|
|
87
|
+
for (let j = 0; j < headers.length; j++) {
|
|
88
|
+
const header = headers[j];
|
|
89
|
+
if (header) {
|
|
90
|
+
entry[header] = (parts[j] ?? '').trim();
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (entry['asset_name']) {
|
|
95
|
+
results.push(entry as unknown as ModelLicense);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return results;
|
|
100
|
+
}
|
package/src/stt/index.ts
CHANGED
|
@@ -40,7 +40,7 @@ function normalizeSttResult(raw: {
|
|
|
40
40
|
*
|
|
41
41
|
* @param modelPath - Model path configuration (asset, file, or auto)
|
|
42
42
|
* @param options - Optional preferInt8 and modelType (default: auto)
|
|
43
|
-
* @returns Object with success, detectedModels (array of { type, modelDir }),
|
|
43
|
+
* @returns Object with success, detectedModels (array of { type, modelDir }), modelType (primary detected type), optional error when success is false, and optionally isHardwareSpecificUnsupported
|
|
44
44
|
* @example
|
|
45
45
|
* ```typescript
|
|
46
46
|
* const path = { type: 'asset' as const, path: 'models/sherpa-onnx-whisper-tiny-en' };
|
|
@@ -55,15 +55,33 @@ export async function detectSttModel(
|
|
|
55
55
|
options?: { preferInt8?: boolean; modelType?: STTModelType }
|
|
56
56
|
): Promise<{
|
|
57
57
|
success: boolean;
|
|
58
|
+
/** Native validation/detect failure. */
|
|
59
|
+
error?: string;
|
|
58
60
|
detectedModels: Array<{ type: string; modelDir: string }>;
|
|
59
61
|
modelType?: string;
|
|
62
|
+
isHardwareSpecificUnsupported?: boolean;
|
|
60
63
|
}> {
|
|
61
64
|
const resolvedPath = await resolveModelPath(modelPath);
|
|
62
|
-
|
|
65
|
+
const raw = await SherpaOnnx.detectSttModel(
|
|
63
66
|
resolvedPath,
|
|
64
67
|
options?.preferInt8,
|
|
65
68
|
options?.modelType
|
|
66
69
|
);
|
|
70
|
+
const err =
|
|
71
|
+
typeof (raw as { error?: unknown }).error === 'string'
|
|
72
|
+
? String((raw as { error: string }).error).trim()
|
|
73
|
+
: '';
|
|
74
|
+
return {
|
|
75
|
+
success: raw.success,
|
|
76
|
+
...(err.length > 0 ? { error: err } : {}),
|
|
77
|
+
...(raw.isHardwareSpecificUnsupported === true
|
|
78
|
+
? { isHardwareSpecificUnsupported: true }
|
|
79
|
+
: {}),
|
|
80
|
+
detectedModels: raw.detectedModels ?? [],
|
|
81
|
+
...(raw.modelType != null && raw.modelType !== ''
|
|
82
|
+
? { modelType: raw.modelType }
|
|
83
|
+
: {}),
|
|
84
|
+
};
|
|
67
85
|
}
|
|
68
86
|
|
|
69
87
|
/**
|
package/src/stt/streaming.ts
CHANGED
|
@@ -82,6 +82,7 @@ function flattenInitOptionsForNative(options: StreamingSttInitOptions): {
|
|
|
82
82
|
provider?: string;
|
|
83
83
|
ruleFsts?: string;
|
|
84
84
|
ruleFars?: string;
|
|
85
|
+
dither?: number;
|
|
85
86
|
blankPenalty?: number;
|
|
86
87
|
debug?: boolean;
|
|
87
88
|
rule1MustContainNonSilence?: boolean;
|
|
@@ -107,6 +108,7 @@ function flattenInitOptionsForNative(options: StreamingSttInitOptions): {
|
|
|
107
108
|
provider: options.provider,
|
|
108
109
|
ruleFsts: options.ruleFsts,
|
|
109
110
|
ruleFars: options.ruleFars,
|
|
111
|
+
dither: options.dither,
|
|
110
112
|
blankPenalty: options.blankPenalty,
|
|
111
113
|
debug: options.debug,
|
|
112
114
|
rule1MustContainNonSilence: ep?.rule1?.mustContainNonSilence,
|
|
@@ -200,6 +202,7 @@ export async function createStreamingSTT(
|
|
|
200
202
|
if (flat.provider !== undefined) nativeOptions.provider = flat.provider;
|
|
201
203
|
if (flat.ruleFsts !== undefined) nativeOptions.ruleFsts = flat.ruleFsts;
|
|
202
204
|
if (flat.ruleFars !== undefined) nativeOptions.ruleFars = flat.ruleFars;
|
|
205
|
+
if (flat.dither !== undefined) nativeOptions.dither = flat.dither;
|
|
203
206
|
if (flat.blankPenalty !== undefined)
|
|
204
207
|
nativeOptions.blankPenalty = flat.blankPenalty;
|
|
205
208
|
if (flat.debug !== undefined) nativeOptions.debug = flat.debug;
|
|
@@ -75,6 +75,11 @@ export interface StreamingSttInitOptions {
|
|
|
75
75
|
ruleFsts?: string;
|
|
76
76
|
/** Path(s) to rule FARs for ITN. */
|
|
77
77
|
ruleFars?: string;
|
|
78
|
+
/**
|
|
79
|
+
* Feature extraction dither. **Android:** applied natively. **iOS:** ignored (C/CXX API has no
|
|
80
|
+
* `dither` on `FeatureConfig`); library default applies.
|
|
81
|
+
*/
|
|
82
|
+
dither?: number;
|
|
78
83
|
/** Blank penalty. */
|
|
79
84
|
blankPenalty?: number;
|
|
80
85
|
/** Enable debug logging. Default: false. */
|
package/src/stt/types.ts
CHANGED
|
@@ -228,7 +228,9 @@ export interface STTInitializeOptions {
|
|
|
228
228
|
ruleFars?: string;
|
|
229
229
|
|
|
230
230
|
/**
|
|
231
|
-
* Dither for feature extraction (Kotlin FeatureConfig.dither). Default
|
|
231
|
+
* Dither for feature extraction (Kotlin `FeatureConfig.dither`). Default: no dither.
|
|
232
|
+
* **Android:** applied natively. **iOS:** ignored — the bundled sherpa-onnx C/CXX API does not
|
|
233
|
+
* expose this field; the native default is used.
|
|
232
234
|
*/
|
|
233
235
|
dither?: number;
|
|
234
236
|
|
package/src/tts/index.ts
CHANGED
|
@@ -86,7 +86,7 @@ function flattenTtsModelOptionsForNative(
|
|
|
86
86
|
*
|
|
87
87
|
* @param modelPath - Model path configuration (asset, file, or auto)
|
|
88
88
|
* @param options - Optional modelType (default: 'auto')
|
|
89
|
-
* @returns Object with success, detectedModels (array of { type, modelDir }), modelType (primary detected type), and optionally lexiconLanguageCandidates (language ids for multi-lang Kokoro/Kitten)
|
|
89
|
+
* @returns Object with success, detectedModels (array of { type, modelDir }), modelType (primary detected type), optional error when success is false, and optionally lexiconLanguageCandidates (language ids for multi-lang Kokoro/Kitten)
|
|
90
90
|
* @example
|
|
91
91
|
* ```typescript
|
|
92
92
|
* const result = await detectTtsModel({ type: 'asset', path: 'models/vits-piper-en' });
|
|
@@ -101,13 +101,31 @@ export async function detectTtsModel(
|
|
|
101
101
|
options?: { modelType?: TTSModelType }
|
|
102
102
|
): Promise<{
|
|
103
103
|
success: boolean;
|
|
104
|
+
/** Native validation/detect failure (e.g. missing lexicon for Zipvoice). */
|
|
105
|
+
error?: string;
|
|
104
106
|
detectedModels: Array<{ type: string; modelDir: string }>;
|
|
105
107
|
modelType?: string;
|
|
106
108
|
/** Language ids from detected lexicon files ("default" for lexicon.txt, or e.g. "us-en", "zh" from lexicon-us-en.txt, lexicon-zh.txt). Present for Kokoro/Kitten; use for language selection UI. */
|
|
107
109
|
lexiconLanguageCandidates?: string[];
|
|
108
110
|
}> {
|
|
109
111
|
const resolvedPath = await resolveModelPath(modelPath);
|
|
110
|
-
|
|
112
|
+
const raw = await SherpaOnnx.detectTtsModel(resolvedPath, options?.modelType);
|
|
113
|
+
const err =
|
|
114
|
+
typeof (raw as { error?: unknown }).error === 'string'
|
|
115
|
+
? String((raw as { error: string }).error).trim()
|
|
116
|
+
: '';
|
|
117
|
+
return {
|
|
118
|
+
success: raw.success,
|
|
119
|
+
...(err.length > 0 ? { error: err } : {}),
|
|
120
|
+
detectedModels: raw.detectedModels ?? [],
|
|
121
|
+
...(raw.modelType != null && raw.modelType !== ''
|
|
122
|
+
? { modelType: raw.modelType }
|
|
123
|
+
: {}),
|
|
124
|
+
...(raw.lexiconLanguageCandidates != null &&
|
|
125
|
+
raw.lexiconLanguageCandidates.length > 0
|
|
126
|
+
? { lexiconLanguageCandidates: raw.lexiconLanguageCandidates }
|
|
127
|
+
: {}),
|
|
128
|
+
};
|
|
111
129
|
}
|
|
112
130
|
|
|
113
131
|
/**
|
|
@@ -124,6 +142,16 @@ function toNativeTtsOptions(
|
|
|
124
142
|
if (options.silenceScale !== undefined)
|
|
125
143
|
out.silenceScale = options.silenceScale;
|
|
126
144
|
if (options.referenceAudio != null) {
|
|
145
|
+
const sr = options.referenceAudio.sampleRate;
|
|
146
|
+
if (
|
|
147
|
+
typeof __DEV__ !== 'undefined' &&
|
|
148
|
+
__DEV__ &&
|
|
149
|
+
(!Number.isFinite(sr) || sr <= 0)
|
|
150
|
+
) {
|
|
151
|
+
console.warn(
|
|
152
|
+
'[react-native-sherpa-onnx] TTS referenceAudio.sampleRate must be > 0 for voice cloning (Zipvoice/Pocket).'
|
|
153
|
+
);
|
|
154
|
+
}
|
|
127
155
|
out.referenceAudio = options.referenceAudio.samples;
|
|
128
156
|
out.referenceSampleRate = options.referenceAudio.sampleRate;
|
|
129
157
|
}
|
package/src/tts/streaming.ts
CHANGED
|
@@ -90,6 +90,16 @@ function toNativeTtsOptions(
|
|
|
90
90
|
if (options.silenceScale !== undefined)
|
|
91
91
|
out.silenceScale = options.silenceScale;
|
|
92
92
|
if (options.referenceAudio != null) {
|
|
93
|
+
const sr = options.referenceAudio.sampleRate;
|
|
94
|
+
if (
|
|
95
|
+
typeof __DEV__ !== 'undefined' &&
|
|
96
|
+
__DEV__ &&
|
|
97
|
+
(!Number.isFinite(sr) || sr <= 0)
|
|
98
|
+
) {
|
|
99
|
+
console.warn(
|
|
100
|
+
'[react-native-sherpa-onnx] TTS referenceAudio.sampleRate must be > 0 for voice cloning (Zipvoice/Pocket).'
|
|
101
|
+
);
|
|
102
|
+
}
|
|
93
103
|
out.referenceAudio = options.referenceAudio.samples;
|
|
94
104
|
out.referenceSampleRate = options.referenceAudio.sampleRate;
|
|
95
105
|
}
|
package/src/tts/types.ts
CHANGED
|
@@ -202,15 +202,16 @@ export interface TtsGenerationOptions {
|
|
|
202
202
|
silenceScale?: number;
|
|
203
203
|
|
|
204
204
|
/**
|
|
205
|
-
* Reference audio for voice cloning (
|
|
206
|
-
*
|
|
207
|
-
*
|
|
205
|
+
* Reference audio for voice cloning (native GenerationConfig / Zipvoice prompt).
|
|
206
|
+
* **Native (iOS & Android):** Requires non-empty samples and `sampleRate > 0`. Used for **Zipvoice** (cloning) and **Pocket** (Mimi encoder).
|
|
207
|
+
* Other model types (vits, matcha, kokoro, kitten) are **rejected** if reference audio is passed.
|
|
208
|
+
* Mono float samples in [-1, 1].
|
|
208
209
|
*/
|
|
209
210
|
referenceAudio?: { samples: number[]; sampleRate: number };
|
|
210
211
|
|
|
211
212
|
/**
|
|
212
|
-
* Transcript
|
|
213
|
-
*
|
|
213
|
+
* Transcript of the reference utterance for **Zipvoice** voice cloning (prompt text); **required** when cloning with Zipvoice (non-empty after trim).
|
|
214
|
+
* **Pocket:** not read by sherpa-onnx native code; optional, e.g. for app metadata only.
|
|
214
215
|
*/
|
|
215
216
|
referenceText?: string;
|
|
216
217
|
|
package/src/utils.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Platform } from 'react-native';
|
|
2
2
|
import type { ModelPathConfig } from './types';
|
|
3
3
|
import SherpaOnnx from './NativeSherpaOnnx';
|
|
4
|
+
import { resolveActualModelDir } from './download';
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* Utility functions for model path handling
|
|
@@ -73,13 +74,33 @@ export function autoModelPath(path: string): ModelPathConfig {
|
|
|
73
74
|
* This handles different path types (asset, file, auto) and returns
|
|
74
75
|
* a platform-specific absolute path that can be used by native code.
|
|
75
76
|
*
|
|
77
|
+
* For type 'file', the path is normalized so that when the given path is an
|
|
78
|
+
* install directory (e.g. with .ready and manifest.json and one model subdir),
|
|
79
|
+
* the returned path is the subdirectory that actually contains the .onnx files.
|
|
80
|
+
* This allows apps that build paths as baseDir/modelId to work without change.
|
|
81
|
+
*
|
|
76
82
|
* @param config - Model path configuration
|
|
77
83
|
* @returns Promise resolving to absolute path usable by native code
|
|
78
84
|
*/
|
|
79
85
|
export async function resolveModelPath(
|
|
80
86
|
config: ModelPathConfig
|
|
81
87
|
): Promise<string> {
|
|
82
|
-
|
|
88
|
+
const path = await SherpaOnnx.resolveModelPath(config);
|
|
89
|
+
if (config.type === 'file') {
|
|
90
|
+
const resolved = await resolveActualModelDir(path);
|
|
91
|
+
// Diagnostic: log so we can tell if /usr/share/espeak-ng-data is due to our path or sherpa-onnx fallback.
|
|
92
|
+
if (__DEV__) {
|
|
93
|
+
console.log(
|
|
94
|
+
'[SherpaOnnx] resolveModelPath(file): native path=',
|
|
95
|
+
path,
|
|
96
|
+
resolved !== path
|
|
97
|
+
? `resolvedActualModelDir=> ${resolved}`
|
|
98
|
+
: '(unchanged)'
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
return resolved;
|
|
102
|
+
}
|
|
103
|
+
return path;
|
|
83
104
|
}
|
|
84
105
|
|
|
85
106
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
sherpa-onnx-android-v1.12.
|
|
1
|
+
sherpa-onnx-android-v1.12.31-1
|
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
sherpa-onnx-ios-v1.12.31-1
|