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.
Files changed (175) hide show
  1. package/README.md +232 -236
  2. package/SherpaOnnx.podspec +68 -64
  3. package/android/build.gradle +182 -192
  4. package/android/codegen.gradle +57 -0
  5. package/android/prebuilt-download.gradle +428 -0
  6. package/android/prebuilt-versions.gradle +43 -0
  7. package/android/proguard-rules.pro +10 -0
  8. package/android/src/main/assets/testModels/add_mul_add.onnx +28 -0
  9. package/android/src/main/assets/testModels/nnapi_internal_uint8_support.onnx +0 -0
  10. package/android/src/main/assets/testModels/qnn_multi_ctx_embed.onnx +0 -0
  11. package/android/src/main/cpp/CMakeLists.txt +166 -129
  12. package/android/src/main/cpp/CMakePresets.json +54 -0
  13. package/android/src/main/cpp/crypto/sha256.cpp +174 -0
  14. package/android/src/main/cpp/crypto/sha256.h +16 -0
  15. package/android/src/main/cpp/jni/archive/sherpa-onnx-archive-helper.cpp +404 -0
  16. package/android/src/main/cpp/jni/archive/sherpa-onnx-archive-helper.h +56 -0
  17. package/android/src/main/cpp/jni/archive/sherpa-onnx-archive-jni.cpp +181 -0
  18. package/android/src/main/cpp/jni/audio/sherpa-onnx-audio-convert-jni.cpp +888 -0
  19. package/{ios → android/src/main/cpp/jni/model_detect}/sherpa-onnx-common.h +18 -18
  20. package/android/src/main/cpp/jni/model_detect/sherpa-onnx-detect-jni-common.cpp +86 -0
  21. package/android/src/main/cpp/jni/model_detect/sherpa-onnx-detect-jni-common.h +20 -0
  22. package/android/src/main/cpp/jni/model_detect/sherpa-onnx-model-detect-helper.cpp +423 -0
  23. package/android/src/main/cpp/jni/model_detect/sherpa-onnx-model-detect-helper.h +55 -0
  24. package/android/src/main/cpp/jni/model_detect/sherpa-onnx-model-detect-stt.cpp +399 -0
  25. package/android/src/main/cpp/jni/model_detect/sherpa-onnx-model-detect-tts.cpp +238 -0
  26. package/{ios → android/src/main/cpp/jni/model_detect}/sherpa-onnx-model-detect.h +122 -89
  27. package/android/src/main/cpp/jni/model_detect/sherpa-onnx-stt-wrapper.cpp +99 -0
  28. package/android/src/main/cpp/jni/model_detect/sherpa-onnx-stt-wrapper.h +16 -0
  29. package/android/src/main/cpp/jni/model_detect/sherpa-onnx-tts-wrapper.cpp +78 -0
  30. package/android/src/main/cpp/jni/model_detect/sherpa-onnx-tts-wrapper.h +16 -0
  31. package/android/src/main/cpp/jni/module/sherpa-onnx-module-jni.cpp +190 -0
  32. package/android/src/main/cpp/jni/tts/sherpa-onnx-tts-zipvoice-jni.cpp +301 -0
  33. package/android/src/main/java/com/sherpaonnx/SherpaOnnxArchiveHelper.kt +94 -0
  34. package/android/src/main/java/com/sherpaonnx/{SherpaOnnxCoreHelper.kt → SherpaOnnxAssetHelper.kt} +350 -236
  35. package/android/src/main/java/com/sherpaonnx/SherpaOnnxModule.kt +791 -483
  36. package/android/src/main/java/com/sherpaonnx/SherpaOnnxSttHelper.kt +699 -109
  37. package/android/src/main/java/com/sherpaonnx/SherpaOnnxTtsHelper.kt +1123 -668
  38. package/android/src/main/java/com/sherpaonnx/ZipvoiceTtsWrapper.kt +187 -0
  39. package/ios/SherpaOnnx+Assets.h +11 -0
  40. package/ios/SherpaOnnx+Assets.mm +325 -0
  41. package/ios/SherpaOnnx+STT.mm +455 -118
  42. package/ios/SherpaOnnx+TTS.mm +1101 -712
  43. package/ios/SherpaOnnx.h +17 -6
  44. package/ios/SherpaOnnx.mm +206 -311
  45. package/ios/SherpaOnnx.xcconfig +19 -19
  46. package/ios/SherpaOnnxCoreMLHelper.swift +24 -0
  47. package/ios/archive/sherpa-onnx-archive-helper.h +21 -0
  48. package/ios/archive/sherpa-onnx-archive-helper.mm +296 -0
  49. package/ios/libarchive_darwin_config.h +153 -0
  50. package/{android/src/main/cpp/jni → ios/model_detect}/sherpa-onnx-common.h +18 -18
  51. package/ios/model_detect/sherpa-onnx-model-detect-helper.h +49 -0
  52. package/ios/model_detect/sherpa-onnx-model-detect-helper.mm +210 -0
  53. package/ios/model_detect/sherpa-onnx-model-detect-stt.mm +344 -0
  54. package/ios/model_detect/sherpa-onnx-model-detect-tts.mm +201 -0
  55. package/{android/src/main/cpp/jni → ios/model_detect}/sherpa-onnx-model-detect.h +117 -89
  56. package/ios/scripts/patch-libarchive-includes.sh +61 -0
  57. package/ios/scripts/setup-ios-libarchive.sh +98 -0
  58. package/ios/stt/sherpa-onnx-stt-wrapper.h +129 -0
  59. package/ios/stt/sherpa-onnx-stt-wrapper.mm +523 -0
  60. package/ios/{sherpa-onnx-tts-wrapper.h → tts/sherpa-onnx-tts-wrapper.h} +90 -85
  61. package/ios/{sherpa-onnx-tts-wrapper.mm → tts/sherpa-onnx-tts-wrapper.mm} +376 -345
  62. package/lib/module/NativeSherpaOnnx.js +3 -0
  63. package/lib/module/NativeSherpaOnnx.js.map +1 -1
  64. package/lib/module/audio/index.js +22 -0
  65. package/lib/module/audio/index.js.map +1 -0
  66. package/lib/module/diarization/index.js +1 -1
  67. package/lib/module/diarization/index.js.map +1 -1
  68. package/lib/module/download/ModelDownloadManager.js +918 -0
  69. package/lib/module/download/ModelDownloadManager.js.map +1 -0
  70. package/lib/module/download/extractTarBz2.js +53 -0
  71. package/lib/module/download/extractTarBz2.js.map +1 -0
  72. package/lib/module/download/index.js +6 -0
  73. package/lib/module/download/index.js.map +1 -0
  74. package/lib/module/download/validation.js +178 -0
  75. package/lib/module/download/validation.js.map +1 -0
  76. package/lib/module/enhancement/index.js +1 -1
  77. package/lib/module/enhancement/index.js.map +1 -1
  78. package/lib/module/index.js +41 -3
  79. package/lib/module/index.js.map +1 -1
  80. package/lib/module/separation/index.js +1 -1
  81. package/lib/module/separation/index.js.map +1 -1
  82. package/lib/module/stt/index.js +127 -60
  83. package/lib/module/stt/index.js.map +1 -1
  84. package/lib/module/stt/sttModelLanguages.js +512 -0
  85. package/lib/module/stt/sttModelLanguages.js.map +1 -0
  86. package/lib/module/stt/types.js +53 -1
  87. package/lib/module/stt/types.js.map +1 -1
  88. package/lib/module/tts/index.js +216 -289
  89. package/lib/module/tts/index.js.map +1 -1
  90. package/lib/module/tts/types.js +86 -1
  91. package/lib/module/tts/types.js.map +1 -1
  92. package/lib/module/types.js.map +1 -1
  93. package/lib/module/utils.js +86 -73
  94. package/lib/module/utils.js.map +1 -1
  95. package/lib/module/vad/index.js +1 -1
  96. package/lib/module/vad/index.js.map +1 -1
  97. package/lib/typescript/src/NativeSherpaOnnx.d.ts +192 -38
  98. package/lib/typescript/src/NativeSherpaOnnx.d.ts.map +1 -1
  99. package/lib/typescript/src/audio/index.d.ts +13 -0
  100. package/lib/typescript/src/audio/index.d.ts.map +1 -0
  101. package/lib/typescript/src/diarization/index.d.ts +3 -2
  102. package/lib/typescript/src/diarization/index.d.ts.map +1 -1
  103. package/lib/typescript/src/download/ModelDownloadManager.d.ts +108 -0
  104. package/lib/typescript/src/download/ModelDownloadManager.d.ts.map +1 -0
  105. package/lib/typescript/src/download/extractTarBz2.d.ts +14 -0
  106. package/lib/typescript/src/download/extractTarBz2.d.ts.map +1 -0
  107. package/lib/typescript/src/download/index.d.ts +7 -0
  108. package/lib/typescript/src/download/index.d.ts.map +1 -0
  109. package/lib/typescript/src/download/validation.d.ts +57 -0
  110. package/lib/typescript/src/download/validation.d.ts.map +1 -0
  111. package/lib/typescript/src/enhancement/index.d.ts +3 -2
  112. package/lib/typescript/src/enhancement/index.d.ts.map +1 -1
  113. package/lib/typescript/src/index.d.ts +26 -2
  114. package/lib/typescript/src/index.d.ts.map +1 -1
  115. package/lib/typescript/src/separation/index.d.ts +3 -2
  116. package/lib/typescript/src/separation/index.d.ts.map +1 -1
  117. package/lib/typescript/src/stt/index.d.ts +31 -43
  118. package/lib/typescript/src/stt/index.d.ts.map +1 -1
  119. package/lib/typescript/src/stt/sttModelLanguages.d.ts +52 -0
  120. package/lib/typescript/src/stt/sttModelLanguages.d.ts.map +1 -0
  121. package/lib/typescript/src/stt/types.d.ts +196 -9
  122. package/lib/typescript/src/stt/types.d.ts.map +1 -1
  123. package/lib/typescript/src/tts/index.d.ts +25 -211
  124. package/lib/typescript/src/tts/index.d.ts.map +1 -1
  125. package/lib/typescript/src/tts/types.d.ts +148 -25
  126. package/lib/typescript/src/tts/types.d.ts.map +1 -1
  127. package/lib/typescript/src/types.d.ts +0 -32
  128. package/lib/typescript/src/types.d.ts.map +1 -1
  129. package/lib/typescript/src/utils.d.ts +28 -13
  130. package/lib/typescript/src/utils.d.ts.map +1 -1
  131. package/lib/typescript/src/vad/index.d.ts +3 -2
  132. package/lib/typescript/src/vad/index.d.ts.map +1 -1
  133. package/package.json +250 -222
  134. package/scripts/check-qnn-support.sh +78 -0
  135. package/scripts/setup-ios-framework.sh +379 -282
  136. package/src/NativeSherpaOnnx.ts +474 -251
  137. package/src/audio/index.ts +32 -0
  138. package/src/diarization/index.ts +4 -2
  139. package/src/download/ModelDownloadManager.ts +1325 -0
  140. package/src/download/extractTarBz2.ts +78 -0
  141. package/src/download/index.ts +43 -0
  142. package/src/download/validation.ts +279 -0
  143. package/src/enhancement/index.ts +4 -2
  144. package/src/index.tsx +78 -27
  145. package/src/separation/index.ts +4 -2
  146. package/src/stt/index.ts +249 -89
  147. package/src/stt/sttModelLanguages.ts +237 -0
  148. package/src/stt/types.ts +263 -9
  149. package/src/tts/index.ts +470 -458
  150. package/src/tts/types.ts +373 -218
  151. package/src/types.ts +0 -44
  152. package/src/utils.ts +145 -131
  153. package/src/vad/index.ts +4 -2
  154. package/third_party/ffmpeg_prebuilt/ANDROID_RELEASE_TAG +1 -0
  155. package/third_party/libarchive_prebuilt/ANDROID_RELEASE_TAG +1 -0
  156. package/third_party/libarchive_prebuilt/IOS_RELEASE_TAG +1 -0
  157. package/third_party/sherpa-onnx-prebuilt/ANDROID_RELEASE_TAG +1 -0
  158. package/third_party/sherpa-onnx-prebuilt/IOS_RELEASE_TAG +1 -0
  159. package/android/src/main/cpp/include/sherpa-onnx/c-api/c-api.h +0 -1918
  160. package/android/src/main/cpp/include/sherpa-onnx/c-api/cxx-api.h +0 -841
  161. package/android/src/main/cpp/jni/sherpa-onnx-model-detect.cpp +0 -541
  162. package/android/src/main/cpp/jni/sherpa-onnx-stt-jni.cpp +0 -336
  163. package/android/src/main/cpp/jni/sherpa-onnx-stt-wrapper.cpp +0 -222
  164. package/android/src/main/cpp/jni/sherpa-onnx-stt-wrapper.h +0 -68
  165. package/android/src/main/cpp/jni/sherpa-onnx-tts-jni.cpp +0 -823
  166. package/android/src/main/cpp/jni/sherpa-onnx-tts-wrapper.cpp +0 -387
  167. package/android/src/main/cpp/jni/sherpa-onnx-tts-wrapper.h +0 -147
  168. package/ios/Frameworks/sherpa_onnx.xcframework.zip +0 -0
  169. package/ios/include/sherpa-onnx/c-api/c-api.h +0 -1918
  170. package/ios/include/sherpa-onnx/c-api/cxx-api.h +0 -841
  171. package/ios/sherpa-onnx-model-detect.mm +0 -441
  172. package/ios/sherpa-onnx-stt-wrapper.h +0 -48
  173. package/ios/sherpa-onnx-stt-wrapper.mm +0 -201
  174. package/scripts/copy-headers.js +0 -184
  175. package/scripts/setup-assets.js +0 -323
