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.
Files changed (222) hide show
  1. package/LICENSE +1 -0
  2. package/README.md +89 -21
  3. package/SherpaOnnx.podspec +3 -0
  4. package/THIRD_PARTY_LICENSES/README.md +62 -0
  5. package/THIRD_PARTY_LICENSES/ffmpeg.txt +502 -0
  6. package/THIRD_PARTY_LICENSES/libarchive.txt +65 -0
  7. package/THIRD_PARTY_LICENSES/nvidia_omla.txt +181 -0
  8. package/THIRD_PARTY_LICENSES/onnxruntime.txt +21 -0
  9. package/THIRD_PARTY_LICENSES/opus.txt +44 -0
  10. package/THIRD_PARTY_LICENSES/sherpa-onnx.txt +201 -0
  11. package/THIRD_PARTY_LICENSES/shine.txt +482 -0
  12. package/THIRD_PARTY_LICENSES/zstd.txt +30 -0
  13. package/android/build.gradle +7 -3
  14. package/android/prebuilt-download.gradle +344 -152
  15. package/android/prebuilt-versions.gradle +1 -1
  16. package/android/src/main/assets/model_licenses/asr-models-license-status.csv +409 -0
  17. package/android/src/main/assets/model_licenses/qnn-asr-models-license-status.csv +695 -0
  18. package/android/src/main/assets/model_licenses/tts-models-license-status.csv +596 -0
  19. package/android/src/main/cpp/CMakeLists.txt +28 -10
  20. package/android/src/main/cpp/jni/archive/sherpa-onnx-archive-helper.cpp +2 -2
  21. package/android/src/main/cpp/jni/audio/sherpa-onnx-audio-convert-jni.cpp +268 -2
  22. package/android/src/main/cpp/jni/model_detect/sherpa-onnx-model-detect-tts.cpp +6 -2
  23. package/android/src/main/cpp/jni/model_detect/sherpa-onnx-validate-tts.cpp +4 -2
  24. package/android/src/main/java/com/sherpaonnx/SherpaOnnxArchiveHelper.kt +40 -10
  25. package/android/src/main/java/com/sherpaonnx/SherpaOnnxModule.kt +99 -0
  26. package/android/src/main/java/com/sherpaonnx/SherpaOnnxOnlineSttHelper.kt +4 -1
  27. package/android/src/main/java/com/sherpaonnx/SherpaOnnxTtsHelper.kt +112 -97
  28. package/ios/Resources/model_licenses/asr-models-license-status.csv +409 -0
  29. package/ios/Resources/model_licenses/qnn-asr-models-license-status.csv +695 -0
  30. package/ios/Resources/model_licenses/tts-models-license-status.csv +596 -0
  31. package/ios/SherpaOnnx+OnlineSTT.mm +2 -0
  32. package/ios/SherpaOnnx+PcmLiveStream.mm +2 -29
  33. package/ios/SherpaOnnx+TTS.mm +178 -20
  34. package/ios/SherpaOnnx.mm +54 -0
  35. package/ios/SherpaOnnxAudioConvert.h +10 -0
  36. package/ios/SherpaOnnxAudioConvert.mm +257 -1
  37. package/ios/archive/sherpa-onnx-archive-helper.h +3 -0
  38. package/ios/archive/sherpa-onnx-archive-helper.mm +39 -6
  39. package/ios/model_detect/sherpa-onnx-model-detect-tts.mm +13 -2
  40. package/ios/model_detect/sherpa-onnx-validate-tts.mm +4 -2
  41. package/ios/online_stt/sherpa-onnx-online-stt-wrapper.h +1 -0
  42. package/ios/online_stt/sherpa-onnx-online-stt-wrapper.mm +4 -0
  43. package/ios/tts/sherpa-onnx-tts-wrapper.h +37 -0
  44. package/ios/tts/sherpa-onnx-tts-wrapper.mm +149 -3
  45. package/lib/module/NativeSherpaOnnx.js.map +1 -1
  46. package/lib/module/audio/index.js +8 -0
  47. package/lib/module/audio/index.js.map +1 -1
  48. package/lib/module/download/ModelDownloadManager.js +10 -929
  49. package/lib/module/download/ModelDownloadManager.js.map +1 -1
  50. package/lib/module/download/activeModelOperations.js +26 -0
  51. package/lib/module/download/activeModelOperations.js.map +1 -0
  52. package/lib/module/download/background-downloader.d.js +2 -0
  53. package/lib/module/download/background-downloader.d.js.map +1 -0
  54. package/lib/module/download/bulkPurge.js +72 -0
  55. package/lib/module/download/bulkPurge.js.map +1 -0
  56. package/lib/module/download/checksumPrompt.js +19 -0
  57. package/lib/module/download/checksumPrompt.js.map +1 -0
  58. package/lib/module/download/constants.js +7 -0
  59. package/lib/module/download/constants.js.map +1 -0
  60. package/lib/module/download/downloadEvents.js +35 -0
  61. package/lib/module/download/downloadEvents.js.map +1 -0
  62. package/lib/module/download/downloadTask.js +385 -0
  63. package/lib/module/download/downloadTask.js.map +1 -0
  64. package/lib/module/download/ensureModel.js +89 -0
  65. package/lib/module/download/ensureModel.js.map +1 -0
  66. package/lib/module/download/index.js +4 -4
  67. package/lib/module/download/index.js.map +1 -1
  68. package/lib/module/download/localModels.js +151 -0
  69. package/lib/module/download/localModels.js.map +1 -0
  70. package/lib/module/download/modelExtraction.js +174 -0
  71. package/lib/module/download/modelExtraction.js.map +1 -0
  72. package/lib/module/download/paths.js +98 -0
  73. package/lib/module/download/paths.js.map +1 -0
  74. package/lib/module/download/postDownloadProcessing.js +206 -0
  75. package/lib/module/download/postDownloadProcessing.js.map +1 -0
  76. package/lib/module/download/protectedModelKeys.js +31 -0
  77. package/lib/module/download/protectedModelKeys.js.map +1 -0
  78. package/lib/module/download/registry.js +267 -0
  79. package/lib/module/download/registry.js.map +1 -0
  80. package/lib/module/download/retry.js +59 -0
  81. package/lib/module/download/retry.js.map +1 -0
  82. package/lib/module/download/types.js +17 -0
  83. package/lib/module/download/types.js.map +1 -0
  84. package/lib/module/download/validation.js +101 -5
  85. package/lib/module/download/validation.js.map +1 -1
  86. package/lib/module/{download → extraction}/extractTarBz2.js +3 -1
  87. package/lib/module/extraction/extractTarBz2.js.map +1 -0
  88. package/lib/module/{download → extraction}/extractTarZst.js +3 -1
  89. package/lib/module/extraction/extractTarZst.js.map +1 -0
  90. package/lib/module/extraction/index.js +3 -4
  91. package/lib/module/extraction/index.js.map +1 -1
  92. package/lib/module/index.js +1 -1
  93. package/lib/module/index.js.map +1 -1
  94. package/lib/module/licenses.js +63 -0
  95. package/lib/module/licenses.js.map +1 -0
  96. package/lib/module/stt/index.js +16 -2
  97. package/lib/module/stt/index.js.map +1 -1
  98. package/lib/module/stt/streaming.js +2 -0
  99. package/lib/module/stt/streaming.js.map +1 -1
  100. package/lib/module/stt/streamingTypes.js.map +1 -1
  101. package/lib/module/stt/types.js.map +1 -1
  102. package/lib/module/tts/index.js +20 -2
  103. package/lib/module/tts/index.js.map +1 -1
  104. package/lib/module/tts/streaming.js +4 -0
  105. package/lib/module/tts/streaming.js.map +1 -1
  106. package/lib/module/tts/types.js.map +1 -1
  107. package/lib/module/utils.js +16 -1
  108. package/lib/module/utils.js.map +1 -1
  109. package/lib/typescript/src/NativeSherpaOnnx.d.ts +33 -5
  110. package/lib/typescript/src/NativeSherpaOnnx.d.ts.map +1 -1
  111. package/lib/typescript/src/audio/index.d.ts +10 -0
  112. package/lib/typescript/src/audio/index.d.ts.map +1 -1
  113. package/lib/typescript/src/download/ModelDownloadManager.d.ts +10 -108
  114. package/lib/typescript/src/download/ModelDownloadManager.d.ts.map +1 -1
  115. package/lib/typescript/src/download/activeModelOperations.d.ts +6 -0
  116. package/lib/typescript/src/download/activeModelOperations.d.ts.map +1 -0
  117. package/lib/typescript/src/download/bulkPurge.d.ts +14 -0
  118. package/lib/typescript/src/download/bulkPurge.d.ts.map +1 -0
  119. package/lib/typescript/src/download/checksumPrompt.d.ts +3 -0
  120. package/lib/typescript/src/download/checksumPrompt.d.ts.map +1 -0
  121. package/lib/typescript/src/download/constants.d.ts +5 -0
  122. package/lib/typescript/src/download/constants.d.ts.map +1 -0
  123. package/lib/typescript/src/download/downloadEvents.d.ts +6 -0
  124. package/lib/typescript/src/download/downloadEvents.d.ts.map +1 -0
  125. package/lib/typescript/src/download/downloadTask.d.ts +20 -0
  126. package/lib/typescript/src/download/downloadTask.d.ts.map +1 -0
  127. package/lib/typescript/src/download/ensureModel.d.ts +26 -0
  128. package/lib/typescript/src/download/ensureModel.d.ts.map +1 -0
  129. package/lib/typescript/src/download/index.d.ts +7 -7
  130. package/lib/typescript/src/download/index.d.ts.map +1 -1
  131. package/lib/typescript/src/download/localModels.d.ts +15 -0
  132. package/lib/typescript/src/download/localModels.d.ts.map +1 -0
  133. package/lib/typescript/src/download/modelExtraction.d.ts +36 -0
  134. package/lib/typescript/src/download/modelExtraction.d.ts.map +1 -0
  135. package/lib/typescript/src/download/paths.d.ts +28 -0
  136. package/lib/typescript/src/download/paths.d.ts.map +1 -0
  137. package/lib/typescript/src/download/postDownloadProcessing.d.ts +19 -0
  138. package/lib/typescript/src/download/postDownloadProcessing.d.ts.map +1 -0
  139. package/lib/typescript/src/download/protectedModelKeys.d.ts +6 -0
  140. package/lib/typescript/src/download/protectedModelKeys.d.ts.map +1 -0
  141. package/lib/typescript/src/download/registry.d.ts +14 -0
  142. package/lib/typescript/src/download/registry.d.ts.map +1 -0
  143. package/lib/typescript/src/download/retry.d.ts +15 -0
  144. package/lib/typescript/src/download/retry.d.ts.map +1 -0
  145. package/lib/typescript/src/download/types.d.ts +96 -0
  146. package/lib/typescript/src/download/types.d.ts.map +1 -0
  147. package/lib/typescript/src/download/validation.d.ts +19 -0
  148. package/lib/typescript/src/download/validation.d.ts.map +1 -1
  149. package/lib/typescript/src/extraction/extractTarBz2.d.ts.map +1 -0
  150. package/lib/typescript/src/extraction/extractTarZst.d.ts.map +1 -0
  151. package/lib/typescript/src/index.d.ts +1 -0
  152. package/lib/typescript/src/index.d.ts.map +1 -1
  153. package/lib/typescript/src/licenses.d.ts +10 -0
  154. package/lib/typescript/src/licenses.d.ts.map +1 -0
  155. package/lib/typescript/src/stt/index.d.ts +4 -1
  156. package/lib/typescript/src/stt/index.d.ts.map +1 -1
  157. package/lib/typescript/src/stt/streaming.d.ts.map +1 -1
  158. package/lib/typescript/src/stt/streamingTypes.d.ts +5 -0
  159. package/lib/typescript/src/stt/streamingTypes.d.ts.map +1 -1
  160. package/lib/typescript/src/stt/types.d.ts +3 -1
  161. package/lib/typescript/src/stt/types.d.ts.map +1 -1
  162. package/lib/typescript/src/tts/index.d.ts +3 -1
  163. package/lib/typescript/src/tts/index.d.ts.map +1 -1
  164. package/lib/typescript/src/tts/streaming.d.ts.map +1 -1
  165. package/lib/typescript/src/tts/types.d.ts +6 -5
  166. package/lib/typescript/src/tts/types.d.ts.map +1 -1
  167. package/lib/typescript/src/utils.d.ts +5 -0
  168. package/lib/typescript/src/utils.d.ts.map +1 -1
  169. package/package.json +6 -1
  170. package/scripts/{check-model-csvs.sh → ci/check-model-csvs.sh} +9 -2
  171. package/scripts/ci/collect_all_sherpa_model_streams.sh +101 -0
  172. package/scripts/ci/collect_one_sherpa_release_stream.sh +189 -0
  173. package/scripts/ci/sherpa_asr_model_release_streams.json +21 -0
  174. package/scripts/ci/sherpa_tts_model_release_streams.json +13 -0
  175. package/scripts/ci/update_model_license_csv.sh +765 -0
  176. package/scripts/setup-ios-framework.sh +14 -11
  177. package/scripts/update_commercial_use.js +73 -0
  178. package/src/NativeSherpaOnnx.ts +36 -5
  179. package/src/audio/index.ts +20 -0
  180. package/src/download/ModelDownloadManager.ts +55 -1343
  181. package/src/download/activeModelOperations.ts +38 -0
  182. package/src/download/background-downloader.d.ts +43 -0
  183. package/src/download/bulkPurge.ts +102 -0
  184. package/src/download/checksumPrompt.ts +25 -0
  185. package/src/download/constants.ts +5 -0
  186. package/src/download/downloadEvents.ts +55 -0
  187. package/src/download/downloadTask.ts +497 -0
  188. package/src/download/ensureModel.ts +124 -0
  189. package/src/download/index.ts +19 -4
  190. package/src/download/localModels.ts +234 -0
  191. package/src/download/modelExtraction.ts +244 -0
  192. package/src/download/paths.ts +134 -0
  193. package/src/download/postDownloadProcessing.ts +292 -0
  194. package/src/download/protectedModelKeys.ts +30 -0
  195. package/src/download/registry.ts +404 -0
  196. package/src/download/retry.ts +76 -0
  197. package/src/download/types.ts +120 -0
  198. package/src/download/validation.ts +114 -8
  199. package/src/{download → extraction}/extractTarBz2.ts +3 -1
  200. package/src/{download → extraction}/extractTarZst.ts +3 -1
  201. package/src/extraction/index.ts +3 -7
  202. package/src/index.tsx +1 -0
  203. package/src/licenses.ts +100 -0
  204. package/src/stt/index.ts +20 -2
  205. package/src/stt/streaming.ts +3 -0
  206. package/src/stt/streamingTypes.ts +5 -0
  207. package/src/stt/types.ts +3 -1
  208. package/src/tts/index.ts +30 -2
  209. package/src/tts/streaming.ts +10 -0
  210. package/src/tts/types.ts +6 -5
  211. package/src/utils.ts +22 -1
  212. package/third_party/sherpa-onnx-prebuilt/ANDROID_RELEASE_TAG +1 -1
  213. package/third_party/sherpa-onnx-prebuilt/IOS_RELEASE_TAG +1 -1
  214. package/android/src/main/cpp/jni/tts/sherpa-onnx-tts-zipvoice-jni.cpp +0 -301
  215. package/android/src/main/java/com/sherpaonnx/ZipvoiceTtsWrapper.kt +0 -187
  216. package/lib/module/download/extractTarBz2.js.map +0 -1
  217. package/lib/module/download/extractTarZst.js.map +0 -1
  218. package/lib/typescript/src/download/extractTarBz2.d.ts.map +0 -1
  219. package/lib/typescript/src/download/extractTarZst.d.ts.map +0 -1
  220. package/scripts/check-qnn-support.sh +0 -78
  221. /package/lib/typescript/src/{download → extraction}/extractTarBz2.d.ts +0 -0
  222. /package/lib/typescript/src/{download → extraction}/extractTarZst.d.ts +0 -0
