Add gitignor
This commit is contained in:
196
assistant/cli.py
Normal file
196
assistant/cli.py
Normal file
@@ -0,0 +1,196 @@
|
||||
import asyncio
|
||||
import sys
|
||||
from . import llm, tts, audio, config
|
||||
|
||||
|
||||
HELP_TEXT = """
|
||||
Commandes disponibles :
|
||||
exit / quit Quitter l'assistant
|
||||
reset Effacer l'historique de conversation
|
||||
voice <id> Changer la voix Voxtral (voice_id)
|
||||
voice clear Revenir à la voix par défaut
|
||||
mode texte Passer en mode saisie texte (défaut)
|
||||
mode vocal Passer en mode entrée microphone
|
||||
profiles Lister les profils de personnalité disponibles
|
||||
profile <slug> Charger un profil (ex: profile traveller_scout)
|
||||
mcp Lister les serveurs MCP connectés
|
||||
mcp tools Lister tous les outils MCP disponibles
|
||||
help Afficher ce message
|
||||
|
||||
Mode vocal : appuyez sur Entrée (sans rien écrire) pour commencer à parler,
|
||||
puis Entrée à nouveau pour envoyer.
|
||||
"""
|
||||
|
||||
|
||||
def _set_voice(parts: list[str]) -> None:
|
||||
if len(parts) < 2:
|
||||
print("Usage : voice <id> ou voice clear")
|
||||
return
|
||||
if parts[1] == "clear":
|
||||
config.VOICE_ID = None
|
||||
print("Voix réinitialisée (défaut).")
|
||||
else:
|
||||
config.VOICE_ID = parts[1]
|
||||
print(f"Voix définie sur : {config.VOICE_ID}")
|
||||
|
||||
|
||||
def _process_message(user_input: str) -> None:
|
||||
"""Envoie un message au LLM et lit la réponse à voix haute."""
|
||||
print(f"Arioch > ", end="", flush=True)
|
||||
try:
|
||||
reply = llm.chat(user_input)
|
||||
except Exception as e:
|
||||
print(f"\n[Erreur LLM] {e}")
|
||||
return
|
||||
|
||||
print(reply)
|
||||
|
||||
try:
|
||||
audio_bytes = tts.text_to_speech(reply)
|
||||
audio.play_audio(audio_bytes)
|
||||
except Exception as e:
|
||||
print(f"[Erreur TTS/Audio] {e}")
|
||||
|
||||
|
||||
def _handle_command(user_input: str) -> bool:
|
||||
"""Gère les commandes spéciales. Retourne True si c'était une commande."""
|
||||
from .profile import list_profiles, apply_profile
|
||||
|
||||
lower = user_input.lower()
|
||||
parts = user_input.split()
|
||||
|
||||
if lower in ("exit", "quit"):
|
||||
print("Au revoir !")
|
||||
sys.exit(0)
|
||||
elif lower == "reset":
|
||||
llm.reset_history()
|
||||
print("Historique effacé.\n")
|
||||
return True
|
||||
elif lower == "help":
|
||||
print(HELP_TEXT)
|
||||
return True
|
||||
elif lower.startswith("voice"):
|
||||
_set_voice(parts)
|
||||
return True
|
||||
elif lower in ("mode texte", "mode text"):
|
||||
return True # signal au caller
|
||||
elif lower in ("mode vocal", "mode voix", "mode voice"):
|
||||
return True # signal au caller
|
||||
elif lower == "profiles":
|
||||
_list_profiles(list_profiles())
|
||||
return True
|
||||
elif lower.startswith("mcp"):
|
||||
_handle_mcp(parts)
|
||||
return True
|
||||
elif lower.startswith("profile ") and len(parts) >= 2:
|
||||
_load_profile(parts[1], apply_profile)
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def _handle_mcp(parts: list[str]) -> None:
|
||||
from . import mcp_client
|
||||
manager = mcp_client.get_manager()
|
||||
servers = manager.summary()
|
||||
|
||||
if len(parts) >= 2 and parts[1] == "tools":
|
||||
tools = manager.get_mistral_tools()
|
||||
if not tools:
|
||||
print("Aucun outil MCP disponible.")
|
||||
return
|
||||
print(f"\n{len(tools)} outil(s) MCP disponible(s) :")
|
||||
for t in tools:
|
||||
fn = t["function"]
|
||||
desc = fn.get("description", "")
|
||||
print(f" {fn['name']:<45} {desc[:60]}")
|
||||
print()
|
||||
return
|
||||
|
||||
if not servers:
|
||||
print("Aucun serveur MCP connecté. Configurez 'mcp_servers' dans un profil YAML.\n")
|
||||
return
|
||||
|
||||
print("\nServeurs MCP connectés :")
|
||||
for name, count in servers:
|
||||
print(f" {name:<30} {count} outil(s)")
|
||||
total = sum(c for _, c in servers)
|
||||
print(f"\nTotal : {total} outil(s). Tapez 'mcp tools' pour les lister.\n")
|
||||
|
||||
|
||||
|
||||
if not profiles:
|
||||
print("Aucun profil disponible dans profiles/")
|
||||
return
|
||||
print("\nProfils disponibles :")
|
||||
for slug, name, desc in profiles:
|
||||
print(f" {slug:<25} {name}" + (f" — {desc}" if desc else ""))
|
||||
print("\nUsage : profile <slug>\n")
|
||||
|
||||
|
||||
def _load_profile(slug: str, apply_fn) -> None:
|
||||
try:
|
||||
profile = apply_fn(slug)
|
||||
print(f"✅ Profil chargé : {profile.name}")
|
||||
if profile.description:
|
||||
print(f" {profile.description}")
|
||||
print()
|
||||
except FileNotFoundError as e:
|
||||
print(f"[Profil] {e}")
|
||||
|
||||
|
||||
def run() -> None:
|
||||
print("🎙️ Arioch — Assistant vocal (Mistral Large + Voxtral)")
|
||||
print("Commandes : 'profiles' pour voir les personnalités, 'mode vocal' pour parler, 'help' pour l'aide.\n")
|
||||
|
||||
vocal_mode = False
|
||||
|
||||
while True:
|
||||
try:
|
||||
if vocal_mode:
|
||||
prompt = "🎤 [vocal] Entrée pour parler > "
|
||||
else:
|
||||
prompt = "Vous > "
|
||||
|
||||
user_input = input(prompt).strip()
|
||||
except (EOFError, KeyboardInterrupt):
|
||||
print("\nAu revoir !")
|
||||
sys.exit(0)
|
||||
|
||||
if not user_input:
|
||||
if vocal_mode:
|
||||
# Entrée vide en mode vocal → lancer la capture micro
|
||||
try:
|
||||
from .stt import transcribe_from_mic
|
||||
user_input = asyncio.run(transcribe_from_mic())
|
||||
except Exception as e:
|
||||
print(f"[Erreur STT] {e}")
|
||||
continue
|
||||
|
||||
if not user_input:
|
||||
print("(rien capturé)")
|
||||
continue
|
||||
|
||||
print(f"Vous (transcrit) : {user_input}")
|
||||
_process_message(user_input)
|
||||
continue
|
||||
|
||||
lower = user_input.lower()
|
||||
|
||||
# Changement de mode
|
||||
if lower in ("mode vocal", "mode voix", "mode voice"):
|
||||
vocal_mode = True
|
||||
print("Mode vocal activé. Appuyez sur Entrée (sans rien écrire) pour parler.\n")
|
||||
continue
|
||||
elif lower in ("mode texte", "mode text"):
|
||||
vocal_mode = False
|
||||
print("Mode texte activé.\n")
|
||||
continue
|
||||
|
||||
# Autres commandes
|
||||
if _handle_command(user_input):
|
||||
continue
|
||||
|
||||
# Message normal (texte)
|
||||
_process_message(user_input)
|
||||
|
||||
Reference in New Issue
Block a user