fix: défaut ttsEngine="lib" (crash-loop install fraîche) + ragCorpusDir externe-d'abord — v0.1.3
Deux bugs de prod trouvés en validant le cycle OTA corpus r2 : 1. ttsEngine default "prod" → toute install fraîche (release patient) chargeait Qwen3TtsEngine legacy → SIGSEGV déterministe dans llama_context ctor (libtts_talker_cpu compilé contre llama-upstream, libllama.so embarqué = fork ql depuis 2026-06-02, dérive ABI llama_context_params). La tablette release crash-loopait au démarrage du service depuis la migration ; la tablette dev ne le voyait pas (config tts_engine=lib persistée). → default "lib" (seul backend compatible avec les jniLibs livrés). 2. Le corpus RAG était résolu via MODELS_DIR/../rag_corpus : sur tablette dev, MODELS_DIR = legacy /data/local/tmp (modèles adb) → syncDir lisait l'ancien corpus alors que l'OTA dépose le composant rag_corpus dans le stockage externe. → KazeiaPaths.ragCorpusDir avec priorité INVERSE des modèles : l'externe (installeur/OTA) prime dès qu'il est non vide, fallback legacy. versionCode 4 / 0.1.3, publié catalog v6. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
747848a475
commit
16d56bfd4d
|
|
@ -44,8 +44,8 @@ android {
|
||||||
applicationId = "com.kazeia"
|
applicationId = "com.kazeia"
|
||||||
minSdk = 28
|
minSdk = 28
|
||||||
targetSdk = 36
|
targetSdk = 36
|
||||||
versionCode = 2
|
versionCode = 4
|
||||||
versionName = "0.1.1"
|
versionName = "0.1.3"
|
||||||
|
|
||||||
// WebDAV de distribution — injecté depuis local.properties.
|
// WebDAV de distribution — injecté depuis local.properties.
|
||||||
buildConfigField("String", "WEBDAV_BASE", "\"${localProp("webdav.base")}\"")
|
buildConfigField("String", "WEBDAV_BASE", "\"${localProp("webdav.base")}\"")
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ object KazeiaPaths {
|
||||||
|
|
||||||
private const val LEGACY_MODELS = "/data/local/tmp/kazeia/models"
|
private const val LEGACY_MODELS = "/data/local/tmp/kazeia/models"
|
||||||
private const val LEGACY_LLM = "/data/local/tmp/kazeia-et"
|
private const val LEGACY_LLM = "/data/local/tmp/kazeia-et"
|
||||||
|
private const val LEGACY_RAG = "/data/local/tmp/kazeia/rag_corpus"
|
||||||
|
|
||||||
/** Racine modèles STT/TTS (Whisper, GGUF, qwen3-tts-npu ; voix via `/../`). */
|
/** Racine modèles STT/TTS (Whisper, GGUF, qwen3-tts-npu ; voix via `/../`). */
|
||||||
@Volatile var modelsDir: String = LEGACY_MODELS
|
@Volatile var modelsDir: String = LEGACY_MODELS
|
||||||
|
|
@ -35,6 +36,13 @@ object KazeiaPaths {
|
||||||
@Volatile var llmDir: String = LEGACY_LLM
|
@Volatile var llmDir: String = LEGACY_LLM
|
||||||
private set
|
private set
|
||||||
|
|
||||||
|
/** Corpus RAG. Priorité INVERSE des modèles : l'EXTERNE prime dès qu'il est
|
||||||
|
* non vide, car c'est là que l'installeur/OTA dépose le composant
|
||||||
|
* `rag_corpus` — sur une tablette dev, les modèles restent legacy mais le
|
||||||
|
* corpus à jour arrive par le catalogue. Fallback legacy (adb push) sinon. */
|
||||||
|
@Volatile var ragCorpusDir: String = LEGACY_RAG
|
||||||
|
private set
|
||||||
|
|
||||||
@Volatile private var initialized = false
|
@Volatile private var initialized = false
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -50,8 +58,9 @@ object KazeiaPaths {
|
||||||
val root = File(context.getExternalFilesDir(null), "kazeia")
|
val root = File(context.getExternalFilesDir(null), "kazeia")
|
||||||
modelsDir = resolve(File(root, "models"), File(LEGACY_MODELS))
|
modelsDir = resolve(File(root, "models"), File(LEGACY_MODELS))
|
||||||
llmDir = resolve(File(root, "llm"), File(LEGACY_LLM))
|
llmDir = resolve(File(root, "llm"), File(LEGACY_LLM))
|
||||||
|
ragCorpusDir = resolveExternalFirst(File(root, "rag_corpus"), File(LEGACY_RAG))
|
||||||
initialized = true
|
initialized = true
|
||||||
Log.i(TAG, "modelsDir=$modelsDir | llmDir=$llmDir")
|
Log.i(TAG, "modelsDir=$modelsDir | llmDir=$llmDir | ragCorpusDir=$ragCorpusDir")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -61,4 +70,11 @@ object KazeiaPaths {
|
||||||
legacy.absolutePath
|
legacy.absolutePath
|
||||||
else
|
else
|
||||||
external.absolutePath
|
external.absolutePath
|
||||||
|
|
||||||
|
/** Externe si non vide (déposé par l'installeur/OTA), sinon legacy (adb push). */
|
||||||
|
private fun resolveExternalFirst(external: File, legacy: File): String =
|
||||||
|
if (external.isDirectory && !external.list().isNullOrEmpty())
|
||||||
|
external.absolutePath
|
||||||
|
else
|
||||||
|
legacy.absolutePath
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -44,10 +44,13 @@ class ConfigStore private constructor(private val file: File) {
|
||||||
* EngineLlmAdapter (libkazeia_engine + GGUF Qwen3.5). Defaults safe = "prod".
|
* EngineLlmAdapter (libkazeia_engine + GGUF Qwen3.5). Defaults safe = "prod".
|
||||||
* Bascule "lib" nécessite libllama.so fork ql dans jniLibs. */
|
* Bascule "lib" nécessite libllama.so fork ql dans jniLibs. */
|
||||||
val llmEngine: String = "prod",
|
val llmEngine: String = "prod",
|
||||||
/** Backend TTS : "prod" = Qwen3TtsEngine legacy, "lib" = libkazeia_tts unifié.
|
/** Backend TTS : "lib" = libkazeia_tts unifié (SEUL compatible avec le
|
||||||
* Defaults safe = "prod". Bascule "lib" nécessite libllama.so fork ql + retrait
|
* libllama.so fork ql embarqué depuis 2026-06-02), "prod" = Qwen3TtsEngine
|
||||||
* des classes legacy `tts_talker_cpu`/`tts_cp_cpu` (incompat ABI struct). */
|
* legacy — CRASHE (SIGSEGV nativeInit, dérive ABI llama_context_params) tant
|
||||||
val ttsEngine: String = "prod",
|
* que les .so legacy ne sont pas recompilés contre les headers fork ql.
|
||||||
|
* Default "lib" depuis 2026-06-11 : l'ancien défaut "prod" mettait toute
|
||||||
|
* install fraîche en crash-loop au démarrage du service. */
|
||||||
|
val ttsEngine: String = "lib",
|
||||||
/** RAG (récupération de contexte injecté au prompt). Default OFF : tant que
|
/** RAG (récupération de contexte injecté au prompt). Default OFF : tant que
|
||||||
* kazeia-engine n'expose pas embedText + qu'aucun corpus n'est ingéré,
|
* kazeia-engine n'expose pas embedText + qu'aucun corpus n'est ingéré,
|
||||||
* l'activer est inerte (l'embedder n'est pas prêt). Pilotable via admin. */
|
* l'activer est inerte (l'embedder n'est pas prêt). Pilotable via admin. */
|
||||||
|
|
@ -113,7 +116,7 @@ class ConfigStore private constructor(private val file: File) {
|
||||||
ttsEnabled = true,
|
ttsEnabled = true,
|
||||||
sttEngine = "prod",
|
sttEngine = "prod",
|
||||||
llmEngine = "prod",
|
llmEngine = "prod",
|
||||||
ttsEngine = "prod"
|
ttsEngine = "lib" // legacy "prod" = SIGSEGV avec le libllama fork ql embarqué
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -668,7 +668,7 @@ Pas d'introduction, pas d'explication. Juste les 4 lignes en francais. /no_think
|
||||||
intent?.getStringExtra("rag_ingest")?.let { dirArg ->
|
intent?.getStringExtra("rag_ingest")?.let { dirArg ->
|
||||||
// (Ré)ingestion du corpus dans l'instance RAG live : clear + ingestDir.
|
// (Ré)ingestion du corpus dans l'instance RAG live : clear + ingestDir.
|
||||||
// dirArg vide -> dossier corpus par défaut. Brique de l'app admin future.
|
// dirArg vide -> dossier corpus par défaut. Brique de l'app admin future.
|
||||||
val dir = dirArg.ifBlank { "${KazeiaApplication.MODELS_DIR}/../rag_corpus" }
|
val dir = dirArg.ifBlank { com.kazeia.KazeiaPaths.ragCorpusDir }
|
||||||
log("RAG ingest: $dir")
|
log("RAG ingest: $dir")
|
||||||
serviceScope.launch {
|
serviceScope.launch {
|
||||||
val r = rag
|
val r = rag
|
||||||
|
|
@ -2081,7 +2081,7 @@ Pas d'introduction, pas d'explication. Juste les 4 lignes en francais. /no_think
|
||||||
// que le delta) : couvre le 1er démarrage ET les MAJ OTA du composant
|
// que le delta) : couvre le 1er démarrage ET les MAJ OTA du composant
|
||||||
// rag_corpus (nouveaux fichiers ingérés au redémarrage suivant).
|
// rag_corpus (nouveaux fichiers ingérés au redémarrage suivant).
|
||||||
if (it.isReady)
|
if (it.isReady)
|
||||||
it.syncDir("${KazeiaApplication.MODELS_DIR}/../rag_corpus")
|
it.syncDir(com.kazeia.KazeiaPaths.ragCorpusDir)
|
||||||
it.reingestMissing() // embed les docs admin ajoutés hors-ligne
|
it.reingestMissing() // embed les docs admin ajoutés hors-ligne
|
||||||
rag = it
|
rag = it
|
||||||
com.kazeia.rag.RagHolder.instance = it
|
com.kazeia.rag.RagHolder.instance = it
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue