cactus-react-native 1.5.0 → 1.10.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 (221) hide show
  1. package/Cactus.podspec +1 -1
  2. package/README.md +347 -241
  3. package/android/CMakeLists.txt +24 -5
  4. package/android/src/main/jniLibs/arm64-v8a/libcactus.a +0 -0
  5. package/android/src/main/jniLibs/arm64-v8a/libcurl.a +0 -0
  6. package/android/src/main/jniLibs/arm64-v8a/libmbedcrypto.a +0 -0
  7. package/android/src/main/jniLibs/arm64-v8a/libmbedtls.a +0 -0
  8. package/android/src/main/jniLibs/arm64-v8a/libmbedx509.a +0 -0
  9. package/cpp/HybridCactus.cpp +197 -117
  10. package/cpp/HybridCactus.hpp +18 -9
  11. package/cpp/cactus_ffi.h +66 -42
  12. package/ios/cactus.xcframework/ios-arm64/cactus.framework/Headers/cactus.h +0 -1
  13. package/ios/cactus.xcframework/ios-arm64/cactus.framework/Headers/cactus_cloud.h +48 -0
  14. package/ios/cactus.xcframework/ios-arm64/cactus.framework/Headers/cactus_ffi.h +66 -42
  15. package/ios/cactus.xcframework/ios-arm64/cactus.framework/Headers/cactus_utils.h +568 -135
  16. package/ios/cactus.xcframework/ios-arm64/cactus.framework/Headers/engine.h +148 -17
  17. package/ios/cactus.xcframework/ios-arm64/cactus.framework/Headers/graph.h +145 -36
  18. package/ios/cactus.xcframework/ios-arm64/cactus.framework/Headers/kernel.h +187 -6
  19. package/ios/cactus.xcframework/ios-arm64/cactus.framework/Headers/kernel_utils.h +49 -149
  20. package/ios/cactus.xcframework/ios-arm64/cactus.framework/Info.plist +0 -0
  21. package/ios/cactus.xcframework/ios-arm64/cactus.framework/cactus +0 -0
  22. package/ios/cactus.xcframework/ios-arm64-simulator/cactus.framework/Headers/cactus.h +0 -1
  23. package/ios/cactus.xcframework/ios-arm64-simulator/cactus.framework/Headers/cactus_cloud.h +48 -0
  24. package/ios/cactus.xcframework/ios-arm64-simulator/cactus.framework/Headers/cactus_ffi.h +66 -42
  25. package/ios/cactus.xcframework/ios-arm64-simulator/cactus.framework/Headers/cactus_utils.h +568 -135
  26. package/ios/cactus.xcframework/ios-arm64-simulator/cactus.framework/Headers/engine.h +148 -17
  27. package/ios/cactus.xcframework/ios-arm64-simulator/cactus.framework/Headers/graph.h +145 -36
  28. package/ios/cactus.xcframework/ios-arm64-simulator/cactus.framework/Headers/kernel.h +187 -6
  29. package/ios/cactus.xcframework/ios-arm64-simulator/cactus.framework/Headers/kernel_utils.h +49 -149
  30. package/ios/cactus.xcframework/ios-arm64-simulator/cactus.framework/Info.plist +0 -0
  31. package/ios/cactus.xcframework/ios-arm64-simulator/cactus.framework/_CodeSignature/CodeResources +1 -1
  32. package/ios/cactus.xcframework/ios-arm64-simulator/cactus.framework/cactus +0 -0
  33. package/lib/module/classes/CactusLM.js +16 -49
  34. package/lib/module/classes/CactusLM.js.map +1 -1
  35. package/lib/module/classes/CactusSTT.js +41 -75
  36. package/lib/module/classes/CactusSTT.js.map +1 -1
  37. package/lib/module/classes/CactusVAD.js +95 -0
  38. package/lib/module/classes/CactusVAD.js.map +1 -0
  39. package/lib/module/hooks/useCactusLM.js +10 -11
  40. package/lib/module/hooks/useCactusLM.js.map +1 -1
  41. package/lib/module/hooks/useCactusSTT.js +23 -62
  42. package/lib/module/hooks/useCactusSTT.js.map +1 -1
  43. package/lib/module/hooks/useCactusVAD.js +171 -0
  44. package/lib/module/hooks/useCactusVAD.js.map +1 -0
  45. package/lib/module/index.js +2 -3
  46. package/lib/module/index.js.map +1 -1
  47. package/lib/module/modelRegistry.js +52 -0
  48. package/lib/module/modelRegistry.js.map +1 -0
  49. package/lib/module/native/Cactus.js +103 -23
  50. package/lib/module/native/Cactus.js.map +1 -1
  51. package/lib/module/native/CactusIndex.js.map +1 -1
  52. package/lib/module/native/index.js +0 -3
  53. package/lib/module/native/index.js.map +1 -1
  54. package/lib/module/types/CactusVAD.js +4 -0
  55. package/lib/module/{specs/CactusUtil.nitro.js.map → types/CactusVAD.js.map} +1 -1
  56. package/lib/typescript/src/classes/CactusLM.d.ts +5 -7
  57. package/lib/typescript/src/classes/CactusLM.d.ts.map +1 -1
  58. package/lib/typescript/src/classes/CactusSTT.d.ts +9 -12
  59. package/lib/typescript/src/classes/CactusSTT.d.ts.map +1 -1
  60. package/lib/typescript/src/classes/CactusVAD.d.ts +20 -0
  61. package/lib/typescript/src/classes/CactusVAD.d.ts.map +1 -0
  62. package/lib/typescript/src/hooks/useCactusLM.d.ts +2 -2
  63. package/lib/typescript/src/hooks/useCactusLM.d.ts.map +1 -1
  64. package/lib/typescript/src/hooks/useCactusSTT.d.ts +6 -8
  65. package/lib/typescript/src/hooks/useCactusSTT.d.ts.map +1 -1
  66. package/lib/typescript/src/hooks/useCactusVAD.d.ts +15 -0
  67. package/lib/typescript/src/hooks/useCactusVAD.d.ts.map +1 -0
  68. package/lib/typescript/src/index.d.ts +7 -5
  69. package/lib/typescript/src/index.d.ts.map +1 -1
  70. package/lib/typescript/src/modelRegistry.d.ts +5 -0
  71. package/lib/typescript/src/modelRegistry.d.ts.map +1 -0
  72. package/lib/typescript/src/native/Cactus.d.ts +13 -11
  73. package/lib/typescript/src/native/Cactus.d.ts.map +1 -1
  74. package/lib/typescript/src/native/CactusIndex.d.ts +2 -2
  75. package/lib/typescript/src/native/CactusIndex.d.ts.map +1 -1
  76. package/lib/typescript/src/native/index.d.ts +0 -3
  77. package/lib/typescript/src/native/index.d.ts.map +1 -1
  78. package/lib/typescript/src/specs/Cactus.nitro.d.ts +7 -6
  79. package/lib/typescript/src/specs/Cactus.nitro.d.ts.map +1 -1
  80. package/lib/typescript/src/types/CactusIndex.d.ts +2 -2
  81. package/lib/typescript/src/types/CactusIndex.d.ts.map +1 -1
  82. package/lib/typescript/src/types/CactusLM.d.ts +19 -11
  83. package/lib/typescript/src/types/CactusLM.d.ts.map +1 -1
  84. package/lib/typescript/src/types/CactusSTT.d.ts +44 -12
  85. package/lib/typescript/src/types/CactusSTT.d.ts.map +1 -1
  86. package/lib/typescript/src/types/CactusVAD.d.ts +34 -0
  87. package/lib/typescript/src/types/CactusVAD.d.ts.map +1 -0
  88. package/lib/typescript/src/types/common.d.ts +1 -6
  89. package/lib/typescript/src/types/common.d.ts.map +1 -1
  90. package/nitro.json +0 -11
  91. package/nitrogen/generated/android/cactus+autolinking.cmake +0 -5
  92. package/nitrogen/generated/android/cactusOnLoad.cpp +0 -30
  93. package/nitrogen/generated/ios/Cactus-Swift-Cxx-Bridge.cpp +0 -50
  94. package/nitrogen/generated/ios/Cactus-Swift-Cxx-Bridge.hpp +9 -147
  95. package/nitrogen/generated/ios/Cactus-Swift-Cxx-Umbrella.hpp +0 -13
  96. package/nitrogen/generated/ios/CactusAutolinking.mm +0 -26
  97. package/nitrogen/generated/ios/CactusAutolinking.swift +0 -30
  98. package/nitrogen/generated/shared/c++/HybridCactusSpec.cpp +5 -4
  99. package/nitrogen/generated/shared/c++/HybridCactusSpec.hpp +7 -6
  100. package/package.json +3 -3
  101. package/src/classes/CactusLM.ts +18 -65
  102. package/src/classes/CactusSTT.ts +52 -90
  103. package/src/classes/CactusVAD.ts +129 -0
  104. package/src/hooks/useCactusLM.ts +14 -17
  105. package/src/hooks/useCactusSTT.ts +47 -98
  106. package/src/hooks/useCactusVAD.ts +215 -0
  107. package/src/index.tsx +21 -12
  108. package/src/modelRegistry.ts +65 -0
  109. package/src/native/Cactus.ts +131 -38
  110. package/src/native/CactusIndex.ts +2 -2
  111. package/src/native/index.ts +0 -3
  112. package/src/specs/Cactus.nitro.ts +16 -7
  113. package/src/types/CactusIndex.ts +2 -2
  114. package/src/types/CactusLM.ts +19 -11
  115. package/src/types/CactusSTT.ts +47 -13
  116. package/src/types/CactusVAD.ts +39 -0
  117. package/src/types/common.ts +1 -6
  118. package/android/src/main/java/com/margelo/nitro/cactus/HybridCactusCrypto.kt +0 -46
  119. package/android/src/main/java/com/margelo/nitro/cactus/HybridCactusDeviceInfo.kt +0 -27
  120. package/android/src/main/jniLibs/arm64-v8a/libcactus_util.a +0 -0
  121. package/cpp/HybridCactusUtil.cpp +0 -47
  122. package/cpp/HybridCactusUtil.hpp +0 -27
  123. package/cpp/cactus_util.h +0 -25
  124. package/ios/HybridCactusCrypto.swift +0 -37
  125. package/ios/HybridCactusDeviceInfo.swift +0 -32
  126. package/ios/cactus.xcframework/ios-arm64/cactus.framework/Headers/cactus_telemetry.h +0 -656
  127. package/ios/cactus.xcframework/ios-arm64-simulator/cactus.framework/Headers/cactus_telemetry.h +0 -656
  128. package/ios/cactus_util.xcframework/Info.plist +0 -39
  129. package/ios/cactus_util.xcframework/ios-arm64/cactus_util.framework/Headers/cactus_util.h +0 -25
  130. package/ios/cactus_util.xcframework/ios-arm64/cactus_util.framework/Headers/database.h +0 -27
  131. package/ios/cactus_util.xcframework/ios-arm64/cactus_util.framework/Headers/ios_utils.h +0 -10
  132. package/ios/cactus_util.xcframework/ios-arm64/cactus_util.framework/Headers/logging.h +0 -25
  133. package/ios/cactus_util.xcframework/ios-arm64/cactus_util.framework/Info.plist +0 -0
  134. package/ios/cactus_util.xcframework/ios-arm64/cactus_util.framework/cactus_util +0 -0
  135. package/ios/cactus_util.xcframework/ios-arm64-simulator/cactus_util.framework/Headers/cactus_util.h +0 -25
  136. package/ios/cactus_util.xcframework/ios-arm64-simulator/cactus_util.framework/Headers/database.h +0 -27
  137. package/ios/cactus_util.xcframework/ios-arm64-simulator/cactus_util.framework/Headers/ios_utils.h +0 -10
  138. package/ios/cactus_util.xcframework/ios-arm64-simulator/cactus_util.framework/Headers/logging.h +0 -25
  139. package/ios/cactus_util.xcframework/ios-arm64-simulator/cactus_util.framework/Info.plist +0 -0
  140. package/ios/cactus_util.xcframework/ios-arm64-simulator/cactus_util.framework/_CodeSignature/CodeResources +0 -135
  141. package/ios/cactus_util.xcframework/ios-arm64-simulator/cactus_util.framework/cactus_util +0 -0
  142. package/lib/module/api/Database.js +0 -45
  143. package/lib/module/api/Database.js.map +0 -1
  144. package/lib/module/api/RemoteLM.js +0 -201
  145. package/lib/module/api/RemoteLM.js.map +0 -1
  146. package/lib/module/config/CactusConfig.js +0 -12
  147. package/lib/module/config/CactusConfig.js.map +0 -1
  148. package/lib/module/models.js +0 -336
  149. package/lib/module/models.js.map +0 -1
  150. package/lib/module/native/CactusCrypto.js +0 -10
  151. package/lib/module/native/CactusCrypto.js.map +0 -1
  152. package/lib/module/native/CactusDeviceInfo.js +0 -13
  153. package/lib/module/native/CactusDeviceInfo.js.map +0 -1
  154. package/lib/module/native/CactusUtil.js +0 -36
  155. package/lib/module/native/CactusUtil.js.map +0 -1
  156. package/lib/module/specs/CactusCrypto.nitro.js +0 -4
  157. package/lib/module/specs/CactusCrypto.nitro.js.map +0 -1
  158. package/lib/module/specs/CactusDeviceInfo.nitro.js +0 -4
  159. package/lib/module/specs/CactusDeviceInfo.nitro.js.map +0 -1
  160. package/lib/module/specs/CactusUtil.nitro.js +0 -4
  161. package/lib/module/telemetry/Telemetry.js +0 -154
  162. package/lib/module/telemetry/Telemetry.js.map +0 -1
  163. package/lib/typescript/src/api/Database.d.ts +0 -12
  164. package/lib/typescript/src/api/Database.d.ts.map +0 -1
  165. package/lib/typescript/src/api/RemoteLM.d.ts +0 -14
  166. package/lib/typescript/src/api/RemoteLM.d.ts.map +0 -1
  167. package/lib/typescript/src/config/CactusConfig.d.ts +0 -7
  168. package/lib/typescript/src/config/CactusConfig.d.ts.map +0 -1
  169. package/lib/typescript/src/models.d.ts +0 -6
  170. package/lib/typescript/src/models.d.ts.map +0 -1
  171. package/lib/typescript/src/native/CactusCrypto.d.ts +0 -5
  172. package/lib/typescript/src/native/CactusCrypto.d.ts.map +0 -1
  173. package/lib/typescript/src/native/CactusDeviceInfo.d.ts +0 -7
  174. package/lib/typescript/src/native/CactusDeviceInfo.d.ts.map +0 -1
  175. package/lib/typescript/src/native/CactusUtil.d.ts +0 -6
  176. package/lib/typescript/src/native/CactusUtil.d.ts.map +0 -1
  177. package/lib/typescript/src/specs/CactusCrypto.nitro.d.ts +0 -8
  178. package/lib/typescript/src/specs/CactusCrypto.nitro.d.ts.map +0 -1
  179. package/lib/typescript/src/specs/CactusDeviceInfo.nitro.d.ts +0 -16
  180. package/lib/typescript/src/specs/CactusDeviceInfo.nitro.d.ts.map +0 -1
  181. package/lib/typescript/src/specs/CactusUtil.nitro.d.ts +0 -10
  182. package/lib/typescript/src/specs/CactusUtil.nitro.d.ts.map +0 -1
  183. package/lib/typescript/src/telemetry/Telemetry.d.ts +0 -34
  184. package/lib/typescript/src/telemetry/Telemetry.d.ts.map +0 -1
  185. package/nitrogen/generated/android/c++/JDeviceInfo.hpp +0 -74
  186. package/nitrogen/generated/android/c++/JHybridCactusCryptoSpec.cpp +0 -65
  187. package/nitrogen/generated/android/c++/JHybridCactusCryptoSpec.hpp +0 -65
  188. package/nitrogen/generated/android/c++/JHybridCactusDeviceInfoSpec.cpp +0 -85
  189. package/nitrogen/generated/android/c++/JHybridCactusDeviceInfoSpec.hpp +0 -66
  190. package/nitrogen/generated/android/kotlin/com/margelo/nitro/cactus/DeviceInfo.kt +0 -50
  191. package/nitrogen/generated/android/kotlin/com/margelo/nitro/cactus/HybridCactusCryptoSpec.kt +0 -58
  192. package/nitrogen/generated/android/kotlin/com/margelo/nitro/cactus/HybridCactusDeviceInfoSpec.kt +0 -62
  193. package/nitrogen/generated/ios/c++/HybridCactusCryptoSpecSwift.cpp +0 -11
  194. package/nitrogen/generated/ios/c++/HybridCactusCryptoSpecSwift.hpp +0 -77
  195. package/nitrogen/generated/ios/c++/HybridCactusDeviceInfoSpecSwift.cpp +0 -11
  196. package/nitrogen/generated/ios/c++/HybridCactusDeviceInfoSpecSwift.hpp +0 -88
  197. package/nitrogen/generated/ios/swift/DeviceInfo.swift +0 -98
  198. package/nitrogen/generated/ios/swift/Func_void_DeviceInfo.swift +0 -47
  199. package/nitrogen/generated/ios/swift/Func_void_std__optional_std__string_.swift +0 -54
  200. package/nitrogen/generated/ios/swift/HybridCactusCryptoSpec.swift +0 -57
  201. package/nitrogen/generated/ios/swift/HybridCactusCryptoSpec_cxx.swift +0 -139
  202. package/nitrogen/generated/ios/swift/HybridCactusDeviceInfoSpec.swift +0 -58
  203. package/nitrogen/generated/ios/swift/HybridCactusDeviceInfoSpec_cxx.swift +0 -164
  204. package/nitrogen/generated/shared/c++/DeviceInfo.hpp +0 -92
  205. package/nitrogen/generated/shared/c++/HybridCactusCryptoSpec.cpp +0 -21
  206. package/nitrogen/generated/shared/c++/HybridCactusCryptoSpec.hpp +0 -63
  207. package/nitrogen/generated/shared/c++/HybridCactusDeviceInfoSpec.cpp +0 -22
  208. package/nitrogen/generated/shared/c++/HybridCactusDeviceInfoSpec.hpp +0 -67
  209. package/nitrogen/generated/shared/c++/HybridCactusUtilSpec.cpp +0 -23
  210. package/nitrogen/generated/shared/c++/HybridCactusUtilSpec.hpp +0 -66
  211. package/src/api/Database.ts +0 -55
  212. package/src/api/RemoteLM.ts +0 -273
  213. package/src/config/CactusConfig.ts +0 -11
  214. package/src/models.ts +0 -344
  215. package/src/native/CactusCrypto.ts +0 -11
  216. package/src/native/CactusDeviceInfo.ts +0 -18
  217. package/src/native/CactusUtil.ts +0 -43
  218. package/src/specs/CactusCrypto.nitro.ts +0 -6
  219. package/src/specs/CactusDeviceInfo.nitro.ts +0 -15
  220. package/src/specs/CactusUtil.nitro.ts +0 -8
  221. package/src/telemetry/Telemetry.ts +0 -236
