235 lines
8.9 KiB
Markdown
235 lines
8.9 KiB
Markdown
# Kazeia — Stack production figée
|
||
|
||
**Date du gel : 2026-05-02**
|
||
|
||
Ce document définit la stack **autorisée** de Kazeia. Tout composant non listé
|
||
ici doit être considéré comme **non autorisé** et ne doit pas être réintroduit
|
||
sans validation explicite + mise à jour de ce contrat.
|
||
|
||
---
|
||
|
||
## Emplacement des modèles (MAJ 2026-05-18 — chantier installeur Phase 0)
|
||
|
||
Les chemins `/data/local/tmp/kazeia/models/` et `/data/local/tmp/kazeia-et/`
|
||
cités ci-dessous restent **valides sur les tablettes de dev** (modèles poussés
|
||
par `adb push`). Ils sont désormais **résolus au runtime par `KazeiaPaths`** :
|
||
|
||
- si la racine `/data/local/tmp` existe et est non vide → elle prime (dev) ;
|
||
- sinon → stockage externe app `getExternalFilesDir("kazeia")/{models,llm}`,
|
||
rempli par l'installeur (modèles téléchargés depuis le Nextcloud).
|
||
|
||
Aucun composant n'est ajouté ni retiré — seul l'emplacement de chargement
|
||
devient dynamique. `KazeiaApplication.MODELS_DIR` / `.LLM_DIR` sont les points
|
||
d'accès uniques. Cf `project_kazeia_installer_updates`.
|
||
|
||
---
|
||
|
||
## STT — Speech-to-Text
|
||
|
||
### Composant figé
|
||
|
||
`com.kazeia.stt.WhisperHybridEngine` (542 lignes) — chemin **NPU only**
|
||
- Encoder + Decoder Qualcomm AI Hub HfWhisper KV-cache (Whisper-Small 12L/12H)
|
||
- Modèles tablette : `/data/local/tmp/kazeia/models/whisper-small-sm8750/`
|
||
(fingerprints MD5 dans `/opt/Kazeia/kazeia-stt-perf-validated/models/README.md`)
|
||
- Backend : ONNX Runtime QNN HTP V79 (Snapdragon 8 Elite)
|
||
- Performance validée : RTF 0.5 (audio 1.6 s → 825 ms)
|
||
- Override `<|translate|>` → `<|transcribe|>` actif (force transcription FR)
|
||
- Auto-détection layers/heads via `enc.outputInfo["k_cache_cross_0"]`
|
||
|
||
### Mel extractor figé
|
||
|
||
`com.kazeia.stt.MelExtractor` + `kazeia-android/app/src/main/jni/mel_extractor.cpp`
|
||
- HuggingFace-compatible WhisperFeatureExtractor en C++ pur
|
||
- 80 mels × 3000 frames, FFT 400, hop 160
|
||
|
||
### Wrapper v2 figé
|
||
|
||
`com.kazeia.v2.SttStage` — thin wrapper sur `WhisperHybridEngine`
|
||
|
||
### ❌ Interdit
|
||
- Pas de fallback CPU (`WhisperSttEngine`, `WhisperJni`, `whisper.cpp`) — supprimés
|
||
- Pas de fallback Android stock (`AndroidSttEngine`) — supprimé
|
||
- Pas d'autres backends (`WhisperLiteRtEngine`, `WhisperNpuSttEngine`) — supprimés
|
||
- Pas de Qwen3-ASR (1.7B GGUF cassé, 0.6B qualité FR insuffisante)
|
||
- Pas de `libwhisper.so` dans jniLibs — supprimé
|
||
|
||
---
|
||
|
||
## VAD — Voice Activity Detection
|
||
|
||
### Composant figé
|
||
|
||
**Détection RMS-énergie inline** :
|
||
- v1 : `KazeiaService.startContinuousListening()` — frame 1600 samples (100 ms),
|
||
threshold RMS=150, ≥ 300 ms speech, ≥ 800 ms silence end
|
||
- v2 : `com.kazeia.v2.VadStage` — réimplémentation propre du même algorithme
|
||
|
||
### ❌ Interdit
|
||
- Pas de Silero VAD (`SileroVadEngine.kt` + `silero_vad.onnx` — supprimés)
|
||
- Pas de `AudioCaptureManager.kt` — supprimé
|
||
- Pas de `core.VadEngine` interface — supprimée
|
||
- Cf `feedback_kazeia_vad_rms.md` : Silero plafonne à 5e-4 sur ce mic
|
||
|
||
---
|
||
|
||
## LLM — Large Language Model
|
||
|
||
### Composants figés v1 (legacy `KazeiaService`)
|
||
|
||
`com.kazeia.llm.ExecuTorchLlmEngine` (in-process)
|
||
- Modèle : `hybrid_llama_qnn.pte` symlink → `hybrid_llama_qnn_4b.pte` sur tablette
|
||
- Tokenizer : `tokenizer.json`
|
||
- Backend : ExecuTorch + QNN HTP NPU (in-process via PyTorch ExecuTorch JNI)
|
||
- Path : `/data/local/tmp/kazeia-et/`
|
||
|
||
### Composants figés v2 (`KazeiaServiceV2`)
|
||
|
||
`com.kazeia.v2.LlmCascadeStage` (mode mono-Speaker — temporaire RAM-budget)
|
||
- Spawn 1× `qnn_llama_runner --daemon_mode` via `ExecutorchDaemon`
|
||
- Modèle : `hybrid_llama_qnn_4b.pte` + `tokenizer.json`
|
||
- System prompt : SYS_SPEAKER (psychologue bienveillant, 1-2 phrases FR concises)
|
||
- Le code Thinker/cascade est conservé en commentaire pour restauration future
|
||
|
||
### ❌ Interdit
|
||
- Pas de `LlamaCppLlmEngine` (purgé 2026-04-29)
|
||
- Pas de `KazeiaLlmJni` (purgé 2026-04-29)
|
||
- Pas de Genie SDK (bug GQA Qwen3)
|
||
- Pas de cascade Thinker+Speaker SIMULTANÉE en cohabitation TTS (RAM OOM, cf
|
||
cleanup 2026-05-02)
|
||
- Pas de `LLM_BACKEND` constante / `_currentLlmModel` UI selector
|
||
|
||
### Restauration cascade complète : conditionné
|
||
|
||
À envisager **uniquement après** :
|
||
- Task #240 (libllama.so contre chraac-llama récent) → -30 % RAM/perf Talker+CP
|
||
- OU partage `.ptd` entre 2× 4B → -2.4 GB RAM
|
||
- OU phased loading opportuniste (cf `feedback_kazeia_vad_rms.md` non, l'analyse
|
||
RAM dans la conversation 2026-05-02)
|
||
- En attendant, mono-Speaker reste figé
|
||
|
||
---
|
||
|
||
## TTS — Text-to-Speech
|
||
|
||
### Composant figé
|
||
|
||
`com.kazeia.tts.Qwen3TtsEngine` — voie **ggml-cpu Talker + ggml-cpu CP + ggml C++ Decoder**
|
||
- Talker : `TtsTalkerCpuJni` linké contre `libllama.so` (in jniLibs)
|
||
- Modèle préféré : `talker_f32.gguf` (1.78 GB, fp32, élimine drift fp16)
|
||
- Fallback : `talker_f16.gguf`
|
||
- CP : `TtsCpCpuJni` linké contre `libllama.so`
|
||
- Modèle préféré : `cp_f32.gguf` (316 MB)
|
||
- Fallback : `cp_f16.gguf`
|
||
- Decoder : `libtts_decoder_ggml.so` static-linked contre **chraac-llama** ggml
|
||
(build : `kazeia-tts-decoder-ggml/build-android-static-chraac/`)
|
||
- GGUF : `qwen3tts_decoder.gguf` (340 MB)
|
||
- **RTF 0.96 mesuré 2026-05-02** (cf `kazeia-tts-perf-validated/`)
|
||
- Tokenizer texte : `Qwen3BpeTokenizer` (BPE byte-level Qwen2/Qwen3)
|
||
- Voice cloning : Damien (prefix 9 × 1024 + suffix 2 × 1024)
|
||
|
||
### API figée
|
||
|
||
- `synthesizeAndPlay(text, language)` — pour invocations one-shot
|
||
- `startStreamingSession()` / `enqueueSentence(text)` / `endStreamingSession()` —
|
||
pour streaming sentence-par-sentence (utilisé dans v2.TtsStage)
|
||
|
||
### Wrapper v2 figé
|
||
|
||
`com.kazeia.v2.TtsStage` — wrapper streaming-session sur `Qwen3TtsEngine`
|
||
|
||
### ❌ Interdit dans le chemin de chargement
|
||
|
||
- Pas de chemin `cp_kv_v2 ONNX` (ligne 630-658 de Qwen3TtsEngine, gated sur
|
||
`!useCpuPath` 2026-05-02)
|
||
- Pas de `cp_et_runner` TCP (sub-process root, gated 2026-05-02)
|
||
- Pas de `talker_kv_cpu` ONNX fp32 (gated sur `!useCpuPath`)
|
||
- Pas de Hexagon talker / CP (`hexStartRunner`, `useHexagonTalker`) — pas dans
|
||
flux production
|
||
- Pas de `phrase_embeds.bin` cache (bypassed 2026-05-02 — provoquait dégénération)
|
||
|
||
### ❌ Interdit moteurs alternatifs
|
||
- Pas de `AndroidTtsEngine` — supprimé
|
||
- Pas de `ChatterboxTtsEngine` — supprimé
|
||
|
||
---
|
||
|
||
## Audio playback
|
||
|
||
### Composant figé
|
||
|
||
`com.kazeia.audio.AudioPlaybackManager` (54 lignes)
|
||
|
||
L'AudioTrack interne au streaming session du `Qwen3TtsEngine` (avec keepAlive
|
||
watchdog ColorOS) reste également figé.
|
||
|
||
---
|
||
|
||
## Build / Backends
|
||
|
||
### ggml — sources autorisées
|
||
|
||
| Composant | Source ggml autorisée | Build dir |
|
||
|---|---|---|
|
||
| **TTS Decoder** | `chraac-llama` (branch `dev-refactoring`, commit `897501a`) | `build-android-static-chraac` |
|
||
| TTS Talker (lib) | jniLibs `libggml-cpu.so` (`llama-upstream`, à migrer Task #240) | `kazeia-android/.../jniLibs/arm64-v8a` |
|
||
| TTS CP (lib) | idem | idem |
|
||
| STT | n/a (ONNX Runtime, pas ggml) | n/a |
|
||
|
||
**Critique** : ne JAMAIS pointer le décodeur TTS vers `whisper.cpp/ggml` ou
|
||
`llama-upstream/ggml` — sinon RTF passe à 1.4-1.5 (mesuré, cf
|
||
`kazeia-tts-perf-validated/docs/MEASUREMENTS.md`).
|
||
|
||
### Compile flags figés
|
||
|
||
```cmake
|
||
# TTS decoder (libtts_decoder_ggml.so)
|
||
-O3 -march=armv8.6-a+dotprod+fp16+i8mm+bf16 -fopenmp -static-openmp
|
||
GGML_CPU_ARM_ARCH=armv8.6-a+dotprod+fp16+i8mm+bf16
|
||
GGML_OPENMP=ON
|
||
BUILD_SHARED_LIBS=OFF
|
||
```
|
||
|
||
---
|
||
|
||
## Fichiers de référence persistants
|
||
|
||
- `/opt/Kazeia/kazeia-stt-perf-validated/` — doc + MD5 modèles STT/VAD
|
||
- `/opt/Kazeia/kazeia-tts-perf-validated/` — doc + libs `.a` + bench CLI
|
||
reproductible TTS (RTF<1)
|
||
- `/opt/Kazeia/chraac-llama/` — fork ggml indispensable pour le décodeur TTS
|
||
- `/opt/Kazeia/kazeia-tts-decoder-ggml/build-android-static-chraac/` — build
|
||
statique pointé par l'app
|
||
|
||
---
|
||
|
||
## Comment dégeler / modifier ce contrat
|
||
|
||
**Procédure obligatoire** avant de réintroduire un composant supprimé OU de
|
||
remplacer un composant figé :
|
||
|
||
1. Mesurer la perf du composant cible **vs** la voie figée (sur la même phrase
|
||
de test, même tablette, même gouverneur DVFS)
|
||
2. Démontrer que la nouvelle voie est strictement meilleure (perf, RAM ou
|
||
maintenabilité) avec des chiffres reproductibles
|
||
3. Mettre à jour ce `FROZEN.md` avec le nouveau composant + les chiffres
|
||
4. Mettre à jour `MEMORY.md` index + memory file pertinent
|
||
5. Documenter le commit/build SHA exact dans `kazeia-{stt,tts}-perf-validated/`
|
||
6. Conserver l'ancien composant comme `*.archive.kt` UN trimestre avant
|
||
suppression définitive (filet de sécurité rollback)
|
||
|
||
Sans ce processus, **ne pas modifier la stack figée**.
|
||
|
||
---
|
||
|
||
## Métriques de référence (2026-05-02)
|
||
|
||
| Domaine | Métrique | Valeur figée | Comment |
|
||
|---|---|---:|---|
|
||
| STT | Load total | 750-1035 ms | NPU encoder + decoder + mel filters |
|
||
| STT | RTF (audio 1.6 s) | **0.51** | mel + encoder + decoder NPU |
|
||
| VAD | Trigger end-of-speech | 800 ms après dernier audio > seuil | hardcoded |
|
||
| LLM | Mono-Speaker forward | ~22 tok/s | qnn_llama_runner subprocess |
|
||
| TTS Decoder | RTF (audio 4.48 s) | **0.96** | ggml C++ chraac-llama, standalone |
|
||
| TTS Pipeline complet | RTF | ~2.87 | bottleneck CP (Task #240 pending) |
|