mirror of
https://github.com/Alkatrazz24/Funk-lab.git
synced 2026-07-09 09:44:41 +02:00
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
129 lines
4.2 KiB
Python
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())
|