llama-cpp-capacitor 0.0.13 → 0.0.21

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 (34) hide show
  1. package/LlamaCpp.podspec +17 -17
  2. package/Package.swift +27 -27
  3. package/README.md +717 -574
  4. package/android/build.gradle +88 -69
  5. package/android/src/main/AndroidManifest.xml +2 -2
  6. package/android/src/main/CMakeLists-arm64.txt +131 -0
  7. package/android/src/main/CMakeLists-x86_64.txt +135 -0
  8. package/android/src/main/CMakeLists.txt +35 -52
  9. package/android/src/main/java/ai/annadata/plugin/capacitor/LlamaCpp.java +956 -717
  10. package/android/src/main/java/ai/annadata/plugin/capacitor/LlamaCppPlugin.java +710 -590
  11. package/android/src/main/jni-utils.h +7 -7
  12. package/android/src/main/jni.cpp +868 -127
  13. package/cpp/{rn-completion.cpp → cap-completion.cpp} +202 -24
  14. package/cpp/{rn-completion.h → cap-completion.h} +22 -11
  15. package/cpp/{rn-llama.cpp → cap-llama.cpp} +81 -27
  16. package/cpp/{rn-llama.h → cap-llama.h} +32 -20
  17. package/cpp/{rn-mtmd.hpp → cap-mtmd.hpp} +15 -15
  18. package/cpp/{rn-tts.cpp → cap-tts.cpp} +12 -12
  19. package/cpp/{rn-tts.h → cap-tts.h} +14 -14
  20. package/cpp/ggml-cpu/ggml-cpu-impl.h +30 -0
  21. package/dist/docs.json +100 -3
  22. package/dist/esm/definitions.d.ts +45 -2
  23. package/dist/esm/definitions.js.map +1 -1
  24. package/dist/esm/index.d.ts +22 -0
  25. package/dist/esm/index.js +66 -3
  26. package/dist/esm/index.js.map +1 -1
  27. package/dist/plugin.cjs.js +71 -3
  28. package/dist/plugin.cjs.js.map +1 -1
  29. package/dist/plugin.js +71 -3
  30. package/dist/plugin.js.map +1 -1
  31. package/ios/Sources/LlamaCppPlugin/LlamaCpp.swift +596 -596
  32. package/ios/Sources/LlamaCppPlugin/LlamaCppPlugin.swift +591 -514
  33. package/ios/Tests/LlamaCppPluginTests/LlamaCppPluginTests.swift +15 -15
  34. package/package.json +111 -110
