react-native-sherpa-onnx 0.3.5 → 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 +90 -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 +345 -153
- package/android/prebuilt-versions.gradle +2 -2
- 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 +306 -6
- package/android/src/main/cpp/jni/archive/sherpa-onnx-archive-helper.h +33 -4
- package/android/src/main/cpp/jni/archive/sherpa-onnx-archive-jni.cpp +266 -7
- 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 +137 -7
- package/android/src/main/java/com/sherpaonnx/SherpaOnnxAssetHelper.kt +51 -6
- package/android/src/main/java/com/sherpaonnx/SherpaOnnxModule.kt +159 -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 +108 -1
- package/ios/SherpaOnnxAudioConvert.h +10 -0
- package/ios/SherpaOnnxAudioConvert.mm +257 -1
- package/ios/archive/sherpa-onnx-archive-helper.h +10 -0
- package/ios/archive/sherpa-onnx-archive-helper.mm +56 -5
- 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 -3
- 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/extraction/extractTarZst.js +54 -0
- package/lib/module/extraction/extractTarZst.js.map +1 -0
- package/lib/module/extraction/index.js +190 -0
- package/lib/module/extraction/index.js.map +1 -0
- package/lib/module/extraction/types.js +2 -0
- package/lib/module/extraction/types.js.map +1 -0
- package/lib/module/index.js +2 -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 +72 -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 -5
- 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 +14 -0
- package/lib/typescript/src/extraction/extractTarZst.d.ts.map +1 -0
- package/lib/typescript/src/extraction/index.d.ts +50 -0
- package/lib/typescript/src/extraction/index.d.ts.map +1 -0
- package/lib/typescript/src/extraction/types.d.ts +60 -0
- package/lib/typescript/src/extraction/types.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 +11 -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 +92 -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 -2
- 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/extraction/extractTarZst.ts +79 -0
- package/src/extraction/index.ts +269 -0
- package/src/extraction/types.ts +63 -0
- package/src/index.tsx +2 -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/libarchive_prebuilt/ANDROID_RELEASE_TAG +1 -1
- package/third_party/libarchive_prebuilt/IOS_RELEASE_TAG +1 -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/typescript/src/download/extractTarBz2.d.ts.map +0 -1
- package/scripts/check-qnn-support.sh +0 -78
- /package/lib/typescript/src/{download → extraction}/extractTarBz2.d.ts +0 -0
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
package com.sherpaonnx
|
|
2
2
|
|
|
3
|
+
import android.content.Context
|
|
4
|
+
import android.util.Log
|
|
3
5
|
import com.facebook.react.bridge.Arguments
|
|
4
6
|
import com.facebook.react.bridge.Promise
|
|
7
|
+
import java.util.concurrent.ConcurrentHashMap
|
|
5
8
|
import java.util.concurrent.ExecutorService
|
|
6
9
|
import java.util.concurrent.Executors
|
|
7
10
|
import java.util.concurrent.atomic.AtomicBoolean
|
|
@@ -11,11 +14,12 @@ import java.util.concurrent.atomic.AtomicBoolean
|
|
|
11
14
|
* This class delegates to C++ native implementation via JNI.
|
|
12
15
|
*/
|
|
13
16
|
class SherpaOnnxArchiveHelper {
|
|
14
|
-
private val cancelRequested = AtomicBoolean(false)
|
|
15
|
-
|
|
16
17
|
companion object {
|
|
17
|
-
/**
|
|
18
|
-
private val extractExecutor: ExecutorService = Executors.
|
|
18
|
+
/** Thread pool for extractions – allows up to 2 concurrent extractions while keeping them off the React Native bridge thread. */
|
|
19
|
+
private val extractExecutor: ExecutorService = Executors.newFixedThreadPool(2)
|
|
20
|
+
|
|
21
|
+
/** Per-source-path cancellation flags. Key = absolute source archive path. */
|
|
22
|
+
private val cancelFlags = ConcurrentHashMap<String, AtomicBoolean>()
|
|
19
23
|
|
|
20
24
|
init {
|
|
21
25
|
try {
|
|
@@ -27,10 +31,24 @@ class SherpaOnnxArchiveHelper {
|
|
|
27
31
|
}
|
|
28
32
|
|
|
29
33
|
fun cancelExtractTarBz2() {
|
|
30
|
-
|
|
34
|
+
// Cancel ALL ongoing extractions (legacy global cancel)
|
|
35
|
+
for (flag in cancelFlags.values) flag.set(true)
|
|
36
|
+
nativeCancelExtract()
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
fun cancelExtractTarZst() {
|
|
40
|
+
// Cancel ALL ongoing extractions (legacy global cancel)
|
|
41
|
+
for (flag in cancelFlags.values) flag.set(true)
|
|
31
42
|
nativeCancelExtract()
|
|
32
43
|
}
|
|
33
44
|
|
|
45
|
+
/** Cancel a specific extraction identified by its source archive path. */
|
|
46
|
+
fun cancelExtractBySourcePath(sourcePath: String) {
|
|
47
|
+
// Only set the per-path flag; do not call nativeCancelExtract() since that is
|
|
48
|
+
// a global cancel that would also interrupt unrelated concurrent extractions.
|
|
49
|
+
cancelFlags[sourcePath]?.set(true)
|
|
50
|
+
}
|
|
51
|
+
|
|
34
52
|
fun extractTarBz2(
|
|
35
53
|
sourcePath: String,
|
|
36
54
|
targetPath: String,
|
|
@@ -48,7 +66,9 @@ class SherpaOnnxArchiveHelper {
|
|
|
48
66
|
}
|
|
49
67
|
|
|
50
68
|
try {
|
|
51
|
-
|
|
69
|
+
// Register per-path cancel flag
|
|
70
|
+
val cancelFlag = AtomicBoolean(false)
|
|
71
|
+
cancelFlags[sourcePath] = cancelFlag
|
|
52
72
|
|
|
53
73
|
// Create a progress callback object that JNI can call
|
|
54
74
|
val progressCallback = object : Any() {
|
|
@@ -58,19 +78,113 @@ class SherpaOnnxArchiveHelper {
|
|
|
58
78
|
}
|
|
59
79
|
|
|
60
80
|
// Run extraction on a background thread so the React Native bridge thread is not blocked.
|
|
61
|
-
//
|
|
81
|
+
// The thread pool allows multiple extractions in parallel.
|
|
62
82
|
extractExecutor.execute {
|
|
63
83
|
try {
|
|
84
|
+
// Check per-path cancel flag before starting the native extraction.
|
|
85
|
+
if (cancelFlag.get()) {
|
|
86
|
+
resolveOnce(false, "Cancelled")
|
|
87
|
+
return@execute
|
|
88
|
+
}
|
|
64
89
|
nativeExtractTarBz2(sourcePath, targetPath, force, progressCallback, promise)
|
|
65
90
|
} catch (e: Exception) {
|
|
66
91
|
resolveOnce(false, "Archive extraction error: ${e.message}")
|
|
92
|
+
} finally {
|
|
93
|
+
cancelFlags.remove(sourcePath)
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
} catch (e: Exception) {
|
|
97
|
+
cancelFlags.remove(sourcePath)
|
|
98
|
+
resolveOnce(false, "Archive extraction error: ${e.message}")
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
fun extractTarZst(
|
|
103
|
+
sourcePath: String,
|
|
104
|
+
targetPath: String,
|
|
105
|
+
force: Boolean,
|
|
106
|
+
promise: Promise,
|
|
107
|
+
onProgress: (bytes: Long, totalBytes: Long, percent: Double) -> Unit
|
|
108
|
+
) {
|
|
109
|
+
val promiseSettled = AtomicBoolean(false)
|
|
110
|
+
fun resolveOnce(success: Boolean, reason: String? = null) {
|
|
111
|
+
if (!promiseSettled.compareAndSet(false, true)) return
|
|
112
|
+
val result = Arguments.createMap()
|
|
113
|
+
result.putBoolean("success", success)
|
|
114
|
+
if (reason != null) result.putString("reason", reason)
|
|
115
|
+
promise.resolve(result)
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
try {
|
|
119
|
+
val cancelFlag = AtomicBoolean(false)
|
|
120
|
+
cancelFlags[sourcePath] = cancelFlag
|
|
121
|
+
|
|
122
|
+
val progressCallback = object : Any() {
|
|
123
|
+
fun invoke(bytesExtracted: Long, totalBytes: Long, percent: Double) {
|
|
124
|
+
onProgress(bytesExtracted, totalBytes, percent)
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
extractExecutor.execute {
|
|
128
|
+
try {
|
|
129
|
+
// Check per-path cancel flag before starting the native extraction.
|
|
130
|
+
if (cancelFlag.get()) {
|
|
131
|
+
resolveOnce(false, "Cancelled")
|
|
132
|
+
return@execute
|
|
133
|
+
}
|
|
134
|
+
nativeExtractTarZst(sourcePath, targetPath, force, progressCallback, promise)
|
|
135
|
+
} catch (e: Exception) {
|
|
136
|
+
resolveOnce(false, "Archive extraction error: ${e.message}")
|
|
137
|
+
} finally {
|
|
138
|
+
cancelFlags.remove(sourcePath)
|
|
67
139
|
}
|
|
68
140
|
}
|
|
69
141
|
} catch (e: Exception) {
|
|
142
|
+
cancelFlags.remove(sourcePath)
|
|
70
143
|
resolveOnce(false, "Archive extraction error: ${e.message}")
|
|
71
144
|
}
|
|
72
145
|
}
|
|
73
146
|
|
|
147
|
+
fun extractTarZstFromAsset(
|
|
148
|
+
context: Context,
|
|
149
|
+
assetPath: String,
|
|
150
|
+
targetPath: String,
|
|
151
|
+
force: Boolean,
|
|
152
|
+
promise: Promise,
|
|
153
|
+
onProgress: (bytes: Long, totalBytes: Long, percent: Double) -> Unit
|
|
154
|
+
) {
|
|
155
|
+
if (BuildConfig.DEBUG) {
|
|
156
|
+
Log.i("SherpaOnnx", "extractTarZstFromAsset assetPath=$assetPath targetPath=$targetPath")
|
|
157
|
+
}
|
|
158
|
+
val progressCallback = object : Any() {
|
|
159
|
+
fun invoke(bytesExtracted: Long, totalBytes: Long, percent: Double) {
|
|
160
|
+
onProgress(bytesExtracted, totalBytes, percent)
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
extractExecutor.execute {
|
|
164
|
+
try {
|
|
165
|
+
context.assets.open(assetPath).use { stream ->
|
|
166
|
+
nativeExtractTarZstFromStream(stream, targetPath, force, progressCallback, promise)
|
|
167
|
+
}
|
|
168
|
+
} catch (e: Exception) {
|
|
169
|
+
val result = Arguments.createMap()
|
|
170
|
+
result.putBoolean("success", false)
|
|
171
|
+
result.putString("reason", e.message ?: "Failed to open asset")
|
|
172
|
+
promise.resolve(result)
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
fun extractTarBz2FromAsset(
|
|
178
|
+
context: Context,
|
|
179
|
+
assetPath: String,
|
|
180
|
+
targetPath: String,
|
|
181
|
+
force: Boolean,
|
|
182
|
+
promise: Promise,
|
|
183
|
+
onProgress: (bytes: Long, totalBytes: Long, percent: Double) -> Unit
|
|
184
|
+
) {
|
|
185
|
+
extractTarZstFromAsset(context, assetPath, targetPath, force, promise, onProgress)
|
|
186
|
+
}
|
|
187
|
+
|
|
74
188
|
fun computeFileSha256(filePath: String, promise: Promise) {
|
|
75
189
|
nativeComputeFileSha256(filePath, promise)
|
|
76
190
|
}
|
|
@@ -84,6 +198,22 @@ class SherpaOnnxArchiveHelper {
|
|
|
84
198
|
promise: Promise
|
|
85
199
|
)
|
|
86
200
|
|
|
201
|
+
private external fun nativeExtractTarZst(
|
|
202
|
+
sourcePath: String,
|
|
203
|
+
targetPath: String,
|
|
204
|
+
force: Boolean,
|
|
205
|
+
progressCallback: Any?,
|
|
206
|
+
promise: Promise
|
|
207
|
+
)
|
|
208
|
+
|
|
209
|
+
private external fun nativeExtractTarZstFromStream(
|
|
210
|
+
inputStream: java.io.InputStream,
|
|
211
|
+
targetPath: String,
|
|
212
|
+
force: Boolean,
|
|
213
|
+
progressCallback: Any?,
|
|
214
|
+
promise: Promise
|
|
215
|
+
)
|
|
216
|
+
|
|
87
217
|
private external fun nativeCancelExtract()
|
|
88
218
|
|
|
89
219
|
private external fun nativeComputeFileSha256(
|
|
@@ -82,10 +82,12 @@ internal class SherpaOnnxAssetHelper(
|
|
|
82
82
|
try {
|
|
83
83
|
val baseDir = File(path)
|
|
84
84
|
if (!baseDir.exists()) {
|
|
85
|
-
|
|
85
|
+
promise.resolve(Arguments.createArray())
|
|
86
|
+
return
|
|
86
87
|
}
|
|
87
88
|
if (!baseDir.isDirectory) {
|
|
88
|
-
|
|
89
|
+
promise.resolve(Arguments.createArray())
|
|
90
|
+
return
|
|
89
91
|
}
|
|
90
92
|
|
|
91
93
|
val folders = mutableListOf<String>()
|
|
@@ -134,11 +136,18 @@ internal class SherpaOnnxAssetHelper(
|
|
|
134
136
|
try {
|
|
135
137
|
Log.i(logTag, "getAssetPackPath: packName=$packName")
|
|
136
138
|
val assetPackManager = AssetPackManagerFactory.getInstance(context)
|
|
137
|
-
|
|
139
|
+
var location: AssetPackLocation? = assetPackManager.getPackLocation(packName)
|
|
138
140
|
if (location == null) {
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
141
|
+
val allLocations = assetPackManager.getPackLocations()
|
|
142
|
+
location = allLocations?.get(packName)
|
|
143
|
+
if (allLocations != null) {
|
|
144
|
+
Log.i(logTag, "getAssetPackPath: getPackLocation was null, getPackLocations keys=${allLocations.keys}")
|
|
145
|
+
}
|
|
146
|
+
if (location == null) {
|
|
147
|
+
Log.i(logTag, "getAssetPackPath: location is null for pack '$packName'")
|
|
148
|
+
promise.resolve(null)
|
|
149
|
+
return
|
|
150
|
+
}
|
|
142
151
|
}
|
|
143
152
|
Log.i(logTag, "getAssetPackPath: storageMethod=${location.packStorageMethod()}, " +
|
|
144
153
|
"assetsPath=${location.assetsPath()}, path=${location.path()}")
|
|
@@ -170,6 +179,42 @@ internal class SherpaOnnxAssetHelper(
|
|
|
170
179
|
}
|
|
171
180
|
}
|
|
172
181
|
|
|
182
|
+
/**
|
|
183
|
+
* Lists asset paths of .tar.zst and .tar.bz2 archives in a PAD pack when stored as APK_ASSETS.
|
|
184
|
+
* Returns empty array when pack is null or STORAGE_FILES (caller uses path + readDir in that case).
|
|
185
|
+
* APK_ASSETS: pack content is merged into the app asset root; canonical path is "models"
|
|
186
|
+
* (pack layout src/main/assets/models/). Same for Play Store and bundletool install-time delivery.
|
|
187
|
+
*/
|
|
188
|
+
fun listBundledArchiveAssetPaths(packName: String, promise: Promise) {
|
|
189
|
+
try {
|
|
190
|
+
val assetPackManager = AssetPackManagerFactory.getInstance(context)
|
|
191
|
+
var location: AssetPackLocation? = assetPackManager.getPackLocation(packName)
|
|
192
|
+
if (location == null) {
|
|
193
|
+
location = assetPackManager.getPackLocations()?.get(packName)
|
|
194
|
+
}
|
|
195
|
+
if (location == null) {
|
|
196
|
+
promise.resolve(Arguments.createArray())
|
|
197
|
+
return
|
|
198
|
+
}
|
|
199
|
+
if (location.packStorageMethod() != AssetPackStorageMethod.STORAGE_FILES) {
|
|
200
|
+
val assetPrefix = "models"
|
|
201
|
+
val names = context.assets.list(assetPrefix) ?: emptyArray()
|
|
202
|
+
val archives = names.filter { it.endsWith(".tar.zst") || it.endsWith(".tar.bz2") }
|
|
203
|
+
val result = Arguments.createArray()
|
|
204
|
+
for (name in archives) {
|
|
205
|
+
result.pushString("$assetPrefix/$name")
|
|
206
|
+
}
|
|
207
|
+
Log.i(logTag, "listBundledArchiveAssetPaths: packName=$packName prefix=$assetPrefix count=${result.size()}")
|
|
208
|
+
promise.resolve(result)
|
|
209
|
+
} else {
|
|
210
|
+
promise.resolve(Arguments.createArray())
|
|
211
|
+
}
|
|
212
|
+
} catch (e: Exception) {
|
|
213
|
+
Log.w(logTag, "listBundledArchiveAssetPaths failed: ${e.message}")
|
|
214
|
+
promise.resolve(Arguments.createArray())
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
173
218
|
private fun resolveAssetPath(assetPath: String): String {
|
|
174
219
|
Log.i(logTag, "resolveAssetPath: assetPath=$assetPath")
|
|
175
220
|
val assetManager = context.assets
|
|
@@ -8,6 +8,7 @@ import com.facebook.react.bridge.ReadableMap
|
|
|
8
8
|
import com.facebook.react.bridge.Arguments
|
|
9
9
|
import com.facebook.react.module.annotations.ReactModule
|
|
10
10
|
import com.facebook.react.modules.core.DeviceEventManagerModule
|
|
11
|
+
import com.k2fsa.sherpa.onnx.WaveReader
|
|
11
12
|
|
|
12
13
|
@ReactModule(name = SherpaOnnxModule.NAME)
|
|
13
14
|
class SherpaOnnxModule(reactContext: ReactApplicationContext) :
|
|
@@ -303,6 +304,22 @@ class SherpaOnnxModule(reactContext: ReactApplicationContext) :
|
|
|
303
304
|
promise.resolve(null)
|
|
304
305
|
}
|
|
305
306
|
|
|
307
|
+
override fun extractTarZst(sourcePath: String, targetPath: String, force: Boolean, promise: Promise) {
|
|
308
|
+
archiveHelper.extractTarZst(sourcePath, targetPath, force, promise) { bytes, total, percent ->
|
|
309
|
+
emitExtractTarZstProgress(sourcePath, bytes, total, percent)
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
override fun cancelExtractTarZst(promise: Promise) {
|
|
314
|
+
archiveHelper.cancelExtractTarZst()
|
|
315
|
+
promise.resolve(null)
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
override fun cancelExtractBySourcePath(sourcePath: String, promise: Promise) {
|
|
319
|
+
archiveHelper.cancelExtractBySourcePath(sourcePath)
|
|
320
|
+
promise.resolve(null)
|
|
321
|
+
}
|
|
322
|
+
|
|
306
323
|
override fun computeFileSha256(filePath: String, promise: Promise) {
|
|
307
324
|
archiveHelper.computeFileSha256(filePath, promise)
|
|
308
325
|
}
|
|
@@ -318,6 +335,17 @@ class SherpaOnnxModule(reactContext: ReactApplicationContext) :
|
|
|
318
335
|
eventEmitter.emit("extractTarBz2Progress", payload)
|
|
319
336
|
}
|
|
320
337
|
|
|
338
|
+
private fun emitExtractTarZstProgress(sourcePath: String, bytes: Long, totalBytes: Long, percent: Double) {
|
|
339
|
+
val eventEmitter = reactApplicationContext
|
|
340
|
+
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
|
|
341
|
+
val payload = Arguments.createMap()
|
|
342
|
+
payload.putString("sourcePath", sourcePath)
|
|
343
|
+
payload.putDouble("bytes", bytes.toDouble())
|
|
344
|
+
payload.putDouble("totalBytes", totalBytes.toDouble())
|
|
345
|
+
payload.putDouble("percent", percent)
|
|
346
|
+
eventEmitter.emit("extractTarZstProgress", payload)
|
|
347
|
+
}
|
|
348
|
+
|
|
321
349
|
/**
|
|
322
350
|
* Resolve asset path - copy from assets to internal storage if needed
|
|
323
351
|
* Preserves the directory structure from assets (e.g., test_wavs/ stays as test_wavs/)
|
|
@@ -430,6 +458,7 @@ class SherpaOnnxModule(reactContext: ReactApplicationContext) :
|
|
|
430
458
|
val provider = if (options.hasKey("provider")) options.getString("provider") else null
|
|
431
459
|
val ruleFsts = if (options.hasKey("ruleFsts")) options.getString("ruleFsts") else null
|
|
432
460
|
val ruleFars = if (options.hasKey("ruleFars")) options.getString("ruleFars") else null
|
|
461
|
+
val dither = if (options.hasKey("dither")) options.getDouble("dither") else null
|
|
433
462
|
val blankPenalty = if (options.hasKey("blankPenalty")) options.getDouble("blankPenalty") else null
|
|
434
463
|
val debug = if (options.hasKey("debug")) options.getBoolean("debug") else null
|
|
435
464
|
val rule1MustContainNonSilence = if (options.hasKey("rule1MustContainNonSilence")) options.getBoolean("rule1MustContainNonSilence") else null
|
|
@@ -454,6 +483,7 @@ class SherpaOnnxModule(reactContext: ReactApplicationContext) :
|
|
|
454
483
|
provider,
|
|
455
484
|
ruleFsts,
|
|
456
485
|
ruleFars,
|
|
486
|
+
dither,
|
|
457
487
|
blankPenalty,
|
|
458
488
|
debug,
|
|
459
489
|
rule1MustContainNonSilence,
|
|
@@ -690,6 +720,72 @@ class SherpaOnnxModule(reactContext: ReactApplicationContext) :
|
|
|
690
720
|
}
|
|
691
721
|
}
|
|
692
722
|
|
|
723
|
+
/**
|
|
724
|
+
* Decode audio to mono float samples (approx. [-1, 1]) and effective sample rate.
|
|
725
|
+
* Same path/URI handling as [convertAudioToFormat]. WAV may use [WaveReader] when no resample is requested.
|
|
726
|
+
*/
|
|
727
|
+
override fun decodeAudioFileToFloatSamples(inputPath: String, targetSampleRateHz: Double?, promise: Promise) {
|
|
728
|
+
var tmpFile: java.io.File? = null
|
|
729
|
+
try {
|
|
730
|
+
val targetHz = (targetSampleRateHz ?: 0.0).toInt()
|
|
731
|
+
if (targetHz < 0) {
|
|
732
|
+
promise.reject("DECODE_ERROR", "targetSampleRateHz must be >= 0")
|
|
733
|
+
return
|
|
734
|
+
}
|
|
735
|
+
val (pathToUse, tmp) = resolveInputForConvert(inputPath)
|
|
736
|
+
tmpFile = tmp
|
|
737
|
+
|
|
738
|
+
if (pathToUse.endsWith(".wav", ignoreCase = true)) {
|
|
739
|
+
try {
|
|
740
|
+
val wave = WaveReader.readWave(pathToUse)
|
|
741
|
+
val s = wave.samples
|
|
742
|
+
if (s != null && s.isNotEmpty() && wave.sampleRate > 0 && (targetHz == 0 || targetHz == wave.sampleRate)) {
|
|
743
|
+
val map = Arguments.createMap()
|
|
744
|
+
val arr = Arguments.createArray()
|
|
745
|
+
for (i in s.indices) {
|
|
746
|
+
arr.pushDouble(s[i].toDouble())
|
|
747
|
+
}
|
|
748
|
+
map.putArray("samples", arr)
|
|
749
|
+
map.putInt("sampleRate", wave.sampleRate)
|
|
750
|
+
promise.resolve(map)
|
|
751
|
+
return
|
|
752
|
+
}
|
|
753
|
+
} catch (_: Throwable) {
|
|
754
|
+
// Fall through to FFmpeg/native path (e.g. odd WAV or resample requested).
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
val result = Companion.nativeDecodeAudioFileToFloatSamples(pathToUse, targetHz)
|
|
759
|
+
if (result.size == 1 && result[0] is String) {
|
|
760
|
+
promise.reject("DECODE_ERROR", result[0] as String)
|
|
761
|
+
return
|
|
762
|
+
}
|
|
763
|
+
if (result.size != 2 || result[0] !is FloatArray) {
|
|
764
|
+
promise.reject("DECODE_ERROR", "Unexpected native decode result")
|
|
765
|
+
return
|
|
766
|
+
}
|
|
767
|
+
val floats = result[0] as FloatArray
|
|
768
|
+
val rateObj = result.getOrNull(1) as? Number ?: run {
|
|
769
|
+
promise.reject("DECODE_ERROR", "Unexpected sample rate in native decode result")
|
|
770
|
+
return
|
|
771
|
+
}
|
|
772
|
+
val sr = rateObj.toInt()
|
|
773
|
+
val map = Arguments.createMap()
|
|
774
|
+
val arr = Arguments.createArray()
|
|
775
|
+
for (i in floats.indices) {
|
|
776
|
+
arr.pushDouble(floats[i].toDouble())
|
|
777
|
+
}
|
|
778
|
+
map.putArray("samples", arr)
|
|
779
|
+
map.putInt("sampleRate", sr)
|
|
780
|
+
promise.resolve(map)
|
|
781
|
+
} catch (e: Exception) {
|
|
782
|
+
android.util.Log.e(NAME, "DECODE_EXCEPTION: ${e.message}", e)
|
|
783
|
+
promise.reject("DECODE_EXCEPTION", e.message ?: "Failed to decode audio", e)
|
|
784
|
+
} finally {
|
|
785
|
+
tmpFile?.delete()
|
|
786
|
+
}
|
|
787
|
+
}
|
|
788
|
+
|
|
693
789
|
// ==================== TTS Methods ====================
|
|
694
790
|
|
|
695
791
|
/**
|
|
@@ -997,6 +1093,63 @@ class SherpaOnnxModule(reactContext: ReactApplicationContext) :
|
|
|
997
1093
|
assetHelper.getAssetPackPath(packName, promise)
|
|
998
1094
|
}
|
|
999
1095
|
|
|
1096
|
+
override fun listBundledArchiveAssetPaths(packName: String, promise: Promise) {
|
|
1097
|
+
assetHelper.listBundledArchiveAssetPaths(packName, promise)
|
|
1098
|
+
}
|
|
1099
|
+
|
|
1100
|
+
override fun extractTarZstFromAsset(
|
|
1101
|
+
assetPath: String,
|
|
1102
|
+
targetPath: String,
|
|
1103
|
+
force: Boolean,
|
|
1104
|
+
promise: Promise
|
|
1105
|
+
) {
|
|
1106
|
+
archiveHelper.extractTarZstFromAsset(
|
|
1107
|
+
reactApplicationContext,
|
|
1108
|
+
assetPath,
|
|
1109
|
+
targetPath,
|
|
1110
|
+
force,
|
|
1111
|
+
promise
|
|
1112
|
+
) { bytes, total, percent ->
|
|
1113
|
+
emitExtractTarZstProgress(assetPath, bytes, total, percent)
|
|
1114
|
+
}
|
|
1115
|
+
}
|
|
1116
|
+
|
|
1117
|
+
override fun extractTarBz2FromAsset(
|
|
1118
|
+
assetPath: String,
|
|
1119
|
+
targetPath: String,
|
|
1120
|
+
force: Boolean,
|
|
1121
|
+
promise: Promise
|
|
1122
|
+
) {
|
|
1123
|
+
archiveHelper.extractTarBz2FromAsset(
|
|
1124
|
+
reactApplicationContext,
|
|
1125
|
+
assetPath,
|
|
1126
|
+
targetPath,
|
|
1127
|
+
force,
|
|
1128
|
+
promise
|
|
1129
|
+
) { bytes, total, percent ->
|
|
1130
|
+
emitExtractProgress(assetPath, bytes, total, percent)
|
|
1131
|
+
}
|
|
1132
|
+
}
|
|
1133
|
+
|
|
1134
|
+
override fun readAssetFileAsUtf8(assetPath: String, promise: Promise) {
|
|
1135
|
+
// Validate assetPath to prevent path traversal: reject paths containing
|
|
1136
|
+
// "..", starting with "/" or "\", or containing backslashes.
|
|
1137
|
+
if (assetPath.contains("..") ||
|
|
1138
|
+
assetPath.startsWith("/") ||
|
|
1139
|
+
assetPath.startsWith("\\") ||
|
|
1140
|
+
assetPath.contains("\\")) {
|
|
1141
|
+
promise.reject("ASSET_READ_ERROR", "Invalid asset path: $assetPath")
|
|
1142
|
+
return
|
|
1143
|
+
}
|
|
1144
|
+
try {
|
|
1145
|
+
val content = reactApplicationContext.assets.open(assetPath).bufferedReader().use { it.readText() }
|
|
1146
|
+
promise.resolve(content)
|
|
1147
|
+
} catch (e: Exception) {
|
|
1148
|
+
android.util.Log.e(NAME, "Failed to read asset $assetPath: ${e.message}", e)
|
|
1149
|
+
promise.reject("ASSET_READ_ERROR", "Failed to read asset $assetPath: ${e.message}", e)
|
|
1150
|
+
}
|
|
1151
|
+
}
|
|
1152
|
+
|
|
1000
1153
|
companion object {
|
|
1001
1154
|
const val NAME = "SherpaOnnx"
|
|
1002
1155
|
|
|
@@ -1039,5 +1192,11 @@ class SherpaOnnxModule(reactContext: ReactApplicationContext) :
|
|
|
1039
1192
|
/** Convert any supported audio file to WAV 16 kHz mono 16-bit PCM. Returns empty string on success, error message otherwise. Requires FFmpeg prebuilts. */
|
|
1040
1193
|
@JvmStatic
|
|
1041
1194
|
private external fun nativeConvertAudioToWav16k(inputPath: String, outputPath: String): String
|
|
1195
|
+
|
|
1196
|
+
/**
|
|
1197
|
+
* On success: [FloatArray samples, Integer sampleRate]. On error: [String message].
|
|
1198
|
+
*/
|
|
1199
|
+
@JvmStatic
|
|
1200
|
+
private external fun nativeDecodeAudioFileToFloatSamples(inputPath: String, targetSampleRateHz: Int): Array<Any>
|
|
1042
1201
|
}
|
|
1043
1202
|
}
|
|
@@ -132,6 +132,7 @@ internal class SherpaOnnxOnlineSttHelper(
|
|
|
132
132
|
provider: String?,
|
|
133
133
|
ruleFsts: String?,
|
|
134
134
|
ruleFars: String?,
|
|
135
|
+
dither: Float?,
|
|
135
136
|
blankPenalty: Float?,
|
|
136
137
|
debug: Boolean?,
|
|
137
138
|
rule1MustContainNonSilence: Boolean?,
|
|
@@ -233,7 +234,7 @@ internal class SherpaOnnxOnlineSttHelper(
|
|
|
233
234
|
}
|
|
234
235
|
|
|
235
236
|
return OnlineRecognizerConfig(
|
|
236
|
-
featConfig = FeatureConfig(sampleRate = 16000, featureDim = 80, dither = 0f),
|
|
237
|
+
featConfig = FeatureConfig(sampleRate = 16000, featureDim = 80, dither = dither ?: 0f),
|
|
237
238
|
modelConfig = modelConfig,
|
|
238
239
|
endpointConfig = endpointConfig,
|
|
239
240
|
enableEndpoint = enableEndpoint,
|
|
@@ -260,6 +261,7 @@ internal class SherpaOnnxOnlineSttHelper(
|
|
|
260
261
|
provider: String?,
|
|
261
262
|
ruleFsts: String?,
|
|
262
263
|
ruleFars: String?,
|
|
264
|
+
dither: Double?,
|
|
263
265
|
blankPenalty: Double?,
|
|
264
266
|
debug: Boolean?,
|
|
265
267
|
rule1MustContainNonSilence: Boolean?,
|
|
@@ -286,6 +288,7 @@ internal class SherpaOnnxOnlineSttHelper(
|
|
|
286
288
|
provider = provider,
|
|
287
289
|
ruleFsts = ruleFsts,
|
|
288
290
|
ruleFars = ruleFars,
|
|
291
|
+
dither = dither?.toFloat(),
|
|
289
292
|
blankPenalty = blankPenalty?.toFloat(),
|
|
290
293
|
debug = debug,
|
|
291
294
|
rule1MustContainNonSilence = rule1MustContainNonSilence,
|