cactus-react-native 1.0.1 → 1.1.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 (128) hide show
  1. package/README.md +609 -56
  2. package/android/src/main/java/com/margelo/nitro/cactus/HybridCactusCrypto.kt +23 -15
  3. package/android/src/main/java/com/margelo/nitro/cactus/HybridCactusDeviceInfo.kt +12 -9
  4. package/android/src/main/java/com/margelo/nitro/cactus/HybridCactusFileSystem.kt +42 -41
  5. package/android/src/main/java/com/margelo/nitro/cactus/HybridCactusImage.kt +81 -0
  6. package/android/src/main/jniLibs/arm64-v8a/libcactus.a +0 -0
  7. package/cpp/HybridCactus.cpp +161 -44
  8. package/cpp/HybridCactus.hpp +34 -14
  9. package/cpp/HybridCactusUtil.cpp +13 -11
  10. package/cpp/HybridCactusUtil.hpp +9 -9
  11. package/cpp/cactus_ffi.h +28 -1
  12. package/ios/HybridCactusImage.swift +53 -0
  13. package/ios/cactus.xcframework/ios-arm64/cactus.framework/Headers/cactus_ffi.h +28 -1
  14. package/ios/cactus.xcframework/ios-arm64/cactus.framework/Headers/engine.h +237 -7
  15. package/ios/cactus.xcframework/ios-arm64/cactus.framework/Headers/ffi_utils.h +158 -43
  16. package/ios/cactus.xcframework/ios-arm64/cactus.framework/Headers/graph.h +23 -2
  17. package/ios/cactus.xcframework/ios-arm64/cactus.framework/Headers/kernel.h +52 -0
  18. package/ios/cactus.xcframework/ios-arm64/cactus.framework/cactus +0 -0
  19. package/ios/cactus.xcframework/ios-arm64-simulator/cactus.framework/Headers/cactus_ffi.h +28 -1
  20. package/ios/cactus.xcframework/ios-arm64-simulator/cactus.framework/Headers/engine.h +237 -7
  21. package/ios/cactus.xcframework/ios-arm64-simulator/cactus.framework/Headers/ffi_utils.h +158 -43
  22. package/ios/cactus.xcframework/ios-arm64-simulator/cactus.framework/Headers/graph.h +23 -2
  23. package/ios/cactus.xcframework/ios-arm64-simulator/cactus.framework/Headers/kernel.h +52 -0
  24. package/ios/cactus.xcframework/ios-arm64-simulator/cactus.framework/cactus +0 -0
  25. package/lib/module/api/Database.js +23 -0
  26. package/lib/module/api/Database.js.map +1 -1
  27. package/lib/module/api/RemoteLM.js +201 -0
  28. package/lib/module/api/RemoteLM.js.map +1 -0
  29. package/lib/module/classes/CactusLM.js +56 -28
  30. package/lib/module/classes/CactusLM.js.map +1 -1
  31. package/lib/module/classes/CactusSTT.js +137 -0
  32. package/lib/module/classes/CactusSTT.js.map +1 -0
  33. package/lib/module/config/CactusConfig.js +4 -0
  34. package/lib/module/config/CactusConfig.js.map +1 -1
  35. package/lib/module/constants/packageVersion.js +1 -1
  36. package/lib/module/hooks/useCactusLM.js +44 -16
  37. package/lib/module/hooks/useCactusLM.js.map +1 -1
  38. package/lib/module/hooks/useCactusSTT.js +234 -0
  39. package/lib/module/hooks/useCactusSTT.js.map +1 -0
  40. package/lib/module/index.js +2 -0
  41. package/lib/module/index.js.map +1 -1
  42. package/lib/module/native/Cactus.js +52 -3
  43. package/lib/module/native/Cactus.js.map +1 -1
  44. package/lib/module/native/CactusFileSystem.js +2 -3
  45. package/lib/module/native/CactusFileSystem.js.map +1 -1
  46. package/lib/module/native/CactusImage.js +13 -0
  47. package/lib/module/native/CactusImage.js.map +1 -0
  48. package/lib/module/native/index.js +1 -0
  49. package/lib/module/native/index.js.map +1 -1
  50. package/lib/module/specs/CactusImage.nitro.js +4 -0
  51. package/lib/module/specs/CactusImage.nitro.js.map +1 -0
  52. package/lib/module/telemetry/Telemetry.js +53 -1
  53. package/lib/module/telemetry/Telemetry.js.map +1 -1
  54. package/lib/module/types/CactusSTT.js +2 -0
  55. package/lib/module/types/CactusSTT.js.map +1 -0
  56. package/lib/typescript/src/api/Database.d.ts +1 -0
  57. package/lib/typescript/src/api/Database.d.ts.map +1 -1
  58. package/lib/typescript/src/api/RemoteLM.d.ts +14 -0
  59. package/lib/typescript/src/api/RemoteLM.d.ts.map +1 -0
  60. package/lib/typescript/src/classes/CactusLM.d.ts +8 -5
  61. package/lib/typescript/src/classes/CactusLM.d.ts.map +1 -1
  62. package/lib/typescript/src/classes/CactusSTT.d.ts +25 -0
  63. package/lib/typescript/src/classes/CactusSTT.d.ts.map +1 -0
  64. package/lib/typescript/src/config/CactusConfig.d.ts +1 -0
  65. package/lib/typescript/src/config/CactusConfig.d.ts.map +1 -1
  66. package/lib/typescript/src/constants/packageVersion.d.ts +1 -1
  67. package/lib/typescript/src/hooks/useCactusLM.d.ts +5 -4
  68. package/lib/typescript/src/hooks/useCactusLM.d.ts.map +1 -1
  69. package/lib/typescript/src/hooks/useCactusSTT.d.ts +20 -0
  70. package/lib/typescript/src/hooks/useCactusSTT.d.ts.map +1 -0
  71. package/lib/typescript/src/index.d.ts +4 -1
  72. package/lib/typescript/src/index.d.ts.map +1 -1
  73. package/lib/typescript/src/native/Cactus.d.ts +10 -3
  74. package/lib/typescript/src/native/Cactus.d.ts.map +1 -1
  75. package/lib/typescript/src/native/CactusFileSystem.d.ts +1 -1
  76. package/lib/typescript/src/native/CactusFileSystem.d.ts.map +1 -1
  77. package/lib/typescript/src/native/CactusImage.d.ts +6 -0
  78. package/lib/typescript/src/native/CactusImage.d.ts.map +1 -0
  79. package/lib/typescript/src/native/index.d.ts +1 -0
  80. package/lib/typescript/src/native/index.d.ts.map +1 -1
  81. package/lib/typescript/src/specs/Cactus.nitro.d.ts +4 -1
  82. package/lib/typescript/src/specs/Cactus.nitro.d.ts.map +1 -1
  83. package/lib/typescript/src/specs/CactusImage.nitro.d.ts +9 -0
  84. package/lib/typescript/src/specs/CactusImage.nitro.d.ts.map +1 -0
  85. package/lib/typescript/src/telemetry/Telemetry.d.ts +5 -1
  86. package/lib/typescript/src/telemetry/Telemetry.d.ts.map +1 -1
  87. package/lib/typescript/src/types/CactusLM.d.ts +11 -6
  88. package/lib/typescript/src/types/CactusLM.d.ts.map +1 -1
  89. package/lib/typescript/src/types/CactusSTT.d.ts +37 -0
  90. package/lib/typescript/src/types/CactusSTT.d.ts.map +1 -0
  91. package/nitro.json +4 -0
  92. package/nitrogen/generated/android/c++/JHybridCactusImageSpec.cpp +81 -0
  93. package/nitrogen/generated/android/c++/JHybridCactusImageSpec.hpp +66 -0
  94. package/nitrogen/generated/android/cactus+autolinking.cmake +2 -0
  95. package/nitrogen/generated/android/cactusOnLoad.cpp +10 -0
  96. package/nitrogen/generated/android/kotlin/com/margelo/nitro/cactus/HybridCactusImageSpec.kt +62 -0
  97. package/nitrogen/generated/ios/Cactus-Swift-Cxx-Bridge.cpp +17 -0
  98. package/nitrogen/generated/ios/Cactus-Swift-Cxx-Bridge.hpp +17 -0
  99. package/nitrogen/generated/ios/Cactus-Swift-Cxx-Umbrella.hpp +5 -0
  100. package/nitrogen/generated/ios/CactusAutolinking.mm +8 -0
  101. package/nitrogen/generated/ios/CactusAutolinking.swift +15 -0
  102. package/nitrogen/generated/ios/c++/HybridCactusImageSpecSwift.cpp +11 -0
  103. package/nitrogen/generated/ios/c++/HybridCactusImageSpecSwift.hpp +85 -0
  104. package/nitrogen/generated/ios/swift/HybridCactusImageSpec.swift +58 -0
  105. package/nitrogen/generated/ios/swift/HybridCactusImageSpec_cxx.swift +158 -0
  106. package/nitrogen/generated/shared/c++/HybridCactusImageSpec.cpp +22 -0
  107. package/nitrogen/generated/shared/c++/HybridCactusImageSpec.hpp +64 -0
  108. package/nitrogen/generated/shared/c++/HybridCactusSpec.cpp +3 -0
  109. package/nitrogen/generated/shared/c++/HybridCactusSpec.hpp +4 -1
  110. package/package.json +1 -1
  111. package/src/api/Database.ts +27 -0
  112. package/src/api/RemoteLM.ts +273 -0
  113. package/src/classes/CactusLM.ts +76 -40
  114. package/src/classes/CactusSTT.ts +182 -0
  115. package/src/config/CactusConfig.ts +4 -0
  116. package/src/constants/packageVersion.ts +1 -1
  117. package/src/hooks/useCactusLM.ts +53 -22
  118. package/src/hooks/useCactusSTT.ts +285 -0
  119. package/src/index.tsx +14 -2
  120. package/src/native/Cactus.ts +100 -6
  121. package/src/native/CactusFileSystem.ts +2 -2
  122. package/src/native/CactusImage.ts +20 -0
  123. package/src/native/index.ts +1 -0
  124. package/src/specs/Cactus.nitro.ts +14 -1
  125. package/src/specs/CactusImage.nitro.ts +12 -0
  126. package/src/telemetry/Telemetry.ts +78 -1
  127. package/src/types/CactusLM.ts +12 -6
  128. package/src/types/CactusSTT.ts +42 -0
