8.3 KiB
Kazeia-Engine — vue d'ensemble et entrée d'intégration
⚠️ 02/06 : bloqueur SELinux découvert sur les libs LLM/TTS in-app (
/dev/fastrpc-cdsprefusé àuntrusted_app). Les libs livrées dansb-jni/sont inutilisables dans un APK Play Store/sideload en l'état. Rebuild CPU-only requis côté dev avant intégration LLM/TTS. STT non affecté (passe par QNN Maven). VoirREBUILD_CPU_ONLY.mdpour la procédure etproject_engine_selinux_fastrpc_blockeren mémoire pour le détail.
Date : 02/06/2026. Moteur d'inférence local-first pour Snapdragon 8 Elite (Pad3). Unifie LLM + TTS + STT dans une stack cohérente. Pas de cloud, pas de root, pas de Python runtime.
Documents d'intégration (3 indépendants)
Pour intégrer dans l'app Kazeia, lis ces 3 docs (un par sous-système) :
| Sous-système | Doc d'intégration | Lib .so |
Façade Kotlin |
|---|---|---|---|
| STT (Whisper-Small NPU) | STT_INTEGRATION.md |
libkazeia_stt.so 183 KB |
SttEngine.kt |
| TTS (Qwen3-TTS + clonage vocal) | TTS_INTEGRATION.md |
libkazeia_tts.so 929 KB |
TtsEngine.kt |
| LLM (Qwen3.5 hybride / Qwen3 dense) | LLM_INTEGRATION.md |
libkazeia_engine.so 60 KB |
EngineLlmEngine.kt |
Chaque doc a la même structure : libs à pousser, façade Kotlin, exemples, codes d'erreur, bench standalone, checklist d'intégration, pièges connus, perf détaillée.
Architecture
┌────────────────────── Kazeia-Engine ──────────────────────┐
│ │
│ STT TTS LLM │
│ libkazeia_stt libkazeia_tts libkazeia_eng │
│ 183 KB 929 KB 60 KB │
│ │ │ │ │
│ └─ libonnxruntime └────────┬───────────┘ │
│ libQnnHtp* libllama 35 MB │
│ libcdsprpc libggml + ggml-cpu │
│ libggml-hexagon │
│ libggml-htp-v79 │
│ (chaîne mutualisée TTS+LLM) │
│ │
└────────────────────────────────────────────────────────────┘
Côté APK :
jniLibs/arm64-v8a/
libkazeia_stt.so + libonnxruntime.so (2 fichiers, ~20 MB)
libkazeia_tts.so + libkazeia_engine.so + libllama.so + ... (8 fichiers, ~53 MB partagés)
libc++_shared.so (commune)
TOTAL ~75 MB pour les 3 sous-systèmes (vs ~50 MB ExecuTorch seul).
API Kotlin unifiée (côté app)
// STT
val stt = SttEngine(modelDir = "/data/.../whisper-small-sm8750", useHtp = true)
val transcript = stt.transcribe(pcm16, language = "fr")
// VAD (drop-in replacement de l'ancienne VadStage.kt)
val vad = SttVad()
when (vad.push(chunk)) {
SttVad.SPEECH -> buffer.addAll(chunk.toList())
SttVad.END_OF_SPEECH -> { stt.transcribe(buffer); vad.reset() }
}
// TTS in-process (Qwen3-TTS + clonage vocal)
val tts = TtsEngine(
talkerGguf = "/data/.../talker_f32.gguf",
vocabGguf = "/data/.../Qwen3-4B-Q4_0.gguf",
dumpDir = "/data/.../tts_dump",
nThreads = 6
)
val r = tts.synthesize("Bonjour, comment ça va ?", "/sdcard/out.wav")
// Clonage vocal embarqué (optionnel)
val pierreVoice = tts.encodeSpeakerWav("/sdcard/voix_pierre.wav")
tts.synthesize("Bonjour Pierre.", outWav, xvectorOverride = pierreVoice)
// LLM (Qwen3.5 GGUF cascade Speaker + Thinker)
val llm = EngineLlmEngine("/data/.../Qwen3.5-4B-Q4_0.gguf", ctx = 4096, nThreads = 6)
val reply = llm.generate(sys = "Tu es Kazeia...", usr = userInput, max = 96)
Pattern d'unification recommandé (cf demande dev Kazeia)
Pour permettre une bascule progressive prod ↔ lib sans dégeler les sous-systèmes, le dev a câblé un flag de dispatch côté app pour STT et propose de faire pareil pour LLM et TTS :
// Dans KazeiaService.kt (ou équivalent)
class KazeiaService {
private val sttEngine = when (flag("sttEngine", default = "prod")) {
"lib" -> SttEngine(...) // libkazeia_stt
else -> WhisperHybridEngine(...) // legacy ONNX/QNN direct
}
private val llmEngine = when (flag("llmEngine", default = "prod")) {
"lib" -> EngineLlmEngine(...) // libkazeia_engine
else -> ExecuTorchLlmEngine(...) // legacy .pte
}
private val ttsEngine = when (flag("ttsEngine", default = "prod")) {
"lib" -> TtsEngine(...) // libkazeia_tts
else -> LegacyTtsPipeline(...) // legacy à supprimer une fois libé validée
}
}
Toggle via adb shell setprop kazeia.sttEngine lib (ou équivalent du flag system). Bascule réversible, mesurable en CER/WER/RTF avant de flip le default.
État réel des 3 dispatch flags (à confirmer côté dev) :
- ✅ STT : flag câblé, default
prod, A/B in-app validé - ⏳ LLM : flag à ajouter (mirror exact du STT). Lib + façade + doc prêts.
- ⏳ TTS : flag à ajouter une fois
libkazeia_tts.sovalidée load + 1 synth in-app.
État livré (01/06/2026, commit en cours)
Lib .so |
Façade Kotlin | JNI source | Doc d'intégration | Bug investigué | |
|---|---|---|---|---|---|
| STT | ✅ 183 KB | ✅ SttEngine.kt |
✅ kazeia_stt_jni.cpp |
✅ STT_INTEGRATION.md 15 KB |
✅ 2 bugs fixés (DFT 400 + forced prompt) |
| TTS | ✅ 929 KB | ✅ TtsEngine.kt |
✅ kazeia_tts_jni.cpp |
✅ TTS_INTEGRATION.md 10 KB (cette session) |
✅ Crash load = libs manquantes, liste exhaustive donnée |
| LLM | ✅ 60 KB | ✅ EngineLlmEngine.kt |
✅ kazeia_engine_jni.cpp |
✅ LLM_INTEGRATION.md 10 KB (cette session) |
✅ Bug threads = nThreads=4 hardcoded, fix nThreads=6 paramétrable |
Empreinte mémoire (Snapdragon 8 Elite, 16 GB RAM, mesures r3)
| Composant chargé | RAM peak |
|---|---|
| STT Whisper-Small NPU (encoder + decoder QAIRT) | 379 MB |
| TTS (talker + CP + decoder + vocab + xvector fixture) | 3.5 GB |
| TTS clonage vocal (speaker encoder, en plus) | +34 MB |
| LLM Qwen3.5-4B Q4_0 (1 instance) | 2.4 GB |
| LLM Qwen3.5-9B Q4_0 (1 instance) | 5.0 GB |
| Cascade typique : STT + Speaker 4B + Guard 4B + TTS | ~9 GB / 16 GB |
Perf bout-en-bout (latence typique)
mic 16 kHz PCM16
↓ AudioRecord
SttVad RMS → ~830 ms après fin parole (silence 800 ms + overhead)
↓ end_of_speech
SttEngine.transcribe(pcm) → ~500-2000 ms (RTF 0.18-0.40 sur audio 3-10s FR)
↓ texte FR
LLM Speaker 4B (+ Guard 4B) → ~5-10 s (cascade Speaker + Guard 4B)
↓ réponse FR
TtsEngine.synthesize(text) → ~3-10 s (RTF 2.5-3.0 selon longueur)
↓
audio playback
Latence totale voix→audio : ~10-25 s par tour, dominée par LLM + TTS.
Documentation détaillée
- STT : STT_INTEGRATION.md — Whisper-Small NPU, VAD, options QNN, A/B accuracy
- TTS : TTS_INTEGRATION.md — Qwen3-TTS, clonage vocal, sampling tuning
- LLM : LLM_INTEGRATION.md — Qwen3.5/Qwen3, option C, threading
- Patch QNN options prod (gratuit, sans migration) : PATCH_QNN_PROD.md
- Engine global (CLAUDE.md projet) :
/opt/Kazeia-engine/CLAUDE.md - Mémoires assistant :
/home/alf/.claude/projects/-opt-Kazeia-engine/memory/
Pour démarrer l'intégration
- Lire les 3 docs d'intégration dans l'ordre : STT → TTS → LLM.
- Pousser les libs nécessaires dans
jniLibs/arm64-v8a/(cf §2.b de chaque doc). - Copier les 3 façades Kotlin (
SttEngine.kt,TtsEngine.kt,EngineLlmEngine.kt). - Câbler les 3 flags dispatch côté app pour bascule progressive (cf section ci-dessus).
- Valider la checklist §7 de chaque doc en premier (System.loadLibrary + 1 call OK).
- Bench A/B
prodvslibsur audios/prompts/modèles fixtures représentatifs. - Flip default vers
libquand les 3 sous-systèmes passent les gates (CER/WER STT, RTF TTS, decode tok/s LLM).