react-native-sherpa-onnx 0.2.0 → 0.3.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 +232 -236
- package/SherpaOnnx.podspec +68 -64
- package/android/build.gradle +182 -192
- package/android/codegen.gradle +57 -0
- package/android/prebuilt-download.gradle +428 -0
- package/android/prebuilt-versions.gradle +43 -0
- package/android/proguard-rules.pro +10 -0
- package/android/src/main/assets/testModels/add_mul_add.onnx +28 -0
- package/android/src/main/assets/testModels/nnapi_internal_uint8_support.onnx +0 -0
- package/android/src/main/assets/testModels/qnn_multi_ctx_embed.onnx +0 -0
- package/android/src/main/cpp/CMakeLists.txt +166 -129
- package/android/src/main/cpp/CMakePresets.json +54 -0
- package/android/src/main/cpp/crypto/sha256.cpp +174 -0
- package/android/src/main/cpp/crypto/sha256.h +16 -0
- package/android/src/main/cpp/jni/archive/sherpa-onnx-archive-helper.cpp +404 -0
- package/android/src/main/cpp/jni/archive/sherpa-onnx-archive-helper.h +56 -0
- package/android/src/main/cpp/jni/archive/sherpa-onnx-archive-jni.cpp +181 -0
- package/android/src/main/cpp/jni/audio/sherpa-onnx-audio-convert-jni.cpp +888 -0
- package/{ios → android/src/main/cpp/jni/model_detect}/sherpa-onnx-common.h +18 -18
- package/android/src/main/cpp/jni/model_detect/sherpa-onnx-detect-jni-common.cpp +86 -0
- package/android/src/main/cpp/jni/model_detect/sherpa-onnx-detect-jni-common.h +20 -0
- package/android/src/main/cpp/jni/model_detect/sherpa-onnx-model-detect-helper.cpp +423 -0
- package/android/src/main/cpp/jni/model_detect/sherpa-onnx-model-detect-helper.h +55 -0
- package/android/src/main/cpp/jni/model_detect/sherpa-onnx-model-detect-stt.cpp +399 -0
- package/android/src/main/cpp/jni/model_detect/sherpa-onnx-model-detect-tts.cpp +238 -0
- package/{ios → android/src/main/cpp/jni/model_detect}/sherpa-onnx-model-detect.h +122 -89
- package/android/src/main/cpp/jni/model_detect/sherpa-onnx-stt-wrapper.cpp +99 -0
- package/android/src/main/cpp/jni/model_detect/sherpa-onnx-stt-wrapper.h +16 -0
- package/android/src/main/cpp/jni/model_detect/sherpa-onnx-tts-wrapper.cpp +78 -0
- package/android/src/main/cpp/jni/model_detect/sherpa-onnx-tts-wrapper.h +16 -0
- package/android/src/main/cpp/jni/module/sherpa-onnx-module-jni.cpp +190 -0
- package/android/src/main/cpp/jni/tts/sherpa-onnx-tts-zipvoice-jni.cpp +301 -0
- package/android/src/main/java/com/sherpaonnx/SherpaOnnxArchiveHelper.kt +94 -0
- package/android/src/main/java/com/sherpaonnx/{SherpaOnnxCoreHelper.kt → SherpaOnnxAssetHelper.kt} +350 -236
- package/android/src/main/java/com/sherpaonnx/SherpaOnnxModule.kt +791 -483
- package/android/src/main/java/com/sherpaonnx/SherpaOnnxSttHelper.kt +699 -109
- package/android/src/main/java/com/sherpaonnx/SherpaOnnxTtsHelper.kt +1123 -668
- package/android/src/main/java/com/sherpaonnx/ZipvoiceTtsWrapper.kt +187 -0
- package/ios/SherpaOnnx+Assets.h +11 -0
- package/ios/SherpaOnnx+Assets.mm +325 -0
- package/ios/SherpaOnnx+STT.mm +455 -118
- package/ios/SherpaOnnx+TTS.mm +1101 -712
- package/ios/SherpaOnnx.h +17 -6
- package/ios/SherpaOnnx.mm +206 -311
- package/ios/SherpaOnnx.xcconfig +19 -19
- package/ios/SherpaOnnxCoreMLHelper.swift +24 -0
- package/ios/archive/sherpa-onnx-archive-helper.h +21 -0
- package/ios/archive/sherpa-onnx-archive-helper.mm +296 -0
- package/ios/libarchive_darwin_config.h +153 -0
- package/{android/src/main/cpp/jni → ios/model_detect}/sherpa-onnx-common.h +18 -18
- package/ios/model_detect/sherpa-onnx-model-detect-helper.h +49 -0
- package/ios/model_detect/sherpa-onnx-model-detect-helper.mm +210 -0
- package/ios/model_detect/sherpa-onnx-model-detect-stt.mm +344 -0
- package/ios/model_detect/sherpa-onnx-model-detect-tts.mm +201 -0
- package/{android/src/main/cpp/jni → ios/model_detect}/sherpa-onnx-model-detect.h +117 -89
- package/ios/scripts/patch-libarchive-includes.sh +61 -0
- package/ios/scripts/setup-ios-libarchive.sh +98 -0
- package/ios/stt/sherpa-onnx-stt-wrapper.h +129 -0
- package/ios/stt/sherpa-onnx-stt-wrapper.mm +523 -0
- package/ios/{sherpa-onnx-tts-wrapper.h → tts/sherpa-onnx-tts-wrapper.h} +90 -85
- package/ios/{sherpa-onnx-tts-wrapper.mm → tts/sherpa-onnx-tts-wrapper.mm} +376 -345
- package/lib/module/NativeSherpaOnnx.js +3 -0
- package/lib/module/NativeSherpaOnnx.js.map +1 -1
- package/lib/module/audio/index.js +22 -0
- package/lib/module/audio/index.js.map +1 -0
- package/lib/module/diarization/index.js +1 -1
- package/lib/module/diarization/index.js.map +1 -1
- package/lib/module/download/ModelDownloadManager.js +918 -0
- package/lib/module/download/ModelDownloadManager.js.map +1 -0
- package/lib/module/download/extractTarBz2.js +53 -0
- package/lib/module/download/extractTarBz2.js.map +1 -0
- package/lib/module/download/index.js +6 -0
- package/lib/module/download/index.js.map +1 -0
- package/lib/module/download/validation.js +178 -0
- package/lib/module/download/validation.js.map +1 -0
- package/lib/module/enhancement/index.js +1 -1
- package/lib/module/enhancement/index.js.map +1 -1
- package/lib/module/index.js +41 -3
- package/lib/module/index.js.map +1 -1
- package/lib/module/separation/index.js +1 -1
- package/lib/module/separation/index.js.map +1 -1
- package/lib/module/stt/index.js +127 -60
- package/lib/module/stt/index.js.map +1 -1
- package/lib/module/stt/sttModelLanguages.js +512 -0
- package/lib/module/stt/sttModelLanguages.js.map +1 -0
- package/lib/module/stt/types.js +53 -1
- package/lib/module/stt/types.js.map +1 -1
- package/lib/module/tts/index.js +216 -289
- package/lib/module/tts/index.js.map +1 -1
- package/lib/module/tts/types.js +86 -1
- package/lib/module/tts/types.js.map +1 -1
- package/lib/module/types.js.map +1 -1
- package/lib/module/utils.js +86 -73
- package/lib/module/utils.js.map +1 -1
- package/lib/module/vad/index.js +1 -1
- package/lib/module/vad/index.js.map +1 -1
- package/lib/typescript/src/NativeSherpaOnnx.d.ts +192 -38
- package/lib/typescript/src/NativeSherpaOnnx.d.ts.map +1 -1
- package/lib/typescript/src/audio/index.d.ts +13 -0
- package/lib/typescript/src/audio/index.d.ts.map +1 -0
- package/lib/typescript/src/diarization/index.d.ts +3 -2
- package/lib/typescript/src/diarization/index.d.ts.map +1 -1
- package/lib/typescript/src/download/ModelDownloadManager.d.ts +108 -0
- package/lib/typescript/src/download/ModelDownloadManager.d.ts.map +1 -0
- package/lib/typescript/src/download/extractTarBz2.d.ts +14 -0
- package/lib/typescript/src/download/extractTarBz2.d.ts.map +1 -0
- package/lib/typescript/src/download/index.d.ts +7 -0
- package/lib/typescript/src/download/index.d.ts.map +1 -0
- package/lib/typescript/src/download/validation.d.ts +57 -0
- package/lib/typescript/src/download/validation.d.ts.map +1 -0
- package/lib/typescript/src/enhancement/index.d.ts +3 -2
- package/lib/typescript/src/enhancement/index.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +26 -2
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/separation/index.d.ts +3 -2
- package/lib/typescript/src/separation/index.d.ts.map +1 -1
- package/lib/typescript/src/stt/index.d.ts +31 -43
- package/lib/typescript/src/stt/index.d.ts.map +1 -1
- package/lib/typescript/src/stt/sttModelLanguages.d.ts +52 -0
- package/lib/typescript/src/stt/sttModelLanguages.d.ts.map +1 -0
- package/lib/typescript/src/stt/types.d.ts +196 -9
- package/lib/typescript/src/stt/types.d.ts.map +1 -1
- package/lib/typescript/src/tts/index.d.ts +25 -211
- package/lib/typescript/src/tts/index.d.ts.map +1 -1
- package/lib/typescript/src/tts/types.d.ts +148 -25
- package/lib/typescript/src/tts/types.d.ts.map +1 -1
- package/lib/typescript/src/types.d.ts +0 -32
- package/lib/typescript/src/types.d.ts.map +1 -1
- package/lib/typescript/src/utils.d.ts +28 -13
- package/lib/typescript/src/utils.d.ts.map +1 -1
- package/lib/typescript/src/vad/index.d.ts +3 -2
- package/lib/typescript/src/vad/index.d.ts.map +1 -1
- package/package.json +250 -222
- package/scripts/check-qnn-support.sh +78 -0
- package/scripts/setup-ios-framework.sh +379 -282
- package/src/NativeSherpaOnnx.ts +474 -251
- package/src/audio/index.ts +32 -0
- package/src/diarization/index.ts +4 -2
- package/src/download/ModelDownloadManager.ts +1325 -0
- package/src/download/extractTarBz2.ts +78 -0
- package/src/download/index.ts +43 -0
- package/src/download/validation.ts +279 -0
- package/src/enhancement/index.ts +4 -2
- package/src/index.tsx +78 -27
- package/src/separation/index.ts +4 -2
- package/src/stt/index.ts +249 -89
- package/src/stt/sttModelLanguages.ts +237 -0
- package/src/stt/types.ts +263 -9
- package/src/tts/index.ts +470 -458
- package/src/tts/types.ts +373 -218
- package/src/types.ts +0 -44
- package/src/utils.ts +145 -131
- package/src/vad/index.ts +4 -2
- package/third_party/ffmpeg_prebuilt/ANDROID_RELEASE_TAG +1 -0
- package/third_party/libarchive_prebuilt/ANDROID_RELEASE_TAG +1 -0
- package/third_party/libarchive_prebuilt/IOS_RELEASE_TAG +1 -0
- package/third_party/sherpa-onnx-prebuilt/ANDROID_RELEASE_TAG +1 -0
- package/third_party/sherpa-onnx-prebuilt/IOS_RELEASE_TAG +1 -0
- package/android/src/main/cpp/include/sherpa-onnx/c-api/c-api.h +0 -1918
- package/android/src/main/cpp/include/sherpa-onnx/c-api/cxx-api.h +0 -841
- package/android/src/main/cpp/jni/sherpa-onnx-model-detect.cpp +0 -541
- package/android/src/main/cpp/jni/sherpa-onnx-stt-jni.cpp +0 -336
- package/android/src/main/cpp/jni/sherpa-onnx-stt-wrapper.cpp +0 -222
- package/android/src/main/cpp/jni/sherpa-onnx-stt-wrapper.h +0 -68
- package/android/src/main/cpp/jni/sherpa-onnx-tts-jni.cpp +0 -823
- package/android/src/main/cpp/jni/sherpa-onnx-tts-wrapper.cpp +0 -387
- package/android/src/main/cpp/jni/sherpa-onnx-tts-wrapper.h +0 -147
- package/ios/Frameworks/sherpa_onnx.xcframework.zip +0 -0
- package/ios/include/sherpa-onnx/c-api/c-api.h +0 -1918
- package/ios/include/sherpa-onnx/c-api/cxx-api.h +0 -841
- package/ios/sherpa-onnx-model-detect.mm +0 -441
- package/ios/sherpa-onnx-stt-wrapper.h +0 -48
- package/ios/sherpa-onnx-stt-wrapper.mm +0 -201
- package/scripts/copy-headers.js +0 -184
- package/scripts/setup-assets.js +0 -323
package/android/src/main/java/com/sherpaonnx/{SherpaOnnxCoreHelper.kt → SherpaOnnxAssetHelper.kt}
RENAMED
|
@@ -1,236 +1,350 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
Log.
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
val
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
1
|
+
/**
|
|
2
|
+
* SherpaOnnxAssetHelper.kt
|
|
3
|
+
*
|
|
4
|
+
* Purpose: Asset and model path logic for the SherpaOnnx module: resolveModelPath (asset/file/auto),
|
|
5
|
+
* listAssetModels, listModelsAtPath, getAssetPackPath (PAD), and path/hint helpers. Aligns with
|
|
6
|
+
* iOS SherpaOnnx+Assets.mm. Used by SherpaOnnxModule.
|
|
7
|
+
*/
|
|
8
|
+
package com.sherpaonnx
|
|
9
|
+
|
|
10
|
+
import android.util.Log
|
|
11
|
+
import com.facebook.react.bridge.Arguments
|
|
12
|
+
import com.facebook.react.bridge.Promise
|
|
13
|
+
import com.facebook.react.bridge.ReadableMap
|
|
14
|
+
import com.facebook.react.bridge.ReactApplicationContext
|
|
15
|
+
import com.google.android.play.core.assetpacks.AssetPackLocation
|
|
16
|
+
import com.google.android.play.core.assetpacks.AssetPackManagerFactory
|
|
17
|
+
import com.google.android.play.core.assetpacks.model.AssetPackStorageMethod
|
|
18
|
+
import java.io.File
|
|
19
|
+
import java.io.FileOutputStream
|
|
20
|
+
|
|
21
|
+
internal class SherpaOnnxAssetHelper(
|
|
22
|
+
private val context: ReactApplicationContext,
|
|
23
|
+
private val logTag: String
|
|
24
|
+
) {
|
|
25
|
+
fun resolveModelPath(config: ReadableMap, promise: Promise) {
|
|
26
|
+
try {
|
|
27
|
+
val type = config.getString("type") ?: "auto"
|
|
28
|
+
val path = config.getString("path")
|
|
29
|
+
?: throw IllegalArgumentException("Path is required")
|
|
30
|
+
|
|
31
|
+
Log.i(logTag, "resolveModelPath: type=$type, path=$path")
|
|
32
|
+
|
|
33
|
+
val resolvedPath = when (type) {
|
|
34
|
+
"asset" -> resolveAssetPath(path)
|
|
35
|
+
"file" -> resolveFilePath(path)
|
|
36
|
+
"auto" -> resolveAutoPath(path)
|
|
37
|
+
else -> throw IllegalArgumentException("Unknown path type: $type")
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
Log.i(logTag, "resolveModelPath: resolved=$resolvedPath")
|
|
41
|
+
promise.resolve(resolvedPath)
|
|
42
|
+
} catch (e: Exception) {
|
|
43
|
+
val errorMessage = "Failed to resolve model path: ${e.message ?: e.javaClass.simpleName}"
|
|
44
|
+
Log.e(logTag, errorMessage, e)
|
|
45
|
+
promise.reject("PATH_RESOLVE_ERROR", errorMessage, e)
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
fun listAssetModels(promise: Promise) {
|
|
50
|
+
try {
|
|
51
|
+
val assetManager = context.assets
|
|
52
|
+
val modelFolders = mutableListOf<String>()
|
|
53
|
+
|
|
54
|
+
try {
|
|
55
|
+
val items = assetManager.list("models") ?: emptyArray()
|
|
56
|
+
for (item in items) {
|
|
57
|
+
val subItems = assetManager.list("models/$item")
|
|
58
|
+
if (subItems != null && subItems.isNotEmpty()) {
|
|
59
|
+
modelFolders.add(item)
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
} catch (e: Exception) {
|
|
63
|
+
Log.w(logTag, "Could not list models directory: ${e.message}")
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
val result = Arguments.createArray()
|
|
67
|
+
modelFolders.forEach { folder ->
|
|
68
|
+
val modelMap = Arguments.createMap()
|
|
69
|
+
modelMap.putString("folder", folder)
|
|
70
|
+
modelMap.putString("hint", inferModelHint(folder))
|
|
71
|
+
result.pushMap(modelMap)
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
promise.resolve(result)
|
|
75
|
+
} catch (e: Exception) {
|
|
76
|
+
Log.e(logTag, "LIST_ASSETS_ERROR: Failed to list asset models: ${e.message}", e)
|
|
77
|
+
promise.reject("LIST_ASSETS_ERROR", "Failed to list asset models: ${e.message}", e)
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
fun listModelsAtPath(path: String, recursive: Boolean, promise: Promise) {
|
|
82
|
+
try {
|
|
83
|
+
val baseDir = File(path)
|
|
84
|
+
if (!baseDir.exists()) {
|
|
85
|
+
throw IllegalArgumentException("Path does not exist: $path")
|
|
86
|
+
}
|
|
87
|
+
if (!baseDir.isDirectory) {
|
|
88
|
+
throw IllegalArgumentException("Path is not a directory: $path")
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
val folders = mutableListOf<String>()
|
|
92
|
+
|
|
93
|
+
if (recursive) {
|
|
94
|
+
val basePath = baseDir.toPath()
|
|
95
|
+
baseDir.walkTopDown().forEach { file ->
|
|
96
|
+
if (file.isDirectory && file != baseDir) {
|
|
97
|
+
val rel = basePath.relativize(file.toPath()).toString()
|
|
98
|
+
.replace(File.separatorChar, '/')
|
|
99
|
+
if (rel.isNotEmpty()) {
|
|
100
|
+
folders.add(rel)
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
} else {
|
|
105
|
+
val children = baseDir.listFiles() ?: emptyArray()
|
|
106
|
+
for (child in children) {
|
|
107
|
+
if (child.isDirectory) {
|
|
108
|
+
folders.add(child.name)
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
val result = Arguments.createArray()
|
|
114
|
+
folders.distinct().forEach { folder ->
|
|
115
|
+
val hintName = folder.substringAfterLast('/')
|
|
116
|
+
val modelMap = Arguments.createMap()
|
|
117
|
+
modelMap.putString("folder", folder)
|
|
118
|
+
modelMap.putString("hint", inferModelHint(hintName))
|
|
119
|
+
result.pushMap(modelMap)
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
promise.resolve(result)
|
|
123
|
+
} catch (e: Exception) {
|
|
124
|
+
Log.e(logTag, "LIST_MODELS_ERROR: Failed to list models at path: ${e.message}", e)
|
|
125
|
+
promise.reject("LIST_MODELS_ERROR", "Failed to list models at path: ${e.message}", e)
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Returns the filesystem path to the "models" directory inside a Play Asset Delivery (PAD) pack,
|
|
131
|
+
* or null if the pack is not available.
|
|
132
|
+
*/
|
|
133
|
+
fun getAssetPackPath(packName: String, promise: Promise) {
|
|
134
|
+
try {
|
|
135
|
+
Log.i(logTag, "getAssetPackPath: packName=$packName")
|
|
136
|
+
val assetPackManager = AssetPackManagerFactory.getInstance(context)
|
|
137
|
+
val location: AssetPackLocation? = assetPackManager.getPackLocation(packName)
|
|
138
|
+
if (location == null) {
|
|
139
|
+
Log.i(logTag, "getAssetPackPath: location is null for pack '$packName'")
|
|
140
|
+
promise.resolve(null)
|
|
141
|
+
return
|
|
142
|
+
}
|
|
143
|
+
Log.i(logTag, "getAssetPackPath: storageMethod=${location.packStorageMethod()}, " +
|
|
144
|
+
"assetsPath=${location.assetsPath()}, path=${location.path()}")
|
|
145
|
+
if (location.packStorageMethod() != AssetPackStorageMethod.STORAGE_FILES) {
|
|
146
|
+
Log.i(logTag, "getAssetPackPath: storage method is not STORAGE_FILES, returning null")
|
|
147
|
+
promise.resolve(null)
|
|
148
|
+
return
|
|
149
|
+
}
|
|
150
|
+
val assetsPath = location.assetsPath()
|
|
151
|
+
val path = location.path()
|
|
152
|
+
val modelsDir = when {
|
|
153
|
+
assetsPath != null && assetsPath.isNotEmpty() -> File(assetsPath, "models").absolutePath
|
|
154
|
+
path != null && path.isNotEmpty() -> File(path, "assets/models").absolutePath
|
|
155
|
+
else -> null
|
|
156
|
+
}
|
|
157
|
+
Log.i(logTag, "getAssetPackPath: resolved modelsDir=$modelsDir")
|
|
158
|
+
if (modelsDir != null) {
|
|
159
|
+
val dir = File(modelsDir)
|
|
160
|
+
Log.i(logTag, "getAssetPackPath: modelsDir exists=${dir.exists()}, isDir=${dir.isDirectory}")
|
|
161
|
+
if (dir.exists() && dir.isDirectory) {
|
|
162
|
+
val children = dir.listFiles()?.map { it.name } ?: emptyList()
|
|
163
|
+
Log.i(logTag, "getAssetPackPath: modelsDir contents=$children")
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
promise.resolve(modelsDir)
|
|
167
|
+
} catch (e: Exception) {
|
|
168
|
+
Log.w(logTag, "getAssetPackPath failed: ${e.message}")
|
|
169
|
+
promise.resolve(null)
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
private fun resolveAssetPath(assetPath: String): String {
|
|
174
|
+
Log.i(logTag, "resolveAssetPath: assetPath=$assetPath")
|
|
175
|
+
val assetManager = context.assets
|
|
176
|
+
|
|
177
|
+
val pathParts = assetPath.split("/")
|
|
178
|
+
val baseDir = if (pathParts.size > 1) pathParts[0] else "models"
|
|
179
|
+
|
|
180
|
+
val targetBaseDir = File(context.filesDir, baseDir)
|
|
181
|
+
targetBaseDir.mkdirs()
|
|
182
|
+
Log.i(logTag, "resolveAssetPath: targetBaseDir=${targetBaseDir.absolutePath}, exists=${targetBaseDir.exists()}")
|
|
183
|
+
|
|
184
|
+
val isFilePath = pathParts.any { it.contains(".") && !it.startsWith(".") }
|
|
185
|
+
|
|
186
|
+
val targetPath = if (isFilePath) {
|
|
187
|
+
File(targetBaseDir, pathParts.drop(1).joinToString("/"))
|
|
188
|
+
} else {
|
|
189
|
+
File(targetBaseDir, File(assetPath).name)
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
if (isFilePath) {
|
|
193
|
+
if (targetPath.exists() && targetPath.isFile) {
|
|
194
|
+
return targetPath.absolutePath
|
|
195
|
+
}
|
|
196
|
+
val parentDir = targetPath.parentFile ?: targetBaseDir
|
|
197
|
+
parentDir.mkdirs()
|
|
198
|
+
|
|
199
|
+
try {
|
|
200
|
+
assetManager.open(assetPath).use { input ->
|
|
201
|
+
FileOutputStream(targetPath).use { output ->
|
|
202
|
+
input.copyTo(output)
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
return targetPath.absolutePath
|
|
206
|
+
} catch (e: java.io.FileNotFoundException) {
|
|
207
|
+
val parentAssetPath = pathParts.dropLast(1).joinToString("/")
|
|
208
|
+
if (parentAssetPath.isNotEmpty()) {
|
|
209
|
+
try {
|
|
210
|
+
copyAssetRecursively(assetManager, parentAssetPath, parentDir)
|
|
211
|
+
if (targetPath.exists() && targetPath.isFile) {
|
|
212
|
+
return targetPath.absolutePath
|
|
213
|
+
}
|
|
214
|
+
throw IllegalArgumentException("File not found after copying parent directory: $assetPath")
|
|
215
|
+
} catch (dirException: Exception) {
|
|
216
|
+
throw IllegalArgumentException(
|
|
217
|
+
"Failed to extract asset file: $assetPath. Tried direct copy and directory copy.",
|
|
218
|
+
dirException
|
|
219
|
+
)
|
|
220
|
+
}
|
|
221
|
+
} else {
|
|
222
|
+
throw IllegalArgumentException("Failed to extract asset file: $assetPath", e)
|
|
223
|
+
}
|
|
224
|
+
} catch (e: Exception) {
|
|
225
|
+
throw IllegalArgumentException("Failed to extract asset file: $assetPath", e)
|
|
226
|
+
}
|
|
227
|
+
} else {
|
|
228
|
+
if (targetPath.exists() && targetPath.isDirectory) {
|
|
229
|
+
return targetPath.absolutePath
|
|
230
|
+
}
|
|
231
|
+
try {
|
|
232
|
+
targetPath.mkdirs()
|
|
233
|
+
copyAssetRecursively(assetManager, assetPath, targetPath)
|
|
234
|
+
return targetPath.absolutePath
|
|
235
|
+
} catch (e: Exception) {
|
|
236
|
+
throw IllegalArgumentException("Failed to extract asset directory: $assetPath", e)
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
private fun copyAssetRecursively(
|
|
242
|
+
assetManager: android.content.res.AssetManager,
|
|
243
|
+
assetPath: String,
|
|
244
|
+
targetDir: File
|
|
245
|
+
) {
|
|
246
|
+
val assetFiles = assetManager.list(assetPath)
|
|
247
|
+
?: throw IllegalArgumentException("Asset path not found: $assetPath")
|
|
248
|
+
|
|
249
|
+
for (fileName in assetFiles) {
|
|
250
|
+
val assetFilePath = "$assetPath/$fileName"
|
|
251
|
+
val targetFile = File(targetDir, fileName)
|
|
252
|
+
|
|
253
|
+
try {
|
|
254
|
+
val subFiles = assetManager.list(assetFilePath)
|
|
255
|
+
if (subFiles != null && subFiles.isNotEmpty()) {
|
|
256
|
+
targetFile.mkdirs()
|
|
257
|
+
copyAssetRecursively(assetManager, assetFilePath, targetFile)
|
|
258
|
+
} else {
|
|
259
|
+
assetManager.open(assetFilePath).use { input ->
|
|
260
|
+
FileOutputStream(targetFile).use { output ->
|
|
261
|
+
input.copyTo(output)
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
} catch (e: Exception) {
|
|
266
|
+
try {
|
|
267
|
+
assetManager.open(assetFilePath).use { input ->
|
|
268
|
+
FileOutputStream(targetFile).use { output ->
|
|
269
|
+
input.copyTo(output)
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
} catch (fileException: Exception) {
|
|
273
|
+
throw IllegalArgumentException("Failed to copy asset: $assetFilePath", fileException)
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
private fun resolveFilePath(filePath: String): String {
|
|
280
|
+
Log.i(logTag, "resolveFilePath: filePath=$filePath")
|
|
281
|
+
val file = File(filePath)
|
|
282
|
+
if (!file.exists()) {
|
|
283
|
+
Log.e(logTag, "resolveFilePath: path does not exist: $filePath")
|
|
284
|
+
throw IllegalArgumentException("File path does not exist: $filePath")
|
|
285
|
+
}
|
|
286
|
+
if (!file.isDirectory) {
|
|
287
|
+
Log.e(logTag, "resolveFilePath: path is not a directory: $filePath")
|
|
288
|
+
throw IllegalArgumentException("Path is not a directory: $filePath")
|
|
289
|
+
}
|
|
290
|
+
val children = file.listFiles()?.map { it.name } ?: emptyList()
|
|
291
|
+
Log.i(logTag, "resolveFilePath: resolved=${file.absolutePath}, contents=$children")
|
|
292
|
+
return file.absolutePath
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
private fun resolveAutoPath(path: String): String {
|
|
296
|
+
return try {
|
|
297
|
+
resolveAssetPath(path)
|
|
298
|
+
} catch (e: Exception) {
|
|
299
|
+
try {
|
|
300
|
+
resolveFilePath(path)
|
|
301
|
+
} catch (fileException: Exception) {
|
|
302
|
+
throw IllegalArgumentException(
|
|
303
|
+
"Path not found as asset or file: $path. Asset error: ${e.message}, File error: ${fileException.message}",
|
|
304
|
+
e
|
|
305
|
+
)
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
private fun inferModelHint(folderName: String): String {
|
|
311
|
+
val name = folderName.lowercase()
|
|
312
|
+
val sttHints = listOf(
|
|
313
|
+
"zipformer",
|
|
314
|
+
"paraformer",
|
|
315
|
+
"nemo",
|
|
316
|
+
"parakeet",
|
|
317
|
+
"whisper",
|
|
318
|
+
"wenet",
|
|
319
|
+
"sensevoice",
|
|
320
|
+
"sense-voice",
|
|
321
|
+
"sense",
|
|
322
|
+
"funasr",
|
|
323
|
+
"transducer",
|
|
324
|
+
"ctc",
|
|
325
|
+
"asr"
|
|
326
|
+
)
|
|
327
|
+
val ttsHints = listOf(
|
|
328
|
+
"vits",
|
|
329
|
+
"piper",
|
|
330
|
+
"matcha",
|
|
331
|
+
"kokoro",
|
|
332
|
+
"kitten",
|
|
333
|
+
"pocket",
|
|
334
|
+
"zipvoice",
|
|
335
|
+
"melo",
|
|
336
|
+
"coqui",
|
|
337
|
+
"mms",
|
|
338
|
+
"tts"
|
|
339
|
+
)
|
|
340
|
+
|
|
341
|
+
val isStt = sttHints.any { name.contains(it) }
|
|
342
|
+
val isTts = ttsHints.any { name.contains(it) }
|
|
343
|
+
|
|
344
|
+
return when {
|
|
345
|
+
isStt && !isTts -> "stt"
|
|
346
|
+
isTts && !isStt -> "tts"
|
|
347
|
+
else -> "unknown"
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
}
|