Add gitignor
This commit is contained in:
100
assistant/profile.py
Normal file
100
assistant/profile.py
Normal file
@@ -0,0 +1,100 @@
|
||||
"""
|
||||
Gestion des profils de personnalité pour l'assistant.
|
||||
|
||||
Chaque profil est un fichier YAML dans le dossier profiles/ contenant :
|
||||
- name : nom affiché
|
||||
- description : courte description
|
||||
- system_prompt : prompt système (obligatoire)
|
||||
- documents : liste de fichiers texte/markdown à injecter dans le contexte (optionnel)
|
||||
- voice_language : surcharge de VOICE_LANGUAGE (optionnel)
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass, field
|
||||
from pathlib import Path
|
||||
|
||||
import yaml
|
||||
|
||||
PROFILES_DIR = Path(__file__).parent.parent / "profiles"
|
||||
|
||||
|
||||
@dataclass
|
||||
class Profile:
|
||||
name: str
|
||||
system_prompt: str
|
||||
description: str = ""
|
||||
documents: list[str] = field(default_factory=list)
|
||||
voice_language: str | None = None
|
||||
mcp_servers: list[dict] = field(default_factory=list)
|
||||
|
||||
def build_system_prompt(self) -> str:
|
||||
"""Retourne le prompt système enrichi des documents de contexte."""
|
||||
parts = [self.system_prompt.strip()]
|
||||
|
||||
for doc_path in self.documents:
|
||||
full_path = PROFILES_DIR / doc_path
|
||||
if full_path.exists():
|
||||
content = full_path.read_text(encoding="utf-8").strip()
|
||||
parts.append(
|
||||
f"\n---\n## Contexte : {full_path.stem}\n\n{content}"
|
||||
)
|
||||
else:
|
||||
print(f"[Profile] Document introuvable : {full_path}")
|
||||
|
||||
return "\n".join(parts)
|
||||
|
||||
|
||||
def list_profiles() -> list[tuple[str, str, str]]:
|
||||
"""Retourne [(slug, name, description), ...] pour tous les profils disponibles."""
|
||||
results = []
|
||||
for yaml_file in sorted(PROFILES_DIR.glob("*.yaml")):
|
||||
slug = yaml_file.stem
|
||||
try:
|
||||
data = yaml.safe_load(yaml_file.read_text(encoding="utf-8"))
|
||||
results.append((slug, data.get("name", slug), data.get("description", "")))
|
||||
except Exception as e:
|
||||
print(f"[Profile] Erreur lecture {yaml_file.name} : {e}")
|
||||
return results
|
||||
|
||||
|
||||
def load_profile(slug: str) -> Profile:
|
||||
"""Charge un profil par son slug (nom de fichier sans extension)."""
|
||||
yaml_file = PROFILES_DIR / f"{slug}.yaml"
|
||||
if not yaml_file.exists():
|
||||
raise FileNotFoundError(f"Profil introuvable : {slug} (cherché dans {PROFILES_DIR})")
|
||||
|
||||
data = yaml.safe_load(yaml_file.read_text(encoding="utf-8"))
|
||||
|
||||
return Profile(
|
||||
name=data.get("name", slug),
|
||||
description=data.get("description", ""),
|
||||
system_prompt=data.get("system_prompt", ""),
|
||||
documents=data.get("documents", []),
|
||||
voice_language=data.get("voice_language"),
|
||||
mcp_servers=data.get("mcp_servers", []),
|
||||
)
|
||||
|
||||
|
||||
def apply_profile(slug: str) -> Profile:
|
||||
"""Charge un profil et l'applique à la configuration active."""
|
||||
from . import config, llm, mcp_client
|
||||
|
||||
profile = load_profile(slug)
|
||||
config.SYSTEM_PROMPT = profile.build_system_prompt()
|
||||
|
||||
if profile.voice_language:
|
||||
config.VOICE_LANGUAGE = profile.voice_language
|
||||
|
||||
import assistant.tts as tts
|
||||
tts._default_voice_id = None
|
||||
|
||||
llm.reset_history()
|
||||
|
||||
# Réinitialise les serveurs MCP et charge ceux du profil
|
||||
manager = mcp_client.reset_manager()
|
||||
if profile.mcp_servers:
|
||||
from .mcp_client import MCPServerConfig, get_manager
|
||||
configs = [MCPServerConfig(**s) for s in profile.mcp_servers]
|
||||
get_manager().load_servers(configs)
|
||||
|
||||
return profile
|
||||
Reference in New Issue
Block a user