Phase 3: JNI bridge to llama.cpp (load, streaming generate, free)
Browse files
app/src/main/cpp/llama_jni.cpp
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#include <jni.h>
|
| 2 |
+
#include <string>
|
| 3 |
+
#include <vector>
|
| 4 |
+
#include "llama.h"
|
| 5 |
+
|
| 6 |
+
struct State {
|
| 7 |
+
llama_model *model;
|
| 8 |
+
llama_context *ctx;
|
| 9 |
+
};
|
| 10 |
+
|
| 11 |
+
extern "C" JNIEXPORT jlong JNICALL
|
| 12 |
+
Java_io_github_abrarul_modularai_engine_LlamaEngine_nativeLoad(JNIEnv *env, jobject, jstring path,
|
| 13 |
+
jint nCtx, jint threads) {
|
| 14 |
+
llama_backend_init();
|
| 15 |
+
const char *p = env->GetStringUTFChars(path, nullptr);
|
| 16 |
+
llama_model_params mp = llama_model_default_params();
|
| 17 |
+
llama_model *m = llama_model_load_from_file(p, mp);
|
| 18 |
+
env->ReleaseStringUTFChars(path, p);
|
| 19 |
+
if (!m) return 0;
|
| 20 |
+
|
| 21 |
+
llama_context_params cp = llama_context_default_params();
|
| 22 |
+
cp.n_ctx = nCtx;
|
| 23 |
+
cp.n_batch = nCtx;
|
| 24 |
+
cp.n_ubatch = 512;
|
| 25 |
+
cp.n_threads = threads;
|
| 26 |
+
cp.n_threads_batch = threads;
|
| 27 |
+
llama_context *c = llama_init_from_model(m, cp);
|
| 28 |
+
if (!c) {
|
| 29 |
+
llama_model_free(m);
|
| 30 |
+
return 0;
|
| 31 |
+
}
|
| 32 |
+
return reinterpret_cast<jlong>(new State{m, c});
|
| 33 |
+
}
|
| 34 |
+
|
| 35 |
+
extern "C" JNIEXPORT void JNICALL
|
| 36 |
+
Java_io_github_abrarul_modularai_engine_LlamaEngine_nativeGenerate(JNIEnv *env, jobject, jlong h,
|
| 37 |
+
jstring prompt, jint maxTokens,
|
| 38 |
+
jfloat temp, jobject sink) {
|
| 39 |
+
auto *s = reinterpret_cast<State *>(h);
|
| 40 |
+
if (!s) return;
|
| 41 |
+
const llama_vocab *vocab = llama_model_get_vocab(s->model);
|
| 42 |
+
|
| 43 |
+
const char *pr = env->GetStringUTFChars(prompt, nullptr);
|
| 44 |
+
std::string text(pr);
|
| 45 |
+
env->ReleaseStringUTFChars(prompt, pr);
|
| 46 |
+
|
| 47 |
+
llama_memory_clear(llama_get_memory(s->ctx), true);
|
| 48 |
+
|
| 49 |
+
int n = -llama_tokenize(vocab, text.c_str(), (int) text.size(), nullptr, 0, true, true);
|
| 50 |
+
if (n <= 0 || n >= (int) llama_n_ctx(s->ctx)) return; // empty or does not fit the context
|
| 51 |
+
std::vector<llama_token> toks(n);
|
| 52 |
+
if (llama_tokenize(vocab, text.c_str(), (int) text.size(), toks.data(), n, true, true) < 0) return;
|
| 53 |
+
|
| 54 |
+
llama_sampler *smpl = llama_sampler_chain_init(llama_sampler_chain_default_params());
|
| 55 |
+
if (temp > 0.0f) {
|
| 56 |
+
llama_sampler_chain_add(smpl, llama_sampler_init_top_p(0.9f, 1));
|
| 57 |
+
llama_sampler_chain_add(smpl, llama_sampler_init_temp(temp));
|
| 58 |
+
llama_sampler_chain_add(smpl, llama_sampler_init_dist(LLAMA_DEFAULT_SEED));
|
| 59 |
+
} else {
|
| 60 |
+
llama_sampler_chain_add(smpl, llama_sampler_init_greedy());
|
| 61 |
+
}
|
| 62 |
+
|
| 63 |
+
jclass cls = env->GetObjectClass(sink);
|
| 64 |
+
jmethodID mid = env->GetMethodID(cls, "onToken", "([B)Z");
|
| 65 |
+
|
| 66 |
+
llama_token tok; // must outlive the loop body: the batch points at it
|
| 67 |
+
llama_batch batch = llama_batch_get_one(toks.data(), (int) toks.size());
|
| 68 |
+
for (int i = 0; i < maxTokens; i++) {
|
| 69 |
+
if (llama_decode(s->ctx, batch) != 0) break;
|
| 70 |
+
tok = llama_sampler_sample(smpl, s->ctx, -1);
|
| 71 |
+
if (llama_vocab_is_eog(vocab, tok)) break;
|
| 72 |
+
|
| 73 |
+
char buf[256];
|
| 74 |
+
int len = llama_token_to_piece(vocab, tok, buf, sizeof(buf), 0, true);
|
| 75 |
+
if (len < 0) break;
|
| 76 |
+
jbyteArray arr = env->NewByteArray(len);
|
| 77 |
+
env->SetByteArrayRegion(arr, 0, len, reinterpret_cast<const jbyte *>(buf));
|
| 78 |
+
jboolean cont = env->CallBooleanMethod(sink, mid, arr);
|
| 79 |
+
env->DeleteLocalRef(arr);
|
| 80 |
+
if (!cont || env->ExceptionCheck()) break;
|
| 81 |
+
|
| 82 |
+
batch = llama_batch_get_one(&tok, 1);
|
| 83 |
+
}
|
| 84 |
+
llama_sampler_free(smpl);
|
| 85 |
+
}
|
| 86 |
+
|
| 87 |
+
extern "C" JNIEXPORT void JNICALL
|
| 88 |
+
Java_io_github_abrarul_modularai_engine_LlamaEngine_nativeFree(JNIEnv *, jobject, jlong h) {
|
| 89 |
+
auto *s = reinterpret_cast<State *>(h);
|
| 90 |
+
if (!s) return;
|
| 91 |
+
llama_free(s->ctx);
|
| 92 |
+
llama_model_free(s->model);
|
| 93 |
+
delete s;
|
| 94 |
+
}
|