cactus-react-native 1.2.1 → 1.5.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 (238) hide show
  1. package/README.md +765 -33
  2. package/android/CMakeLists.txt +4 -3
  3. package/android/src/main/java/com/margelo/nitro/cactus/HybridCactusFileSystem.kt +20 -1
  4. package/android/src/main/jniLibs/arm64-v8a/libcactus.a +0 -0
  5. package/android/src/main/jniLibs/arm64-v8a/libcactus_util.a +0 -0
  6. package/cpp/HybridCactus.cpp +231 -19
  7. package/cpp/HybridCactus.hpp +25 -3
  8. package/cpp/HybridCactusIndex.cpp +325 -0
  9. package/cpp/HybridCactusIndex.hpp +43 -0
  10. package/cpp/HybridCactusUtil.cpp +3 -3
  11. package/cpp/HybridCactusUtil.hpp +2 -1
  12. package/cpp/cactus_ffi.h +107 -2
  13. package/cpp/cactus_util.h +1 -1
  14. package/ios/HybridCactusFileSystem.swift +23 -2
  15. package/ios/cactus.xcframework/ios-arm64/cactus.framework/Headers/cactus.h +2 -0
  16. package/ios/cactus.xcframework/ios-arm64/cactus.framework/Headers/cactus_ffi.h +107 -2
  17. package/ios/cactus.xcframework/ios-arm64/cactus.framework/Headers/cactus_telemetry.h +656 -0
  18. package/ios/cactus.xcframework/ios-arm64/cactus.framework/Headers/{ffi_utils.h → cactus_utils.h} +145 -18
  19. package/ios/cactus.xcframework/ios-arm64/cactus.framework/Headers/engine.h +135 -7
  20. package/ios/cactus.xcframework/ios-arm64/cactus.framework/Headers/gemma_tools.h +549 -0
  21. package/ios/cactus.xcframework/ios-arm64/cactus.framework/Headers/graph.h +193 -26
  22. package/ios/cactus.xcframework/ios-arm64/cactus.framework/Headers/kernel.h +54 -195
  23. package/ios/cactus.xcframework/ios-arm64/cactus.framework/Headers/kernel_utils.h +399 -140
  24. package/ios/cactus.xcframework/ios-arm64/cactus.framework/Info.plist +0 -0
  25. package/ios/cactus.xcframework/ios-arm64/cactus.framework/cactus +0 -0
  26. package/ios/cactus.xcframework/ios-arm64-simulator/cactus.framework/Headers/cactus.h +2 -0
  27. package/ios/cactus.xcframework/ios-arm64-simulator/cactus.framework/Headers/cactus_ffi.h +107 -2
  28. package/ios/cactus.xcframework/ios-arm64-simulator/cactus.framework/Headers/cactus_telemetry.h +656 -0
  29. package/ios/cactus.xcframework/ios-arm64-simulator/cactus.framework/Headers/{ffi_utils.h → cactus_utils.h} +145 -18
  30. package/ios/cactus.xcframework/ios-arm64-simulator/cactus.framework/Headers/engine.h +135 -7
  31. package/ios/cactus.xcframework/ios-arm64-simulator/cactus.framework/Headers/gemma_tools.h +549 -0
  32. package/ios/cactus.xcframework/ios-arm64-simulator/cactus.framework/Headers/graph.h +193 -26
  33. package/ios/cactus.xcframework/ios-arm64-simulator/cactus.framework/Headers/kernel.h +54 -195
  34. package/ios/cactus.xcframework/ios-arm64-simulator/cactus.framework/Headers/kernel_utils.h +399 -140
  35. package/ios/cactus.xcframework/ios-arm64-simulator/cactus.framework/Info.plist +0 -0
  36. package/ios/cactus.xcframework/ios-arm64-simulator/cactus.framework/_CodeSignature/CodeResources +1 -1
  37. package/ios/cactus.xcframework/ios-arm64-simulator/cactus.framework/cactus +0 -0
  38. package/ios/cactus_util.xcframework/Info.plist +4 -4
  39. package/ios/cactus_util.xcframework/ios-arm64/cactus_util.framework/Headers/cactus_util.h +1 -1
  40. package/ios/cactus_util.xcframework/ios-arm64/cactus_util.framework/Headers/database.h +27 -0
  41. package/ios/cactus_util.xcframework/ios-arm64/cactus_util.framework/Info.plist +0 -0
  42. package/ios/cactus_util.xcframework/ios-arm64/cactus_util.framework/cactus_util +0 -0
  43. package/ios/cactus_util.xcframework/ios-arm64-simulator/cactus_util.framework/Headers/cactus_util.h +1 -1
  44. package/ios/cactus_util.xcframework/ios-arm64-simulator/cactus_util.framework/Headers/database.h +27 -0
  45. package/ios/cactus_util.xcframework/ios-arm64-simulator/cactus_util.framework/Info.plist +0 -0
  46. package/ios/cactus_util.xcframework/ios-arm64-simulator/cactus_util.framework/_CodeSignature/CodeResources +3 -3
  47. package/ios/cactus_util.xcframework/ios-arm64-simulator/cactus_util.framework/cactus_util +0 -0
  48. package/lib/module/api/Database.js +12 -95
  49. package/lib/module/api/Database.js.map +1 -1
  50. package/lib/module/classes/CactusIndex.js +45 -0
  51. package/lib/module/classes/CactusIndex.js.map +1 -0
  52. package/lib/module/classes/CactusLM.js +65 -17
  53. package/lib/module/classes/CactusLM.js.map +1 -1
  54. package/lib/module/classes/CactusSTT.js +104 -17
  55. package/lib/module/classes/CactusSTT.js.map +1 -1
  56. package/lib/module/config/CactusConfig.js +2 -0
  57. package/lib/module/config/CactusConfig.js.map +1 -1
  58. package/lib/module/constants/packageVersion.js +1 -1
  59. package/lib/module/hooks/useCactusIndex.js +175 -0
  60. package/lib/module/hooks/useCactusIndex.js.map +1 -0
  61. package/lib/module/hooks/useCactusLM.js +68 -7
  62. package/lib/module/hooks/useCactusLM.js.map +1 -1
  63. package/lib/module/hooks/useCactusSTT.js +102 -6
  64. package/lib/module/hooks/useCactusSTT.js.map +1 -1
  65. package/lib/module/index.js +2 -0
  66. package/lib/module/index.js.map +1 -1
  67. package/lib/module/models.js +336 -0
  68. package/lib/module/models.js.map +1 -0
  69. package/lib/module/native/Cactus.js +61 -13
  70. package/lib/module/native/Cactus.js.map +1 -1
  71. package/lib/module/native/CactusFileSystem.js +3 -0
  72. package/lib/module/native/CactusFileSystem.js.map +1 -1
  73. package/lib/module/native/CactusIndex.js +32 -0
  74. package/lib/module/native/CactusIndex.js.map +1 -0
  75. package/lib/module/native/CactusUtil.js +16 -3
  76. package/lib/module/native/CactusUtil.js.map +1 -1
  77. package/lib/module/native/index.js +1 -0
  78. package/lib/module/native/index.js.map +1 -1
  79. package/lib/module/specs/CactusIndex.nitro.js +4 -0
  80. package/lib/module/specs/CactusIndex.nitro.js.map +1 -0
  81. package/lib/module/telemetry/Telemetry.js +3 -1
  82. package/lib/module/telemetry/Telemetry.js.map +1 -1
  83. package/lib/module/types/CactusIndex.js +2 -0
  84. package/lib/module/types/{CactusModel.js.map → CactusIndex.js.map} +1 -1
  85. package/lib/module/types/CactusLM.js +2 -0
  86. package/lib/module/types/CactusSTT.js +2 -0
  87. package/lib/module/types/common.js +2 -0
  88. package/lib/module/types/{CactusSTTModel.js.map → common.js.map} +1 -1
  89. package/lib/typescript/src/api/Database.d.ts +4 -7
  90. package/lib/typescript/src/api/Database.d.ts.map +1 -1
  91. package/lib/typescript/src/classes/CactusIndex.d.ts +15 -0
  92. package/lib/typescript/src/classes/CactusIndex.d.ts.map +1 -0
  93. package/lib/typescript/src/classes/CactusLM.d.ts +12 -5
  94. package/lib/typescript/src/classes/CactusLM.d.ts.map +1 -1
  95. package/lib/typescript/src/classes/CactusSTT.d.ts +15 -5
  96. package/lib/typescript/src/classes/CactusSTT.d.ts.map +1 -1
  97. package/lib/typescript/src/config/CactusConfig.d.ts +1 -0
  98. package/lib/typescript/src/config/CactusConfig.d.ts.map +1 -1
  99. package/lib/typescript/src/constants/packageVersion.d.ts +1 -1
  100. package/lib/typescript/src/hooks/useCactusIndex.d.ts +14 -0
  101. package/lib/typescript/src/hooks/useCactusIndex.d.ts.map +1 -0
  102. package/lib/typescript/src/hooks/useCactusLM.d.ts +6 -4
  103. package/lib/typescript/src/hooks/useCactusLM.d.ts.map +1 -1
  104. package/lib/typescript/src/hooks/useCactusSTT.d.ts +13 -5
  105. package/lib/typescript/src/hooks/useCactusSTT.d.ts.map +1 -1
  106. package/lib/typescript/src/index.d.ts +6 -4
  107. package/lib/typescript/src/index.d.ts.map +1 -1
  108. package/lib/typescript/src/models.d.ts +6 -0
  109. package/lib/typescript/src/models.d.ts.map +1 -0
  110. package/lib/typescript/src/native/Cactus.d.ts +10 -3
  111. package/lib/typescript/src/native/Cactus.d.ts.map +1 -1
  112. package/lib/typescript/src/native/CactusFileSystem.d.ts +1 -0
  113. package/lib/typescript/src/native/CactusFileSystem.d.ts.map +1 -1
  114. package/lib/typescript/src/native/CactusIndex.d.ts +12 -0
  115. package/lib/typescript/src/native/CactusIndex.d.ts.map +1 -0
  116. package/lib/typescript/src/native/CactusUtil.d.ts.map +1 -1
  117. package/lib/typescript/src/native/index.d.ts +1 -0
  118. package/lib/typescript/src/native/index.d.ts.map +1 -1
  119. package/lib/typescript/src/specs/Cactus.nitro.d.ts +9 -2
  120. package/lib/typescript/src/specs/Cactus.nitro.d.ts.map +1 -1
  121. package/lib/typescript/src/specs/CactusFileSystem.nitro.d.ts +1 -0
  122. package/lib/typescript/src/specs/CactusFileSystem.nitro.d.ts.map +1 -1
  123. package/lib/typescript/src/specs/CactusIndex.nitro.d.ts +24 -0
  124. package/lib/typescript/src/specs/CactusIndex.nitro.d.ts.map +1 -0
  125. package/lib/typescript/src/specs/CactusUtil.nitro.d.ts +1 -1
  126. package/lib/typescript/src/specs/CactusUtil.nitro.d.ts.map +1 -1
  127. package/lib/typescript/src/types/CactusIndex.d.ts +34 -0
  128. package/lib/typescript/src/types/CactusIndex.d.ts.map +1 -0
  129. package/lib/typescript/src/types/CactusLM.d.ts +19 -0
  130. package/lib/typescript/src/types/CactusLM.d.ts.map +1 -1
  131. package/lib/typescript/src/types/CactusSTT.d.ts +21 -1
  132. package/lib/typescript/src/types/CactusSTT.d.ts.map +1 -1
  133. package/lib/typescript/src/types/common.d.ts +28 -0
  134. package/lib/typescript/src/types/common.d.ts.map +1 -0
  135. package/nitro.json +3 -0
  136. package/nitrogen/generated/android/c++/JDeviceInfo.hpp +1 -1
  137. package/nitrogen/generated/android/c++/JFunc_void_double.hpp +1 -1
  138. package/nitrogen/generated/android/c++/JHybridCactusCryptoSpec.cpp +1 -1
  139. package/nitrogen/generated/android/c++/JHybridCactusCryptoSpec.hpp +1 -1
  140. package/nitrogen/generated/android/c++/JHybridCactusDeviceInfoSpec.cpp +1 -1
  141. package/nitrogen/generated/android/c++/JHybridCactusDeviceInfoSpec.hpp +1 -1
  142. package/nitrogen/generated/android/c++/JHybridCactusFileSystemSpec.cpp +17 -1
  143. package/nitrogen/generated/android/c++/JHybridCactusFileSystemSpec.hpp +2 -1
  144. package/nitrogen/generated/android/c++/JHybridCactusImageSpec.cpp +1 -1
  145. package/nitrogen/generated/android/c++/JHybridCactusImageSpec.hpp +1 -1
  146. package/nitrogen/generated/android/cactus+autolinking.cmake +2 -1
  147. package/nitrogen/generated/android/cactus+autolinking.gradle +1 -1
  148. package/nitrogen/generated/android/cactusOnLoad.cpp +11 -1
  149. package/nitrogen/generated/android/cactusOnLoad.hpp +1 -1
  150. package/nitrogen/generated/android/kotlin/com/margelo/nitro/cactus/DeviceInfo.kt +1 -1
  151. package/nitrogen/generated/android/kotlin/com/margelo/nitro/cactus/Func_void_double.kt +1 -1
  152. package/nitrogen/generated/android/kotlin/com/margelo/nitro/cactus/HybridCactusCryptoSpec.kt +1 -1
  153. package/nitrogen/generated/android/kotlin/com/margelo/nitro/cactus/HybridCactusDeviceInfoSpec.kt +1 -1
  154. package/nitrogen/generated/android/kotlin/com/margelo/nitro/cactus/HybridCactusFileSystemSpec.kt +5 -1
  155. package/nitrogen/generated/android/kotlin/com/margelo/nitro/cactus/HybridCactusImageSpec.kt +1 -1
  156. package/nitrogen/generated/android/kotlin/com/margelo/nitro/cactus/cactusOnLoad.kt +1 -1
  157. package/nitrogen/generated/ios/Cactus+autolinking.rb +1 -1
  158. package/nitrogen/generated/ios/Cactus-Swift-Cxx-Bridge.cpp +1 -1
  159. package/nitrogen/generated/ios/Cactus-Swift-Cxx-Bridge.hpp +1 -1
  160. package/nitrogen/generated/ios/Cactus-Swift-Cxx-Umbrella.hpp +1 -1
  161. package/nitrogen/generated/ios/CactusAutolinking.mm +11 -1
  162. package/nitrogen/generated/ios/CactusAutolinking.swift +1 -1
  163. package/nitrogen/generated/ios/c++/HybridCactusCryptoSpecSwift.cpp +1 -1
  164. package/nitrogen/generated/ios/c++/HybridCactusCryptoSpecSwift.hpp +1 -1
  165. package/nitrogen/generated/ios/c++/HybridCactusDeviceInfoSpecSwift.cpp +1 -1
  166. package/nitrogen/generated/ios/c++/HybridCactusDeviceInfoSpecSwift.hpp +1 -1
  167. package/nitrogen/generated/ios/c++/HybridCactusFileSystemSpecSwift.cpp +1 -1
  168. package/nitrogen/generated/ios/c++/HybridCactusFileSystemSpecSwift.hpp +9 -1
  169. package/nitrogen/generated/ios/c++/HybridCactusImageSpecSwift.cpp +1 -1
  170. package/nitrogen/generated/ios/c++/HybridCactusImageSpecSwift.hpp +1 -1
  171. package/nitrogen/generated/ios/swift/DeviceInfo.swift +1 -1
  172. package/nitrogen/generated/ios/swift/Func_void.swift +1 -1
  173. package/nitrogen/generated/ios/swift/Func_void_DeviceInfo.swift +1 -1
  174. package/nitrogen/generated/ios/swift/Func_void_bool.swift +1 -1
  175. package/nitrogen/generated/ios/swift/Func_void_double.swift +1 -1
  176. package/nitrogen/generated/ios/swift/Func_void_std__exception_ptr.swift +1 -1
  177. package/nitrogen/generated/ios/swift/Func_void_std__optional_std__string_.swift +1 -1
  178. package/nitrogen/generated/ios/swift/Func_void_std__string.swift +1 -1
  179. package/nitrogen/generated/ios/swift/HybridCactusCryptoSpec.swift +1 -1
  180. package/nitrogen/generated/ios/swift/HybridCactusCryptoSpec_cxx.swift +1 -1
  181. package/nitrogen/generated/ios/swift/HybridCactusDeviceInfoSpec.swift +1 -1
  182. package/nitrogen/generated/ios/swift/HybridCactusDeviceInfoSpec_cxx.swift +1 -1
  183. package/nitrogen/generated/ios/swift/HybridCactusFileSystemSpec.swift +2 -1
  184. package/nitrogen/generated/ios/swift/HybridCactusFileSystemSpec_cxx.swift +20 -1
  185. package/nitrogen/generated/ios/swift/HybridCactusImageSpec.swift +1 -1
  186. package/nitrogen/generated/ios/swift/HybridCactusImageSpec_cxx.swift +1 -1
  187. package/nitrogen/generated/shared/c++/CactusIndexGetResult.hpp +84 -0
  188. package/nitrogen/generated/shared/c++/CactusIndexQueryResult.hpp +79 -0
  189. package/nitrogen/generated/shared/c++/DeviceInfo.hpp +1 -1
  190. package/nitrogen/generated/shared/c++/HybridCactusCryptoSpec.cpp +1 -1
  191. package/nitrogen/generated/shared/c++/HybridCactusCryptoSpec.hpp +1 -1
  192. package/nitrogen/generated/shared/c++/HybridCactusDeviceInfoSpec.cpp +1 -1
  193. package/nitrogen/generated/shared/c++/HybridCactusDeviceInfoSpec.hpp +1 -1
  194. package/nitrogen/generated/shared/c++/HybridCactusFileSystemSpec.cpp +2 -1
  195. package/nitrogen/generated/shared/c++/HybridCactusFileSystemSpec.hpp +2 -1
  196. package/nitrogen/generated/shared/c++/HybridCactusImageSpec.cpp +1 -1
  197. package/nitrogen/generated/shared/c++/HybridCactusImageSpec.hpp +1 -1
  198. package/nitrogen/generated/shared/c++/HybridCactusIndexSpec.cpp +27 -0
  199. package/nitrogen/generated/shared/c++/HybridCactusIndexSpec.hpp +76 -0
  200. package/nitrogen/generated/shared/c++/HybridCactusSpec.cpp +8 -1
  201. package/nitrogen/generated/shared/c++/HybridCactusSpec.hpp +11 -3
  202. package/nitrogen/generated/shared/c++/HybridCactusUtilSpec.cpp +1 -1
  203. package/nitrogen/generated/shared/c++/HybridCactusUtilSpec.hpp +2 -2
  204. package/package.json +2 -2
  205. package/src/api/Database.ts +14 -135
  206. package/src/classes/CactusIndex.ts +58 -0
  207. package/src/classes/CactusLM.ts +87 -19
  208. package/src/classes/CactusSTT.ts +134 -20
  209. package/src/config/CactusConfig.ts +3 -0
  210. package/src/constants/packageVersion.ts +1 -1
  211. package/src/hooks/useCactusIndex.ts +195 -0
  212. package/src/hooks/useCactusLM.ts +88 -8
  213. package/src/hooks/useCactusSTT.ts +119 -7
  214. package/src/index.tsx +22 -2
  215. package/src/models.ts +344 -0
  216. package/src/native/Cactus.ts +95 -13
  217. package/src/native/CactusFileSystem.ts +4 -0
  218. package/src/native/CactusIndex.ts +54 -0
  219. package/src/native/CactusUtil.ts +19 -3
  220. package/src/native/index.ts +1 -0
  221. package/src/specs/Cactus.nitro.ts +18 -2
  222. package/src/specs/CactusFileSystem.nitro.ts +2 -0
  223. package/src/specs/CactusIndex.nitro.ts +31 -0
  224. package/src/specs/CactusUtil.nitro.ts +1 -1
  225. package/src/telemetry/Telemetry.ts +1 -1
  226. package/src/types/CactusIndex.ts +40 -0
  227. package/src/types/CactusLM.ts +24 -0
  228. package/src/types/CactusSTT.ts +27 -1
  229. package/src/types/common.ts +28 -0
  230. package/android/src/main/jniLibs/arm64-v8a/libcactus_util.so +0 -0
  231. package/lib/module/types/CactusModel.js +0 -2
  232. package/lib/module/types/CactusSTTModel.js +0 -2
  233. package/lib/typescript/src/types/CactusModel.d.ts +0 -13
  234. package/lib/typescript/src/types/CactusModel.d.ts.map +0 -1
  235. package/lib/typescript/src/types/CactusSTTModel.d.ts +0 -8
  236. package/lib/typescript/src/types/CactusSTTModel.d.ts.map +0 -1
  237. package/src/types/CactusModel.ts +0 -15
  238. package/src/types/CactusSTTModel.ts +0 -10
