cactus-react-native 0.1.0 → 0.1.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/android/src/main/CMakeLists.txt +0 -4
- package/android/src/main/java/com/cactus/Cactus.java +179 -42
- package/android/src/main/java/com/cactus/LlamaContext.java +22 -0
- package/android/src/main/jni.cpp +53 -1
- package/android/src/main/jniLibs/arm64-v8a/libcactus.so +0 -0
- package/android/src/main/jniLibs/arm64-v8a/libcactus_v8.so +0 -0
- package/android/src/main/jniLibs/arm64-v8a/libcactus_v8_2.so +0 -0
- package/android/src/main/jniLibs/arm64-v8a/libcactus_v8_2_dotprod.so +0 -0
- package/android/src/main/jniLibs/arm64-v8a/libcactus_v8_2_dotprod_i8mm.so +0 -0
- package/android/src/main/jniLibs/arm64-v8a/libcactus_v8_2_i8mm.so +0 -0
- package/android/src/main/jniLibs/x86_64/libcactus.so +0 -0
- package/android/src/main/jniLibs/x86_64/libcactus_x86_64.so +0 -0
- package/android/src/newarch/java/com/cactus/CactusModule.java +20 -0
- package/android/src/oldarch/java/com/cactus/CactusModule.java +20 -0
- package/ios/CMakeLists.txt +2 -0
- package/ios/Cactus.mm +80 -0
- package/ios/CactusContext.h +6 -0
- package/ios/CactusContext.mm +27 -0
- package/ios/cactus.xcframework/ios-arm64/cactus.framework/Headers/cactus.h +18 -0
- package/ios/cactus.xcframework/ios-arm64/cactus.framework/Headers/cactus_ffi.h +39 -0
- package/ios/cactus.xcframework/ios-arm64/cactus.framework/cactus +0 -0
- package/ios/cactus.xcframework/ios-arm64_x86_64-simulator/cactus.framework/Headers/cactus.h +18 -0
- package/ios/cactus.xcframework/ios-arm64_x86_64-simulator/cactus.framework/Headers/cactus_ffi.h +39 -0
- package/ios/cactus.xcframework/ios-arm64_x86_64-simulator/cactus.framework/cactus +0 -0
- package/ios/cactus.xcframework/tvos-arm64/cactus.framework/Headers/cactus.h +18 -0
- package/ios/cactus.xcframework/tvos-arm64/cactus.framework/Headers/cactus_ffi.h +39 -0
- package/ios/cactus.xcframework/tvos-arm64/cactus.framework/cactus +0 -0
- package/ios/cactus.xcframework/tvos-arm64_x86_64-simulator/cactus.framework/Headers/cactus.h +18 -0
- package/ios/cactus.xcframework/tvos-arm64_x86_64-simulator/cactus.framework/Headers/cactus_ffi.h +39 -0
- package/ios/cactus.xcframework/tvos-arm64_x86_64-simulator/cactus.framework/cactus +0 -0
- package/lib/commonjs/NativeCactus.js +1 -0
- package/lib/commonjs/NativeCactus.js.map +1 -1
- package/lib/commonjs/index.js +29 -0
- package/lib/commonjs/index.js.map +1 -1
- package/lib/module/NativeCactus.js +2 -0
- package/lib/module/NativeCactus.js.map +1 -1
- package/lib/module/index.js +29 -0
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/NativeCactus.d.ts +10 -0
- package/lib/typescript/NativeCactus.d.ts.map +1 -1
- package/lib/typescript/index.d.ts +17 -1
- package/lib/typescript/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/NativeCactus.ts +22 -0
- package/src/index.ts +36 -0
|
@@ -3,11 +3,8 @@ cmake_minimum_required(VERSION 3.10)
|
|
|
3
3
|
project(cactus)
|
|
4
4
|
|
|
5
5
|
set(CMAKE_CXX_STANDARD 17)
|
|
6
|
-
|
|
7
|
-
# Use cactus as the C++ source directory
|
|
8
6
|
set(SOURCE_DIR ${CMAKE_SOURCE_DIR}/../../../../cactus)
|
|
9
7
|
|
|
10
|
-
# Include directories to match cactus core structure
|
|
11
8
|
include_directories(${SOURCE_DIR})
|
|
12
9
|
include_directories(${SOURCE_DIR}/ggml-cpu)
|
|
13
10
|
include_directories(${SOURCE_DIR}/minja)
|
|
@@ -127,7 +124,6 @@ function(build_library target_name cpu_flags)
|
|
|
127
124
|
|
|
128
125
|
endfunction()
|
|
129
126
|
|
|
130
|
-
# Default target (no specific CPU features)
|
|
131
127
|
build_library("cactus" "")
|
|
132
128
|
|
|
133
129
|
if (${ANDROID_ABI} STREQUAL "arm64-v8a")
|
|
@@ -21,11 +21,14 @@ import java.util.Random;
|
|
|
21
21
|
import java.io.File;
|
|
22
22
|
import java.io.FileInputStream;
|
|
23
23
|
import java.io.PushbackInputStream;
|
|
24
|
+
import java.util.concurrent.ExecutorService;
|
|
25
|
+
import java.util.concurrent.Executors;
|
|
24
26
|
|
|
25
27
|
public class Cactus implements LifecycleEventListener {
|
|
26
28
|
public static final String NAME = "Cactus";
|
|
27
29
|
|
|
28
30
|
private ReactApplicationContext reactContext;
|
|
31
|
+
private final ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
|
|
29
32
|
|
|
30
33
|
public Cactus(ReactApplicationContext reactContext) {
|
|
31
34
|
reactContext.addLifecycleEventListener(this);
|
|
@@ -95,7 +98,7 @@ public class Cactus implements LifecycleEventListener {
|
|
|
95
98
|
}
|
|
96
99
|
promise.resolve(result);
|
|
97
100
|
}
|
|
98
|
-
}.executeOnExecutor(
|
|
101
|
+
}.executeOnExecutor(singleThreadExecutor);
|
|
99
102
|
}
|
|
100
103
|
|
|
101
104
|
public void initContext(double id, final ReadableMap params, final Promise promise) {
|
|
@@ -139,7 +142,7 @@ public class Cactus implements LifecycleEventListener {
|
|
|
139
142
|
promise.resolve(result);
|
|
140
143
|
tasks.remove(this);
|
|
141
144
|
}
|
|
142
|
-
}.executeOnExecutor(
|
|
145
|
+
}.executeOnExecutor(singleThreadExecutor);
|
|
143
146
|
tasks.put(task, "initContext");
|
|
144
147
|
}
|
|
145
148
|
|
|
@@ -178,7 +181,7 @@ public class Cactus implements LifecycleEventListener {
|
|
|
178
181
|
promise.resolve(result);
|
|
179
182
|
tasks.remove(this);
|
|
180
183
|
}
|
|
181
|
-
}.executeOnExecutor(
|
|
184
|
+
}.executeOnExecutor(singleThreadExecutor);
|
|
182
185
|
tasks.put(task, "getFormattedChat-" + contextId);
|
|
183
186
|
}
|
|
184
187
|
|
|
@@ -211,7 +214,7 @@ public class Cactus implements LifecycleEventListener {
|
|
|
211
214
|
promise.resolve(result);
|
|
212
215
|
tasks.remove(this);
|
|
213
216
|
}
|
|
214
|
-
}.executeOnExecutor(
|
|
217
|
+
}.executeOnExecutor(singleThreadExecutor);
|
|
215
218
|
tasks.put(task, "loadSession-" + contextId);
|
|
216
219
|
}
|
|
217
220
|
|
|
@@ -244,12 +247,12 @@ public class Cactus implements LifecycleEventListener {
|
|
|
244
247
|
promise.resolve(result);
|
|
245
248
|
tasks.remove(this);
|
|
246
249
|
}
|
|
247
|
-
}.executeOnExecutor(
|
|
250
|
+
}.executeOnExecutor(singleThreadExecutor);
|
|
248
251
|
tasks.put(task, "saveSession-" + contextId);
|
|
249
252
|
}
|
|
250
253
|
|
|
251
254
|
public void completion(double id, final ReadableMap params, final Promise promise) {
|
|
252
|
-
Log.d(NAME, "
|
|
255
|
+
Log.d(NAME, "BRIDGE: completion() method called with contextId=" + (int)id);
|
|
253
256
|
final int contextId = (int) id;
|
|
254
257
|
AsyncTask task = new AsyncTask<Void, Void, WritableMap>() {
|
|
255
258
|
private Exception exception;
|
|
@@ -260,20 +263,20 @@ public class Cactus implements LifecycleEventListener {
|
|
|
260
263
|
try {
|
|
261
264
|
LlamaContext context = contexts.get(contextId);
|
|
262
265
|
if (context == null) {
|
|
263
|
-
Log.e(NAME, "
|
|
266
|
+
Log.e(NAME, "BRIDGE: Context not found for id=" + contextId);
|
|
264
267
|
throw new Exception("Context not found");
|
|
265
268
|
}
|
|
266
|
-
Log.d(NAME, "
|
|
269
|
+
Log.d(NAME, "BRIDGE: Context found, checking if predicting...");
|
|
267
270
|
if (context.isPredicting()) {
|
|
268
|
-
Log.e(NAME, "
|
|
271
|
+
Log.e(NAME, "BRIDGE: Context is busy (predicting)");
|
|
269
272
|
throw new Exception("Context is busy");
|
|
270
273
|
}
|
|
271
|
-
Log.d(NAME, "
|
|
274
|
+
Log.d(NAME, "BRIDGE: About to call context.completion()...");
|
|
272
275
|
WritableMap result = context.completion(params);
|
|
273
|
-
Log.d(NAME, "
|
|
276
|
+
Log.d(NAME, "BRIDGE: context.completion() returned successfully");
|
|
274
277
|
return result;
|
|
275
278
|
} catch (Exception e) {
|
|
276
|
-
Log.e(NAME, "
|
|
279
|
+
Log.e(NAME, "BRIDGE: Exception in doInBackground: " + e.getMessage());
|
|
277
280
|
exception = e;
|
|
278
281
|
}
|
|
279
282
|
return null;
|
|
@@ -281,19 +284,19 @@ public class Cactus implements LifecycleEventListener {
|
|
|
281
284
|
|
|
282
285
|
@Override
|
|
283
286
|
protected void onPostExecute(WritableMap result) {
|
|
284
|
-
Log.d(NAME, "
|
|
287
|
+
Log.d(NAME, "BRIDGE: onPostExecute called");
|
|
285
288
|
if (exception != null) {
|
|
286
|
-
Log.e(NAME, "
|
|
289
|
+
Log.e(NAME, "BRIDGE: Rejecting promise with exception: " + exception.getMessage());
|
|
287
290
|
promise.reject(exception);
|
|
288
291
|
return;
|
|
289
292
|
}
|
|
290
|
-
Log.d(NAME, "
|
|
293
|
+
Log.d(NAME, "BRIDGE: Resolving promise with result");
|
|
291
294
|
promise.resolve(result);
|
|
292
295
|
tasks.remove(this);
|
|
293
|
-
Log.d(NAME, "
|
|
296
|
+
Log.d(NAME, "BRIDGE: completion() finished successfully");
|
|
294
297
|
}
|
|
295
|
-
}.executeOnExecutor(
|
|
296
|
-
Log.d(NAME, "
|
|
298
|
+
}.executeOnExecutor(singleThreadExecutor);
|
|
299
|
+
Log.d(NAME, "BRIDGE: AsyncTask queued for execution");
|
|
297
300
|
tasks.put(task, "completion-" + contextId);
|
|
298
301
|
}
|
|
299
302
|
|
|
@@ -332,7 +335,7 @@ public class Cactus implements LifecycleEventListener {
|
|
|
332
335
|
promise.resolve(result);
|
|
333
336
|
tasks.remove(this);
|
|
334
337
|
}
|
|
335
|
-
}.executeOnExecutor(
|
|
338
|
+
}.executeOnExecutor(singleThreadExecutor);
|
|
336
339
|
tasks.put(task, "stopCompletion-" + contextId);
|
|
337
340
|
}
|
|
338
341
|
|
|
@@ -364,7 +367,7 @@ public class Cactus implements LifecycleEventListener {
|
|
|
364
367
|
promise.resolve(result);
|
|
365
368
|
tasks.remove(this);
|
|
366
369
|
}
|
|
367
|
-
}.executeOnExecutor(
|
|
370
|
+
}.executeOnExecutor(singleThreadExecutor);
|
|
368
371
|
tasks.put(task, "tokenize-" + contextId);
|
|
369
372
|
}
|
|
370
373
|
|
|
@@ -396,7 +399,7 @@ public class Cactus implements LifecycleEventListener {
|
|
|
396
399
|
promise.resolve(result);
|
|
397
400
|
tasks.remove(this);
|
|
398
401
|
}
|
|
399
|
-
}.executeOnExecutor(
|
|
402
|
+
}.executeOnExecutor(singleThreadExecutor);
|
|
400
403
|
tasks.put(task, "tokenize-" + contextId);
|
|
401
404
|
}
|
|
402
405
|
|
|
@@ -428,7 +431,7 @@ public class Cactus implements LifecycleEventListener {
|
|
|
428
431
|
promise.resolve(result);
|
|
429
432
|
tasks.remove(this);
|
|
430
433
|
}
|
|
431
|
-
}.executeOnExecutor(
|
|
434
|
+
}.executeOnExecutor(singleThreadExecutor);
|
|
432
435
|
tasks.put(task, "detokenize-" + contextId);
|
|
433
436
|
}
|
|
434
437
|
|
|
@@ -460,7 +463,7 @@ public class Cactus implements LifecycleEventListener {
|
|
|
460
463
|
promise.resolve(result);
|
|
461
464
|
tasks.remove(this);
|
|
462
465
|
}
|
|
463
|
-
}.executeOnExecutor(
|
|
466
|
+
}.executeOnExecutor(singleThreadExecutor);
|
|
464
467
|
tasks.put(task, "embedding-" + contextId);
|
|
465
468
|
}
|
|
466
469
|
|
|
@@ -492,7 +495,7 @@ public class Cactus implements LifecycleEventListener {
|
|
|
492
495
|
promise.resolve(result);
|
|
493
496
|
tasks.remove(this);
|
|
494
497
|
}
|
|
495
|
-
}.executeOnExecutor(
|
|
498
|
+
}.executeOnExecutor(singleThreadExecutor);
|
|
496
499
|
tasks.put(task, "bench-" + contextId);
|
|
497
500
|
}
|
|
498
501
|
|
|
@@ -525,7 +528,7 @@ public class Cactus implements LifecycleEventListener {
|
|
|
525
528
|
return;
|
|
526
529
|
}
|
|
527
530
|
}
|
|
528
|
-
}.executeOnExecutor(
|
|
531
|
+
}.executeOnExecutor(singleThreadExecutor);
|
|
529
532
|
tasks.put(task, "applyLoraAdapters-" + contextId);
|
|
530
533
|
}
|
|
531
534
|
|
|
@@ -559,7 +562,7 @@ public class Cactus implements LifecycleEventListener {
|
|
|
559
562
|
}
|
|
560
563
|
promise.resolve(null);
|
|
561
564
|
}
|
|
562
|
-
}.executeOnExecutor(
|
|
565
|
+
}.executeOnExecutor(singleThreadExecutor);
|
|
563
566
|
tasks.put(task, "removeLoraAdapters-" + contextId);
|
|
564
567
|
}
|
|
565
568
|
|
|
@@ -590,7 +593,7 @@ public class Cactus implements LifecycleEventListener {
|
|
|
590
593
|
}
|
|
591
594
|
promise.resolve(result);
|
|
592
595
|
}
|
|
593
|
-
}.executeOnExecutor(
|
|
596
|
+
}.executeOnExecutor(singleThreadExecutor);
|
|
594
597
|
tasks.put(task, "getLoadedLoraAdapters-" + contextId);
|
|
595
598
|
}
|
|
596
599
|
|
|
@@ -632,7 +635,7 @@ public class Cactus implements LifecycleEventListener {
|
|
|
632
635
|
promise.resolve(null);
|
|
633
636
|
tasks.remove(this);
|
|
634
637
|
}
|
|
635
|
-
}.executeOnExecutor(
|
|
638
|
+
}.executeOnExecutor(singleThreadExecutor);
|
|
636
639
|
tasks.put(task, "releaseContext-" + contextId);
|
|
637
640
|
}
|
|
638
641
|
|
|
@@ -659,7 +662,7 @@ public class Cactus implements LifecycleEventListener {
|
|
|
659
662
|
promise.resolve(null);
|
|
660
663
|
tasks.remove(this);
|
|
661
664
|
}
|
|
662
|
-
}.executeOnExecutor(
|
|
665
|
+
}.executeOnExecutor(singleThreadExecutor);
|
|
663
666
|
tasks.put(task, "releaseAllContexts");
|
|
664
667
|
}
|
|
665
668
|
|
|
@@ -718,7 +721,7 @@ public class Cactus implements LifecycleEventListener {
|
|
|
718
721
|
promise.resolve(result);
|
|
719
722
|
tasks.remove(this);
|
|
720
723
|
}
|
|
721
|
-
}.executeOnExecutor(
|
|
724
|
+
}.executeOnExecutor(singleThreadExecutor);
|
|
722
725
|
tasks.put(task, "initMultimodal-" + contextId);
|
|
723
726
|
}
|
|
724
727
|
|
|
@@ -750,7 +753,7 @@ public class Cactus implements LifecycleEventListener {
|
|
|
750
753
|
promise.resolve(result);
|
|
751
754
|
tasks.remove(this);
|
|
752
755
|
}
|
|
753
|
-
}.executeOnExecutor(
|
|
756
|
+
}.executeOnExecutor(singleThreadExecutor);
|
|
754
757
|
tasks.put(task, "isMultimodalEnabled-" + contextId);
|
|
755
758
|
}
|
|
756
759
|
|
|
@@ -782,7 +785,7 @@ public class Cactus implements LifecycleEventListener {
|
|
|
782
785
|
promise.resolve(result);
|
|
783
786
|
tasks.remove(this);
|
|
784
787
|
}
|
|
785
|
-
}.executeOnExecutor(
|
|
788
|
+
}.executeOnExecutor(singleThreadExecutor);
|
|
786
789
|
tasks.put(task, "isMultimodalSupportVision-" + contextId);
|
|
787
790
|
}
|
|
788
791
|
|
|
@@ -814,7 +817,7 @@ public class Cactus implements LifecycleEventListener {
|
|
|
814
817
|
promise.resolve(result);
|
|
815
818
|
tasks.remove(this);
|
|
816
819
|
}
|
|
817
|
-
}.executeOnExecutor(
|
|
820
|
+
}.executeOnExecutor(singleThreadExecutor);
|
|
818
821
|
tasks.put(task, "isMultimodalSupportAudio-" + contextId);
|
|
819
822
|
}
|
|
820
823
|
|
|
@@ -846,7 +849,7 @@ public class Cactus implements LifecycleEventListener {
|
|
|
846
849
|
promise.resolve(null);
|
|
847
850
|
tasks.remove(this);
|
|
848
851
|
}
|
|
849
|
-
}.executeOnExecutor(
|
|
852
|
+
}.executeOnExecutor(singleThreadExecutor);
|
|
850
853
|
tasks.put(task, "releaseMultimodal-" + contextId);
|
|
851
854
|
}
|
|
852
855
|
|
|
@@ -881,7 +884,7 @@ public class Cactus implements LifecycleEventListener {
|
|
|
881
884
|
promise.resolve(result);
|
|
882
885
|
tasks.remove(this);
|
|
883
886
|
}
|
|
884
|
-
}.executeOnExecutor(
|
|
887
|
+
}.executeOnExecutor(singleThreadExecutor);
|
|
885
888
|
tasks.put(task, "multimodalCompletion-" + contextId);
|
|
886
889
|
}
|
|
887
890
|
|
|
@@ -913,7 +916,7 @@ public class Cactus implements LifecycleEventListener {
|
|
|
913
916
|
promise.resolve(result);
|
|
914
917
|
tasks.remove(this);
|
|
915
918
|
}
|
|
916
|
-
}.executeOnExecutor(
|
|
919
|
+
}.executeOnExecutor(singleThreadExecutor);
|
|
917
920
|
tasks.put(task, "initVocoder-" + contextId);
|
|
918
921
|
}
|
|
919
922
|
|
|
@@ -945,7 +948,7 @@ public class Cactus implements LifecycleEventListener {
|
|
|
945
948
|
promise.resolve(result);
|
|
946
949
|
tasks.remove(this);
|
|
947
950
|
}
|
|
948
|
-
}.executeOnExecutor(
|
|
951
|
+
}.executeOnExecutor(singleThreadExecutor);
|
|
949
952
|
tasks.put(task, "isVocoderEnabled-" + contextId);
|
|
950
953
|
}
|
|
951
954
|
|
|
@@ -977,7 +980,7 @@ public class Cactus implements LifecycleEventListener {
|
|
|
977
980
|
promise.resolve(result);
|
|
978
981
|
tasks.remove(this);
|
|
979
982
|
}
|
|
980
|
-
}.executeOnExecutor(
|
|
983
|
+
}.executeOnExecutor(singleThreadExecutor);
|
|
981
984
|
tasks.put(task, "getTTSType-" + contextId);
|
|
982
985
|
}
|
|
983
986
|
|
|
@@ -1009,7 +1012,7 @@ public class Cactus implements LifecycleEventListener {
|
|
|
1009
1012
|
promise.resolve(result);
|
|
1010
1013
|
tasks.remove(this);
|
|
1011
1014
|
}
|
|
1012
|
-
}.executeOnExecutor(
|
|
1015
|
+
}.executeOnExecutor(singleThreadExecutor);
|
|
1013
1016
|
tasks.put(task, "getFormattedAudioCompletion-" + contextId);
|
|
1014
1017
|
}
|
|
1015
1018
|
|
|
@@ -1041,7 +1044,7 @@ public class Cactus implements LifecycleEventListener {
|
|
|
1041
1044
|
promise.resolve(result);
|
|
1042
1045
|
tasks.remove(this);
|
|
1043
1046
|
}
|
|
1044
|
-
}.executeOnExecutor(
|
|
1047
|
+
}.executeOnExecutor(singleThreadExecutor);
|
|
1045
1048
|
tasks.put(task, "getAudioCompletionGuideTokens-" + contextId);
|
|
1046
1049
|
}
|
|
1047
1050
|
|
|
@@ -1073,7 +1076,7 @@ public class Cactus implements LifecycleEventListener {
|
|
|
1073
1076
|
promise.resolve(result);
|
|
1074
1077
|
tasks.remove(this);
|
|
1075
1078
|
}
|
|
1076
|
-
}.executeOnExecutor(
|
|
1079
|
+
}.executeOnExecutor(singleThreadExecutor);
|
|
1077
1080
|
tasks.put(task, "decodeAudioTokens-" + contextId);
|
|
1078
1081
|
}
|
|
1079
1082
|
|
|
@@ -1105,7 +1108,141 @@ public class Cactus implements LifecycleEventListener {
|
|
|
1105
1108
|
promise.resolve(null);
|
|
1106
1109
|
tasks.remove(this);
|
|
1107
1110
|
}
|
|
1108
|
-
}.executeOnExecutor(
|
|
1111
|
+
}.executeOnExecutor(singleThreadExecutor);
|
|
1109
1112
|
tasks.put(task, "releaseVocoder-" + contextId);
|
|
1110
1113
|
}
|
|
1114
|
+
|
|
1115
|
+
public void generateResponse(double id, final String userMessage, final double maxTokens, final Promise promise) {
|
|
1116
|
+
final int contextId = (int) id;
|
|
1117
|
+
AsyncTask task = new AsyncTask<Void, Void, String>() {
|
|
1118
|
+
private Exception exception;
|
|
1119
|
+
|
|
1120
|
+
@Override
|
|
1121
|
+
protected String doInBackground(Void... voids) {
|
|
1122
|
+
try {
|
|
1123
|
+
LlamaContext context = contexts.get(contextId);
|
|
1124
|
+
if (context == null) {
|
|
1125
|
+
throw new Exception("Context not found");
|
|
1126
|
+
}
|
|
1127
|
+
if (context.isPredicting()) {
|
|
1128
|
+
throw new Exception("Context is busy");
|
|
1129
|
+
}
|
|
1130
|
+
return context.generateResponse(userMessage, (int) maxTokens);
|
|
1131
|
+
} catch (Exception e) {
|
|
1132
|
+
exception = e;
|
|
1133
|
+
}
|
|
1134
|
+
return null;
|
|
1135
|
+
}
|
|
1136
|
+
|
|
1137
|
+
@Override
|
|
1138
|
+
protected void onPostExecute(String result) {
|
|
1139
|
+
if (exception != null) {
|
|
1140
|
+
promise.reject(exception);
|
|
1141
|
+
return;
|
|
1142
|
+
}
|
|
1143
|
+
promise.resolve(result);
|
|
1144
|
+
tasks.remove(this);
|
|
1145
|
+
}
|
|
1146
|
+
}.executeOnExecutor(singleThreadExecutor);
|
|
1147
|
+
tasks.put(task, "generateResponse-" + contextId);
|
|
1148
|
+
}
|
|
1149
|
+
|
|
1150
|
+
public void continueConversation(double id, final String userMessage, final double maxTokens, final Promise promise) {
|
|
1151
|
+
final int contextId = (int) id;
|
|
1152
|
+
AsyncTask task = new AsyncTask<Void, Void, WritableMap>() {
|
|
1153
|
+
private Exception exception;
|
|
1154
|
+
|
|
1155
|
+
@Override
|
|
1156
|
+
protected WritableMap doInBackground(Void... voids) {
|
|
1157
|
+
try {
|
|
1158
|
+
LlamaContext context = contexts.get(contextId);
|
|
1159
|
+
if (context == null) {
|
|
1160
|
+
throw new Exception("Context not found");
|
|
1161
|
+
}
|
|
1162
|
+
if (context.isPredicting()) {
|
|
1163
|
+
throw new Exception("Context is busy");
|
|
1164
|
+
}
|
|
1165
|
+
return context.continueConversation(userMessage, (int) maxTokens);
|
|
1166
|
+
} catch (Exception e) {
|
|
1167
|
+
exception = e;
|
|
1168
|
+
}
|
|
1169
|
+
return null;
|
|
1170
|
+
}
|
|
1171
|
+
|
|
1172
|
+
@Override
|
|
1173
|
+
protected void onPostExecute(WritableMap result) {
|
|
1174
|
+
if (exception != null) {
|
|
1175
|
+
promise.reject(exception);
|
|
1176
|
+
return;
|
|
1177
|
+
}
|
|
1178
|
+
promise.resolve(result);
|
|
1179
|
+
tasks.remove(this);
|
|
1180
|
+
}
|
|
1181
|
+
}.executeOnExecutor(singleThreadExecutor);
|
|
1182
|
+
tasks.put(task, "continueConversation-" + contextId);
|
|
1183
|
+
}
|
|
1184
|
+
|
|
1185
|
+
public void clearConversation(double id, final Promise promise) {
|
|
1186
|
+
final int contextId = (int) id;
|
|
1187
|
+
AsyncTask task = new AsyncTask<Void, Void, Void>() {
|
|
1188
|
+
private Exception exception;
|
|
1189
|
+
|
|
1190
|
+
@Override
|
|
1191
|
+
protected Void doInBackground(Void... voids) {
|
|
1192
|
+
try {
|
|
1193
|
+
LlamaContext context = contexts.get(contextId);
|
|
1194
|
+
if (context == null) {
|
|
1195
|
+
throw new Exception("Context not found");
|
|
1196
|
+
}
|
|
1197
|
+
context.clearConversation();
|
|
1198
|
+
} catch (Exception e) {
|
|
1199
|
+
exception = e;
|
|
1200
|
+
}
|
|
1201
|
+
return null;
|
|
1202
|
+
}
|
|
1203
|
+
|
|
1204
|
+
@Override
|
|
1205
|
+
protected void onPostExecute(Void result) {
|
|
1206
|
+
if (exception != null) {
|
|
1207
|
+
promise.reject(exception);
|
|
1208
|
+
return;
|
|
1209
|
+
}
|
|
1210
|
+
promise.resolve(null);
|
|
1211
|
+
tasks.remove(this);
|
|
1212
|
+
}
|
|
1213
|
+
}.executeOnExecutor(singleThreadExecutor);
|
|
1214
|
+
tasks.put(task, "clearConversation-" + contextId);
|
|
1215
|
+
}
|
|
1216
|
+
|
|
1217
|
+
public void isConversationActive(double id, final Promise promise) {
|
|
1218
|
+
final int contextId = (int) id;
|
|
1219
|
+
AsyncTask task = new AsyncTask<Void, Void, Boolean>() {
|
|
1220
|
+
private Exception exception;
|
|
1221
|
+
|
|
1222
|
+
@Override
|
|
1223
|
+
protected Boolean doInBackground(Void... voids) {
|
|
1224
|
+
try {
|
|
1225
|
+
LlamaContext context = contexts.get(contextId);
|
|
1226
|
+
if (context == null) {
|
|
1227
|
+
throw new Exception("Context not found");
|
|
1228
|
+
}
|
|
1229
|
+
return context.isConversationActive();
|
|
1230
|
+
} catch (Exception e) {
|
|
1231
|
+
exception = e;
|
|
1232
|
+
}
|
|
1233
|
+
return false;
|
|
1234
|
+
}
|
|
1235
|
+
|
|
1236
|
+
@Override
|
|
1237
|
+
protected void onPostExecute(Boolean result) {
|
|
1238
|
+
if (exception != null) {
|
|
1239
|
+
promise.reject(exception);
|
|
1240
|
+
return;
|
|
1241
|
+
}
|
|
1242
|
+
promise.resolve(result);
|
|
1243
|
+
tasks.remove(this);
|
|
1244
|
+
}
|
|
1245
|
+
}.executeOnExecutor(singleThreadExecutor);
|
|
1246
|
+
tasks.put(task, "isConversationActive-" + contextId);
|
|
1247
|
+
}
|
|
1111
1248
|
}
|
|
@@ -524,6 +524,22 @@ public class LlamaContext {
|
|
|
524
524
|
releaseVocoder(this.context);
|
|
525
525
|
}
|
|
526
526
|
|
|
527
|
+
public String generateResponse(String userMessage, int maxTokens) {
|
|
528
|
+
return generateResponse(this.context, userMessage, maxTokens);
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
public WritableMap continueConversation(String userMessage, int maxTokens) {
|
|
532
|
+
return continueConversation(this.context, userMessage, maxTokens);
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
public void clearConversation() {
|
|
536
|
+
clearConversation(this.context);
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
public boolean isConversationActive() {
|
|
540
|
+
return isConversationActive(this.context);
|
|
541
|
+
}
|
|
542
|
+
|
|
527
543
|
static {
|
|
528
544
|
Log.d(NAME, "Primary ABI: " + Build.SUPPORTED_ABIS[0]);
|
|
529
545
|
|
|
@@ -775,4 +791,10 @@ public class LlamaContext {
|
|
|
775
791
|
protected static native WritableArray getAudioCompletionGuideTokens(long contextPtr, String textToSpeak);
|
|
776
792
|
protected static native WritableArray decodeAudioTokens(long contextPtr, int[] tokens);
|
|
777
793
|
protected static native void releaseVocoder(long contextPtr);
|
|
794
|
+
|
|
795
|
+
// New conversation management methods
|
|
796
|
+
protected static native String generateResponse(long contextPtr, String userMessage, int maxTokens);
|
|
797
|
+
protected static native WritableMap continueConversation(long contextPtr, String userMessage, int maxTokens);
|
|
798
|
+
protected static native void clearConversation(long contextPtr);
|
|
799
|
+
protected static native boolean isConversationActive(long contextPtr);
|
|
778
800
|
}
|
package/android/src/main/jni.cpp
CHANGED
|
@@ -1563,7 +1563,59 @@ JNIEXPORT void JNICALL
|
|
|
1563
1563
|
Java_com_cactus_LlamaContext_unsetLog(JNIEnv *env, jobject thiz) {
|
|
1564
1564
|
UNUSED(env);
|
|
1565
1565
|
UNUSED(thiz);
|
|
1566
|
-
llama_log_set(cactus_log_callback_default,
|
|
1566
|
+
llama_log_set(cactus_log_callback_default, nullptr);
|
|
1567
|
+
}
|
|
1568
|
+
|
|
1569
|
+
JNIEXPORT jstring JNICALL
|
|
1570
|
+
Java_com_cactus_LlamaContext_generateResponse(
|
|
1571
|
+
JNIEnv *env, jobject thiz, jlong context_ptr, jstring user_message, jint max_tokens) {
|
|
1572
|
+
UNUSED(thiz);
|
|
1573
|
+
auto llama = context_map[(long) context_ptr];
|
|
1574
|
+
const char *user_message_chars = env->GetStringUTFChars(user_message, nullptr);
|
|
1575
|
+
|
|
1576
|
+
std::string result = llama->generateResponse(user_message_chars, max_tokens);
|
|
1577
|
+
llama->is_predicting = false;
|
|
1578
|
+
|
|
1579
|
+
env->ReleaseStringUTFChars(user_message, user_message_chars);
|
|
1580
|
+
return env->NewStringUTF(result.c_str());
|
|
1581
|
+
}
|
|
1582
|
+
|
|
1583
|
+
JNIEXPORT jobject JNICALL
|
|
1584
|
+
Java_com_cactus_LlamaContext_continueConversation(
|
|
1585
|
+
JNIEnv *env, jobject thiz, jlong context_ptr, jstring user_message, jint max_tokens) {
|
|
1586
|
+
UNUSED(thiz);
|
|
1587
|
+
auto llama = context_map[(long) context_ptr];
|
|
1588
|
+
const char *user_message_chars = env->GetStringUTFChars(user_message, nullptr);
|
|
1589
|
+
|
|
1590
|
+
cactus::conversation_result result = llama->continueConversation(user_message_chars, max_tokens);
|
|
1591
|
+
llama->is_predicting = false;
|
|
1592
|
+
|
|
1593
|
+
auto result_map = createWriteableMap(env);
|
|
1594
|
+
putString(env, result_map, "text", result.text.c_str());
|
|
1595
|
+
putInt(env, result_map, "time_to_first_token", result.time_to_first_token.count());
|
|
1596
|
+
putInt(env, result_map, "total_time", result.total_time.count());
|
|
1597
|
+
putInt(env, result_map, "tokens_generated", result.tokens_generated);
|
|
1598
|
+
|
|
1599
|
+
env->ReleaseStringUTFChars(user_message, user_message_chars);
|
|
1600
|
+
return reinterpret_cast<jobject>(result_map);
|
|
1601
|
+
}
|
|
1602
|
+
|
|
1603
|
+
JNIEXPORT void JNICALL
|
|
1604
|
+
Java_com_cactus_LlamaContext_clearConversation(
|
|
1605
|
+
JNIEnv *env, jobject thiz, jlong context_ptr) {
|
|
1606
|
+
UNUSED(thiz);
|
|
1607
|
+
UNUSED(env);
|
|
1608
|
+
auto llama = context_map[(long) context_ptr];
|
|
1609
|
+
llama->clearConversation();
|
|
1610
|
+
}
|
|
1611
|
+
|
|
1612
|
+
JNIEXPORT jboolean JNICALL
|
|
1613
|
+
Java_com_cactus_LlamaContext_isConversationActive(
|
|
1614
|
+
JNIEnv *env, jobject thiz, jlong context_ptr) {
|
|
1615
|
+
UNUSED(thiz);
|
|
1616
|
+
UNUSED(env);
|
|
1617
|
+
auto llama = context_map[(long) context_ptr];
|
|
1618
|
+
return llama->isConversationActive();
|
|
1567
1619
|
}
|
|
1568
1620
|
|
|
1569
1621
|
} // extern "C"
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -184,6 +184,26 @@ public class CactusModule extends NativeCactusSpec {
|
|
|
184
184
|
cactus.releaseVocoder(id, promise);
|
|
185
185
|
}
|
|
186
186
|
|
|
187
|
+
@ReactMethod
|
|
188
|
+
public void generateResponse(double id, String userMessage, Double maxTokens, Promise promise) {
|
|
189
|
+
cactus.generateResponse(id, userMessage, maxTokens != null ? maxTokens.doubleValue() : 200.0, promise);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
@ReactMethod
|
|
193
|
+
public void continueConversation(double id, String userMessage, Double maxTokens, Promise promise) {
|
|
194
|
+
cactus.continueConversation(id, userMessage, maxTokens != null ? maxTokens.doubleValue() : 200.0, promise);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
@ReactMethod
|
|
198
|
+
public void clearConversation(double id, Promise promise) {
|
|
199
|
+
cactus.clearConversation(id, promise);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
@ReactMethod
|
|
203
|
+
public void isConversationActive(double id, Promise promise) {
|
|
204
|
+
cactus.isConversationActive(id, promise);
|
|
205
|
+
}
|
|
206
|
+
|
|
187
207
|
@ReactMethod
|
|
188
208
|
public void releaseContext(double id, Promise promise) {
|
|
189
209
|
cactus.releaseContext(id, promise);
|
|
@@ -183,6 +183,26 @@ public class CactusModule extends ReactContextBaseJavaModule {
|
|
|
183
183
|
cactus.releaseVocoder(id, promise);
|
|
184
184
|
}
|
|
185
185
|
|
|
186
|
+
@ReactMethod
|
|
187
|
+
public void generateResponse(double id, final String userMessage, final Double maxTokens, final Promise promise) {
|
|
188
|
+
cactus.generateResponse(id, userMessage, maxTokens != null ? maxTokens.doubleValue() : 200.0, promise);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
@ReactMethod
|
|
192
|
+
public void continueConversation(double id, final String userMessage, final Double maxTokens, final Promise promise) {
|
|
193
|
+
cactus.continueConversation(id, userMessage, maxTokens != null ? maxTokens.doubleValue() : 200.0, promise);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
@ReactMethod
|
|
197
|
+
public void clearConversation(double id, final Promise promise) {
|
|
198
|
+
cactus.clearConversation(id, promise);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
@ReactMethod
|
|
202
|
+
public void isConversationActive(double id, final Promise promise) {
|
|
203
|
+
cactus.isConversationActive(id, promise);
|
|
204
|
+
}
|
|
205
|
+
|
|
186
206
|
@ReactMethod
|
|
187
207
|
public void releaseContext(double id, Promise promise) {
|
|
188
208
|
cactus.releaseContext(id, promise);
|
package/ios/CMakeLists.txt
CHANGED
|
@@ -24,6 +24,7 @@ set(SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../cactus)
|
|
|
24
24
|
# Define public headers
|
|
25
25
|
set(PUBLIC_HEADERS
|
|
26
26
|
${SOURCE_DIR}/cactus.h
|
|
27
|
+
${SOURCE_DIR}/cactus_ffi.h
|
|
27
28
|
${SOURCE_DIR}/llama.h
|
|
28
29
|
${SOURCE_DIR}/llama-impl.h
|
|
29
30
|
${SOURCE_DIR}/ggml.h
|
|
@@ -42,6 +43,7 @@ add_library(cactus SHARED
|
|
|
42
43
|
${SOURCE_DIR}/cactus_tts.cpp
|
|
43
44
|
${SOURCE_DIR}/cactus_bench.cpp
|
|
44
45
|
${SOURCE_DIR}/cactus_chat.cpp
|
|
46
|
+
${SOURCE_DIR}/cactus_ffi.cpp
|
|
45
47
|
${SOURCE_DIR}/tools/mtmd/mtmd.cpp
|
|
46
48
|
${SOURCE_DIR}/tools/mtmd/mtmd-audio.cpp
|
|
47
49
|
${SOURCE_DIR}/tools/mtmd/clip.cpp
|