# Kazeia-Engine — vue d'ensemble et entrée d'intégration **Date** : 01/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`](STT_INTEGRATION.md) | `libkazeia_stt.so` 183 KB | `SttEngine.kt` | | **TTS** (Qwen3-TTS + clonage vocal) | [`TTS_INTEGRATION.md`](TTS_INTEGRATION.md) | `libkazeia_tts.so` 929 KB | `TtsEngine.kt` | | **LLM** (Qwen3.5 hybride / Qwen3 dense) | [`LLM_INTEGRATION.md`](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) ```kotlin // 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 : ```kotlin // 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.so` validé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](STT_INTEGRATION.md) — Whisper-Small NPU, VAD, options QNN, A/B accuracy - **TTS** : [TTS_INTEGRATION.md](TTS_INTEGRATION.md) — Qwen3-TTS, clonage vocal, sampling tuning - **LLM** : [LLM_INTEGRATION.md](LLM_INTEGRATION.md) — Qwen3.5/Qwen3, option C, threading - **Patch QNN options prod (gratuit, sans migration)** : [PATCH_QNN_PROD.md](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 1. Lire les 3 docs d'intégration dans l'ordre : STT → TTS → LLM. 2. Pousser les libs nécessaires dans `jniLibs/arm64-v8a/` (cf §2.b de chaque doc). 3. Copier les 3 façades Kotlin (`SttEngine.kt`, `TtsEngine.kt`, `EngineLlmEngine.kt`). 4. Câbler les 3 flags dispatch côté app pour bascule progressive (cf section ci-dessus). 5. Valider la checklist §7 de chaque doc en premier (System.loadLibrary + 1 call OK). 6. Bench A/B `prod` vs `lib` sur audios/prompts/modèles fixtures représentatifs. 7. Flip default vers `lib` quand les 3 sous-systèmes passent les gates (CER/WER STT, RTF TTS, decode tok/s LLM).