@@ -3,18 +3,22 @@ import type {
3
3
  CactusLMDownloadParams,
4
4
  CactusLMCompleteParams,
5
5
  CactusLMCompleteResult,
6
+ CactusLMTokenizeParams,
7
+ CactusLMTokenizeResult,
8
+ CactusLMScoreWindowParams,
9
+ CactusLMScoreWindowResult,
6
10
  CactusLMEmbedParams,
7
11
  CactusLMEmbedResult,
8
12
  CactusLMImageEmbedParams,
9
13
  CactusLMImageEmbedResult,
10
14
  CactusLMParams,
11
15
  } from '../types/CactusLM';
12
- import type { CactusModel } from '../types/CactusModel';
13
16
  import { Telemetry } from '../telemetry/Telemetry';
14
17
  import { CactusConfig } from '../config/CactusConfig';
15
- import { Database } from '../api/Database';
16
18
  import { getErrorMessage } from '../utils/error';
17
19
  import { RemoteLM } from '../api/RemoteLM';
20
+ import models from '../models';
21
+ import type { CactusModel } from '../types/common';
18
22
 
19
23
  export class CactusLM {
20
24
  private readonly cactus = new Cactus();
@@ -22,45 +26,79 @@ export class CactusLM {
22
26
  private readonly model: string;
23
27
  private readonly contextSize: number;
24
28
  private readonly corpusDir?: string;
29
+ private readonly options: {
30
+ quantization: 'int4' | 'int8';
31
+ pro: boolean;
32
+ };
25
33
 
26
34
  private isDownloading = false;
27
35
  private isInitialized = false;
28
36
  private isGenerating = false;
29
37
 
30
- private static readonly defaultModel = 'qwen3-0.6';
38
+ private static readonly defaultModel = 'qwen3-0.6b';
31
39
  private static readonly defaultContextSize = 2048;
40
+ private static readonly defaultOptions = {
41
+ quantization: 'int4' as const,
42
+ pro: false,
43
+ };
44
+ private static readonly quantizationExceptions: {
45
+ [model: string]: 'int4' | 'int8';
46
+ } = {
47
+ 'gemma-3-270m-it': 'int8' as const,
48
+ 'functiongemma-270m-it': 'int8' as const,
49
+ };
32
50
  private static readonly defaultCompleteOptions = {
33
51
  maxTokens: 512,
34
52
  };
35
53
  private static readonly defaultCompleteMode = 'local';
36
54
  private static readonly defaultEmbedBufferSize = 2048;
37
55
 
38
- constructor({ model, contextSize, corpusDir }: CactusLMParams = {}) {
56
+ constructor({ model, contextSize, corpusDir, options }: CactusLMParams = {}) {
39
57
  Telemetry.init(CactusConfig.telemetryToken);
40
58
 
41
59
  this.model = model ?? CactusLM.defaultModel;
42
60
  this.contextSize = contextSize ?? CactusLM.defaultContextSize;
43
61
  this.corpusDir = corpusDir;
62
+ this.options = {
63
+ quantization:
64
+ options?.quantization ??
65
+ CactusLM.quantizationExceptions[this.model] ??
66
+ CactusLM.defaultOptions.quantization,
67
+ pro: options?.pro ?? CactusLM.defaultOptions.pro,
68
+ };
44
69
  }
45
70
 
46
71
  public async download({
47
72
  onProgress,
48
73
  }: CactusLMDownloadParams = {}): Promise<void> {
74
+ if (this.isModelPath(this.model)) {
75
+ onProgress?.(1.0);
76
+ return;
77
+ }
78
+
49
79
  if (this.isDownloading) {
50
80
  throw new Error('CactusLM is already downloading');
51
81
  }
52
82
 
53
- if (await CactusFileSystem.modelExists(this.model)) {
83
+ if (await CactusFileSystem.modelExists(this.getModelName())) {
84
+ console.log('Model already exists', this.getModelName());
54
85
  onProgress?.(1.0);
55
86
  return;
56
87
  }
57
88
 
58
89
  this.isDownloading = true;
59
90
  try {
60
- const model = await Database.getModel(this.model);
91
+ const modelConfig =
92
+ models[this.model]?.quantization[this.options.quantization];
93
+ const url = this.options.pro ? modelConfig?.pro?.apple : modelConfig?.url;
94
+
95
+ if (!url) {
96
+ throw new Error(`Model ${this.model} with specified options not found`);
97
+ }
98
+
61
99
  await CactusFileSystem.downloadModel(
62
- this.model,
63
- model.downloadUrl,
100
+ this.getModelName(),
101
+ url,
64
102
  onProgress
65
103
  );
66
104
  } finally {
@@ -73,12 +111,19 @@ export class CactusLM {
73
111
  return;
74
112
  }
75
113
 
76
- if (!(await CactusFileSystem.modelExists(this.model))) {
77
- throw new Error(`Model "${this.model}" is not downloaded`);
114
+ let modelPath: string;
115
+ if (this.isModelPath(this.model)) {
116
+ modelPath = this.model.replace('file://', '');
117
+ } else {
118
+ if (!(await CactusFileSystem.modelExists(this.getModelName()))) {
119
+ console.log('Model not found:', this.getModelName());
120
+ throw new Error(
121
+ `Model "${this.model}" with options ${JSON.stringify(this.options)} is not downloaded`
122
+ );
123
+ }
124
+ modelPath = await CactusFileSystem.getModelPath(this.getModelName());
78
125
  }
79
126
 
80
- const modelPath = await CactusFileSystem.getModelPath(this.model);
81
-
82
127
  try {
83
128
  await this.cactus.init(modelPath, this.contextSize, this.corpusDir);
84
129
  Telemetry.logInit(this.model, true);
@@ -153,8 +198,26 @@ export class CactusLM {
153
198
  }
154
199
  }
155
200
 
201
+ public async tokenize({
202
+ text,
203
+ }: CactusLMTokenizeParams): Promise<CactusLMTokenizeResult> {
204
+ return { tokens: await this.cactus.tokenize(text) };
205
+ }
206
+
207
+ public async scoreWindow({
208
+ tokens,
209
+ start,
210
+ end,
211
+ context,
212
+ }: CactusLMScoreWindowParams): Promise<CactusLMScoreWindowResult> {
213
+ return {
214
+ score: await this.cactus.scoreWindow(tokens, start, end, context),
215
+ };
216
+ }
217
+
156
218
  public async embed({
157
219
  text,
220
+ normalize = false,
158
221
  }: CactusLMEmbedParams): Promise<CactusLMEmbedResult> {
159
222
  if (this.isGenerating) {
160
223
  throw new Error('CactusLM is already generating');
@@ -166,7 +229,8 @@ export class CactusLM {
166
229
  try {
167
230
  const embedding = await this.cactus.embed(
168
231
  text,
169
- CactusLM.defaultEmbedBufferSize
232
+ CactusLM.defaultEmbedBufferSize,
233
+ normalize
170
234
  );
171
235
  Telemetry.logEmbedding(this.model, true);
172
236
  return { embedding };
@@ -223,11 +287,15 @@ export class CactusLM {
223
287
  this.isInitialized = false;
224
288
  }
225
289
 
226
- public async getModels(): Promise<CactusModel[]> {
227
- const models = await Database.getModels();
228
- for (const model of models) {
229
- model.isDownloaded = await CactusFileSystem.modelExists(model.slug);
230
- }
231
- return models;
290
+ public getModels(): CactusModel[] {
291
+ return Object.values(models).filter((model) => model.completion);
292
+ }
293
+
294
+ private isModelPath(model: string): boolean {
295
+ return model.startsWith('file://') || model.startsWith('/');
296
+ }
297
+
298
+ private getModelName(): string {
299
+ return `${this.model}-${this.options.quantization}${this.options.pro ? '-pro' : ''}`;
232
300
  }
233
301
  }
@@ -6,57 +6,89 @@ import type {
6
6
  CactusSTTParams,
7
7
  CactusSTTAudioEmbedParams,
8
8
  CactusSTTAudioEmbedResult,
9
+ CactusSTTStreamTranscribeInsertParams,
10
+ CactusSTTStreamTranscribeProcessParams,
11
+ CactusSTTStreamTranscribeProcessResult,
12
+ CactusSTTStreamTranscribeFinalizeResult,
9
13
  } from '../types/CactusSTT';
10
14
  import { Telemetry } from '../telemetry/Telemetry';
11
15
  import { CactusConfig } from '../config/CactusConfig';
12
- import { Database } from '../api/Database';
13
16
  import { getErrorMessage } from '../utils/error';
14
- import type { CactusSTTModel } from '../types/CactusSTTModel';
17
+ import models from '../models';
18
+ import type { CactusModel } from '../types/common';
15
19
 
16
20
  export class CactusSTT {
17
21
  private readonly cactus = new Cactus();
18
22
 
19
23
  private readonly model: string;
20
24
  private readonly contextSize: number;
25
+ private readonly options: {
26
+ quantization: 'int4' | 'int8';
27
+ pro: boolean;
28
+ };
21
29
 
22
30
  private isDownloading = false;
23
31
  private isInitialized = false;
24
32
  private isGenerating = false;
25
33
 
34
+ private isStreamTranscribeInitialized = false;
35
+
26
36
  private static readonly defaultModel = 'whisper-small';
27
37
  private static readonly defaultContextSize = 2048;
38
+ private static readonly defaultOptions = {
39
+ quantization: 'int4' as const,
40
+ pro: false,
41
+ };
28
42
  private static readonly defaultPrompt =
29
43
  '<|startoftranscript|><|en|><|transcribe|><|notimestamps|>';
30
44
  private static readonly defaultTranscribeOptions = {
31
- maxTokens: 512,
45
+ maxTokens: 384,
32
46
  };
33
47
  private static readonly defaultEmbedBufferSize = 4096;
34
48
 
35
- constructor({ model, contextSize }: CactusSTTParams = {}) {
49
+ constructor({ model, contextSize, options }: CactusSTTParams = {}) {
36
50
  Telemetry.init(CactusConfig.telemetryToken);
37
51
 
38
52
  this.model = model ?? CactusSTT.defaultModel;
39
53
  this.contextSize = contextSize ?? CactusSTT.defaultContextSize;
54
+ this.options = {
55
+ quantization:
56
+ options?.quantization ?? CactusSTT.defaultOptions.quantization,
57
+ pro: options?.pro ?? CactusSTT.defaultOptions.pro,
58
+ };
40
59
  }
41
60
 
42
61
  public async download({
43
62
  onProgress,
44
63
  }: CactusSTTDownloadParams = {}): Promise<void> {
64
+ if (this.isModelPath(this.model)) {
65
+ onProgress?.(1.0);
66
+ return;
67
+ }
68
+
45
69
  if (this.isDownloading) {
46
70
  throw new Error('CactusSTT is already downloading');
47
71
  }
48
72
 
49
- if (await CactusFileSystem.modelExists(this.model)) {
73
+ if (await CactusFileSystem.modelExists(this.getModelName())) {
74
+ console.log('Model already exists', this.getModelName());
50
75
  onProgress?.(1.0);
51
76
  return;
52
77
  }
53
78
 
54
79
  this.isDownloading = true;
55
80
  try {
56
- const model = await Database.getSTTModel(this.model);
81
+ const modelConfig =
82
+ models[this.model]?.quantization[this.options.quantization];
83
+ const url = this.options.pro ? modelConfig?.pro?.apple : modelConfig?.url;
84
+
85
+ if (!url) {
86
+ throw new Error(`Model ${this.model} with specified options not found`);
87
+ }
88
+
57
89
  await CactusFileSystem.downloadModel(
58
- this.model,
59
- model.downloadUrl,
90
+ this.getModelName(),
91
+ url,
60
92
  onProgress
61
93
  );
62
94
  } finally {
@@ -69,12 +101,19 @@ export class CactusSTT {
69
101
  return;
70
102
  }
71
103
 
72
- if (!(await CactusFileSystem.modelExists(this.model))) {
73
- throw new Error(`Model "${this.model}" is not downloaded`);
104
+ let modelPath: string;
105
+ if (this.isModelPath(this.model)) {
106
+ modelPath = this.model.replace('file://', '');
107
+ } else {
108
+ if (!(await CactusFileSystem.modelExists(this.getModelName()))) {
109
+ console.log('Model does not exist', this.getModelName());
110
+ throw new Error(
111
+ `Model "${this.model}" with options ${JSON.stringify(this.options)} is not downloaded`
112
+ );
113
+ }
114
+ modelPath = await CactusFileSystem.getModelPath(this.getModelName());
74
115
  }
75
116
 
76
- const modelPath = await CactusFileSystem.getModelPath(this.model);
77
-
78
117
  try {
79
118
  await this.cactus.init(modelPath, this.contextSize);
80
119
  Telemetry.logInit(this.model, true);
@@ -86,7 +125,7 @@ export class CactusSTT {
86
125
  }
87
126
 
88
127
  public async transcribe({
89
- audioFilePath,
128
+ audio,
90
129
  prompt,
91
130
  options,
92
131
  onToken,
@@ -107,7 +146,7 @@ export class CactusSTT {
107
146
  this.isGenerating = true;
108
147
  try {
109
148
  const result = await this.cactus.transcribe(
110
- audioFilePath,
149
+ audio,
111
150
  prompt,
112
151
  responseBufferSize,
113
152
  options,
@@ -128,6 +167,76 @@ export class CactusSTT {
128
167
  }
129
168
  }
130
169
 
170
+ public async streamTranscribeInit(): Promise<void> {
171
+ if (this.isStreamTranscribeInitialized) {
172
+ return;
173
+ }
174
+
175
+ await this.init();
176
+
177
+ try {
178
+ await this.cactus.streamTranscribeInit();
179
+ this.isStreamTranscribeInitialized = true;
180
+ } catch (error) {
181
+ throw error;
182
+ }
183
+ }
184
+
185
+ public async streamTranscribeInsert({
186
+ audio,
187
+ }: CactusSTTStreamTranscribeInsertParams): Promise<void> {
188
+ if (!this.isStreamTranscribeInitialized) {
189
+ throw new Error('CactusSTT stream transcribe is not initialized');
190
+ }
191
+
192
+ try {
193
+ await this.cactus.streamTranscribeInsert(audio);
194
+ } catch (error) {
195
+ throw error;
196
+ }
197
+ }
198
+
199
+ public async streamTranscribeProcess({
200
+ options,
201
+ }: CactusSTTStreamTranscribeProcessParams = {}): Promise<CactusSTTStreamTranscribeProcessResult> {
202
+ if (!this.isStreamTranscribeInitialized) {
203
+ throw new Error('CactusSTT stream transcribe is not initialized');
204
+ }
205
+
206
+ try {
207
+ const result = await this.cactus.streamTranscribeProcess(options);
208
+ return result;
209
+ } catch (error) {
210
+ throw error;
211
+ }
212
+ }
213
+
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;
224
+ }
225
+ }
226
+
227
+ public async streamTranscribeDestroy(): Promise<void> {
228
+ if (!this.isStreamTranscribeInitialized) {
229
+ return;
230
+ }
231
+
232
+ try {
233
+ await this.cactus.streamTranscribeDestroy();
234
+ this.isStreamTranscribeInitialized = false;
235
+ } catch (error) {
236
+ throw error;
237
+ }
238
+ }
239
+
131
240
  public async audioEmbed({
132
241
  audioPath,
133
242
  }: CactusSTTAudioEmbedParams): Promise<CactusSTTAudioEmbedResult> {
@@ -168,16 +277,21 @@ export class CactusSTT {
168
277
  }
169
278
 
170
279
  await this.stop();
280
+ await this.streamTranscribeDestroy();
171
281
  await this.cactus.destroy();
172
282
 
173
283
  this.isInitialized = false;
174
284
  }
175
285
 
176
- public async getModels(): Promise<CactusSTTModel[]> {
177
- const models = await Database.getSTTModels();
178
- for (const model of models) {
179
- model.isDownloaded = await CactusFileSystem.modelExists(model.slug);
180
- }
181
- return models;
286
+ public getModels(): CactusModel[] {
287
+ return Object.values(models).filter((model) => model.speech);
288
+ }
289
+
290
+ private isModelPath(model: string): boolean {
291
+ return model.startsWith('file://') || model.startsWith('/');
292
+ }
293
+
294
+ private getModelName(): string {
295
+ return `${this.model}-${this.options.quantization}${this.options.pro ? '-pro' : ''}`;
182
296
  }
183
297
  }
@@ -5,4 +5,7 @@ export class CactusConfig {
5
5
 
6
6
  // Hybrid mode
7
7
  public static cactusToken?: string;
8
+
9
+ // Pro features
10
+ public static cactusProKey?: string;
8
11
  }
@@ -1 +1 @@
1
- export const packageVersion = '1.2.1';
1
+ export const packageVersion = '1.4.0';
@@ -0,0 +1,195 @@
1
+ import { useCallback, useEffect, useState } from 'react';
2
+ import { CactusIndex } from '../classes/CactusIndex';
3
+ import { getErrorMessage } from '../utils/error';
4
+ import type {
5
+ CactusIndexParams,
6
+ CactusIndexAddParams,
7
+ CactusIndexGetParams,
8
+ CactusIndexGetResult,
9
+ CactusIndexQueryParams,
10
+ CactusIndexQueryResult,
11
+ CactusIndexDeleteParams,
12
+ } from '../types/CactusIndex';
13
+
14
+ export const useCactusIndex = ({ name, embeddingDim }: CactusIndexParams) => {
15
+ const [cactusIndex, setCactusIndex] = useState(
16
+ () => new CactusIndex(name, embeddingDim)
17
+ );
18
+
19
+ // State
20
+ const [isInitializing, setIsInitializing] = useState(false);
21
+ const [isProcessing, setIsProcessing] = useState(false);
22
+ const [error, setError] = useState<string | null>(null);
23
+
24
+ useEffect(() => {
25
+ setCactusIndex(new CactusIndex(name, embeddingDim));
26
+
27
+ setIsInitializing(false);
28
+ setIsProcessing(false);
29
+ setError(null);
30
+ }, [name, embeddingDim]);
31
+
32
+ useEffect(() => {
33
+ return () => {
34
+ cactusIndex.destroy().catch(() => {});
35
+ };
36
+ }, [cactusIndex]);
37
+
38
+ const init = useCallback(async () => {
39
+ if (isInitializing) {
40
+ const message = 'CactusIndex is already initializing';
41
+ setError(message);
42
+ throw new Error(message);
43
+ }
44
+
45
+ setError(null);
46
+ setIsInitializing(true);
47
+ try {
48
+ await cactusIndex.init();
49
+ } catch (e) {
50
+ setError(getErrorMessage(e));
51
+ throw e;
52
+ } finally {
53
+ setIsInitializing(false);
54
+ }
55
+ }, [cactusIndex, isInitializing]);
56
+
57
+ const add = useCallback(
58
+ async ({
59
+ ids,
60
+ documents,
61
+ metadatas,
62
+ embeddings,
63
+ }: CactusIndexAddParams): Promise<void> => {
64
+ if (isProcessing) {
65
+ const message = 'CactusIndex is already processing';
66
+ setError(message);
67
+ throw new Error(message);
68
+ }
69
+
70
+ setError(null);
71
+ setIsProcessing(true);
72
+ try {
73
+ await cactusIndex.add({ ids, documents, metadatas, embeddings });
74
+ } catch (e) {
75
+ setError(getErrorMessage(e));
76
+ throw e;
77
+ } finally {
78
+ setIsProcessing(false);
79
+ }
80
+ },
81
+ [cactusIndex, isProcessing]
82
+ );
83
+
84
+ const _delete = useCallback(
85
+ async ({ ids }: CactusIndexDeleteParams): Promise<void> => {
86
+ if (isProcessing) {
87
+ const message = 'CactusIndex is already processing';
88
+ setError(message);
89
+ throw new Error(message);
90
+ }
91
+
92
+ setError(null);
93
+ setIsProcessing(true);
94
+ try {
95
+ await cactusIndex.delete({ ids });
96
+ } catch (e) {
97
+ setError(getErrorMessage(e));
98
+ throw e;
99
+ } finally {
100
+ setIsProcessing(false);
101
+ }
102
+ },
103
+ [cactusIndex, isProcessing]
104
+ );
105
+
106
+ const get = useCallback(
107
+ async ({ ids }: CactusIndexGetParams): Promise<CactusIndexGetResult> => {
108
+ if (isProcessing) {
109
+ const message = 'CactusIndex is already processing';
110
+ setError(message);
111
+ throw new Error(message);
112
+ }
113
+
114
+ setError(null);
115
+ setIsProcessing(true);
116
+ try {
117
+ return await cactusIndex.get({ ids });
118
+ } catch (e) {
119
+ setError(getErrorMessage(e));
120
+ throw e;
121
+ } finally {
122
+ setIsProcessing(false);
123
+ }
124
+ },
125
+ [cactusIndex, isProcessing]
126
+ );
127
+
128
+ const query = useCallback(
129
+ async ({
130
+ embeddings,
131
+ options,
132
+ }: CactusIndexQueryParams): Promise<CactusIndexQueryResult> => {
133
+ if (isProcessing) {
134
+ const message = 'CactusIndex is already processing';
135
+ setError(message);
136
+ throw new Error(message);
137
+ }
138
+
139
+ setError(null);
140
+ setIsProcessing(true);
141
+ try {
142
+ return await cactusIndex.query({ embeddings, options });
143
+ } catch (e) {
144
+ setError(getErrorMessage(e));
145
+ throw e;
146
+ } finally {
147
+ setIsProcessing(false);
148
+ }
149
+ },
150
+ [cactusIndex, isProcessing]
151
+ );
152
+
153
+ const compact = useCallback(async () => {
154
+ if (isProcessing) {
155
+ const message = 'CactusIndex is already processing';
156
+ setError(message);
157
+ throw new Error(message);
158
+ }
159
+
160
+ setError(null);
161
+ setIsProcessing(true);
162
+ try {
163
+ await cactusIndex.compact();
164
+ } catch (e) {
165
+ setError(getErrorMessage(e));
166
+ throw e;
167
+ } finally {
168
+ setIsProcessing(false);
169
+ }
170
+ }, [cactusIndex, isProcessing]);
171
+
172
+ const destroy = useCallback(async () => {
173
+ setError(null);
174
+ try {
175
+ await cactusIndex.destroy();
176
+ } catch (e) {
177
+ setError(getErrorMessage(e));
178
+ throw e;
179
+ }
180
+ }, [cactusIndex]);
181
+
182
+ return {
183
+ isInitializing,
184
+ isProcessing,
185
+ error,
186
+
187
+ init,
188
+ add,
189
+ delete: _delete,
190
+ get,
191
+ query,
192
+ compact,
193
+ destroy,
194
+ };
195
+ };