mirror of
https://github.com/Alkatrazz24/Funk-lab.git
synced 2026-07-08 17:54:41 +02:00
feat(stt): auto-start via stt --install-service (phase 6)
Ajoute `stt --install-service` / `--uninstall-service` : génère et active un service systemd --user (lié à graphical-session.target) qui lance le HUD + voix à l'ouverture de session. Le kiosk existant (ui.kiosk) fournit l'« écran Jarvis ». - cli : _service_unit (génération du unit, fonction pure testable), _cmd_install_service (écrit le unit + import-environment DISPLAY/WAYLAND + daemon-reload/enable/start), _cmd_uninstall_service. - Docs : admin/ia/stt.md (phase 6 → ✅, section Auto-start + caveat DISPLAY), stt/README. - Bump client 0.2.1 → 0.3.0. Phase 6 de la roadmap STT. Reste : test sur poste, outils Hermes (7). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017Qjq5jHiqNepnobJpHYpCa
This commit is contained in:
parent
2658f92c2f
commit
d1bf20c86d
4 changed files with 131 additions and 9 deletions
|
|
@ -12,10 +12,11 @@ Objectif ultérieur : « agir sur le homelab » via les outils de Hermes (phase
|
|||
> ✅ **2026-06-17** — déployé in-cluster (ArgoCD), mémoire court-terme (5a) + long-terme (5b)
|
||||
> **validées sur cible**, embeddings dédiés nomic `:1238` (5d) + fix thinking Qwen3 `/no_think`
|
||||
> (5e).
|
||||
> ✅ **2026-06-18** — HUD avancé (4) implémenté (design **Claude Design**) : avatar portrait
|
||||
> réactif (anneau/ping/spinner), transcript à bulles, drawer Réglages **câblé au backend**
|
||||
> (reset / mode cerveau / mot de réveil à chaud). Reste : test audio bout-en-bout sur le poste
|
||||
> (phase 1), portraits réels + test HUD sur cible, auto-start (6), outils Hermes (7).
|
||||
> ✅ **2026-06-18** — HUD avancé (4) + auto-start (6). HUD : design **Claude Design** (avatar
|
||||
> portrait réactif, transcript à bulles, drawer Réglages **câblé au backend** : reset / mode
|
||||
> cerveau / mot de réveil à chaud). Auto-start : `stt --install-service` (systemd --user,
|
||||
> `graphical-session.target`). Reste : test audio bout-en-bout (phase 1), portraits réels +
|
||||
> test sur cible, outils Hermes (7).
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -29,7 +30,7 @@ Objectif ultérieur : « agir sur le homelab » via les outils de Hermes (phase
|
|||
| 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é |
|
||||
| Démarrage auto au boot | `stt --install-service` (systemd --user) — repris du pattern `tools/hermes-voice/` | ✅ |
|
||||
| Mémoire sémantique | Qdrant `:6333` + RAG (`rag-query`/`rag-ingest`) sur s01 | ✅ Qdrant réparé 17/06 (RAG `funk-docs` à re-ingérer) |
|
||||
|
||||
Maillon réellement manquant : **l'interface graphique HUD** + le packaging + la mémoire perso.
|
||||
|
|
@ -157,6 +158,30 @@ Côté client, pilotable depuis `stt/client/config/` + l'écran de réglages du
|
|||
|
||||
---
|
||||
|
||||
## Auto-start (service systemd --user)
|
||||
|
||||
Lancer le HUD + voix automatiquement à l'ouverture de session (écran « Jarvis ») :
|
||||
|
||||
```bash
|
||||
stt --install-service # écrit ~/.config/systemd/user/stt.service, enable + start
|
||||
stt --uninstall-service # retire le service
|
||||
```
|
||||
|
||||
Le unit est lié à `graphical-session.target` (démarre avec la session graphique, s'arrête avec).
|
||||
Suivi : `systemctl --user status|restart stt`, `journalctl --user -u stt -f`.
|
||||
|
||||
**Caveat DISPLAY** : un service `systemd --user` n'hérite de `DISPLAY`/`WAYLAND_DISPLAY` que si la
|
||||
session graphique les a importés dans le gestionnaire user. `--install-service` exécute un
|
||||
`systemctl --user import-environment DISPLAY WAYLAND_DISPLAY XAUTHORITY` (best-effort). Si le kiosk
|
||||
ne s'ouvre pas : vérifier que le bureau peuple `graphical-session.target` (GNOME/KDE le font), ou
|
||||
lancer `stt` via les « applications au démarrage » du bureau. Le kiosk est piloté par `[ui].kiosk`
|
||||
(défaut `true`).
|
||||
|
||||
**Boot sans login** (borne dédiée) : `sudo loginctl enable-linger "$USER"` + auto-login du bureau —
|
||||
la session graphique démarre au boot et tire le service.
|
||||
|
||||
---
|
||||
|
||||
## Roadmap
|
||||
|
||||
| Phase | Objectif | État |
|
||||
|
|
@ -171,7 +196,7 @@ Côté client, pilotable depuis `stt/client/config/` + l'écran de réglages du
|
|||
| **5c — Réparation Qdrant** | drop `funk-docs` corrompu + restart (s01) | ✅ (17/06) |
|
||||
| **5d — Embeddings dédiés** | `nomic-embed-text` (dim 768) sur gpu-01 `:1238` → recherche plus précise | ✅ (rôle llama_server + migration auto collection) |
|
||||
| **5e — Fix thinking Qwen3** | `/no_think` (content vide / timeout 502) + fallback reasoning_content | ✅ (17/06) |
|
||||
| **6 — Auto-start client** | `install-service.sh` (systemd --user) + kiosk | ⏳ |
|
||||
| **6 — Auto-start client** | `stt --install-service` (systemd --user, `graphical-session.target`) + kiosk | ✅ (à tester sur poste) |
|
||||
| **7 — Outils Hermes** | « agir sur Funk » via gateway `:8080` (API à spécifier) | ⏳ |
|
||||
|
||||
### État (validé sur cible)
|
||||
|
|
@ -179,8 +204,9 @@ Côté client, pilotable depuis `stt/client/config/` + l'écran de réglages du
|
|||
Serveur déployé in-cluster via ArgoCD (image `sha-<commit>` gérée par CI). Mémoire **5a + 5b
|
||||
validées en prod** : court-terme (historique de session) et long-terme (rappel cross-session
|
||||
« Felix », `points_count` confirmé via `/v1/memory/health`). HUD avancé (4) **implémenté**
|
||||
(design Claude Design, câblé au websocket backend). Reste côté poste : test audio bout-en-bout
|
||||
(micro → STT → serveur → TTS) et test du HUD avec portraits réels.
|
||||
(design Claude Design, câblé au websocket backend) ; auto-start (6) via `stt --install-service`.
|
||||
Reste côté poste : test audio bout-en-bout (micro → STT → serveur → TTS) et test du HUD/kiosk
|
||||
avec portraits réels.
|
||||
|
||||
---
|
||||
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ stt --setup # génère ~/.config/stt/stt.toml (dont [server] url)
|
|||
stt --text # chat texte simple (sans micro ni HUD) — idéal pour tester
|
||||
stt # voix + HUD ; dis "Ok Hermès …"
|
||||
stt --model claude # choisir le modèle : hermes (défaut) | claude | qwen | opus
|
||||
stt --install-service # auto-start au login (systemd --user, kiosk « écran Jarvis »)
|
||||
```
|
||||
En mode texte : commandes `/model <nom>`, `/models`, `/quit`.
|
||||
Prérequis voix : micro, Piper + voix dans `~/.local/share/piper/`, `aplay` (alsa-utils).
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
[project]
|
||||
name = "stt"
|
||||
version = "0.2.1"
|
||||
version = "0.3.0"
|
||||
description = "STT — client vocal Jarvis du homelab Funk (voix + HUD, parle au STT-server)"
|
||||
requires-python = ">=3.11"
|
||||
readme = "README.md"
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ from __future__ import annotations
|
|||
|
||||
import argparse
|
||||
import asyncio
|
||||
import os
|
||||
import sys
|
||||
|
||||
|
||||
|
|
@ -22,6 +23,92 @@ def _cmd_setup() -> int:
|
|||
return 0
|
||||
|
||||
|
||||
SERVICE_NAME = "stt.service"
|
||||
|
||||
|
||||
def _service_unit(stt_bin: str) -> str:
|
||||
"""Contenu du unit systemd --user : lance `stt` (HUD + voix) avec la session graphique."""
|
||||
return f"""[Unit]
|
||||
Description=STT — Assistant vocal Jarvis (HUD + voix)
|
||||
After=graphical-session.target
|
||||
PartOf=graphical-session.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
ExecStart={stt_bin}
|
||||
Restart=on-failure
|
||||
RestartSec=5
|
||||
Environment=PYTHONUNBUFFERED=1
|
||||
StandardOutput=journal
|
||||
StandardError=journal
|
||||
SyslogIdentifier=stt
|
||||
|
||||
[Install]
|
||||
WantedBy=graphical-session.target
|
||||
"""
|
||||
|
||||
|
||||
def _cmd_install_service() -> int:
|
||||
"""Installe et démarre le service systemd --user (auto-start au login + kiosk)."""
|
||||
import shutil
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
|
||||
stt_bin = shutil.which("stt") or os.path.realpath(sys.argv[0])
|
||||
unit_dir = Path.home() / ".config" / "systemd" / "user"
|
||||
unit_dir.mkdir(parents=True, exist_ok=True)
|
||||
unit_path = unit_dir / SERVICE_NAME
|
||||
unit_path.write_text(_service_unit(stt_bin))
|
||||
print(f"✓ Unit écrit : {unit_path}")
|
||||
print(f" ExecStart = {stt_bin}")
|
||||
|
||||
def sc(*args):
|
||||
subprocess.run(["systemctl", "--user", *args], check=False)
|
||||
|
||||
# Rendre DISPLAY/WAYLAND dispo au gestionnaire systemd --user (pour le kiosk)
|
||||
subprocess.run(
|
||||
["systemctl", "--user", "import-environment",
|
||||
"DISPLAY", "WAYLAND_DISPLAY", "XAUTHORITY"],
|
||||
check=False,
|
||||
)
|
||||
sc("daemon-reload")
|
||||
sc("enable", SERVICE_NAME)
|
||||
sc("start", SERVICE_NAME)
|
||||
|
||||
print("\n✓ Service activé et démarré (systemd --user).")
|
||||
print("\nCommandes utiles :")
|
||||
print(" systemctl --user status stt")
|
||||
print(" journalctl --user -u stt -f")
|
||||
print(" systemctl --user restart stt")
|
||||
print(" stt --uninstall-service")
|
||||
print("\nDémarrer dès le boot (kiosk dédié, sans login manuel) :")
|
||||
print(' sudo loginctl enable-linger "$USER" # + auto-login du bureau')
|
||||
print("\nLe HUD s'ouvre en kiosk si [ui].kiosk = true (défaut).")
|
||||
print("Si l'écran ne s'ouvre pas : voir le caveat DISPLAY dans admin/ia/stt.md.")
|
||||
return 0
|
||||
|
||||
|
||||
def _cmd_uninstall_service() -> int:
|
||||
"""Arrête, désactive et supprime le service systemd --user."""
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
|
||||
def sc(*args):
|
||||
subprocess.run(["systemctl", "--user", *args], check=False)
|
||||
|
||||
sc("stop", SERVICE_NAME)
|
||||
sc("disable", SERVICE_NAME)
|
||||
unit_path = Path.home() / ".config" / "systemd" / "user" / SERVICE_NAME
|
||||
if unit_path.exists():
|
||||
unit_path.unlink()
|
||||
print(f"✓ Unit supprimé : {unit_path}")
|
||||
else:
|
||||
print("(unit déjà absent)")
|
||||
sc("daemon-reload")
|
||||
print("✓ Service STT désinstallé.")
|
||||
return 0
|
||||
|
||||
|
||||
def _make_client(args):
|
||||
from stt.api import ServerClient
|
||||
from stt.config import load_config, resolve_model
|
||||
|
|
@ -116,10 +203,18 @@ def main(argv: list[str] | None = None) -> int:
|
|||
p.add_argument("--model", help="Modèle : hermes, claude, qwen, opus (ou alias LiteLLM)")
|
||||
p.add_argument("--server", help="Force l'URL du STT-server (sinon config)")
|
||||
p.add_argument("--no-tts", action="store_true", help="Réponses texte seulement (voix)")
|
||||
p.add_argument("--install-service", action="store_true",
|
||||
help="Installe le service systemd --user (auto-start au login + kiosk)")
|
||||
p.add_argument("--uninstall-service", action="store_true",
|
||||
help="Désinstalle le service systemd --user")
|
||||
args = p.parse_args(argv)
|
||||
|
||||
if args.setup:
|
||||
return _cmd_setup()
|
||||
if args.install_service:
|
||||
return _cmd_install_service()
|
||||
if args.uninstall_service:
|
||||
return _cmd_uninstall_service()
|
||||
if args.text:
|
||||
return _cmd_text(args)
|
||||
return _cmd_voice(args)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue