llama-cpp-pro 0.2.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/CHANGELOG.md +295 -0
- package/LICENSE +21 -0
- package/LlamaCpp.podspec +33 -0
- package/LlamaCppCapacitor.podspec +33 -0
- package/Package.swift +29 -0
- package/README.md +93 -0
- package/android/build.gradle +88 -0
- package/android/src/main/AndroidManifest.xml +4 -0
- package/android/src/main/CMakeLists-arm64.txt +138 -0
- package/android/src/main/CMakeLists-x86_64.txt +141 -0
- package/android/src/main/CMakeLists.txt +138 -0
- package/android/src/main/java/ai/annadata/plugin/capacitor/LlamaCpp.java +1340 -0
- package/android/src/main/java/ai/annadata/plugin/capacitor/LlamaCppPlugin.java +814 -0
- package/android/src/main/java/ai/annadata/plugin/capacitor/ModelAdmissionController.java +214 -0
- package/android/src/main/jni-chat-session.cpp +261 -0
- package/android/src/main/jni-lora.cpp +197 -0
- package/android/src/main/jni-multimodal.cpp +167 -0
- package/android/src/main/jni-tts.cpp +290 -0
- package/android/src/main/jni-utils.h +148 -0
- package/android/src/main/jni.cpp +1808 -0
- package/android/src/main/jniLibs/arm64-v8a/libllama-cpp-arm64.so +0 -0
- package/android/src/main/res/.gitkeep +0 -0
- package/build-native.sh +280 -0
- package/cmake/desktop-metal-embed.cmake +30 -0
- package/cmake/desktop-sources.cmake +100 -0
- package/cmake/ggml-backends.cmake +44 -0
- package/cpp/LICENSE +21 -0
- package/cpp/README.md +15 -0
- package/cpp/anyascii.c +22223 -0
- package/cpp/anyascii.h +42 -0
- package/cpp/cap-completion.cpp +942 -0
- package/cpp/cap-completion.h +127 -0
- package/cpp/cap-embedding.cpp +193 -0
- package/cpp/cap-embedding.h +35 -0
- package/cpp/cap-ios-bridge.cpp +1810 -0
- package/cpp/cap-ios-bridge.h +61 -0
- package/cpp/cap-llama.cpp +412 -0
- package/cpp/cap-llama.h +161 -0
- package/cpp/cap-mtmd.hpp +602 -0
- package/cpp/cap-native-server.cpp +1095 -0
- package/cpp/cap-native-server.h +40 -0
- package/cpp/cap-tts.cpp +591 -0
- package/cpp/cap-tts.h +59 -0
- package/cpp/cap-wasm-fs.cpp +156 -0
- package/cpp/cap-wasm-jspi.cpp +19 -0
- package/cpp/cap-wasm-jspi.h +30 -0
- package/cpp/cap-wasm-vfs.cpp +22 -0
- package/cpp/chat-parser.cpp +393 -0
- package/cpp/chat-parser.h +120 -0
- package/cpp/chat.cpp +2315 -0
- package/cpp/chat.h +221 -0
- package/cpp/common.cpp +1664 -0
- package/cpp/common.h +744 -0
- package/cpp/ggml-alloc.c +1028 -0
- package/cpp/ggml-alloc.h +76 -0
- package/cpp/ggml-backend-impl.h +255 -0
- package/cpp/ggml-backend-reg.cpp +600 -0
- package/cpp/ggml-backend.cpp +2121 -0
- package/cpp/ggml-backend.h +354 -0
- package/cpp/ggml-common.h +1878 -0
- package/cpp/ggml-cpp.h +39 -0
- package/cpp/ggml-cpu/amx/amx.cpp +221 -0
- package/cpp/ggml-cpu/amx/amx.h +8 -0
- package/cpp/ggml-cpu/amx/common.h +91 -0
- package/cpp/ggml-cpu/amx/mmq.cpp +2512 -0
- package/cpp/ggml-cpu/amx/mmq.h +10 -0
- package/cpp/ggml-cpu/arch/arm/cpu-feats.cpp +94 -0
- package/cpp/ggml-cpu/arch/arm/quants.c +3650 -0
- package/cpp/ggml-cpu/arch/arm/repack.cpp +1891 -0
- package/cpp/ggml-cpu/arch/x86/cpu-feats.cpp +327 -0
- package/cpp/ggml-cpu/arch/x86/quants.c +3820 -0
- package/cpp/ggml-cpu/arch/x86/repack.cpp +6307 -0
- package/cpp/ggml-cpu/arch-fallback.h +215 -0
- package/cpp/ggml-cpu/binary-ops.cpp +158 -0
- package/cpp/ggml-cpu/binary-ops.h +16 -0
- package/cpp/ggml-cpu/common.h +73 -0
- package/cpp/ggml-cpu/ggml-cpu-impl.h +559 -0
- package/cpp/ggml-cpu/ggml-cpu.c +3578 -0
- package/cpp/ggml-cpu/ggml-cpu.cpp +672 -0
- package/cpp/ggml-cpu/ops.cpp +10587 -0
- package/cpp/ggml-cpu/ops.h +114 -0
- package/cpp/ggml-cpu/quants.c +1193 -0
- package/cpp/ggml-cpu/quants.h +97 -0
- package/cpp/ggml-cpu/repack.cpp +1982 -0
- package/cpp/ggml-cpu/repack.h +120 -0
- package/cpp/ggml-cpu/simd-mappings.h +1184 -0
- package/cpp/ggml-cpu/traits.cpp +36 -0
- package/cpp/ggml-cpu/traits.h +38 -0
- package/cpp/ggml-cpu/unary-ops.cpp +186 -0
- package/cpp/ggml-cpu/unary-ops.h +28 -0
- package/cpp/ggml-cpu/vec.cpp +348 -0
- package/cpp/ggml-cpu/vec.h +1121 -0
- package/cpp/ggml-cpu.h +145 -0
- package/cpp/ggml-impl.h +622 -0
- package/cpp/ggml-metal-impl.h +688 -0
- package/cpp/ggml-metal.h +66 -0
- package/cpp/ggml-metal.m +6833 -0
- package/cpp/ggml-metal.metal +10754 -0
- package/cpp/ggml-opt.cpp +1093 -0
- package/cpp/ggml-opt.h +256 -0
- package/cpp/ggml-quants.c +5324 -0
- package/cpp/ggml-quants.h +106 -0
- package/cpp/ggml-threading.cpp +12 -0
- package/cpp/ggml-threading.h +14 -0
- package/cpp/ggml.c +7108 -0
- package/cpp/ggml.h +2492 -0
- package/cpp/gguf.cpp +1358 -0
- package/cpp/gguf.h +202 -0
- package/cpp/json-partial.cpp +256 -0
- package/cpp/json-partial.h +38 -0
- package/cpp/json-schema-to-grammar.cpp +985 -0
- package/cpp/json-schema-to-grammar.h +21 -0
- package/cpp/llama-adapter.cpp +388 -0
- package/cpp/llama-adapter.h +76 -0
- package/cpp/llama-arch.cpp +2355 -0
- package/cpp/llama-arch.h +499 -0
- package/cpp/llama-batch.cpp +875 -0
- package/cpp/llama-batch.h +160 -0
- package/cpp/llama-chat.cpp +783 -0
- package/cpp/llama-chat.h +65 -0
- package/cpp/llama-context.cpp +2788 -0
- package/cpp/llama-context.h +306 -0
- package/cpp/llama-cparams.cpp +5 -0
- package/cpp/llama-cparams.h +41 -0
- package/cpp/llama-cpp.h +30 -0
- package/cpp/llama-grammar.cpp +1229 -0
- package/cpp/llama-grammar.h +173 -0
- package/cpp/llama-graph.cpp +1891 -0
- package/cpp/llama-graph.h +810 -0
- package/cpp/llama-hparams.cpp +180 -0
- package/cpp/llama-hparams.h +233 -0
- package/cpp/llama-impl.cpp +167 -0
- package/cpp/llama-impl.h +61 -0
- package/cpp/llama-io.cpp +15 -0
- package/cpp/llama-io.h +35 -0
- package/cpp/llama-kv-cache-iswa.cpp +318 -0
- package/cpp/llama-kv-cache-iswa.h +135 -0
- package/cpp/llama-kv-cache.cpp +2059 -0
- package/cpp/llama-kv-cache.h +374 -0
- package/cpp/llama-kv-cells.h +491 -0
- package/cpp/llama-memory-hybrid.cpp +258 -0
- package/cpp/llama-memory-hybrid.h +137 -0
- package/cpp/llama-memory-recurrent.cpp +1146 -0
- package/cpp/llama-memory-recurrent.h +179 -0
- package/cpp/llama-memory.cpp +59 -0
- package/cpp/llama-memory.h +119 -0
- package/cpp/llama-mmap.cpp +609 -0
- package/cpp/llama-mmap.h +68 -0
- package/cpp/llama-model-loader.cpp +1166 -0
- package/cpp/llama-model-loader.h +170 -0
- package/cpp/llama-model-saver.cpp +282 -0
- package/cpp/llama-model-saver.h +37 -0
- package/cpp/llama-model.cpp +19061 -0
- package/cpp/llama-model.h +491 -0
- package/cpp/llama-sampling.cpp +2575 -0
- package/cpp/llama-sampling.h +32 -0
- package/cpp/llama-vocab.cpp +3792 -0
- package/cpp/llama-vocab.h +176 -0
- package/cpp/llama.cpp +358 -0
- package/cpp/llama.h +1373 -0
- package/cpp/log.cpp +428 -0
- package/cpp/log.h +103 -0
- package/cpp/minja/chat-template.hpp +550 -0
- package/cpp/minja/minja.hpp +3009 -0
- package/cpp/nlohmann/json.hpp +25526 -0
- package/cpp/nlohmann/json_fwd.hpp +187 -0
- package/cpp/regex-partial.cpp +204 -0
- package/cpp/regex-partial.h +56 -0
- package/cpp/sampling.cpp +579 -0
- package/cpp/sampling.h +107 -0
- package/cpp/tools/mtmd/clip-impl.h +473 -0
- package/cpp/tools/mtmd/clip.cpp +4322 -0
- package/cpp/tools/mtmd/clip.h +106 -0
- package/cpp/tools/mtmd/miniaudio/miniaudio.h +93468 -0
- package/cpp/tools/mtmd/mtmd-audio.cpp +769 -0
- package/cpp/tools/mtmd/mtmd-audio.h +47 -0
- package/cpp/tools/mtmd/mtmd-helper.cpp +460 -0
- package/cpp/tools/mtmd/mtmd-helper.h +95 -0
- package/cpp/tools/mtmd/mtmd.cpp +1066 -0
- package/cpp/tools/mtmd/mtmd.h +302 -0
- package/cpp/tools/mtmd/stb/stb_image.h +7988 -0
- package/cpp/unicode-data.cpp +7034 -0
- package/cpp/unicode-data.h +20 -0
- package/cpp/unicode.cpp +1061 -0
- package/cpp/unicode.h +68 -0
- package/cpp/vendor/cpp-httplib/httplib.cpp +16509 -0
- package/cpp/vendor/cpp-httplib/httplib.h +3883 -0
- package/desktop/electron-builder.config.cjs +157 -0
- package/desktop/entitlements.mac.plist +12 -0
- package/desktop/package.json +11 -0
- package/desktop/resolve-package-root.cjs +88 -0
- package/desktop/src/main/backend-selector.cjs +148 -0
- package/desktop/src/main/gpu-probe.cjs +142 -0
- package/desktop/src/main/index.cjs +58 -0
- package/desktop/src/main/ipc-handlers.cjs +212 -0
- package/desktop/src/main/model-store.cjs +50 -0
- package/desktop/src/main/preload.cjs +39 -0
- package/desktop/src/main/sidecar-client.cjs +76 -0
- package/desktop/src/main/sidecar-manager.cjs +364 -0
- package/dist/docs.json +14357 -0
- package/dist/esm/definitions.d.ts +731 -0
- package/dist/esm/definitions.js +2 -0
- package/dist/esm/definitions.js.map +1 -0
- package/dist/esm/desktop.d.ts +37 -0
- package/dist/esm/desktop.js +133 -0
- package/dist/esm/desktop.js.map +1 -0
- package/dist/esm/index.d.ts +200 -0
- package/dist/esm/index.js +612 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/isomorphic/desktop.runtime.d.ts +37 -0
- package/dist/esm/isomorphic/desktop.runtime.js +36 -0
- package/dist/esm/isomorphic/desktop.runtime.js.map +1 -0
- package/dist/esm/isomorphic/errors.d.ts +6 -0
- package/dist/esm/isomorphic/errors.js +9 -0
- package/dist/esm/isomorphic/errors.js.map +1 -0
- package/dist/esm/isomorphic/model.admission.d.ts +17 -0
- package/dist/esm/isomorphic/model.admission.js +27 -0
- package/dist/esm/isomorphic/model.admission.js.map +1 -0
- package/dist/esm/isomorphic/model.scheduler.d.ts +31 -0
- package/dist/esm/isomorphic/model.scheduler.js +95 -0
- package/dist/esm/isomorphic/model.scheduler.js.map +1 -0
- package/dist/esm/isomorphic/provider.desktop.d.ts +40 -0
- package/dist/esm/isomorphic/provider.desktop.js +411 -0
- package/dist/esm/isomorphic/provider.desktop.js.map +1 -0
- package/dist/esm/isomorphic/provider.factory.d.ts +2 -0
- package/dist/esm/isomorphic/provider.factory.js +16 -0
- package/dist/esm/isomorphic/provider.factory.js.map +1 -0
- package/dist/esm/isomorphic/provider.interface.d.ts +76 -0
- package/dist/esm/isomorphic/provider.interface.js +2 -0
- package/dist/esm/isomorphic/provider.interface.js.map +1 -0
- package/dist/esm/isomorphic/provider.native.d.ts +18 -0
- package/dist/esm/isomorphic/provider.native.js +173 -0
- package/dist/esm/isomorphic/provider.native.js.map +1 -0
- package/dist/esm/isomorphic/provider.web.d.ts +88 -0
- package/dist/esm/isomorphic/provider.web.js +573 -0
- package/dist/esm/isomorphic/provider.web.js.map +1 -0
- package/dist/esm/isomorphic/sidecar-sse.d.ts +14 -0
- package/dist/esm/isomorphic/sidecar-sse.js +76 -0
- package/dist/esm/isomorphic/sidecar-sse.js.map +1 -0
- package/dist/esm/isomorphic/wasmMemoryCalibration.d.ts +26 -0
- package/dist/esm/isomorphic/wasmMemoryCalibration.js +60 -0
- package/dist/esm/isomorphic/wasmMemoryCalibration.js.map +1 -0
- package/dist/esm/isomorphic/wasmMemoryPolicy.d.ts +55 -0
- package/dist/esm/isomorphic/wasmMemoryPolicy.js +93 -0
- package/dist/esm/isomorphic/wasmMemoryPolicy.js.map +1 -0
- package/dist/esm/storage/manifest.d.ts +13 -0
- package/dist/esm/storage/manifest.js +87 -0
- package/dist/esm/storage/manifest.js.map +1 -0
- package/dist/esm/storage/opfs.store.d.ts +31 -0
- package/dist/esm/storage/opfs.store.js +241 -0
- package/dist/esm/storage/opfs.store.js.map +1 -0
- package/dist/esm/web.d.ts +206 -0
- package/dist/esm/web.js +521 -0
- package/dist/esm/web.js.map +1 -0
- package/dist/esm/workers/async-file.d.ts +13 -0
- package/dist/esm/workers/async-file.js +12 -0
- package/dist/esm/workers/async-file.js.map +1 -0
- package/dist/esm/workers/heapfs.d.ts +55 -0
- package/dist/esm/workers/heapfs.js +115 -0
- package/dist/esm/workers/heapfs.js.map +1 -0
- package/dist/esm/workers/wasm.engine.d.ts +86 -0
- package/dist/esm/workers/wasm.engine.js +504 -0
- package/dist/esm/workers/wasm.engine.js.map +1 -0
- package/dist/esm/workers/worker.protocol.d.ts +160 -0
- package/dist/esm/workers/worker.protocol.js +2 -0
- package/dist/esm/workers/worker.protocol.js.map +1 -0
- package/dist/plugin.cjs +3179 -0
- package/dist/plugin.cjs.map +1 -0
- package/dist/plugin.js +3181 -0
- package/dist/plugin.js.map +1 -0
- package/dist/wasm/llama_engine.d.ts +74 -0
- package/dist/wasm/llama_engine.js +1829 -0
- package/dist/wasm/llama_engine.wasm +0 -0
- package/dist/wasm/llama_engine_emscripten.mjs +2 -0
- package/dist/wasm/package.json +16 -0
- package/dist/workers/llm.worker.js +1226 -0
- package/dist/workers/llm.worker.js.map +7 -0
- package/extraResources/llama-wasm/llama_engine.d.ts +74 -0
- package/extraResources/llama-wasm/llama_engine.js +1829 -0
- package/extraResources/llama-wasm/llama_engine.wasm +0 -0
- package/extraResources/llama-wasm/llama_engine_emscripten.mjs +2 -0
- package/extraResources/llama-wasm/package.json +16 -0
- package/extraResources/sidecar/README.md +11 -0
- package/extraResources/sidecar/darwin-arm64 +0 -0
- package/extraResources/sidecar/darwin-x64 +0 -0
- package/ios/CMakeLists-arm64.txt +161 -0
- package/ios/CMakeLists-x86_64.txt +188 -0
- package/ios/CMakeLists.txt +161 -0
- package/ios/Frameworks/llama-cpp.framework/Info.plist +28 -0
- package/ios/Frameworks/llama-cpp.framework/llama-cpp +0 -0
- package/ios/Sources/LlamaCppCapacitor/LlamaCpp.swift +1365 -0
- package/ios/Sources/LlamaCppCapacitor/LlamaCppPlugin.swift +694 -0
- package/ios/Sources/LlamaCppCapacitor/LlamaNativeBridge.swift +349 -0
- package/ios/Sources/LlamaCppCapacitor/ModelAdmissionController.swift +177 -0
- package/ios/embed-metal-shaders.sh +24 -0
- package/ios/metal-embed.cmake +29 -0
- package/package.json +281 -0
- package/scripts/build-js-preserve-wasm.cjs +53 -0
- package/scripts/build-sidecar-linux.sh +6 -0
- package/scripts/build-sidecar-win.bat +19 -0
- package/scripts/build-sidecar.sh +184 -0
- package/scripts/embed-llama-ios-app-framework.sh +63 -0
- package/scripts/ensure-desktop-sidecar-bundle.cjs +103 -0
- package/scripts/ensure-llama-ios-xcframework.sh +108 -0
- package/scripts/fix-esm-extensions.cjs +45 -0
- package/scripts/prepare-js-dist.cjs +28 -0
- package/scripts/stage-desktop-resources.cjs +116 -0
- package/sidecar/CMakeLists.txt +192 -0
- package/sidecar/cap-sidecar-main.cpp +68 -0
- package/types/llama-cpp-pro.d.ts +441 -0
|
@@ -0,0 +1,1808 @@
|
|
|
1
|
+
#include "jni-utils.h"
|
|
2
|
+
#include "cap-llama.h"
|
|
3
|
+
#include "cap-completion.h"
|
|
4
|
+
#include "cap-embedding.h"
|
|
5
|
+
#include "cap-native-server.h"
|
|
6
|
+
#include "nlohmann/json.hpp"
|
|
7
|
+
#include "llama.h"
|
|
8
|
+
#include <android/log.h>
|
|
9
|
+
#include <cstring>
|
|
10
|
+
#include <memory>
|
|
11
|
+
#include <fstream> // Added for file existence and size checks
|
|
12
|
+
#include <signal.h> // Added for signal handling
|
|
13
|
+
#include <sys/signal.h> // Added for sigaction
|
|
14
|
+
#include <thread> // For background downloads
|
|
15
|
+
#include <atomic> // For thread-safe progress tracking
|
|
16
|
+
#include <filesystem> // For file operations
|
|
17
|
+
#include <mutex> // For thread synchronization
|
|
18
|
+
|
|
19
|
+
// Add missing symbol
|
|
20
|
+
// namespace rnllama {
|
|
21
|
+
// bool rnllama_verbose = false;
|
|
22
|
+
// }
|
|
23
|
+
|
|
24
|
+
#define LOG_TAG "LlamaCpp"
|
|
25
|
+
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
|
|
26
|
+
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)
|
|
27
|
+
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
|
|
28
|
+
|
|
29
|
+
namespace jni_utils {
|
|
30
|
+
|
|
31
|
+
std::string jstring_to_string(JNIEnv* env, jstring jstr) {
|
|
32
|
+
if (jstr == nullptr) return "";
|
|
33
|
+
const char* chars = env->GetStringUTFChars(jstr, nullptr);
|
|
34
|
+
std::string str(chars);
|
|
35
|
+
env->ReleaseStringUTFChars(jstr, chars);
|
|
36
|
+
return str;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
jstring string_to_jstring(JNIEnv* env, const std::string& str) {
|
|
40
|
+
return env->NewStringUTF(str.c_str());
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
std::vector<std::string> jstring_array_to_string_vector(JNIEnv* env, jobjectArray jarray) {
|
|
44
|
+
std::vector<std::string> result;
|
|
45
|
+
if (jarray == nullptr) return result;
|
|
46
|
+
|
|
47
|
+
jsize length = env->GetArrayLength(jarray);
|
|
48
|
+
for (jsize i = 0; i < length; i++) {
|
|
49
|
+
jstring jstr = (jstring)env->GetObjectArrayElement(jarray, i);
|
|
50
|
+
result.push_back(jstring_to_string(env, jstr));
|
|
51
|
+
env->DeleteLocalRef(jstr);
|
|
52
|
+
}
|
|
53
|
+
return result;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
jobjectArray string_vector_to_jstring_array(JNIEnv* env, const std::vector<std::string>& vec) {
|
|
57
|
+
jclass stringClass = env->FindClass("java/lang/String");
|
|
58
|
+
jobjectArray result = env->NewObjectArray(vec.size(), stringClass, nullptr);
|
|
59
|
+
|
|
60
|
+
for (size_t i = 0; i < vec.size(); i++) {
|
|
61
|
+
jstring jstr = string_to_jstring(env, vec[i]);
|
|
62
|
+
env->SetObjectArrayElement(result, i, jstr);
|
|
63
|
+
env->DeleteLocalRef(jstr);
|
|
64
|
+
}
|
|
65
|
+
return result;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
bool jboolean_to_bool(jboolean jbool) {
|
|
69
|
+
return jbool == JNI_TRUE;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
jboolean bool_to_jboolean(bool b) {
|
|
73
|
+
return b ? JNI_TRUE : JNI_FALSE;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
int jint_to_int(jint jint_val) {
|
|
77
|
+
return static_cast<int>(jint_val);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
jint int_to_jint(int val) {
|
|
81
|
+
return static_cast<jint>(val);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
float jfloat_to_float(jfloat jfloat_val) {
|
|
85
|
+
return static_cast<float>(jfloat_val);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
jfloat float_to_jfloat(float val) {
|
|
89
|
+
return static_cast<jfloat>(val);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
long jlong_to_long(jlong jlong_val) {
|
|
93
|
+
return static_cast<long>(jlong_val);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
jlong long_to_jlong(long val) {
|
|
97
|
+
return static_cast<jlong>(val);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
double jdouble_to_double(jdouble jdouble_val) {
|
|
101
|
+
return static_cast<double>(jdouble_val);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
jdouble double_to_jdouble(double val) {
|
|
105
|
+
return static_cast<jdouble>(val);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
void throw_java_exception(JNIEnv* env, const char* class_name, const char* message) {
|
|
109
|
+
jclass exceptionClass = env->FindClass(class_name);
|
|
110
|
+
if (exceptionClass != nullptr) {
|
|
111
|
+
env->ThrowNew(exceptionClass, message);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
bool check_exception(JNIEnv* env) {
|
|
116
|
+
return env->ExceptionCheck() == JNI_TRUE;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
jfieldID get_field_id(JNIEnv* env, jclass clazz, const char* name, const char* sig) {
|
|
120
|
+
jfieldID fieldID = env->GetFieldID(clazz, name, sig);
|
|
121
|
+
if (check_exception(env)) {
|
|
122
|
+
return nullptr;
|
|
123
|
+
}
|
|
124
|
+
return fieldID;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
jmethodID get_method_id(JNIEnv* env, jclass clazz, const char* name, const char* sig) {
|
|
128
|
+
jmethodID methodID = env->GetMethodID(clazz, name, sig);
|
|
129
|
+
if (check_exception(env)) {
|
|
130
|
+
return nullptr;
|
|
131
|
+
}
|
|
132
|
+
return methodID;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
double jsobject_opt_double(JNIEnv* env, jobject jso, const char* key, double default_value) {
|
|
136
|
+
if (jso == nullptr || key == nullptr) {
|
|
137
|
+
return default_value;
|
|
138
|
+
}
|
|
139
|
+
if (env->ExceptionCheck()) {
|
|
140
|
+
env->ExceptionClear();
|
|
141
|
+
}
|
|
142
|
+
jclass jsClass = env->GetObjectClass(jso);
|
|
143
|
+
if (jsClass == nullptr) {
|
|
144
|
+
if (env->ExceptionCheck()) {
|
|
145
|
+
env->ExceptionClear();
|
|
146
|
+
}
|
|
147
|
+
return default_value;
|
|
148
|
+
}
|
|
149
|
+
jmethodID optDouble = get_method_id(env, jsClass, "optDouble", "(Ljava/lang/String;D)D");
|
|
150
|
+
env->DeleteLocalRef(jsClass);
|
|
151
|
+
if (optDouble == nullptr) {
|
|
152
|
+
return default_value;
|
|
153
|
+
}
|
|
154
|
+
jstring jkey = string_to_jstring(env, key);
|
|
155
|
+
jdouble value = env->CallDoubleMethod(jso, optDouble, jkey, static_cast<jdouble>(default_value));
|
|
156
|
+
env->DeleteLocalRef(jkey);
|
|
157
|
+
if (env->ExceptionCheck()) {
|
|
158
|
+
env->ExceptionClear();
|
|
159
|
+
return default_value;
|
|
160
|
+
}
|
|
161
|
+
return static_cast<double>(value);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
bool jsobject_opt_bool(JNIEnv* env, jobject jso, const char* key, bool default_value) {
|
|
165
|
+
if (jso == nullptr || key == nullptr) {
|
|
166
|
+
return default_value;
|
|
167
|
+
}
|
|
168
|
+
if (env->ExceptionCheck()) {
|
|
169
|
+
env->ExceptionClear();
|
|
170
|
+
}
|
|
171
|
+
jclass jsClass = env->GetObjectClass(jso);
|
|
172
|
+
if (jsClass == nullptr) {
|
|
173
|
+
if (env->ExceptionCheck()) {
|
|
174
|
+
env->ExceptionClear();
|
|
175
|
+
}
|
|
176
|
+
return default_value;
|
|
177
|
+
}
|
|
178
|
+
jmethodID optBoolean = get_method_id(env, jsClass, "optBoolean", "(Ljava/lang/String;Z)Z");
|
|
179
|
+
env->DeleteLocalRef(jsClass);
|
|
180
|
+
if (optBoolean == nullptr) {
|
|
181
|
+
return default_value;
|
|
182
|
+
}
|
|
183
|
+
jstring jkey = string_to_jstring(env, key);
|
|
184
|
+
jboolean value = env->CallBooleanMethod(
|
|
185
|
+
jso, optBoolean, jkey, default_value ? JNI_TRUE : JNI_FALSE);
|
|
186
|
+
env->DeleteLocalRef(jkey);
|
|
187
|
+
if (env->ExceptionCheck()) {
|
|
188
|
+
env->ExceptionClear();
|
|
189
|
+
return default_value;
|
|
190
|
+
}
|
|
191
|
+
return value == JNI_TRUE;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
std::string jsobject_opt_string(
|
|
195
|
+
JNIEnv* env, jobject jso, const char* key, const std::string& default_value) {
|
|
196
|
+
if (jso == nullptr || key == nullptr) {
|
|
197
|
+
return default_value;
|
|
198
|
+
}
|
|
199
|
+
if (env->ExceptionCheck()) {
|
|
200
|
+
env->ExceptionClear();
|
|
201
|
+
}
|
|
202
|
+
jclass jsClass = env->GetObjectClass(jso);
|
|
203
|
+
if (jsClass == nullptr) {
|
|
204
|
+
if (env->ExceptionCheck()) {
|
|
205
|
+
env->ExceptionClear();
|
|
206
|
+
}
|
|
207
|
+
return default_value;
|
|
208
|
+
}
|
|
209
|
+
jmethodID optString = get_method_id(env, jsClass, "optString", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;");
|
|
210
|
+
env->DeleteLocalRef(jsClass);
|
|
211
|
+
if (optString == nullptr) {
|
|
212
|
+
return default_value;
|
|
213
|
+
}
|
|
214
|
+
jstring jkey = string_to_jstring(env, key);
|
|
215
|
+
jstring jdefault = string_to_jstring(env, default_value);
|
|
216
|
+
jstring jvalue = static_cast<jstring>(env->CallObjectMethod(jso, optString, jkey, jdefault));
|
|
217
|
+
env->DeleteLocalRef(jkey);
|
|
218
|
+
env->DeleteLocalRef(jdefault);
|
|
219
|
+
if (env->ExceptionCheck() || jvalue == nullptr) {
|
|
220
|
+
if (env->ExceptionCheck()) {
|
|
221
|
+
env->ExceptionClear();
|
|
222
|
+
}
|
|
223
|
+
return default_value;
|
|
224
|
+
}
|
|
225
|
+
std::string value = jstring_to_string(env, jvalue);
|
|
226
|
+
env->DeleteLocalRef(jvalue);
|
|
227
|
+
return value;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
jclass find_class(JNIEnv* env, const char* name) {
|
|
231
|
+
jclass clazz = env->FindClass(name);
|
|
232
|
+
if (check_exception(env)) {
|
|
233
|
+
return nullptr;
|
|
234
|
+
}
|
|
235
|
+
return clazz;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// Convert llama_cap_context to jobject
|
|
239
|
+
jobject llama_context_to_jobject(JNIEnv* env, const capllama::llama_cap_context* context);
|
|
240
|
+
|
|
241
|
+
// Convert jobject to llama_cap_context
|
|
242
|
+
capllama::llama_cap_context* jobject_to_llama_context(JNIEnv* env, jobject obj);
|
|
243
|
+
|
|
244
|
+
// Convert completion result to jobject
|
|
245
|
+
jobject completion_result_to_jobject(JNIEnv* env, const capllama::completion_token_output& result);
|
|
246
|
+
|
|
247
|
+
// Convert tokenize result to jobject
|
|
248
|
+
jobject tokenize_result_to_jobject(JNIEnv* env, const capllama::llama_cap_tokenize_result& result);
|
|
249
|
+
|
|
250
|
+
// Global context storage - fix namespace
|
|
251
|
+
static std::map<jlong, std::unique_ptr<capllama::llama_cap_context>> contexts;
|
|
252
|
+
static jlong next_context_id = 1;
|
|
253
|
+
|
|
254
|
+
static void apply_params_from_jsobject(JNIEnv* env, jobject params, common_params& cparams) {
|
|
255
|
+
if (params == nullptr) {
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
cparams.embedding = jni_utils::jsobject_opt_bool(env, params, "embedding", cparams.embedding);
|
|
259
|
+
cparams.use_mmap = jni_utils::jsobject_opt_bool(env, params, "use_mmap", cparams.use_mmap);
|
|
260
|
+
cparams.use_mlock = jni_utils::jsobject_opt_bool(env, params, "use_mlock", cparams.use_mlock);
|
|
261
|
+
|
|
262
|
+
jclass jsClass = env->GetObjectClass(params);
|
|
263
|
+
if (jsClass != nullptr && !env->ExceptionCheck()) {
|
|
264
|
+
jmethodID optInt = env->GetMethodID(jsClass, "optInt", "(Ljava/lang/String;I)I");
|
|
265
|
+
if (optInt != nullptr && !env->ExceptionCheck()) {
|
|
266
|
+
auto readInt = [&](const char* key, int& target) {
|
|
267
|
+
jstring jkey = jni_utils::string_to_jstring(env, key);
|
|
268
|
+
target = env->CallIntMethod(params, optInt, jkey, target);
|
|
269
|
+
env->DeleteLocalRef(jkey);
|
|
270
|
+
if (env->ExceptionCheck()) {
|
|
271
|
+
env->ExceptionClear();
|
|
272
|
+
}
|
|
273
|
+
};
|
|
274
|
+
readInt("n_ctx", cparams.n_ctx);
|
|
275
|
+
readInt("n_batch", cparams.n_batch);
|
|
276
|
+
readInt("n_gpu_layers", cparams.n_gpu_layers);
|
|
277
|
+
} else if (env->ExceptionCheck()) {
|
|
278
|
+
env->ExceptionClear();
|
|
279
|
+
}
|
|
280
|
+
env->DeleteLocalRef(jsClass);
|
|
281
|
+
} else if (env->ExceptionCheck()) {
|
|
282
|
+
env->ExceptionClear();
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
const std::string pooling_type = jni_utils::jsobject_opt_string(env, params, "pooling_type", "");
|
|
286
|
+
if (!pooling_type.empty() && pooling_type != "none") {
|
|
287
|
+
cparams.embedding = true;
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
static void tune_params_for_embedding_model(common_params& cparams) {
|
|
292
|
+
if (!cparams.embedding) {
|
|
293
|
+
return;
|
|
294
|
+
}
|
|
295
|
+
cparams.ctx_shift = false;
|
|
296
|
+
if (cparams.n_ctx > 512) {
|
|
297
|
+
cparams.n_ctx = 512;
|
|
298
|
+
}
|
|
299
|
+
if (cparams.n_batch <= 0 || cparams.n_batch < cparams.n_ctx) {
|
|
300
|
+
cparams.n_batch = cparams.n_ctx;
|
|
301
|
+
} else if (cparams.n_batch > cparams.n_ctx) {
|
|
302
|
+
cparams.n_batch = cparams.n_ctx;
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
// Download progress tracking (simplified for now)
|
|
307
|
+
// This can be enhanced later to track actual download progress
|
|
308
|
+
|
|
309
|
+
extern "C" {
|
|
310
|
+
|
|
311
|
+
JNIEXPORT jlong JNICALL
|
|
312
|
+
Java_ai_annadata_plugin_capacitor_LlamaCpp_initContextNative(
|
|
313
|
+
JNIEnv *env, jobject thiz, jstring modelPath, jobjectArray searchPaths, jobject params) {
|
|
314
|
+
|
|
315
|
+
try {
|
|
316
|
+
std::string model_path_str = jstring_to_string(env, modelPath);
|
|
317
|
+
|
|
318
|
+
// Get search paths from Java
|
|
319
|
+
jsize pathCount = env->GetArrayLength(searchPaths);
|
|
320
|
+
std::vector<std::string> paths_to_check;
|
|
321
|
+
|
|
322
|
+
// Add the original path first
|
|
323
|
+
paths_to_check.push_back(model_path_str);
|
|
324
|
+
|
|
325
|
+
// Add all search paths from Java
|
|
326
|
+
for (jsize i = 0; i < pathCount; i++) {
|
|
327
|
+
jstring pathJString = (jstring)env->GetObjectArrayElement(searchPaths, i);
|
|
328
|
+
std::string path = jstring_to_string(env, pathJString);
|
|
329
|
+
paths_to_check.push_back(path);
|
|
330
|
+
env->DeleteLocalRef(pathJString);
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
// Rest of the existing logic remains the same...
|
|
334
|
+
std::string full_model_path;
|
|
335
|
+
bool file_found = false;
|
|
336
|
+
|
|
337
|
+
for (const auto& path : paths_to_check) {
|
|
338
|
+
LOGI("Checking path: %s", path.c_str());
|
|
339
|
+
if (std::filesystem::exists(path)) {
|
|
340
|
+
full_model_path = path;
|
|
341
|
+
file_found = true;
|
|
342
|
+
LOGI("Found model file at: %s", path.c_str());
|
|
343
|
+
break;
|
|
344
|
+
} else {
|
|
345
|
+
LOGE("Path not found: %s", path.c_str());
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
if (!file_found) {
|
|
350
|
+
LOGE("Model file not found in any of the search paths");
|
|
351
|
+
return -1;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
// Additional model validation
|
|
355
|
+
LOGI("Performing additional model validation...");
|
|
356
|
+
std::ifstream validation_file(full_model_path, std::ios::binary);
|
|
357
|
+
if (validation_file.good()) {
|
|
358
|
+
// Read first 8 bytes to check GGUF version
|
|
359
|
+
char header[8];
|
|
360
|
+
if (validation_file.read(header, 8)) {
|
|
361
|
+
uint32_t version = *reinterpret_cast<uint32_t*>(header + 4);
|
|
362
|
+
LOGI("GGUF version: %u", version);
|
|
363
|
+
|
|
364
|
+
// Check if version is reasonable (should be > 0 and < 1000)
|
|
365
|
+
if (version == 0 || version > 1000) {
|
|
366
|
+
LOGE("Suspicious GGUF version: %u", version);
|
|
367
|
+
LOGI("This might indicate a corrupted or incompatible model file");
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
validation_file.close();
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
// Create new context - fix namespace
|
|
374
|
+
auto context = std::make_unique<capllama::llama_cap_context>();
|
|
375
|
+
LOGI("Created llama_cap_context");
|
|
376
|
+
|
|
377
|
+
// Initialize common parameters with defaults
|
|
378
|
+
common_params cparams;
|
|
379
|
+
cparams.model.path = full_model_path;
|
|
380
|
+
cparams.n_ctx = 2048;
|
|
381
|
+
cparams.n_batch = 512;
|
|
382
|
+
cparams.n_gpu_layers = 0;
|
|
383
|
+
cparams.rope_freq_base = 10000.0f;
|
|
384
|
+
cparams.rope_freq_scale = 1.0f;
|
|
385
|
+
cparams.use_mmap = true;
|
|
386
|
+
cparams.use_mlock = false;
|
|
387
|
+
cparams.numa = LM_GGML_NUMA_STRATEGY_DISABLED;
|
|
388
|
+
cparams.ctx_shift = false;
|
|
389
|
+
cparams.chat_template = "";
|
|
390
|
+
cparams.embedding = false; // Default to false, will be extracted from params if provided
|
|
391
|
+
cparams.cont_batching = false;
|
|
392
|
+
cparams.n_parallel = 1;
|
|
393
|
+
cparams.antiprompt.clear();
|
|
394
|
+
cparams.vocab_only = false;
|
|
395
|
+
cparams.rope_scaling_type = LLAMA_ROPE_SCALING_TYPE_UNSPECIFIED;
|
|
396
|
+
cparams.yarn_ext_factor = -1.0f;
|
|
397
|
+
cparams.yarn_attn_factor = 1.0f;
|
|
398
|
+
cparams.yarn_beta_fast = 32.0f;
|
|
399
|
+
cparams.yarn_beta_slow = 1.0f;
|
|
400
|
+
cparams.yarn_orig_ctx = 0;
|
|
401
|
+
cparams.flash_attn = false;
|
|
402
|
+
cparams.n_keep = 0;
|
|
403
|
+
cparams.n_chunks = -1;
|
|
404
|
+
cparams.n_sequences = 1;
|
|
405
|
+
cparams.model_alias = "unknown";
|
|
406
|
+
|
|
407
|
+
// Extract parameters from JSObject if provided
|
|
408
|
+
apply_params_from_jsobject(env, params, cparams);
|
|
409
|
+
tune_params_for_embedding_model(cparams);
|
|
410
|
+
|
|
411
|
+
LOGI("Initialized common parameters, attempting to load model from: %s", full_model_path.c_str());
|
|
412
|
+
LOGI("Model parameters: n_ctx=%d, n_batch=%d, n_gpu_layers=%d, embedding=%s",
|
|
413
|
+
cparams.n_ctx, cparams.n_batch, cparams.n_gpu_layers, cparams.embedding ? "true" : "false");
|
|
414
|
+
|
|
415
|
+
// Try to load the model with error handling and signal protection
|
|
416
|
+
bool load_success = false;
|
|
417
|
+
|
|
418
|
+
// Set up signal handler to catch segmentation faults
|
|
419
|
+
struct sigaction old_action;
|
|
420
|
+
struct sigaction new_action;
|
|
421
|
+
new_action.sa_handler = [](int sig) {
|
|
422
|
+
LOGE("Segmentation fault caught during model loading");
|
|
423
|
+
// Restore default handler and re-raise signal
|
|
424
|
+
signal(sig, SIG_DFL);
|
|
425
|
+
raise(sig);
|
|
426
|
+
};
|
|
427
|
+
new_action.sa_flags = SA_RESETHAND;
|
|
428
|
+
sigemptyset(&new_action.sa_mask);
|
|
429
|
+
|
|
430
|
+
if (sigaction(SIGSEGV, &new_action, &old_action) == 0) {
|
|
431
|
+
LOGI("Signal handler installed for segmentation fault protection");
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
try {
|
|
435
|
+
LOGI("Attempting to load model with standard parameters...");
|
|
436
|
+
load_success = context->loadModel(cparams);
|
|
437
|
+
} catch (const std::exception& e) {
|
|
438
|
+
LOGE("Exception during model loading: %s", e.what());
|
|
439
|
+
load_success = false;
|
|
440
|
+
} catch (...) {
|
|
441
|
+
LOGE("Unknown exception during model loading");
|
|
442
|
+
load_success = false;
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
// Restore original signal handler
|
|
446
|
+
sigaction(SIGSEGV, &old_action, nullptr);
|
|
447
|
+
|
|
448
|
+
if (!load_success) {
|
|
449
|
+
LOGE("context->loadModel() returned false - model loading failed");
|
|
450
|
+
|
|
451
|
+
// Try with ultra-minimal parameters as fallback
|
|
452
|
+
LOGI("Trying with ultra-minimal parameters...");
|
|
453
|
+
common_params ultra_minimal_params;
|
|
454
|
+
ultra_minimal_params.model.path = full_model_path;
|
|
455
|
+
ultra_minimal_params.n_ctx = 256; // Very small context
|
|
456
|
+
ultra_minimal_params.n_batch = 128; // Very small batch
|
|
457
|
+
ultra_minimal_params.n_gpu_layers = 0;
|
|
458
|
+
ultra_minimal_params.use_mmap = false; // Disable mmap to avoid memory issues
|
|
459
|
+
ultra_minimal_params.use_mlock = false;
|
|
460
|
+
ultra_minimal_params.numa = LM_GGML_NUMA_STRATEGY_DISABLED;
|
|
461
|
+
ultra_minimal_params.ctx_shift = false;
|
|
462
|
+
ultra_minimal_params.chat_template = "";
|
|
463
|
+
ultra_minimal_params.embedding = cparams.embedding; // Preserve embedding setting even in fallback
|
|
464
|
+
tune_params_for_embedding_model(ultra_minimal_params);
|
|
465
|
+
ultra_minimal_params.cont_batching = false;
|
|
466
|
+
ultra_minimal_params.n_parallel = 1;
|
|
467
|
+
ultra_minimal_params.antiprompt.clear();
|
|
468
|
+
ultra_minimal_params.vocab_only = false;
|
|
469
|
+
ultra_minimal_params.rope_scaling_type = LLAMA_ROPE_SCALING_TYPE_UNSPECIFIED;
|
|
470
|
+
ultra_minimal_params.yarn_ext_factor = -1.0f;
|
|
471
|
+
ultra_minimal_params.yarn_attn_factor = 1.0f;
|
|
472
|
+
ultra_minimal_params.yarn_beta_fast = 32.0f;
|
|
473
|
+
ultra_minimal_params.yarn_beta_slow = 1.0f;
|
|
474
|
+
ultra_minimal_params.yarn_orig_ctx = 0;
|
|
475
|
+
ultra_minimal_params.flash_attn = false;
|
|
476
|
+
ultra_minimal_params.n_keep = 0;
|
|
477
|
+
ultra_minimal_params.n_chunks = -1;
|
|
478
|
+
ultra_minimal_params.n_sequences = 1;
|
|
479
|
+
ultra_minimal_params.model_alias = "unknown";
|
|
480
|
+
|
|
481
|
+
// Set up signal handler again for ultra-minimal attempt
|
|
482
|
+
if (sigaction(SIGSEGV, &new_action, &old_action) == 0) {
|
|
483
|
+
LOGI("Signal handler reinstalled for ultra-minimal attempt");
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
try {
|
|
487
|
+
load_success = context->loadModel(ultra_minimal_params);
|
|
488
|
+
} catch (const std::exception& e) {
|
|
489
|
+
LOGE("Exception during ultra-minimal model loading: %s", e.what());
|
|
490
|
+
load_success = false;
|
|
491
|
+
} catch (...) {
|
|
492
|
+
LOGE("Unknown exception during ultra-minimal model loading");
|
|
493
|
+
load_success = false;
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
// Restore original signal handler
|
|
497
|
+
sigaction(SIGSEGV, &old_action, nullptr);
|
|
498
|
+
|
|
499
|
+
if (!load_success) {
|
|
500
|
+
LOGE("Model loading failed even with ultra-minimal parameters");
|
|
501
|
+
throw_java_exception(env, "java/lang/RuntimeException",
|
|
502
|
+
"Failed to load model - model appears to be corrupted or incompatible with this llama.cpp version. "
|
|
503
|
+
"Try downloading a fresh copy of the model file.");
|
|
504
|
+
return -1;
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
LOGI("Model loaded successfully!");
|
|
509
|
+
|
|
510
|
+
// Store context
|
|
511
|
+
jlong context_id = next_context_id++;
|
|
512
|
+
capllama::llama_cap_context* raw_ctx = context.get();
|
|
513
|
+
contexts[context_id] = std::move(context);
|
|
514
|
+
llama_embedding_register_context(context_id, raw_ctx);
|
|
515
|
+
|
|
516
|
+
LOGI("Initialized context %ld with model: %s", context_id, full_model_path.c_str());
|
|
517
|
+
return context_id;
|
|
518
|
+
|
|
519
|
+
} catch (const std::exception& e) {
|
|
520
|
+
LOGE("Exception in initContext: %s", e.what());
|
|
521
|
+
throw_java_exception(env, "java/lang/RuntimeException", e.what());
|
|
522
|
+
return -1;
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
JNIEXPORT void JNICALL
|
|
527
|
+
Java_ai_annadata_plugin_capacitor_LlamaCpp_releaseContextNative(
|
|
528
|
+
JNIEnv* env, jobject thiz, jlong context_id) {
|
|
529
|
+
|
|
530
|
+
try {
|
|
531
|
+
auto it = contexts.find(context_id);
|
|
532
|
+
if (it != contexts.end()) {
|
|
533
|
+
llama_embedding_unregister_context(context_id);
|
|
534
|
+
contexts.erase(it);
|
|
535
|
+
LOGI("Released context %ld", context_id);
|
|
536
|
+
}
|
|
537
|
+
} catch (const std::exception& e) {
|
|
538
|
+
LOGE("Exception in releaseContext: %s", e.what());
|
|
539
|
+
throw_java_exception(env, "java/lang/RuntimeException", e.what());
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
JNIEXPORT jobject JNICALL
|
|
544
|
+
Java_ai_annadata_plugin_capacitor_LlamaCpp_completionNative(
|
|
545
|
+
JNIEnv* env, jobject thiz, jlong context_id, jobject params) {
|
|
546
|
+
|
|
547
|
+
try {
|
|
548
|
+
LOGI("Starting completion for context: %ld", context_id);
|
|
549
|
+
|
|
550
|
+
auto it = contexts.find(context_id);
|
|
551
|
+
if (it == contexts.end()) {
|
|
552
|
+
LOGE("Context not found: %ld", context_id);
|
|
553
|
+
throw_java_exception(env, "java/lang/IllegalArgumentException", "Invalid context ID");
|
|
554
|
+
return nullptr;
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
auto& ctx = it->second;
|
|
558
|
+
if (!ctx || !ctx->ctx) {
|
|
559
|
+
LOGE("Invalid context or llama context is null");
|
|
560
|
+
throw_java_exception(env, "java/lang/RuntimeException", "Invalid context");
|
|
561
|
+
return nullptr;
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
// Extract parameters from JSObject using compatible API
|
|
565
|
+
jclass jsObjectClass = env->GetObjectClass(params);
|
|
566
|
+
|
|
567
|
+
// Try to get method IDs and handle exceptions
|
|
568
|
+
jmethodID getStringMethod = nullptr;
|
|
569
|
+
jmethodID getIntegerMethod = nullptr;
|
|
570
|
+
|
|
571
|
+
// Clear any pending exceptions first
|
|
572
|
+
if (env->ExceptionCheck()) {
|
|
573
|
+
env->ExceptionClear();
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
try {
|
|
577
|
+
getStringMethod = env->GetMethodID(jsObjectClass, "getString", "(Ljava/lang/String;)Ljava/lang/String;");
|
|
578
|
+
if (env->ExceptionCheck()) {
|
|
579
|
+
env->ExceptionClear();
|
|
580
|
+
getStringMethod = nullptr;
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
getIntegerMethod = env->GetMethodID(jsObjectClass, "getInteger", "(Ljava/lang/String;)Ljava/lang/Integer;");
|
|
584
|
+
if (env->ExceptionCheck()) {
|
|
585
|
+
env->ExceptionClear();
|
|
586
|
+
getIntegerMethod = nullptr;
|
|
587
|
+
}
|
|
588
|
+
} catch (...) {
|
|
589
|
+
LOGE("Exception getting JSObject method IDs");
|
|
590
|
+
if (env->ExceptionCheck()) {
|
|
591
|
+
env->ExceptionClear();
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
// Get prompt with safe method calls
|
|
596
|
+
std::string prompt_str = "Once upon a time";
|
|
597
|
+
jint n_predict = 50;
|
|
598
|
+
jdouble temperature = 0.7;
|
|
599
|
+
|
|
600
|
+
if (getStringMethod) {
|
|
601
|
+
jstring promptKey = jni_utils::string_to_jstring(env, "prompt");
|
|
602
|
+
jstring promptObj = (jstring)env->CallObjectMethod(params, getStringMethod, promptKey);
|
|
603
|
+
if (promptObj && !env->ExceptionCheck()) {
|
|
604
|
+
prompt_str = jni_utils::jstring_to_string(env, promptObj);
|
|
605
|
+
} else if (env->ExceptionCheck()) {
|
|
606
|
+
env->ExceptionClear();
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
// Get n_predict with safe method calls
|
|
611
|
+
if (getIntegerMethod) {
|
|
612
|
+
jstring nPredictKey = jni_utils::string_to_jstring(env, "n_predict");
|
|
613
|
+
jobject nPredictObj = env->CallObjectMethod(params, getIntegerMethod, nPredictKey);
|
|
614
|
+
if (nPredictObj && !env->ExceptionCheck()) {
|
|
615
|
+
n_predict = env->CallIntMethod(nPredictObj, env->GetMethodID(env->FindClass("java/lang/Integer"), "intValue", "()I"));
|
|
616
|
+
if (env->ExceptionCheck()) {
|
|
617
|
+
env->ExceptionClear();
|
|
618
|
+
n_predict = 50; // fallback
|
|
619
|
+
}
|
|
620
|
+
} else if (env->ExceptionCheck()) {
|
|
621
|
+
env->ExceptionClear();
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
temperature = jni_utils::jsobject_opt_double(env, params, "temperature", 0.7);
|
|
626
|
+
|
|
627
|
+
// --- Full sampling parameter propagation ---
|
|
628
|
+
ctx->params.sampling.top_k = (int)jni_utils::jsobject_opt_double(env, params, "top_k", 40);
|
|
629
|
+
ctx->params.sampling.top_p = (float)jni_utils::jsobject_opt_double(env, params, "top_p", 0.95);
|
|
630
|
+
ctx->params.sampling.min_p = (float)jni_utils::jsobject_opt_double(env, params, "min_p", 0.05);
|
|
631
|
+
ctx->params.sampling.typ_p = (float)jni_utils::jsobject_opt_double(env, params, "typical_p", 1.0);
|
|
632
|
+
ctx->params.sampling.penalty_repeat = (float)jni_utils::jsobject_opt_double(env, params, "penalty_repeat", 1.1);
|
|
633
|
+
ctx->params.sampling.penalty_freq = (float)jni_utils::jsobject_opt_double(env, params, "penalty_freq", 0.0);
|
|
634
|
+
ctx->params.sampling.penalty_present = (float)jni_utils::jsobject_opt_double(env, params, "penalty_present", 0.0);
|
|
635
|
+
ctx->params.sampling.penalty_last_n = (int)jni_utils::jsobject_opt_double(env, params, "penalty_last_n", 64);
|
|
636
|
+
ctx->params.sampling.mirostat = (int)jni_utils::jsobject_opt_double(env, params, "mirostat", 0);
|
|
637
|
+
ctx->params.sampling.mirostat_tau = (float)jni_utils::jsobject_opt_double(env, params, "mirostat_tau", 5.0);
|
|
638
|
+
ctx->params.sampling.mirostat_eta = (float)jni_utils::jsobject_opt_double(env, params, "mirostat_eta", 0.1);
|
|
639
|
+
ctx->params.sampling.xtc_probability = (float)jni_utils::jsobject_opt_double(env, params, "xtc_probability", 0.0);
|
|
640
|
+
ctx->params.sampling.xtc_threshold = (float)jni_utils::jsobject_opt_double(env, params, "xtc_threshold", 0.1);
|
|
641
|
+
ctx->params.sampling.dry_multiplier = (float)jni_utils::jsobject_opt_double(env, params, "dry_multiplier", 0.0);
|
|
642
|
+
ctx->params.sampling.dry_base = (float)jni_utils::jsobject_opt_double(env, params, "dry_base", 1.75);
|
|
643
|
+
ctx->params.sampling.dry_allowed_length = (int)jni_utils::jsobject_opt_double(env, params, "dry_allowed_length", 2);
|
|
644
|
+
ctx->params.sampling.dry_penalty_last_n = (int)jni_utils::jsobject_opt_double(env, params, "dry_penalty_last_n", -1);
|
|
645
|
+
ctx->params.sampling.top_n_sigma = (float)jni_utils::jsobject_opt_double(env, params, "top_n_sigma", -1.0);
|
|
646
|
+
ctx->params.sampling.seed = (uint32_t)(int64_t)jni_utils::jsobject_opt_double(env, params, "seed", -1);
|
|
647
|
+
ctx->params.sampling.n_probs = (int)jni_utils::jsobject_opt_double(env, params, "n_probs", 0);
|
|
648
|
+
|
|
649
|
+
// Grammar
|
|
650
|
+
std::string grammar_str = jni_utils::jsobject_opt_string(env, params, "grammar", "");
|
|
651
|
+
ctx->params.sampling.grammar = grammar_str;
|
|
652
|
+
|
|
653
|
+
// Stop strings
|
|
654
|
+
ctx->params.antiprompt.clear();
|
|
655
|
+
if (getStringMethod) {
|
|
656
|
+
jstring stopKey = jni_utils::string_to_jstring(env, "stop");
|
|
657
|
+
jobject stopObj = env->CallObjectMethod(params, getStringMethod, stopKey);
|
|
658
|
+
env->DeleteLocalRef(stopKey);
|
|
659
|
+
if (stopObj && !env->ExceptionCheck()) {
|
|
660
|
+
// stop is passed as a JSON array string from the Java side
|
|
661
|
+
std::string stop_json = jni_utils::jstring_to_string(env, (jstring)stopObj);
|
|
662
|
+
env->DeleteLocalRef(stopObj);
|
|
663
|
+
if (!stop_json.empty() && stop_json[0] == '[') {
|
|
664
|
+
try {
|
|
665
|
+
auto j = nlohmann::json::parse(stop_json);
|
|
666
|
+
for (const auto& el : j) {
|
|
667
|
+
if (el.is_string()) ctx->params.antiprompt.push_back(el.get<std::string>());
|
|
668
|
+
}
|
|
669
|
+
} catch (...) {}
|
|
670
|
+
}
|
|
671
|
+
} else if (env->ExceptionCheck()) {
|
|
672
|
+
env->ExceptionClear();
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
// ------------------------------------------
|
|
676
|
+
|
|
677
|
+
// Set sampling parameters based on extracted values
|
|
678
|
+
ctx->params.sampling.temp = temperature;
|
|
679
|
+
ctx->params.sampling.top_k = 40; // Default value
|
|
680
|
+
ctx->params.sampling.top_p = 0.95f; // Default value
|
|
681
|
+
ctx->params.sampling.penalty_repeat = 1.1f; // Default value (correct field name)
|
|
682
|
+
ctx->params.n_predict = n_predict;
|
|
683
|
+
ctx->params.prompt = prompt_str;
|
|
684
|
+
|
|
685
|
+
LOGI("Updated context sampling params - temp: %.2f, top_k: %d, top_p: %.2f",
|
|
686
|
+
ctx->params.sampling.temp, ctx->params.sampling.top_k, ctx->params.sampling.top_p);
|
|
687
|
+
|
|
688
|
+
// Tokenize the prompt
|
|
689
|
+
capllama::llama_cap_tokenize_result tokenize_result = ctx->tokenize(prompt_str, {});
|
|
690
|
+
std::vector<llama_token> prompt_tokens = tokenize_result.tokens;
|
|
691
|
+
|
|
692
|
+
LOGI("Tokenized prompt into %zu tokens", prompt_tokens.size());
|
|
693
|
+
|
|
694
|
+
// Initialize completion context if not already done
|
|
695
|
+
if (!ctx->completion) {
|
|
696
|
+
LOGI("Initializing completion context for the first time");
|
|
697
|
+
|
|
698
|
+
// Validate parent context before creating completion
|
|
699
|
+
if (!ctx->ctx || !ctx->model) {
|
|
700
|
+
LOGE("Parent context is invalid - missing llama context or model");
|
|
701
|
+
throw_java_exception(env, "java/lang/RuntimeException", "Parent context is not properly initialized");
|
|
702
|
+
return nullptr;
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
try {
|
|
706
|
+
LOGI("Creating llama_cap_context_completion...");
|
|
707
|
+
LOGI("Parent context pointer: %p", ctx.get());
|
|
708
|
+
LOGI("Parent context->ctx: %p", ctx->ctx);
|
|
709
|
+
LOGI("Parent context->model: %p", ctx->model);
|
|
710
|
+
|
|
711
|
+
// Additional safety checks before constructor
|
|
712
|
+
if (!ctx.get()) {
|
|
713
|
+
LOGE("Parent context pointer is null");
|
|
714
|
+
throw_java_exception(env, "java/lang/RuntimeException", "Parent context pointer is null");
|
|
715
|
+
return nullptr;
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
ctx->completion = new capllama::llama_cap_context_completion(ctx.get());
|
|
719
|
+
|
|
720
|
+
if (!ctx->completion) {
|
|
721
|
+
LOGE("Failed to create completion context - constructor returned null");
|
|
722
|
+
throw_java_exception(env, "java/lang/RuntimeException", "Failed to create completion context");
|
|
723
|
+
return nullptr;
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
LOGI("Completion context created successfully at: %p", ctx->completion);
|
|
727
|
+
|
|
728
|
+
LOGI("Initializing sampling for completion context...");
|
|
729
|
+
LOGI("Parent context params before initSampling - model: %p, params: %p", ctx->model, &(ctx->params));
|
|
730
|
+
LOGI("Parent context sampling params - temperature: %.2f, top_k: %d, top_p: %.2f",
|
|
731
|
+
ctx->params.sampling.temp, ctx->params.sampling.top_k, ctx->params.sampling.top_p);
|
|
732
|
+
|
|
733
|
+
bool sampling_result = false;
|
|
734
|
+
try {
|
|
735
|
+
sampling_result = ctx->completion->initSampling();
|
|
736
|
+
LOGI("initSampling completed, result: %s", sampling_result ? "true" : "false");
|
|
737
|
+
LOGI("Sampler pointer after init: %p", ctx->completion->ctx_sampling);
|
|
738
|
+
} catch (const std::exception& e) {
|
|
739
|
+
LOGE("Exception in initSampling: %s", e.what());
|
|
740
|
+
delete ctx->completion;
|
|
741
|
+
ctx->completion = nullptr;
|
|
742
|
+
throw_java_exception(env, "java/lang/RuntimeException",
|
|
743
|
+
("Failed to initialize sampling: " + std::string(e.what())).c_str());
|
|
744
|
+
return nullptr;
|
|
745
|
+
} catch (...) {
|
|
746
|
+
LOGE("Unknown exception in initSampling");
|
|
747
|
+
delete ctx->completion;
|
|
748
|
+
ctx->completion = nullptr;
|
|
749
|
+
throw_java_exception(env, "java/lang/RuntimeException", "Unknown error in sampling initialization");
|
|
750
|
+
return nullptr;
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
if (!sampling_result || !ctx->completion->ctx_sampling) {
|
|
754
|
+
LOGE("Failed to initialize sampling - result: %s, sampler: %p",
|
|
755
|
+
sampling_result ? "true" : "false", ctx->completion->ctx_sampling);
|
|
756
|
+
delete ctx->completion;
|
|
757
|
+
ctx->completion = nullptr;
|
|
758
|
+
throw_java_exception(env, "java/lang/RuntimeException", "Failed to initialize sampling context");
|
|
759
|
+
return nullptr;
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
LOGI("Completion context initialized successfully");
|
|
763
|
+
} catch (const std::exception& e) {
|
|
764
|
+
LOGE("Exception during completion context creation: %s", e.what());
|
|
765
|
+
if (ctx->completion) {
|
|
766
|
+
delete ctx->completion;
|
|
767
|
+
ctx->completion = nullptr;
|
|
768
|
+
}
|
|
769
|
+
throw_java_exception(env, "java/lang/RuntimeException",
|
|
770
|
+
("Failed to create completion context: " + std::string(e.what())).c_str());
|
|
771
|
+
return nullptr;
|
|
772
|
+
} catch (...) {
|
|
773
|
+
LOGE("Unknown exception during completion context creation");
|
|
774
|
+
if (ctx->completion) {
|
|
775
|
+
delete ctx->completion;
|
|
776
|
+
ctx->completion = nullptr;
|
|
777
|
+
}
|
|
778
|
+
throw_java_exception(env, "java/lang/RuntimeException", "Unknown error during completion context creation");
|
|
779
|
+
return nullptr;
|
|
780
|
+
}
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
// Set up sampling parameters
|
|
784
|
+
// Note: For now, we'll use the completion context's default parameters
|
|
785
|
+
// TODO: Update sampling parameters with user values
|
|
786
|
+
//
|
|
787
|
+
// Declare variables outside try block so they're accessible later
|
|
788
|
+
std::string generated_text;
|
|
789
|
+
int tokens_generated = 0;
|
|
790
|
+
|
|
791
|
+
try {
|
|
792
|
+
LOGI("Rewinding completion context...");
|
|
793
|
+
try {
|
|
794
|
+
ctx->completion->rewind();
|
|
795
|
+
LOGI("Rewind completed successfully");
|
|
796
|
+
} catch (const std::exception& e) {
|
|
797
|
+
LOGE("Exception in rewind: %s", e.what());
|
|
798
|
+
throw;
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
LOGI("Loading prompt into completion context...");
|
|
802
|
+
try {
|
|
803
|
+
// Validate sampler is properly initialized before loadPrompt
|
|
804
|
+
if (!ctx->completion->ctx_sampling) {
|
|
805
|
+
LOGE("Sampler context is null - reinitializing");
|
|
806
|
+
if (!ctx->completion->initSampling()) {
|
|
807
|
+
LOGE("Failed to reinitialize sampling");
|
|
808
|
+
throw std::runtime_error("Sampler initialization failed");
|
|
809
|
+
}
|
|
810
|
+
LOGI("Sampler reinitialized successfully");
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
ctx->completion->loadPrompt({});
|
|
814
|
+
LOGI("loadPrompt completed successfully");
|
|
815
|
+
} catch (const std::exception& e) {
|
|
816
|
+
LOGE("Exception in loadPrompt: %s", e.what());
|
|
817
|
+
throw;
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
LOGI("Beginning completion generation...");
|
|
821
|
+
try {
|
|
822
|
+
ctx->completion->beginCompletion();
|
|
823
|
+
LOGI("beginCompletion completed successfully");
|
|
824
|
+
} catch (const std::exception& e) {
|
|
825
|
+
LOGE("Exception in beginCompletion: %s", e.what());
|
|
826
|
+
throw;
|
|
827
|
+
}
|
|
828
|
+
|
|
829
|
+
LOGI("Starting token generation loop (max tokens: %d)...", n_predict);
|
|
830
|
+
|
|
831
|
+
while (tokens_generated < n_predict && !ctx->completion->is_interrupted) {
|
|
832
|
+
try {
|
|
833
|
+
LOGI("Generating token %d...", tokens_generated + 1);
|
|
834
|
+
auto token_output = ctx->completion->nextToken();
|
|
835
|
+
|
|
836
|
+
// Check for end-of-sequence (simplified check)
|
|
837
|
+
if (token_output.tok == 2) { // Most models use 2 as EOS token
|
|
838
|
+
LOGI("Reached EOS token, stopping generation");
|
|
839
|
+
break;
|
|
840
|
+
}
|
|
841
|
+
|
|
842
|
+
// Convert token to text
|
|
843
|
+
std::string token_text = capllama::tokens_to_output_formatted_string(ctx->ctx, token_output.tok);
|
|
844
|
+
generated_text += token_text;
|
|
845
|
+
tokens_generated++;
|
|
846
|
+
|
|
847
|
+
LOGI("Generated token %d (ID: %d): %s", tokens_generated, token_output.tok, token_text.c_str());
|
|
848
|
+
|
|
849
|
+
} catch (const std::exception& e) {
|
|
850
|
+
LOGE("Exception during token generation %d: %s", tokens_generated + 1, e.what());
|
|
851
|
+
break;
|
|
852
|
+
} catch (...) {
|
|
853
|
+
LOGE("Unknown exception during token generation %d", tokens_generated + 1);
|
|
854
|
+
break;
|
|
855
|
+
}
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
LOGI("Token generation completed. Generated %d tokens.", tokens_generated);
|
|
859
|
+
|
|
860
|
+
// End completion
|
|
861
|
+
LOGI("Ending completion...");
|
|
862
|
+
ctx->completion->endCompletion();
|
|
863
|
+
|
|
864
|
+
} catch (const std::exception& e) {
|
|
865
|
+
LOGE("Exception during completion process: %s", e.what());
|
|
866
|
+
try {
|
|
867
|
+
ctx->completion->endCompletion();
|
|
868
|
+
} catch (...) {
|
|
869
|
+
LOGE("Failed to properly end completion after exception");
|
|
870
|
+
}
|
|
871
|
+
throw_java_exception(env, "java/lang/RuntimeException",
|
|
872
|
+
("Completion process failed: " + std::string(e.what())).c_str());
|
|
873
|
+
return nullptr;
|
|
874
|
+
} catch (...) {
|
|
875
|
+
LOGE("Unknown exception during completion process");
|
|
876
|
+
try {
|
|
877
|
+
ctx->completion->endCompletion();
|
|
878
|
+
} catch (...) {
|
|
879
|
+
LOGE("Failed to properly end completion after unknown exception");
|
|
880
|
+
}
|
|
881
|
+
throw_java_exception(env, "java/lang/RuntimeException", "Unknown error during completion process");
|
|
882
|
+
return nullptr;
|
|
883
|
+
}
|
|
884
|
+
|
|
885
|
+
LOGI("Completion finished. Generated %d tokens: %s", tokens_generated, generated_text.c_str());
|
|
886
|
+
|
|
887
|
+
// Create result HashMap
|
|
888
|
+
jclass hashMapClass = env->FindClass("java/util/HashMap");
|
|
889
|
+
jmethodID hashMapConstructor = env->GetMethodID(hashMapClass, "<init>", "()V");
|
|
890
|
+
jmethodID putMethod = env->GetMethodID(hashMapClass, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
|
|
891
|
+
|
|
892
|
+
jobject resultMap = env->NewObject(hashMapClass, hashMapConstructor);
|
|
893
|
+
|
|
894
|
+
// Add completion results
|
|
895
|
+
env->CallObjectMethod(resultMap, putMethod,
|
|
896
|
+
jni_utils::string_to_jstring(env, "text"), jni_utils::string_to_jstring(env, generated_text));
|
|
897
|
+
env->CallObjectMethod(resultMap, putMethod,
|
|
898
|
+
jni_utils::string_to_jstring(env, "content"), jni_utils::string_to_jstring(env, generated_text));
|
|
899
|
+
env->CallObjectMethod(resultMap, putMethod,
|
|
900
|
+
jni_utils::string_to_jstring(env, "reasoning_content"), jni_utils::string_to_jstring(env, ""));
|
|
901
|
+
|
|
902
|
+
// Create empty tool_calls array
|
|
903
|
+
jclass arrayListClass = env->FindClass("java/util/ArrayList");
|
|
904
|
+
jmethodID arrayListConstructor = env->GetMethodID(arrayListClass, "<init>", "()V");
|
|
905
|
+
jobject emptyToolCalls = env->NewObject(arrayListClass, arrayListConstructor);
|
|
906
|
+
env->CallObjectMethod(resultMap, putMethod,
|
|
907
|
+
jni_utils::string_to_jstring(env, "tool_calls"), emptyToolCalls);
|
|
908
|
+
|
|
909
|
+
// Add token counts and status
|
|
910
|
+
env->CallObjectMethod(resultMap, putMethod,
|
|
911
|
+
jni_utils::string_to_jstring(env, "tokens_predicted"),
|
|
912
|
+
env->NewObject(env->FindClass("java/lang/Integer"),
|
|
913
|
+
env->GetMethodID(env->FindClass("java/lang/Integer"), "<init>", "(I)V"), tokens_generated));
|
|
914
|
+
env->CallObjectMethod(resultMap, putMethod,
|
|
915
|
+
jni_utils::string_to_jstring(env, "tokens_evaluated"),
|
|
916
|
+
env->NewObject(env->FindClass("java/lang/Integer"),
|
|
917
|
+
env->GetMethodID(env->FindClass("java/lang/Integer"), "<init>", "(I)V"), (jint)prompt_tokens.size()));
|
|
918
|
+
|
|
919
|
+
// Add completion status flags
|
|
920
|
+
env->CallObjectMethod(resultMap, putMethod,
|
|
921
|
+
jni_utils::string_to_jstring(env, "truncated"),
|
|
922
|
+
env->NewObject(env->FindClass("java/lang/Boolean"),
|
|
923
|
+
env->GetMethodID(env->FindClass("java/lang/Boolean"), "<init>", "(Z)V"), JNI_FALSE));
|
|
924
|
+
env->CallObjectMethod(resultMap, putMethod,
|
|
925
|
+
jni_utils::string_to_jstring(env, "stopped_eos"),
|
|
926
|
+
env->NewObject(env->FindClass("java/lang/Boolean"),
|
|
927
|
+
env->GetMethodID(env->FindClass("java/lang/Boolean"), "<init>", "(Z)V"),
|
|
928
|
+
tokens_generated < n_predict ? JNI_TRUE : JNI_FALSE));
|
|
929
|
+
env->CallObjectMethod(resultMap, putMethod,
|
|
930
|
+
jni_utils::string_to_jstring(env, "stopped_limit"),
|
|
931
|
+
env->NewObject(env->FindClass("java/lang/Boolean"),
|
|
932
|
+
env->GetMethodID(env->FindClass("java/lang/Boolean"), "<init>", "(Z)V"),
|
|
933
|
+
tokens_generated >= n_predict ? JNI_TRUE : JNI_FALSE));
|
|
934
|
+
env->CallObjectMethod(resultMap, putMethod,
|
|
935
|
+
jni_utils::string_to_jstring(env, "context_full"),
|
|
936
|
+
env->NewObject(env->FindClass("java/lang/Boolean"),
|
|
937
|
+
env->GetMethodID(env->FindClass("java/lang/Boolean"), "<init>", "(Z)V"), JNI_FALSE));
|
|
938
|
+
env->CallObjectMethod(resultMap, putMethod,
|
|
939
|
+
jni_utils::string_to_jstring(env, "interrupted"),
|
|
940
|
+
env->NewObject(env->FindClass("java/lang/Boolean"),
|
|
941
|
+
env->GetMethodID(env->FindClass("java/lang/Boolean"), "<init>", "(Z)V"), JNI_FALSE));
|
|
942
|
+
|
|
943
|
+
// Add empty strings for stop reasons
|
|
944
|
+
env->CallObjectMethod(resultMap, putMethod,
|
|
945
|
+
jni_utils::string_to_jstring(env, "stopped_word"), jni_utils::string_to_jstring(env, ""));
|
|
946
|
+
env->CallObjectMethod(resultMap, putMethod,
|
|
947
|
+
jni_utils::string_to_jstring(env, "stopping_word"), jni_utils::string_to_jstring(env, ""));
|
|
948
|
+
|
|
949
|
+
// Add timing information (basic)
|
|
950
|
+
jobject timingsMap = env->NewObject(hashMapClass, hashMapConstructor);
|
|
951
|
+
env->CallObjectMethod(timingsMap, putMethod,
|
|
952
|
+
jni_utils::string_to_jstring(env, "prompt_n"),
|
|
953
|
+
env->NewObject(env->FindClass("java/lang/Integer"),
|
|
954
|
+
env->GetMethodID(env->FindClass("java/lang/Integer"), "<init>", "(I)V"), (jint)prompt_tokens.size()));
|
|
955
|
+
env->CallObjectMethod(timingsMap, putMethod,
|
|
956
|
+
jni_utils::string_to_jstring(env, "predicted_n"),
|
|
957
|
+
env->NewObject(env->FindClass("java/lang/Integer"),
|
|
958
|
+
env->GetMethodID(env->FindClass("java/lang/Integer"), "<init>", "(I)V"), tokens_generated));
|
|
959
|
+
env->CallObjectMethod(resultMap, putMethod,
|
|
960
|
+
jni_utils::string_to_jstring(env, "timings"), timingsMap);
|
|
961
|
+
|
|
962
|
+
LOGI("Completion result created successfully");
|
|
963
|
+
return resultMap;
|
|
964
|
+
|
|
965
|
+
} catch (const std::exception& e) {
|
|
966
|
+
LOGE("Exception in completion: %s", e.what());
|
|
967
|
+
throw_java_exception(env, "java/lang/RuntimeException", e.what());
|
|
968
|
+
return nullptr;
|
|
969
|
+
}
|
|
970
|
+
}
|
|
971
|
+
|
|
972
|
+
JNIEXPORT void JNICALL
|
|
973
|
+
Java_ai_annadata_plugin_capacitor_LlamaCpp_stopCompletionNative(
|
|
974
|
+
JNIEnv* env, jobject thiz, jlong context_id) {
|
|
975
|
+
|
|
976
|
+
try {
|
|
977
|
+
auto it = contexts.find(context_id);
|
|
978
|
+
if (it != contexts.end()) {
|
|
979
|
+
// Stop completion logic would go here
|
|
980
|
+
LOGI("Stopped completion for context %ld", context_id);
|
|
981
|
+
}
|
|
982
|
+
} catch (const std::exception& e) {
|
|
983
|
+
LOGE("Exception in stopCompletion: %s", e.what());
|
|
984
|
+
throw_java_exception(env, "java/lang/RuntimeException", e.what());
|
|
985
|
+
}
|
|
986
|
+
}
|
|
987
|
+
|
|
988
|
+
JNIEXPORT jstring JNICALL
|
|
989
|
+
Java_ai_annadata_plugin_capacitor_LlamaCpp_getFormattedChatNative(
|
|
990
|
+
JNIEnv* env, jobject thiz, jlong context_id, jstring messages, jstring chat_template) {
|
|
991
|
+
|
|
992
|
+
try {
|
|
993
|
+
auto it = contexts.find(context_id);
|
|
994
|
+
if (it == contexts.end()) {
|
|
995
|
+
throw_java_exception(env, "java/lang/IllegalArgumentException", "Invalid context ID");
|
|
996
|
+
return nullptr;
|
|
997
|
+
}
|
|
998
|
+
|
|
999
|
+
std::string messages_str = jstring_to_string(env, messages);
|
|
1000
|
+
std::string template_str = jstring_to_string(env, chat_template);
|
|
1001
|
+
|
|
1002
|
+
capllama::llama_cap_context* context = it->second.get();
|
|
1003
|
+
|
|
1004
|
+
// Format chat using the context's method
|
|
1005
|
+
std::string result = context->getFormattedChat(messages_str, template_str);
|
|
1006
|
+
|
|
1007
|
+
LOGI("Formatted chat for context %ld", context_id);
|
|
1008
|
+
return string_to_jstring(env, result);
|
|
1009
|
+
|
|
1010
|
+
} catch (const std::exception& e) {
|
|
1011
|
+
LOGE("Exception in getFormattedChat: %s", e.what());
|
|
1012
|
+
throw_java_exception(env, "java/lang/RuntimeException", e.what());
|
|
1013
|
+
return nullptr;
|
|
1014
|
+
}
|
|
1015
|
+
}
|
|
1016
|
+
|
|
1017
|
+
JNIEXPORT jboolean JNICALL
|
|
1018
|
+
Java_ai_annadata_plugin_capacitor_LlamaCpp_toggleNativeLogNative(
|
|
1019
|
+
JNIEnv* env, jobject thiz, jboolean enabled) {
|
|
1020
|
+
|
|
1021
|
+
try {
|
|
1022
|
+
// rnllama::rnllama_verbose = jboolean_to_bool(enabled); // This line is removed as per the edit hint
|
|
1023
|
+
LOGI("Native logging %s", enabled ? "enabled" : "disabled");
|
|
1024
|
+
return bool_to_jboolean(true);
|
|
1025
|
+
} catch (const std::exception& e) {
|
|
1026
|
+
LOGE("Exception in toggleNativeLog: %s", e.what());
|
|
1027
|
+
throw_java_exception(env, "java/lang/RuntimeException", e.what());
|
|
1028
|
+
return bool_to_jboolean(false);
|
|
1029
|
+
}
|
|
1030
|
+
}
|
|
1031
|
+
|
|
1032
|
+
JNIEXPORT jobject JNICALL
|
|
1033
|
+
Java_ai_annadata_plugin_capacitor_LlamaCpp_modelInfoNative(
|
|
1034
|
+
JNIEnv* env, jobject thiz, jstring model_path) {
|
|
1035
|
+
|
|
1036
|
+
try {
|
|
1037
|
+
std::string model_path_str = jstring_to_string(env, model_path);
|
|
1038
|
+
LOGI("Getting model info for: %s", model_path_str.c_str());
|
|
1039
|
+
|
|
1040
|
+
// Extract filename from path
|
|
1041
|
+
std::string filename = model_path_str;
|
|
1042
|
+
size_t last_slash = model_path_str.find_last_of('/');
|
|
1043
|
+
if (last_slash != std::string::npos) {
|
|
1044
|
+
filename = model_path_str.substr(last_slash + 1);
|
|
1045
|
+
}
|
|
1046
|
+
LOGI("Extracted filename for model info: %s", filename.c_str());
|
|
1047
|
+
|
|
1048
|
+
// List all possible paths we should check (same as initContextNative)
|
|
1049
|
+
std::vector<std::string> paths_to_check = {
|
|
1050
|
+
model_path_str, // Try the original path first
|
|
1051
|
+
"/data/data/ai.annadata.llamacpp/files/" + filename,
|
|
1052
|
+
"/data/data/ai.annadata.llamacpp/files/Documents/" + filename,
|
|
1053
|
+
"/storage/emulated/0/Android/data/ai.annadata.llamacpp/files/" + filename,
|
|
1054
|
+
"/storage/emulated/0/Android/data/ai.annadata.llamacpp/files/Documents/" + filename,
|
|
1055
|
+
"/storage/emulated/0/Documents/" + filename,
|
|
1056
|
+
"/storage/emulated/0/Download/" + filename
|
|
1057
|
+
};
|
|
1058
|
+
|
|
1059
|
+
// Check each path and find the actual file
|
|
1060
|
+
std::string full_model_path;
|
|
1061
|
+
bool file_found = false;
|
|
1062
|
+
|
|
1063
|
+
for (const auto& path : paths_to_check) {
|
|
1064
|
+
LOGI("Checking path for model info: %s", path.c_str());
|
|
1065
|
+
std::ifstream file_check(path, std::ios::binary);
|
|
1066
|
+
if (file_check.good()) {
|
|
1067
|
+
file_check.seekg(0, std::ios::end);
|
|
1068
|
+
std::streamsize file_size = file_check.tellg();
|
|
1069
|
+
file_check.seekg(0, std::ios::beg);
|
|
1070
|
+
|
|
1071
|
+
// Validate file size
|
|
1072
|
+
if (file_size < 1024 * 1024) { // Less than 1MB
|
|
1073
|
+
LOGE("Model file is too small, likely corrupted: %s", path.c_str());
|
|
1074
|
+
file_check.close();
|
|
1075
|
+
continue; // Try next path
|
|
1076
|
+
}
|
|
1077
|
+
|
|
1078
|
+
// Check if it's a valid GGUF file by reading the magic number
|
|
1079
|
+
char magic[4];
|
|
1080
|
+
if (file_check.read(magic, 4)) {
|
|
1081
|
+
if (magic[0] == 'G' && magic[1] == 'G' && magic[2] == 'U' && magic[3] == 'F') {
|
|
1082
|
+
LOGI("Valid GGUF file detected for model info at: %s", path.c_str());
|
|
1083
|
+
full_model_path = path;
|
|
1084
|
+
file_found = true;
|
|
1085
|
+
file_check.close();
|
|
1086
|
+
break;
|
|
1087
|
+
} else {
|
|
1088
|
+
LOGI("File does not appear to be a GGUF file (magic: %c%c%c%c) at: %s",
|
|
1089
|
+
magic[0], magic[1], magic[2], magic[3], path.c_str());
|
|
1090
|
+
}
|
|
1091
|
+
}
|
|
1092
|
+
file_check.close();
|
|
1093
|
+
} else {
|
|
1094
|
+
LOGI("File not found at: %s", path.c_str());
|
|
1095
|
+
}
|
|
1096
|
+
}
|
|
1097
|
+
|
|
1098
|
+
if (!file_found) {
|
|
1099
|
+
LOGE("Model file not found in any of the checked paths");
|
|
1100
|
+
throw_java_exception(env, "java/lang/RuntimeException", "Model file not found");
|
|
1101
|
+
return nullptr;
|
|
1102
|
+
}
|
|
1103
|
+
|
|
1104
|
+
// Now use the found path for getting model info
|
|
1105
|
+
std::ifstream file_check(full_model_path, std::ios::binary);
|
|
1106
|
+
|
|
1107
|
+
// Get file size
|
|
1108
|
+
file_check.seekg(0, std::ios::end);
|
|
1109
|
+
std::streamsize file_size = file_check.tellg();
|
|
1110
|
+
file_check.seekg(0, std::ios::beg);
|
|
1111
|
+
|
|
1112
|
+
// Check GGUF magic number
|
|
1113
|
+
char magic[4];
|
|
1114
|
+
if (!file_check.read(magic, 4)) {
|
|
1115
|
+
LOGE("Failed to read magic number from: %s", full_model_path.c_str());
|
|
1116
|
+
throw_java_exception(env, "java/lang/RuntimeException", "Failed to read model file header");
|
|
1117
|
+
return nullptr;
|
|
1118
|
+
}
|
|
1119
|
+
|
|
1120
|
+
if (magic[0] != 'G' || magic[1] != 'G' || magic[2] != 'U' || magic[3] != 'F') {
|
|
1121
|
+
LOGE("Invalid GGUF file (magic: %c%c%c%c): %s", magic[0], magic[1], magic[2], magic[3], full_model_path.c_str());
|
|
1122
|
+
throw_java_exception(env, "java/lang/RuntimeException", "Invalid GGUF file format");
|
|
1123
|
+
return nullptr;
|
|
1124
|
+
}
|
|
1125
|
+
|
|
1126
|
+
// Read GGUF version
|
|
1127
|
+
uint32_t version;
|
|
1128
|
+
if (!file_check.read(reinterpret_cast<char*>(&version), sizeof(version))) {
|
|
1129
|
+
LOGE("Failed to read GGUF version from: %s", full_model_path.c_str());
|
|
1130
|
+
throw_java_exception(env, "java/lang/RuntimeException", "Failed to read GGUF version");
|
|
1131
|
+
return nullptr;
|
|
1132
|
+
}
|
|
1133
|
+
|
|
1134
|
+
file_check.close();
|
|
1135
|
+
|
|
1136
|
+
// Create Java HashMap
|
|
1137
|
+
jclass hashMapClass = env->FindClass("java/util/HashMap");
|
|
1138
|
+
jmethodID hashMapConstructor = env->GetMethodID(hashMapClass, "<init>", "()V");
|
|
1139
|
+
jmethodID putMethod = env->GetMethodID(hashMapClass, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
|
|
1140
|
+
|
|
1141
|
+
jobject hashMap = env->NewObject(hashMapClass, hashMapConstructor);
|
|
1142
|
+
|
|
1143
|
+
// Add model info to HashMap
|
|
1144
|
+
env->CallObjectMethod(hashMap, putMethod,
|
|
1145
|
+
string_to_jstring(env, "path"),
|
|
1146
|
+
string_to_jstring(env, full_model_path));
|
|
1147
|
+
|
|
1148
|
+
env->CallObjectMethod(hashMap, putMethod,
|
|
1149
|
+
string_to_jstring(env, "size"),
|
|
1150
|
+
env->NewObject(env->FindClass("java/lang/Long"),
|
|
1151
|
+
env->GetMethodID(env->FindClass("java/lang/Long"), "<init>", "(J)V"),
|
|
1152
|
+
static_cast<jlong>(file_size)));
|
|
1153
|
+
|
|
1154
|
+
env->CallObjectMethod(hashMap, putMethod,
|
|
1155
|
+
string_to_jstring(env, "desc"),
|
|
1156
|
+
string_to_jstring(env, "GGUF Model (v" + std::to_string(version) + ")"));
|
|
1157
|
+
|
|
1158
|
+
env->CallObjectMethod(hashMap, putMethod,
|
|
1159
|
+
string_to_jstring(env, "nEmbd"),
|
|
1160
|
+
env->NewObject(env->FindClass("java/lang/Integer"),
|
|
1161
|
+
env->GetMethodID(env->FindClass("java/lang/Integer"), "<init>", "(I)V"),
|
|
1162
|
+
0)); // Will be filled by actual model loading
|
|
1163
|
+
|
|
1164
|
+
env->CallObjectMethod(hashMap, putMethod,
|
|
1165
|
+
string_to_jstring(env, "nParams"),
|
|
1166
|
+
env->NewObject(env->FindClass("java/lang/Integer"),
|
|
1167
|
+
env->GetMethodID(env->FindClass("java/lang/Integer"), "<init>", "(I)V"),
|
|
1168
|
+
0)); // Will be filled by actual model loading
|
|
1169
|
+
|
|
1170
|
+
LOGI("Model info retrieved successfully from %s: size=%ld, version=%u", full_model_path.c_str(), file_size, version);
|
|
1171
|
+
return hashMap;
|
|
1172
|
+
|
|
1173
|
+
} catch (const std::exception& e) {
|
|
1174
|
+
LOGE("Exception in modelInfo: %s", e.what());
|
|
1175
|
+
throw_java_exception(env, "java/lang/RuntimeException", e.what());
|
|
1176
|
+
return nullptr;
|
|
1177
|
+
}
|
|
1178
|
+
}
|
|
1179
|
+
|
|
1180
|
+
|
|
1181
|
+
|
|
1182
|
+
JNIEXPORT jstring JNICALL
|
|
1183
|
+
Java_ai_annadata_plugin_capacitor_LlamaCpp_downloadModelNative(
|
|
1184
|
+
JNIEnv* env, jobject thiz, jstring url, jstring filename) {
|
|
1185
|
+
|
|
1186
|
+
try {
|
|
1187
|
+
std::string url_str = jstring_to_string(env, url);
|
|
1188
|
+
std::string filename_str = jstring_to_string(env, filename);
|
|
1189
|
+
|
|
1190
|
+
LOGI("Preparing download path for model: %s", filename_str.c_str());
|
|
1191
|
+
|
|
1192
|
+
// Determine local storage path (use external storage for large files)
|
|
1193
|
+
std::string local_path = "/storage/emulated/0/Android/data/ai.annadata.llamacpp/files/Models/" + filename_str;
|
|
1194
|
+
|
|
1195
|
+
// Create directory if it doesn't exist
|
|
1196
|
+
std::string dir_path = "/storage/emulated/0/Android/data/ai.annadata.llamacpp/files/Models/";
|
|
1197
|
+
std::filesystem::create_directories(dir_path);
|
|
1198
|
+
|
|
1199
|
+
LOGI("Download path prepared: %s", local_path.c_str());
|
|
1200
|
+
|
|
1201
|
+
return string_to_jstring(env, local_path);
|
|
1202
|
+
|
|
1203
|
+
} catch (const std::exception& e) {
|
|
1204
|
+
LOGE("Exception in downloadModel: %s", e.what());
|
|
1205
|
+
throw_java_exception(env, "java/lang/RuntimeException", e.what());
|
|
1206
|
+
return nullptr;
|
|
1207
|
+
}
|
|
1208
|
+
}
|
|
1209
|
+
|
|
1210
|
+
JNIEXPORT jobject JNICALL
|
|
1211
|
+
Java_ai_annadata_plugin_capacitor_LlamaCpp_getDownloadProgressNative(
|
|
1212
|
+
JNIEnv* env, jobject thiz, jstring url) {
|
|
1213
|
+
|
|
1214
|
+
try {
|
|
1215
|
+
// For now, return a placeholder since we'll handle download in Java
|
|
1216
|
+
// This can be enhanced later to track actual download progress
|
|
1217
|
+
|
|
1218
|
+
jclass hashMapClass = env->FindClass("java/util/HashMap");
|
|
1219
|
+
jmethodID hashMapConstructor = env->GetMethodID(hashMapClass, "<init>", "()V");
|
|
1220
|
+
jmethodID putMethod = env->GetMethodID(hashMapClass, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
|
|
1221
|
+
|
|
1222
|
+
jobject hashMap = env->NewObject(hashMapClass, hashMapConstructor);
|
|
1223
|
+
|
|
1224
|
+
// Return placeholder progress info
|
|
1225
|
+
env->CallObjectMethod(hashMap, putMethod,
|
|
1226
|
+
string_to_jstring(env, "progress"),
|
|
1227
|
+
env->NewObject(env->FindClass("java/lang/Double"),
|
|
1228
|
+
env->GetMethodID(env->FindClass("java/lang/Double"), "<init>", "(D)V"),
|
|
1229
|
+
0.0));
|
|
1230
|
+
|
|
1231
|
+
env->CallObjectMethod(hashMap, putMethod,
|
|
1232
|
+
string_to_jstring(env, "completed"),
|
|
1233
|
+
env->NewObject(env->FindClass("java/lang/Boolean"),
|
|
1234
|
+
env->GetMethodID(env->FindClass("java/lang/Boolean"), "<init>", "(Z)V"),
|
|
1235
|
+
false));
|
|
1236
|
+
|
|
1237
|
+
env->CallObjectMethod(hashMap, putMethod,
|
|
1238
|
+
string_to_jstring(env, "failed"),
|
|
1239
|
+
env->NewObject(env->FindClass("java/lang/Boolean"),
|
|
1240
|
+
env->GetMethodID(env->FindClass("java/lang/Boolean"), "<init>", "(Z)V"),
|
|
1241
|
+
false));
|
|
1242
|
+
|
|
1243
|
+
return hashMap;
|
|
1244
|
+
|
|
1245
|
+
} catch (const std::exception& e) {
|
|
1246
|
+
LOGE("Exception in getDownloadProgress: %s", e.what());
|
|
1247
|
+
throw_java_exception(env, "java/lang/RuntimeException", e.what());
|
|
1248
|
+
return nullptr;
|
|
1249
|
+
}
|
|
1250
|
+
}
|
|
1251
|
+
|
|
1252
|
+
JNIEXPORT jboolean JNICALL
|
|
1253
|
+
Java_ai_annadata_plugin_capacitor_LlamaCpp_cancelDownloadNative(
|
|
1254
|
+
JNIEnv* env, jobject thiz, jstring url) {
|
|
1255
|
+
|
|
1256
|
+
try {
|
|
1257
|
+
// For now, return false since we'll handle download cancellation in Java
|
|
1258
|
+
// This can be enhanced later to actually cancel downloads
|
|
1259
|
+
return JNI_FALSE;
|
|
1260
|
+
|
|
1261
|
+
} catch (const std::exception& e) {
|
|
1262
|
+
LOGE("Exception in cancelDownload: %s", e.what());
|
|
1263
|
+
throw_java_exception(env, "java/lang/RuntimeException", e.what());
|
|
1264
|
+
return JNI_FALSE;
|
|
1265
|
+
}
|
|
1266
|
+
}
|
|
1267
|
+
|
|
1268
|
+
JNIEXPORT jobject JNICALL
|
|
1269
|
+
Java_ai_annadata_plugin_capacitor_LlamaCpp_getAvailableModelsNative(
|
|
1270
|
+
JNIEnv* env, jobject thiz) {
|
|
1271
|
+
|
|
1272
|
+
try {
|
|
1273
|
+
std::string models_dir = "/storage/emulated/0/Android/data/ai.annadata.llamacpp/files/Models/";
|
|
1274
|
+
|
|
1275
|
+
// Create Java ArrayList
|
|
1276
|
+
jclass arrayListClass = env->FindClass("java/util/ArrayList");
|
|
1277
|
+
jmethodID arrayListConstructor = env->GetMethodID(arrayListClass, "<init>", "()V");
|
|
1278
|
+
jmethodID addMethod = env->GetMethodID(arrayListClass, "add", "(Ljava/lang/Object;)Z");
|
|
1279
|
+
|
|
1280
|
+
jobject arrayList = env->NewObject(arrayListClass, arrayListConstructor);
|
|
1281
|
+
|
|
1282
|
+
if (std::filesystem::exists(models_dir)) {
|
|
1283
|
+
for (const auto& entry : std::filesystem::directory_iterator(models_dir)) {
|
|
1284
|
+
if (entry.is_regular_file() && entry.path().extension() == ".gguf") {
|
|
1285
|
+
std::string filename = entry.path().filename().string();
|
|
1286
|
+
std::string full_path = entry.path().string();
|
|
1287
|
+
size_t file_size = entry.file_size();
|
|
1288
|
+
|
|
1289
|
+
// Create model info HashMap
|
|
1290
|
+
jclass hashMapClass = env->FindClass("java/util/HashMap");
|
|
1291
|
+
jmethodID hashMapConstructor = env->GetMethodID(hashMapClass, "<init>", "()V");
|
|
1292
|
+
jmethodID putMethod = env->GetMethodID(hashMapClass, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
|
|
1293
|
+
|
|
1294
|
+
jobject modelInfo = env->NewObject(hashMapClass, hashMapConstructor);
|
|
1295
|
+
|
|
1296
|
+
env->CallObjectMethod(modelInfo, putMethod,
|
|
1297
|
+
string_to_jstring(env, "name"),
|
|
1298
|
+
string_to_jstring(env, filename));
|
|
1299
|
+
|
|
1300
|
+
env->CallObjectMethod(modelInfo, putMethod,
|
|
1301
|
+
string_to_jstring(env, "path"),
|
|
1302
|
+
string_to_jstring(env, full_path));
|
|
1303
|
+
|
|
1304
|
+
env->CallObjectMethod(modelInfo, putMethod,
|
|
1305
|
+
string_to_jstring(env, "size"),
|
|
1306
|
+
env->NewObject(env->FindClass("java/lang/Long"),
|
|
1307
|
+
env->GetMethodID(env->FindClass("java/lang/Long"), "<init>", "(J)V"),
|
|
1308
|
+
static_cast<jlong>(file_size)));
|
|
1309
|
+
|
|
1310
|
+
// Add to ArrayList
|
|
1311
|
+
env->CallBooleanMethod(arrayList, addMethod, modelInfo);
|
|
1312
|
+
}
|
|
1313
|
+
}
|
|
1314
|
+
}
|
|
1315
|
+
|
|
1316
|
+
return arrayList;
|
|
1317
|
+
|
|
1318
|
+
} catch (const std::exception& e) {
|
|
1319
|
+
LOGE("Exception in getAvailableModels: %s", e.what());
|
|
1320
|
+
throw_java_exception(env, "java/lang/RuntimeException", e.what());
|
|
1321
|
+
return nullptr;
|
|
1322
|
+
}
|
|
1323
|
+
}
|
|
1324
|
+
|
|
1325
|
+
// MARK: - Tokenization methods
|
|
1326
|
+
|
|
1327
|
+
JNIEXPORT jobject JNICALL
|
|
1328
|
+
Java_ai_annadata_plugin_capacitor_LlamaCpp_tokenizeNative(
|
|
1329
|
+
JNIEnv* env, jobject thiz, jlong contextId, jstring text, jobjectArray imagePaths) {
|
|
1330
|
+
|
|
1331
|
+
try {
|
|
1332
|
+
LOGI("Tokenizing with context ID: %ld", contextId);
|
|
1333
|
+
|
|
1334
|
+
std::string text_str = jni_utils::jstring_to_string(env, text);
|
|
1335
|
+
LOGI("Text to tokenize: %s", text_str.c_str());
|
|
1336
|
+
|
|
1337
|
+
// Find the context
|
|
1338
|
+
auto it = contexts.find(contextId);
|
|
1339
|
+
if (it == contexts.end()) {
|
|
1340
|
+
LOGE("Context not found: %ld", contextId);
|
|
1341
|
+
throw_java_exception(env, "java/lang/RuntimeException", "Context not found");
|
|
1342
|
+
return nullptr;
|
|
1343
|
+
}
|
|
1344
|
+
|
|
1345
|
+
auto& ctx = it->second;
|
|
1346
|
+
if (!ctx || !ctx->ctx) {
|
|
1347
|
+
LOGE("Invalid context or llama context is null");
|
|
1348
|
+
throw_java_exception(env, "java/lang/RuntimeException", "Invalid context");
|
|
1349
|
+
return nullptr;
|
|
1350
|
+
}
|
|
1351
|
+
|
|
1352
|
+
// Tokenize the text using the context's tokenize method
|
|
1353
|
+
capllama::llama_cap_tokenize_result tokenize_result = ctx->tokenize(text_str, {});
|
|
1354
|
+
std::vector<llama_token> tokens = tokenize_result.tokens;
|
|
1355
|
+
|
|
1356
|
+
LOGI("Tokenized %zu tokens", tokens.size());
|
|
1357
|
+
|
|
1358
|
+
// Create Java HashMap for result
|
|
1359
|
+
jclass hashMapClass = env->FindClass("java/util/HashMap");
|
|
1360
|
+
jmethodID hashMapConstructor = env->GetMethodID(hashMapClass, "<init>", "()V");
|
|
1361
|
+
jmethodID putMethod = env->GetMethodID(hashMapClass, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
|
|
1362
|
+
|
|
1363
|
+
jobject resultMap = env->NewObject(hashMapClass, hashMapConstructor);
|
|
1364
|
+
|
|
1365
|
+
// Create Java ArrayList for tokens
|
|
1366
|
+
jclass arrayListClass = env->FindClass("java/util/ArrayList");
|
|
1367
|
+
jmethodID arrayListConstructor = env->GetMethodID(arrayListClass, "<init>", "()V");
|
|
1368
|
+
jmethodID addMethod = env->GetMethodID(arrayListClass, "add", "(Ljava/lang/Object;)Z");
|
|
1369
|
+
|
|
1370
|
+
jobject tokensArray = env->NewObject(arrayListClass, arrayListConstructor);
|
|
1371
|
+
|
|
1372
|
+
// Add tokens to ArrayList
|
|
1373
|
+
jclass integerClass = env->FindClass("java/lang/Integer");
|
|
1374
|
+
jmethodID integerConstructor = env->GetMethodID(integerClass, "<init>", "(I)V");
|
|
1375
|
+
|
|
1376
|
+
for (llama_token token : tokens) {
|
|
1377
|
+
jobject jToken = env->NewObject(integerClass, integerConstructor, static_cast<jint>(token));
|
|
1378
|
+
env->CallBooleanMethod(tokensArray, addMethod, jToken);
|
|
1379
|
+
env->DeleteLocalRef(jToken);
|
|
1380
|
+
}
|
|
1381
|
+
|
|
1382
|
+
// Create empty arrays for other fields
|
|
1383
|
+
jobject emptyBitmapHashes = env->NewObject(arrayListClass, arrayListConstructor);
|
|
1384
|
+
jobject emptyChunkPos = env->NewObject(arrayListClass, arrayListConstructor);
|
|
1385
|
+
jobject emptyChunkPosImages = env->NewObject(arrayListClass, arrayListConstructor);
|
|
1386
|
+
|
|
1387
|
+
// Put all data into result map
|
|
1388
|
+
env->CallObjectMethod(resultMap, putMethod,
|
|
1389
|
+
jni_utils::string_to_jstring(env, "tokens"), tokensArray);
|
|
1390
|
+
env->CallObjectMethod(resultMap, putMethod,
|
|
1391
|
+
jni_utils::string_to_jstring(env, "has_images"),
|
|
1392
|
+
env->NewObject(env->FindClass("java/lang/Boolean"),
|
|
1393
|
+
env->GetMethodID(env->FindClass("java/lang/Boolean"), "<init>", "(Z)V"), JNI_FALSE));
|
|
1394
|
+
env->CallObjectMethod(resultMap, putMethod,
|
|
1395
|
+
jni_utils::string_to_jstring(env, "bitmap_hashes"), emptyBitmapHashes);
|
|
1396
|
+
env->CallObjectMethod(resultMap, putMethod,
|
|
1397
|
+
jni_utils::string_to_jstring(env, "chunk_pos"), emptyChunkPos);
|
|
1398
|
+
env->CallObjectMethod(resultMap, putMethod,
|
|
1399
|
+
jni_utils::string_to_jstring(env, "chunk_pos_images"), emptyChunkPosImages);
|
|
1400
|
+
|
|
1401
|
+
LOGI("Tokenization completed successfully");
|
|
1402
|
+
return resultMap;
|
|
1403
|
+
|
|
1404
|
+
} catch (const std::exception& e) {
|
|
1405
|
+
LOGE("Exception in tokenize: %s", e.what());
|
|
1406
|
+
throw_java_exception(env, "java/lang/RuntimeException", e.what());
|
|
1407
|
+
return nullptr;
|
|
1408
|
+
}
|
|
1409
|
+
}
|
|
1410
|
+
|
|
1411
|
+
JNIEXPORT jstring JNICALL
|
|
1412
|
+
Java_ai_annadata_plugin_capacitor_LlamaCpp_detokenizeNative(
|
|
1413
|
+
JNIEnv* env, jobject thiz, jlong contextId, jintArray tokens) {
|
|
1414
|
+
|
|
1415
|
+
try {
|
|
1416
|
+
LOGI("Detokenizing with context ID: %ld", contextId);
|
|
1417
|
+
|
|
1418
|
+
// Find the context
|
|
1419
|
+
auto it = contexts.find(contextId);
|
|
1420
|
+
if (it == contexts.end()) {
|
|
1421
|
+
LOGE("Context not found: %ld", contextId);
|
|
1422
|
+
throw_java_exception(env, "java/lang/RuntimeException", "Context not found");
|
|
1423
|
+
return nullptr;
|
|
1424
|
+
}
|
|
1425
|
+
|
|
1426
|
+
auto& ctx = it->second;
|
|
1427
|
+
if (!ctx || !ctx->ctx) {
|
|
1428
|
+
LOGE("Invalid context or llama context is null");
|
|
1429
|
+
throw_java_exception(env, "java/lang/RuntimeException", "Invalid context");
|
|
1430
|
+
return nullptr;
|
|
1431
|
+
}
|
|
1432
|
+
|
|
1433
|
+
// Convert Java int array to C++ vector
|
|
1434
|
+
jsize length = env->GetArrayLength(tokens);
|
|
1435
|
+
jint* tokenArray = env->GetIntArrayElements(tokens, nullptr);
|
|
1436
|
+
|
|
1437
|
+
std::vector<llama_token> llamaTokens;
|
|
1438
|
+
for (jsize i = 0; i < length; i++) {
|
|
1439
|
+
llamaTokens.push_back(static_cast<llama_token>(tokenArray[i]));
|
|
1440
|
+
}
|
|
1441
|
+
|
|
1442
|
+
env->ReleaseIntArrayElements(tokens, tokenArray, JNI_ABORT);
|
|
1443
|
+
|
|
1444
|
+
// Detokenize using llama.cpp
|
|
1445
|
+
std::string result = capllama::tokens_to_str(ctx->ctx, llamaTokens.begin(), llamaTokens.end());
|
|
1446
|
+
|
|
1447
|
+
LOGI("Detokenized to: %s", result.c_str());
|
|
1448
|
+
|
|
1449
|
+
return jni_utils::string_to_jstring(env, result);
|
|
1450
|
+
|
|
1451
|
+
} catch (const std::exception& e) {
|
|
1452
|
+
LOGE("Exception in detokenize: %s", e.what());
|
|
1453
|
+
throw_java_exception(env, "java/lang/RuntimeException", e.what());
|
|
1454
|
+
return nullptr;
|
|
1455
|
+
}
|
|
1456
|
+
}
|
|
1457
|
+
|
|
1458
|
+
// MARK: - Embedding methods
|
|
1459
|
+
|
|
1460
|
+
JNIEXPORT jobject JNICALL
|
|
1461
|
+
Java_ai_annadata_plugin_capacitor_LlamaCpp_embeddingNative(
|
|
1462
|
+
JNIEnv* env, jobject thiz, jlong contextId, jstring text, jobject params) {
|
|
1463
|
+
|
|
1464
|
+
try {
|
|
1465
|
+
LOGI("Generating embeddings for context ID: %ld", contextId);
|
|
1466
|
+
|
|
1467
|
+
std::string text_str = jni_utils::jstring_to_string(env, text);
|
|
1468
|
+
LOGI("Text to embed: %s", text_str.substr(0, std::min(50, (int)text_str.length())).c_str());
|
|
1469
|
+
|
|
1470
|
+
auto it = contexts.find(contextId);
|
|
1471
|
+
if (it == contexts.end()) {
|
|
1472
|
+
LOGE("Context not found: %ld", contextId);
|
|
1473
|
+
throw_java_exception(env, "java/lang/RuntimeException", "Context not found");
|
|
1474
|
+
return nullptr;
|
|
1475
|
+
}
|
|
1476
|
+
|
|
1477
|
+
auto& ctx = it->second;
|
|
1478
|
+
if (!ctx || !ctx->ctx || !ctx->model) {
|
|
1479
|
+
LOGE("Invalid context, llama context, or model is null");
|
|
1480
|
+
throw_java_exception(env, "java/lang/RuntimeException", "Invalid context or model not loaded");
|
|
1481
|
+
return nullptr;
|
|
1482
|
+
}
|
|
1483
|
+
|
|
1484
|
+
if (!ctx->params.embedding) {
|
|
1485
|
+
LOGI("WARNING: Model was not initialized with embedding: true; vectors may be zero");
|
|
1486
|
+
}
|
|
1487
|
+
|
|
1488
|
+
int32_t n_embd = llama_model_n_embd(ctx->model);
|
|
1489
|
+
if (n_embd <= 0) {
|
|
1490
|
+
LOGE("Model does not support embeddings (n_embd = %d)", n_embd);
|
|
1491
|
+
throw_java_exception(env, "java/lang/RuntimeException", "Model does not support embeddings");
|
|
1492
|
+
return nullptr;
|
|
1493
|
+
}
|
|
1494
|
+
|
|
1495
|
+
std::string params_json = "{}";
|
|
1496
|
+
if (params != nullptr) {
|
|
1497
|
+
const double embd_normalize = jni_utils::jsobject_opt_double(env, params, "embd_normalize", 2.0);
|
|
1498
|
+
params_json = "{\"embd_normalize\":" + std::to_string(static_cast<int>(embd_normalize)) + "}";
|
|
1499
|
+
}
|
|
1500
|
+
|
|
1501
|
+
float* embedding_vector = llama_embedding(contextId, text_str.c_str(), params_json.c_str());
|
|
1502
|
+
if (embedding_vector == nullptr) {
|
|
1503
|
+
LOGE("llama_embedding returned null");
|
|
1504
|
+
throw_java_exception(env, "java/lang/RuntimeException", "Failed to generate embedding");
|
|
1505
|
+
return nullptr;
|
|
1506
|
+
}
|
|
1507
|
+
|
|
1508
|
+
LOGI("Embedding generated successfully, dimension: %d", n_embd);
|
|
1509
|
+
|
|
1510
|
+
jclass hashMapClass = env->FindClass("java/util/HashMap");
|
|
1511
|
+
jmethodID hashMapConstructor = env->GetMethodID(hashMapClass, "<init>", "()V");
|
|
1512
|
+
jmethodID putMethod = env->GetMethodID(hashMapClass, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
|
|
1513
|
+
|
|
1514
|
+
jobject resultMap = env->NewObject(hashMapClass, hashMapConstructor);
|
|
1515
|
+
|
|
1516
|
+
jclass arrayListClass = env->FindClass("java/util/ArrayList");
|
|
1517
|
+
jmethodID arrayListConstructor = env->GetMethodID(arrayListClass, "<init>", "()V");
|
|
1518
|
+
jmethodID addMethod = env->GetMethodID(arrayListClass, "add", "(Ljava/lang/Object;)Z");
|
|
1519
|
+
|
|
1520
|
+
jobject embeddingArray = env->NewObject(arrayListClass, arrayListConstructor);
|
|
1521
|
+
|
|
1522
|
+
jclass doubleClass = env->FindClass("java/lang/Double");
|
|
1523
|
+
jmethodID doubleConstructor = env->GetMethodID(doubleClass, "<init>", "(D)V");
|
|
1524
|
+
|
|
1525
|
+
for (int i = 0; i < n_embd; i++) {
|
|
1526
|
+
jobject jValue = env->NewObject(doubleClass, doubleConstructor, static_cast<jdouble>(embedding_vector[i]));
|
|
1527
|
+
env->CallBooleanMethod(embeddingArray, addMethod, jValue);
|
|
1528
|
+
env->DeleteLocalRef(jValue);
|
|
1529
|
+
}
|
|
1530
|
+
|
|
1531
|
+
env->CallObjectMethod(resultMap, putMethod,
|
|
1532
|
+
jni_utils::string_to_jstring(env, "embedding"), embeddingArray);
|
|
1533
|
+
env->CallObjectMethod(resultMap, putMethod,
|
|
1534
|
+
jni_utils::string_to_jstring(env, "n_embd"),
|
|
1535
|
+
env->NewObject(env->FindClass("java/lang/Integer"),
|
|
1536
|
+
env->GetMethodID(env->FindClass("java/lang/Integer"), "<init>", "(I)V"), n_embd));
|
|
1537
|
+
|
|
1538
|
+
LOGI("Embedding result created successfully");
|
|
1539
|
+
return resultMap;
|
|
1540
|
+
|
|
1541
|
+
} catch (const std::exception& e) {
|
|
1542
|
+
LOGE("Exception in embedding: %s", e.what());
|
|
1543
|
+
throw_java_exception(env, "java/lang/RuntimeException", e.what());
|
|
1544
|
+
return nullptr;
|
|
1545
|
+
}
|
|
1546
|
+
}
|
|
1547
|
+
|
|
1548
|
+
JNIEXPORT jboolean JNICALL
|
|
1549
|
+
Java_ai_annadata_plugin_capacitor_LlamaCpp_startLlamaServerNative(JNIEnv *env, jobject thiz, jstring modelPath,
|
|
1550
|
+
jstring host, jint port, jstring paramsJson) {
|
|
1551
|
+
(void)thiz;
|
|
1552
|
+
try {
|
|
1553
|
+
std::string m = jstring_to_string(env, modelPath);
|
|
1554
|
+
std::string h = (host != nullptr) ? jstring_to_string(env, host) : std::string("127.0.0.1");
|
|
1555
|
+
std::string pj;
|
|
1556
|
+
if (paramsJson != nullptr) {
|
|
1557
|
+
pj = jstring_to_string(env, paramsJson);
|
|
1558
|
+
}
|
|
1559
|
+
const int ok = cap_llama_server_start(m.c_str(), h.c_str(), static_cast<int>(port),
|
|
1560
|
+
pj.empty() ? nullptr : pj.c_str());
|
|
1561
|
+
return ok ? JNI_TRUE : JNI_FALSE;
|
|
1562
|
+
} catch (...) {
|
|
1563
|
+
return JNI_FALSE;
|
|
1564
|
+
}
|
|
1565
|
+
}
|
|
1566
|
+
|
|
1567
|
+
JNIEXPORT void JNICALL
|
|
1568
|
+
Java_ai_annadata_plugin_capacitor_LlamaCpp_stopLlamaServerNative(JNIEnv *env, jobject thiz) {
|
|
1569
|
+
(void)env;
|
|
1570
|
+
(void)thiz;
|
|
1571
|
+
cap_llama_server_stop();
|
|
1572
|
+
}
|
|
1573
|
+
|
|
1574
|
+
JNIEXPORT jboolean JNICALL
|
|
1575
|
+
Java_ai_annadata_plugin_capacitor_LlamaCpp_isLlamaServerRunningNative(JNIEnv *env, jobject thiz) {
|
|
1576
|
+
(void)env;
|
|
1577
|
+
(void)thiz;
|
|
1578
|
+
return cap_llama_server_is_running() ? JNI_TRUE : JNI_FALSE;
|
|
1579
|
+
}
|
|
1580
|
+
|
|
1581
|
+
// ---------------------------------------------------------------------------
|
|
1582
|
+
// Rerank
|
|
1583
|
+
// ---------------------------------------------------------------------------
|
|
1584
|
+
JNIEXPORT jobject JNICALL
|
|
1585
|
+
Java_ai_annadata_plugin_capacitor_LlamaCpp_rerankNative(
|
|
1586
|
+
JNIEnv* env, jobject thiz, jlong contextId, jstring query, jobjectArray documents, jobject params) {
|
|
1587
|
+
(void)thiz; (void)params;
|
|
1588
|
+
try {
|
|
1589
|
+
auto it = contexts.find(contextId);
|
|
1590
|
+
if (it == contexts.end() || !it->second || !it->second->ctx) {
|
|
1591
|
+
throw_java_exception(env, "java/lang/RuntimeException", "Context not found");
|
|
1592
|
+
return nullptr;
|
|
1593
|
+
}
|
|
1594
|
+
auto& ctx = it->second;
|
|
1595
|
+
std::string query_str = jni_utils::jstring_to_string(env, query);
|
|
1596
|
+
jsize n_docs = env->GetArrayLength(documents);
|
|
1597
|
+
std::vector<std::string> docs;
|
|
1598
|
+
for (jsize i = 0; i < n_docs; i++) {
|
|
1599
|
+
jstring js = (jstring)env->GetObjectArrayElement(documents, i);
|
|
1600
|
+
docs.push_back(jni_utils::jstring_to_string(env, js));
|
|
1601
|
+
env->DeleteLocalRef(js);
|
|
1602
|
+
}
|
|
1603
|
+
if (!ctx->completion) {
|
|
1604
|
+
ctx->completion = new capllama::llama_cap_context_completion(ctx.get());
|
|
1605
|
+
}
|
|
1606
|
+
std::vector<float> scores = ctx->completion->rerank(query_str, docs);
|
|
1607
|
+
jclass alClass = env->FindClass("java/util/ArrayList");
|
|
1608
|
+
jobject resultList = env->NewObject(alClass,
|
|
1609
|
+
env->GetMethodID(alClass, "<init>", "()V"));
|
|
1610
|
+
jmethodID addM = env->GetMethodID(alClass, "add", "(Ljava/lang/Object;)Z");
|
|
1611
|
+
jclass hmClass = env->FindClass("java/util/HashMap");
|
|
1612
|
+
jmethodID hmCtor = env->GetMethodID(hmClass, "<init>", "()V");
|
|
1613
|
+
jmethodID putM = env->GetMethodID(hmClass, "put",
|
|
1614
|
+
"(Ljava/lang/Object;)Ljava/lang/Object;");
|
|
1615
|
+
// HashMap.put returns Object, but we only need the side-effect
|
|
1616
|
+
jmethodID hmPut = env->GetMethodID(hmClass, "put",
|
|
1617
|
+
"(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
|
|
1618
|
+
for (size_t i = 0; i < scores.size(); i++) {
|
|
1619
|
+
jobject map = env->NewObject(hmClass, hmCtor);
|
|
1620
|
+
jclass dblC = env->FindClass("java/lang/Double");
|
|
1621
|
+
jobject scoreObj = env->NewObject(dblC,
|
|
1622
|
+
env->GetMethodID(dblC, "<init>", "(D)V"), (jdouble)scores[i]);
|
|
1623
|
+
jclass intC = env->FindClass("java/lang/Integer");
|
|
1624
|
+
jobject idxObj = env->NewObject(intC,
|
|
1625
|
+
env->GetMethodID(intC, "<init>", "(I)V"), (jint)i);
|
|
1626
|
+
env->CallObjectMethod(map, hmPut,
|
|
1627
|
+
jni_utils::string_to_jstring(env, "score"), scoreObj);
|
|
1628
|
+
env->CallObjectMethod(map, hmPut,
|
|
1629
|
+
jni_utils::string_to_jstring(env, "index"), idxObj);
|
|
1630
|
+
env->CallBooleanMethod(resultList, addM, map);
|
|
1631
|
+
env->DeleteLocalRef(map);
|
|
1632
|
+
env->DeleteLocalRef(scoreObj);
|
|
1633
|
+
env->DeleteLocalRef(idxObj);
|
|
1634
|
+
}
|
|
1635
|
+
return resultList;
|
|
1636
|
+
} catch (const std::exception& e) {
|
|
1637
|
+
throw_java_exception(env, "java/lang/RuntimeException", e.what());
|
|
1638
|
+
return nullptr;
|
|
1639
|
+
}
|
|
1640
|
+
}
|
|
1641
|
+
|
|
1642
|
+
// ---------------------------------------------------------------------------
|
|
1643
|
+
// Bench
|
|
1644
|
+
// ---------------------------------------------------------------------------
|
|
1645
|
+
JNIEXPORT jstring JNICALL
|
|
1646
|
+
Java_ai_annadata_plugin_capacitor_LlamaCpp_benchNative(
|
|
1647
|
+
JNIEnv* env, jobject thiz, jlong contextId, jint pp, jint tg, jint pl, jint nr) {
|
|
1648
|
+
(void)thiz;
|
|
1649
|
+
try {
|
|
1650
|
+
auto it = contexts.find(contextId);
|
|
1651
|
+
if (it == contexts.end() || !it->second || !it->second->ctx) {
|
|
1652
|
+
throw_java_exception(env, "java/lang/RuntimeException", "Context not found");
|
|
1653
|
+
return nullptr;
|
|
1654
|
+
}
|
|
1655
|
+
auto& ctx = it->second;
|
|
1656
|
+
if (!ctx->completion) {
|
|
1657
|
+
ctx->completion = new capllama::llama_cap_context_completion(ctx.get());
|
|
1658
|
+
}
|
|
1659
|
+
std::string result = ctx->completion->bench(pp, tg, pl, nr);
|
|
1660
|
+
return jni_utils::string_to_jstring(env, result);
|
|
1661
|
+
} catch (const std::exception& e) {
|
|
1662
|
+
throw_java_exception(env, "java/lang/RuntimeException", e.what());
|
|
1663
|
+
return nullptr;
|
|
1664
|
+
}
|
|
1665
|
+
}
|
|
1666
|
+
|
|
1667
|
+
// ---------------------------------------------------------------------------
|
|
1668
|
+
// Session management — backed by llama_state_save/load_file
|
|
1669
|
+
// ---------------------------------------------------------------------------
|
|
1670
|
+
JNIEXPORT jobject JNICALL
|
|
1671
|
+
Java_ai_annadata_plugin_capacitor_LlamaCpp_loadSessionNative(
|
|
1672
|
+
JNIEnv* env, jobject thiz, jlong contextId, jstring filepath) {
|
|
1673
|
+
(void)thiz;
|
|
1674
|
+
try {
|
|
1675
|
+
auto it = contexts.find(contextId);
|
|
1676
|
+
if (it == contexts.end() || !it->second || !it->second->ctx) {
|
|
1677
|
+
throw_java_exception(env, "java/lang/RuntimeException", "Context not found");
|
|
1678
|
+
return nullptr;
|
|
1679
|
+
}
|
|
1680
|
+
auto& ctx = it->second;
|
|
1681
|
+
std::string path = jni_utils::jstring_to_string(env, filepath);
|
|
1682
|
+
// Load KV-cache state
|
|
1683
|
+
std::vector<llama_token> session_tokens;
|
|
1684
|
+
size_t n_token_count = 0;
|
|
1685
|
+
const size_t max_tokens = ctx->n_ctx;
|
|
1686
|
+
session_tokens.resize(max_tokens);
|
|
1687
|
+
bool ok = llama_state_load_file(ctx->ctx, path.c_str(),
|
|
1688
|
+
session_tokens.data(), max_tokens, &n_token_count);
|
|
1689
|
+
if (!ok) {
|
|
1690
|
+
throw_java_exception(env, "java/lang/RuntimeException",
|
|
1691
|
+
("Failed to load session from: " + path).c_str());
|
|
1692
|
+
return nullptr;
|
|
1693
|
+
}
|
|
1694
|
+
session_tokens.resize(n_token_count);
|
|
1695
|
+
// Rebuild the embd vector so the next completion continues from the right n_past
|
|
1696
|
+
if (ctx->completion) {
|
|
1697
|
+
ctx->completion->embd = session_tokens;
|
|
1698
|
+
ctx->completion->n_past = (llama_pos)n_token_count;
|
|
1699
|
+
}
|
|
1700
|
+
// Build result map
|
|
1701
|
+
jclass hmClass = env->FindClass("java/util/HashMap");
|
|
1702
|
+
jobject map = env->NewObject(hmClass, env->GetMethodID(hmClass, "<init>", "()V"));
|
|
1703
|
+
jmethodID put = env->GetMethodID(hmClass, "put",
|
|
1704
|
+
"(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
|
|
1705
|
+
jclass intC = env->FindClass("java/lang/Integer");
|
|
1706
|
+
jobject nTok = env->NewObject(intC,
|
|
1707
|
+
env->GetMethodID(intC, "<init>", "(I)V"), (jint)n_token_count);
|
|
1708
|
+
env->CallObjectMethod(map, put,
|
|
1709
|
+
jni_utils::string_to_jstring(env, "tokens_loaded"), nTok);
|
|
1710
|
+
env->CallObjectMethod(map, put,
|
|
1711
|
+
jni_utils::string_to_jstring(env, "prompt"),
|
|
1712
|
+
jni_utils::string_to_jstring(env, ""));
|
|
1713
|
+
env->DeleteLocalRef(nTok);
|
|
1714
|
+
return map;
|
|
1715
|
+
} catch (const std::exception& e) {
|
|
1716
|
+
throw_java_exception(env, "java/lang/RuntimeException", e.what());
|
|
1717
|
+
return nullptr;
|
|
1718
|
+
}
|
|
1719
|
+
}
|
|
1720
|
+
|
|
1721
|
+
JNIEXPORT jint JNICALL
|
|
1722
|
+
Java_ai_annadata_plugin_capacitor_LlamaCpp_saveSessionNative(
|
|
1723
|
+
JNIEnv* env, jobject thiz, jlong contextId, jstring filepath, jint size) {
|
|
1724
|
+
(void)thiz;
|
|
1725
|
+
try {
|
|
1726
|
+
auto it = contexts.find(contextId);
|
|
1727
|
+
if (it == contexts.end() || !it->second || !it->second->ctx) {
|
|
1728
|
+
throw_java_exception(env, "java/lang/RuntimeException", "Context not found");
|
|
1729
|
+
return -1;
|
|
1730
|
+
}
|
|
1731
|
+
auto& ctx = it->second;
|
|
1732
|
+
std::string path = jni_utils::jstring_to_string(env, filepath);
|
|
1733
|
+
// Determine how many tokens to save (n_past capped by requested size)
|
|
1734
|
+
const std::vector<llama_token>* embd_ptr = nullptr;
|
|
1735
|
+
if (ctx->completion) embd_ptr = &ctx->completion->embd;
|
|
1736
|
+
std::vector<llama_token> empty_embd;
|
|
1737
|
+
const std::vector<llama_token>& embd = embd_ptr ? *embd_ptr : empty_embd;
|
|
1738
|
+
size_t n_save = (size >= 0 && (size_t)size < embd.size()) ? (size_t)size : embd.size();
|
|
1739
|
+
bool ok = llama_state_save_file(ctx->ctx, path.c_str(),
|
|
1740
|
+
embd.data(), n_save);
|
|
1741
|
+
if (!ok) {
|
|
1742
|
+
throw_java_exception(env, "java/lang/RuntimeException",
|
|
1743
|
+
("Failed to save session to: " + path).c_str());
|
|
1744
|
+
return -1;
|
|
1745
|
+
}
|
|
1746
|
+
return (jint)n_save;
|
|
1747
|
+
} catch (const std::exception& e) {
|
|
1748
|
+
throw_java_exception(env, "java/lang/RuntimeException", e.what());
|
|
1749
|
+
return -1;
|
|
1750
|
+
}
|
|
1751
|
+
}
|
|
1752
|
+
|
|
1753
|
+
// ---------------------------------------------------------------------------
|
|
1754
|
+
// Supplementary JNI translation units — included here so they share the same
|
|
1755
|
+
// contexts map, LOG macros, and jni_utils helpers defined above.
|
|
1756
|
+
// ---------------------------------------------------------------------------
|
|
1757
|
+
#include "jni-lora.cpp"
|
|
1758
|
+
#include "jni-chat-session.cpp"
|
|
1759
|
+
#include "jni-multimodal.cpp"
|
|
1760
|
+
#include "jni-tts.cpp"
|
|
1761
|
+
|
|
1762
|
+
// ---------------------------------------------------------------------------
|
|
1763
|
+
// LoRA adapters — delegate to jni-lora.cpp implementations
|
|
1764
|
+
// Note: jni-lora.cpp is included above, its functions use the same
|
|
1765
|
+
// `contexts` map defined in this translation unit.
|
|
1766
|
+
// The Java-side now declares native int applyLoraAdaptersNative(long, Object[]).
|
|
1767
|
+
// We bridge Object[] → jobjectArray here.
|
|
1768
|
+
// ---------------------------------------------------------------------------
|
|
1769
|
+
JNIEXPORT jint JNICALL
|
|
1770
|
+
Java_ai_annadata_plugin_capacitor_LlamaCpp_applyLoraAdaptersNative(
|
|
1771
|
+
JNIEnv* env, jobject thiz, jlong contextId, jobjectArray loraAdapters) {
|
|
1772
|
+
// Forward directly — jni-lora.cpp has the same signature from the old declaration.
|
|
1773
|
+
// (Defined in jni-lora.cpp, linked together.)
|
|
1774
|
+
extern JNIEXPORT jint JNICALL
|
|
1775
|
+
Java_ai_annadata_plugin_capacitor_LlamaCpp_applyLoraAdaptersNative_impl(
|
|
1776
|
+
JNIEnv*, jobject, jlong, jobjectArray);
|
|
1777
|
+
return Java_ai_annadata_plugin_capacitor_LlamaCpp_applyLoraAdaptersNative_impl(
|
|
1778
|
+
env, thiz, contextId, loraAdapters);
|
|
1779
|
+
}
|
|
1780
|
+
|
|
1781
|
+
// Forward removeLoraAdaptersNative and getLoadedLoraAdaptersNative from jni-lora.cpp
|
|
1782
|
+
extern "C" {
|
|
1783
|
+
|
|
1784
|
+
JNIEXPORT void JNICALL
|
|
1785
|
+
Java_ai_annadata_plugin_capacitor_LlamaCpp_removeLoraAdaptersNative(
|
|
1786
|
+
JNIEnv* env, jobject thiz, jlong contextId) {
|
|
1787
|
+
extern JNIEXPORT void JNICALL
|
|
1788
|
+
Java_ai_annadata_plugin_capacitor_LlamaCpp_removeLoraAdaptersNative_impl(
|
|
1789
|
+
JNIEnv*, jobject, jlong);
|
|
1790
|
+
Java_ai_annadata_plugin_capacitor_LlamaCpp_removeLoraAdaptersNative_impl(
|
|
1791
|
+
env, thiz, contextId);
|
|
1792
|
+
}
|
|
1793
|
+
|
|
1794
|
+
JNIEXPORT jobject JNICALL
|
|
1795
|
+
Java_ai_annadata_plugin_capacitor_LlamaCpp_getLoadedLoraAdaptersNative(
|
|
1796
|
+
JNIEnv* env, jobject thiz, jlong contextId) {
|
|
1797
|
+
extern JNIEXPORT jobject JNICALL
|
|
1798
|
+
Java_ai_annadata_plugin_capacitor_LlamaCpp_getLoadedLoraAdaptersNative_impl(
|
|
1799
|
+
JNIEnv*, jobject, jlong);
|
|
1800
|
+
return Java_ai_annadata_plugin_capacitor_LlamaCpp_getLoadedLoraAdaptersNative_impl(
|
|
1801
|
+
env, thiz, contextId);
|
|
1802
|
+
}
|
|
1803
|
+
|
|
1804
|
+
} // extern "C" (LoRA forwarders)
|
|
1805
|
+
|
|
1806
|
+
} // extern "C" (main block)
|
|
1807
|
+
|
|
1808
|
+
} // namespace jni_utils
|