7.5 KiB
7.5 KiB
Architecture Pipeline Kazeia
Version 2.0 — 28 mars 2026
Principe
Le pipeline Kazeia est modulaire : STT et TTS sont indépendants et échangent uniquement du texte avec une chaîne de processeurs pluggables.
┌─────────┐ ┌──────────────────────────┐ ┌─────────┐
│ STT │────→│ PROCESSOR CHAIN │────→│ TTS │
│(Whisper)│ │ │ │(Android/│
│ │ │ ┌──────────────────┐ │ │Chatterbox│
│ Audio │ │ │ Voice Commands │ │ │ │
│ → Text │ │ └────────┬─────────┘ │ │ Text │
│ │ │ ┌────────▼─────────┐ │ │ → Audio│
│ │ │ │ LLM (Qwen3 NPU) │ │ │ │
│ │ │ └────────┬─────────┘ │ │ │
│ │ │ ┌────────▼─────────┐ │ │ │
│ │ │ │ (Future: RAG) │ │ │ │
│ │ │ └────────┬─────────┘ │ │ │
│ │ │ ┌────────▼─────────┐ │ │ │
│ │ │ │ (Future: Emotion)│ │ │ │
│ │ │ └──────────────────┘ │ │ │
└─────────┘ └──────────────────────────┘ └─────────┘
Interfaces
SttEngine (Speech-to-Text)
interface SttEngine {
suspend fun load(modelPath: String?)
fun isLoaded(): Boolean
suspend fun transcribe(audioData: ShortArray, language: String): TranscriptionResult
fun release()
}
Implémentations :
| Classe | Backend | Latence | NPU |
|---|---|---|---|
WhisperSttEngine |
whisper.cpp CPU | ~1500ms | Non |
WhisperNpuSttEngine |
ExecuTorch QNN | ~50ms* | Oui |
AndroidSttEngine |
Google SpeechRecognizer | ~500ms | Non (cloud) |
TtsEngine (Text-to-Speech)
interface TtsEngine {
suspend fun load(modelPath: String?, voiceId: String?)
fun isLoaded(): Boolean
suspend fun synthesizeAndPlay(text: String, language: String, onStart: (() -> Unit)?, onComplete: (() -> Unit)?)
fun stop()
fun release()
}
Implémentations :
| Classe | Backend | Latence | Clonage voix |
|---|---|---|---|
AndroidTtsEngine |
Google TTS | ~200ms | Non |
ChatterboxTtsEngine |
ONNX CPU/NPU | ~3-10s | Oui |
MessageProcessor (Middleware)
interface MessageProcessor {
val name: String
suspend fun initialize()
fun isReady(): Boolean
suspend fun process(input: String, context: ConversationContext): ProcessorResult
fun release()
}
Implémentations :
| Classe | Rôle | Priorité |
|---|---|---|
VoiceCommandProcessor2 |
Intercepte les commandes vocales | 1 (premier) |
LlmProcessor |
Génère des réponses via LLM | 2 |
EchoProcessor |
Répète l'input (fallback/test) | 3 |
(Future) EmotionProcessor |
Détecte l'émotion de la voix | 1.5 |
(Future) RagProcessor |
Enrichit avec des documents | 1.5 |
(Future) DiarizationProcessor |
Identifie le locuteur | 1 |
Chaîne de traitement
Les processeurs sont exécutés dans l'ordre. Le premier qui retourne shouldContinueChain = false termine la chaîne.
Input: "Bonjour, comment vas-tu ?"
→ VoiceCommandProcessor2: pas de commande → continue
→ LlmProcessor: "Je vais bien, comment puis-je t'aider ?" → done
Output: "Je vais bien, comment puis-je t'aider ?"
Input: "stop"
→ VoiceCommandProcessor2: commande STOP_LISTENING → done (shouldSpeak=false)
Output: (arrête l'écoute)
Ajouter un nouveau processeur
class MonNouveauProcessor : MessageProcessor {
override val name = "MonProcesseur"
override suspend fun process(input: String, context: ConversationContext): ProcessorResult {
// Traiter l'input
val enrichedInput = "[$emotion] $input"
return ProcessorResult(
responseText = "",
shouldContinueChain = true, // passe au processeur suivant
metadata = mapOf("emotion" to "triste")
)
}
}
// Ajout au pipeline
pipeline.addProcessor(MonNouveauProcessor())
ConversationContext
Le contexte est partagé entre tous les processeurs :
data class ConversationContext(
val history: List<ChatMessage>, // historique conversation
val metadata: MutableMap<String, Any>, // données partagées
val language: String, // "fr"
val speakerId: String?, // identification locuteur
val emotion: String?, // émotion détectée
val sessionId: String // identifiant session
)
Les processeurs peuvent lire et écrire dans metadata pour communiquer entre eux.
Performances actuelles
| Composant | Backend | Latence |
|---|---|---|
| STT Whisper | CPU (whisper.cpp) | 1500ms |
| STT Whisper | NPU (ExecuTorch) | ~50ms* |
| LLM Qwen3-0.6B | NPU (ExecuTorch) | 93 tok/s, TTFT 31ms |
| LLM Qwen3-1.7B | NPU (ExecuTorch) | 46 tok/s, TTFT 27ms |
| TTS Android | 200ms | |
| Pipeline total (CPU STT) | STT→LLM→TTS | ~3-7s |
| Pipeline total (NPU STT)* | STT→LLM→TTS | ~1-3s |
*STT NPU en cours d'intégration
Fichiers
kazeia-android/app/src/main/java/com/kazeia/
├── core/
│ ├── LlmEngine.kt # Interface LLM
│ ├── SttEngine.kt # Interface STT
│ ├── TtsEngine.kt # Interface TTS
│ ├── VadEngine.kt # Interface VAD
│ ├── ConversationState.kt # États pipeline
│ └── Pipeline.kt # Interfaces MessageProcessor, PipelineOrchestrator
├── llm/
│ ├── ExecuTorchLlmEngine.kt # LLM sur NPU via ExecuTorch
│ └── GenieLlmEngine.kt # LLM via Genie SDK (abandonné)
├── stt/
│ ├── WhisperSttEngine.kt # STT CPU via whisper.cpp
│ ├── WhisperNpuSttEngine.kt # STT NPU via ExecuTorch
│ └── AndroidSttEngine.kt # STT cloud via Google
├── tts/
│ ├── AndroidTtsEngine.kt # TTS Google natif
│ └── ChatterboxTtsEngine.kt # TTS avec clonage voix
├── conversation/
│ ├── LlmProcessor.kt # Processor LLM
│ ├── EchoProcessor.kt # Processor écho
│ ├── VoiceCommandProcessor.kt # Commandes vocales (config JSON)
│ ├── VoiceCommandProcessor2.kt # Adapter MessageProcessor
│ ├── PromptBuilder.kt # Construction prompts
│ └── StoppingCriteria.kt # Critères d'arrêt
├── service/
│ ├── KazeiaService.kt # Service Android foreground
│ └── KazeiaPipeline.kt # Orchestrateur pipeline modulaire
└── ui/
├── ChatActivity.kt # Interface utilisateur
├── ChatAdapter.kt # Adapter RecyclerView
├── MiniGraphView.kt # Graphe temps réel
└── ResourceMonitor.kt # Monitoring CPU/GPU/RAM
Projet Kazeia — Damien Micottis & Richard Loyer