package/README.md CHANGED
@@ -10,10 +10,78 @@
10
10
  npm install cactus-react-native react-native-nitro-modules
11
11
  ```
12
12
 
13
+ ## Quick Start
14
+
15
+ Get started with Cactus in just a few lines of code:
16
+
17
+ ```typescript
18
+ import { CactusLM, type Message } from 'cactus-react-native';
19
+
20
+ // Create a new instance
21
+ const cactusLM = new CactusLM();
22
+
23
+ // Download the model
24
+ await cactusLM.download({
25
+ onProgress: (progress) => console.log(`Download: ${Math.round(progress * 100)}%`)
26
+ });
27
+
28
+ // Generate a completion
29
+ const messages: Message[] = [
30
+ { role: 'user', content: 'What is the capital of France?' }
31
+ ];
32
+
33
+ const result = await cactusLM.complete({ messages });
34
+ console.log(result.response); // "The capital of France is Paris."
35
+
36
+ // Clean up resources
37
+ await cactusLM.destroy();
38
+ ```
39
+
40
+ **Using the React Hook:**
41
+
42
+ ```tsx
43
+ import { useCactusLM } from 'cactus-react-native';
44
+
45
+ const App = () => {
46
+ const cactusLM = useCactusLM();
47
+
48
+ useEffect(() => {
49
+ // Download the model if not already available
50
+ if (!cactusLM.isDownloaded) {
51
+ cactusLM.download();
52
+ }
53
+ }, []);
54
+
55
+ const handleGenerate = () => {
56
+ // Generate a completion
57
+ cactusLM.complete({
58
+ messages: [{ role: 'user', content: 'Hello!' }],
59
+ });
60
+ };
61
+
62
+ if (cactusLM.isDownloading) {
63
+ return (
64
+ <Text>
65
+ Downloading model: {Math.round(cactusLM.downloadProgress * 100)}%
66
+ </Text>
67
+ );
68
+ }
69
+
70
+ return (
71
+ <>
72
+ <Button onPress={handleGenerate} title="Generate" />
73
+ <Text>{cactusLM.completion}</Text>
74
+ </>
75
+ );
76
+ };
77
+ ```
78
+
13
79
  ## Language Model
14
80
 
15
81
  ### Completion
16
82
 
83
+ Generate text responses from the model by providing a conversation history.
84
+
17
85
  #### Class
18
86
 
19
87
  ```typescript