@@ -1,590 +1,710 @@
1
- package ai.annadata.plugin.capacitor;
2
-
3
- import android.util.Log;
4
- import com.getcapacitor.JSObject;
5
- import com.getcapacitor.JSArray;
6
- import com.getcapacitor.Plugin;
7
- import com.getcapacitor.PluginCall;
8
- import com.getcapacitor.PluginMethod;
9
- import com.getcapacitor.annotation.CapacitorPlugin;
10
- import java.util.Map;
11
- import org.json.JSONException;
12
-
13
- @CapacitorPlugin(name = "LlamaCpp")
14
- public class LlamaCppPlugin extends Plugin {
15
- private static final String TAG = "LlamaCppPlugin";
16
-
17
- private LlamaCpp implementation = new LlamaCpp();
18
-
19
- @Override
20
- public void load() {
21
- super.load();
22
- Log.i(TAG, "LlamaCppPlugin loaded successfully");
23
- }
24
-
25
- // MARK: - Core initialization and management
26
-
27
- @PluginMethod
28
- public void toggleNativeLog(PluginCall call) {
29
- boolean enabled = call.getBoolean("enabled", false);
30
- implementation.toggleNativeLog(enabled, result -> {
31
- if (result.isSuccess()) {
32
- call.resolve();
33
- } else {
34
- call.reject(result.getError().getMessage());
35
- }
36
- });
37
- }
38
-
39
- @PluginMethod
40
- public void setContextLimit(PluginCall call) {
41
- int limit = call.getInt("limit", 10);
42
- implementation.setContextLimit(limit, result -> {
43
- if (result.isSuccess()) {
44
- call.resolve();
45
- } else {
46
- call.reject(result.getError().getMessage());
47
- }
48
- });
49
- }
50
-
51
- @PluginMethod
52
- public void modelInfo(PluginCall call) {
53
- String path = call.getString("path", "");
54
- JSArray skipArray = call.getArray("skip");
55
- String[] skip = new String[0];
56
- if (skipArray != null) {
57
- skip = new String[skipArray.length()];
58
- for (int i = 0; i < skipArray.length(); i++) {
59
- try {
60
- skip[i] = skipArray.getString(i);
61
- } catch (JSONException e) {
62
- skip[i] = "";
63
- }
64
- }
65
- }
66
-
67
- implementation.modelInfo(path, skip, result -> {
68
- if (result.isSuccess()) {
69
- JSObject jsResult = new JSObject();
70
- Map<String, Object> data = result.getData();
71
- for (Map.Entry<String, Object> entry : data.entrySet()) {
72
- jsResult.put(entry.getKey(), entry.getValue());
73
- }
74
- call.resolve(jsResult);
75
- } else {
76
- call.reject(result.getError().getMessage());
77
- }
78
- });
79
- }
80
-
81
- @PluginMethod
82
- public void initContext(PluginCall call) {
83
- Log.i(TAG, "initContext called with contextId: " + call.getInt("contextId", 0));
84
- int contextId = call.getInt("contextId", 0);
85
- JSObject params = call.getObject("params", new JSObject());
86
-
87
- implementation.initContext(contextId, params, result -> {
88
- if (result.isSuccess()) {
89
- JSObject jsResult = new JSObject();
90
- Map<String, Object> data = result.getData();
91
- for (Map.Entry<String, Object> entry : data.entrySet()) {
92
- jsResult.put(entry.getKey(), entry.getValue());
93
- }
94
- call.resolve(jsResult);
95
- } else {
96
- call.reject(result.getError().getMessage());
97
- }
98
- });
99
- }
100
-
101
- @PluginMethod
102
- public void releaseContext(PluginCall call) {
103
- int contextId = call.getInt("contextId", 0);
104
-
105
- implementation.releaseContext(contextId, result -> {
106
- if (result.isSuccess()) {
107
- call.resolve();
108
- } else {
109
- call.reject(result.getError().getMessage());
110
- }
111
- });
112
- }
113
-
114
- @PluginMethod
115
- public void releaseAllContexts(PluginCall call) {
116
- implementation.releaseAllContexts(result -> {
117
- if (result.isSuccess()) {
118
- call.resolve();
119
- } else {
120
- call.reject(result.getError().getMessage());
121
- }
122
- });
123
- }
124
-
125
- // MARK: - Chat and completion
126
-
127
- @PluginMethod
128
- public void getFormattedChat(PluginCall call) {
129
- int contextId = call.getInt("contextId", 0);
130
- String messages = call.getString("messages", "");
131
- String chatTemplate = call.getString("chatTemplate");
132
- JSObject params = call.getObject("params");
133
-
134
- implementation.getFormattedChat(contextId, messages, chatTemplate, params, result -> {
135
- if (result.isSuccess()) {
136
- JSObject jsResult = new JSObject();
137
- Map<String, Object> data = result.getData();
138
- for (Map.Entry<String, Object> entry : data.entrySet()) {
139
- jsResult.put(entry.getKey(), entry.getValue());
140
- }
141
- call.resolve(jsResult);
142
- } else {
143
- call.reject(result.getError().getMessage());
144
- }
145
- });
146
- }
147
-
148
- @PluginMethod
149
- public void completion(PluginCall call) {
150
- int contextId = call.getInt("contextId", 0);
151
- JSObject params = call.getObject("params", new JSObject());
152
-
153
- implementation.completion(contextId, params, result -> {
154
- if (result.isSuccess()) {
155
- JSObject jsResult = new JSObject();
156
- Map<String, Object> data = result.getData();
157
- for (Map.Entry<String, Object> entry : data.entrySet()) {
158
- jsResult.put(entry.getKey(), entry.getValue());
159
- }
160
- call.resolve(jsResult);
161
- } else {
162
- call.reject(result.getError().getMessage());
163
- }
164
- });
165
- }
166
-
167
- @PluginMethod
168
- public void stopCompletion(PluginCall call) {
169
- int contextId = call.getInt("contextId", 0);
170
-
171
- implementation.stopCompletion(contextId, result -> {
172
- if (result.isSuccess()) {
173
- call.resolve();
174
- } else {
175
- call.reject(result.getError().getMessage());
176
- }
177
- });
178
- }
179
-
180
- // MARK: - Session management
181
-
182
- @PluginMethod
183
- public void loadSession(PluginCall call) {
184
- int contextId = call.getInt("contextId", 0);
185
- String path = call.getString("path", "");
186
-
187
- implementation.loadSession(contextId, path, result -> {
188
- if (result.isSuccess()) {
189
- JSObject jsResult = new JSObject();
190
- Map<String, Object> data = result.getData();
191
- for (Map.Entry<String, Object> entry : data.entrySet()) {
192
- jsResult.put(entry.getKey(), entry.getValue());
193
- }
194
- call.resolve(jsResult);
195
- } else {
196
- call.reject(result.getError().getMessage());
197
- }
198
- });
199
- }
200
-
201
- @PluginMethod
202
- public void saveSession(PluginCall call) {
203
- int contextId = call.getInt("contextId", 0);
204
- String path = call.getString("path", "");
205
- int size = call.getInt("size", -1);
206
-
207
- implementation.saveSession(contextId, path, size, result -> {
208
- if (result.isSuccess()) {
209
- JSObject ret = new JSObject();
210
- ret.put("tokensSaved", result.getData());
211
- call.resolve(ret);
212
- } else {
213
- call.reject(result.getError().getMessage());
214
- }
215
- });
216
- }
217
-
218
- // MARK: - Tokenization
219
-
220
- @PluginMethod
221
- public void tokenize(PluginCall call) {
222
- int contextId = call.getInt("contextId", 0);
223
- String text = call.getString("text", "");
224
- JSArray imagePathsArray = call.getArray("imagePaths");
225
- String[] imagePaths = new String[0];
226
- if (imagePathsArray != null) {
227
- imagePaths = new String[imagePathsArray.length()];
228
- for (int i = 0; i < imagePathsArray.length(); i++) {
229
- try {
230
- imagePaths[i] = imagePathsArray.getString(i);
231
- } catch (JSONException e) {
232
- imagePaths[i] = "";
233
- }
234
- }
235
- }
236
-
237
- implementation.tokenize(contextId, text, imagePaths, result -> {
238
- if (result.isSuccess()) {
239
- JSObject jsResult = new JSObject();
240
- Map<String, Object> data = result.getData();
241
- for (Map.Entry<String, Object> entry : data.entrySet()) {
242
- jsResult.put(entry.getKey(), entry.getValue());
243
- }
244
- call.resolve(jsResult);
245
- } else {
246
- call.reject(result.getError().getMessage());
247
- }
248
- });
249
- }
250
-
251
- @PluginMethod
252
- public void detokenize(PluginCall call) {
253
- int contextId = call.getInt("contextId", 0);
254
- JSArray tokensArray = call.getArray("tokens");
255
- Integer[] tokens = new Integer[0];
256
- if (tokensArray != null) {
257
- tokens = new Integer[tokensArray.length()];
258
- for (int i = 0; i < tokensArray.length(); i++) {
259
- try {
260
- tokens[i] = tokensArray.getInt(i);
261
- } catch (JSONException e) {
262
- tokens[i] = 0;
263
- }
264
- }
265
- }
266
-
267
- implementation.detokenize(contextId, tokens, result -> {
268
- if (result.isSuccess()) {
269
- JSObject ret = new JSObject();
270
- ret.put("text", result.getData());
271
- call.resolve(ret);
272
- } else {
273
- call.reject(result.getError().getMessage());
274
- }
275
- });
276
- }
277
-
278
- // MARK: - Embeddings and reranking
279
-
280
- @PluginMethod
281
- public void embedding(PluginCall call) {
282
- int contextId = call.getInt("contextId", 0);
283
- String text = call.getString("text", "");
284
- JSObject params = call.getObject("params", new JSObject());
285
-
286
- implementation.embedding(contextId, text, params, result -> {
287
- if (result.isSuccess()) {
288
- JSObject jsResult = new JSObject();
289
- Map<String, Object> data = result.getData();
290
- for (Map.Entry<String, Object> entry : data.entrySet()) {
291
- jsResult.put(entry.getKey(), entry.getValue());
292
- }
293
- call.resolve(jsResult);
294
- } else {
295
- call.reject(result.getError().getMessage());
296
- }
297
- });
298
- }
299
-
300
- @PluginMethod
301
- public void rerank(PluginCall call) {
302
- int contextId = call.getInt("contextId", 0);
303
- String query = call.getString("query", "");
304
- JSArray documentsArray = call.getArray("documents");
305
- String[] documents = new String[0];
306
- if (documentsArray != null) {
307
- documents = new String[documentsArray.length()];
308
- for (int i = 0; i < documentsArray.length(); i++) {
309
- try {
310
- documents[i] = documentsArray.getString(i);
311
- } catch (JSONException e) {
312
- documents[i] = "";
313
- }
314
- }
315
- }
316
- JSObject params = call.getObject("params");
317
-
318
- implementation.rerank(contextId, query, documents, params, result -> {
319
- if (result.isSuccess()) {
320
- JSObject ret = new JSObject();
321
- ret.put("results", result.getData());
322
- call.resolve(ret);
323
- } else {
324
- call.reject(result.getError().getMessage());
325
- }
326
- });
327
- }
328
-
329
- // MARK: - Benchmarking
330
-
331
- @PluginMethod
332
- public void bench(PluginCall call) {
333
- int contextId = call.getInt("contextId", 0);
334
- int pp = call.getInt("pp", 0);
335
- int tg = call.getInt("tg", 0);
336
- int pl = call.getInt("pl", 0);
337
- int nr = call.getInt("nr", 0);
338
-
339
- implementation.bench(contextId, pp, tg, pl, nr, result -> {
340
- if (result.isSuccess()) {
341
- JSObject ret = new JSObject();
342
- ret.put("result", result.getData());
343
- call.resolve(ret);
344
- } else {
345
- call.reject(result.getError().getMessage());
346
- }
347
- });
348
- }
349
-
350
- // MARK: - LoRA adapters
351
-
352
- @PluginMethod
353
- public void applyLoraAdapters(PluginCall call) {
354
- int contextId = call.getInt("contextId", 0);
355
- JSArray loraAdaptersArray = call.getArray("loraAdapters");
356
- JSObject[] loraAdapters = new JSObject[0];
357
- if (loraAdaptersArray != null) {
358
- loraAdapters = new JSObject[loraAdaptersArray.length()];
359
- for (int i = 0; i < loraAdaptersArray.length(); i++) {
360
- // For now, create empty JSObjects since the exact method is unclear
361
- loraAdapters[i] = new JSObject();
362
- }
363
- }
364
-
365
- implementation.applyLoraAdapters(contextId, loraAdapters, result -> {
366
- if (result.isSuccess()) {
367
- call.resolve();
368
- } else {
369
- call.reject(result.getError().getMessage());
370
- }
371
- });
372
- }
373
-
374
- @PluginMethod
375
- public void removeLoraAdapters(PluginCall call) {
376
- int contextId = call.getInt("contextId", 0);
377
-
378
- implementation.removeLoraAdapters(contextId, result -> {
379
- if (result.isSuccess()) {
380
- call.resolve();
381
- } else {
382
- call.reject(result.getError().getMessage());
383
- }
384
- });
385
- }
386
-
387
- @PluginMethod
388
- public void getLoadedLoraAdapters(PluginCall call) {
389
- int contextId = call.getInt("contextId", 0);
390
-
391
- implementation.getLoadedLoraAdapters(contextId, result -> {
392
- if (result.isSuccess()) {
393
- JSObject ret = new JSObject();
394
- ret.put("adapters", result.getData());
395
- call.resolve(ret);
396
- } else {
397
- call.reject(result.getError().getMessage());
398
- }
399
- });
400
- }
401
-
402
- // MARK: - Multimodal methods
403
-
404
- @PluginMethod
405
- public void initMultimodal(PluginCall call) {
406
- int contextId = call.getInt("contextId", 0);
407
- JSObject params = call.getObject("params", new JSObject());
408
- String path = params.getString("path", "");
409
- boolean useGpu = params.getBoolean("use_gpu", true);
410
-
411
- implementation.initMultimodal(contextId, path, useGpu, result -> {
412
- if (result.isSuccess()) {
413
- JSObject ret = new JSObject();
414
- ret.put("success", result.getData());
415
- call.resolve(ret);
416
- } else {
417
- call.reject(result.getError().getMessage());
418
- }
419
- });
420
- }
421
-
422
- @PluginMethod
423
- public void isMultimodalEnabled(PluginCall call) {
424
- int contextId = call.getInt("contextId", 0);
425
-
426
- implementation.isMultimodalEnabled(contextId, result -> {
427
- if (result.isSuccess()) {
428
- JSObject ret = new JSObject();
429
- ret.put("enabled", result.getData());
430
- call.resolve(ret);
431
- } else {
432
- call.reject(result.getError().getMessage());
433
- }
434
- });
435
- }
436
-
437
- @PluginMethod
438
- public void getMultimodalSupport(PluginCall call) {
439
- int contextId = call.getInt("contextId", 0);
440
-
441
- implementation.getMultimodalSupport(contextId, result -> {
442
- if (result.isSuccess()) {
443
- JSObject ret = new JSObject();
444
- ret.put("support", result.getData());
445
- call.resolve(ret);
446
- } else {
447
- call.reject(result.getError().getMessage());
448
- }
449
- });
450
- }
451
-
452
- @PluginMethod
453
- public void releaseMultimodal(PluginCall call) {
454
- int contextId = call.getInt("contextId", 0);
455
-
456
- implementation.releaseMultimodal(contextId, result -> {
457
- if (result.isSuccess()) {
458
- call.resolve();
459
- } else {
460
- call.reject(result.getError().getMessage());
461
- }
462
- });
463
- }
464
-
465
- // MARK: - TTS methods
466
-
467
- @PluginMethod
468
- public void initVocoder(PluginCall call) {
469
- int contextId = call.getInt("contextId", 0);
470
- JSObject params = call.getObject("params", new JSObject());
471
- String path = params.getString("path", "");
472
- Integer nBatch = params.getInteger("n_batch");
473
-
474
- implementation.initVocoder(contextId, path, nBatch, result -> {
475
- if (result.isSuccess()) {
476
- JSObject ret = new JSObject();
477
- ret.put("success", result.getData());
478
- call.resolve(ret);
479
- } else {
480
- call.reject(result.getError().getMessage());
481
- }
482
- });
483
- }
484
-
485
- @PluginMethod
486
- public void isVocoderEnabled(PluginCall call) {
487
- int contextId = call.getInt("contextId", 0);
488
-
489
- implementation.isVocoderEnabled(contextId, result -> {
490
- if (result.isSuccess()) {
491
- JSObject ret = new JSObject();
492
- ret.put("enabled", result.getData());
493
- call.resolve(ret);
494
- } else {
495
- call.reject(result.getError().getMessage());
496
- }
497
- });
498
- }
499
-
500
- @PluginMethod
501
- public void getFormattedAudioCompletion(PluginCall call) {
502
- int contextId = call.getInt("contextId", 0);
503
- String speakerJsonStr = call.getString("speakerJsonStr", "");
504
- String textToSpeak = call.getString("textToSpeak", "");
505
-
506
- implementation.getFormattedAudioCompletion(contextId, speakerJsonStr, textToSpeak, result -> {
507
- if (result.isSuccess()) {
508
- JSObject ret = new JSObject();
509
- ret.put("completion", result.getData());
510
- call.resolve(ret);
511
- } else {
512
- call.reject(result.getError().getMessage());
513
- }
514
- });
515
- }
516
-
517
- @PluginMethod
518
- public void getAudioCompletionGuideTokens(PluginCall call) {
519
- int contextId = call.getInt("contextId", 0);
520
- String textToSpeak = call.getString("textToSpeak", "");
521
-
522
- implementation.getAudioCompletionGuideTokens(contextId, textToSpeak, result -> {
523
- if (result.isSuccess()) {
524
- JSObject ret = new JSObject();
525
- ret.put("tokens", result.getData());
526
- call.resolve(ret);
527
- } else {
528
- call.reject(result.getError().getMessage());
529
- }
530
- });
531
- }
532
-
533
- @PluginMethod
534
- public void decodeAudioTokens(PluginCall call) {
535
- int contextId = call.getInt("contextId", 0);
536
- JSArray tokensArray = call.getArray("tokens");
537
- Integer[] tokens = new Integer[0];
538
- if (tokensArray != null) {
539
- tokens = new Integer[tokensArray.length()];
540
- for (int i = 0; i < tokensArray.length(); i++) {
541
- try {
542
- tokens[i] = tokensArray.getInt(i);
543
- } catch (JSONException e) {
544
- tokens[i] = 0;
545
- }
546
- }
547
- }
548
-
549
- implementation.decodeAudioTokens(contextId, tokens, result -> {
550
- if (result.isSuccess()) {
551
- JSObject ret = new JSObject();
552
- ret.put("decodedTokens", result.getData());
553
- call.resolve(ret);
554
- } else {
555
- call.reject(result.getError().getMessage());
556
- }
557
- });
558
- }
559
-
560
- @PluginMethod
561
- public void releaseVocoder(PluginCall call) {
562
- int contextId = call.getInt("contextId", 0);
563
-
564
- implementation.releaseVocoder(contextId, result -> {
565
- if (result.isSuccess()) {
566
- call.resolve();
567
- } else {
568
- call.reject(result.getError().getMessage());
569
- }
570
- });
571
- }
572
-
573
- // MARK: - Events
574
-
575
- @PluginMethod
576
- public void addListener(PluginCall call) {
577
- String eventName = call.getString("eventName", "");
578
- // Note: In Capacitor, event listeners are typically handled differently
579
- // This is a placeholder for the event system
580
- call.resolve();
581
- }
582
-
583
- @PluginMethod
584
- public void removeAllListeners(PluginCall call) {
585
- String eventName = call.getString("eventName", "");
586
- // Note: In Capacitor, event listeners are typically handled differently
587
- // This is a placeholder for the event system
588
- call.resolve();
589
- }
590
- }
1
+ package ai.annadata.plugin.capacitor;
2
+
3
+ import android.util.Log;
4
+ import com.getcapacitor.JSObject;
5
+ import com.getcapacitor.JSArray;
6
+ import com.getcapacitor.Plugin;
7
+ import com.getcapacitor.PluginCall;
8
+ import com.getcapacitor.PluginMethod;
9
+ import com.getcapacitor.annotation.CapacitorPlugin;
10
+ import java.util.Map;
11
+ import org.json.JSONException;
12
+ import org.json.JSONObject;
13
+ import android.content.Context;
14
+ import android.os.Environment;
15
+ import java.io.File;
16
+ import java.util.ArrayList;
17
+ import java.util.List;
18
+ import java.util.HashMap;
19
+
20
+ @CapacitorPlugin(name = "LlamaCpp")
21
+ public class LlamaCppPlugin extends Plugin {
22
+ private static final String TAG = "LlamaCppPlugin";
23
+
24
+ private LlamaCpp implementation;
25
+
26
+ @Override
27
+ public void load() {
28
+ super.load();
29
+ // Initialize implementation with context
30
+ implementation = new LlamaCpp(getContext());
31
+ Log.i(TAG, "LlamaCppPlugin loaded successfully");
32
+ }
33
+
34
+ // MARK: - Core initialization and management
35
+
36
+ @PluginMethod
37
+ public void toggleNativeLog(PluginCall call) {
38
+ boolean enabled = call.getBoolean("enabled", false);
39
+ implementation.toggleNativeLog(enabled, result -> {
40
+ if (result.isSuccess()) {
41
+ call.resolve();
42
+ } else {
43
+ call.reject(result.getError().getMessage());
44
+ }
45
+ });
46
+ }
47
+
48
+ @PluginMethod
49
+ public void setContextLimit(PluginCall call) {
50
+ int limit = call.getInt("limit", 10);
51
+ implementation.setContextLimit(limit, result -> {
52
+ if (result.isSuccess()) {
53
+ call.resolve();
54
+ } else {
55
+ call.reject(result.getError().getMessage());
56
+ }
57
+ });
58
+ }
59
+
60
+ @PluginMethod
61
+ public void modelInfo(PluginCall call) {
62
+ String path = call.getString("path", "");
63
+ JSArray skipArray = call.getArray("skip");
64
+ String[] skip = new String[0];
65
+ if (skipArray != null) {
66
+ skip = new String[skipArray.length()];
67
+ for (int i = 0; i < skipArray.length(); i++) {
68
+ try {
69
+ skip[i] = skipArray.getString(i);
70
+ } catch (JSONException e) {
71
+ skip[i] = "";
72
+ }
73
+ }
74
+ }
75
+
76
+ implementation.modelInfo(path, skip, result -> {
77
+ if (result.isSuccess()) {
78
+ JSObject jsResult = new JSObject();
79
+ Map<String, Object> data = result.getData();
80
+ for (Map.Entry<String, Object> entry : data.entrySet()) {
81
+ jsResult.put(entry.getKey(), entry.getValue());
82
+ }
83
+ call.resolve(jsResult);
84
+ } else {
85
+ call.reject(result.getError().getMessage());
86
+ }
87
+ });
88
+ }
89
+
90
+ @PluginMethod
91
+ public void initContext(PluginCall call) {
92
+ Log.i(TAG, "initContext called with contextId: " + call.getInt("contextId", 0));
93
+ int contextId = call.getInt("contextId", 0);
94
+ JSObject params = call.getObject("params", new JSObject());
95
+
96
+ implementation.initContext(contextId, params, result -> {
97
+ if (result.isSuccess()) {
98
+ JSObject jsResult = new JSObject();
99
+ Map<String, Object> data = result.getData();
100
+ for (Map.Entry<String, Object> entry : data.entrySet()) {
101
+ jsResult.put(entry.getKey(), entry.getValue());
102
+ }
103
+ call.resolve(jsResult);
104
+ } else {
105
+ call.reject(result.getError().getMessage());
106
+ }
107
+ });
108
+ }
109
+
110
+ @PluginMethod
111
+ public void releaseContext(PluginCall call) {
112
+ int contextId = call.getInt("contextId", 0);
113
+ implementation.releaseContext(contextId, result -> {
114
+ if (result.isSuccess()) {
115
+ call.resolve();
116
+ } else {
117
+ call.reject(result.getError().getMessage());
118
+ }
119
+ });
120
+ }
121
+
122
+ @PluginMethod
123
+ public void releaseAllContexts(PluginCall call) {
124
+ implementation.releaseAllContexts(result -> {
125
+ if (result.isSuccess()) {
126
+ call.resolve();
127
+ } else {
128
+ call.reject(result.getError().getMessage());
129
+ }
130
+ });
131
+ }
132
+
133
+ // MARK: - Chat and completion
134
+
135
+ @PluginMethod
136
+ public void getFormattedChat(PluginCall call) {
137
+ int contextId = call.getInt("contextId", 0);
138
+ String messages = call.getString("messages", "");
139
+ String chatTemplate = call.getString("chatTemplate", "");
140
+ JSObject params = call.getObject("params", new JSObject());
141
+
142
+ implementation.getFormattedChat(contextId, messages, chatTemplate, params, result -> {
143
+ if (result.isSuccess()) {
144
+ Map<String, Object> data = result.getData();
145
+ JSObject jsResult = convertMapToJSObject(data);
146
+ call.resolve(jsResult);
147
+ } else {
148
+ call.reject(result.getError().getMessage());
149
+ }
150
+ });
151
+ }
152
+
153
+ @PluginMethod
154
+ public void completion(PluginCall call) {
155
+ int contextId = call.getInt("contextId", 0);
156
+ JSObject params = call.getObject("params", new JSObject());
157
+
158
+ implementation.completion(contextId, params, result -> {
159
+ if (result.isSuccess()) {
160
+ Map<String, Object> data = result.getData();
161
+ JSObject jsResult = convertMapToJSObject(data);
162
+ call.resolve(jsResult);
163
+ } else {
164
+ call.reject(result.getError().getMessage());
165
+ }
166
+ });
167
+ }
168
+
169
+ @PluginMethod
170
+ public void stopCompletion(PluginCall call) {
171
+ int contextId = call.getInt("contextId", 0);
172
+ implementation.stopCompletion(contextId, result -> {
173
+ if (result.isSuccess()) {
174
+ call.resolve();
175
+ } else {
176
+ call.reject(result.getError().getMessage());
177
+ }
178
+ });
179
+ }
180
+
181
+ // MARK: - Session management
182
+
183
+ @PluginMethod
184
+ public void loadSession(PluginCall call) {
185
+ int contextId = call.getInt("contextId", 0);
186
+ String filepath = call.getString("filepath", "");
187
+
188
+ implementation.loadSession(contextId, filepath, result -> {
189
+ if (result.isSuccess()) {
190
+ Map<String, Object> data = result.getData();
191
+ JSObject jsResult = convertMapToJSObject(data);
192
+ call.resolve(jsResult);
193
+ } else {
194
+ call.reject(result.getError().getMessage());
195
+ }
196
+ });
197
+ }
198
+
199
+ @PluginMethod
200
+ public void saveSession(PluginCall call) {
201
+ int contextId = call.getInt("contextId", 0);
202
+ String filepath = call.getString("filepath", "");
203
+ int size = call.getInt("size", -1);
204
+
205
+ implementation.saveSession(contextId, filepath, size, result -> {
206
+ if (result.isSuccess()) {
207
+ JSObject ret = new JSObject();
208
+ ret.put("tokens_saved", result.getData());
209
+ call.resolve(ret);
210
+ } else {
211
+ call.reject(result.getError().getMessage());
212
+ }
213
+ });
214
+ }
215
+
216
+ // MARK: - Tokenization
217
+
218
+ @PluginMethod
219
+ public void tokenize(PluginCall call) {
220
+ int contextId = call.getInt("contextId", 0);
221
+ String text = call.getString("text", "");
222
+ JSArray imagePathsArray = call.getArray("imagePaths");
223
+ String[] imagePaths = new String[0];
224
+ if (imagePathsArray != null) {
225
+ imagePaths = new String[imagePathsArray.length()];
226
+ for (int i = 0; i < imagePathsArray.length(); i++) {
227
+ try {
228
+ imagePaths[i] = imagePathsArray.getString(i);
229
+ } catch (JSONException e) {
230
+ imagePaths[i] = "";
231
+ }
232
+ }
233
+ }
234
+
235
+ implementation.tokenize(contextId, text, imagePaths, result -> {
236
+ if (result.isSuccess()) {
237
+ Map<String, Object> data = result.getData();
238
+ JSObject jsResult = convertMapToJSObject(data);
239
+ call.resolve(jsResult);
240
+ } else {
241
+ call.reject(result.getError().getMessage());
242
+ }
243
+ });
244
+ }
245
+
246
+ @PluginMethod
247
+ public void detokenize(PluginCall call) {
248
+ int contextId = call.getInt("contextId", 0);
249
+ JSArray tokensArray = call.getArray("tokens");
250
+ Integer[] tokens = new Integer[0];
251
+ if (tokensArray != null) {
252
+ tokens = new Integer[tokensArray.length()];
253
+ for (int i = 0; i < tokensArray.length(); i++) {
254
+ try {
255
+ tokens[i] = tokensArray.getInt(i);
256
+ } catch (JSONException e) {
257
+ tokens[i] = 0;
258
+ }
259
+ }
260
+ }
261
+
262
+ implementation.detokenize(contextId, tokens, result -> {
263
+ if (result.isSuccess()) {
264
+ JSObject ret = new JSObject();
265
+ ret.put("text", result.getData());
266
+ call.resolve(ret);
267
+ } else {
268
+ call.reject(result.getError().getMessage());
269
+ }
270
+ });
271
+ }
272
+
273
+ // MARK: - Embeddings and reranking
274
+
275
+ @PluginMethod
276
+ public void embedding(PluginCall call) {
277
+ int contextId = call.getInt("contextId", 0);
278
+ String text = call.getString("text", "");
279
+ JSObject params = call.getObject("params", new JSObject());
280
+
281
+ implementation.embedding(contextId, text, params, result -> {
282
+ if (result.isSuccess()) {
283
+ Map<String, Object> data = result.getData();
284
+ JSObject jsResult = convertMapToJSObject(data);
285
+ call.resolve(jsResult);
286
+ } else {
287
+ call.reject(result.getError().getMessage());
288
+ }
289
+ });
290
+ }
291
+
292
+ @PluginMethod
293
+ public void rerank(PluginCall call) {
294
+ int contextId = call.getInt("contextId", 0);
295
+ String query = call.getString("query", "");
296
+ JSArray documentsArray = call.getArray("documents");
297
+ String[] documents = new String[0];
298
+ if (documentsArray != null) {
299
+ documents = new String[documentsArray.length()];
300
+ for (int i = 0; i < documentsArray.length(); i++) {
301
+ try {
302
+ documents[i] = documentsArray.getString(i);
303
+ } catch (JSONException e) {
304
+ documents[i] = "";
305
+ }
306
+ }
307
+ }
308
+ JSObject params = call.getObject("params", new JSObject());
309
+
310
+ implementation.rerank(contextId, query, documents, params, result -> {
311
+ if (result.isSuccess()) {
312
+ List<Map<String, Object>> data = result.getData();
313
+ JSArray jsArray = convertListToJSArray(data);
314
+ JSObject ret = new JSObject();
315
+ ret.put("results", jsArray);
316
+ call.resolve(ret);
317
+ } else {
318
+ call.reject(result.getError().getMessage());
319
+ }
320
+ });
321
+ }
322
+
323
+ // MARK: - Benchmarking
324
+
325
+ @PluginMethod
326
+ public void bench(PluginCall call) {
327
+ int contextId = call.getInt("contextId", 0);
328
+ int pp = call.getInt("pp", 128);
329
+ int tg = call.getInt("tg", 128);
330
+ int pl = call.getInt("pl", 1);
331
+ int nr = call.getInt("nr", 1);
332
+
333
+ implementation.bench(contextId, pp, tg, pl, nr, result -> {
334
+ if (result.isSuccess()) {
335
+ JSObject ret = new JSObject();
336
+ ret.put("result", result.getData());
337
+ call.resolve(ret);
338
+ } else {
339
+ call.reject(result.getError().getMessage());
340
+ }
341
+ });
342
+ }
343
+
344
+ // MARK: - LoRA adapters
345
+
346
+ @PluginMethod
347
+ public void applyLoraAdapters(PluginCall call) {
348
+ int contextId = call.getInt("contextId", 0);
349
+ JSArray loraAdaptersArray = call.getArray("loraAdapters");
350
+ List<Map<String, Object>> loraAdapters = new ArrayList<>();
351
+
352
+ if (loraAdaptersArray != null) {
353
+ for (int i = 0; i < loraAdaptersArray.length(); i++) {
354
+ try {
355
+ JSONObject adapter = loraAdaptersArray.getJSONObject(i);
356
+ Map<String, Object> adapterMap = new HashMap<>();
357
+ adapterMap.put("path", adapter.optString("path", ""));
358
+ adapterMap.put("scaled", adapter.optDouble("scaled", 1.0));
359
+ loraAdapters.add(adapterMap);
360
+ } catch (JSONException e) {
361
+ Log.e(TAG, "Error parsing LoRA adapter: " + e.getMessage());
362
+ }
363
+ }
364
+ }
365
+
366
+ implementation.applyLoraAdapters(contextId, loraAdapters, result -> {
367
+ if (result.isSuccess()) {
368
+ call.resolve();
369
+ } else {
370
+ call.reject(result.getError().getMessage());
371
+ }
372
+ });
373
+ }
374
+
375
+ @PluginMethod
376
+ public void removeLoraAdapters(PluginCall call) {
377
+ int contextId = call.getInt("contextId", 0);
378
+ implementation.removeLoraAdapters(contextId, result -> {
379
+ if (result.isSuccess()) {
380
+ call.resolve();
381
+ } else {
382
+ call.reject(result.getError().getMessage());
383
+ }
384
+ });
385
+ }
386
+
387
+ @PluginMethod
388
+ public void getLoadedLoraAdapters(PluginCall call) {
389
+ int contextId = call.getInt("contextId", 0);
390
+ implementation.getLoadedLoraAdapters(contextId, result -> {
391
+ if (result.isSuccess()) {
392
+ List<Map<String, Object>> data = result.getData();
393
+ JSArray jsArray = convertListToJSArray(data);
394
+ JSObject ret = new JSObject();
395
+ ret.put("adapters", jsArray);
396
+ call.resolve(ret);
397
+ } else {
398
+ call.reject(result.getError().getMessage());
399
+ }
400
+ });
401
+ }
402
+
403
+ // MARK: - Multimodal methods
404
+
405
+ @PluginMethod
406
+ public void initMultimodal(PluginCall call) {
407
+ int contextId = call.getInt("contextId", 0);
408
+ JSObject params = call.getObject("params", new JSObject());
409
+ String path = params.getString("path", "");
410
+ boolean useGpu = params.getBoolean("use_gpu", true);
411
+
412
+ implementation.initMultimodal(contextId, path, useGpu, result -> {
413
+ if (result.isSuccess()) {
414
+ JSObject ret = new JSObject();
415
+ ret.put("success", result.getData());
416
+ call.resolve(ret);
417
+ } else {
418
+ call.reject(result.getError().getMessage());
419
+ }
420
+ });
421
+ }
422
+
423
+ @PluginMethod
424
+ public void isMultimodalEnabled(PluginCall call) {
425
+ int contextId = call.getInt("contextId", 0);
426
+ implementation.isMultimodalEnabled(contextId, result -> {
427
+ if (result.isSuccess()) {
428
+ JSObject ret = new JSObject();
429
+ ret.put("enabled", result.getData());
430
+ call.resolve(ret);
431
+ } else {
432
+ call.reject(result.getError().getMessage());
433
+ }
434
+ });
435
+ }
436
+
437
+ @PluginMethod
438
+ public void getMultimodalSupport(PluginCall call) {
439
+ int contextId = call.getInt("contextId", 0);
440
+ implementation.getMultimodalSupport(contextId, result -> {
441
+ if (result.isSuccess()) {
442
+ Map<String, Object> data = result.getData();
443
+ JSObject jsResult = convertMapToJSObject(data);
444
+ call.resolve(jsResult);
445
+ } else {
446
+ call.reject(result.getError().getMessage());
447
+ }
448
+ });
449
+ }
450
+
451
+ @PluginMethod
452
+ public void releaseMultimodal(PluginCall call) {
453
+ int contextId = call.getInt("contextId", 0);
454
+ implementation.releaseMultimodal(contextId, result -> {
455
+ if (result.isSuccess()) {
456
+ call.resolve();
457
+ } else {
458
+ call.reject(result.getError().getMessage());
459
+ }
460
+ });
461
+ }
462
+
463
+ // MARK: - TTS methods
464
+
465
+ @PluginMethod
466
+ public void initVocoder(PluginCall call) {
467
+ int contextId = call.getInt("contextId", 0);
468
+ JSObject params = call.getObject("params", new JSObject());
469
+ String path = params.getString("path", "");
470
+ Integer nBatch = params.getInteger("n_batch", 512);
471
+
472
+ implementation.initVocoder(contextId, path, nBatch, result -> {
473
+ if (result.isSuccess()) {
474
+ JSObject ret = new JSObject();
475
+ ret.put("success", result.getData());
476
+ call.resolve(ret);
477
+ } else {
478
+ call.reject(result.getError().getMessage());
479
+ }
480
+ });
481
+ }
482
+
483
+ @PluginMethod
484
+ public void isVocoderEnabled(PluginCall call) {
485
+ int contextId = call.getInt("contextId", 0);
486
+ implementation.isVocoderEnabled(contextId, result -> {
487
+ if (result.isSuccess()) {
488
+ JSObject ret = new JSObject();
489
+ ret.put("enabled", result.getData());
490
+ call.resolve(ret);
491
+ } else {
492
+ call.reject(result.getError().getMessage());
493
+ }
494
+ });
495
+ }
496
+
497
+ @PluginMethod
498
+ public void getFormattedAudioCompletion(PluginCall call) {
499
+ int contextId = call.getInt("contextId", 0);
500
+ String speakerJsonStr = call.getString("speakerJsonStr", "");
501
+ String textToSpeak = call.getString("textToSpeak", "");
502
+
503
+ implementation.getFormattedAudioCompletion(contextId, speakerJsonStr, textToSpeak, result -> {
504
+ if (result.isSuccess()) {
505
+ Map<String, Object> data = result.getData();
506
+ JSObject jsResult = convertMapToJSObject(data);
507
+ call.resolve(jsResult);
508
+ } else {
509
+ call.reject(result.getError().getMessage());
510
+ }
511
+ });
512
+ }
513
+
514
+ @PluginMethod
515
+ public void getAudioCompletionGuideTokens(PluginCall call) {
516
+ int contextId = call.getInt("contextId", 0);
517
+ String textToSpeak = call.getString("textToSpeak", "");
518
+
519
+ implementation.getAudioCompletionGuideTokens(contextId, textToSpeak, result -> {
520
+ if (result.isSuccess()) {
521
+ List<Integer> data = result.getData();
522
+ JSArray jsArray = new JSArray();
523
+ for (Integer token : data) {
524
+ jsArray.put(token);
525
+ }
526
+ JSObject ret = new JSObject();
527
+ ret.put("tokens", jsArray);
528
+ call.resolve(ret);
529
+ } else {
530
+ call.reject(result.getError().getMessage());
531
+ }
532
+ });
533
+ }
534
+
535
+ @PluginMethod
536
+ public void decodeAudioTokens(PluginCall call) {
537
+ int contextId = call.getInt("contextId", 0);
538
+ JSArray tokensArray = call.getArray("tokens");
539
+ Integer[] tokens = new Integer[0];
540
+ if (tokensArray != null) {
541
+ tokens = new Integer[tokensArray.length()];
542
+ for (int i = 0; i < tokensArray.length(); i++) {
543
+ try {
544
+ tokens[i] = tokensArray.getInt(i);
545
+ } catch (JSONException e) {
546
+ tokens[i] = 0;
547
+ }
548
+ }
549
+ }
550
+
551
+ implementation.decodeAudioTokens(contextId, tokens, result -> {
552
+ if (result.isSuccess()) {
553
+ List<Integer> data = result.getData();
554
+ JSArray jsArray = new JSArray();
555
+ for (Integer token : data) {
556
+ jsArray.put(token);
557
+ }
558
+ JSObject ret = new JSObject();
559
+ ret.put("audioData", jsArray);
560
+ call.resolve(ret);
561
+ } else {
562
+ call.reject(result.getError().getMessage());
563
+ }
564
+ });
565
+ }
566
+
567
+ @PluginMethod
568
+ public void releaseVocoder(PluginCall call) {
569
+ int contextId = call.getInt("contextId", 0);
570
+ implementation.releaseVocoder(contextId, result -> {
571
+ if (result.isSuccess()) {
572
+ call.resolve();
573
+ } else {
574
+ call.reject(result.getError().getMessage());
575
+ }
576
+ });
577
+ }
578
+
579
+ // MARK: - Model download and management
580
+
581
+ @PluginMethod
582
+ public void downloadModel(PluginCall call) {
583
+ String url = call.getString("url", "");
584
+ String filename = call.getString("filename", "");
585
+
586
+ implementation.downloadModel(url, filename, result -> {
587
+ if (result.isSuccess()) {
588
+ JSObject ret = new JSObject();
589
+ ret.put("localPath", result.getData());
590
+ call.resolve(ret);
591
+ } else {
592
+ call.reject(result.getError().getMessage());
593
+ }
594
+ });
595
+ }
596
+
597
+ @PluginMethod
598
+ public void getDownloadProgress(PluginCall call) {
599
+ String url = call.getString("url", "");
600
+
601
+ implementation.getDownloadProgress(url, result -> {
602
+ if (result.isSuccess()) {
603
+ Map<String, Object> data = result.getData();
604
+ JSObject jsResult = convertMapToJSObject(data);
605
+ call.resolve(jsResult);
606
+ } else {
607
+ call.reject(result.getError().getMessage());
608
+ }
609
+ });
610
+ }
611
+
612
+ @PluginMethod
613
+ public void cancelDownload(PluginCall call) {
614
+ String url = call.getString("url", "");
615
+
616
+ implementation.cancelDownload(url, result -> {
617
+ if (result.isSuccess()) {
618
+ JSObject ret = new JSObject();
619
+ ret.put("cancelled", result.getData());
620
+ call.resolve(ret);
621
+ } else {
622
+ call.reject(result.getError().getMessage());
623
+ }
624
+ });
625
+ }
626
+
627
+ @PluginMethod
628
+ public void getAvailableModels(PluginCall call) {
629
+ implementation.getAvailableModels(result -> {
630
+ if (result.isSuccess()) {
631
+ List<Map<String, Object>> data = result.getData();
632
+ JSArray jsArray = convertListToJSArray(data);
633
+ JSObject ret = new JSObject();
634
+ ret.put("models", jsArray);
635
+ call.resolve(ret);
636
+ } else {
637
+ call.reject(result.getError().getMessage());
638
+ }
639
+ });
640
+ }
641
+
642
+ @PluginMethod
643
+ public void convertJsonSchemaToGrammar(PluginCall call) {
644
+ String schema = call.getString("schema");
645
+ if (schema == null) {
646
+ call.reject("Schema parameter is required");
647
+ return;
648
+ }
649
+
650
+ implementation.convertJsonSchemaToGrammar(schema, result -> {
651
+ if (result.isSuccess()) {
652
+ JSObject ret = new JSObject();
653
+ ret.put("grammar", result.getData());
654
+ call.resolve(ret);
655
+ } else {
656
+ call.reject(result.getError().getMessage());
657
+ }
658
+ });
659
+ }
660
+
661
+ // MARK: - Utility Methods
662
+
663
+ /**
664
+ * Convert a Map to JSObject with proper handling of nested structures
665
+ */
666
+ private JSObject convertMapToJSObject(Map<String, Object> map) {
667
+ JSObject jsObject = new JSObject();
668
+
669
+ for (Map.Entry<String, Object> entry : map.entrySet()) {
670
+ String key = entry.getKey();
671
+ Object value = entry.getValue();
672
+
673
+ if (value instanceof List<?>) {
674
+ List<?> list = (List<?>) value;
675
+ JSArray jsArray = new JSArray();
676
+ for (Object item : list) {
677
+ if (item instanceof Map<?, ?>) {
678
+ @SuppressWarnings("unchecked")
679
+ Map<String, Object> itemMap = (Map<String, Object>) item;
680
+ jsArray.put(convertMapToJSObject(itemMap));
681
+ } else {
682
+ jsArray.put(item);
683
+ }
684
+ }
685
+ jsObject.put(key, jsArray);
686
+ } else if (value instanceof Map<?, ?>) {
687
+ @SuppressWarnings("unchecked")
688
+ Map<String, Object> nestedMap = (Map<String, Object>) value;
689
+ jsObject.put(key, convertMapToJSObject(nestedMap));
690
+ } else {
691
+ jsObject.put(key, value);
692
+ }
693
+ }
694
+
695
+ return jsObject;
696
+ }
697
+
698
+ /**
699
+ * Convert a List of Maps to JSArray
700
+ */
701
+ private JSArray convertListToJSArray(List<Map<String, Object>> list) {
702
+ JSArray jsArray = new JSArray();
703
+
704
+ for (Map<String, Object> item : list) {
705
+ jsArray.put(convertMapToJSObject(item));
706
+ }
707
+
708
+ return jsArray;
709
+ }
710
+ }