cactus-react-native 1.0.1 → 1.0.2
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.
- package/README.md +241 -45
- package/android/src/main/jniLibs/arm64-v8a/libcactus.a +0 -0
- package/cpp/HybridCactus.cpp +63 -51
- package/cpp/HybridCactus.hpp +21 -14
- package/cpp/HybridCactusUtil.cpp +13 -11
- package/cpp/HybridCactusUtil.hpp +9 -9
- package/cpp/cactus_ffi.h +1 -1
- package/ios/cactus.xcframework/ios-arm64/cactus.framework/Headers/cactus_ffi.h +1 -1
- package/ios/cactus.xcframework/ios-arm64/cactus.framework/Headers/engine.h +204 -6
- package/ios/cactus.xcframework/ios-arm64/cactus.framework/Headers/ffi_utils.h +150 -36
- package/ios/cactus.xcframework/ios-arm64/cactus.framework/Headers/graph.h +20 -1
- package/ios/cactus.xcframework/ios-arm64/cactus.framework/Headers/kernel.h +21 -0
- package/ios/cactus.xcframework/ios-arm64/cactus.framework/cactus +0 -0
- package/ios/cactus.xcframework/ios-arm64-simulator/cactus.framework/Headers/cactus_ffi.h +1 -1
- package/ios/cactus.xcframework/ios-arm64-simulator/cactus.framework/Headers/engine.h +204 -6
- package/ios/cactus.xcframework/ios-arm64-simulator/cactus.framework/Headers/ffi_utils.h +150 -36
- package/ios/cactus.xcframework/ios-arm64-simulator/cactus.framework/Headers/graph.h +20 -1
- package/ios/cactus.xcframework/ios-arm64-simulator/cactus.framework/Headers/kernel.h +21 -0
- package/ios/cactus.xcframework/ios-arm64-simulator/cactus.framework/cactus +0 -0
- package/lib/module/classes/CactusLM.js +4 -2
- package/lib/module/classes/CactusLM.js.map +1 -1
- package/lib/module/constants/packageVersion.js +1 -1
- package/lib/module/hooks/useCactusLM.js +11 -6
- package/lib/module/hooks/useCactusLM.js.map +1 -1
- package/lib/module/native/Cactus.js +2 -2
- package/lib/module/native/Cactus.js.map +1 -1
- package/lib/typescript/src/classes/CactusLM.d.ts +2 -1
- package/lib/typescript/src/classes/CactusLM.d.ts.map +1 -1
- package/lib/typescript/src/constants/packageVersion.d.ts +1 -1
- package/lib/typescript/src/hooks/useCactusLM.d.ts +1 -1
- package/lib/typescript/src/hooks/useCactusLM.d.ts.map +1 -1
- package/lib/typescript/src/native/Cactus.d.ts +1 -1
- package/lib/typescript/src/native/Cactus.d.ts.map +1 -1
- package/lib/typescript/src/specs/Cactus.nitro.d.ts +1 -1
- package/lib/typescript/src/specs/Cactus.nitro.d.ts.map +1 -1
- package/lib/typescript/src/types/CactusLM.d.ts +3 -1
- package/lib/typescript/src/types/CactusLM.d.ts.map +1 -1
- package/nitrogen/generated/shared/c++/HybridCactusSpec.hpp +1 -1
- package/package.json +1 -1
- package/src/classes/CactusLM.ts +4 -2
- package/src/constants/packageVersion.ts +1 -1
- package/src/hooks/useCactusLM.ts +8 -5
- package/src/native/Cactus.ts +6 -2
- package/src/specs/Cactus.nitro.ts +5 -1
- package/src/types/CactusLM.ts +3 -1
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
|
|
@@ -87,11 +209,12 @@ const messages: Message[] = [
|
|
|
87
209
|
|
|
88
210
|
const result = await cactusLM.complete({ messages, tools });
|
|
89
211
|
console.log('Response:', result.response);
|
|
212
|
+
console.log('Function calls:', result.functionCalls);
|
|
90
213
|
```
|
|
91
214
|
|
|
92
215
|
#### Hook
|
|
93
216
|
|
|
94
|
-
```
|
|
217
|
+
```tsx
|
|
95
218
|
import { useCactusLM, type Message, type Tool } from 'cactus-react-native';
|
|
96
219
|
|
|
97
220
|
const tools: Tool[] = [
|
|
@@ -129,8 +252,58 @@ const App = () => {
|
|
|
129
252
|
};
|
|
130
253
|
```
|
|
131
254
|
|
|
255
|
+
### RAG (Retrieval Augmented Generation)
|
|
256
|
+
|
|
257
|
+
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.
|
|
258
|
+
|
|
259
|
+
#### Class
|
|
260
|
+
|
|
261
|
+
```typescript
|
|
262
|
+
import { CactusLM, type Message } from 'cactus-react-native';
|
|
263
|
+
|
|
264
|
+
const cactusLM = new CactusLM({
|
|
265
|
+
corpusDir: 'path/to/your/corpus', // Directory containing .txt files
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
const messages: Message[] = [
|
|
269
|
+
{ role: 'user', content: 'What information is in the documents?' },
|
|
270
|
+
];
|
|
271
|
+
|
|
272
|
+
const result = await cactusLM.complete({ messages });
|
|
273
|
+
console.log(result.response);
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
#### Hook
|
|
277
|
+
|
|
278
|
+
```tsx
|
|
279
|
+
import { useCactusLM, type Message } from 'cactus-react-native';
|
|
280
|
+
|
|
281
|
+
const App = () => {
|
|
282
|
+
const cactusLM = useCactusLM({
|
|
283
|
+
corpusDir: 'path/to/your/corpus', // Directory containing .txt files
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
const handleAsk = async () => {
|
|
287
|
+
const messages: Message[] = [
|
|
288
|
+
{ role: 'user', content: 'What information is in the documents?' },
|
|
289
|
+
];
|
|
290
|
+
|
|
291
|
+
await cactusLM.complete({ messages });
|
|
292
|
+
};
|
|
293
|
+
|
|
294
|
+
return (
|
|
295
|
+
<>
|
|
296
|
+
<Button title="Ask Question" onPress={handleAsk} />
|
|
297
|
+
<Text>{cactusLM.completion}</Text>
|
|
298
|
+
</>
|
|
299
|
+
);
|
|
300
|
+
};
|
|
301
|
+
```
|
|
302
|
+
|
|
132
303
|
### Embedding
|
|
133
304
|
|
|
305
|
+
Convert text into numerical vector representations that capture semantic meaning, useful for similarity search and semantic understanding.
|
|
306
|
+
|
|
134
307
|
#### Class
|
|
135
308
|
|
|
136
309
|
```typescript
|
|
@@ -145,7 +318,7 @@ console.log('Embedding vector length:', result.embedding.length);
|
|
|
145
318
|
|
|
146
319
|
#### Hook
|
|
147
320
|
|
|
148
|
-
```
|
|
321
|
+
```tsx
|
|
149
322
|
import { useCactusLM } from 'cactus-react-native';
|
|
150
323
|
|
|
151
324
|
const App = () => {
|
|
@@ -163,32 +336,37 @@ const App = () => {
|
|
|
163
336
|
|
|
164
337
|
## API Reference
|
|
165
338
|
|
|
166
|
-
###
|
|
339
|
+
### CactusLM Class
|
|
167
340
|
|
|
168
341
|
#### Constructor
|
|
169
342
|
|
|
170
343
|
**`new CactusLM(params?: CactusLMParams)`**
|
|
171
344
|
|
|
172
|
-
|
|
173
|
-
- `
|
|
345
|
+
**Parameters:**
|
|
346
|
+
- `model` - Model slug (default: `'qwen3-0.6'`).
|
|
347
|
+
- `contextSize` - Context window size (default: `2048`).
|
|
348
|
+
- `corpusDir` - Directory containing text files for RAG (default: `undefined`).
|
|
174
349
|
|
|
175
350
|
#### Methods
|
|
176
351
|
|
|
177
352
|
**`download(params?: CactusLMDownloadParams): Promise<void>`**
|
|
178
353
|
|
|
179
|
-
|
|
354
|
+
Downloads the model. If the model is already downloaded, returns immediately with progress at 100%. Throws an error if a download is already in progress. Automatically refreshes the models list after successful download.
|
|
355
|
+
|
|
356
|
+
**Parameters:**
|
|
180
357
|
- `onProgress` - Callback for download progress (0-1).
|
|
181
358
|
|
|
182
359
|
**`init(): Promise<void>`**
|
|
183
360
|
|
|
184
|
-
|
|
361
|
+
Initializes the model and prepares it for inference. Safe to call multiple times (idempotent). Throws an error if the model is not downloaded yet. Automatically initializes telemetry if not already done.
|
|
185
362
|
|
|
186
363
|
**`complete(params: CactusLMCompleteParams): Promise<CactusLMCompleteResult>`**
|
|
187
364
|
|
|
188
|
-
|
|
365
|
+
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.
|
|
366
|
+
|
|
367
|
+
**Parameters:**
|
|
189
368
|
- `messages` - Array of `Message` objects.
|
|
190
369
|
- `options` - Generation options:
|
|
191
|
-
|
|
192
370
|
- `temperature` - Sampling temperature (default: model-optimized).
|
|
193
371
|
- `topP` - Nucleus sampling threshold (default: model-optimized).
|
|
194
372
|
- `topK` - Top-K sampling limit (default: model-optimized).
|
|
@@ -199,61 +377,68 @@ const App = () => {
|
|
|
199
377
|
|
|
200
378
|
**`embed(params: CactusLMEmbedParams): Promise<CactusLMEmbedResult>`**
|
|
201
379
|
|
|
202
|
-
|
|
380
|
+
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.
|
|
381
|
+
|
|
382
|
+
**Parameters:**
|
|
203
383
|
- `text` - Text to embed.
|
|
204
384
|
|
|
205
385
|
**`stop(): Promise<void>`**
|
|
206
386
|
|
|
207
|
-
|
|
387
|
+
Stops ongoing generation.
|
|
208
388
|
|
|
209
389
|
**`reset(): Promise<void>`**
|
|
210
390
|
|
|
211
|
-
|
|
391
|
+
Resets the model's internal state, clearing any cached context. Automatically calls `stop()` first.
|
|
212
392
|
|
|
213
393
|
**`destroy(): Promise<void>`**
|
|
214
394
|
|
|
215
|
-
|
|
395
|
+
Releases all resources associated with the model. Automatically calls `stop()` first. Safe to call even if the model is not initialized.
|
|
216
396
|
|
|
217
397
|
**`getModels(params?: CactusLMGetModelsParams): Promise<CactusModel[]>`**
|
|
218
398
|
|
|
219
|
-
|
|
220
|
-
- `forceRefresh` - If `true`, forces a fetch from the server and updates the local data (default: `false`).
|
|
399
|
+
Fetches available models and persists the results locally for caching. Returns cached results if available, unless `forceRefresh` is `true`. Checks the download status for each model and includes it in the results.
|
|
221
400
|
|
|
222
|
-
|
|
401
|
+
**Parameters:**
|
|
402
|
+
- `forceRefresh` - If `true`, fetches from the server and updates the local cache (default: `false`).
|
|
403
|
+
|
|
404
|
+
### useCactusLM Hook
|
|
405
|
+
|
|
406
|
+
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
407
|
|
|
224
408
|
#### State
|
|
225
409
|
|
|
226
|
-
- `completion: string` - Current generated text.
|
|
227
|
-
- `isGenerating: boolean` - Whether the model is currently generating.
|
|
410
|
+
- `completion: string` - Current generated text. Automatically accumulated during streaming. Cleared before each new completion and when calling `reset()` or `destroy()`.
|
|
411
|
+
- `isGenerating: boolean` - Whether the model is currently generating (completion or embedding). Both operations share this flag.
|
|
228
412
|
- `isInitializing: boolean` - Whether the model is initializing.
|
|
229
|
-
- `isDownloaded: boolean` - Whether the model is downloaded locally.
|
|
413
|
+
- `isDownloaded: boolean` - Whether the model is downloaded locally. Automatically checked when the hook mounts or model changes.
|
|
230
414
|
- `isDownloading: boolean` - Whether the model is being downloaded.
|
|
231
|
-
- `downloadProgress: number` - Download progress (0-1). `0`
|
|
232
|
-
- `error: string | null` - Last error message, or `null` if there is no error.
|
|
415
|
+
- `downloadProgress: number` - Download progress (0-1). Reset to `0` after download completes.
|
|
416
|
+
- `error: string | null` - Last error message from any operation, or `null` if there is no error. Cleared before starting new operations.
|
|
233
417
|
|
|
234
418
|
#### Methods
|
|
235
419
|
|
|
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[]>`
|
|
420
|
+
- `download(params?: CactusLMDownloadParams): Promise<void>` - Downloads the model. Updates `isDownloading` and `downloadProgress` state during download. Sets `isDownloaded` to `true` on success.
|
|
421
|
+
- `init(): Promise<void>` - Initializes the model for inference. Sets `isInitializing` to `true` during initialization.
|
|
422
|
+
- `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.
|
|
423
|
+
- `embed(params: CactusLMEmbedParams): Promise<CactusLMEmbedResult>` - Generates embeddings for the given text. Sets `isGenerating` to `true` during operation.
|
|
424
|
+
- `stop(): Promise<void>` - Stops ongoing generation. Clears any errors.
|
|
425
|
+
- `reset(): Promise<void>` - Resets the model's internal state, clearing cached context. Also clears the `completion` state.
|
|
426
|
+
- `destroy(): Promise<void>` - Releases all resources associated with the model. Clears the `completion` state. Automatically called when the component unmounts.
|
|
427
|
+
- `getModels(params?: CactusLMGetModelsParams): Promise<CactusModel[]>` - Fetches available models and returns them. Results are cached locally.
|
|
244
428
|
|
|
245
429
|
## Type Definitions
|
|
246
430
|
|
|
247
|
-
###
|
|
431
|
+
### CactusLMParams
|
|
248
432
|
|
|
249
433
|
```typescript
|
|
250
434
|
interface CactusLMParams {
|
|
251
435
|
model?: string;
|
|
252
436
|
contextSize?: number;
|
|
437
|
+
corpusDir?: string;
|
|
253
438
|
}
|
|
254
439
|
```
|
|
255
440
|
|
|
256
|
-
###
|
|
441
|
+
### CactusLMDownloadParams
|
|
257
442
|
|
|
258
443
|
```typescript
|
|
259
444
|
interface CactusLMDownloadParams {
|
|
@@ -261,16 +446,17 @@ interface CactusLMDownloadParams {
|
|
|
261
446
|
}
|
|
262
447
|
```
|
|
263
448
|
|
|
264
|
-
###
|
|
449
|
+
### Message
|
|
265
450
|
|
|
266
451
|
```typescript
|
|
267
452
|
interface Message {
|
|
268
453
|
role: 'user' | 'assistant' | 'system';
|
|
269
|
-
content
|
|
454
|
+
content?: string;
|
|
455
|
+
images?: string[];
|
|
270
456
|
}
|
|
271
457
|
```
|
|
272
458
|
|
|
273
|
-
###
|
|
459
|
+
### Options
|
|
274
460
|
|
|
275
461
|
```typescript
|
|
276
462
|
interface Options {
|
|
@@ -282,7 +468,7 @@ interface Options {
|
|
|
282
468
|
}
|
|
283
469
|
```
|
|
284
470
|
|
|
285
|
-
###
|
|
471
|
+
### Tool
|
|
286
472
|
|
|
287
473
|
```typescript
|
|
288
474
|
interface Tool {
|
|
@@ -302,7 +488,7 @@ interface Tool {
|
|
|
302
488
|
}
|
|
303
489
|
```
|
|
304
490
|
|
|
305
|
-
###
|
|
491
|
+
### CactusLMCompleteParams
|
|
306
492
|
|
|
307
493
|
```typescript
|
|
308
494
|
interface CactusLMCompleteParams {
|
|
@@ -313,7 +499,7 @@ interface CactusLMCompleteParams {
|
|
|
313
499
|
}
|
|
314
500
|
```
|
|
315
501
|
|
|
316
|
-
###
|
|
502
|
+
### CactusLMCompleteResult
|
|
317
503
|
|
|
318
504
|
```typescript
|
|
319
505
|
interface CactusLMCompleteResult {
|
|
@@ -332,7 +518,7 @@ interface CactusLMCompleteResult {
|
|
|
332
518
|
}
|
|
333
519
|
```
|
|
334
520
|
|
|
335
|
-
###
|
|
521
|
+
### CactusLMEmbedParams
|
|
336
522
|
|
|
337
523
|
```typescript
|
|
338
524
|
interface CactusLMEmbedParams {
|
|
@@ -340,7 +526,7 @@ interface CactusLMEmbedParams {
|
|
|
340
526
|
}
|
|
341
527
|
```
|
|
342
528
|
|
|
343
|
-
###
|
|
529
|
+
### CactusLMEmbedResult
|
|
344
530
|
|
|
345
531
|
```typescript
|
|
346
532
|
interface CactusLMEmbedResult {
|
|
@@ -348,7 +534,7 @@ interface CactusLMEmbedResult {
|
|
|
348
534
|
}
|
|
349
535
|
```
|
|
350
536
|
|
|
351
|
-
###
|
|
537
|
+
### CactusLMGetModelsParams
|
|
352
538
|
|
|
353
539
|
```typescript
|
|
354
540
|
interface CactusLMGetModelsParams {
|
|
@@ -356,7 +542,7 @@ interface CactusLMGetModelsParams {
|
|
|
356
542
|
}
|
|
357
543
|
```
|
|
358
544
|
|
|
359
|
-
###
|
|
545
|
+
### CactusModel
|
|
360
546
|
|
|
361
547
|
```typescript
|
|
362
548
|
interface CactusModel {
|
|
@@ -386,4 +572,14 @@ CactusConfig.telemetryToken = 'your-token-here';
|
|
|
386
572
|
|
|
387
573
|
// Disable telemetry
|
|
388
574
|
CactusConfig.isTelemetryEnabled = false;
|
|
389
|
-
```
|
|
575
|
+
```
|
|
576
|
+
|
|
577
|
+
## Performance Tips
|
|
578
|
+
|
|
579
|
+
- **Model Selection** - Choose smaller models for faster inference on mobile devices.
|
|
580
|
+
- **Context Size** - Reduce the context size to lower memory usage.
|
|
581
|
+
- **Memory Management** - Always call `destroy()` when you're done with models to free up resources.
|
|
582
|
+
|
|
583
|
+
## Example App
|
|
584
|
+
|
|
585
|
+
Check out [our example app](/example) for a complete React Native implementation.
|
|
Binary file
|
package/cpp/HybridCactus.cpp
CHANGED
|
@@ -1,30 +1,41 @@
|
|
|
1
1
|
#include "HybridCactus.hpp"
|
|
2
2
|
|
|
3
|
-
namespace margelo::nitro::cactus
|
|
4
|
-
{
|
|
3
|
+
namespace margelo::nitro::cactus {
|
|
5
4
|
HybridCactus::HybridCactus() : HybridObject(TAG) {}
|
|
6
5
|
|
|
7
|
-
std::shared_ptr<Promise<void>>
|
|
8
|
-
|
|
9
|
-
|
|
6
|
+
std::shared_ptr<Promise<void>>
|
|
7
|
+
HybridCactus::init(const std::string &modelPath, double contextSize,
|
|
8
|
+
const std::optional<std::string> &corpusDir) {
|
|
9
|
+
return Promise<void>::async(
|
|
10
|
+
[this, modelPath, contextSize, corpusDir]() -> void {
|
|
11
|
+
std::lock_guard<std::mutex> lock(this->_modelMutex);
|
|
10
12
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
13
|
+
if (this->_model) {
|
|
14
|
+
throw std::runtime_error("Cactus model is already initialized");
|
|
15
|
+
}
|
|
14
16
|
|
|
15
|
-
|
|
17
|
+
const cactus_model_t model =
|
|
18
|
+
cactus_init(modelPath.c_str(), contextSize,
|
|
19
|
+
corpusDir ? corpusDir->c_str() : nullptr);
|
|
16
20
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
21
|
+
if (!model) {
|
|
22
|
+
throw std::runtime_error("Failed to initialize Cactus model");
|
|
23
|
+
}
|
|
20
24
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
25
|
+
this->_model = model;
|
|
26
|
+
this->_contextSize = contextSize;
|
|
27
|
+
});
|
|
24
28
|
}
|
|
25
29
|
|
|
26
|
-
std::shared_ptr<Promise<std::string>> HybridCactus::complete(
|
|
27
|
-
|
|
30
|
+
std::shared_ptr<Promise<std::string>> HybridCactus::complete(
|
|
31
|
+
const std::string &messagesJson, double responseBufferSize,
|
|
32
|
+
const std::optional<std::string> &optionsJson,
|
|
33
|
+
const std::optional<std::string> &toolsJson,
|
|
34
|
+
const std::optional<std::function<void(const std::string & /* token */,
|
|
35
|
+
double /* tokenId */)>> &callback) {
|
|
36
|
+
return Promise<std::string>::async([this, messagesJson, optionsJson,
|
|
37
|
+
toolsJson, callback,
|
|
38
|
+
responseBufferSize]() -> std::string {
|
|
28
39
|
std::lock_guard<std::mutex> lock(this->_modelMutex);
|
|
29
40
|
|
|
30
41
|
if (!this->_model) {
|
|
@@ -32,28 +43,26 @@ std::shared_ptr<Promise<std::string>> HybridCactus::complete(const std::string &
|
|
|
32
43
|
}
|
|
33
44
|
|
|
34
45
|
struct CallbackCtx {
|
|
35
|
-
const std::function<void(const std::string & /* token */,
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
46
|
+
const std::function<void(const std::string & /* token */,
|
|
47
|
+
double /* tokenId */)> *callback;
|
|
48
|
+
} callbackCtx{callback.has_value() ? &callback.value() : nullptr};
|
|
49
|
+
|
|
50
|
+
auto cactusTokenCallback = [](const char *token, uint32_t tokenId,
|
|
51
|
+
void *userData) {
|
|
52
|
+
auto *callbackCtx = static_cast<CallbackCtx *>(userData);
|
|
53
|
+
if (!callbackCtx || !callbackCtx->callback || !(*callbackCtx->callback))
|
|
54
|
+
return;
|
|
41
55
|
(*callbackCtx->callback)(token, tokenId);
|
|
42
56
|
};
|
|
43
57
|
|
|
44
58
|
std::string responseBuffer;
|
|
45
59
|
responseBuffer.resize(responseBufferSize);
|
|
46
60
|
|
|
47
|
-
int result = cactus_complete(
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
optionsJson ? optionsJson->c_str() : nullptr,
|
|
53
|
-
toolsJson ? toolsJson->c_str() : nullptr,
|
|
54
|
-
cactusTokenCallback,
|
|
55
|
-
&callbackCtx
|
|
56
|
-
);
|
|
61
|
+
int result = cactus_complete(this->_model, messagesJson.c_str(),
|
|
62
|
+
responseBuffer.data(), responseBufferSize,
|
|
63
|
+
optionsJson ? optionsJson->c_str() : nullptr,
|
|
64
|
+
toolsJson ? toolsJson->c_str() : nullptr,
|
|
65
|
+
cactusTokenCallback, &callbackCtx);
|
|
57
66
|
|
|
58
67
|
if (result < 0) {
|
|
59
68
|
throw std::runtime_error("Cactus completion failed");
|
|
@@ -66,27 +75,32 @@ std::shared_ptr<Promise<std::string>> HybridCactus::complete(const std::string &
|
|
|
66
75
|
});
|
|
67
76
|
}
|
|
68
77
|
|
|
69
|
-
std::shared_ptr<Promise<std::vector<double>>>
|
|
70
|
-
|
|
71
|
-
|
|
78
|
+
std::shared_ptr<Promise<std::vector<double>>>
|
|
79
|
+
HybridCactus::embed(const std::string &text, double embeddingBufferSize) {
|
|
80
|
+
return Promise<std::vector<double>>::async(
|
|
81
|
+
[this, text, embeddingBufferSize]() -> std::vector<double> {
|
|
82
|
+
std::lock_guard<std::mutex> lock(this->_modelMutex);
|
|
72
83
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
84
|
+
if (!this->_model) {
|
|
85
|
+
throw std::runtime_error("Cactus model is not initialized");
|
|
86
|
+
}
|
|
76
87
|
|
|
77
|
-
|
|
78
|
-
|
|
88
|
+
std::vector<float> embeddingBuffer(embeddingBufferSize);
|
|
89
|
+
size_t embeddingDim;
|
|
79
90
|
|
|
80
|
-
|
|
91
|
+
int result =
|
|
92
|
+
cactus_embed(this->_model, text.c_str(), embeddingBuffer.data(),
|
|
93
|
+
embeddingBufferSize * sizeof(float), &embeddingDim);
|
|
81
94
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
95
|
+
if (result < 0) {
|
|
96
|
+
throw std::runtime_error("Cactus embedding failed");
|
|
97
|
+
}
|
|
85
98
|
|
|
86
|
-
|
|
99
|
+
embeddingBuffer.resize(embeddingDim);
|
|
87
100
|
|
|
88
|
-
|
|
89
|
-
|
|
101
|
+
return std::vector<double>(embeddingBuffer.begin(),
|
|
102
|
+
embeddingBuffer.end());
|
|
103
|
+
});
|
|
90
104
|
}
|
|
91
105
|
|
|
92
106
|
std::shared_ptr<Promise<void>> HybridCactus::reset() {
|
|
@@ -102,9 +116,7 @@ std::shared_ptr<Promise<void>> HybridCactus::reset() {
|
|
|
102
116
|
}
|
|
103
117
|
|
|
104
118
|
std::shared_ptr<Promise<void>> HybridCactus::stop() {
|
|
105
|
-
return Promise<void>::async([this]() -> void {
|
|
106
|
-
cactus_stop(this->_model);
|
|
107
|
-
});
|
|
119
|
+
return Promise<void>::async([this]() -> void { cactus_stop(this->_model); });
|
|
108
120
|
}
|
|
109
121
|
|
|
110
122
|
std::shared_ptr<Promise<void>> HybridCactus::destroy() {
|
package/cpp/HybridCactus.hpp
CHANGED
|
@@ -5,26 +5,33 @@
|
|
|
5
5
|
|
|
6
6
|
#include <mutex>
|
|
7
7
|
|
|
8
|
-
namespace margelo::nitro::cactus
|
|
9
|
-
{
|
|
8
|
+
namespace margelo::nitro::cactus {
|
|
10
9
|
|
|
11
|
-
class HybridCactus : public HybridCactusSpec
|
|
12
|
-
{
|
|
10
|
+
class HybridCactus : public HybridCactusSpec {
|
|
13
11
|
public:
|
|
14
12
|
HybridCactus();
|
|
15
|
-
|
|
16
|
-
std::shared_ptr<Promise<void>>
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
std::shared_ptr<Promise<std::
|
|
21
|
-
|
|
13
|
+
|
|
14
|
+
std::shared_ptr<Promise<void>>
|
|
15
|
+
init(const std::string &modelPath, double contextSize,
|
|
16
|
+
const std::optional<std::string> &corpusDir) override;
|
|
17
|
+
|
|
18
|
+
std::shared_ptr<Promise<std::string>> complete(
|
|
19
|
+
const std::string &messagesJson, double responseBufferSize,
|
|
20
|
+
const std::optional<std::string> &optionsJson,
|
|
21
|
+
const std::optional<std::string> &toolsJson,
|
|
22
|
+
const std::optional<std::function<void(const std::string & /* token */,
|
|
23
|
+
double /* tokenId */)>> &callback)
|
|
24
|
+
override;
|
|
25
|
+
|
|
26
|
+
std::shared_ptr<Promise<std::vector<double>>>
|
|
27
|
+
embed(const std::string &text, double embeddingBufferSize) override;
|
|
28
|
+
|
|
22
29
|
std::shared_ptr<Promise<void>> reset() override;
|
|
23
|
-
|
|
30
|
+
|
|
24
31
|
std::shared_ptr<Promise<void>> stop() override;
|
|
25
|
-
|
|
32
|
+
|
|
26
33
|
std::shared_ptr<Promise<void>> destroy() override;
|
|
27
|
-
|
|
34
|
+
|
|
28
35
|
private:
|
|
29
36
|
cactus_model_t _model = nullptr;
|
|
30
37
|
size_t _contextSize;
|