@@ -22,9 +90,7 @@ import { CactusLM, type Message } from 'cactus-react-native';
22
90
  const cactusLM = new CactusLM();
23
91
 
24
92
  const messages: Message[] = [{ role: 'user', content: 'Hello, World!' }];
25
- const onToken = (token: string) => {
26
- console.log('Received token:', token);
27
- };
93
+ const onToken = (token: string) => { console.log('Token:', token) };
28
94
 
29
95
  const result = await cactusLM.complete({ messages, onToken });
30
96
  console.log('Completion result:', result);
@@ -54,8 +120,64 @@ const App = () => {
54
120
  };
55
121
  ```
56
122
 
123
+ ### Vision
124
+
125
+ Vision allows you to pass images along with text prompts, enabling the model to analyze and understand visual content.
126
+
127
+ #### Class
128
+
129
+ ```typescript
130
+ import { CactusLM, type Message } from 'cactus-react-native';
131
+
132
+ // Vision-capable model
133
+ const cactusLM = new CactusLM({ model: 'lfm2-vl-450m' });
134
+
135
+ const messages: Message[] = [
136
+ {
137
+ role: 'user',
138
+ content: "What's in the image?",
139
+ images: ['path/to/your/image'],
140
+ },
141
+ ];
142
+
143
+ const result = await cactusLM.complete({ messages });
144
+ console.log('Response:', result.response);
145
+ ```
146
+
147
+ #### Hook
148
+
149
+ ```tsx
150
+ import { useCactusLM, type Message } from 'cactus-react-native';
151
+
152
+ const App = () => {
153
+ // Vision-capable model
154
+ const cactusLM = useCactusLM({ model: 'lfm2-vl-450m' });
155
+
156
+ const handleAnalyze = async () => {
157
+ const messages: Message[] = [
158
+ {
159
+ role: 'user',
160
+ content: "What's in the image?",
161
+ images: ['path/to/your/image'],
162
+ },
163
+ ];
164
+
165
+ await cactusLM.complete({ messages });
166
+ };
167
+
168
+ return (
169
+ <>
170
+ <Button title="Analyze Image" onPress={handleAnalyze} />
171
+ <Text>{cactusLM.completion}</Text>
172
+ </>
173
+ );
174
+ };
175
+ ```
176
+
57
177
  ### Tool Calling
58
178
 
179
+ Enable the model to generate function calls by defining available tools and their parameters.
180
+
59
181
  #### Class
60
182
 
61
183
  ```typescript
@@ -63,7 +185,6 @@ import { CactusLM, type Message, type Tool } from 'cactus-react-native';
63
185
 