@@ -0,0 +1,151 @@
1
+ "use strict";
2
+
3
+ import { Platform } from 'react-native';
4
+ import { DocumentDirectoryPath, exists, readFile, readDir, unlink, writeFile } from '@dr.pogodin/react-native-fs';
5
+ import { getCachePath, getModelsBaseDir, getModelDir, getManifestPath, getNativeAssetExtractedModelDir, getReadyMarkerPath, getTarArchivePath, getOnnxPath } from "./paths.js";
6
+ import { resolveActualModelDir, removeDirectoryRecursive } from "./validation.js";
7
+ import { emitModelsListUpdated } from "./downloadEvents.js";
8
+ import { clearMemoryCacheForCategory } from "./registry.js";
9
+ export async function listDownloadedModelsByCategory(category) {
10
+ const baseDir = getModelsBaseDir(category);
11
+ const existsResult = await exists(baseDir);
12
+ if (!existsResult) return [];
13
+ const entries = await readDir(baseDir);
14
+ const models = [];
15
+ for (const entry of entries) {
16
+ if (!entry.isDirectory()) continue;
17
+ const manifestPath = getManifestPath(category, entry.name);
18
+ const manifestExists = await exists(manifestPath);
19
+ if (!manifestExists) continue;
20
+ try {
21
+ const raw = await readFile(manifestPath, 'utf8');
22
+ const manifest = JSON.parse(raw);
23
+ if (manifest.model) {
24
+ models.push(manifest.model);
25
+ }
26
+ } catch {
27
+ // ignore invalid manifest
28
+ }
29
+ }
30
+ return models;
31
+ }
32
+ export async function isModelDownloadedByCategory(category, id) {
33
+ const readyPath = getReadyMarkerPath(category, id);
34
+ return exists(readyPath);
35
+ }
36
+ export async function getLocalModelPathByCategory(category, id) {
37
+ const ready = await isModelDownloadedByCategory(category, id);
38
+ if (!ready) return null;
39
+ await updateModelLastUsed(category, id);
40
+ const installDir = getModelDir(category, id);
41
+ return resolveActualModelDir(installDir);
42
+ }
43
+ export async function updateModelLastUsed(category, id) {
44
+ const manifestPath = getManifestPath(category, id);
45
+ const existsResult = await exists(manifestPath);
46
+ if (!existsResult) return;
47
+ try {
48
+ const raw = await readFile(manifestPath, 'utf8');
49
+ const manifest = JSON.parse(raw);
50
+ manifest.lastUsed = new Date().toISOString();
51
+ await writeFile(manifestPath, JSON.stringify(manifest), 'utf8');
52
+ } catch (error) {
53
+ console.warn(`Failed to update lastUsed for ${category}:${id}:`, error);
54
+ }
55
+ }
56
+ export async function listDownloadedModelsWithMetadata(category) {
57
+ const baseDir = getModelsBaseDir(category);
58
+ const existsResult = await exists(baseDir);
59
+ if (!existsResult) return [];
60
+ const entries = await readDir(baseDir);
61
+ const modelsWithMetadata = [];
62
+ for (const entry of entries) {
63
+ if (!entry.isDirectory()) continue;
64
+ const manifestPath = getManifestPath(category, entry.name);
65
+ const manifestExists = await exists(manifestPath);
66
+ if (manifestExists) {
67
+ try {
68
+ const raw = await readFile(manifestPath, 'utf8');
69
+ const manifest = JSON.parse(raw);
70
+ if (manifest.model) {
71
+ modelsWithMetadata.push({
72
+ model: manifest.model,
73
+ downloadedAt: manifest.downloadedAt,
74
+ lastUsed: manifest.lastUsed ?? null,
75
+ sizeOnDisk: manifest.sizeOnDisk ?? entry.size,
76
+ status: 'ready'
77
+ });
78
+ }
79
+ } catch (error) {
80
+ console.warn(`Failed to read manifest for ${category}:${entry.name}:`, error);
81
+ }
82
+ }
83
+ }
84
+ return modelsWithMetadata;
85
+ }
86
+ export async function cleanupLeastRecentlyUsed(category, options) {
87
+ const modelsWithMetadata = await listDownloadedModelsWithMetadata(category);
88
+ if (modelsWithMetadata.length === 0) {
89
+ return [];
90
+ }
91
+ const keepCount = options?.keepCount ?? 1;
92
+ if (modelsWithMetadata.length <= keepCount) {
93
+ return [];
94
+ }
95
+ const sorted = modelsWithMetadata.sort((a, b) => {
96
+ const aTime = a.lastUsed ?? a.downloadedAt;
97
+ const bTime = b.lastUsed ?? b.downloadedAt;
98
+ return new Date(aTime).getTime() - new Date(bTime).getTime();
99
+ });
100
+ const deletedIds = [];
101
+ let bytesFreed = 0;
102
+ const targetBytes = options?.targetBytes ?? 0;
103
+ const maxToDelete = options?.maxModelsToDelete ?? sorted.length - keepCount;
104
+ for (let i = 0; i < sorted.length - keepCount && i < maxToDelete; i++) {
105
+ const item = sorted[i];
106
+ if (!item) continue;
107
+ try {
108
+ await deleteModelByCategory(category, item.model.id);
109
+ deletedIds.push(item.model.id);
110
+ bytesFreed += item.sizeOnDisk ?? 0;
111
+ console.log(`[LRU Cleanup] Deleted ${category}:${item.model.id} (freed ${(item.sizeOnDisk ?? 0) / 1024 / 1024} MB)`);
112
+ if (targetBytes > 0 && bytesFreed >= targetBytes) {
113
+ break;
114
+ }
115
+ } catch (error) {
116
+ console.warn(`[LRU Cleanup] Failed to delete ${category}:${item.model.id}:`, error);
117
+ }
118
+ }
119
+ return deletedIds;
120
+ }
121
+ export async function deleteModelByCategory(category, id) {
122
+ const modelDir = getModelDir(category, id);
123
+ const tarPath = getTarArchivePath(category, id);
124
+ const onnxPath = getOnnxPath(category, id);
125
+ if (await exists(modelDir)) {
126
+ await unlink(modelDir);
127
+ }
128
+ if (await exists(tarPath)) {
129
+ await unlink(tarPath);
130
+ }
131
+ if (await exists(onnxPath)) {
132
+ await unlink(onnxPath);
133
+ }
134
+ await removeDirectoryRecursive(getNativeAssetExtractedModelDir(id));
135
+ const list = await listDownloadedModelsByCategory(category);
136
+ emitModelsListUpdated(category, list);
137
+ }
138
+ export async function clearModelCacheByCategory(category) {
139
+ const cachePath = getCachePath(category);
140
+ if (await exists(cachePath)) {
141
+ await unlink(cachePath);
142
+ }
143
+ clearMemoryCacheForCategory(category);
144
+ }
145
+ export async function getDownloadStorageBase() {
146
+ if (Platform.OS === 'ios') {
147
+ return DocumentDirectoryPath;
148
+ }
149
+ return DocumentDirectoryPath;
150
+ }
151
+ //# sourceMappingURL=localModels.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["Platform","DocumentDirectoryPath","exists","readFile","readDir","unlink","writeFile","getCachePath","getModelsBaseDir","getModelDir","getManifestPath","getNativeAssetExtractedModelDir","getReadyMarkerPath","getTarArchivePath","getOnnxPath","resolveActualModelDir","removeDirectoryRecursive","emitModelsListUpdated","clearMemoryCacheForCategory","listDownloadedModelsByCategory","category","baseDir","existsResult","entries","models","entry","isDirectory","manifestPath","name","manifestExists","raw","manifest","JSON","parse","model","push","isModelDownloadedByCategory","id","readyPath","getLocalModelPathByCategory","ready","updateModelLastUsed","installDir","lastUsed","Date","toISOString","stringify","error","console","warn","listDownloadedModelsWithMetadata","modelsWithMetadata","downloadedAt","sizeOnDisk","size","status","cleanupLeastRecentlyUsed","options","length","keepCount","sorted","sort","a","b","aTime","bTime","getTime","deletedIds","bytesFreed","targetBytes","maxToDelete","maxModelsToDelete","i","item","deleteModelByCategory","log","modelDir","tarPath","onnxPath","list","clearModelCacheByCategory","cachePath","getDownloadStorageBase","OS"],"sourceRoot":"../../../src","sources":["download/localModels.ts"],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,174 @@
1
+ "use strict";
2
+
3
+ import { exists, readFile, readDir, mkdir, stat, unlink } from '@dr.pogodin/react-native-fs';
4
+ import { getModelsBaseDir, getModelDir, getArchivePath, getReadyMarkerPath, getExtractionStatePath, getNativeAssetExtractedModelDir } from "./paths.js";
5
+ import { runPostDownloadProcessing } from "./postDownloadProcessing.js";
6
+ import { getModelByIdByCategory } from "./registry.js";
7
+ import { listDownloadedModelsByCategory, getLocalModelPathByCategory } from "./localModels.js";
8
+ import { resolveActualModelDir, removeDirectoryRecursive } from "./validation.js";
9
+ const EXTRACTION_STATE_PREFIX = '.extraction-state-';
10
+ const EXTRACTION_STATE_SUFFIX = '.json';
11
+
12
+ /**
13
+ * Start extraction for a model: archive must already exist (e.g. after download or from PAD).
14
+ * Writes extraction state so that if the app crashes, extraction can be resumed via
15
+ * getIncompleteExtractions + resumeExtraction.
16
+ * Use signal to abort (pause) extraction.
17
+ */
18
+ export async function extractModelByCategory(category, id, opts) {
19
+ const model = await getModelByIdByCategory(category, id);
20
+ if (!model) {
21
+ throw new Error(`Unknown model id: ${id}`);
22
+ }
23
+ if (model.archiveExt !== 'tar.bz2') {
24
+ throw new Error(`Model ${id} is not a tar.bz2 archive; extraction is only for archived models.`);
25
+ }
26
+ const downloadPath = getArchivePath(category, id, model.archiveExt);
27
+ const modelDir = getModelDir(category, id);
28
+ const statePath = getExtractionStatePath(category, id);
29
+ const archiveExists = await exists(downloadPath);
30
+ if (!archiveExists) {
31
+ throw new Error(`Archive not found at ${downloadPath}. Download the model first or ensure the archive is present.`);
32
+ }
33
+ try {
34
+ const archiveStat = await stat(downloadPath);
35
+ if (model.bytes > 0 && archiveStat.size < model.bytes) {
36
+ throw new Error(`Archive is truncated (${archiveStat.size}/${model.bytes} bytes). Re-download or replace the file.`);
37
+ }
38
+ } catch (statErr) {
39
+ if (statErr instanceof Error) throw statErr;
40
+ throw new Error('Failed to read archive size.');
41
+ }
42
+ await mkdir(getModelsBaseDir(category));
43
+ return runPostDownloadProcessing({
44
+ category,
45
+ id,
46
+ model,
47
+ downloadPath,
48
+ modelDir,
49
+ isArchive: true,
50
+ statePath,
51
+ signal: opts?.signal,
52
+ onChecksumIssue: opts?.onChecksumIssue,
53
+ deleteArchiveAfterExtract: opts?.deleteArchiveAfterExtract,
54
+ onProgress: opts?.onProgress,
55
+ getDownloadedList: () => listDownloadedModelsByCategory(category)
56
+ });
57
+ }
58
+
59
+ /**
60
+ * Returns models in the given category that have incomplete extractions (e.g. after app
61
+ * crash during extraction). Use with resumeExtraction to continue.
62
+ */
63
+ export async function getIncompleteExtractions(category) {
64
+ const baseDir = getModelsBaseDir(category);
65
+ const baseExists = await exists(baseDir);
66
+ if (!baseExists) return [];
67
+ let entries;
68
+ try {
69
+ entries = await readDir(baseDir);
70
+ } catch {
71
+ return [];
72
+ }
73
+ const results = [];
74
+ for (const entry of entries) {
75
+ const name = entry.name;
76
+ if (!name.startsWith(EXTRACTION_STATE_PREFIX) || !name.endsWith(EXTRACTION_STATE_SUFFIX)) {
77
+ continue;
78
+ }
79
+ const modelId = name.slice(EXTRACTION_STATE_PREFIX.length, name.length - EXTRACTION_STATE_SUFFIX.length);
80
+ const statePath = getExtractionStatePath(category, modelId);
81
+ let state;
82
+ try {
83
+ const raw = await readFile(statePath, 'utf8');
84
+ state = JSON.parse(raw);
85
+ } catch {
86
+ continue;
87
+ }
88
+ const readyPath = getReadyMarkerPath(category, modelId);
89
+ if (await exists(readyPath)) continue;
90
+ try {
91
+ const archiveExists = await exists(state.archivePath);
92
+ if (!archiveExists) continue;
93
+ const st = await stat(state.archivePath);
94
+ if (state.model.bytes > 0 && st.size != null && st.size < state.model.bytes) {
95
+ continue;
96
+ }
97
+ } catch {
98
+ continue;
99
+ }
100
+ results.push(state);
101
+ }
102
+ return results;
103
+ }
104
+
105
+ /**
106
+ * Resume an incomplete extraction (e.g. after app restart). Use getIncompleteExtractions
107
+ * to discover items to resume. Runs extraction from the start (archive is overwritten into
108
+ * model dir with force).
109
+ */
110
+ export async function resumeExtraction(category, id, opts) {
111
+ const statePath = getExtractionStatePath(category, id);
112
+ const stateExists = await exists(statePath);
113
+ if (!stateExists) {
114
+ return extractModelByCategory(category, id, opts);
115
+ }
116
+ let state;
117
+ try {
118
+ const raw = await readFile(statePath, 'utf8');
119
+ state = JSON.parse(raw);
120
+ } catch {
121
+ return extractModelByCategory(category, id, opts);
122
+ }
123
+ if (state.modelId !== id || state.category !== category) {
124
+ return extractModelByCategory(category, id, opts);
125
+ }
126
+ const readyPath = getReadyMarkerPath(category, id);
127
+ if (await exists(readyPath)) {
128
+ try {
129
+ await unlink(statePath);
130
+ } catch {
131
+ // non-fatal
132
+ }
133
+ const localPath = (await getLocalModelPathByCategory(category, id)) ?? (await resolveActualModelDir(state.modelDir));
134
+ return {
135
+ modelId: id,
136
+ localPath
137
+ };
138
+ }
139
+ return runPostDownloadProcessing({
140
+ category: state.category,
141
+ id: state.modelId,
142
+ model: state.model,
143
+ downloadPath: state.archivePath,
144
+ modelDir: state.modelDir,
145
+ isArchive: true,
146
+ statePath,
147
+ signal: opts?.signal,
148
+ onChecksumIssue: opts?.onChecksumIssue,
149
+ deleteArchiveAfterExtract: opts?.deleteArchiveAfterExtract,
150
+ onProgress: opts?.onProgress,
151
+ getDownloadedList: () => listDownloadedModelsByCategory(category)
152
+ });
153
+ }
154
+
155
+ /**
156
+ * Cancel/delete an incomplete extraction: removes extraction state and partial model dir.
157
+ * Does not delete the archive so the user can retry extraction later.
158
+ */
159
+ export async function deleteIncompleteExtraction(category, id) {
160
+ const statePath = getExtractionStatePath(category, id);
161
+ try {
162
+ if (await exists(statePath)) await unlink(statePath);
163
+ } catch {
164
+ // non-fatal
165
+ }
166
+ const modelDir = getModelDir(category, id);
167
+ try {
168
+ if (await exists(modelDir)) await unlink(modelDir);
169
+ } catch {
170
+ // non-fatal
171
+ }
172
+ await removeDirectoryRecursive(getNativeAssetExtractedModelDir(id));
173
+ }
174
+ //# sourceMappingURL=modelExtraction.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["exists","readFile","readDir","mkdir","stat","unlink","getModelsBaseDir","getModelDir","getArchivePath","getReadyMarkerPath","getExtractionStatePath","getNativeAssetExtractedModelDir","runPostDownloadProcessing","getModelByIdByCategory","listDownloadedModelsByCategory","getLocalModelPathByCategory","resolveActualModelDir","removeDirectoryRecursive","EXTRACTION_STATE_PREFIX","EXTRACTION_STATE_SUFFIX","extractModelByCategory","category","id","opts","model","Error","archiveExt","downloadPath","modelDir","statePath","archiveExists","archiveStat","bytes","size","statErr","isArchive","signal","onChecksumIssue","deleteArchiveAfterExtract","onProgress","getDownloadedList","getIncompleteExtractions","baseDir","baseExists","entries","results","entry","name","startsWith","endsWith","modelId","slice","length","state","raw","JSON","parse","readyPath","archivePath","st","push","resumeExtraction","stateExists","localPath","deleteIncompleteExtraction"],"sourceRoot":"../../../src","sources":["download/modelExtraction.ts"],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,98 @@
1
+ "use strict";
2
+
3
+ import { DocumentDirectoryPath } from '@dr.pogodin/react-native-fs';
4
+ import { ModelCategory } from "./types.js";
5
+ import { RELEASE_API_BASE } from "./constants.js";
6
+ export const CATEGORY_CONFIG = {
7
+ [ModelCategory.Tts]: {
8
+ tag: 'tts-models',
9
+ cacheFile: 'tts-models.json',
10
+ baseDir: `${DocumentDirectoryPath}/sherpa-onnx/models/tts`
11
+ },
12
+ [ModelCategory.Stt]: {
13
+ tag: 'asr-models',
14
+ cacheFile: 'asr-models.json',
15
+ baseDir: `${DocumentDirectoryPath}/sherpa-onnx/models/stt`
16
+ },
17
+ [ModelCategory.Vad]: {
18
+ tag: 'asr-models',
19
+ cacheFile: 'vad-models.json',
20
+ baseDir: `${DocumentDirectoryPath}/sherpa-onnx/models/vad`
21
+ },
22
+ [ModelCategory.Diarization]: {
23
+ tag: 'speaker-segmentation-models',
24
+ cacheFile: 'diarization-models.json',
25
+ baseDir: `${DocumentDirectoryPath}/sherpa-onnx/models/diarization`
26
+ },
27
+ [ModelCategory.Enhancement]: {
28
+ tag: 'speech-enhancement-models',
29
+ cacheFile: 'enhancement-models.json',
30
+ baseDir: `${DocumentDirectoryPath}/sherpa-onnx/models/enhancement`
31
+ },
32
+ [ModelCategory.Separation]: {
33
+ tag: 'source-separation-models',
34
+ cacheFile: 'separation-models.json',
35
+ baseDir: `${DocumentDirectoryPath}/sherpa-onnx/models/separation`
36
+ },
37
+ [ModelCategory.Qnn]: {
38
+ tag: 'asr-models-qnn-binary',
39
+ cacheFile: 'qnn-models.json',
40
+ baseDir: `${DocumentDirectoryPath}/sherpa-onnx/models/qnn`
41
+ }
42
+ };
43
+ export function getCacheDir() {
44
+ return `${DocumentDirectoryPath}/sherpa-onnx/cache`;
45
+ }
46
+ export function getCachePath(category) {
47
+ return `${getCacheDir()}/${CATEGORY_CONFIG[category].cacheFile}`;
48
+ }
49
+ export function getModelsBaseDir(category) {
50
+ return CATEGORY_CONFIG[category].baseDir;
51
+ }
52
+ export function getModelDir(category, modelId) {
53
+ return `${getModelsBaseDir(category)}/${modelId}`;
54
+ }
55
+ export function getArchiveFilename(modelId, archiveExt) {
56
+ return `${modelId}.${archiveExt}`;
57
+ }
58
+ export function getArchivePath(category, modelId, archiveExt) {
59
+ const filename = getArchiveFilename(modelId, archiveExt);
60
+ if (archiveExt === 'onnx') {
61
+ return `${getModelDir(category, modelId)}/${filename}`;
62
+ }
63
+ return `${getModelsBaseDir(category)}/${filename}`;
64
+ }
65
+ export function getTarArchivePath(category, modelId) {
66
+ return getArchivePath(category, modelId, 'tar.bz2');
67
+ }
68
+ export function getOnnxPath(category, modelId) {
69
+ return getArchivePath(category, modelId, 'onnx');
70
+ }
71
+ export function getReadyMarkerPath(category, modelId) {
72
+ return `${getModelDir(category, modelId)}/.ready`;
73
+ }
74
+ export function getManifestPath(category, modelId) {
75
+ return `${getModelDir(category, modelId)}/manifest.json`;
76
+ }
77
+ export function getDownloadStatePath(category, modelId) {
78
+ return `${getModelsBaseDir(category)}/.download-state-${modelId}.json`;
79
+ }
80
+
81
+ /** Path to extraction state file; used to detect and resume incomplete extractions after app restart. */
82
+ export function getExtractionStatePath(category, modelId) {
83
+ return `${getModelsBaseDir(category)}/.extraction-state-${modelId}.json`;
84
+ }
85
+
86
+ /**
87
+ * Directory where native `resolveAssetPath` materializes a bundled model folder
88
+ * (`DocumentDirectoryPath/models/{modelId}` — Android internal `files/models/...`).
89
+ * Separate from {@link getModelDir}. Remove on delete so empty dirs do not break detection.
90
+ */
91
+ export function getNativeAssetExtractedModelDir(modelId) {
92
+ const safeId = modelId.replace(/[/\\]/g, '');
93
+ return `${DocumentDirectoryPath}/models/${safeId}`.replace(/\/+/g, '/');
94
+ }
95
+ export function getReleaseUrl(category) {
96
+ return `${RELEASE_API_BASE}/${CATEGORY_CONFIG[category].tag}`;
97
+ }
98
+ //# sourceMappingURL=paths.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["DocumentDirectoryPath","ModelCategory","RELEASE_API_BASE","CATEGORY_CONFIG","Tts","tag","cacheFile","baseDir","Stt","Vad","Diarization","Enhancement","Separation","Qnn","getCacheDir","getCachePath","category","getModelsBaseDir","getModelDir","modelId","getArchiveFilename","archiveExt","getArchivePath","filename","getTarArchivePath","getOnnxPath","getReadyMarkerPath","getManifestPath","getDownloadStatePath","getExtractionStatePath","getNativeAssetExtractedModelDir","safeId","replace","getReleaseUrl"],"sourceRoot":"../../../src","sources":["download/paths.ts"],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,206 @@
1
+ "use strict";
2
+
3
+ import { exists, mkdir, writeFile, stat, unlink } from '@dr.pogodin/react-native-fs';
4
+ import { getReadyMarkerPath, getManifestPath, getExtractionStatePath } from "./paths.js";
5
+ import { validateChecksum, validateExtractedFiles, resolveActualModelDir } from "./validation.js";
6
+ import { extractTarBz2 } from "../extraction/extractTarBz2.js";
7
+ import { promptChecksumFallback } from "./checksumPrompt.js";
8
+ import { emitDownloadProgress, emitModelsListUpdated } from "./downloadEvents.js";
9
+ import { registerActivePostProcess, unregisterActivePostProcess } from "./activeModelOperations.js";
10
+ export async function runPostDownloadProcessing(options) {
11
+ const {
12
+ category,
13
+ id,
14
+ model,
15
+ downloadPath,
16
+ modelDir,
17
+ isArchive,
18
+ statePath,
19
+ signal,
20
+ onChecksumIssue,
21
+ deleteArchiveAfterExtract,
22
+ onProgress,
23
+ getDownloadedList
24
+ } = options;
25
+ registerActivePostProcess(category, id);
26
+ try {
27
+ return await runPostDownloadProcessingBody({
28
+ category,
29
+ id,
30
+ model,
31
+ downloadPath,
32
+ modelDir,
33
+ isArchive,
34
+ statePath,
35
+ signal,
36
+ onChecksumIssue,
37
+ deleteArchiveAfterExtract,
38
+ onProgress,
39
+ getDownloadedList
40
+ });
41
+ } finally {
42
+ unregisterActivePostProcess(category, id);
43
+ }
44
+ }
45
+ async function runPostDownloadProcessingBody(options) {
46
+ const {
47
+ category,
48
+ id,
49
+ model,
50
+ downloadPath,
51
+ modelDir,
52
+ isArchive,
53
+ statePath,
54
+ signal,
55
+ onChecksumIssue,
56
+ deleteArchiveAfterExtract,
57
+ onProgress,
58
+ getDownloadedList
59
+ } = options;
60
+ const isAborted = () => Boolean(signal?.aborted);
61
+ const abortError = new Error('Download aborted');
62
+ abortError.name = 'AbortError';
63
+ if (signal?.aborted) throw abortError;
64
+ let extractResult = null;
65
+ let extractedTotalBytes = 0;
66
+ if (isArchive) {
67
+ try {
68
+ const archiveStat = await stat(downloadPath);
69
+ if (model.bytes > 0 && archiveStat.size < model.bytes) {
70
+ console.warn(`[Download] Archive truncated for ${category}:${id}: ${archiveStat.size}/${model.bytes} bytes. Deleting for re-download.`);
71
+ await unlink(downloadPath);
72
+ throw new Error(`Archive file is truncated (${archiveStat.size}/${model.bytes} bytes). Please retry the download.`);
73
+ }
74
+ } catch (statErr) {
75
+ if (statErr instanceof Error && statErr.message.includes('truncated')) throw statErr;
76
+ }
77
+ await mkdir(modelDir);
78
+ const extractionStatePath = getExtractionStatePath(category, id);
79
+ try {
80
+ await writeFile(extractionStatePath, JSON.stringify({
81
+ modelId: id,
82
+ category,
83
+ phase: 'extracting',
84
+ startedAt: new Date().toISOString(),
85
+ archivePath: downloadPath,
86
+ modelDir,
87
+ model
88
+ }), 'utf8');
89
+ } catch {
90
+ // non-fatal; resume after crash may not be possible for this run
91
+ }
92
+ extractResult = await extractTarBz2(downloadPath, modelDir, true, evt => {
93
+ if (isAborted()) return;
94
+ if (evt.totalBytes > 0) extractedTotalBytes = evt.totalBytes;
95
+ const progress = {
96
+ bytesDownloaded: evt.bytes,
97
+ totalBytes: evt.totalBytes,
98
+ percent: evt.percent,
99
+ phase: 'extracting'
100
+ };
101
+ onProgress?.(progress);
102
+ emitDownloadProgress(category, id, progress);
103
+ }, signal);
104
+ }
105
+ if (model.sha256) {
106
+ const expectedSha = model.sha256.toLowerCase();
107
+ let issue = null;
108
+ if (isArchive) {
109
+ const nativeSha = extractResult?.sha256?.toLowerCase();
110
+ if (!nativeSha) {
111
+ issue = {
112
+ category,
113
+ id,
114
+ archivePath: downloadPath,
115
+ expected: model.sha256,
116
+ message: 'Native SHA-256 not available after extraction.',
117
+ reason: 'CHECKSUM_FAILED'
118
+ };
119
+ } else if (nativeSha !== expectedSha) {
120
+ issue = {
121
+ category,
122
+ id,
123
+ archivePath: downloadPath,
124
+ expected: model.sha256,
125
+ message: `Checksum mismatch: expected ${model.sha256}, got ${extractResult?.sha256}`,
126
+ reason: 'CHECKSUM_MISMATCH'
127
+ };
128
+ }
129
+ } else {
130
+ const checksumResult = await validateChecksum(downloadPath, expectedSha);
131
+ if (!checksumResult.success) {
132
+ issue = {
133
+ category,
134
+ id,
135
+ archivePath: downloadPath,
136
+ expected: model.sha256,
137
+ message: checksumResult.message ?? 'Checksum validation failed.',
138
+ reason: checksumResult.error === 'CHECKSUM_MISMATCH' ? 'CHECKSUM_MISMATCH' : 'CHECKSUM_FAILED'
139
+ };
140
+ }
141
+ }
142
+ if (issue) {
143
+ const keepFile = onChecksumIssue ? await onChecksumIssue(issue) : await promptChecksumFallback(issue);
144
+ if (!keepFile) {
145
+ if (await exists(modelDir)) await unlink(modelDir);
146
+ if (await exists(downloadPath)) await unlink(downloadPath);
147
+ throw new Error(`Checksum validation failed: ${issue.message}`);
148
+ }
149
+ }
150
+ }
151
+ if (signal?.aborted) throw abortError;
152
+ const filesValidation = await validateExtractedFiles(modelDir, category);
153
+ if (!filesValidation.success) {
154
+ await unlink(modelDir);
155
+ throw new Error(`Extracted files validation failed: ${filesValidation.message}`);
156
+ }
157
+ await writeFile(getReadyMarkerPath(category, id), 'ready', 'utf8');
158
+ const now = new Date().toISOString();
159
+ let sizeOnDisk;
160
+ if (isArchive && extractedTotalBytes > 0) {
161
+ sizeOnDisk = extractedTotalBytes;
162
+ } else if (!isArchive) {
163
+ try {
164
+ const s = await stat(downloadPath);
165
+ sizeOnDisk = s.size;
166
+ } catch {
167
+ // ignore
168
+ }
169
+ }
170
+ await writeFile(getManifestPath(category, id), JSON.stringify({
171
+ downloadedAt: now,
172
+ lastUsed: now,
173
+ model,
174
+ sizeOnDisk
175
+ }), 'utf8');
176
+ try {
177
+ if (await exists(statePath)) await unlink(statePath);
178
+ } catch {
179
+ // non-fatal
180
+ }
181
+ if (isArchive) {
182
+ try {
183
+ const extractionStatePath = getExtractionStatePath(category, id);
184
+ if (extractionStatePath !== statePath && (await exists(extractionStatePath))) {
185
+ await unlink(extractionStatePath);
186
+ }
187
+ } catch {
188
+ // non-fatal
189
+ }
190
+ }
191
+ if (isArchive && deleteArchiveAfterExtract !== false) {
192
+ try {
193
+ if (await exists(downloadPath)) await unlink(downloadPath);
194
+ } catch (err) {
195
+ console.warn(`[Download] Failed to delete archive after extraction for ${category}:${id}:`, err instanceof Error ? err.message : String(err));
196
+ }
197
+ }
198
+ const list = await getDownloadedList();
199
+ emitModelsListUpdated(category, list);
200
+ const resolvedPath = await resolveActualModelDir(modelDir);
201
+ return {
202
+ modelId: id,
203
+ localPath: resolvedPath
204
+ };
205
+ }
206
+ //# sourceMappingURL=postDownloadProcessing.js.map