diff --git a/admin/ia/stt.md b/admin/ia/stt.md new file mode 100644 index 0000000..20e6af5 --- /dev/null +++ b/admin/ia/stt.md @@ -0,0 +1,167 @@ +# STT — Assistant vocal "Jarvis" du homelab Funk + +**STT** est l'interface vocale et graphique de Funk : un assistant type *Jarvis / Iron Man* +qui écoute, parle, affiche un HUD animé, et **agit sur le homelab** via Hermes Agent. +Il s'installe sur le poste perso comme **une commande unique** (`stt`) et démarre au boot. + +> **Nom de code** : `STT`. À l'origine « Speech-To-Text », mais le projet couvre toute la +> chaîne voix → cerveau → voix + interface + mémoire. Renommable plus tard sans impact +> technique (FRIDAY, etc.) — c'est juste un identifiant de répertoire/commande. + +> ⚠️ **Conception validée (2026-06-17)** — squelette en place, implémentation par phases +> (voir Roadmap). Aucun composant n'est encore déployé sur le poste. + +--- + +## Principe directeur : réutiliser, ne pas réinventer + +~70 % du backend existe déjà dans Funk. STT n'ajoute que **le visage** (HUD), la +**personnalisation**, la **mémoire multi-tiers** et le **packaging en commande**. + +| Besoin Jarvis | Brique Funk réutilisée | État | +|---|---|---| +| Modèle local **ou** Claude | LiteLLM `:4000` + `hermes-default` + `hermes-switch qwen\|claude` | ✅ opérationnel | +| Agir sur le homelab | Hermes Agent (`:8080`, profils funk-ai/system/monitor/brain) | ✅ opérationnel | +| Voix (STT + TTS + wake word) | `tools/hermes-voice/` — faster-whisper + Piper + webrtcvad | ✅ existe (CLI only) | +| Démarrage auto au boot | pattern `systemd --user` (`tools/hermes-voice/install-service.sh`) | ✅ éprouvé | +| Mémoire sémantique | Qdrant `:6333` + RAG (`rag-query`/`rag-ingest`) sur s01 | ⚠️ **HS depuis 05/06** | + +Maillon réellement manquant : **l'interface graphique HUD** + le packaging + la mémoire perso. + +--- + +## Décisions d'architecture (verrouillées 2026-06-17) + +| Décision | Choix retenu | +|---|---| +| Interface | **HUD web sur-mesure** (canvas/WebGL) + backend Python local | +| STT / TTS | **Local sur le poste** (faster-whisper CPU + Piper) | +| Packaging | **Commande `stt` via pipx** (`pipx install git+…#subdirectory=stt`) | +| Cerveau | **3 modes + auto-détection LAN** (voir ci-dessous) | +| Mémoire | **3 tiers** : local (SQLite) + s01 (Qdrant) + GitHub (distillée, versionnée) | + +--- + +## Architecture + +``` +┌─ POSTE PERSO — commande `stt` (systemd --user, démarrage auto) ─────┐ +│ │ +│ ┌──────────────┐ websocket ┌───────────────────────────┐ │ +│ │ HUD web │ ◀────────────▶ │ backend `stt` (Python) │ │ +│ │ (kiosk) │ états + │ • micro + VAD + wake word │ │ +│ │ • visualiseur│ transcript │ • faster-whisper (STT) │ │ +│ │ • avatar │ + réponses │ • Piper (TTS) │ │ +│ │ • thème │ │ • routeur cerveau (3 modes)│ │ +│ │ • réglages │ │ • gestionnaire mémoire │ │ +│ └──────────────┘ └───┬─────────────┬──────────┘ │ +│ │ │ │ +│ mémoire │ │ cerveau │ +│ ┌────────────────────┘ │ │ +│ ▼ ▼ │ +│ SQLite local + cache (selon mode + LAN) │ +│ git pull/push GitHub │ +└───────────────────────────────────────────────────┼─────────────────┘ + │ LAN (192.168.1.200) + ┌───────────────────────────────────┼──────────────────┐ + ▼ ▼ ▼ ▼ + Hermes :8080 LiteLLM :4000 Qdrant :6333 API Anthropic + (mode hermes) (mode local-direct) (mémoire s01) (mode claude-direct, + agit sur Funk chat g01/Claude sémantique hors-LAN, chat seul) +``` + +### Le cerveau — 3 modes + auto-détection + +Au démarrage (et périodiquement), `stt` ping s01 (`192.168.1.200`) : + +| Mode | Déclenché quand | Chemin | Agit sur Funk ? | Coût | +|---|---|---|---|---| +| **`hermes`** | LAN OK (défaut maison) | PC → Hermes `:8080` (route Qwen3 g01 ou Claude via `hermes-switch`) | ✅ oui | gratuit/local sauf si switch claude | +| **`local-direct`** | LAN OK, chat pur voulu | PC → LiteLLM `:4000` (Qwen3 g01) | ❌ chat seul | gratuit | +| **`claude-direct`** | hors-LAN (nomade) | PC → API Anthropic (clé locale) | ❌ (Funk injoignable) | facturé | + +> **Clé de lecture** : « agir sur Funk » vit dans Hermes (sur s01). À la maison, même pour +> l'intelligence de Claude, on passe par Hermes (`hermes-switch claude`) → pouvoirs Funk +> conservés. Le mode `claude-direct` est le fallback nomade (Funk inatteignable de toute façon). +> Auto-détection par défaut, **override manuel** dans les réglages. + +### La mémoire — 3 tiers + +| Tier | Support | Contenu | Disponibilité | +|---|---|---|---| +| **Local** | SQLite + cache (`stt/memory/` local, gitignoré) | Historique brut récent, working memory | Toujours (offline) | +| **s01** | Qdrant `:6333`, collection dédiée STT | Mémoire sémantique long-terme, partagée avec le RAG Funk | Sur LAN | +| **GitHub** | `stt/memory/distilled/` (versionné) | Mémoire **distillée** : faits, préférences, résumés — source de vérité portable | Via git pull/push | + +**Flux de synchro :** +1. Démarrage → `git pull` la mémoire distillée GitHub → charge en local. +2. Pendant l'usage → écriture immédiate en SQLite local. +3. Périodiquement / à l'arrêt → distillation (résumé via le cerveau) → `git commit` GitHub + **+** (si LAN) embedding dans Qdrant s01. +4. Sur nouveau poste / réinstall → GitHub re-seed local + Qdrant. + +> ⚠️ **Vie privée** : seule la mémoire **distillée** est committée (faits/préférences). +> Les transcripts bruts restent locaux et **gitignorés**. Repo privé impératif. + +--- + +## Composants + +| Composant | Emplacement | Description | +|---|---|---| +| Commande `stt` | `stt/pyproject.toml` → entrypoint | `stt` (lance), `stt --setup` (install Whisper/Piper/voix), `stt --stop`, `stt --mode ` | +| Backend | `stt/stt/` (package Python) | Extension de `tools/hermes-voice.py` : wake word, STT, TTS, routeur cerveau, mémoire, serveur websocket | +| HUD web | `stt/hud/` | Front statique (HTML/JS/canvas) : visualiseur animé, conversation, écran de réglages. Servi localement, ouvert en kiosk | +| Config | `stt/config/` | `stt.example.toml` + thèmes, avatars, voix Piper | +| Mémoire | `stt/memory/` | `distilled/` versionné + raw local gitignoré | +| Auto-start | `stt/install-service.sh` | `systemd --user` : backend + ouverture HUD au login | +| (opt.) cluster | `k8s/apps/stt/` | Phase 6 : STT/TTS déportés en Wyoming sur gpu-01 | + +--- + +## Personnalisation (« l'image, le design, la voix ») + +Pilotable depuis `stt/config/` + l'écran de réglages du HUD, sans recompiler : + +- **Avatar / image** : asset swappable (`config/avatars/`). +- **Thème / design** : couleurs, fond, style du visualiseur (`config/themes/`). +- **Voix** : modèle Piper `.onnx` interchangeable (`config/voices/`), fr_FR par défaut. +- **Wake word** : configurable (défaut « Ok Hermès »). +- **Cerveau** : mode par défaut + override, clé API Anthropic locale (pour `claude-direct`). + +--- + +## Prérequis / dépendances + +- **Poste** : micro, Python 3.11+, pipx, navigateur (kiosk). `stt --setup` gère Whisper/Piper/voix. +- **LAN** : accès `192.168.1.200` (s01) pour modes `hermes`/`local-direct` + Qdrant. +- **Qdrant réparé** requis pour la mémoire tier s01 (crash-loop depuis 05/06, voir + `admin/incidents.md`). **Non bloquant** : MVP fonctionne avec mémoire locale + GitHub seules. +- **Clé Anthropic** locale (poste) pour le mode `claude-direct` nomade. + +--- + +## Roadmap + +| Phase | Objectif | Livrable | +|---|---|---| +| **0 — Cadrage** | Conception validée | ✅ ce doc + squelette `stt/` | +| **1 — Commande + backend** | `stt`/`stt --setup` lancent le moteur vocal + websocket | `stt/pyproject.toml`, `stt/stt/` (hermes-voice + ws + états) | +| **2 — Routeur cerveau** | 3 modes + auto-détection LAN | module `brain` (hermes/local-direct/claude-direct) | +| **3 — HUD MVP** | Visualiseur + conversation à l'écran | `stt/hud/` relié au websocket | +| **4 — Mémoire 3 tiers** | local + GitHub (+ Qdrant si dispo) | module `memory` + sync git + distillation | +| **5 — Personnalisation** | Thèmes / avatar / voix / wake word | écran réglages + `stt/config/` | +| **6 — Auto-start** | Démarre au boot du poste | `install-service.sh` + kiosk | +| **7 — Cluster (opt.)** | STT/TTS sur GPU | Wyoming sur gpu-01 + `k8s/apps/stt/` | + +--- + +## Projets de référence (inspiration, non forkés) + +Aucun ne se branche proprement sur LiteLLM + Hermes (ils embarquent leur propre LLM/agent), +mais bons pour le design et le code à piocher : + +- [AlexandreSajus/JARVIS](https://github.com/AlexandreSajus/JARVIS) — Voice→LLM→Speech, interface web (proche du front visé). +- [InterGenJLU/jarvis](https://github.com/InterGenJLU/jarvis) — AMD ROCm (comme la RX 6700XT), HUD santé, streaming TTS. +- [novik133/jarvis](https://github.com/novik133/jarvis) — whisper.cpp + Piper (même TTS) + monitoring système. +- [rhasspy/wyoming-addons](https://github.com/rhasspy/wyoming-addons) — faster-whisper / Piper conteneurisés (option phase 7). diff --git a/stt/README.md b/stt/README.md new file mode 100644 index 0000000..1b8108b --- /dev/null +++ b/stt/README.md @@ -0,0 +1,57 @@ +# STT — Assistant vocal "Jarvis" de Funk + +Assistant vocal + HUD pour le poste perso, branché sur le homelab Funk. +Écoute (wake word « Ok Hermès »), parle (Piper), affiche un HUD animé, et **agit sur Funk** +via Hermes Agent — ou discute avec Claude directement en déplacement. + +> 📐 **Conception complète** : `admin/ia/stt.md`. Ce dossier est le squelette du projet ; +> l'implémentation se fait par phases (voir la Roadmap dans le doc de conception). + +## Installation (cible : poste perso) + +```bash +pipx install "git+https://github.com/Alkatrazz24/Funk-lab.git#subdirectory=stt" +stt --setup # télécharge le modèle Whisper, Piper et la voix fr_FR +stt # lance le backend + ouvre le HUD +``` + +## Commandes prévues + +| Commande | Effet | +|---|---| +| `stt` | Lance le backend vocal + ouvre le HUD en kiosk | +| `stt --setup` | Première install : Whisper, Piper, voix, config par défaut | +| `stt --mode hermes\|local\|claude` | Force le mode cerveau (sinon auto-détection LAN) | +| `stt --no-tts` | Réponses texte seulement (debug) | +| `stt --stop` | Arrête le service | + +## Structure + +``` +stt/ +├── pyproject.toml # définit la commande `stt` (entrypoint pipx) +├── stt/ # package Python — backend (à implémenter, phases 1-4) +│ ├── voice/ # wake word, STT (faster-whisper), TTS (Piper) +│ ├── brain/ # routeur 3 modes : hermes / local-direct / claude-direct +│ ├── memory/ # gestionnaire mémoire 3 tiers (local/s01/GitHub) +│ └── server/ # serveur websocket vers le HUD +├── hud/ # front web (HTML/JS/canvas) — phase 3 +├── config/ # stt.example.toml + thèmes / avatars / voix +├── memory/ # distilled/ (versionné) + raw local (gitignoré) +└── install-service.sh # systemd --user (démarrage auto) — phase 6 +``` + +## Cerveau — 3 modes + +Auto-détection au démarrage (ping s01 `192.168.1.200`) : +- **`hermes`** (LAN) → Hermes `:8080`, agit sur Funk. +- **`local-direct`** (LAN) → LiteLLM `:4000`, chat Qwen3 sur g01. +- **`claude-direct`** (hors-LAN) → API Anthropic, chat seul. + +## Mémoire — 3 tiers + +- **Local** : SQLite, historique brut, offline (gitignoré). +- **s01** : Qdrant `:6333`, sémantique long-terme (partagée RAG Funk, sur LAN). +- **GitHub** : `memory/distilled/`, mémoire distillée versionnée, portable. + +> ⚠️ Seule la mémoire distillée est committée. Transcripts bruts gitignorés. Repo privé. diff --git a/stt/config/README.md b/stt/config/README.md new file mode 100644 index 0000000..0bc2138 --- /dev/null +++ b/stt/config/README.md @@ -0,0 +1,25 @@ +# stt/config — personnalisation + +Tout ce qui se change **sans recompiler**. `stt --setup` copie `stt.example.toml` vers +`~/.config/stt/stt.toml`. + +``` +config/ +├── stt.example.toml # config de référence (modes cerveau, voix, thème, mémoire) +├── themes/ # thèmes HUD : couleurs, fond, style du visualiseur (CSS/JSON) +├── avatars/ # images / avatars affichés dans le HUD +└── voices/ # modèles Piper .onnx (TTS) — fr_FR par défaut +``` + +## Points de personnalisation + +| Quoi | Où | Note | +|---|---|---| +| Image / avatar | `avatars/` + `ui.avatar` | swappable à chaud | +| Thème / design | `themes/` + `ui.theme` | couleurs, fond, visualiseur | +| Voix | `voices/*.onnx` + `voice.piper_voice` | géré par `stt --setup` | +| Wake word | `voice.wake_word` | défaut « Ok Hermès » | +| Cerveau | `[brain]` | mode + override + endpoints | + +> 🔒 La clé Anthropic (mode `claude-direct`) passe par la variable d'env `ANTHROPIC_API_KEY`, +> **jamais** dans ce fichier (qui peut finir versionné). diff --git a/stt/config/stt.example.toml b/stt/config/stt.example.toml new file mode 100644 index 0000000..ea1e69d --- /dev/null +++ b/stt/config/stt.example.toml @@ -0,0 +1,40 @@ +# Configuration STT — copier vers ~/.config/stt/stt.toml (via `stt --setup`) + +[brain] +# Mode cerveau : "auto" (détecte le LAN), "hermes", "local", "claude" +mode = "auto" +# Hôte testé pour décider LAN vs hors-LAN +lan_probe_host = "192.168.1.200" + +[brain.hermes] # mode hermes (LAN) — agit sur Funk +url = "http://192.168.1.200:8080" +profile = "funk-ai" + +[brain.local] # mode local-direct (LAN) — chat Qwen3 sur g01 +url = "http://192.168.1.200:4000/v1/chat/completions" +api_key = "lm-studio" +model = "hermes-default" + +[brain.claude] # mode claude-direct (hors-LAN) — chat seul +# Clé via variable d'env ANTHROPIC_API_KEY (ne JAMAIS committer la clé ici) +model = "claude-sonnet-4-6" + +[voice] +wake_word = "hermes" # "Ok Hermès" +whisper_model = "large-v3" # STT (faster-whisper, CPU int8) +piper_voice = "fr_FR-upmc-medium" # TTS — voix dans config/voices/ +language = "fr" +silence_sec = 1.2 # silence avant fin d'enregistrement +chat_timeout_sec = 60 # retour en veille sans interaction + +[ui] +theme = "arc-reactor" # thème dans config/themes/ +avatar = "default" # image dans config/avatars/ +kiosk = true # ouvre le HUD en plein écran au lancement + +[memory] +enabled = true +local_db = "~/.local/share/stt/memory.sqlite" # tier local (gitignoré) +distill_on_exit = true # distille → GitHub à l'arrêt +qdrant_url = "http://192.168.1.200:6333" # tier s01 (si LAN + Qdrant up) +qdrant_collection = "stt-memory" diff --git a/stt/hud/README.md b/stt/hud/README.md new file mode 100644 index 0000000..553e4ad --- /dev/null +++ b/stt/hud/README.md @@ -0,0 +1,20 @@ +# stt/hud — interface HUD web (à implémenter, phase 3) + +Front statique servi localement par le backend, ouvert en kiosk (`ui.kiosk = true`). +Se connecte au serveur websocket du backend. + +## Contenu prévu + +- **Visualiseur** : canvas/WebGL animé (arc-reactor / waveform) réagissant aux états + `idle / listening / thinking / speaking`. +- **Conversation** : transcript utilisateur + réponses de l'assistant. +- **Réglages** : thème, avatar, voix, wake word, mode cerveau — écrit dans `~/.config/stt/stt.toml`. + +## Design + +S'inspire de [AlexandreSajus/JARVIS](https://github.com/AlexandreSajus/JARVIS) (interface web) +et de l'esthétique Iron Man. Thèmes pilotés par `stt/config/themes/`, avatar par +`stt/config/avatars/`. + +Pas de framework lourd imposé — HTML/JS + canvas suffit pour le MVP. Le choix (vanilla vs +petit framework) sera tranché en phase 3. diff --git a/stt/memory/.gitignore b/stt/memory/.gitignore new file mode 100644 index 0000000..6361353 --- /dev/null +++ b/stt/memory/.gitignore @@ -0,0 +1,5 @@ +# Mémoire brute — ne quitte jamais le poste +raw/ +*.sqlite +*.sqlite-* +*.db diff --git a/stt/memory/README.md b/stt/memory/README.md new file mode 100644 index 0000000..b4250e0 --- /dev/null +++ b/stt/memory/README.md @@ -0,0 +1,26 @@ +# stt/memory — mémoire 3 tiers + +``` +memory/ +├── distilled/ # mémoire DISTILLÉE — versionnée sur GitHub (faits, préférences, résumés) +└── raw/ # historique BRUT local — gitignoré, ne quitte jamais le poste +``` + +## Les 3 tiers + +| Tier | Support | Contenu | Versionné ? | +|---|---|---|---| +| **Local** | SQLite (`~/.local/share/stt/`) + `raw/` | Historique brut, working memory | ❌ gitignoré | +| **s01** | Qdrant `:6333` (collection `stt-memory`) | Sémantique long-terme, partagée RAG Funk | — (sur s01) | +| **GitHub** | `distilled/` | Faits, préférences, résumés distillés | ✅ committé | + +## Synchro + +1. **Démarrage** → `git pull` `distilled/` → charge en local. +2. **Usage** → écriture immédiate en SQLite local. +3. **Arrêt / périodique** → distillation (résumé via le cerveau) → `git commit` `distilled/` + **+** embedding dans Qdrant s01 (si LAN). +4. **Nouveau poste** → `distilled/` re-seed le local + Qdrant. + +> ⚠️ **Vie privée** : ne committer QUE de la mémoire distillée (pas de transcripts bruts). +> `raw/` et la SQLite sont gitignorés. Le repo doit rester privé. diff --git a/stt/memory/distilled/.gitkeep b/stt/memory/distilled/.gitkeep new file mode 100644 index 0000000..74b8f62 --- /dev/null +++ b/stt/memory/distilled/.gitkeep @@ -0,0 +1 @@ +# Mémoire distillée versionnée (faits, préférences, résumés). Rempli par le backend. diff --git a/stt/pyproject.toml b/stt/pyproject.toml new file mode 100644 index 0000000..ad8644e --- /dev/null +++ b/stt/pyproject.toml @@ -0,0 +1,30 @@ +[project] +name = "stt" +version = "0.0.1" +description = "STT — assistant vocal Jarvis du homelab Funk (voix + HUD + Hermes/Claude)" +requires-python = ">=3.11" +readme = "README.md" + +# Réutilise les dépendances éprouvées de tools/hermes-voice + ajouts STT +dependencies = [ + "faster-whisper>=1.0.0", # STT local + "sounddevice>=0.4.6", # capture micro + "numpy>=1.24.0", + "requests>=2.31.0", # appels Hermes / LiteLLM + "webrtcvad-wheels>=2.0.10",# VAD / wake word + "websockets>=12.0", # backend ↔ HUD + "anthropic>=0.40.0", # mode claude-direct (hors-LAN) + "qdrant-client>=1.13.0", # mémoire tier s01 + "tomli-w>=1.0.0", # écriture config TOML +] + +[project.scripts] +stt = "stt.cli:main" + +[build-system] +requires = ["setuptools>=68"] +build-backend = "setuptools.build_meta" + +[tool.setuptools.packages.find] +where = ["."] +include = ["stt*"] diff --git a/stt/stt/README.md b/stt/stt/README.md new file mode 100644 index 0000000..83d9a87 --- /dev/null +++ b/stt/stt/README.md @@ -0,0 +1,24 @@ +# stt/stt — package backend (à implémenter) + +Cœur Python de la commande `stt`. Réutilise le moteur vocal de `tools/hermes-voice.py`. + +``` +stt/ +├── cli.py # entrypoint `stt` (--setup, --mode, --no-tts, --stop) [phase 1] +├── voice/ # wake word + VAD, STT faster-whisper, TTS Piper [phase 1] +├── brain/ # routeur 3 modes : hermes / local-direct / claude-direct +│ # + auto-détection LAN (ping s01) [phase 2] +├── memory/ # mémoire 3 tiers : SQLite local, Qdrant s01, git GitHub [phase 4] +└── server/ # serveur websocket : pousse états + transcript + réponses au HUD [phase 1] +``` + +## États exposés au HUD (via websocket) + +`idle` (veille) → `listening` (écoute) → `thinking` (réflexion cerveau) → `speaking` (TTS) → `idle`. +Le HUD anime le visualiseur selon l'état et affiche transcript utilisateur + réponse. + +## Point de départ + +Le module `voice/` part de `tools/hermes-voice.py` (déjà fonctionnel : wake word « Ok Hermès », +faster-whisper, Piper, webrtcvad). À refactorer en classe + callbacks d'état pour le websocket, +puis brancher `brain/` (routeur) à la place de l'appel direct actuel.