refonte(llm): Phase 3 — archivage code mort (Genie + EngineLlmAdapter)
Après analyse de dépendances : l'essentiel d'ExecuTorch/QNN est VIVANT via le TTS Qwen3TtsEngine "prod" (org.pytorch.executorch.Module → libexecutorch.so, + libQnnGpu.so backend Adreno, + QnnHtp). NE PAS archiver (stack TTS figée). Réellement mort (refonte LLM) → archivé dans /opt/Kazeia/archive/2026-06-17_refonte-engine/ : - EngineLlmAdapter.kt (ancien adaptateur GGUF, remplacé par UnifiedLlmAdapter ; références restantes = commentaires uniquement) - GenieJni.kt + genie_jni.cpp + libGenie.so (backend Genie mort ; libgenie_jni.so n'était même plus shipé → GenieJni ne pouvait plus se charger) - cible CMake genie_jni retirée ; manifest jniLibs re-figé (27 libs, -libGenie) Aussi : ConfigStore.llmEngine documenté comme VESTIGIAL (le dispatch passe par UnifiedLlmAdapter magic-byte depuis la refonte ; modèle choisi par speaker.modelId). Build release vert ; LLM device non-régressé (GGUF 18 / qwen3-4b .pte 18.6 / guard4b .pte 21 tok/s) ; aucune lib genie dans l'APK. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
0108f47c09
commit
d1baacd096
|
|
@ -40,12 +40,11 @@ class ConfigStore private constructor(private val file: File) {
|
||||||
* (Kazeia-Engine unifié, A/B identique sur set 6 audios mais à valider plus large).
|
* (Kazeia-Engine unifié, A/B identique sur set 6 audios mais à valider plus large).
|
||||||
* Pilotable depuis l'app admin / provider. Defaults safe = "prod". */
|
* Pilotable depuis l'app admin / provider. Defaults safe = "prod". */
|
||||||
val sttEngine: String = "prod",
|
val sttEngine: String = "prod",
|
||||||
/** Backend LLM : "lib" = EngineLlmAdapter (libkazeia_engine + GGUF Qwen3.5,
|
/** Backend LLM : VESTIGIAL depuis la refonte 2026-06-17. Le dispatch ne passe
|
||||||
* q35-lmq4 par défaut) — défaut depuis 2026-06-15 : on n'utilise PLUS le
|
* plus par cette valeur : KazeiaService charge tout LLM via UnifiedLlmAdapter
|
||||||
* .pte avec kazeia-engine (directive). "prod" = ExecuTorchLlmEngine (.pte) —
|
* qui auto-détecte le format par MAGIC-BYTE (GGUF→CPU i8mm, .pte→NPU V79). Le
|
||||||
* conservé en repli d'urgence uniquement ; sur cette plateforme le runner QNN
|
* modèle effectif est choisi par `speaker.modelId` (ModelRegistry). Champ
|
||||||
* du .pte échoue au load (« Failed to load llm runner [1] »), donc à éviter.
|
* conservé pour compat config/télémétrie. */
|
||||||
* "lib" valide device : load q35-lmq4.gguf 2.6s + génération FR cohérente. */
|
|
||||||
val llmEngine: String = "lib",
|
val llmEngine: String = "lib",
|
||||||
/** Backend TTS : "lib" = libkazeia_tts unifié (SEUL compatible avec le
|
/** Backend TTS : "lib" = libkazeia_tts unifié (SEUL compatible avec le
|
||||||
* libllama.so fork ql embarqué depuis 2026-06-02), "prod" = Qwen3TtsEngine
|
* libllama.so fork ql embarqué depuis 2026-06-02), "prod" = Qwen3TtsEngine
|
||||||
|
|
|
||||||
|
|
@ -1,97 +0,0 @@
|
||||||
package com.kazeia.llm
|
|
||||||
|
|
||||||
import com.kazeia.core.GenerationResult
|
|
||||||
import com.kazeia.core.LlmConfig
|
|
||||||
import com.kazeia.core.LlmEngine
|
|
||||||
import com.kazeia.core.SamplingParams
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.coroutines.withContext
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adapter qui expose `com.kazeia.llm.EngineLlmEngine` (façade dist Kazeia-Engine,
|
|
||||||
* GGUF Qwen3.5/Qwen3 via libkazeia_engine.so + libllama fork ql + Hexagon)
|
|
||||||
* derrière l'interface prod `com.kazeia.core.LlmEngine`. Sert au swap réversible
|
|
||||||
* piloté par le flag config `llmEngine` ("prod" = ExecuTorch .pte | "lib" = engine GGUF).
|
|
||||||
*
|
|
||||||
* Pré-requis runtime : `libllama.so` fork ql + `libggml*.so` cohérents dans jniLibs.
|
|
||||||
* Si la chaîne libllama est encore en legacy (f86d), `System.loadLibrary("kazeia_engine")`
|
|
||||||
* jette UnsatisfiedLinkError au 1er accès à `EngineJni` → KazeiaService doit catch
|
|
||||||
* et tomber en repli sur le path prod.
|
|
||||||
*
|
|
||||||
* Modèle par défaut : Qwen3.5-4B `q35-lmq4.gguf` (upgrade vs Qwen3 dense en prod).
|
|
||||||
*/
|
|
||||||
class EngineLlmAdapter(
|
|
||||||
private val modelPath: String,
|
|
||||||
private val systemPrompt: String,
|
|
||||||
private val ctxLen: Int = 4096,
|
|
||||||
private val nThreads: Int = 6,
|
|
||||||
// true = ChatML standard sans <think> (Qwen2.5…) via generateRaw ;
|
|
||||||
// false = bloc thinking-off Qwen3.5 injecté côté natif (generate).
|
|
||||||
private val plainChatml: Boolean = false,
|
|
||||||
private val onLog: ((String) -> Unit)? = null
|
|
||||||
) : LlmEngine {
|
|
||||||
private var engine: EngineLlmEngine? = null
|
|
||||||
// Session = cache de préfixe KV : le system prompt n'est prefillé QU'UNE fois
|
|
||||||
// (à la création), puis chaque tour ne prefille que le message user → ~2,5×
|
|
||||||
// moins de latence/tour (mesuré ~2991→~1190 ms sur q35-lmq4) + streaming.
|
|
||||||
// Pas créée pour plainChatml (Qwen2.5 = template ChatML différent → generateRaw).
|
|
||||||
// Stateless : reset() avant chaque ask (comportement historique sans mémoire
|
|
||||||
// LLM) — retirer ce reset activerait la mémoire conversationnelle.
|
|
||||||
private var session: LlmSession? = null
|
|
||||||
|
|
||||||
override suspend fun load(modelPath: String, config: LlmConfig) = withContext(Dispatchers.IO) {
|
|
||||||
if (engine != null) return@withContext
|
|
||||||
val t0 = System.currentTimeMillis()
|
|
||||||
val e = EngineLlmEngine(this@EngineLlmAdapter.modelPath, ctx = ctxLen, nThreads = nThreads)
|
|
||||||
engine = e
|
|
||||||
if (!plainChatml) session = e.newSession(systemPrompt) // prefille le system 1×
|
|
||||||
onLog?.invoke("[ENGINE] load OK (${System.currentTimeMillis() - t0}ms) path=${this@EngineLlmAdapter.modelPath} t=${nThreads} session=${session != null}")
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun isLoaded(): Boolean = engine != null
|
|
||||||
|
|
||||||
override suspend fun generate(
|
|
||||||
prompt: String,
|
|
||||||
params: SamplingParams,
|
|
||||||
onToken: ((String) -> Boolean)?
|
|
||||||
): GenerationResult = withContext(Dispatchers.IO) {
|
|
||||||
val e = engine ?: throw IllegalStateException("EngineLlmAdapter not loaded")
|
|
||||||
val t0 = System.currentTimeMillis()
|
|
||||||
val s = session
|
|
||||||
val out: String = if (s != null) {
|
|
||||||
// Cache de préfixe + MÉMOIRE conversationnelle : le system reste prefillé,
|
|
||||||
// chaque ask ne prefille que le user et conserve l'historique en KV.
|
|
||||||
// (NB : on NE reset PAS par tour — sessionReset+ask renvoie vide,
|
|
||||||
// bug natif n_past non restauré ; reset boundary à rétablir côté engine.)
|
|
||||||
val sb = StringBuilder()
|
|
||||||
s.ask(prompt, params.maxNewTokens) { piece ->
|
|
||||||
sb.append(piece); onToken?.invoke(piece) ?: true
|
|
||||||
}
|
|
||||||
sb.toString().trim()
|
|
||||||
} else {
|
|
||||||
// plainChatml (Qwen2.5) : ChatML manuel, generateRaw bloquant.
|
|
||||||
val p = buildString {
|
|
||||||
append("<|im_start|>system\n").append(systemPrompt).append("<|im_end|>\n")
|
|
||||||
append("<|im_start|>user\n").append(prompt).append("<|im_end|>\n")
|
|
||||||
append("<|im_start|>assistant\n")
|
|
||||||
}
|
|
||||||
e.generateRaw(p, params.maxNewTokens).trim().also { onToken?.invoke(it) }
|
|
||||||
}
|
|
||||||
// Timing réel fourni par l'engine (prefill/decode séparés). tps = débit
|
|
||||||
// DÉCODE (fini l'artefact "prefill inclus" qui donnait ~3 tok/s).
|
|
||||||
val st = e.lastStats()
|
|
||||||
val n = if (st.nTokens > 0) st.nTokens.toInt() else out.split(Regex("\\s+")).size
|
|
||||||
val ms: Long = (st.prefillMs + st.decodeMs).takeIf { it > 0 } ?: (System.currentTimeMillis() - t0)
|
|
||||||
onLog?.invoke("[ENGINE] prefill=${st.prefillMs}ms decode=${st.decodeMs}ms tok=${st.nTokens} (${"%.1f".format(st.decodeTokPerSec)} tok/s decode)")
|
|
||||||
GenerationResult(out, n, ms, st.decodeTokPerSec.toFloat())
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Démarre une conversation VIERGE (garde le system prefillé). À appeler aux
|
|
||||||
* bornes de conversation (changement de patient, effacement du chat) — sinon
|
|
||||||
* la mémoire d'un patient fuiterait vers le suivant. sessionReset natif corrigé
|
|
||||||
* 2026-06-15 (clear + re-prefill system sur archi hybride où le rewind partiel
|
|
||||||
* échoue), donc on l'utilise directement. */
|
|
||||||
fun resetSession() { session?.reset() }
|
|
||||||
|
|
||||||
override fun release() { session = null; engine?.release(); engine = null }
|
|
||||||
}
|
|
||||||
|
|
@ -1,53 +0,0 @@
|
||||||
package com.kazeia.llm
|
|
||||||
|
|
||||||
/**
|
|
||||||
* JNI bridge to Qualcomm Genie SDK (libGenie.so).
|
|
||||||
* Native implementation in jni/genie_jni.cpp
|
|
||||||
*/
|
|
||||||
object GenieJni {
|
|
||||||
|
|
||||||
init {
|
|
||||||
System.loadLibrary("Genie")
|
|
||||||
System.loadLibrary("genie_jni")
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize Genie dialog from a JSON config file.
|
|
||||||
* @param configPath path to genie_config.json
|
|
||||||
* @return handle (pointer) to the dialog, or 0 on failure
|
|
||||||
*/
|
|
||||||
external fun createDialog(configPath: String): Long
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send a query to the dialog and get a response.
|
|
||||||
* @param dialogHandle handle from createDialog
|
|
||||||
* @param prompt the text prompt
|
|
||||||
* @param callback called with each decoded token; return false to stop
|
|
||||||
* @return full response string
|
|
||||||
*/
|
|
||||||
external fun query(dialogHandle: Long, prompt: String, callback: TokenCallback?): String
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set a stop sequence for the dialog.
|
|
||||||
* @param dialogHandle handle from createDialog
|
|
||||||
* @param stopSequence the stop sequence string
|
|
||||||
*/
|
|
||||||
external fun setStopSequence(dialogHandle: Long, stopSequence: String)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Free the dialog resources.
|
|
||||||
* @param dialogHandle handle from createDialog
|
|
||||||
*/
|
|
||||||
external fun freeDialog(dialogHandle: Long)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get Genie API version.
|
|
||||||
* @return "major.minor"
|
|
||||||
*/
|
|
||||||
external fun getVersion(): String
|
|
||||||
|
|
||||||
interface TokenCallback {
|
|
||||||
/** Called for each generated token. Return false to stop generation. */
|
|
||||||
fun onToken(token: String): Boolean
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -7,14 +7,9 @@ set(JNILIBS_DIR ${CMAKE_SOURCE_DIR}/../jniLibs/${ANDROID_ABI})
|
||||||
set(KAZEIA_LLM_DIR /opt/Kazeia/kazeia-llm)
|
set(KAZEIA_LLM_DIR /opt/Kazeia/kazeia-llm)
|
||||||
set(LLAMA_UPSTREAM /opt/Kazeia/llama-upstream)
|
set(LLAMA_UPSTREAM /opt/Kazeia/llama-upstream)
|
||||||
|
|
||||||
# --- Genie JNI bridge (legacy QNN backend, kept for fallback) ---
|
# Genie JNI bridge supprimé 2026-06-17 (refonte engine) : backend Genie mort,
|
||||||
add_library(genie_jni SHARED genie_jni.cpp)
|
# remplacé par UnifiedLlmAdapter (GGUF + .pte). genie_jni.cpp + libGenie.so
|
||||||
|
# archivés dans /opt/Kazeia/archive/2026-06-17_refonte-engine/.
|
||||||
add_library(Genie SHARED IMPORTED)
|
|
||||||
set_target_properties(Genie PROPERTIES IMPORTED_LOCATION ${JNILIBS_DIR}/libGenie.so)
|
|
||||||
|
|
||||||
target_link_libraries(genie_jni Genie android log)
|
|
||||||
target_compile_options(genie_jni PRIVATE -std=c++17 -O2)
|
|
||||||
|
|
||||||
# Whisper.cpp JNI fallback supprimé 2026-05-02 (frozen stack — STT = NPU only).
|
# Whisper.cpp JNI fallback supprimé 2026-05-02 (frozen stack — STT = NPU only).
|
||||||
# Les libggml IMPORTED restent ci-dessous : utilisées par tts_talker_cpu et tts_cp_cpu.
|
# Les libggml IMPORTED restent ci-dessous : utilisées par tts_talker_cpu et tts_cp_cpu.
|
||||||
|
|
|
||||||
|
|
@ -1,201 +0,0 @@
|
||||||
#include <jni.h>
|
|
||||||
#include <string>
|
|
||||||
#include <android/log.h>
|
|
||||||
|
|
||||||
#define TAG "GenieJNI"
|
|
||||||
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, TAG, __VA_ARGS__)
|
|
||||||
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__)
|
|
||||||
|
|
||||||
// Genie C API declarations (from libGenie.so)
|
|
||||||
extern "C" {
|
|
||||||
// Opaque types
|
|
||||||
typedef void* GenieDialogConfig;
|
|
||||||
typedef void* GenieDialog;
|
|
||||||
typedef void* GenieTokenizer;
|
|
||||||
typedef void* GenieSampler;
|
|
||||||
|
|
||||||
// Version
|
|
||||||
int Genie_getApiMajorVersion();
|
|
||||||
int Genie_getApiMinorVersion();
|
|
||||||
int Genie_getApiPatchVersion();
|
|
||||||
|
|
||||||
// DialogConfig
|
|
||||||
GenieDialogConfig GenieDialogConfig_createFromJson(const char* jsonPath);
|
|
||||||
void GenieDialogConfig_free(GenieDialogConfig config);
|
|
||||||
|
|
||||||
// Dialog
|
|
||||||
GenieDialog GenieDialog_create(GenieDialogConfig config);
|
|
||||||
void GenieDialog_free(GenieDialog dialog);
|
|
||||||
const char* GenieDialog_query(GenieDialog dialog, const char* prompt);
|
|
||||||
void GenieDialog_setStopSequence(GenieDialog dialog, const char* stopSeq);
|
|
||||||
void GenieDialog_reset(GenieDialog dialog);
|
|
||||||
void GenieDialog_signal(GenieDialog dialog);
|
|
||||||
GenieTokenizer GenieDialog_getTokenizer(GenieDialog dialog);
|
|
||||||
GenieSampler GenieDialog_getSampler(GenieDialog dialog);
|
|
||||||
|
|
||||||
// Sampler callback
|
|
||||||
typedef bool (*GenieSamplerCallback)(const char* token, void* userData);
|
|
||||||
void GenieSampler_registerUserDataCallback(
|
|
||||||
GenieSampler sampler,
|
|
||||||
GenieSamplerCallback callback,
|
|
||||||
void* userData
|
|
||||||
);
|
|
||||||
|
|
||||||
// Tokenizer
|
|
||||||
const char* GenieTokenizer_decode(GenieTokenizer tokenizer, const int* tokens, int numTokens);
|
|
||||||
int* GenieTokenizer_encode(GenieTokenizer tokenizer, const char* text, int* numTokens);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if a pointer looks like a valid heap pointer (not an error code)
|
|
||||||
// Genie SDK returns small negative int values as error codes (e.g. -5 = 0xfffffffb)
|
|
||||||
// On ARM64 Android, valid heap pointers are always > 0x100000000 (above 4GB)
|
|
||||||
static bool isValidPointer(void* ptr) {
|
|
||||||
uintptr_t addr = reinterpret_cast<uintptr_t>(ptr);
|
|
||||||
if (ptr == nullptr) return false;
|
|
||||||
// Any value that fits in 32 bits is likely an error code, not a heap pointer
|
|
||||||
if (addr <= 0xFFFFFFFFULL) return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Callback context for token streaming
|
|
||||||
struct CallbackContext {
|
|
||||||
JNIEnv* env;
|
|
||||||
jobject callback;
|
|
||||||
jmethodID onTokenMethod;
|
|
||||||
std::string fullResponse;
|
|
||||||
bool shouldStop;
|
|
||||||
};
|
|
||||||
|
|
||||||
static bool samplerCallback(const char* token, void* userData) {
|
|
||||||
auto* ctx = reinterpret_cast<CallbackContext*>(userData);
|
|
||||||
if (ctx->shouldStop || token == nullptr) return false;
|
|
||||||
|
|
||||||
ctx->fullResponse += token;
|
|
||||||
|
|
||||||
if (ctx->callback != nullptr) {
|
|
||||||
JNIEnv* env = ctx->env;
|
|
||||||
jstring jToken = env->NewStringUTF(token);
|
|
||||||
jboolean continueGen = env->CallBooleanMethod(
|
|
||||||
ctx->callback, ctx->onTokenMethod, jToken
|
|
||||||
);
|
|
||||||
env->DeleteLocalRef(jToken);
|
|
||||||
|
|
||||||
if (!continueGen) {
|
|
||||||
ctx->shouldStop = true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C" {
|
|
||||||
|
|
||||||
JNIEXPORT jlong JNICALL
|
|
||||||
Java_com_kazeia_llm_GenieJni_createDialog(JNIEnv* env, jobject, jstring configPath) {
|
|
||||||
const char* path = env->GetStringUTFChars(configPath, nullptr);
|
|
||||||
LOGI("Creating dialog from config: %s", path);
|
|
||||||
|
|
||||||
GenieDialogConfig config = GenieDialogConfig_createFromJson(path);
|
|
||||||
env->ReleaseStringUTFChars(configPath, path);
|
|
||||||
|
|
||||||
if (!isValidPointer(config)) {
|
|
||||||
LOGE("Failed to create dialog config (returned %p, likely error code %ld)",
|
|
||||||
config, reinterpret_cast<long>(config));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
LOGI("Dialog config created: %p", config);
|
|
||||||
GenieDialog dialog = GenieDialog_create(config);
|
|
||||||
GenieDialogConfig_free(config);
|
|
||||||
|
|
||||||
if (!isValidPointer(dialog)) {
|
|
||||||
LOGE("Failed to create dialog (returned %p, likely error code %ld)",
|
|
||||||
dialog, reinterpret_cast<long>(dialog));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
LOGI("Dialog created successfully: %p", dialog);
|
|
||||||
return reinterpret_cast<jlong>(dialog);
|
|
||||||
}
|
|
||||||
|
|
||||||
JNIEXPORT jstring JNICALL
|
|
||||||
Java_com_kazeia_llm_GenieJni_query(
|
|
||||||
JNIEnv* env, jobject, jlong dialogHandle, jstring prompt, jobject callback
|
|
||||||
) {
|
|
||||||
auto* dialog = reinterpret_cast<GenieDialog>(dialogHandle);
|
|
||||||
|
|
||||||
if (!isValidPointer(dialog)) {
|
|
||||||
LOGE("Invalid dialog handle: %p", dialog);
|
|
||||||
return env->NewStringUTF("[Erreur: modèle LLM non chargé]");
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* promptStr = env->GetStringUTFChars(prompt, nullptr);
|
|
||||||
|
|
||||||
CallbackContext ctx;
|
|
||||||
ctx.env = env;
|
|
||||||
ctx.callback = callback;
|
|
||||||
ctx.shouldStop = false;
|
|
||||||
|
|
||||||
if (callback != nullptr) {
|
|
||||||
jclass cbClass = env->GetObjectClass(callback);
|
|
||||||
ctx.onTokenMethod = env->GetMethodID(
|
|
||||||
cbClass, "onToken", "(Ljava/lang/String;)Z"
|
|
||||||
);
|
|
||||||
|
|
||||||
// Register the sampler callback
|
|
||||||
GenieSampler sampler = GenieDialog_getSampler(dialog);
|
|
||||||
if (isValidPointer(sampler)) {
|
|
||||||
GenieSampler_registerUserDataCallback(sampler, samplerCallback, &ctx);
|
|
||||||
} else {
|
|
||||||
LOGE("Invalid sampler pointer: %p", sampler);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
LOGI("Query: %.80s...", promptStr);
|
|
||||||
const char* response = GenieDialog_query(dialog, promptStr);
|
|
||||||
env->ReleaseStringUTFChars(prompt, promptStr);
|
|
||||||
|
|
||||||
// Use callback accumulated response if available, otherwise use direct response
|
|
||||||
std::string result;
|
|
||||||
if (!ctx.fullResponse.empty()) {
|
|
||||||
result = ctx.fullResponse;
|
|
||||||
} else if (response != nullptr) {
|
|
||||||
result = response;
|
|
||||||
}
|
|
||||||
|
|
||||||
LOGI("Response length: %zu chars", result.size());
|
|
||||||
return env->NewStringUTF(result.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
JNIEXPORT void JNICALL
|
|
||||||
Java_com_kazeia_llm_GenieJni_setStopSequence(
|
|
||||||
JNIEnv* env, jobject, jlong dialogHandle, jstring stopSequence
|
|
||||||
) {
|
|
||||||
auto* dialog = reinterpret_cast<GenieDialog>(dialogHandle);
|
|
||||||
if (!isValidPointer(dialog)) return;
|
|
||||||
const char* seq = env->GetStringUTFChars(stopSequence, nullptr);
|
|
||||||
GenieDialog_setStopSequence(dialog, seq);
|
|
||||||
env->ReleaseStringUTFChars(stopSequence, seq);
|
|
||||||
}
|
|
||||||
|
|
||||||
JNIEXPORT void JNICALL
|
|
||||||
Java_com_kazeia_llm_GenieJni_freeDialog(JNIEnv*, jobject, jlong dialogHandle) {
|
|
||||||
auto* dialog = reinterpret_cast<GenieDialog>(dialogHandle);
|
|
||||||
if (isValidPointer(dialog)) {
|
|
||||||
GenieDialog_free(dialog);
|
|
||||||
LOGI("Dialog freed");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
JNIEXPORT jstring JNICALL
|
|
||||||
Java_com_kazeia_llm_GenieJni_getVersion(JNIEnv* env, jobject) {
|
|
||||||
int major = Genie_getApiMajorVersion();
|
|
||||||
int minor = Genie_getApiMinorVersion();
|
|
||||||
int patch = Genie_getApiPatchVersion();
|
|
||||||
std::string version = std::to_string(major) + "." +
|
|
||||||
std::to_string(minor) + "." +
|
|
||||||
std::to_string(patch);
|
|
||||||
return env->NewStringUTF(version.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
} // extern "C"
|
|
||||||
|
|
@ -9,7 +9,6 @@ d523468d62d9b603cb3354294d70d4b2feabf2c3f1e43b0c96c9aabf32813708 libc++_shared.
|
||||||
dd0506873aeb45e103ef0023678a7f14938a0f147f2348d1efc366f1dce40863 libexecutorch_jni.so
|
dd0506873aeb45e103ef0023678a7f14938a0f147f2348d1efc366f1dce40863 libexecutorch_jni.so
|
||||||
0b6f86e114f0cf9f2940194797f06ded576e6b3272a5ffbb2c4b8cdc02850ef8 libexecutorch.so
|
0b6f86e114f0cf9f2940194797f06ded576e6b3272a5ffbb2c4b8cdc02850ef8 libexecutorch.so
|
||||||
34a0af206f660461e3da687f64172830cc61a32a93732fd7e984c43996d6fd91 libfbjni.so
|
34a0af206f660461e3da687f64172830cc61a32a93732fd7e984c43996d6fd91 libfbjni.so
|
||||||
d49b53137f478b7b4ccbd58b9166d83e832c299b681609c70628291c61ae7204 libGenie.so
|
|
||||||
616fa830f6fd3396ea7f0ca92f348c2146efb0b1154ab6ed2e6709655905ead3 libggml-base.so
|
616fa830f6fd3396ea7f0ca92f348c2146efb0b1154ab6ed2e6709655905ead3 libggml-base.so
|
||||||
66ea0c948385d8060a7296285d7a85738c21318a88ef767986444a3d9683aeea libggml-cpu.so
|
66ea0c948385d8060a7296285d7a85738c21318a88ef767986444a3d9683aeea libggml-cpu.so
|
||||||
7aeb209ec5c1da8857779b8f3b4c3e7519ed69c6211491948d3c87349dbced57 libggml.so
|
7aeb209ec5c1da8857779b8f3b4c3e7519ed69c6211491948d3c87349dbced57 libggml.so
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue