diff --git a/README.md b/README.md index 0c79749..fe522d7 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,8 @@ L'ensemble est géré en Infrastructure-as-Code : **Ansible** pour les hôtes AlmaLinux, **talhelper** pour Talos, **ArgoCD** pour les workloads Kubernetes. +L'interface du homelab est **Asa**, un assistant **vocal agentique** (STT client‑serveur) qui sait interroger l'état live, chercher sur le web et agir sur l'infra — voir [Asa (STT)](#asa--assistant-vocal-agentique-stt). + --- ## Architecture @@ -102,6 +104,30 @@ L'ensemble est géré en Infrastructure-as-Code : **Ansible** pour les hôtes Al --- +## Asa — assistant vocal agentique (STT) + +**Asa** est l'interface **vocale et graphique** de Funk : un assistant type *Jarvis* qui écoute, +parle et affiche un **HUD** animé. Architecture **client‑serveur** — un client `stt` (pipx) sur le +poste (voix + HUD), un **STT‑server in‑cluster** (le « cerveau »). 100 % local (Qwen3‑8B). + +![Asa — HUD](docs/img/stt-hud-conversation.png) + +Au‑delà du chat, Asa est une véritable **agente** : le modèle **choisit ses outils** (function +calling) pour répondre à partir de données réelles. + +| Capacité | Détail | +|---|---| +| 🔎 **Savoir** | doc Funk (RAG) + **état live** (santé machines/GPU, cluster, PromQL) | +| 🌐 **Chercher** | recherche Internet **privée** (SearXNG self‑host) | +| 🤖 **Agir** | actions d'admin via Hermes, **toujours derrière une confirmation vocale** | +| 🧠 **Mémoire** | court terme (session) + long terme (Qdrant `stt-memory`) | +| 🗣️ **Veille/réveil** | « Asa » réveille · « Asa stop » endort | + +📖 **Présentation complète (schémas de la chaîne + captures)** : [`docs/stt-presentation.md`](docs/stt-presentation.md) +· Détails techniques : [`admin/ia/stt.md`](admin/ia/stt.md) + +--- + ## Infrastructure ### Machines @@ -159,14 +185,17 @@ L'ensemble est géré en Infrastructure-as-Code : **Ansible** pour les hôtes Al ├── tools/ # Sources des outils déployés │ ├── hermes-auto-improve/ # auto-improve.py + trigger-server.py │ └── hermes-voice/ # Client vocal Hermes (CLI faster-whisper + Piper) -├── stt/ # Assistant vocal « Jarvis » — client `stt` (pipx) + STT-server (conteneur) +├── stt/ # Asa — assistant vocal agentique (voir docs/stt-presentation.md) +│ ├── client/ # commande `stt` (pipx) : voix (VAD/wake/ASR/TTS) + HUD web +│ └── server/ # STT-server (conteneur, ns ai) : brain + tools + RAG + mémoire ├── admin/ # Base de connaissance (indexée dans le RAG) +├── docs/ # Présentations & schémas (stt-presentation.md, images) ├── progress/ # Journaux de session (référencés par PROGRESS.md) ├── archive/ # Documents historiques obsolètes (conception d'origine) — ne fait pas foi ├── talos/ # Cluster Kubernetes (talhelper) └── k8s/ # Workloads ArgoCD ├── infra/ # monitoring, nfs-provisioner (Traefik + MetalLB via helm au bootstrap) - └── apps/ # Open WebUI, n8n, STT, Ghostfolio, external-services + └── apps/ # Open WebUI, n8n, STT, SearXNG, Ghostfolio, external-services ``` --- diff --git a/docs/img/stt-hud-asleep.png b/docs/img/stt-hud-asleep.png new file mode 100644 index 0000000..9beab07 Binary files /dev/null and b/docs/img/stt-hud-asleep.png differ diff --git a/docs/img/stt-hud-conversation.png b/docs/img/stt-hud-conversation.png new file mode 100644 index 0000000..3abb459 Binary files /dev/null and b/docs/img/stt-hud-conversation.png differ diff --git a/docs/stt-presentation.md b/docs/stt-presentation.md new file mode 100644 index 0000000..ca8c77e --- /dev/null +++ b/docs/stt-presentation.md @@ -0,0 +1,140 @@ +# Asa — l'assistant vocal de Funk (STT client‑serveur) + +**Asa** est l'interface vocale et graphique du homelab **Funk** : un assistant type *Jarvis* qui +**écoute**, **parle**, affiche un **HUD** animé, et — surtout — agit comme une véritable **agente** +sur le homelab. Elle **sait** (doc + état live), **cherche** (web) et **agit** (avec confirmation). + +Architecture **client‑serveur** : un client `stt` (pipx) tourne sur le poste (voix + HUD) ; le +« cerveau » est un **STT‑server** déployé *dans le cluster* (namespace `ai`, exposé `stt.lab.local`). + +| | | +|---|---| +| **Code** | client `stt/client/` · serveur `stt/server/` | +| **Déploiement** | client : `pipx` + service systemd `--user` · serveur : image GHCR → ArgoCD | +| **Modèle** | 100 % local — Qwen3‑8B via LiteLLM (`function calling` natif) | +| **Doc de référence** | [`admin/ia/stt.md`](../admin/ia/stt.md) | + +--- + +## Le HUD en images + +| Conversation (Asa agentique) | Veille / réveil vocal | +|---|---| +| ![HUD — conversation](img/stt-hud-conversation.png) | ![HUD — veille](img/stt-hud-asleep.png) | +| Asa sonde l'état **live** (« gpu‑01 tourne bien ? » → CPU/RAM/disque/**GPU**) puis fait une **recherche web** — chaque réponse taguée `asa`. État **RÉPONSE** : anneau arc‑reactor actif. | « Asa, stop » → état **SOMMEIL** : portrait désaturé, Asa n'écoute plus que le mot de réveil. Dire « Asa » la rallume. | + +> Le portrait affiche le repli « あ » (Asa en hiragana) tant qu'aucun jeu d'avatars n'est déposé +> dans `stt/client/stt/hud/avatars/` (cf. son README). Thème *arc‑reactor*, réglable dans le HUD. + +--- + +## Architecture — la chaîne de bout en bout + +```mermaid +flowchart LR + subgraph POSTE["Poste perso — client stt (pipx)"] + MIC["Micro"] --> VAD["VAD + wake word
« Asa » / « Asa stop »"] + VAD --> ASR["ASR local
whisper / Parakeet (onnx)"] + ASR --> API["api.py → ServerClient"] + REPLY["Réponse"] --> TTS["TTS Piper"] + REPLY --> HUD["HUD web
bulles, portrait, portail"] + end + + subgraph CLUSTER["Cluster k8s — namespace ai"] + SRV["STT-server (FastAPI)
stt.lab.local"] + SRV --> LOOP["brain.ask_with_tools
function calling (contexte asa)"] + LOOP --> TOOLS["tools.py"] + end + + API -->|"POST /v1/ask"| SRV + SRV -->|"reply + trace"| REPLY + + LOOP -->|"inférence + tool_calls"| LITELLM["LiteLLM :4000
storage-01"] + LITELLM --> QWEN["Qwen3-8B
gpu-01 :1234"] + + TOOLS -->|"host_health / cluster_status / prometheus_query"| PROM["Prometheus
in-cluster"] + TOOLS -->|"search_docs"| QDRANT["Qdrant RAG
funk-docs (s01)"] + TOOLS -->|"web_search"| SEARX["SearXNG
in-cluster, privé"] + TOOLS -->|"admin_action ⇒ confirmation"| HEXEC["hermes-exec :9096
hermes -z --yolo (s01)"] + + classDef poste fill:#fde,stroke:#c69; + classDef cluster fill:#def,stroke:#69c; + class POSTE poste + class CLUSTER cluster +``` + +**Principe** : le poste ne fait que la **voix** (STT/TTS) et l'**affichage**. Toute l'intelligence +est côté serveur, qui orchestre LiteLLM et **choisit ses outils**. Aucune dépendance cloud : modèle, +recherche web et données sont tous **self‑host**. + +--- + +## Le tour d'une question vocale (séquence) + +```mermaid +sequenceDiagram + actor U as Utilisateur + participant C as Client stt (poste) + participant S as STT-server (cluster) + participant L as LiteLLM puis Qwen3-8B + participant T as Outils (Prom/SearXNG/RAG) + + U->>C: « Asa, est-ce que gpu-01 tourne bien ? » + Note over C: wake word détecté puis ASR (texte) + C->>S: POST /v1/ask {text, context:"asa"} + Note over S: recall mémoire (Qdrant) + assemblage prompt + S->>L: chat + tools (function calling) + L-->>S: tool_call host_health(gpu-01) + S->>T: PromQL (up, CPU, RAM, disque, GPU) + T-->>S: « en ligne, GPU 61 °C, 99 % » + S->>L: résultat de l'outil réinjecté + L-->>S: réponse finale en français + S-->>C: reply + trace des outils + C->>U: TTS Piper + bulle dans le HUD +``` + +Si Asa veut **agir** (`admin_action`), la boucle s'arrête et elle **propose** ; l'exécution +(`hermes‑exec`) n'a lieu qu'au tour suivant, après un **« confirme »** vocal. + +--- + +## Ce qu'Asa sait faire + +| Capacité | Comment | Outils / sources | +|---|---|---| +| 🔎 **Savoir** | Doc Funk + **état live** du homelab, l'outil est choisi par le modèle | `search_docs` (RAG), `host_health`, `cluster_status`, `prometheus_query` | +| 🌐 **Chercher** | Recherche Internet privée (méta‑moteur self‑host) | `web_search` → SearXNG | +| 🤖 **Agir** | Actions d'admin **avec confirmation vocale** + jeton | `admin_action` → `hermes‑exec` | +| 🧠 **Se souvenir** | Mémoire court terme (session) + long terme (Qdrant) | `stt-memory` | +| 🗣️ **Veille/réveil** | « Asa » réveille · « Asa stop » endort | machine à états côté client | +| 🧩 **Contextes** | Profils présélectionnables (funk, ghostfolio, grafana, alerting, cluster) | `contexts.py` | + +--- + +## Où vivent les choses + +``` +stt/ +├── client/ # commande `stt` (pipx) — poste perso +│ └── stt/ +│ ├── voice/engine.py # micro, VAD, wake word, ASR, TTS +│ ├── api.py # client HTTP vers le STT‑server +│ └── hud/index.html # le HUD (portrait, bulles, portail, visualiseur) +└── server/ # image conteneur — déployée par ArgoCD (ns ai) + └── stt_server/ + ├── app.py # API FastAPI (/v1/ask, /v1/contexts…) + ├── brain.py # appel LiteLLM + boucle de function‑calling + ├── tools.py # outils : doc, état live, web, action + ├── contexts.py # profils (dont « asa » = boucle d'outils) + ├── sources.py # sondes Prometheus / Alertmanager / Ghostfolio + ├── knowledge.py # RAG funk‑docs (Qdrant) + └── longterm.py # mémoire long terme (Qdrant) +``` + +Manifests k8s : [`k8s/apps/stt/`](../k8s/apps/stt) (STT‑server) et +[`k8s/apps/searxng/`](../k8s/apps/searxng) (recherche web). Détails et pièges : +[`admin/ia/stt.md`](../admin/ia/stt.md). + +> **Capturer ses propres écrans du HUD** : déposer un jeu d'avatars dans +> `stt/client/stt/hud/avatars/`, lancer le client, et capturer les états (idle, écoute, réponse, +> portail, visualiseur). Les deux images ci‑dessus ont été rendues depuis le HUD réel.