64
186
  const tools: Tool[] = [
65
187
  {
66
- type: 'function',
67
188
  name: 'get_weather',
68
189
  description: 'Get current weather for a location',
69
190
  parameters: {
@@ -87,16 +208,16 @@ const messages: Message[] = [
87
208
 
88
209
  const result = await cactusLM.complete({ messages, tools });
89
210
  console.log('Response:', result.response);
211
+ console.log('Function calls:', result.functionCalls);
90
212
  ```
91
213
 
92
214
  #### Hook
93
215
 
94
- ```typescript
216
+ ```tsx
95
217
  import { useCactusLM, type Message, type Tool } from 'cactus-react-native';
96
218
 
97
219
  const tools: Tool[] = [
98
220
  {
99
- type: 'function',
100
221
  name: 'get_weather',
101
222
  description: 'Get current weather for a location',
102
223
  parameters: {
@@ -129,10 +250,62 @@ const App = () => {
129
250
  };
130
251
  ```
131
252
 
132
- ### Embedding
253
+ ### RAG (Retrieval Augmented Generation)
254
+
255
+ RAG allows you to provide a corpus of documents that the model can reference during generation, enabling it to answer questions based on your data.
133
256
 
134
257
  #### Class
135
258
 
259
+ ```typescript
260
+ import { CactusLM, type Message } from 'cactus-react-native';
261
+
262
+ const cactusLM = new CactusLM({
263
+ corpusDir: 'path/to/your/corpus', // Directory containing .txt files
264
+ });
265
+
266
+ const messages: Message[] = [
267
+ { role: 'user', content: 'What information is in the documents?' },
268
+ ];
269
+
270
+ const result = await cactusLM.complete({ messages });
271
+ console.log(result.response);
272
+ ```
273
+
274
+ #### Hook
275
+
276
+ ```tsx
277
+ import { useCactusLM, type Message } from 'cactus-react-native';
278
+
279
+ const App = () => {
280
+ const cactusLM = useCactusLM({
281
+ corpusDir: 'path/to/your/corpus', // Directory containing .txt files
282
+ });
283
+
284
+ const handleAsk = async () => {
285
+ const messages: Message[] = [
286
+ { role: 'user', content: 'What information is in the documents?' },
287
+ ];
288
+
289
+ await cactusLM.complete({ messages });
290
+ };
291
+
292
+ return (
293
+ <>
294
+ <Button title="Ask Question" onPress={handleAsk} />
295
+ <Text>{cactusLM.completion}</Text>
296
+ </>
297
+ );
298
+ };
299
+ ```
300
+
301
+ ### Embedding
302
+
303
+ Convert text and images into numerical vector representations that capture semantic meaning, useful for similarity search and semantic understanding.
304
+
305
+ #### Text Embedding
306
+
307
+ ##### Class
308
+
136
309
  ```typescript
137
310
  import { CactusLM } from 'cactus-react-native';
138
311
 
@@ -143,9 +316,9 @@ console.log('Embedding vector:', result.embedding);
143
316
  console.log('Embedding vector length:', result.embedding.length);
144
317
  ```
145
318
 
146
- #### Hook
319
+ ##### Hook
147
320
 
148
- ```typescript
321
+ ```tsx
149
322
  import { useCactusLM } from 'cactus-react-native';
150
323
 
151
324
  const App = () => {
@@ -161,34 +334,212 @@ const App = () => {
161
334
  };
162
335
  ```
163
336
 
337
+ #### Image Embedding
338
+
339
+ ##### Class
340
+
341
+ ```typescript
342
+ import { CactusLM } from 'cactus-react-native';
343
+
344
+ const cactusLM = new CactusLM({ model: 'lfm2-vl-450m' });
345
+
346
+ const result = await cactusLM.imageEmbed({ imagePath: 'path/to/your/image.jpg' });
347
+ console.log('Image embedding vector:', result.embedding);
348
+ console.log('Embedding vector length:', result.embedding.length);
349
+ ```
350
+
351
+ ##### Hook
352
+
353
+ ```tsx
354
+ import { useCactusLM } from 'cactus-react-native';
355
+
356
+ const App = () => {
357
+ const cactusLM = useCactusLM({ model: 'lfm2-vl-450m' });
358
+
359
+ const handleImageEmbed = async () => {
360
+ const result = await cactusLM.imageEmbed({ imagePath: 'path/to/your/image.jpg' });
361
+ console.log('Image embedding vector:', result.embedding);
362
+ console.log('Embedding vector length:', result.embedding.length);
363
+ };
364
+
365
+ return <Button title="Embed Image" onPress={handleImageEmbed} />;
366
+ };
367
+ ```
368
+
369
+ ### Hybrid Mode (Cloud Fallback)
370
+
371
+ The CactusLM supports a hybrid completion mode that falls back to a cloud-based LLM provider `OpenRouter` if local inference fails.
372
+
373
+ #### Class
374
+
375
+ ```typescript
376
+ import { CactusLM, type Message } from 'cactus-react-native';
377
+
378
+ const cactusLM = new CactusLM();
379
+
380
+ const messages: Message[] = [
381
+ { role: 'user', content: 'Hello, World!' }
382
+ ];
383
+
384
+ // Falls back to remote if local fails
385
+ const result = await cactusLM.complete({
386
+ messages,
387
+ mode: 'hybrid'
388
+ });
389
+ ```
390
+
391
+ #### Hook
392
+
393
+ ```tsx
394
+ import { useCactusLM, type Message } from 'cactus-react-native';
395
+
396
+ const App = () => {
397
+ const cactusLM = useCactusLM();
398
+
399
+ const handleComplete = async () => {
400
+ const messages: Message[] = [
401
+ { role: 'user', content: 'Hello, World!' }
402
+ ];
403
+
404
+ // Falls back to remote if local fails
405
+ await cactusLM.complete({
406
+ messages,
407
+ mode: 'hybrid'
408
+ });
409
+ };
410
+
411
+ return (
412
+ <>
413
+ <Button title="Complete" onPress={handleComplete} />
414
+ <Text>{cactusLM.completion}</Text>
415
+ </>
416
+ );
417
+ };
418
+ ```
419
+
420
+ ## Speech-to-Text (STT)
421
+
422
+ The `CactusSTT` class provides audio transcription and audio embedding capabilities using Whisper models.
423
+
424
+ ### Transcription
425
+
426
+ Transcribe audio files to text with streaming support.
427
+
428
+ #### Class
429
+
430
+ ```typescript
431
+ import { CactusSTT } from 'cactus-react-native';
432
+
433
+ const cactusSTT = new CactusSTT({ model: 'whisper-small' });
434
+
435
+ await cactusSTT.init();
436
+
437
+ const result = await cactusSTT.transcribe({
438
+ audioFilePath: 'path/to/audio.wav',
439
+ onToken: (token) => console.log('Token:', token)
440
+ });
441
+
442
+ console.log('Transcription:', result.response);
443
+ ```
444
+
445
+ #### Hook
446
+
447
+ ```tsx
448
+ import { useCactusSTT } from 'cactus-react-native';
449
+
450
+ const App = () => {
451
+ const cactusSTT = useCactusSTT({ model: 'whisper-small' });
452
+
453
+ const handleTranscribe = async () => {
454
+ const result = await cactusSTT.transcribe({
455
+ audioFilePath: 'path/to/audio.wav',
456
+ });
457
+ console.log('Transcription:', result.response);
458
+ };
459
+
460
+ return (
461
+ <>
462
+ <Button onPress={handleTranscribe} title="Transcribe" />
463
+ <Text>{cactusSTT.response}</Text>
464
+ </>
465
+ );
466
+ };
467
+ ```
468
+
469
+ ### Audio Embedding
470
+
471
+ Generate embeddings from audio files for audio understanding.
472
+
473
+ #### Class
474
+
475
+ ```typescript
476
+ import { CactusSTT } from 'cactus-react-native';
477
+
478
+ const cactusSTT = new CactusSTT();
479
+
480
+ await cactusSTT.init();
481
+
482
+ const result = await cactusSTT.audioEmbed({
483
+ audioPath: 'path/to/audio.wav'
484
+ });
485
+
486
+ console.log('Audio embedding vector:', result.embedding);
487
+ console.log('Embedding vector length:', result.embedding.length);
488
+ ```
489
+
490
+ #### Hook
491
+
492
+ ```tsx
493
+ import { useCactusSTT } from 'cactus-react-native';
494
+
495
+ const App = () => {
496
+ const cactusSTT = useCactusSTT();
497
+
498
+ const handleAudioEmbed = async () => {
499
+ const result = await cactusSTT.audioEmbed({
500
+ audioPath: 'path/to/audio.wav'
501
+ });
502
+ console.log('Audio embedding vector:', result.embedding);
503
+ console.log('Embedding vector length:', result.embedding.length);
504
+ };
505
+
506
+ return <Button title="Embed Audio" onPress={handleAudioEmbed} />;
507
+ };
508
+ ```
509
+
164
510
  ## API Reference
165
511
 
166
- ### `CactusLM` Class
512
+ ### CactusLM Class
167
513
 
168
514
  #### Constructor
169
515
 
170
516
  **`new CactusLM(params?: CactusLMParams)`**
171
517
 
172
- - `model` - Model slug (default: `'qwen3-0.6'`)
173
- - `contextSize` - Context window size (default: `2048`)
518
+ **Parameters:**
519
+ - `model` - Model slug (default: `'qwen3-0.6'`).
520
+ - `contextSize` - Context window size (default: `2048`).
521
+ - `corpusDir` - Directory containing text files for RAG (default: `undefined`).
174
522
 
175
523
  #### Methods
176
524
 
177
525
  **`download(params?: CactusLMDownloadParams): Promise<void>`**
178
526
 
179
- - Downloads the model.
527
+ Downloads the model. If the model is already downloaded, returns immediately with progress `1`. Throws an error if a download is already in progress.
528
+
529
+ **Parameters:**
180
530
  - `onProgress` - Callback for download progress (0-1).
181
531
 
182
532
  **`init(): Promise<void>`**
183
533
 
184
- - Initializes the model and prepares it for inference.
534
+ Initializes the model and prepares it for inference. Safe to call multiple times (idempotent). Throws an error if the model is not downloaded yet.
185
535
 
186
536
  **`complete(params: CactusLMCompleteParams): Promise<CactusLMCompleteResult>`**
187
537
 
188
- - Performs text completion with optional streaming and tool support (initializes the model if needed).
538
+ Performs text completion with optional streaming and tool support. Automatically calls `init()` if not already initialized. Throws an error if a generation (completion or embedding) is already in progress.
539
+
540
+ **Parameters:**
189
541
  - `messages` - Array of `Message` objects.
190
542
  - `options` - Generation options:
191
-
192
543
  - `temperature` - Sampling temperature (default: model-optimized).
193
544
  - `topP` - Nucleus sampling threshold (default: model-optimized).
194
545
  - `topK` - Top-K sampling limit (default: model-optimized).
@@ -196,64 +547,163 @@ const App = () => {
196
547
  - `stopSequences` - Array of strings to stop generation (default: `undefined`).
197
548
  - `tools` - Array of `Tool` objects for function calling (default: `undefined`).
198
549
  - `onToken` - Callback for streaming tokens.
550
+ - `mode` - Completion mode: `'local'` | `'hybrid'` (default: `'local'`)
199
551
 
200
552
  **`embed(params: CactusLMEmbedParams): Promise<CactusLMEmbedResult>`**
201
553
 
202
- - Generates embeddings for the given text (initializes the model if needed).
554
+ Generates embeddings for the given text. Automatically calls `init()` if not already initialized. Throws an error if a generation (completion or embedding) is already in progress.
555
+
556
+ **Parameters:**
203
557
  - `text` - Text to embed.
204
558
 
559
+ **`imageEmbed(params: CactusLMImageEmbedParams): Promise<CactusLMImageEmbedResult>`**
560
+
561
+ Generates embeddings for the given image. Requires a vision-capable model. Automatically calls `init()` if not already initialized. Throws an error if a generation (completion or embedding) is already in progress.
562
+
563
+ **Parameters:**
564
+ - `imagePath` - Path to the image file.
565
+
205
566
  **`stop(): Promise<void>`**
206
567
 
207
- - Stops ongoing generation.
568
+ Stops ongoing generation.
208
569
 
209
570
  **`reset(): Promise<void>`**
210
571
 
211
- - Resets the model's internal state, clearing any cached context.
572
+ Resets the model's internal state, clearing any cached context. Automatically calls `stop()` first.
212
573
 
213
574
  **`destroy(): Promise<void>`**
214
575
 
215
- - Releases all resources associated with the model.
576
+ Releases all resources associated with the model. Automatically calls `stop()` first. Safe to call even if the model is not initialized.
216
577
 
217
- **`getModels(params?: CactusLMGetModelsParams): Promise<CactusModel[]>`**
578
+ **`getModels(): Promise<CactusModel[]>`**
218
579
 
219
- - Fetches available models and persists the results locally.
220
- - `forceRefresh` - If `true`, forces a fetch from the server and updates the local data (default: `false`).
580
+ Fetches available models from the database and checks their download status. Results are cached in memory after the first call and subsequent calls return the cached results.
221
581
 
222
- ### `useCactusLM` Hook
582
+ ### useCactusLM Hook
583
+
584
+ The `useCactusLM` hook manages a `CactusLM` instance with reactive state. When model parameters (`model`, `contextSize`, or `corpusDir`) change, the hook creates a new instance and resets all state. The hook automatically cleans up resources when the component unmounts.
223
585
 
224
586
  #### State
225
587
 
226
- - `completion: string` - Current generated text.
227
- - `isGenerating: boolean` - Whether the model is currently generating.
588
+ - `completion: string` - Current generated text. Automatically accumulated during streaming. Cleared before each new completion and when calling `reset()` or `destroy()`.
589
+ - `isGenerating: boolean` - Whether the model is currently generating (completion or embedding). Both operations share this flag.
228
590
  - `isInitializing: boolean` - Whether the model is initializing.
229
- - `isDownloaded: boolean` - Whether the model is downloaded locally.
591
+ - `isDownloaded: boolean` - Whether the model is downloaded locally. Automatically checked when the hook mounts or model changes.
230
592
  - `isDownloading: boolean` - Whether the model is being downloaded.
231
- - `downloadProgress: number` - Download progress (0-1). `0` if not downloading.
232
- - `error: string | null` - Last error message, or `null` if there is no error.
593
+ - `downloadProgress: number` - Download progress (0-1). Reset to `0` after download completes.
594
+ - `error: string | null` - Last error message from any operation, or `null` if there is no error. Cleared before starting new operations.
233
595
 
234
596
  #### Methods
235
597
 
236
- - `download(params?: CactusLMDownloadParams): Promise<void>`
237
- - `init(): Promise<void>`
238
- - `complete(params: CactusLMCompleteParams): Promise<CactusLMCompleteResult>`
239
- - `embed(params: CactusLMEmbedParams): Promise<CactusLMEmbedResult>`
240
- - `stop(): Promise<void>`
241
- - `reset(): Promise<void>`
242
- - `destroy(): Promise<void>`
243
- - `getModels(params?: CactusLMGetModelsParams): Promise<CactusModel[]>`
598
+ - `download(params?: CactusLMDownloadParams): Promise<void>` - Downloads the model. Updates `isDownloading` and `downloadProgress` state during download. Sets `isDownloaded` to `true` on success.
599
+ - `init(): Promise<void>` - Initializes the model for inference. Sets `isInitializing` to `true` during initialization.
600
+ - `complete(params: CactusLMCompleteParams): Promise<CactusLMCompleteResult>` - Generates text completions. Automatically accumulates tokens in the `completion` state during streaming. Sets `isGenerating` to `true` while generating. Clears `completion` before starting.
601
+ - `embed(params: CactusLMEmbedParams): Promise<CactusLMEmbedResult>` - Generates embeddings for the given text. Sets `isGenerating` to `true` during operation.
602
+ - `imageEmbed(params: CactusLMImageEmbedParams): Promise<CactusLMImageEmbedResult>` - Generates embeddings for the given image. Sets `isGenerating` to `true` while generating.
603
+ - `stop(): Promise<void>` - Stops ongoing generation. Clears any errors.
604
+ - `reset(): Promise<void>` - Resets the model's internal state, clearing cached context. Also clears the `completion` state.
605
+ - `destroy(): Promise<void>` - Releases all resources associated with the model. Clears the `completion` state. Automatically called when the component unmounts.
606
+ - `getModels(): Promise<CactusModel[]>` - Fetches available models from the database and checks their download status. Results are cached in memory and reused on subsequent calls.
607
+
608
+ ### CactusSTT Class
609
+
610
+ #### Constructor
611
+
612
+ **`new CactusSTT(params?: CactusSTTParams)`**
613
+
614
+ **Parameters:**
615
+ - `model` - Model slug (default: `'whisper-small'`).
616
+ - `contextSize` - Context window size (default: `2048`).
617
+
618
+ #### Methods
619
+
620
+ **`download(params?: CactusSTTDownloadParams): Promise<void>`**
621
+
622
+ Downloads the model. If the model is already downloaded, returns immediately with progress `1`. Throws an error if a download is already in progress.
623
+
624
+ **Parameters:**
625
+ - `onProgress` - Callback for download progress (0-1).
626
+
627
+ **`init(): Promise<void>`**
628
+
629
+ Initializes the model and prepares it for inference. Safe to call multiple times (idempotent). Throws an error if the model is not downloaded yet.
630
+
631
+ **`transcribe(params: CactusSTTTranscribeParams): Promise<CactusSTTTranscribeResult>`**
632
+
633
+ Transcribes audio to text with optional streaming support. Automatically calls `init()` if not already initialized. Throws an error if a generation is already in progress.
634
+
635
+ **Parameters:**
636
+ - `audioFilePath` - Path to the audio file.
637
+ - `prompt` - Optional prompt to guide transcription (default: `'<|startoftranscript|><|en|><|transcribe|><|notimestamps|>'`).
638
+ - `options` - Transcription options:
639
+ - `temperature` - Sampling temperature (default: model-optimized).
640
+ - `topP` - Nucleus sampling threshold (default: model-optimized).
641
+ - `topK` - Top-K sampling limit (default: model-optimized).
642
+ - `maxTokens` - Maximum number of tokens to generate (default: `512`).
643
+ - `stopSequences` - Array of strings to stop generation (default: `undefined`).
644
+ - `onToken` - Callback for streaming tokens.
645
+
646
+ **`audioEmbed(params: CactusSTTAudioEmbedParams): Promise<CactusSTTAudioEmbedResult>`**
647
+
648
+ Generates embeddings for the given audio file. Automatically calls `init()` if not already initialized. Throws an error if a generation is already in progress.
649
+
650
+ **Parameters:**
651
+ - `audioPath` - Path to the audio file.
652
+
653
+ **`stop(): Promise<void>`**
654
+
655
+ Stops ongoing transcription or embedding generation.
656
+
657
+ **`reset(): Promise<void>`**
658
+
659
+ Resets the model's internal state. Automatically calls `stop()` first.
660
+
661
+ **`destroy(): Promise<void>`**
662
+
663
+ Releases all resources associated with the model. Automatically calls `stop()` first. Safe to call even if the model is not initialized.
664
+
665
+ **`getModels(): Promise<CactusModel[]>`**
666
+
667
+ Fetches available models from the database and checks their download status. Results are cached in memory after the first call and subsequent calls return the cached results.
668
+
669
+ ### useCactusSTT Hook
670
+
671
+ The `useCactusSTT` hook manages a `CactusSTT` instance with reactive state. When model parameters (`model`, `contextSize`) change, the hook creates a new instance and resets all state. The hook automatically cleans up resources when the component unmounts.
672
+
673
+ #### State
674
+
675
+ - `response: string` - Current transcription text. Automatically accumulated during streaming. Cleared before each new transcription and when calling `reset()` or `destroy()`.
676
+ - `isGenerating: boolean` - Whether the model is currently generating (transcription or embedding). Both operations share this flag.
677
+ - `isInitializing: boolean` - Whether the model is initializing.
678
+ - `isDownloaded: boolean` - Whether the model is downloaded locally. Automatically checked when the hook mounts or model changes.
679
+ - `isDownloading: boolean` - Whether the model is being downloaded.
680
+ - `downloadProgress: number` - Download progress (0-1). Reset to `0` after download completes.
681
+ - `error: string | null` - Last error message from any operation, or `null` if there is no error. Cleared before starting new operations.
682
+
683
+ #### Methods
684
+
685
+ - `download(params?: CactusSTTDownloadParams): Promise<void>` - Downloads the model. Updates `isDownloading` and `downloadProgress` state during download. Sets `isDownloaded` to `true` on success.
686
+ - `init(): Promise<void>` - Initializes the model for inference. Sets `isInitializing` to `true` during initialization.
687
+ - `transcribe(params: CactusSTTTranscribeParams): Promise<CactusSTTTranscribeResult>` - Transcribes audio to text. Automatically accumulates tokens in the `response` state during streaming. Sets `isGenerating` to `true` while generating. Clears `response` before starting.
688
+ - `audioEmbed(params: CactusSTTAudioEmbedParams): Promise<CactusSTTAudioEmbedResult>` - Generates embeddings for the given audio. Sets `isGenerating` to `true` during operation.
689
+ - `stop(): Promise<void>` - Stops ongoing generation. Clears any errors.
690
+ - `reset(): Promise<void>` - Resets the model's internal state. Also clears the `response` state.
691
+ - `destroy(): Promise<void>` - Releases all resources associated with the model. Clears the `response` state. Automatically called when the component unmounts.
692
+ - `getModels(): Promise<CactusModel[]>` - Fetches available models from the database and checks their download status. Results are cached in memory and reused on subsequent calls.
244
693
 
245
694
  ## Type Definitions
246
695
 
247
- ### `CactusLMParams`
696
+ ### CactusLMParams
248
697
 
249
698
  ```typescript
250
699
  interface CactusLMParams {
251
700
  model?: string;
252
701
  contextSize?: number;
702
+ corpusDir?: string;
253
703
  }
254
704
  ```
255
705
 
256
- ### `CactusLMDownloadParams`
706
+ ### CactusLMDownloadParams
257
707
 
258
708
  ```typescript
259
709
  interface CactusLMDownloadParams {
@@ -261,19 +711,20 @@ interface CactusLMDownloadParams {
261
711
  }
262
712
  ```
263
713
 
264
- ### `Message`
714
+ ### Message
265
715
 
266
716
  ```typescript
267
717
  interface Message {
268
718
  role: 'user' | 'assistant' | 'system';
269
- content: string;
719
+ content?: string;
720
+ images?: string[];
270
721
  }
271
722
  ```
272
723
 
273
- ### `Options`
724
+ ### CompleteOptions
274
725
 
275
726
  ```typescript
276
- interface Options {
727
+ interface CompleteOptions {
277
728
  temperature?: number;
278
729
  topP?: number;
279
730
  topK?: number;
@@ -282,11 +733,10 @@ interface Options {
282
733
  }
283
734
  ```
284
735
 
285
- ### `Tool`
736
+ ### Tool
286
737
 
287
738
  ```typescript
288
739
  interface Tool {
289
- type: 'function';
290
740
  name: string;
291
741
  description: string;
292
742
  parameters: {
@@ -302,18 +752,19 @@ interface Tool {
302
752
  }
303
753
  ```
304
754
 
305
- ### `CactusLMCompleteParams`
755
+ ### CactusLMCompleteParams
306
756
 
307
757
  ```typescript
308
758
  interface CactusLMCompleteParams {
309
759
  messages: Message[];
310
- options?: Options;
760
+ options?: CompleteOptions;
311
761
  tools?: Tool[];
312
762
  onToken?: (token: string) => void;
763
+ mode?: 'local' | 'hybrid';
313
764
  }
314
765
  ```
315
766
 
316
- ### `CactusLMCompleteResult`
767
+ ### CactusLMCompleteResult
317
768
 
318
769
  ```typescript
319
770
  interface CactusLMCompleteResult {
@@ -332,7 +783,7 @@ interface CactusLMCompleteResult {
332
783
  }
333
784
  ```
334
785
 
335
- ### `CactusLMEmbedParams`
786
+ ### CactusLMEmbedParams
336
787
 
337
788
  ```typescript
338
789
  interface CactusLMEmbedParams {
@@ -340,7 +791,7 @@ interface CactusLMEmbedParams {
340
791
  }
341
792
  ```
342
793
 
343
- ### `CactusLMEmbedResult`
794
+ ### CactusLMEmbedResult
344
795
 
345
796
  ```typescript
346
797
  interface CactusLMEmbedResult {
@@ -348,15 +799,23 @@ interface CactusLMEmbedResult {
348
799
  }
349
800
  ```
350
801
 
351
- ### `CactusLMGetModelsParams`
802
+ ### CactusLMImageEmbedParams
352
803
 
353
804
  ```typescript
354
- interface CactusLMGetModelsParams {
355
- forceRefresh?: boolean;
805
+ interface CactusLMImageEmbedParams {
806
+ imagePath: string;
356
807
  }
357
808
  ```
358
809
 
359
- ### `CactusModel`
810
+ ### CactusLMImageEmbedResult
811
+
812
+ ```typescript
813
+ interface CactusLMImageEmbedResult {
814
+ embedding: number[];
815
+ }
816
+ ```
817
+
818
+ ### CactusModel
360
819
 
361
820
  ```typescript
362
821
  interface CactusModel {
@@ -372,6 +831,79 @@ interface CactusModel {
372
831
  }
373
832
  ```
374
833
 
834
+ ### CactusSTTParams
835
+
836
+ ```typescript
837
+ interface CactusSTTParams {
838
+ model?: string;
839
+ contextSize?: number;
840
+ }
841
+ ```
842
+
843
+ ### CactusSTTDownloadParams
844
+
845
+ ```typescript
846
+ interface CactusSTTDownloadParams {
847
+ onProgress?: (progress: number) => void;
848
+ }
849
+
850
+ ```
851
+
852
+ ### TranscribeOptions
853
+
854
+ ```ts
855
+ interface TranscribeOptions {
856
+ temperature?: number;
857
+ topP?: number;
858
+ topK?: number;
859
+ maxTokens?: number;
860
+ stopSequences?: string[];
861
+ }
862
+ ```
863
+
864
+ ### CactusSTTTranscribeParams
865
+
866
+ ```typescript
867
+ interface CactusSTTTranscribeParams {
868
+ audioFilePath: string;
869
+ prompt?: string;
870
+ options?: TranscribeOptions;
871
+ onToken?: (token: string) => void;
872
+ }
873
+ ```
874
+
875
+ ### CactusSTTTranscribeResult
876
+
877
+ ```typescript
878
+ interface CactusSTTTranscribeResult {
879
+ success: boolean;
880
+ response: string;
881
+ timeToFirstTokenMs: number;
882
+ totalTimeMs: number;
883
+ tokensPerSecond: number;
884
+ prefillTokens: number;
885
+ decodeTokens: number;
886
+ totalTokens: number;
887
+ }
888
+
889
+ ```
890
+
891
+ ### CactusSTTAudioEmbedParams
892
+
893
+ ```typescript
894
+ interface CactusSTTAudioEmbedParams {
895
+ audioPath: string;
896
+ }
897
+ ```
898
+
899
+ ### CactusSTTAudioEmbedResult
900
+
901
+ ```typescript
902
+ interface CactusSTTAudioEmbedResult {
903
+ embedding: number[];
904
+ }
905
+ ```
906
+
375
907
  ## Configuration
376
908
 
377
909
  ### Telemetry
@@ -382,8 +914,29 @@ Cactus offers powerful telemetry for all your projects. Create a token on the [C
382
914
  import { CactusConfig } from 'cactus-react-native';
383
915
 
384
916
  // Enable Telemetry for your project
385
- CactusConfig.telemetryToken = 'your-token-here';
917
+ CactusConfig.telemetryToken = 'your-telemetry-token-here';
386
918
 
387
919
  // Disable telemetry
388
920
  CactusConfig.isTelemetryEnabled = false;
389
- ```
921
+ ```
922
+
923
+ ### Hybrid Mode
924
+
925
+ Enable cloud fallback.
926
+
927
+ ```typescript
928
+ import { CactusConfig } from 'cactus-react-native';
929
+
930
+ // Set your Cactus token for hybrid mode
931
+ CactusConfig.cactusToken = 'your-cactus-token-here';
932
+ ```
933
+
934
+ ## Performance Tips
935
+
936
+ - **Model Selection** - Choose smaller models for faster inference on mobile devices.
937
+ - **Context Size** - Reduce the context size to lower memory usage.
938
+ - **Memory Management** - Always call `destroy()` when you're done with models to free up resources.
939
+
940
+ ## Example App
941
+
942
+ Check out [our example app](/example) for a complete React Native implementation.