165 lines
8.5 KiB
Markdown
165 lines
8.5 KiB
Markdown
# 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-cdsp` refusé à `untrusted_app`). Les libs livrées dans `b-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). Voir `REBUILD_CPU_ONLY.md` pour la procédure et `project_engine_selinux_fastrpc_blocker` en 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`](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` 64 KB | `EngineLlmEngine.kt` |
|
|
| **RAG** (embeddings e5/bge, CPU) | [`RAG_INTEGRATION.md`](RAG_INTEGRATION.md) | `libkazeia_engine.so` (mêmes symboles) | `EmbedderEngine` |
|
|
|
|
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).
|