mirror of
https://github.com/Ladebeze66/llm_lab.git
synced 2025-12-13 09:06:49 +01:00
modifatester
This commit is contained in:
parent
82c933bd5f
commit
bec848f5ac
113
agents/analyse_image.py
Normal file
113
agents/analyse_image.py
Normal file
@ -0,0 +1,113 @@
|
||||
import os
|
||||
import json
|
||||
from typing import Dict, List, Any, Optional
|
||||
from datetime import datetime
|
||||
|
||||
from agents.base_agent import Agent
|
||||
from core.factory import LLMFactory
|
||||
|
||||
class AgentAnalyseImage(Agent):
|
||||
"""
|
||||
Agent pour analyser des images avec LlamaVision
|
||||
"""
|
||||
def __init__(self, nom: str = "AgentAnalyseImage"):
|
||||
"""
|
||||
Initialisation de l'agent d'analyse d'image
|
||||
|
||||
Args:
|
||||
nom: Nom de l'agent
|
||||
"""
|
||||
super().__init__(nom)
|
||||
self.llm = LLMFactory.create("llamavision")
|
||||
self.questions_standard = [
|
||||
"Décris en détail ce que tu vois sur cette image.",
|
||||
"Quels sont les éléments principaux visibles sur cette image?",
|
||||
"Y a-t-il du texte visible sur cette image? Si oui, peux-tu le transcrire?",
|
||||
"Quelle est l'ambiance générale de cette image?"
|
||||
]
|
||||
|
||||
def executer(self, image_path: str, json_data: Optional[Dict[str, Any]] = None,
|
||||
question: Optional[str] = None) -> Dict[str, Any]:
|
||||
"""
|
||||
Analyse une image avec Llama Vision
|
||||
|
||||
Args:
|
||||
image_path: Chemin vers l'image à analyser
|
||||
json_data: Données JSON optionnelles associées à l'image
|
||||
question: Question à poser au modèle (si None, utilise les questions standard)
|
||||
|
||||
Returns:
|
||||
Résultats de l'analyse sous forme de dictionnaire
|
||||
"""
|
||||
# Vérification de l'existence de l'image
|
||||
if not os.path.exists(image_path):
|
||||
resultat = {"erreur": f"L'image {image_path} n'existe pas"}
|
||||
self.ajouter_historique("analyse_image_erreur", image_path, resultat)
|
||||
return resultat
|
||||
|
||||
# Chargement de l'image
|
||||
with open(image_path, "rb") as image_file:
|
||||
image_data = image_file.read()
|
||||
|
||||
# Préparation de la liste des questions à poser
|
||||
questions_a_poser = [question] if question else self.questions_standard
|
||||
|
||||
# Exécution de l'analyse pour chaque question
|
||||
resultats = {
|
||||
"image": image_path,
|
||||
"timestamp": datetime.now().isoformat(),
|
||||
"analyses": []
|
||||
}
|
||||
|
||||
# Traitement pour chaque question
|
||||
for q in questions_a_poser:
|
||||
try:
|
||||
# Ajout des données JSON si fournies
|
||||
if json_data:
|
||||
q_enrichie = f"{q}\n\nContexte: {json.dumps(json_data, ensure_ascii=False)}"
|
||||
else:
|
||||
q_enrichie = q
|
||||
|
||||
# Appel du modèle via la factory
|
||||
reponse = self.llm.generate(q_enrichie, images=[image_data])
|
||||
|
||||
# Ajout du résultat
|
||||
resultats["analyses"].append({
|
||||
"question": q,
|
||||
"reponse": reponse
|
||||
})
|
||||
|
||||
# Ajout à l'historique
|
||||
self.ajouter_historique("analyse_image", q, reponse[:200] + "...")
|
||||
except Exception as e:
|
||||
resultats["analyses"].append({
|
||||
"question": q,
|
||||
"erreur": str(e)
|
||||
})
|
||||
self.ajouter_historique("analyse_image_erreur", q, str(e))
|
||||
|
||||
return resultats
|
||||
|
||||
def sauvegarder_resultats(self, chemin_fichier: str, resultats: Dict[str, Any]) -> bool:
|
||||
"""
|
||||
Sauvegarde les résultats d'analyse dans un fichier JSON
|
||||
|
||||
Args:
|
||||
chemin_fichier: Chemin où sauvegarder le fichier de résultats
|
||||
resultats: Dictionnaire de résultats à sauvegarder
|
||||
|
||||
Returns:
|
||||
True si la sauvegarde a réussi, False sinon
|
||||
"""
|
||||
try:
|
||||
# Création du dossier parent si nécessaire
|
||||
os.makedirs(os.path.dirname(os.path.abspath(chemin_fichier)), exist_ok=True)
|
||||
|
||||
with open(chemin_fichier, 'w', encoding='utf-8') as f:
|
||||
json.dump(resultats, f, ensure_ascii=False, indent=2)
|
||||
|
||||
self.ajouter_historique("sauvegarder_resultats", chemin_fichier, "Résultats sauvegardés")
|
||||
return True
|
||||
except Exception as e:
|
||||
self.ajouter_historique("sauvegarder_resultats_erreur", chemin_fichier, str(e))
|
||||
return False
|
||||
177
agents/analyse_json.py
Normal file
177
agents/analyse_json.py
Normal file
@ -0,0 +1,177 @@
|
||||
import json
|
||||
import time
|
||||
from typing import Dict, List, Any, Optional
|
||||
from datetime import datetime
|
||||
|
||||
from agents.base_agent import Agent
|
||||
from core.factory import LLMFactory
|
||||
|
||||
class AgentAnalyseJSON(Agent):
|
||||
"""
|
||||
Agent pour analyser des données JSON
|
||||
"""
|
||||
def __init__(self, nom: str = "AgentAnalyseJSON", modele: str = "mistral7b"):
|
||||
"""
|
||||
Initialisation de l'agent d'analyse JSON
|
||||
|
||||
Args:
|
||||
nom: Nom de l'agent
|
||||
modele: Identifiant du modèle LLM à utiliser (par défaut: mistral7b)
|
||||
"""
|
||||
super().__init__(nom)
|
||||
|
||||
# Création du modèle via la factory
|
||||
self.llm = LLMFactory.create(modele)
|
||||
|
||||
# Configuration du modèle
|
||||
self.llm.set_role("formateur", {
|
||||
"system_prompt": "Tu es un expert en analyse de données JSON. Tu dois extraire des informations pertinentes, identifier des tendances et répondre à des questions sur les données.",
|
||||
"params": {
|
||||
"temperature": 0.4,
|
||||
"top_p": 0.9
|
||||
}
|
||||
})
|
||||
|
||||
def executer(self, json_data: Dict[str, Any],
|
||||
question: str = "Analyse ces données et extrait les informations principales.") -> Dict[str, Any]:
|
||||
"""
|
||||
Analyse des données JSON
|
||||
|
||||
Args:
|
||||
json_data: Données JSON à analyser
|
||||
question: Question à poser au modèle
|
||||
|
||||
Returns:
|
||||
Résultats de l'analyse sous forme de dictionnaire
|
||||
"""
|
||||
# Conversion du JSON en chaîne formatée
|
||||
json_str = json.dumps(json_data, ensure_ascii=False, indent=2)
|
||||
|
||||
# Construction du prompt avec le JSON et la question
|
||||
prompt = f"{question}\n\nDonnées JSON à analyser:\n```json\n{json_str}\n```"
|
||||
|
||||
# Interrogation du modèle
|
||||
reponse = self.llm.generate(prompt)
|
||||
|
||||
# Construction du résultat
|
||||
resultats = {
|
||||
"question": question,
|
||||
"reponse": reponse,
|
||||
"timestamp": datetime.now().isoformat(),
|
||||
"taille_json": len(json_str)
|
||||
}
|
||||
|
||||
# Ajout à l'historique
|
||||
self.ajouter_historique("analyse_json", prompt[:200] + "...", reponse[:200] + "...")
|
||||
|
||||
return resultats
|
||||
|
||||
def extraire_structure(self, json_data: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""
|
||||
Extrait la structure d'un JSON (clés, types, profondeur)
|
||||
|
||||
Args:
|
||||
json_data: Données JSON à analyser
|
||||
|
||||
Returns:
|
||||
Dictionnaire contenant la structure et des statistiques
|
||||
"""
|
||||
resultat = {
|
||||
"structure": {},
|
||||
"statistiques": {
|
||||
"nb_cles": 0,
|
||||
"profondeur_max": 0,
|
||||
"types": {}
|
||||
}
|
||||
}
|
||||
|
||||
def explorer_structure(data, chemin="", profondeur=0):
|
||||
nonlocal resultat
|
||||
|
||||
# Mise à jour de la profondeur max
|
||||
resultat["statistiques"]["profondeur_max"] = max(resultat["statistiques"]["profondeur_max"], profondeur)
|
||||
|
||||
if isinstance(data, dict):
|
||||
structure = {}
|
||||
for cle, valeur in data.items():
|
||||
nouveau_chemin = f"{chemin}.{cle}" if chemin else cle
|
||||
resultat["statistiques"]["nb_cles"] += 1
|
||||
|
||||
type_valeur = type(valeur).__name__
|
||||
if type_valeur not in resultat["statistiques"]["types"]:
|
||||
resultat["statistiques"]["types"][type_valeur] = 0
|
||||
resultat["statistiques"]["types"][type_valeur] += 1
|
||||
|
||||
if isinstance(valeur, (dict, list)):
|
||||
structure[cle] = explorer_structure(valeur, nouveau_chemin, profondeur + 1)
|
||||
else:
|
||||
structure[cle] = type_valeur
|
||||
return structure
|
||||
|
||||
elif isinstance(data, list):
|
||||
if data and isinstance(data[0], (dict, list)):
|
||||
# Pour les listes de structures complexes, on analyse le premier élément
|
||||
return [explorer_structure(data[0], f"{chemin}[0]", profondeur + 1)]
|
||||
else:
|
||||
# Pour les listes de valeurs simples
|
||||
type_elements = "vide" if not data else type(data[0]).__name__
|
||||
resultat["statistiques"]["nb_cles"] += 1
|
||||
|
||||
if "list" not in resultat["statistiques"]["types"]:
|
||||
resultat["statistiques"]["types"]["list"] = 0
|
||||
resultat["statistiques"]["types"]["list"] += 1
|
||||
|
||||
return f"list[{type_elements}]"
|
||||
else:
|
||||
return type(data).__name__
|
||||
|
||||
resultat["structure"] = explorer_structure(json_data)
|
||||
|
||||
self.ajouter_historique("extraire_structure", "JSON", resultat)
|
||||
return resultat
|
||||
|
||||
def fusionner_jsons(self, json1: Dict[str, Any], json2: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""
|
||||
Fusionne deux structures JSON en conservant les informations des deux
|
||||
|
||||
Args:
|
||||
json1: Premier dictionnaire JSON
|
||||
json2: Second dictionnaire JSON
|
||||
|
||||
Returns:
|
||||
Dictionnaire fusionné
|
||||
"""
|
||||
if not json1:
|
||||
return json2
|
||||
|
||||
if not json2:
|
||||
return json1
|
||||
|
||||
resultat = json1.copy()
|
||||
|
||||
# Fonction récursive pour fusionner
|
||||
def fusionner(dict1, dict2):
|
||||
for cle, valeur in dict2.items():
|
||||
if cle in dict1:
|
||||
# Si les deux sont des dictionnaires, fusion récursive
|
||||
if isinstance(dict1[cle], dict) and isinstance(valeur, dict):
|
||||
fusionner(dict1[cle], valeur)
|
||||
# Si les deux sont des listes, concaténation
|
||||
elif isinstance(dict1[cle], list) and isinstance(valeur, list):
|
||||
dict1[cle].extend(valeur)
|
||||
# Sinon, on garde les deux valeurs dans une liste
|
||||
else:
|
||||
if not isinstance(dict1[cle], list):
|
||||
dict1[cle] = [dict1[cle]]
|
||||
if isinstance(valeur, list):
|
||||
dict1[cle].extend(valeur)
|
||||
else:
|
||||
dict1[cle].append(valeur)
|
||||
else:
|
||||
# Si la clé n'existe pas dans dict1, on l'ajoute simplement
|
||||
dict1[cle] = valeur
|
||||
|
||||
fusionner(resultat, json2)
|
||||
self.ajouter_historique("fusionner_jsons", "Fusion de deux JSON", "Fusion réussie")
|
||||
|
||||
return resultat
|
||||
50
agents/base_agent.py
Normal file
50
agents/base_agent.py
Normal file
@ -0,0 +1,50 @@
|
||||
from datetime import datetime
|
||||
from typing import Dict, List, Any, Optional
|
||||
|
||||
class Agent:
|
||||
"""Classe de base pour tous les agents d'analyse"""
|
||||
|
||||
def __init__(self, nom: str = "Agent"):
|
||||
"""
|
||||
Initialisation d'un agent
|
||||
|
||||
Args:
|
||||
nom: Nom de l'agent
|
||||
"""
|
||||
self.nom: str = nom
|
||||
self.historique: List[Dict[str, Any]] = []
|
||||
|
||||
def ajouter_historique(self, action: str, input_data: Any, output_data: Any) -> None:
|
||||
"""
|
||||
Ajoute une entrée dans l'historique de l'agent
|
||||
|
||||
Args:
|
||||
action: Type d'action effectuée
|
||||
input_data: Données d'entrée de l'action
|
||||
output_data: Résultat de l'action
|
||||
"""
|
||||
self.historique.append({
|
||||
"timestamp": datetime.now().isoformat(),
|
||||
"action": action,
|
||||
"input": str(input_data)[:500], # Limite pour éviter des historiques trop grands
|
||||
"output": str(output_data)[:500] # Limite pour éviter des historiques trop grands
|
||||
})
|
||||
|
||||
def obtenir_historique(self) -> List[Dict[str, Any]]:
|
||||
"""
|
||||
Retourne l'historique complet de l'agent
|
||||
|
||||
Returns:
|
||||
Liste des actions effectuées par l'agent
|
||||
"""
|
||||
return self.historique
|
||||
|
||||
def executer(self, *args, **kwargs) -> Any:
|
||||
"""
|
||||
Méthode abstraite à implémenter dans les classes dérivées
|
||||
C'est la méthode principale qui exécute la tâche spécifique de l'agent
|
||||
|
||||
Returns:
|
||||
Résultat de l'exécution, dépend de l'implémentation de chaque agent
|
||||
"""
|
||||
raise NotImplementedError("Chaque agent doit implémenter sa propre méthode executer()")
|
||||
@ -38,7 +38,8 @@ llm_lab-test/
|
||||
├── config/
|
||||
├── prompts/
|
||||
├── outputs/
|
||||
└── logs/
|
||||
├── logs/
|
||||
└── analyse_projets.md (ce document)
|
||||
```
|
||||
|
||||
### Principales différences
|
||||
@ -136,18 +137,16 @@ La différence principale est la séparation entre les modèles et les rôles (a
|
||||
- Gestion détaillée des erreurs
|
||||
|
||||
#### LlamaVision90B dans llm_lab-test
|
||||
- Implémentation plus simple
|
||||
- Implémentation plus simple
|
||||
- Moins de paramètres configurables
|
||||
- Support pour la traduction automatique
|
||||
- Support pour la traduction automatique (fonctionnalité absente de l'ancien projet)
|
||||
- Structure plus légère
|
||||
|
||||
## 4. Recommandations pour le nouveau projet
|
||||
## 4. Recommandations d'implémentations pour le nouveau projet
|
||||
|
||||
### Intégration de la classe Agent dans llm_lab-test
|
||||
### 1. Proposition d'intégration de la classe Agent abstraite
|
||||
|
||||
L'approche avec une classe abstraite `Agent` présente des avantages significatifs qui pourraient être bénéfiques pour le nouveau projet sans perturber son fonctionnement actuel.
|
||||
|
||||
Voici comment elle pourrait être implémentée :
|
||||
Il serait bénéfique de créer une classe abstraite `Agent` dans le nouveau projet sans perturber son fonctionnement actuel :
|
||||
|
||||
```python
|
||||
# Proposition pour agents/base_agent.py
|
||||
@ -179,9 +178,68 @@ class Agent:
|
||||
raise NotImplementedError("Chaque agent doit implémenter sa propre méthode executer()")
|
||||
```
|
||||
|
||||
### Adaptation de LlamaVision90B avec plus de paramètres
|
||||
### 2. Proposition d'agents spécialisés
|
||||
|
||||
Le modèle LlamaVision90B du nouveau projet pourrait bénéficier des paramètres supplémentaires disponibles dans l'ancien projet :
|
||||
Des agents spécialisés pourraient être créés pour hériter de cette classe abstraite :
|
||||
|
||||
#### AgentAnalyseImage
|
||||
|
||||
Un agent qui utiliserait LlamaVision pour analyser des images :
|
||||
|
||||
```python
|
||||
# Proposition pour agents/analyse_image.py
|
||||
class AgentAnalyseImage(Agent):
|
||||
"""
|
||||
Agent pour analyser des images avec LlamaVision
|
||||
"""
|
||||
def __init__(self, nom: str = "AgentAnalyseImage"):
|
||||
super().__init__(nom)
|
||||
self.llm = LLMFactory.create("llamavision")
|
||||
self.questions_standard = [
|
||||
"Décris en détail ce que tu vois sur cette image.",
|
||||
"Quels sont les éléments principaux visibles sur cette image?",
|
||||
"Y a-t-il du texte visible sur cette image? Si oui, peux-tu le transcrire?",
|
||||
"Quelle est l'ambiance générale de cette image?"
|
||||
]
|
||||
|
||||
def executer(self, image_path: str, json_data: Optional[Dict[str, Any]] = None,
|
||||
question: Optional[str] = None) -> Dict[str, Any]:
|
||||
# Implémentation de l'analyse d'image
|
||||
```
|
||||
|
||||
#### AgentAnalyseJSON
|
||||
|
||||
Un agent qui analyserait des données JSON :
|
||||
|
||||
```python
|
||||
# Proposition pour agents/analyseJSON.py
|
||||
class AgentAnalyseJSON(Agent):
|
||||
"""
|
||||
Agent pour analyser des données JSON
|
||||
"""
|
||||
def __init__(self, nom: str = "AgentAnalyseJSON", modele: str = "mistral7b"):
|
||||
super().__init__(nom)
|
||||
|
||||
# Choix du modèle
|
||||
self.llm = LLMFactory.create(modele)
|
||||
|
||||
# Configuration du modèle
|
||||
self.llm.set_role("formateur", {
|
||||
"system_prompt": "Tu es un expert en analyse de données JSON...",
|
||||
"params": {
|
||||
"temperature": 0.4,
|
||||
"top_p": 0.9
|
||||
}
|
||||
})
|
||||
|
||||
def executer(self, json_data: Dict[str, Any],
|
||||
question: str = "Analyse ces données...") -> Dict[str, Any]:
|
||||
# Implémentation de l'analyse JSON
|
||||
```
|
||||
|
||||
### 3. Proposition d'adaptation de LlamaVision90B
|
||||
|
||||
L'implémentation de LlamaVision90B pourrait être enrichie pour inclure tous les paramètres et fonctionnalités de la version originale :
|
||||
|
||||
```python
|
||||
# Proposition de mise à jour pour core/llama_vision90b.py
|
||||
@ -193,54 +251,48 @@ class LlamaVision90B(BaseLLM):
|
||||
self.api_url = "http://217.182.105.173:11434/api/chat"
|
||||
|
||||
default_params = {
|
||||
# Paramètres existants
|
||||
# Paramètres de créativité
|
||||
"temperature": 0.3,
|
||||
"top_p": 1.0,
|
||||
"top_k": 40,
|
||||
"repeat_penalty": 1.1,
|
||||
"num_predict": 512,
|
||||
"num_ctx": 4096,
|
||||
|
||||
# Nouveaux paramètres inspirés de l'ancien projet
|
||||
# Paramètres de qualité
|
||||
"repeat_penalty": 1.1,
|
||||
"min_p": 0.0,
|
||||
|
||||
# Paramètres de contrôle avancé
|
||||
"mirostat": 0,
|
||||
"mirostat_eta": 0.1,
|
||||
"mirostat_tau": 5.0,
|
||||
|
||||
# Paramètres de taille
|
||||
"num_predict": 512,
|
||||
"num_ctx": 4096,
|
||||
|
||||
# Paramètres de contrôle
|
||||
"seed": 0,
|
||||
"stop": [],
|
||||
"min_p": 0.0,
|
||||
|
||||
# Paramètres existants
|
||||
# Autres paramètres
|
||||
"format": "json",
|
||||
"stream": False,
|
||||
"raw": False,
|
||||
"keep_alive": "5m"
|
||||
}
|
||||
|
||||
super().__init__(model_name=model_name, engine=engine, base_params=default_params)
|
||||
|
||||
# Support pour les données JSON associées
|
||||
# Attributs pour la gestion des images et données JSON
|
||||
self.image_data = None
|
||||
self.json_data = {}
|
||||
|
||||
def set_json_data(self, json_data: Dict[str, Any]) -> bool:
|
||||
"""Définit les données JSON à associer à l'image"""
|
||||
try:
|
||||
self.json_data = json_data
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"Erreur lors de la définition des données JSON: {e}")
|
||||
return False
|
||||
|
||||
# [...] Reste de l'implémentation
|
||||
super().__init__(model_name=model_name, engine=engine, base_params=default_params)
|
||||
```
|
||||
|
||||
### Création d'une classe Mistral compatible avec l'ancien projet
|
||||
### 4. Proposition de création de MistralAPI
|
||||
|
||||
Une nouvelle classe MistralAPI compatible avec l'API Mistral externe pourrait être ajoutée :
|
||||
|
||||
```python
|
||||
# Proposition pour core/mistral_api.py
|
||||
from core.base_llm import BaseLLM
|
||||
import requests
|
||||
import json
|
||||
|
||||
class MistralAPI(BaseLLM):
|
||||
"""Intégration avec l'API Mistral (similaire à la classe Mistral de l'ancien projet)"""
|
||||
|
||||
@ -249,45 +301,51 @@ class MistralAPI(BaseLLM):
|
||||
engine = "MistralAPI"
|
||||
|
||||
self.api_url = "https://api.mistral.ai/v1/chat/completions"
|
||||
self.api_key = "VOTRE_CLE_API" # À remplacer par la clé réelle ou une variable d'environnement
|
||||
self.api_key = os.environ.get("MISTRAL_API_KEY", "")
|
||||
|
||||
default_params = {
|
||||
# Paramètres de génération
|
||||
"temperature": 0.7,
|
||||
"top_p": 0.9,
|
||||
"max_tokens": 1024,
|
||||
|
||||
# Paramètres de contrôle
|
||||
"presence_penalty": 0,
|
||||
"frequency_penalty": 0,
|
||||
"stop": []
|
||||
"stop": [],
|
||||
|
||||
# Paramètres divers
|
||||
"random_seed": None
|
||||
}
|
||||
|
||||
super().__init__(model_name=model_name, engine=engine, base_params=default_params)
|
||||
|
||||
def generate(self, user_prompt):
|
||||
prompt = self._format_prompt(user_prompt)
|
||||
|
||||
headers = {
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": f"Bearer {self.api_key}"
|
||||
}
|
||||
|
||||
payload = {
|
||||
"model": self.model,
|
||||
"messages": [
|
||||
{"role": "system", "content": self.system_prompt},
|
||||
{"role": "user", "content": user_prompt}
|
||||
],
|
||||
"temperature": self.params.get("temperature", 0.7),
|
||||
"top_p": self.params.get("top_p", 0.9),
|
||||
"max_tokens": self.params.get("max_tokens", 1024)
|
||||
}
|
||||
|
||||
response = requests.post(self.api_url, headers=headers, json=payload)
|
||||
|
||||
if not response.ok:
|
||||
raise Exception(f"Erreur API Mistral: {response.status_code} - {response.text}")
|
||||
|
||||
result_data = response.json()
|
||||
result_text = result_data.get("choices", [{}])[0].get("message", {}).get("content", "")
|
||||
|
||||
return self._log_result(user_prompt, result_text)
|
||||
```
|
||||
```
|
||||
|
||||
### 5. Proposition de mise à jour de la Factory
|
||||
|
||||
La Factory pourrait être mise à jour pour inclure le nouveau modèle MistralAPI :
|
||||
|
||||
```python
|
||||
# Proposition de mise à jour pour core/factory.py
|
||||
class LLMFactory:
|
||||
"""
|
||||
Factory pour créer des instances de modèles LLM dynamiquement
|
||||
"""
|
||||
_registry = {
|
||||
"mistral7b": Mistral7B,
|
||||
"llamavision": LlamaVision90B,
|
||||
"mistralapi": MistralAPI,
|
||||
# Ajouter d'autres modèles LLM ici
|
||||
}
|
||||
```
|
||||
|
||||
## 5. Conclusion
|
||||
|
||||
Cette analyse a permis d'identifier des opportunités d'enrichissement du nouveau projet llm_lab-test avec les fonctionnalités clés de l'ancien projet AIagent2, tout en conservant sa structure modulaire et moderne. Les ajouts potentiels sont :
|
||||
|
||||
1. Une classe abstraite Agent pour unifier les comportements des agents
|
||||
2. Des implémentations d'agents spécialisés (analyse d'image et JSON)
|
||||
3. Une version enrichie de LlamaVision90B avec tous les paramètres de l'original
|
||||
4. Une nouvelle classe MistralAPI compatible avec l'API Mistral externe
|
||||
|
||||
Ces modifications permettraient de bénéficier des avantages des deux approches : la richesse fonctionnelle de l'ancien projet et la structure modulaire du nouveau.
|
||||
@ -1,5 +1,6 @@
|
||||
from core.mistral7b import Mistral7B
|
||||
from core.llama_vision90b import LlamaVision90B
|
||||
from core.mistral_api import MistralAPI
|
||||
|
||||
class LLMFactory:
|
||||
"""
|
||||
@ -8,6 +9,7 @@ class LLMFactory:
|
||||
_registry = {
|
||||
"mistral7b": Mistral7B,
|
||||
"llamavision": LlamaVision90B,
|
||||
"mistralapi": MistralAPI,
|
||||
# Ajouter d'autres modèles LLM ici
|
||||
}
|
||||
|
||||
|
||||
@ -2,6 +2,8 @@ from core.base_llm import BaseLLM
|
||||
import requests
|
||||
import json
|
||||
import os
|
||||
import base64
|
||||
from typing import Dict, List, Any, Optional
|
||||
from deep_translator import GoogleTranslator
|
||||
|
||||
class LlamaVision90B(BaseLLM):
|
||||
@ -11,30 +13,143 @@ class LlamaVision90B(BaseLLM):
|
||||
|
||||
self.api_url = "http://217.182.105.173:11434/api/chat"
|
||||
|
||||
# Paramètres enrichis basés sur l'ancien projet
|
||||
default_params = {
|
||||
"temperature": 0.3, #Créativité basse pour analyse technique
|
||||
"top_p": 1.0, # Conserve toute la distribution
|
||||
"top_k": 40, #Limite vocabulaire
|
||||
"repeat_penalty": 1.1, #Réduction des répétitions
|
||||
"num_predict": 512, #longueur max sortie
|
||||
"num-ctx": 4096, #Contexte étendu
|
||||
"format": "json", #Réponse structurée JSON (optionnel)
|
||||
"stream": False, #Réponse d'un seul bloc
|
||||
"raw": False, #laisse le formatage systèmes
|
||||
"keep_alive": "5m" #Durée de vie de la connexion
|
||||
# Paramètres de créativité
|
||||
"temperature": 0.3, # Créativité basse pour analyse technique
|
||||
"top_p": 1.0, # Conserve toute la distribution
|
||||
"top_k": 40, # Limite vocabulaire
|
||||
|
||||
# Paramètres de qualité
|
||||
"repeat_penalty": 1.1, # Réduction des répétitions
|
||||
"min_p": 0.0, # Seuil minimal pour la probabilité des tokens
|
||||
|
||||
# Paramètres de contrôle avancé
|
||||
"mirostat": 0, # 0=désactivé, 1=v1, 2=v2
|
||||
"mirostat_eta": 0.1, # Taux d'apprentissage pour mirostat
|
||||
"mirostat_tau": 5.0, # Cible pour mirostat
|
||||
|
||||
# Paramètres de taille
|
||||
"num_predict": 512, # Longueur max sortie
|
||||
"num_ctx": 4096, # Contexte étendu
|
||||
|
||||
# Paramètres de contrôle
|
||||
"seed": 0, # Graine pour reproductibilité (0=aléatoire)
|
||||
"stop": [], # Séquences d'arrêt
|
||||
|
||||
# Paramètres de format
|
||||
"format": "json", # Réponse structurée JSON (optionnel)
|
||||
"stream": False, # Réponse d'un seul bloc
|
||||
"raw": False, # Laisse le formatage systèmes
|
||||
"keep_alive": "5m" # Durée de vie de la connexion
|
||||
}
|
||||
|
||||
super().__init__(model_name=model_name, engine=engine, base_params=default_params)
|
||||
|
||||
def generate(self, user_prompt: str, images: list = None, translate: bool = False):
|
||||
# Attributs spécifiques pour Llama Vision
|
||||
self.image_data = None # Données de l'image en bytes
|
||||
self.image_path = "" # Chemin vers l'image
|
||||
self.json_data = {} # Données JSON associées
|
||||
self.dernier_resultat = {} # Stockage du dernier résultat d'analyse
|
||||
self.historique_resultats = [] # Historique des résultats d'analyse
|
||||
|
||||
def set_image(self, image_path: str) -> bool:
|
||||
"""
|
||||
Définit l'image à analyser à partir d'un chemin de fichier
|
||||
|
||||
Args:
|
||||
image_path: Chemin vers l'image à analyser
|
||||
|
||||
Returns:
|
||||
True si l'image a été chargée avec succès, False sinon
|
||||
"""
|
||||
if not os.path.exists(image_path):
|
||||
return False
|
||||
|
||||
try:
|
||||
with open(image_path, "rb") as f:
|
||||
self.image_data = f.read()
|
||||
self.image_path = image_path
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"Erreur lors du chargement de l'image: {e}")
|
||||
return False
|
||||
|
||||
def set_image_data(self, image_data: bytes) -> bool:
|
||||
"""
|
||||
Définit directement les données de l'image à analyser
|
||||
|
||||
Args:
|
||||
image_data: Données binaires de l'image
|
||||
|
||||
Returns:
|
||||
True si les données ont été définies avec succès, False sinon
|
||||
"""
|
||||
try:
|
||||
self.image_data = image_data
|
||||
self.image_path = ""
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"Erreur lors de la définition des données d'image: {e}")
|
||||
return False
|
||||
|
||||
def set_json_data(self, json_data: Dict[str, Any]) -> bool:
|
||||
"""
|
||||
Définit les données JSON à associer à l'image
|
||||
|
||||
Args:
|
||||
json_data: Dictionnaire de données à associer
|
||||
|
||||
Returns:
|
||||
True si les données ont été définies avec succès, False sinon
|
||||
"""
|
||||
try:
|
||||
self.json_data = json_data
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"Erreur lors de la définition des données JSON: {e}")
|
||||
return False
|
||||
|
||||
def generate(self, user_prompt: str, images: Optional[List[str]] = None, translate: bool = False):
|
||||
"""
|
||||
Génère une réponse à partir d'un prompt utilisateur et d'images
|
||||
|
||||
Args:
|
||||
user_prompt: Texte du prompt utilisateur
|
||||
images: Liste d'images encodées en base64 (optionnel)
|
||||
translate: Indique si la réponse doit être traduite
|
||||
|
||||
Returns:
|
||||
Réponse du modèle, ou tuple (réponse, traduction) si translate=True
|
||||
"""
|
||||
prompt = self._format_prompt(user_prompt)
|
||||
|
||||
# Si des images sont fournies directement, utilisez-les
|
||||
images_to_use = images if images is not None else []
|
||||
|
||||
# Si image_data est défini et aucune image n'est fournie explicitement
|
||||
if self.image_data is not None and (images is None or len(images) == 0):
|
||||
# Encodage en base64 si ce n'est pas déjà fait
|
||||
try:
|
||||
if isinstance(self.image_data, bytes):
|
||||
encoded_image = base64.b64encode(self.image_data).decode('utf-8')
|
||||
images_to_use = [encoded_image]
|
||||
except Exception as e:
|
||||
print(f"Erreur lors de l'encodage de l'image: {e}")
|
||||
|
||||
# Ajout des données JSON dans le prompt si disponibles
|
||||
if self.json_data:
|
||||
json_str = json.dumps(self.json_data, ensure_ascii=False, indent=2)
|
||||
# On ajoute le JSON au prompt pour qu'il soit traité avec l'image
|
||||
prompt = f"{prompt}\n\nVoici des données JSON associées à cette image:\n```json\n{json_str}\n```"
|
||||
|
||||
payload = {
|
||||
"model": self.model,
|
||||
"messages": [
|
||||
{
|
||||
"role": "user",
|
||||
"content": prompt,
|
||||
"images": images if images else []
|
||||
"images": images_to_use
|
||||
}
|
||||
],
|
||||
"options": self.params,
|
||||
@ -49,10 +164,70 @@ class LlamaVision90B(BaseLLM):
|
||||
result_data = response.json()
|
||||
result_text = result_data.get("message", {}).get("content", "")
|
||||
|
||||
# Stockage du résultat pour fusion ultérieure
|
||||
self.dernier_resultat = result_data
|
||||
self.historique_resultats.append(result_data)
|
||||
|
||||
self._log_result(user_prompt, result_text)
|
||||
|
||||
if translate:
|
||||
result_fr = GoogleTranslator(source="auto", target="fr").translate(result_text)
|
||||
return result_text, result_fr
|
||||
|
||||
return result_text
|
||||
return result_text
|
||||
|
||||
def fusionner_json_avec_resultats(self) -> Dict[str, Any]:
|
||||
"""
|
||||
Fusionne les données JSON existantes avec les résultats de l'analyse d'image
|
||||
|
||||
Returns:
|
||||
Dictionnaire combinant le JSON initial et les résultats d'analyse
|
||||
"""
|
||||
if not hasattr(self, 'dernier_resultat') or not self.dernier_resultat:
|
||||
return self.json_data
|
||||
|
||||
# Créer une copie du JSON original
|
||||
resultat_fusionne = self.json_data.copy() if self.json_data else {}
|
||||
|
||||
# Ajouter le résultat de l'analyse d'image
|
||||
if "analyse_image" not in resultat_fusionne:
|
||||
resultat_fusionne["analyse_image"] = []
|
||||
|
||||
# Ajouter le résultat à la liste des analyses
|
||||
nouvelle_analyse = {
|
||||
"modele": self.model,
|
||||
"reponse": self.dernier_resultat.get("message", {}).get("content", ""),
|
||||
"parametres": {
|
||||
"temperature": self.params.get("temperature"),
|
||||
"top_p": self.params.get("top_p"),
|
||||
"num_ctx": self.params.get("num_ctx")
|
||||
}
|
||||
}
|
||||
|
||||
resultat_fusionne["analyse_image"].append(nouvelle_analyse)
|
||||
|
||||
return resultat_fusionne
|
||||
|
||||
def sauvegarder_resultats(self, chemin_fichier: str) -> bool:
|
||||
"""
|
||||
Sauvegarde les résultats fusionnés dans un fichier JSON
|
||||
|
||||
Args:
|
||||
chemin_fichier: Chemin où sauvegarder le fichier de résultats
|
||||
|
||||
Returns:
|
||||
True si la sauvegarde a réussi, False sinon
|
||||
"""
|
||||
try:
|
||||
resultats_fusionnes = self.fusionner_json_avec_resultats()
|
||||
|
||||
# Création du dossier parent si nécessaire
|
||||
os.makedirs(os.path.dirname(os.path.abspath(chemin_fichier)), exist_ok=True)
|
||||
|
||||
with open(chemin_fichier, 'w', encoding='utf-8') as f:
|
||||
json.dump(resultats_fusionnes, f, ensure_ascii=False, indent=2)
|
||||
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"Erreur lors de la sauvegarde des résultats: {e}")
|
||||
return False
|
||||
134
core/mistral_api.py
Normal file
134
core/mistral_api.py
Normal file
@ -0,0 +1,134 @@
|
||||
from core.base_llm import BaseLLM
|
||||
import requests
|
||||
import json
|
||||
import os
|
||||
from typing import Dict, List, Any, Optional
|
||||
|
||||
class MistralAPI(BaseLLM):
|
||||
"""Intégration avec l'API Mistral (similaire à la classe Mistral de l'ancien projet)"""
|
||||
|
||||
def __init__(self):
|
||||
model_name = "mistral-large-latest"
|
||||
engine = "MistralAPI"
|
||||
|
||||
self.api_url = "https://api.mistral.ai/v1/chat/completions"
|
||||
# À remplacer par la clé réelle ou une variable d'environnement
|
||||
self.api_key = os.environ.get("MISTRAL_API_KEY", "")
|
||||
|
||||
default_params = {
|
||||
# Paramètres de génération
|
||||
"temperature": 0.7,
|
||||
"top_p": 0.9,
|
||||
"max_tokens": 1024,
|
||||
|
||||
# Paramètres de contrôle
|
||||
"presence_penalty": 0,
|
||||
"frequency_penalty": 0,
|
||||
"stop": [],
|
||||
|
||||
# Paramètres divers
|
||||
"random_seed": None
|
||||
}
|
||||
|
||||
super().__init__(model_name=model_name, engine=engine, base_params=default_params)
|
||||
|
||||
def generate(self, user_prompt: str) -> str:
|
||||
"""
|
||||
Génère une réponse à partir du prompt utilisateur via l'API Mistral
|
||||
|
||||
Args:
|
||||
user_prompt: Texte du prompt utilisateur
|
||||
|
||||
Returns:
|
||||
Réponse générée par le modèle
|
||||
|
||||
Raises:
|
||||
ValueError: Si la clé API n'est pas définie
|
||||
Exception: Si une erreur survient lors de l'appel à l'API
|
||||
"""
|
||||
prompt = self._format_prompt(user_prompt)
|
||||
|
||||
if not self.api_key:
|
||||
raise ValueError("Clé API Mistral non définie. Définissez la variable d'environnement MISTRAL_API_KEY.")
|
||||
|
||||
headers = {
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": f"Bearer {self.api_key}"
|
||||
}
|
||||
|
||||
# Préparation des messages
|
||||
messages = []
|
||||
|
||||
# Ajout du prompt système si défini
|
||||
if self.system_prompt:
|
||||
messages.append({"role": "system", "content": self.system_prompt})
|
||||
|
||||
# Ajout du prompt utilisateur
|
||||
messages.append({"role": "user", "content": user_prompt})
|
||||
|
||||
# Préparation du payload
|
||||
payload = {
|
||||
"model": self.model,
|
||||
"messages": messages,
|
||||
"temperature": self.params.get("temperature", 0.7),
|
||||
"top_p": self.params.get("top_p", 0.9),
|
||||
"max_tokens": self.params.get("max_tokens", 1024)
|
||||
}
|
||||
|
||||
# Ajout des paramètres optionnels
|
||||
if self.params.get("presence_penalty") is not None:
|
||||
payload["presence_penalty"] = self.params.get("presence_penalty")
|
||||
|
||||
if self.params.get("frequency_penalty") is not None:
|
||||
payload["frequency_penalty"] = self.params.get("frequency_penalty")
|
||||
|
||||
# Vérifier que stop est une liste non vide
|
||||
stop_sequences = self.params.get("stop")
|
||||
if isinstance(stop_sequences, list) and stop_sequences:
|
||||
payload["stop"] = stop_sequences
|
||||
|
||||
if self.params.get("random_seed") is not None:
|
||||
payload["random_seed"] = self.params.get("random_seed")
|
||||
|
||||
# Envoi de la requête
|
||||
response = requests.post(self.api_url, headers=headers, json=payload)
|
||||
|
||||
if not response.ok:
|
||||
raise Exception(f"Erreur API Mistral: {response.status_code} - {response.text}")
|
||||
|
||||
# Traitement de la réponse
|
||||
result_data = response.json()
|
||||
result_text = result_data.get("choices", [{}])[0].get("message", {}).get("content", "")
|
||||
|
||||
# Logging du résultat
|
||||
filename = self._log_result(user_prompt, result_text)
|
||||
|
||||
return result_text
|
||||
|
||||
def obtenir_liste_modeles(self) -> List[str]:
|
||||
"""
|
||||
Récupère la liste des modèles disponibles via l'API Mistral
|
||||
|
||||
Returns:
|
||||
Liste des identifiants de modèles disponibles
|
||||
|
||||
Raises:
|
||||
ValueError: Si la clé API n'est pas définie
|
||||
Exception: Si une erreur survient lors de l'appel à l'API
|
||||
"""
|
||||
if not self.api_key:
|
||||
raise ValueError("Clé API Mistral non définie. Définissez la variable d'environnement MISTRAL_API_KEY.")
|
||||
|
||||
headers = {
|
||||
"Authorization": f"Bearer {self.api_key}"
|
||||
}
|
||||
|
||||
response = requests.get("https://api.mistral.ai/v1/models", headers=headers)
|
||||
|
||||
if not response.ok:
|
||||
raise Exception(f"Erreur API Mistral: {response.status_code} - {response.text}")
|
||||
|
||||
result_data = response.json()
|
||||
models = [model.get("id") for model in result_data.get("data", [])]
|
||||
|
||||
return models
|
||||
123
docs/README.md
Normal file
123
docs/README.md
Normal file
@ -0,0 +1,123 @@
|
||||
# LLM Lab - Documentation
|
||||
|
||||
## Vue d'ensemble
|
||||
|
||||
LLM Lab est une plateforme modulaire conçue pour l'expérimentation avec différents modèles de langage (LLM) et la création d'agents spécialisés. Cette architecture permet l'intégration facile de nouveaux modèles et la création rapide d'agents pour des tâches spécifiques.
|
||||
|
||||
## Architecture du projet
|
||||
|
||||
```
|
||||
llm_lab-test/
|
||||
│
|
||||
├── agents/ # Agents spécialisés
|
||||
│ ├── base_agent.py # Classe abstraite de base pour tous les agents
|
||||
│ ├── analyse_image.py # Agent pour l'analyse d'images
|
||||
│ └── analyse_json.py # Agent pour l'analyse de données JSON
|
||||
│
|
||||
├── core/ # Composants principaux
|
||||
│ ├── factory.py # Factory pour l'instanciation des LLMs
|
||||
│ ├── llama_vision90b.py # Implémentation de LlamaVision pour l'analyse d'images
|
||||
│ └── mistral_api.py # Implémentation de l'API Mistral
|
||||
│
|
||||
├── examples/ # Exemples d'utilisation
|
||||
│ ├── analyse_image_workflow.py # Workflow d'analyse d'images
|
||||
│ ├── test_mistralapi.py # Test de l'API Mistral
|
||||
│ └── agent_question_reponse.py # Agent de questions-réponses
|
||||
│
|
||||
├── config/ # Fichiers de configuration
|
||||
├── prompts/ # Templates de prompts
|
||||
├── outputs/ # Répertoire pour les sorties générées
|
||||
├── logs/ # Journaux d'exécution
|
||||
└── tests/ # Tests unitaires
|
||||
```
|
||||
|
||||
## Modèles LLM disponibles
|
||||
|
||||
Le projet intègre plusieurs modèles de langage accessibles via la factory `LLMFactory` :
|
||||
|
||||
1. **LlamaVision90B** : Modèle spécialisé dans l'analyse d'images avec capacités de vision.
|
||||
2. **MistralAPI** : Interface pour l'API Mistral, permettant d'accéder aux modèles comme mistral-large-latest.
|
||||
|
||||
## Agents disponibles
|
||||
|
||||
Les agents sont des composants spécialisés qui encapsulent des fonctionnalités spécifiques :
|
||||
|
||||
### Agent de base (`base_agent.py`)
|
||||
|
||||
Classe abstraite définissant l'interface commune à tous les agents, avec :
|
||||
- Gestion d'un historique des actions
|
||||
- Méthode abstraite `executer()` à implémenter par les sous-classes
|
||||
|
||||
### Agent d'analyse d'images (`analyse_image.py`)
|
||||
|
||||
Spécialisé dans l'analyse d'images via LlamaVision :
|
||||
- Analyse d'images individuelles
|
||||
- Intégration avec des données JSON contextuelles
|
||||
- Extraction d'informations visuelles (texte, objets, scènes)
|
||||
|
||||
### Agent d'analyse JSON (`analyse_json.py`)
|
||||
|
||||
Analyse et traite des données JSON :
|
||||
- Extraction de structure
|
||||
- Fusion de données JSON
|
||||
- Analyse approfondie du contenu
|
||||
|
||||
### Agent de questions-réponses (`agent_question_reponse.py`)
|
||||
|
||||
Agent conversationnel utilisant MistralAPI :
|
||||
- Réponses à des questions avec ou sans contexte
|
||||
- Génération de questions pertinentes
|
||||
- Évaluation de la qualité des réponses
|
||||
|
||||
## Exemples d'utilisation
|
||||
|
||||
### Workflow d'analyse d'images
|
||||
|
||||
```python
|
||||
# Initialisation d'un agent d'analyse d'image
|
||||
agent = AgentAnalyseImage("AgentVision")
|
||||
|
||||
# Analyse d'une image
|
||||
resultats = agent.executer("chemin/vers/image.jpg",
|
||||
question="Décris cette image en détail")
|
||||
```
|
||||
|
||||
### Utilisation de MistralAPI
|
||||
|
||||
```python
|
||||
# Via la factory
|
||||
llm = LLMFactory().create("mistralapi")
|
||||
|
||||
# Configuration des paramètres
|
||||
llm.parametres_generation["temperature"] = 0.7
|
||||
|
||||
# Génération de texte
|
||||
reponse = llm.generate("Explique-moi comment fonctionne un LLM")
|
||||
```
|
||||
|
||||
### Agent de questions-réponses
|
||||
|
||||
```python
|
||||
# Initialisation
|
||||
agent = AgentQuestionReponse("AgentQR")
|
||||
|
||||
# Poser une question
|
||||
resultat = agent.executer("Qu'est-ce que l'apprentissage par renforcement?")
|
||||
print(resultat["reponse"])
|
||||
|
||||
# Générer des questions sur un sujet
|
||||
questions = agent.generer_questions(contexte_json, nombre=3)
|
||||
```
|
||||
|
||||
## Configuration requise
|
||||
|
||||
- Python 3.8+
|
||||
- Clé API Mistral (pour MistralAPI)
|
||||
- Dépendances listées dans `requirements.txt`
|
||||
|
||||
## Pour commencer
|
||||
|
||||
1. Cloner le dépôt
|
||||
2. Installer les dépendances : `pip install -r requirements.txt`
|
||||
3. Configurer les variables d'environnement nécessaires (ex: `MISTRAL_API_KEY`)
|
||||
4. Explorer les exemples dans le dossier `examples/`
|
||||
250
docs/guide_utilisation.md
Normal file
250
docs/guide_utilisation.md
Normal file
@ -0,0 +1,250 @@
|
||||
# Guide d'utilisation des agents et classes LLM
|
||||
|
||||
Ce guide fournit des instructions détaillées sur l'utilisation des différents agents et classes LLM disponibles dans le projet LLM Lab.
|
||||
|
||||
## Table des matières
|
||||
|
||||
1. [Utilisation des modèles LLM](#utilisation-des-modèles-llm)
|
||||
- [LlamaVision90B](#llamavision90b)
|
||||
- [MistralAPI](#mistralapi)
|
||||
|
||||
2. [Utilisation des agents](#utilisation-des-agents)
|
||||
- [Agent d'analyse d'images](#agent-danalyse-dimages)
|
||||
- [Agent d'analyse JSON](#agent-danalyse-json)
|
||||
- [Agent de questions-réponses](#agent-de-questions-réponses)
|
||||
|
||||
3. [Exemples de workflows complets](#exemples-de-workflows-complets)
|
||||
|
||||
## Utilisation des modèles LLM
|
||||
|
||||
Les modèles LLM sont accessibles via la factory `LLMFactory` pour garantir une instanciation cohérente et configurable.
|
||||
|
||||
### LlamaVision90B
|
||||
|
||||
Ce modèle est spécialisé dans l'analyse d'images avec des capacités multimodales (texte + image).
|
||||
|
||||
#### Configuration de base
|
||||
|
||||
```python
|
||||
from core.factory import LLMFactory
|
||||
|
||||
# Création d'une instance via la factory
|
||||
vision_llm = LLMFactory().create("llamavision")
|
||||
|
||||
# Configuration des paramètres
|
||||
vision_llm.parametres_generation["temperature"] = 0.2
|
||||
vision_llm.parametres_generation["max_tokens"] = 1000
|
||||
vision_llm.parametres_avances["top_p"] = 0.9
|
||||
```
|
||||
|
||||
#### Analyse d'une image
|
||||
|
||||
```python
|
||||
# Définir le chemin de l'image
|
||||
vision_llm.definir_image("chemin/vers/image.jpg")
|
||||
|
||||
# Générer une description de l'image
|
||||
prompt = "Décris en détail ce que tu vois dans cette image."
|
||||
description = vision_llm.generate(prompt)
|
||||
print(description)
|
||||
```
|
||||
|
||||
#### Analyse avec des données JSON complémentaires
|
||||
|
||||
```python
|
||||
# Définir des données JSON complémentaires
|
||||
donnees_complementaires = {
|
||||
"metadata": {
|
||||
"source": "caméra de surveillance",
|
||||
"timestamp": "2023-03-15T14:30:00",
|
||||
"location": "entrée principale"
|
||||
}
|
||||
}
|
||||
|
||||
vision_llm.definir_donnees_json(donnees_complementaires)
|
||||
|
||||
# Générer une analyse avec contexte
|
||||
prompt = "Analyse cette image en tenant compte des métadonnées fournies."
|
||||
resultat = vision_llm.generate(prompt)
|
||||
```
|
||||
|
||||
### MistralAPI
|
||||
|
||||
Cette classe permet d'accéder aux modèles de langage de Mistral AI via leur API.
|
||||
|
||||
#### Configuration de base
|
||||
|
||||
```python
|
||||
from core.factory import LLMFactory
|
||||
import os
|
||||
|
||||
# Définir la clé API (ou via variable d'environnement)
|
||||
os.environ["MISTRAL_API_KEY"] = "votre_clé_api"
|
||||
|
||||
# Création d'une instance via la factory
|
||||
mistral = LLMFactory().create("mistralapi")
|
||||
|
||||
# Configuration des paramètres
|
||||
mistral.parametres_generation["temperature"] = 0.7
|
||||
mistral.parametres_generation["max_tokens"] = 500
|
||||
```
|
||||
|
||||
#### Génération de texte
|
||||
|
||||
```python
|
||||
# Génération simple
|
||||
prompt = "Explique le concept de l'intelligence artificielle en 3 paragraphes."
|
||||
reponse = mistral.generate(prompt)
|
||||
print(reponse)
|
||||
```
|
||||
|
||||
#### Obtention de la liste des modèles disponibles
|
||||
|
||||
```python
|
||||
modeles = mistral.obtenir_liste_modeles()
|
||||
print("Modèles disponibles:")
|
||||
for modele in modeles:
|
||||
print(f"- {modele}")
|
||||
```
|
||||
|
||||
## Utilisation des agents
|
||||
|
||||
Les agents sont des composants de plus haut niveau qui encapsulent les modèles LLM avec des fonctionnalités spécifiques.
|
||||
|
||||
### Agent d'analyse d'images
|
||||
|
||||
Cet agent facilite l'analyse d'images en utilisant LlamaVision.
|
||||
|
||||
```python
|
||||
from agents.analyse_image import AgentAnalyseImage
|
||||
|
||||
# Création de l'agent
|
||||
agent = AgentAnalyseImage("AgentVision")
|
||||
|
||||
# Analyse simple d'une image
|
||||
resultats = agent.executer(
|
||||
"chemin/vers/image.jpg",
|
||||
question="Que vois-tu dans cette image? Y a-t-il du texte visible?"
|
||||
)
|
||||
|
||||
# Affichage des résultats
|
||||
print(resultats["analyses"][0]["reponse"])
|
||||
|
||||
# Sauvegarde des résultats
|
||||
agent.sauvegarder_resultats("resultats_analyse.json", resultats)
|
||||
```
|
||||
|
||||
### Agent d'analyse JSON
|
||||
|
||||
Cet agent permet d'analyser et de manipuler des données JSON.
|
||||
|
||||
```python
|
||||
from agents.analyse_json import AgentAnalyseJSON
|
||||
|
||||
# Création de l'agent
|
||||
agent = AgentAnalyseJSON("AgentJSON")
|
||||
|
||||
# Données JSON à analyser
|
||||
donnees = {
|
||||
"utilisateurs": [
|
||||
{"id": 1, "nom": "Dupont", "age": 32},
|
||||
{"id": 2, "nom": "Martin", "age": 45},
|
||||
{"id": 3, "nom": "Durand", "age": 28}
|
||||
],
|
||||
"statistiques": {
|
||||
"moyenne_age": 35,
|
||||
"total_utilisateurs": 3
|
||||
}
|
||||
}
|
||||
|
||||
# Analyse des données
|
||||
resultats = agent.executer(
|
||||
donnees,
|
||||
question="Quelles informations importantes peux-tu extraire de ces données?"
|
||||
)
|
||||
|
||||
print(resultats["analyse"])
|
||||
|
||||
# Extraction de la structure
|
||||
structure = agent.extraire_structure(donnees)
|
||||
print("Structure des données:", structure)
|
||||
```
|
||||
|
||||
### Agent de questions-réponses
|
||||
|
||||
Cet agent utilise MistralAPI pour des interactions de type questions-réponses.
|
||||
|
||||
```python
|
||||
from agents.agent_question_reponse import AgentQuestionReponse
|
||||
|
||||
# Création de l'agent avec le modèle souhaité
|
||||
agent = AgentQuestionReponse("AgentQR", modele="mistral-large-latest")
|
||||
|
||||
# Poser une question simple
|
||||
resultat = agent.executer("Comment fonctionne l'apprentissage par renforcement?")
|
||||
print(resultat["reponse"])
|
||||
|
||||
# Poser une question avec contexte
|
||||
contexte = {
|
||||
"sujet": "Intelligence artificielle",
|
||||
"domaine": "Apprentissage automatique",
|
||||
"concepts_cles": ["réseaux de neurones", "deep learning", "données d'entraînement"]
|
||||
}
|
||||
|
||||
resultat_avec_contexte = agent.executer(
|
||||
"Quelles sont les différences entre l'apprentissage supervisé et non supervisé?",
|
||||
contexte=contexte
|
||||
)
|
||||
print(resultat_avec_contexte["reponse"])
|
||||
|
||||
# Générer des questions à partir d'un contexte
|
||||
questions = agent.generer_questions(contexte, nombre=5)
|
||||
for i, question in enumerate(questions, 1):
|
||||
print(f"{i}. {question}")
|
||||
|
||||
# Évaluer une réponse
|
||||
evaluation = agent.evaluer_reponse(
|
||||
question="Qu'est-ce que le deep learning?",
|
||||
reponse="Le deep learning est une technique d'IA qui utilise des réseaux de neurones profonds."
|
||||
)
|
||||
print(evaluation["evaluation_detaillee"])
|
||||
print("Scores:", evaluation["scores"])
|
||||
```
|
||||
|
||||
## Exemples de workflows complets
|
||||
|
||||
### Workflow d'analyse d'image avec post-traitement
|
||||
|
||||
```python
|
||||
from agents.analyse_image import AgentAnalyseImage
|
||||
from agents.analyse_json import AgentAnalyseJSON
|
||||
from agents.agent_question_reponse import AgentQuestionReponse
|
||||
import json
|
||||
|
||||
# 1. Analyse de l'image
|
||||
agent_image = AgentAnalyseImage("AgentVision")
|
||||
resultats_image = agent_image.executer("chemin/vers/image.jpg")
|
||||
|
||||
# 2. Analyse des résultats JSON
|
||||
agent_json = AgentAnalyseJSON("AgentJSON")
|
||||
resultats_analyse = agent_json.executer(
|
||||
resultats_image,
|
||||
question="Extrais les éléments clés détectés dans l'image."
|
||||
)
|
||||
|
||||
# 3. Génération de questions sur le contenu
|
||||
agent_qr = AgentQuestionReponse("AgentQR")
|
||||
questions = agent_qr.generer_questions(resultats_analyse, nombre=3)
|
||||
|
||||
# 4. Sauvegarde des résultats complets
|
||||
workflow_results = {
|
||||
"analyse_image": resultats_image,
|
||||
"analyse_structure": resultats_analyse,
|
||||
"questions_potentielles": questions
|
||||
}
|
||||
|
||||
with open("resultats_workflow.json", "w", encoding="utf-8") as f:
|
||||
json.dump(workflow_results, f, ensure_ascii=False, indent=2)
|
||||
```
|
||||
|
||||
Ce workflow illustre comment combiner plusieurs agents pour créer une chaîne de traitement complète, de l'analyse d'image initiale jusqu'à la génération de questions pertinentes sur le contenu identifié.
|
||||
337
examples/agent_question_reponse.py
Normal file
337
examples/agent_question_reponse.py
Normal file
@ -0,0 +1,337 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
Agent de questions-réponses utilisant MistralAPI
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import json
|
||||
import argparse
|
||||
from pathlib import Path
|
||||
from typing import Dict, List, Any, Optional
|
||||
from datetime import datetime
|
||||
|
||||
# Ajouter le répertoire parent au sys.path pour importer les modules
|
||||
sys.path.append(str(Path(__file__).parent.parent))
|
||||
|
||||
from agents.base_agent import Agent
|
||||
from core.factory import LLMFactory
|
||||
|
||||
class AgentQuestionReponse(Agent):
|
||||
"""
|
||||
Agent spécialisé dans les questions-réponses utilisant Mistral API
|
||||
"""
|
||||
|
||||
def __init__(self, nom: str, modele: str = "mistral-large-latest"):
|
||||
"""
|
||||
Initialise l'agent avec un nom et un modèle Mistral
|
||||
|
||||
Args:
|
||||
nom: Nom de l'agent
|
||||
modele: Modèle Mistral à utiliser
|
||||
"""
|
||||
super().__init__(nom)
|
||||
self.llm = LLMFactory().create("mistralapi")
|
||||
self.llm.modele = modele
|
||||
|
||||
def executer(self, question: str, contexte: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
|
||||
"""
|
||||
Exécute une requête de question-réponse
|
||||
|
||||
Args:
|
||||
question: La question à poser
|
||||
contexte: Contexte supplémentaire pour la question (optionnel)
|
||||
|
||||
Returns:
|
||||
Dictionnaire contenant la réponse et les métadonnées
|
||||
"""
|
||||
# Formater le prompt avec le contexte si disponible
|
||||
prompt = self._construire_prompt(question, contexte)
|
||||
|
||||
try:
|
||||
# Générer la réponse
|
||||
reponse = self.llm.generate(prompt)
|
||||
|
||||
# Enregistrer dans l'historique
|
||||
input_data = {
|
||||
"type": "question",
|
||||
"contenu": question,
|
||||
"contexte": contexte
|
||||
}
|
||||
output_data = {
|
||||
"type": "reponse",
|
||||
"contenu": reponse
|
||||
}
|
||||
self.ajouter_historique("generation_reponse", input_data, output_data)
|
||||
|
||||
# Préparer le résultat
|
||||
resultat = {
|
||||
"question": question,
|
||||
"reponse": reponse,
|
||||
"timestamp": datetime.now().isoformat(),
|
||||
"modele": self.llm.modele
|
||||
}
|
||||
|
||||
if contexte:
|
||||
resultat["contexte_utilise"] = True
|
||||
|
||||
return resultat
|
||||
|
||||
except Exception as e:
|
||||
return {
|
||||
"erreur": str(e),
|
||||
"question": question,
|
||||
"timestamp": datetime.now().isoformat()
|
||||
}
|
||||
|
||||
def _construire_prompt(self, question: str, contexte: Optional[Dict[str, Any]] = None) -> str:
|
||||
"""
|
||||
Construit le prompt en fonction de la question et du contexte
|
||||
"""
|
||||
if not contexte:
|
||||
return question
|
||||
|
||||
# Formater le contexte en texte
|
||||
contexte_texte = self._formater_contexte(contexte)
|
||||
|
||||
# Construire le prompt avec le contexte
|
||||
prompt = f"""Contexte :
|
||||
{contexte_texte}
|
||||
|
||||
Question : {question}
|
||||
|
||||
Réponds à la question ci-dessus en utilisant le contexte fourni.
|
||||
Si le contexte ne suffit pas pour répondre complètement, indique-le clairement.
|
||||
"""
|
||||
return prompt
|
||||
|
||||
def _formater_contexte(self, contexte: Dict[str, Any]) -> str:
|
||||
"""
|
||||
Formate le contexte en texte lisible
|
||||
"""
|
||||
if isinstance(contexte, str):
|
||||
return contexte
|
||||
|
||||
if isinstance(contexte, dict):
|
||||
# Si le contexte est un dictionnaire JSON
|
||||
try:
|
||||
return json.dumps(contexte, ensure_ascii=False, indent=2)
|
||||
except:
|
||||
parts = []
|
||||
for key, value in contexte.items():
|
||||
parts.append(f"{key}: {value}")
|
||||
return "\n".join(parts)
|
||||
|
||||
# Fallback pour d'autres types
|
||||
return str(contexte)
|
||||
|
||||
def generer_questions(self, contexte: Dict[str, Any], nombre: int = 3) -> List[str]:
|
||||
"""
|
||||
Génère des questions pertinentes basées sur un contexte
|
||||
|
||||
Args:
|
||||
contexte: Le contexte à partir duquel générer des questions
|
||||
nombre: Nombre de questions à générer
|
||||
|
||||
Returns:
|
||||
Liste des questions générées
|
||||
"""
|
||||
contexte_texte = self._formater_contexte(contexte)
|
||||
|
||||
prompt = f"""À partir du contexte suivant :
|
||||
{contexte_texte}
|
||||
|
||||
Génère {nombre} questions pertinentes et intéressantes qui pourraient être posées sur ce contenu.
|
||||
Format attendu : une question par ligne, numérotée (1., 2., etc.)
|
||||
"""
|
||||
|
||||
try:
|
||||
reponse = self.llm.generate(prompt)
|
||||
|
||||
# Extraire les questions de la réponse
|
||||
questions = []
|
||||
for ligne in reponse.split('\n'):
|
||||
ligne = ligne.strip()
|
||||
if ligne and (ligne[0].isdigit() and ligne[1:3] in ['. ', '- ', ') ']):
|
||||
# Extraire la question après le numéro
|
||||
question = ligne[ligne.find(' ')+1:].strip()
|
||||
questions.append(question)
|
||||
|
||||
# Si l'extraction a échoué, retourner la réponse brute divisée
|
||||
if not questions and reponse:
|
||||
questions = [q.strip() for q in reponse.split('\n') if q.strip()]
|
||||
|
||||
return questions[:nombre] # Limiter au nombre demandé
|
||||
|
||||
except Exception as e:
|
||||
print(f"Erreur lors de la génération de questions: {e}")
|
||||
return []
|
||||
|
||||
def evaluer_reponse(self, question: str, reponse: str, reference: Optional[str] = None) -> Dict[str, Any]:
|
||||
"""
|
||||
Évalue la qualité d'une réponse à une question
|
||||
|
||||
Args:
|
||||
question: La question posée
|
||||
reponse: La réponse à évaluer
|
||||
reference: Réponse de référence (optionnelle)
|
||||
|
||||
Returns:
|
||||
Dictionnaire contenant l'évaluation et les scores
|
||||
"""
|
||||
if reference:
|
||||
prompt = f"""Question : {question}
|
||||
|
||||
Réponse à évaluer :
|
||||
{reponse}
|
||||
|
||||
Réponse de référence :
|
||||
{reference}
|
||||
|
||||
Évalue la réponse fournie par rapport à la réponse de référence. Attribue un score pour chaque critère :
|
||||
1. Précision (1-10) : La réponse est-elle factuelle et correcte ?
|
||||
2. Complétude (1-10) : La réponse couvre-t-elle tous les aspects importants ?
|
||||
3. Clarté (1-10) : La réponse est-elle claire et facile à comprendre ?
|
||||
|
||||
Pour chaque critère, justifie brièvement ton score. Termine par une note globale sur 10.
|
||||
"""
|
||||
else:
|
||||
prompt = f"""Question : {question}
|
||||
|
||||
Réponse à évaluer :
|
||||
{reponse}
|
||||
|
||||
Évalue la qualité de cette réponse. Attribue un score pour chaque critère :
|
||||
1. Précision (1-10) : La réponse semble-t-elle factuelle et correcte ?
|
||||
2. Complétude (1-10) : La réponse semble-t-elle couvrir tous les aspects importants ?
|
||||
3. Clarté (1-10) : La réponse est-elle claire et facile à comprendre ?
|
||||
|
||||
Pour chaque critère, justifie brièvement ton score. Termine par une note globale sur 10.
|
||||
"""
|
||||
|
||||
try:
|
||||
evaluation = self.llm.generate(prompt)
|
||||
|
||||
# Tenter d'extraire les scores numériques
|
||||
scores = {}
|
||||
|
||||
for ligne in evaluation.split('\n'):
|
||||
if "précision" in ligne.lower() and ":" in ligne:
|
||||
try:
|
||||
score = int([s for s in ligne.split() if s.isdigit()][0])
|
||||
scores["precision"] = score
|
||||
except:
|
||||
pass
|
||||
|
||||
elif "complétude" in ligne.lower() and ":" in ligne:
|
||||
try:
|
||||
score = int([s for s in ligne.split() if s.isdigit()][0])
|
||||
scores["completude"] = score
|
||||
except:
|
||||
pass
|
||||
|
||||
elif "clarté" in ligne.lower() and ":" in ligne:
|
||||
try:
|
||||
score = int([s for s in ligne.split() if s.isdigit()][0])
|
||||
scores["clarte"] = score
|
||||
except:
|
||||
pass
|
||||
|
||||
elif "globale" in ligne.lower() and ":" in ligne:
|
||||
try:
|
||||
score = int([s for s in ligne.split() if s.isdigit()][0])
|
||||
scores["globale"] = score
|
||||
except:
|
||||
pass
|
||||
|
||||
return {
|
||||
"evaluation_detaillee": evaluation,
|
||||
"scores": scores
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
return {
|
||||
"erreur": str(e),
|
||||
"evaluation_detaillee": "Échec de l'évaluation"
|
||||
}
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser(description="Agent de Questions-Réponses avec Mistral API")
|
||||
parser.add_argument("--question", help="Question à poser")
|
||||
parser.add_argument("--contexte", help="Chemin vers un fichier JSON de contexte")
|
||||
parser.add_argument("--model", default="mistral-large-latest", help="Modèle Mistral à utiliser")
|
||||
parser.add_argument("--generer-questions", action="store_true", help="Générer des questions à partir du contexte")
|
||||
parser.add_argument("--nombre", type=int, default=3, help="Nombre de questions à générer")
|
||||
parser.add_argument("--evaluer", help="Réponse à évaluer (nécessite --question)")
|
||||
parser.add_argument("--reference", help="Réponse de référence pour l'évaluation")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
# Vérification de la clé API
|
||||
if not os.environ.get("MISTRAL_API_KEY"):
|
||||
print("Erreur: Variable d'environnement MISTRAL_API_KEY non définie.")
|
||||
print("Veuillez définir cette variable avec votre clé API Mistral.")
|
||||
print("Exemple: export MISTRAL_API_KEY=votre_clé_api")
|
||||
sys.exit(1)
|
||||
|
||||
# Initialisation de l'agent
|
||||
agent = AgentQuestionReponse("AgentQR", modele=args.model)
|
||||
|
||||
# Chargement du contexte si spécifié
|
||||
contexte = None
|
||||
if args.contexte:
|
||||
try:
|
||||
with open(args.contexte, 'r', encoding='utf-8') as f:
|
||||
contexte = json.load(f)
|
||||
print(f"Contexte chargé depuis {args.contexte}")
|
||||
except Exception as e:
|
||||
print(f"Erreur lors du chargement du contexte: {e}")
|
||||
sys.exit(1)
|
||||
|
||||
# Génération de questions à partir du contexte
|
||||
if args.generer_questions and contexte:
|
||||
print(f"\n=== Génération de {args.nombre} questions à partir du contexte ===")
|
||||
questions = agent.generer_questions(contexte, nombre=args.nombre)
|
||||
|
||||
print("\nQuestions générées:")
|
||||
for i, question in enumerate(questions, 1):
|
||||
print(f"{i}. {question}")
|
||||
sys.exit(0)
|
||||
|
||||
# Évaluation d'une réponse
|
||||
if args.evaluer and args.question:
|
||||
print("\n=== Évaluation de la réponse ===")
|
||||
evaluation = agent.evaluer_reponse(args.question, args.evaluer, args.reference)
|
||||
|
||||
if "erreur" in evaluation:
|
||||
print(f"Erreur: {evaluation['erreur']}")
|
||||
else:
|
||||
print("\nÉvaluation détaillée:")
|
||||
print(evaluation["evaluation_detaillee"])
|
||||
|
||||
if evaluation.get("scores"):
|
||||
print("\nScores:")
|
||||
for critere, score in evaluation["scores"].items():
|
||||
print(f"- {critere.capitalize()}: {score}/10")
|
||||
|
||||
sys.exit(0)
|
||||
|
||||
# Traitement d'une question simple
|
||||
if args.question:
|
||||
print(f"\n=== Traitement de la question avec le modèle {args.model} ===")
|
||||
print(f"Question: {args.question}")
|
||||
|
||||
resultat = agent.executer(args.question, contexte)
|
||||
|
||||
if "erreur" in resultat:
|
||||
print(f"Erreur: {resultat['erreur']}")
|
||||
else:
|
||||
print("\nRéponse:")
|
||||
print(resultat["reponse"])
|
||||
|
||||
sys.exit(0)
|
||||
|
||||
# Si aucune action spécifiée
|
||||
parser.print_help()
|
||||
137
examples/analyse_image_workflow.py
Normal file
137
examples/analyse_image_workflow.py
Normal file
@ -0,0 +1,137 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
Script d'exemple pour montrer l'utilisation des agents d'analyse d'image et JSON
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import json
|
||||
import argparse
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
|
||||
# Ajouter le répertoire parent au sys.path pour importer les modules
|
||||
sys.path.append(str(Path(__file__).parent.parent))
|
||||
|
||||
from agents.analyse_image import AgentAnalyseImage
|
||||
from agents.analyse_json import AgentAnalyseJSON
|
||||
|
||||
def create_output_dir():
|
||||
"""Crée un répertoire pour les sorties basé sur la date/heure"""
|
||||
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
||||
output_dir = f"outputs/vision_{timestamp}"
|
||||
os.makedirs(output_dir, exist_ok=True)
|
||||
return output_dir
|
||||
|
||||
def analyse_directe(image_path, output_dir):
|
||||
"""Analyse directe avec l'agent d'analyse d'image"""
|
||||
print(f"\n=== Analyse directe de l'image {os.path.basename(image_path)} ===")
|
||||
|
||||
# Création d'une instance AgentAnalyseImage
|
||||
agent = AgentAnalyseImage("AgentVision")
|
||||
|
||||
# Analyse de l'image avec une question spécifique
|
||||
question = "Décris en détail cette image. Qu'est-ce que tu y vois? Y a-t-il du texte visible?"
|
||||
print(f"Question: {question}")
|
||||
|
||||
resultats = agent.executer(image_path, question=question)
|
||||
|
||||
if "erreur" in resultats:
|
||||
print(f"Erreur: {resultats['erreur']}")
|
||||
return
|
||||
|
||||
# Affichage du résultat
|
||||
print("\nRéponse:")
|
||||
for analyse in resultats["analyses"]:
|
||||
print(f"\n{analyse['reponse']}")
|
||||
|
||||
# Sauvegarde du résultat
|
||||
output_file = os.path.join(output_dir, "resultat_direct.json")
|
||||
agent.sauvegarder_resultats(output_file, resultats)
|
||||
print(f"\nRésultat sauvegardé dans: {output_file}")
|
||||
|
||||
def workflow_complet(image_path, json_path=None, output_dir=None):
|
||||
"""Workflow complet: analyse image puis analyse JSON"""
|
||||
print(f"\n=== Workflow complet pour l'image {os.path.basename(image_path)} ===")
|
||||
|
||||
if output_dir is None:
|
||||
output_dir = create_output_dir()
|
||||
|
||||
# Étape 1: Analyse de l'image
|
||||
print("\nÉtape 1: Analyse de l'image")
|
||||
agent_image = AgentAnalyseImage("AgentVision")
|
||||
|
||||
# Chargement des données JSON si spécifiées
|
||||
json_data = None
|
||||
if json_path:
|
||||
try:
|
||||
with open(json_path, 'r', encoding='utf-8') as f:
|
||||
json_data = json.load(f)
|
||||
print(f"Données JSON chargées depuis {json_path}")
|
||||
except Exception as e:
|
||||
print(f"Erreur lors du chargement du JSON: {e}")
|
||||
|
||||
# Exécution de l'analyse d'image
|
||||
resultats_image = agent_image.executer(image_path, json_data)
|
||||
|
||||
# Sauvegarde des résultats intermédiaires
|
||||
image_output_file = os.path.join(output_dir, "analyse_image.json")
|
||||
agent_image.sauvegarder_resultats(image_output_file, resultats_image)
|
||||
print(f"Analyse d'image sauvegardée dans: {image_output_file}")
|
||||
|
||||
# Étape 2: Analyse des résultats JSON
|
||||
print("\nÉtape 2: Analyse approfondie des résultats")
|
||||
agent_json = AgentAnalyseJSON("AgentAnalyseJSON")
|
||||
|
||||
# Analyse des résultats de l'image
|
||||
question_json = "Analyse les résultats de l'analyse d'image et extrait les éléments clés."
|
||||
resultats_analyse = agent_json.executer(resultats_image, question_json)
|
||||
|
||||
# Sauvegarde des résultats d'analyse
|
||||
json_output_file = os.path.join(output_dir, "analyse_complete.json")
|
||||
with open(json_output_file, 'w', encoding='utf-8') as f:
|
||||
json.dump(resultats_analyse, f, ensure_ascii=False, indent=2)
|
||||
print(f"Analyse complète sauvegardée dans: {json_output_file}")
|
||||
|
||||
# Fusion des résultats
|
||||
resultats_finaux = {
|
||||
"image": image_path,
|
||||
"timestamp": datetime.now().isoformat(),
|
||||
"analyse_image": resultats_image,
|
||||
"analyse_json": resultats_analyse
|
||||
}
|
||||
|
||||
# Sauvegarde des résultats finaux
|
||||
final_output_file = os.path.join(output_dir, "resultats_finaux.json")
|
||||
with open(final_output_file, 'w', encoding='utf-8') as f:
|
||||
json.dump(resultats_finaux, f, ensure_ascii=False, indent=2)
|
||||
print(f"Résultats finaux sauvegardés dans: {final_output_file}")
|
||||
|
||||
return resultats_finaux
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser(description="Analyse d'images avec les agents")
|
||||
parser.add_argument("--image", required=True, help="Chemin vers l'image à analyser")
|
||||
parser.add_argument("--json", help="Chemin vers un fichier JSON complémentaire (optionnel)")
|
||||
parser.add_argument("--mode", choices=["direct", "complet"], default="complet",
|
||||
help="Mode d'analyse: direct (simple) ou complet (workflow)")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
# Vérification de l'existence de l'image
|
||||
if not os.path.exists(args.image):
|
||||
print(f"Erreur: L'image {args.image} n'existe pas")
|
||||
sys.exit(1)
|
||||
|
||||
# Création du répertoire de sortie
|
||||
output_dir = create_output_dir()
|
||||
|
||||
# Exécution du mode choisi
|
||||
if args.mode == "direct":
|
||||
analyse_directe(args.image, output_dir)
|
||||
else:
|
||||
workflow_complet(args.image, args.json, output_dir)
|
||||
|
||||
print("\nAnalyse terminée !")
|
||||
103
examples/test_mistralapi.py
Normal file
103
examples/test_mistralapi.py
Normal file
@ -0,0 +1,103 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
Script d'exemple pour montrer l'utilisation de la classe MistralAPI
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import argparse
|
||||
from pathlib import Path
|
||||
|
||||
# Ajouter le répertoire parent au sys.path pour importer les modules
|
||||
sys.path.append(str(Path(__file__).parent.parent))
|
||||
|
||||
from core.factory import LLMFactory
|
||||
|
||||
def afficher_modeles_disponibles():
|
||||
"""Affiche les modèles disponibles via l'API Mistral"""
|
||||
# Création d'une instance MistralAPI via la factory
|
||||
llm = LLMFactory().create("mistralapi")
|
||||
|
||||
try:
|
||||
modeles = llm.obtenir_liste_modeles()
|
||||
print("\n=== Modèles disponibles sur l'API Mistral ===")
|
||||
|
||||
if not modeles:
|
||||
print("Aucun modèle trouvé ou erreur de récupération.")
|
||||
return
|
||||
|
||||
for i, modele in enumerate(modeles, 1):
|
||||
print(f"{i}. {modele}")
|
||||
|
||||
except Exception as e:
|
||||
print(f"Erreur lors de la récupération des modèles: {e}")
|
||||
|
||||
def generer_reponse(prompt, modele=None, temperature=None, max_tokens=None):
|
||||
"""Génère une réponse avec MistralAPI"""
|
||||
# Création d'une instance MistralAPI via la factory
|
||||
llm = LLMFactory().create("mistralapi")
|
||||
|
||||
# Configuration des paramètres si spécifiés
|
||||
if modele:
|
||||
llm.modele = modele
|
||||
|
||||
if temperature is not None:
|
||||
llm.parametres_generation["temperature"] = temperature
|
||||
|
||||
if max_tokens is not None:
|
||||
llm.parametres_generation["max_tokens"] = max_tokens
|
||||
|
||||
# Affichage des paramètres utilisés
|
||||
print(f"\n=== Génération avec MistralAPI ===")
|
||||
print(f"Modèle: {llm.modele}")
|
||||
print(f"Température: {llm.parametres_generation['temperature']}")
|
||||
print(f"Max tokens: {llm.parametres_generation.get('max_tokens', 'Non spécifié')}")
|
||||
print(f"\nPrompt: {prompt}\n")
|
||||
|
||||
try:
|
||||
# Génération de la réponse
|
||||
reponse = llm.generate(prompt)
|
||||
|
||||
# Affichage de la réponse
|
||||
print("\n=== Réponse ===")
|
||||
print(reponse)
|
||||
|
||||
return reponse
|
||||
|
||||
except Exception as e:
|
||||
print(f"Erreur lors de la génération: {e}")
|
||||
return None
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser(description="Test de l'API Mistral")
|
||||
parser.add_argument("--list-models", action="store_true", help="Afficher les modèles disponibles")
|
||||
parser.add_argument("--prompt", help="Prompt pour générer une réponse")
|
||||
parser.add_argument("--model", help="Nom du modèle à utiliser (ex: mistral-large-latest)")
|
||||
parser.add_argument("--temperature", type=float, help="Température pour la génération (0.0-1.0)")
|
||||
parser.add_argument("--max-tokens", type=int, help="Nombre maximum de tokens à générer")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
# Vérification de la clé API dans l'environnement
|
||||
if not os.environ.get("MISTRAL_API_KEY"):
|
||||
print("Erreur: Variable d'environnement MISTRAL_API_KEY non définie.")
|
||||
print("Veuillez définir cette variable avec votre clé API Mistral.")
|
||||
print("Exemple: export MISTRAL_API_KEY=votre_clé_api")
|
||||
sys.exit(1)
|
||||
|
||||
# Exécution en fonction des arguments
|
||||
if args.list_models:
|
||||
afficher_modeles_disponibles()
|
||||
|
||||
elif args.prompt:
|
||||
generer_reponse(
|
||||
args.prompt,
|
||||
modele=args.model,
|
||||
temperature=args.temperature,
|
||||
max_tokens=args.max_tokens
|
||||
)
|
||||
|
||||
else:
|
||||
parser.print_help()
|
||||
65
tests/test_agent.py
Normal file
65
tests/test_agent.py
Normal file
@ -0,0 +1,65 @@
|
||||
import unittest
|
||||
import os
|
||||
import sys
|
||||
import json
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
|
||||
# Ajouter le répertoire parent au sys.path pour importer les modules
|
||||
sys.path.append(str(Path(__file__).parent.parent))
|
||||
|
||||
from agents.base_agent import Agent
|
||||
|
||||
class TestAgent(unittest.TestCase):
|
||||
"""Tests pour la classe Agent de base"""
|
||||
|
||||
def setUp(self):
|
||||
"""Initialisation pour chaque test"""
|
||||
self.agent = Agent(nom="TestAgent")
|
||||
|
||||
def test_initialisation(self):
|
||||
"""Test de l'initialisation correcte de l'agent"""
|
||||
self.assertEqual(self.agent.nom, "TestAgent")
|
||||
self.assertEqual(len(self.agent.historique), 0)
|
||||
|
||||
def test_ajouter_historique(self):
|
||||
"""Test de l'ajout d'entrées dans l'historique"""
|
||||
self.agent.ajouter_historique("test_action", "données d'entrée", "données de sortie")
|
||||
|
||||
self.assertEqual(len(self.agent.historique), 1)
|
||||
entry = self.agent.historique[0]
|
||||
|
||||
self.assertEqual(entry["action"], "test_action")
|
||||
self.assertEqual(entry["input"], "données d'entrée")
|
||||
self.assertEqual(entry["output"], "données de sortie")
|
||||
self.assertTrue("timestamp" in entry)
|
||||
|
||||
def test_obtenir_historique(self):
|
||||
"""Test de la récupération de l'historique"""
|
||||
# Ajouter plusieurs entrées
|
||||
self.agent.ajouter_historique("action1", "entrée1", "sortie1")
|
||||
self.agent.ajouter_historique("action2", "entrée2", "sortie2")
|
||||
|
||||
historique = self.agent.obtenir_historique()
|
||||
|
||||
self.assertEqual(len(historique), 2)
|
||||
self.assertEqual(historique[0]["action"], "action1")
|
||||
self.assertEqual(historique[1]["action"], "action2")
|
||||
|
||||
def test_executer_not_implemented(self):
|
||||
"""Test que la méthode executer lève une NotImplementedError"""
|
||||
with self.assertRaises(NotImplementedError):
|
||||
self.agent.executer()
|
||||
|
||||
def test_limite_taille_historique(self):
|
||||
"""Test de la limite de taille dans l'historique"""
|
||||
# Créer une entrée avec une chaîne très longue
|
||||
longue_chaine = "x" * 1000
|
||||
self.agent.ajouter_historique("test_limite", longue_chaine, longue_chaine)
|
||||
|
||||
entry = self.agent.historique[0]
|
||||
self.assertEqual(len(entry["input"]), 500) # Limite à 500 caractères
|
||||
self.assertEqual(len(entry["output"]), 500) # Limite à 500 caractères
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Loading…
x
Reference in New Issue
Block a user