# 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<br/>« Asa » / « Asa stop »"]
        VAD --> ASR["ASR local<br/>whisper / Parakeet (onnx)"]
        ASR --> API["api.py → ServerClient"]
        REPLY["Réponse"] --> TTS["TTS Piper"]
        REPLY --> HUD["HUD web<br/>bulles, portrait, portail"]
    end

    subgraph CLUSTER["Cluster k8s — namespace ai"]
        SRV["STT-server (FastAPI)<br/>stt.lab.local"]
        SRV --> LOOP["brain.ask_with_tools<br/>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<br/>storage-01"]
    LITELLM --> QWEN["Qwen3-8B<br/>gpu-01 :1234"]

    TOOLS -->|"host_health / cluster_status / prometheus_query"| PROM["Prometheus<br/>in-cluster"]
    TOOLS -->|"search_docs"| QDRANT["Qdrant RAG<br/>funk-docs (s01)"]
    TOOLS -->|"web_search"| SEARX["SearXNG<br/>in-cluster, privé"]
    TOOLS -->|"admin_action ⇒ confirmation"| HEXEC["hermes-exec :9096<br/>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

> 🗣️ **Liste complète des demandes possibles (exemples de phrases)** : [`asa-commandes.md`](asa-commandes.md).

| 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.