@@ -6,22 +6,20 @@ import type {
6
6
  CactusSTTParams,
7
7
  CactusSTTAudioEmbedParams,
8
8
  CactusSTTAudioEmbedResult,
9
- CactusSTTStreamTranscribeInsertParams,
9
+ CactusSTTStreamTranscribeStartOptions,
10
10
  CactusSTTStreamTranscribeProcessParams,
11
11
  CactusSTTStreamTranscribeProcessResult,
12
- CactusSTTStreamTranscribeFinalizeResult,
12
+ CactusSTTStreamTranscribeStopResult,
13
+ CactusSTTDetectLanguageParams,
14
+ CactusSTTDetectLanguageResult,
13
15
  } from '../types/CactusSTT';
14
- import { Telemetry } from '../telemetry/Telemetry';
15
- import { CactusConfig } from '../config/CactusConfig';
16
- import { getErrorMessage } from '../utils/error';
17
- import models from '../models';
16
+ import { getRegistry } from '../modelRegistry';
18
17
  import type { CactusModel } from '../types/common';
19
18
 
20
19
  export class CactusSTT {
21
20
  private readonly cactus = new Cactus();
22
21
 
23
22
  private readonly model: string;
24
- private readonly contextSize: number;
25
23
  private readonly options: {
26
24
  quantization: 'int4' | 'int8';
27
25
  pro: boolean;
@@ -30,13 +28,11 @@ export class CactusSTT {
30
28
  private isDownloading = false;
31
29
  private isInitialized = false;
32
30
  private isGenerating = false;
33
-
34
- private isStreamTranscribeInitialized = false;
31
+ private isStreamTranscribing = false;
35
32
 
36
33
  private static readonly defaultModel = 'whisper-small';
37
- private static readonly defaultContextSize = 2048;
38
34
  private static readonly defaultOptions = {
39
- quantization: 'int4' as const,
35
+ quantization: 'int8' as const,
40
36
  pro: false,
41
37
  };
42
38
  private static readonly defaultPrompt =
@@ -46,11 +42,8 @@ export class CactusSTT {
46
42
  };
47
43
  private static readonly defaultEmbedBufferSize = 4096;
48
44
 
49
- constructor({ model, contextSize, options }: CactusSTTParams = {}) {
50
- Telemetry.init(CactusConfig.telemetryToken);
51
-
45
+ constructor({ model, options }: CactusSTTParams = {}) {
52
46
  this.model = model ?? CactusSTT.defaultModel;
53
- this.contextSize = contextSize ?? CactusSTT.defaultContextSize;
54
47
  this.options = {
55
48
  quantization:
56
49
  options?.quantization ?? CactusSTT.defaultOptions.quantization,
@@ -78,8 +71,9 @@ export class CactusSTT {
78
71
 
79
72
  this.isDownloading = true;
80
73
  try {
74
+ const registry = await getRegistry();
81
75
  const modelConfig =
82
- models[this.model]?.quantization[this.options.quantization];
76
+ registry[this.model]?.quantization[this.options.quantization];
83
77
  const url = this.options.pro ? modelConfig?.pro?.apple : modelConfig?.url;
84
78
 
85
79
  if (!url) {
@@ -114,14 +108,10 @@ export class CactusSTT {
114
108
  modelPath = await CactusFileSystem.getModelPath(this.getModelName());
115
109
  }
116
110
 
117
- try {
118
- await this.cactus.init(modelPath, this.contextSize);
119
- Telemetry.logInit(this.model, true);
120
- this.isInitialized = true;
121
- } catch (error) {
122
- Telemetry.logInit(this.model, false, getErrorMessage(error));
123
- throw error;
124
- }
111
+ const cacheDir = await CactusFileSystem.getCactusDirectory();
112
+ await this.cactus.setTelemetryEnvironment(cacheDir);
113
+ await this.cactus.init(modelPath);
114
+ this.isInitialized = true;
125
115
  }
126
116
 
127
117
  public async transcribe({
@@ -145,95 +135,67 @@ export class CactusSTT {
145
135
 
146
136
  this.isGenerating = true;
147
137
  try {
148
- const result = await this.cactus.transcribe(
138
+ return await this.cactus.transcribe(
149
139
  audio,
150
140
  prompt,
151
141
  responseBufferSize,
152
142
  options,
153
143
  onToken
154
144
  );
155
- Telemetry.logTranscribe(
156
- this.model,
157
- result.success,
158
- result.success ? undefined : result.response,
159
- result
160
- );
161
- return result;
162
- } catch (error) {
163
- Telemetry.logTranscribe(this.model, false, getErrorMessage(error));
164
- throw error;
165
145
  } finally {
166
146
  this.isGenerating = false;
167
147
  }
168
148
  }
169
149
 
170
- public async streamTranscribeInit(): Promise<void> {
171
- if (this.isStreamTranscribeInitialized) {
150
+ public async streamTranscribeStart(
151
+ options?: CactusSTTStreamTranscribeStartOptions
152
+ ): Promise<void> {
153
+ if (this.isStreamTranscribing) {
172
154
  return;
173
155
  }
174
156
 
175
157
  await this.init();
176
-
177
- try {
178
- await this.cactus.streamTranscribeInit();
179
- this.isStreamTranscribeInitialized = true;
180
- } catch (error) {
181
- throw error;
182
- }
158
+ await this.cactus.streamTranscribeStart(options);
159
+ this.isStreamTranscribing = true;
183
160
  }
184
161
 
185
- public async streamTranscribeInsert({
162
+ public async streamTranscribeProcess({
186
163
  audio,
187
- }: CactusSTTStreamTranscribeInsertParams): Promise<void> {
188
- if (!this.isStreamTranscribeInitialized) {
189
- throw new Error('CactusSTT stream transcribe is not initialized');
164
+ }: CactusSTTStreamTranscribeProcessParams): Promise<CactusSTTStreamTranscribeProcessResult> {
165
+ if (!this.isStreamTranscribing) {
166
+ throw new Error('CactusSTT stream transcribe is not started');
190
167
  }
191
168
 
192
- try {
193
- await this.cactus.streamTranscribeInsert(audio);
194
- } catch (error) {
195
- throw error;
196
- }
169
+ return this.cactus.streamTranscribeProcess(audio);
197
170
  }
198
171
 
199
- public async streamTranscribeProcess({
200
- options,
201
- }: CactusSTTStreamTranscribeProcessParams = {}): Promise<CactusSTTStreamTranscribeProcessResult> {
202
- if (!this.isStreamTranscribeInitialized) {
203
- throw new Error('CactusSTT stream transcribe is not initialized');
172
+ public async streamTranscribeStop(): Promise<CactusSTTStreamTranscribeStopResult> {
173
+ if (!this.isStreamTranscribing) {
174
+ throw new Error('CactusSTT stream transcribe is not started');
204
175
  }
205
176
 
206
177
  try {
207
- const result = await this.cactus.streamTranscribeProcess(options);
208
- return result;
209
- } catch (error) {
210
- throw error;
178
+ return await this.cactus.streamTranscribeStop();
179
+ } finally {
180
+ this.isStreamTranscribing = false;
211
181
  }
212
182
  }
213
183
 
214
- public async streamTranscribeFinalize(): Promise<CactusSTTStreamTranscribeFinalizeResult> {
215
- if (!this.isStreamTranscribeInitialized) {
216
- throw new Error('CactusSTT stream transcribe is not initialized');
217
- }
218
-
219
- try {
220
- const result = await this.cactus.streamTranscribeFinalize();
221
- return result;
222
- } catch (error) {
223
- throw error;
184
+ public async detectLanguage({
185
+ audio,
186
+ options,
187
+ }: CactusSTTDetectLanguageParams): Promise<CactusSTTDetectLanguageResult> {
188
+ if (this.isGenerating) {
189
+ throw new Error('CactusSTT is already generating');
224
190
  }
225
- }
226
191
 
227
- public async streamTranscribeDestroy(): Promise<void> {
228
- if (!this.isStreamTranscribeInitialized) {
229
- return;
230
- }
192
+ await this.init();
231
193
 
194
+ this.isGenerating = true;
232
195
  try {
233
- await this.cactus.streamTranscribeDestroy();
234
- this.isStreamTranscribeInitialized = false;
235
- } catch (error) {
236
- throw error;
196
+ return await this.cactus.detectLanguage(audio, options);
197
+ } finally {
198
+ this.isGenerating = false;
237
199
  }
238
200
  }
239
201
 
@@ -252,11 +214,7 @@ export class CactusSTT {
252
214
  audioPath,
253
215
  CactusSTT.defaultEmbedBufferSize
254
216
  );
255
- Telemetry.logAudioEmbedding(this.model, true);
256
217
  return { embedding };
257
- } catch (error) {
258
- Telemetry.logAudioEmbedding(this.model, false, getErrorMessage(error));
259
- throw error;
260
218
  } finally {
261
219
  this.isGenerating = false;
262
220
  }
@@ -277,21 +235,25 @@ export class CactusSTT {
277
235
  }
278
236
 
279
237
  await this.stop();
280
- await this.streamTranscribeDestroy();
281
- await this.cactus.destroy();
282
238
 
239
+ if (this.isStreamTranscribing) {
240
+ await this.cactus.streamTranscribeStop().catch(() => {});
241
+ this.isStreamTranscribing = false;
242
+ }
243
+
244
+ await this.cactus.destroy();
283
245
  this.isInitialized = false;
284
246
  }
285
247
 
286
- public getModels(): CactusModel[] {
287
- return Object.values(models).filter((model) => model.speech);
248
+ public async getModels(): Promise<CactusModel[]> {
249
+ return Object.values(await getRegistry());
288
250
  }
289
251
 
290
252
  private isModelPath(model: string): boolean {
291
253
  return model.startsWith('file://') || model.startsWith('/');
292
254
  }
293
255
 
294
- private getModelName(): string {
256
+ public getModelName(): string {
295
257
  return `${this.model}-${this.options.quantization}${this.options.pro ? '-pro' : ''}`;
296
258
  }
297
259
  }
@@ -0,0 +1,129 @@
1
+ import { Cactus, CactusFileSystem } from '../native';
2
+ import type {
3
+ CactusVADParams,
4
+ CactusVADDownloadParams,
5
+ CactusVADVadParams,
6
+ CactusVADResult,
7
+ } from '../types/CactusVAD';
8
+ import { getRegistry } from '../modelRegistry';
9
+ import type { CactusModel } from '../types/common';
10
+
11
+ export class CactusVAD {
12
+ private readonly cactus = new Cactus();
13
+
14
+ private readonly model: string;
15
+ private readonly options: {
16
+ quantization: 'int4' | 'int8';
17
+ pro: boolean;
18
+ };
19
+
20
+ private isDownloading = false;
21
+ private isInitialized = false;
22
+
23
+ private static readonly defaultModel = 'silero-vad';
24
+ private static readonly defaultOptions = {
25
+ quantization: 'int8' as const,
26
+ pro: false,
27
+ };
28
+
29
+ constructor({ model, options }: CactusVADParams = {}) {
30
+ this.model = model ?? CactusVAD.defaultModel;
31
+ this.options = {
32
+ quantization:
33
+ options?.quantization ?? CactusVAD.defaultOptions.quantization,
34
+ pro: options?.pro ?? CactusVAD.defaultOptions.pro,
35
+ };
36
+ }
37
+
38
+ public async download({
39
+ onProgress,
40
+ }: CactusVADDownloadParams = {}): Promise<void> {
41
+ if (this.isModelPath(this.model)) {
42
+ onProgress?.(1.0);
43
+ return;
44
+ }
45
+
46
+ if (this.isDownloading) {
47
+ throw new Error('CactusVAD is already downloading');
48
+ }
49
+
50
+ if (await CactusFileSystem.modelExists(this.getModelName())) {
51
+ console.log('Model already exists', this.getModelName());
52
+ onProgress?.(1.0);
53
+ return;
54
+ }
55
+
56
+ this.isDownloading = true;
57
+ try {
58
+ const registry = await getRegistry();
59
+ const modelConfig =
60
+ registry[this.model]?.quantization[this.options.quantization];
61
+ const url = this.options.pro ? modelConfig?.pro?.apple : modelConfig?.url;
62
+
63
+ if (!url) {
64
+ throw new Error(`Model ${this.model} with specified options not found`);
65
+ }
66
+
67
+ await CactusFileSystem.downloadModel(
68
+ this.getModelName(),
69
+ url,
70
+ onProgress
71
+ );
72
+ } finally {
73
+ this.isDownloading = false;
74
+ }
75
+ }
76
+
77
+ public async init(): Promise<void> {
78
+ if (this.isInitialized) {
79
+ return;
80
+ }
81
+
82
+ let modelPath: string;
83
+ if (this.isModelPath(this.model)) {
84
+ modelPath = this.model.replace('file://', '');
85
+ } else {
86
+ if (!(await CactusFileSystem.modelExists(this.getModelName()))) {
87
+ console.log('Model does not exist', this.getModelName());
88
+ throw new Error(
89
+ `Model "${this.model}" with options ${JSON.stringify(this.options)} is not downloaded`
90
+ );
91
+ }
92
+ modelPath = await CactusFileSystem.getModelPath(this.getModelName());
93
+ }
94
+
95
+ const cacheDir = await CactusFileSystem.getCactusDirectory();
96
+ await this.cactus.setTelemetryEnvironment(cacheDir);
97
+ await this.cactus.init(modelPath);
98
+ this.isInitialized = true;
99
+ }
100
+
101
+ public async vad({
102
+ audio,
103
+ options,
104
+ }: CactusVADVadParams): Promise<CactusVADResult> {
105
+ await this.init();
106
+ return this.cactus.vad(audio, options);
107
+ }
108
+
109
+ public async destroy(): Promise<void> {
110
+ if (!this.isInitialized) {
111
+ return;
112
+ }
113
+
114
+ await this.cactus.destroy();
115
+ this.isInitialized = false;
116
+ }
117
+
118
+ public async getModels(): Promise<CactusModel[]> {
119
+ return Object.values(await getRegistry());
120
+ }
121
+
122
+ private isModelPath(model: string): boolean {
123
+ return model.startsWith('file://') || model.startsWith('/');
124
+ }
125
+
126
+ public getModelName(): string {
127
+ return `${this.model}-${this.options.quantization}${this.options.pro ? '-pro' : ''}`;
128
+ }
129
+ }
@@ -20,15 +20,15 @@ import type { CactusModel } from '../types/common';
20
20
 
21
21
  export const useCactusLM = ({
22
22
  model = 'qwen3-0.6b',
23
- contextSize = 2048,
24
23
  corpusDir = undefined,
24
+ cacheIndex = false,
25
25
  options: modelOptions = {
26
26
  quantization: undefined,
27
27
  pro: false,
28
28
  },
29
29
  }: CactusLMParams = {}) => {
30
30
  const [cactusLM, setCactusLM] = useState(
31
- () => new CactusLM({ model, contextSize, corpusDir, options: modelOptions })
31
+ () => new CactusLM({ model, corpusDir, cacheIndex, options: modelOptions })
32
32
  );
33
33
 
34
34
  // State
@@ -48,17 +48,16 @@ export const useCactusLM = ({
48
48
  }, [model]);
49
49
 
50
50
  useEffect(() => {
51
- setCactusLM(
52
- new CactusLM({
53
- model,
54
- contextSize,
55
- corpusDir,
56
- options: {
57
- quantization: modelOptions.quantization,
58
- pro: modelOptions.pro,
59
- },
60
- })
61
- );
51
+ const newInstance = new CactusLM({
52
+ model,
53
+ corpusDir,
54
+ cacheIndex,
55
+ options: {
56
+ quantization: modelOptions.quantization,
57
+ pro: modelOptions.pro,
58
+ },
59
+ });
60
+ setCactusLM(newInstance);
62
61
 
63
62
  setCompletion('');
64
63
  setIsGenerating(false);
@@ -69,7 +68,7 @@ export const useCactusLM = ({
69
68
  setError(null);
70
69
 
71
70
  let mounted = true;
72
- CactusFileSystem.modelExists(model)
71
+ CactusFileSystem.modelExists(newInstance.getModelName())
73
72
  .then((exists) => {
74
73
  if (!mounted) {
75
74
  return;
@@ -89,8 +88,8 @@ export const useCactusLM = ({
89
88
  };
90
89
  }, [
91
90
  model,
92
- contextSize,
93
91
  corpusDir,
92
+ cacheIndex,
94
93
  modelOptions.quantization,
95
94
  modelOptions.pro,
96
95
  ]);
@@ -193,7 +192,6 @@ export const useCactusLM = ({
193
192
  options,
194
193
  tools,
195
194
  onToken,
196
- mode,
197
195
  }: CactusLMCompleteParams): Promise<CactusLMCompleteResult> => {
198
196
  if (isGenerating) {
199
197
  const message = 'CactusLM is already generating';
@@ -213,7 +211,6 @@ export const useCactusLM = ({
213
211
  setCompletion((prev) => prev + token);
214
212
  onToken?.(token);
215
213
  },
216
- mode,
217
214
  });
218
215
  } catch (e) {
219
216
  setError(getErrorMessage(e));