package/ios/SherpaOnnx.h CHANGED
@@ -1,6 +1,17 @@
1
- #import <React/RCTEventEmitter.h>
2
- #import <SherpaOnnxSpec/SherpaOnnxSpec.h>
3
-
4
- @interface SherpaOnnx : RCTEventEmitter <NativeSherpaOnnxSpec>
5
-
6
- @end
1
+ #import <React/RCTEventEmitter.h>
2
+
3
+ // The codegen-generated header `SherpaOnnxSpec/SherpaOnnxSpec.h` is produced
4
+ // by React Native's codegen. In some build setups (CI or a fresh checkout)
5
+ // it may be missing until the iOS codegen step runs. Guard the import so
6
+ // the library can still compile (useful for IDEs and quick static checks).
7
+ #if __has_include(<SherpaOnnxSpec/SherpaOnnxSpec.h>)
8
+ #import <SherpaOnnxSpec/SherpaOnnxSpec.h>
9
+ #else
10
+ // Minimal fallback to allow compilation before codegen runs.
11
+ @protocol NativeSherpaOnnxSpec
12
+ @end
13
+ #endif
14
+
15
+ @interface SherpaOnnx : RCTEventEmitter <NativeSherpaOnnxSpec>
16
+
17
+ @end
package/ios/SherpaOnnx.mm CHANGED
@@ -1,311 +1,206 @@
1
- /*
2
- * Core SherpaOnnx module helpers (paths, assets, and event registration).
3
- * Feature-specific methods are implemented in SherpaOnnx+STT.mm and SherpaOnnx+TTS.mm.
4
- */
5
-
6
- #import "SherpaOnnx.h"
7
- #import <React/RCTLog.h>
8
-
9
- @implementation SherpaOnnx
10
-
11
- - (NSArray<NSString *> *)supportedEvents
12
- {
13
- return @[ @"ttsStreamChunk", @"ttsStreamEnd", @"ttsStreamError" ];
14
- }
15
-
16
- - (void)resolveModelPath:(NSDictionary *)config
17
- withResolver:(RCTPromiseResolveBlock)resolve
18
- withRejecter:(RCTPromiseRejectBlock)reject
19
- {
20
- NSString *type = config[@"type"] ?: @"auto";
21
- NSString *path = config[@"path"];
22
-
23
- if (!path) {
24
- reject(@"PATH_REQUIRED", @"Path is required", nil);
25
- return;
26
- }
27
-
28
- NSError *error = nil;
29
- NSString *resolvedPath = nil;
30
-
31
- if ([type isEqualToString:@"asset"]) {
32
- resolvedPath = [self resolveAssetPath:path error:&error];
33
- } else if ([type isEqualToString:@"file"]) {
34
- resolvedPath = [self resolveFilePath:path error:&error];
35
- } else if ([type isEqualToString:@"auto"]) {
36
- resolvedPath = [self resolveAutoPath:path error:&error];
37
- } else {
38
- NSString *errorMsg = [NSString stringWithFormat:@"Unknown path type: %@", type];
39
- reject(@"INVALID_TYPE", errorMsg, nil);
40
- return;
41
- }
42
-
43
- if (error) {
44
- reject(@"PATH_RESOLVE_ERROR", error.localizedDescription, error);
45
- return;
46
- }
47
-
48
- resolve(resolvedPath);
49
- }
50
-
51
- - (NSString *)resolveAssetPath:(NSString *)assetPath error:(NSError **)error
52
- {
53
- NSFileManager *fileManager = [NSFileManager defaultManager];
54
-
55
- // First, try to find directly in bundle (for folder references)
56
- NSString *bundlePath = [[NSBundle mainBundle] pathForResource:assetPath ofType:nil];
57
-
58
- if (bundlePath && [fileManager fileExistsAtPath:bundlePath]) {
59
- return bundlePath;
60
- }
61
-
62
- // Try with directory structure (for resources in subdirectories)
63
- NSArray *pathComponents = [assetPath componentsSeparatedByString:@"/"];
64
- if (pathComponents.count > 1) {
65
- NSString *directory = pathComponents[0];
66
- for (NSInteger i = 1; i < pathComponents.count - 1; i++) {
67
- directory = [directory stringByAppendingPathComponent:pathComponents[i]];
68
- }
69
- NSString *resourceName = pathComponents.lastObject;
70
- bundlePath = [[NSBundle mainBundle] pathForResource:resourceName ofType:nil inDirectory:directory];
71
-
72
- if (bundlePath && [fileManager fileExistsAtPath:bundlePath]) {
73
- return bundlePath;
74
- }
75
- }
76
-
77
- // If not found in bundle, try to copy from bundle to Documents
78
- NSString *documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
79
- NSString *targetDir = [documentsPath stringByAppendingPathComponent:@"models"];
80
- NSString *modelDir = [targetDir stringByAppendingPathComponent:[assetPath lastPathComponent]];
81
-
82
- // Check if already copied
83
- if ([fileManager fileExistsAtPath:modelDir]) {
84
- return modelDir;
85
- }
86
-
87
- // Try to find and copy from bundle resource path
88
- NSString *bundleResourcePath = [[NSBundle mainBundle] resourcePath];
89
- NSString *sourcePath = [bundleResourcePath stringByAppendingPathComponent:assetPath];
90
-
91
- if ([fileManager fileExistsAtPath:sourcePath]) {
92
- NSError *copyError = nil;
93
- [fileManager createDirectoryAtPath:targetDir withIntermediateDirectories:YES attributes:nil error:&copyError];
94
- if (copyError) {
95
- if (error) *error = copyError;
96
- return nil;
97
- }
98
-
99
- // Copy recursively if it's a directory
100
- BOOL isDirectory = NO;
101
- [fileManager fileExistsAtPath:sourcePath isDirectory:&isDirectory];
102
-
103
- if (isDirectory) {
104
- [fileManager copyItemAtPath:sourcePath toPath:modelDir error:&copyError];
105
- } else {
106
- [fileManager copyItemAtPath:sourcePath toPath:modelDir error:&copyError];
107
- }
108
-
109
- if (copyError) {
110
- if (error) *error = copyError;
111
- return nil;
112
- }
113
-
114
- return modelDir;
115
- }
116
-
117
- if (error) {
118
- *error = [NSError errorWithDomain:@"SherpaOnnx"
119
- code:1
120
- userInfo:@{NSLocalizedDescriptionKey: [NSString stringWithFormat:@"Asset path not found: %@", assetPath]}];
121
- }
122
- return nil;
123
- }
124
-
125
- - (NSString *)resolveFilePath:(NSString *)filePath error:(NSError **)error
126
- {
127
- NSFileManager *fileManager = [NSFileManager defaultManager];
128
- BOOL isDirectory = NO;
129
- BOOL exists = [fileManager fileExistsAtPath:filePath isDirectory:&isDirectory];
130
-
131
- if (!exists) {
132
- if (error) {
133
- *error = [NSError errorWithDomain:@"SherpaOnnx"
134
- code:2
135
- userInfo:@{NSLocalizedDescriptionKey: [NSString stringWithFormat:@"File path does not exist: %@", filePath]}];
136
- }
137
- return nil;
138
- }
139
-
140
- if (!isDirectory) {
141
- if (error) {
142
- *error = [NSError errorWithDomain:@"SherpaOnnx"
143
- code:3
144
- userInfo:@{NSLocalizedDescriptionKey: [NSString stringWithFormat:@"Path is not a directory: %@", filePath]}];
145
- }
146
- return nil;
147
- }
148
-
149
- return [filePath stringByStandardizingPath];
150
- }
151
-
152
- - (NSString *)resolveAutoPath:(NSString *)path error:(NSError **)error
153
- {
154
- // Try asset first
155
- NSError *assetError = nil;
156
- NSString *resolvedPath = [self resolveAssetPath:path error:&assetError];
157
-
158
- if (resolvedPath) {
159
- return resolvedPath;
160
- }
161
-
162
- // If asset fails, try file system
163
- NSError *fileError = nil;
164
- resolvedPath = [self resolveFilePath:path error:&fileError];
165
-
166
- if (resolvedPath) {
167
- return resolvedPath;
168
- }
169
-
170
- // Both failed
171
- if (error) {
172
- NSString *errorMessage = [NSString stringWithFormat:@"Path not found as asset or file: %@. Asset error: %@, File error: %@",
173
- path,
174
- assetError.localizedDescription ?: @"Unknown",
175
- fileError.localizedDescription ?: @"Unknown"];
176
- *error = [NSError errorWithDomain:@"SherpaOnnx"
177
- code:4
178
- userInfo:@{NSLocalizedDescriptionKey: errorMessage}];
179
- }
180
- return nil;
181
- }
182
-
183
- - (void)testSherpaInitWithResolver:(RCTPromiseResolveBlock)resolve
184
- withRejecter:(RCTPromiseRejectBlock)reject
185
- {
186
- @try {
187
- resolve(@"Sherpa ONNX loaded!");
188
- } @catch (NSException *exception) {
189
- NSString *errorMsg = [NSString stringWithFormat:@"Exception during test: %@", exception.reason];
190
- reject(@"TEST_ERROR", errorMsg, nil);
191
- }
192
- }
193
-
194
- - (void)listAssetModels:(RCTPromiseResolveBlock)resolve
195
- withRejecter:(RCTPromiseRejectBlock)reject
196
- {
197
- @try {
198
- NSFileManager *fileManager = [NSFileManager defaultManager];
199
- NSMutableArray<NSString *> *modelFolders = [NSMutableArray array];
200
-
201
- // Get the main bundle resource path
202
- NSString *bundleResourcePath = [[NSBundle mainBundle] resourcePath];
203
- NSString *modelsPath = [bundleResourcePath stringByAppendingPathComponent:@"models"];
204
-
205
- // Check if models directory exists
206
- BOOL isDirectory = NO;
207
- BOOL exists = [fileManager fileExistsAtPath:modelsPath isDirectory:&isDirectory];
208
-
209
- if (exists && isDirectory) {
210
- NSError *error = nil;
211
- NSArray<NSString *> *items = [fileManager contentsOfDirectoryAtPath:modelsPath error:&error];
212
-
213
- if (error) {
214
- RCTLogWarn(@"Could not list models directory: %@", error.localizedDescription);
215
- } else {
216
- // Filter to only include directories
217
- for (NSString *item in items) {
218
- // Skip hidden files (starting with .)
219
- if ([item hasPrefix:@"."]) {
220
- continue;
221
- }
222
-
223
- NSString *itemPath = [modelsPath stringByAppendingPathComponent:item];
224
- BOOL itemIsDirectory = NO;
225
- [fileManager fileExistsAtPath:itemPath isDirectory:&itemIsDirectory];
226
-
227
- if (itemIsDirectory) {
228
- [modelFolders addObject:item];
229
- }
230
- }
231
- }
232
- } else {
233
- RCTLogWarn(@"Models directory not found at: %@", modelsPath);
234
- }
235
-
236
- NSMutableArray<NSDictionary *> *result = [NSMutableArray array];
237
- for (NSString *folder in modelFolders) {
238
- NSString *hint = [self inferModelHint:folder];
239
- [result addObject:@{ @"folder": folder, @"hint": hint }];
240
- }
241
- resolve(result);
242
- } @catch (NSException *exception) {
243
- NSString *errorMsg = [NSString stringWithFormat:@"Exception listing asset models: %@", exception.reason];
244
- reject(@"LIST_ASSETS_ERROR", errorMsg, nil);
245
- }
246
- }
247
-
248
- // Infer a high-level model type hint from a folder name.
249
- - (NSString *)inferModelHint:(NSString *)folderName
250
- {
251
- NSString *name = [folderName lowercaseString];
252
- NSArray<NSString *> *sttHints = @[
253
- @"zipformer",
254
- @"paraformer",
255
- @"nemo",
256
- @"parakeet",
257
- @"whisper",
258
- @"wenet",
259
- @"sensevoice",
260
- @"sense-voice",
261
- @"sense",
262
- @"funasr",
263
- @"transducer",
264
- @"ctc",
265
- @"asr"
266
- ];
267
- NSArray<NSString *> *ttsHints = @[
268
- @"vits",
269
- @"piper",
270
- @"matcha",
271
- @"kokoro",
272
- @"kitten",
273
- @"zipvoice",
274
- @"melo",
275
- @"coqui",
276
- @"mms",
277
- @"tts"
278
- ];
279
-
280
- BOOL isStt = NO;
281
- for (NSString *hint in sttHints) {
282
- if ([name containsString:hint]) {
283
- isStt = YES;
284
- break;
285
- }
286
- }
287
-
288
- BOOL isTts = NO;
289
- for (NSString *hint in ttsHints) {
290
- if ([name containsString:hint]) {
291
- isTts = YES;
292
- break;
293
- }
294
- }
295
-
296
- if (isStt && isTts) {
297
- return @"unknown";
298
- }
299
-
300
- if (isStt) {
301
- return @"stt";
302
- }
303
-
304
- if (isTts) {
305
- return @"tts";
306
- }
307
-
308
- return @"unknown";
309
- }
310
-
311
- @end
1
+ /**
2
+ * SherpaOnnx.mm
3
+ *
4
+ * Purpose: Main React Native TurboModule for SherpaOnnx. Implements resolveModelPath (delegates to
5
+ * SherpaOnnx+Assets.mm), extractTarBz2/computeFileSha256 via sherpa-onnx-archive-helper, capability
6
+ * stubs (QNN/NNAPI/XNNPACK/CoreML), and event registration. Asset/path logic lives in
7
+ * SherpaOnnx+Assets.mm; STT/TTS in SherpaOnnx+STT.mm and SherpaOnnx+TTS.mm.
8
+ */
9
+
10
+ #import "SherpaOnnx.h"
11
+ #import "SherpaOnnx+Assets.h"
12
+ #import "sherpa-onnx-archive-helper.h"
13
+ #import <React/RCTLog.h>
14
+ #if __has_include("SherpaOnnx-Swift.h")
15
+ #import "SherpaOnnx-Swift.h"
16
+ #endif
17
+
18
+ @implementation SherpaOnnx
19
+
20
+ + (NSString *)moduleName
21
+ {
22
+ return @"SherpaOnnx";
23
+ }
24
+
25
+ - (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:
26
+ (const facebook::react::ObjCTurboModule::InitParams &)params
27
+ {
28
+ return std::make_shared<facebook::react::NativeSherpaOnnxSpecJSI>(params);
29
+ }
30
+
31
+ - (NSArray<NSString *> *)supportedEvents
32
+ {
33
+ return @[ @"ttsStreamChunk", @"ttsStreamEnd", @"ttsStreamError", @"extractTarBz2Progress" ];
34
+ }
35
+
36
+ - (void)resolveModelPath:(JS::NativeSherpaOnnx::SpecResolveModelPathConfig &)config
37
+ resolve:(RCTPromiseResolveBlock)resolve
38
+ reject:(RCTPromiseRejectBlock)reject
39
+ {
40
+ NSString *type = config.type() ?: @"auto";
41
+ NSString *path = config.path();
42
+
43
+ if (!path) {
44
+ reject(@"PATH_REQUIRED", @"Path is required", nil);
45
+ return;
46
+ }
47
+
48
+ NSError *error = nil;
49
+ NSString *resolvedPath = nil;
50
+
51
+ if ([type isEqualToString:@"asset"]) {
52
+ resolvedPath = [self resolveAssetPath:path error:&error];
53
+ } else if ([type isEqualToString:@"file"]) {
54
+ resolvedPath = [self resolveFilePath:path error:&error];
55
+ } else if ([type isEqualToString:@"auto"]) {
56
+ resolvedPath = [self resolveAutoPath:path error:&error];
57
+ } else {
58
+ NSString *errorMsg = [NSString stringWithFormat:@"Unknown path type: %@", type];
59
+ reject(@"INVALID_TYPE", errorMsg, nil);
60
+ return;
61
+ }
62
+
63
+ if (error) {
64
+ reject(@"PATH_RESOLVE_ERROR", error.localizedDescription, error);
65
+ return;
66
+ }
67
+
68
+ resolve(resolvedPath);
69
+ }
70
+
71
+ - (void)testSherpaInit:(RCTPromiseResolveBlock)resolve
72
+ reject:(RCTPromiseRejectBlock)reject
73
+ {
74
+ @try {
75
+ resolve(@"Sherpa ONNX loaded!");
76
+ } @catch (NSException *exception) {
77
+ NSString *errorMsg = [NSString stringWithFormat:@"Exception during test: %@", exception.reason];
78
+ reject(@"TEST_ERROR", errorMsg, nil);
79
+ }
80
+ }
81
+
82
+ // QNN (Qualcomm NPU) is Android-only; on iOS the build never has QNN support.
83
+ - (void)getQnnSupport:(NSString *)modelBase64
84
+ resolve:(RCTPromiseResolveBlock)resolve
85
+ reject:(RCTPromiseRejectBlock)reject
86
+ {
87
+ resolve(@{ @"providerCompiled": @NO, @"hasAccelerator": @NO, @"canInit": @NO });
88
+ }
89
+
90
+ // NNAPI is Android-only; on iOS we always return no support.
91
+ - (void)getNnapiSupport:(NSString *)modelBase64
92
+ resolve:(RCTPromiseResolveBlock)resolve
93
+ reject:(RCTPromiseRejectBlock)reject
94
+ {
95
+ resolve(@{ @"providerCompiled": @NO, @"hasAccelerator": @NO, @"canInit": @NO });
96
+ }
97
+
98
+ // XNNPACK support: stub on iOS (could be extended to check ORT providers and session init).
99
+ - (void)getXnnpackSupport:(NSString *)modelBase64
100
+ resolve:(RCTPromiseResolveBlock)resolve
101
+ reject:(RCTPromiseRejectBlock)reject
102
+ {
103
+ resolve(@{ @"providerCompiled": @NO, @"hasAccelerator": @NO, @"canInit": @NO });
104
+ }
105
+
106
+ // Core ML support (iOS): providerCompiled = true (Core ML on iOS 11+), hasAccelerator = Apple Neural Engine, canInit = session test (stub false unless ORT linked).
107
+ - (void)getCoreMlSupport:(NSString *)modelBase64
108
+ resolve:(RCTPromiseResolveBlock)resolve
109
+ reject:(RCTPromiseRejectBlock)reject
110
+ {
111
+ BOOL hasANE = NO;
112
+ #if __has_include("SherpaOnnx-Swift.h")
113
+ if ([SherpaOnnxCoreMLHelper respondsToSelector:@selector(hasAppleNeuralEngine)]) {
114
+ hasANE = [SherpaOnnxCoreMLHelper hasAppleNeuralEngine];
115
+ }
116
+ #endif
117
+ resolve(@{
118
+ @"providerCompiled": @YES, // Core ML always present on iOS 11+
119
+ @"hasAccelerator": hasANE ? @YES : @NO,
120
+ @"canInit": @NO, // Would require ORT session with CoreML EP; not implemented here
121
+ });
122
+ }
123
+
124
+ - (void)extractTarBz2:(NSString *)sourcePath
125
+ targetPath:(NSString *)targetPath
126
+ force:(BOOL)force
127
+ resolve:(RCTPromiseResolveBlock)resolve
128
+ reject:(RCTPromiseRejectBlock)reject
129
+ {
130
+ SherpaOnnxArchiveHelper *helper = [SherpaOnnxArchiveHelper new];
131
+ NSDictionary *result = [helper extractTarBz2:sourcePath
132
+ targetPath:targetPath
133
+ force:force
134
+ progress:^(long long bytes, long long totalBytes, double percent) {
135
+ [self sendEventWithName:@"extractTarBz2Progress"
136
+ body:@{ @"sourcePath": sourcePath,
137
+ @"bytes": @(bytes),
138
+ @"totalBytes": @(totalBytes),
139
+ @"percent": @(percent) }];
140
+ }];
141
+ resolve(result);
142
+ }
143
+
144
+ - (void)cancelExtractTarBz2:(RCTPromiseResolveBlock)resolve
145
+ reject:(RCTPromiseRejectBlock)reject
146
+ {
147
+ [SherpaOnnxArchiveHelper cancelExtractTarBz2];
148
+ resolve(nil);
149
+ }
150
+
151
+ - (void)computeFileSha256:(NSString *)filePath
152
+ resolve:(RCTPromiseResolveBlock)resolve
153
+ reject:(RCTPromiseRejectBlock)reject
154
+ {
155
+ SherpaOnnxArchiveHelper *helper = [SherpaOnnxArchiveHelper new];
156
+ NSError *error = nil;
157
+ NSString *digest = [helper computeFileSha256:filePath error:&error];
158
+ if (error || !digest) {
159
+ reject(@"CHECKSUM_ERROR", error.localizedDescription ?: @"Failed to compute SHA-256", error);
160
+ return;
161
+ }
162
+ resolve(digest);
163
+ }
164
+
165
+ - (void)getAssetPackPath:(NSString *)packName
166
+ resolve:(RCTPromiseResolveBlock)resolve
167
+ reject:(RCTPromiseRejectBlock)reject
168
+ {
169
+ // Play Asset Delivery is Android-only; on iOS there is no asset pack path.
170
+ resolve([NSNull null]);
171
+ }
172
+
173
+ - (void)convertAudioToFormat:(NSString *)inputPath
174
+ outputPath:(NSString *)outputPath
175
+ format:(NSString *)format
176
+ outputSampleRateHz:(NSNumber *)outputSampleRateHz
177
+ resolve:(RCTPromiseResolveBlock)resolve
178
+ reject:(RCTPromiseRejectBlock)reject
179
+ {
180
+ reject(@"UNSUPPORTED", @"convertAudioToFormat is not implemented on iOS", nil);
181
+ }
182
+
183
+ - (void)convertAudioToWav16k:(NSString *)inputPath
184
+ outputPath:(NSString *)outputPath
185
+ resolve:(RCTPromiseResolveBlock)resolve
186
+ reject:(RCTPromiseRejectBlock)reject
187
+ {
188
+ reject(@"UNSUPPORTED", @"convertAudioToWav16k is not implemented on iOS", nil);
189
+ }
190
+
191
+ - (void)getAvailableProviders:(RCTPromiseResolveBlock)resolve
192
+ reject:(RCTPromiseRejectBlock)reject
193
+ {
194
+ @try {
195
+ NSMutableArray<NSString *> *providers = [NSMutableArray arrayWithObject:@"CPUExecutionProvider"];
196
+ #if __has_include(<onnxruntime/coreml_provider_factory.h>)
197
+ [providers addObject:@"CoreMLExecutionProvider"];
198
+ #endif
199
+ resolve(providers);
200
+ } @catch (NSException *exception) {
201
+ NSString *errorMsg = [NSString stringWithFormat:@"Failed to get providers: %@", exception.reason];
202
+ reject(@"PROVIDERS_ERROR", errorMsg, nil);
203
+ }
204
+ }
205
+
206
+ @end
@@ -1,19 +1,19 @@
1
- // SherpaOnnx build configuration
2
- // This file handles the conditional linking of sherpa-onnx static library
3
- // based on the target platform (device vs simulator)
4
- //
5
- // SHERPA_ONNX_FRAMEWORK_PATH should be set by the Podfile or build system
6
- // to the absolute path of the sherpa_onnx.xcframework directory
7
-
8
- // Define the library directory based on SDK
9
- // For device builds (iphoneos)
10
- SHERPA_ONNX_LIB_DIR[sdk=iphoneos*] = $(SHERPA_ONNX_FRAMEWORK_PATH)/ios-arm64
11
- // For simulator builds (iphonesimulator)
12
- SHERPA_ONNX_LIB_DIR[sdk=iphonesimulator*] = $(SHERPA_ONNX_FRAMEWORK_PATH)/ios-arm64_x86_64-simulator
13
-
14
- // Add the library search path
15
- LIBRARY_SEARCH_PATHS = $(inherited) "$(SHERPA_ONNX_LIB_DIR)"
16
-
17
- // Force load the static library to ensure all symbols are included
18
- // This is necessary because the library symbols are called from Objective-C++
19
- OTHER_LDFLAGS = $(inherited) -force_load "$(SHERPA_ONNX_LIB_DIR)/libsherpa-onnx.a"
1
+ // SherpaOnnx build configuration
2
+ // This file handles the conditional linking of sherpa-onnx static library
3
+ // based on the target platform (device vs simulator)
4
+ //
5
+ // SHERPA_ONNX_FRAMEWORK_PATH should be set by the Podfile or build system
6
+ // to the absolute path of the sherpa_onnx.xcframework directory
7
+
8
+ // Define the library directory based on SDK
9
+ // For device builds (iphoneos)
10
+ SHERPA_ONNX_LIB_DIR[sdk=iphoneos*] = $(SHERPA_ONNX_FRAMEWORK_PATH)/ios-arm64
11
+ // For simulator builds (iphonesimulator)
12
+ SHERPA_ONNX_LIB_DIR[sdk=iphonesimulator*] = $(SHERPA_ONNX_FRAMEWORK_PATH)/ios-arm64_x86_64-simulator
13
+
14
+ // Add the library search path
15
+ LIBRARY_SEARCH_PATHS = $(inherited) "$(SHERPA_ONNX_LIB_DIR)"
16
+
17
+ // Force load the static library to ensure all symbols are included
18
+ // This is necessary because the library symbols are called from Objective-C++
19
+ OTHER_LDFLAGS = $(inherited) -force_load "$(SHERPA_ONNX_LIB_DIR)/libsherpa-onnx.a"
@@ -0,0 +1,24 @@
1
+ /*
2
+ * Core ML / Apple Neural Engine detection for getCoreMlSupport (AccelerationSupport).
3
+ * Used only on iOS.
4
+ */
5
+
6
+ import Foundation
7
+ import CoreML
8
+
9
+ @objc(SherpaOnnxCoreMLHelper)
10
+ public class SherpaOnnxCoreMLHelper: NSObject {
11
+
12
+ /// True if the device reports Apple Neural Engine in Core ML compute devices (iOS 17+).
13
+ @objc public static func hasAppleNeuralEngine() -> Bool {
14
+ if #available(iOS 17.0, *) {
15
+ for device in MLModel.availableComputeDevices {
16
+ let typeName = String(describing: type(of: device))
17
+ if typeName.contains("NeuralEngine") {
18
+ return true
19
+ }
20
+ }
21
+ }
22
+ return false
23
+ }
24
+ }
@@ -0,0 +1,21 @@
1
+ #import <Foundation/Foundation.h>
2
+
3
+ NS_ASSUME_NONNULL_BEGIN
4
+
5
+ @interface SherpaOnnxArchiveHelper : NSObject
6
+
7
+ typedef void (^SherpaOnnxArchiveProgressBlock)(long long bytes, long long totalBytes, double percent);
8
+
9
+ - (NSDictionary *)extractTarBz2:(NSString *)sourcePath
10
+ targetPath:(NSString *)targetPath
11
+ force:(BOOL)force
12
+ progress:(nullable SherpaOnnxArchiveProgressBlock)progress;
13
+
14
+ - (nullable NSString *)computeFileSha256:(NSString *)filePath
15
+ error:(NSError * _Nullable * _Nullable)error;
16
+
17
+ + (void)cancelExtractTarBz2;
18
+
19
+ @end
20
+
21
+ NS_ASSUME_NONNULL_END