Funk-lab/stt/client/stt/cli.py
Claude 08529b825a
feat(stt): HUD avancé — design Claude Design câblé au backend
Remplace le HUD minimal (cercle CSS) par le design Claude Design : avatar
portrait réactif (anneau + ping d'écoute + spinner de réflexion), transcript
à bulles (tag modèle), indicateur de connexion + reconnexion auto, et un
drawer Réglages.

- HUD (stt/hud/index.html) : HTML/CSS/JS sans dépendance externe, DEMO=false
  branché sur le websocket existant (états idle/listening/thinking/speaking,
  user/assistant/error). Portraits chargés depuis hud/avatars/ (repli « あ »
  si absent — voir avatars/README.md).
- Backend (ui/app.py) : le HUD renvoie {"type":"settings",...} ; le serveur
  applique à chaud reset / mode cerveau (modèle LiteLLM) / mot de réveil via
  _apply_settings (best-effort, non bloquant).
- engine/cli : tag du modèle courant ajouté aux réponses (events assistant).
- Docs : hud/README + avatars/README + admin/ia/stt.md (phase 4 ) + config.

Phase 4 de la roadmap STT. Reste : test sur poste + portraits réels.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017Qjq5jHiqNepnobJpHYpCa
2026-06-18 19:41:15 +00:00

129 lines
4.2 KiB
Python

"""Entrypoint de la commande `stt` (client)."""
from __future__ import annotations
import argparse
import asyncio
import sys
def _cmd_setup() -> int:
from stt.config import MODEL_PRESETS, write_default_config
path = write_default_config()
print(f"✓ Config : {path}")
print("\nUtilisation :")
print(" stt --text # chat texte simple (sans micro ni HUD)")
print(" stt # voix + HUD")
print(f" stt --model claude # modèles : {', '.join(MODEL_PRESETS)}")
print("\nÀ configurer si besoin :")
print(f" • URL du STT-server dans {path} ([server] url)")
print(" • Pour la voix : Piper + voix → ~/.local/share/piper/<voix>.onnx")
return 0
def _make_client(args):
from stt.api import ServerClient
from stt.config import load_config, resolve_model
cfg = load_config()
if args.server:
cfg["server"]["url"] = args.server
client = ServerClient(cfg["server"])
if args.model:
client.model = resolve_model(args.model)
return cfg, client
def _cmd_text(args) -> int:
"""Chat texte simple : tape, le serveur répond. Pas de micro ni HUD."""
_, client = _make_client(args)
print(f"STT (texte) — serveur {client.url} — modèle '{client.model}'")
if not client.healthy():
print(" ⚠️ serveur injoignable — vérifie [server] url et le réseau")
print(" commandes : /model <nom>, /models, /reset, /quit\n")
from stt.config import resolve_model
while True:
try:
line = input("vous> ").strip()
except (EOFError, KeyboardInterrupt):
print("\n👋")
return 0
if not line:
continue
if line in ("/quit", "/exit", "/q"):
return 0
if line == "/reset":
client.reset()
print(" → mémoire de session effacée\n")
continue
if line == "/models":
try:
m = client.models()
print(f" défaut: {m['default']} — dispo: {', '.join(m['available'])}\n")
except Exception as e: # noqa: BLE001
print(f"{e}\n")
continue
if line.startswith("/model "):
client.model = resolve_model(line.split(maxsplit=1)[1].strip())
print(f" → modèle : {client.model}\n")
continue
try:
reply = client.ask(line)
except Exception as e: # noqa: BLE001
print(f"{e}\n")
continue
print(f"hermes [{client.model}]> {reply}\n")
def _cmd_voice(args) -> int:
from stt.config import load_config # noqa: F401 (cfg via _make_client)
from stt.memory import LocalMemory
from stt.ui import serve
from stt.voice import VoiceEngine
cfg, client = _make_client(args)
print(f"STT-server : {client.url} — modèle '{client.model}'")
if not client.healthy():
print(" ⚠️ serveur injoignable — vérifie [server] url et le réseau")
memory = None
if cfg["memory"].get("enabled"):
memory = LocalMemory(cfg["memory"]["local_db"])
def make_engine(emit):
return VoiceEngine(
cfg["voice"], client.ask, emit, memory=memory, no_tts=args.no_tts,
model_label=lambda: client.model,
)
try:
asyncio.run(serve(cfg, make_engine, client))
except KeyboardInterrupt:
print("\n👋 Au revoir")
finally:
if memory:
memory.close()
return 0
def main(argv: list[str] | None = None) -> int:
p = argparse.ArgumentParser(prog="stt", description="Client vocal Jarvis de Funk")
p.add_argument("--setup", action="store_true", help="Écrit la config par défaut")
p.add_argument("--text", action="store_true", help="Mode chat texte (sans micro ni HUD)")
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)")
args = p.parse_args(argv)
if args.setup:
return _cmd_setup()
if args.text:
return _cmd_text(args)
return _cmd_voice(args)
if __name__ == "__main__":
sys.exit(main())