mirror of
https://github.com/Ladebeze66/AIagent.git
synced 2025-12-15 19:26:49 +01:00
216 lines
7.9 KiB
Python
216 lines
7.9 KiB
Python
import json
|
|
import base64
|
|
import os
|
|
from typing import Dict, List, Any, Optional, Union, Tuple
|
|
from datetime import timedelta
|
|
import requests
|
|
from .llm import LLM
|
|
|
|
class LlamaVision(LLM):
|
|
"""
|
|
Classe pour l'intégration avec le modèle Llama Vision 3.2 90B
|
|
Cette classe hérite de la classe de base LLM et ajoute le support des images
|
|
"""
|
|
|
|
def __init__(self):
|
|
"""
|
|
Initialisation des attributs spécifiques à Llama Vision
|
|
"""
|
|
super().__init__()
|
|
|
|
# Configuration du modèle
|
|
self.Modele = "llama-vision:3.2-90b"
|
|
|
|
# Attributs spécifiques pour Llama Vision
|
|
self.image_path: str = ""
|
|
self.image_data: Optional[bytes] = None
|
|
self.json_data: Dict[str, Any] = {}
|
|
|
|
# Paramètres de génération
|
|
self.o_mirostat: int = 0
|
|
self.o_mirostat_eta: float = 0.1
|
|
self.o_mirostat_tau: float = 5
|
|
self.o_num_ctx: int = 4096 # Contexte plus large pour les images + texte
|
|
self.o_repeat_last_n: int = 64
|
|
self.o_repeat_penalty: float = 1.1
|
|
self.o_temperature: float = 0.7 # Valeur par défaut adaptée pour les descriptions d'images
|
|
self.o_seed: int = 0
|
|
self.o_stop: List[str] = []
|
|
self.o_num_predict: int = 1024 # Nombre de tokens à prédire
|
|
self.o_top_k: int = 40
|
|
self.o_top_p: float = 0.9
|
|
self.o_min_p: float = 0
|
|
|
|
# Options supplémentaires
|
|
self.keep_alive: timedelta = timedelta(minutes=5)
|
|
self.raw: bool = False
|
|
self._stream: bool = False
|
|
|
|
# Stockage des résultats
|
|
self.dernier_resultat: Dict[str, Any] = {}
|
|
self.historique_resultats: List[Dict[str, Any]] = []
|
|
|
|
def urlBase(self) -> str:
|
|
"""
|
|
Retourne l'URL de base de l'API Ollama pour Llama Vision
|
|
"""
|
|
return "http:/217.182.105.173/:11434/"
|
|
|
|
def cleAPI(self) -> str:
|
|
"""
|
|
Retourne la clé API (vide pour Ollama local)
|
|
"""
|
|
return ""
|
|
|
|
def set_image(self, image_path: str) -> bool:
|
|
"""
|
|
Définit l'image à analyser à partir d'un chemin de fichier
|
|
Retourne True si l'image a été chargée avec succès
|
|
"""
|
|
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
|
|
"""
|
|
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
|
|
"""
|
|
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 Interroger(self, question: str) -> str:
|
|
"""
|
|
Interroge le modèle Llama Vision avec une question et l'image chargée
|
|
"""
|
|
if not self.image_data:
|
|
return "Erreur: Aucune image n'a été chargée. Utilisez set_image() ou set_image_data() d'abord."
|
|
|
|
return self.LLM_POST(question)
|
|
|
|
def _even_LLM_POST(self, question: str) -> None:
|
|
"""
|
|
Préparation du contenu de la requête pour Llama Vision
|
|
"""
|
|
# Paramètres de base
|
|
self._Contenu["model"] = self.Modele
|
|
self._Contenu["system"] = self.prompt_system if self.prompt_system else "Tu es un assistant d'analyse d'images qui peut analyser des images et répondre à des questions en français. Sois précis et détaillé dans tes descriptions."
|
|
self._Contenu["prompt"] = question
|
|
self._Contenu["stream"] = self._stream
|
|
self._Contenu["raw"] = self.raw
|
|
|
|
# Ajout de l'image en base64
|
|
if self.image_data:
|
|
base64_image = base64.b64encode(self.image_data).decode('utf-8')
|
|
self._Contenu["images"] = [base64_image]
|
|
|
|
# Conversion de timedelta en nombre de secondes pour keep_alive
|
|
if isinstance(self.keep_alive, timedelta):
|
|
self._Contenu["keep_alive"] = int(self.keep_alive.total_seconds())
|
|
|
|
# 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
|
|
self._Contenu["prompt"] = f"{question}\n\nVoici des données JSON associées à cette image:\n```json\n{json_str}\n```"
|
|
|
|
# Options avancées pour la génération
|
|
self._Contenu["options"] = {
|
|
"mirostat": self.o_mirostat,
|
|
"mirostat_eta": self.o_mirostat_eta,
|
|
"mirostat_tau": self.o_mirostat_tau,
|
|
"num_ctx": self.o_num_ctx,
|
|
"repeat_last_n": self.o_repeat_last_n,
|
|
"repeat_penalty": self.o_repeat_penalty,
|
|
"temperature": self.o_temperature,
|
|
"seed": self.o_seed,
|
|
"stop": self.o_stop,
|
|
"num_predict": self.o_num_predict,
|
|
"top_k": self.o_top_k,
|
|
"top_p": self.o_top_p,
|
|
"min_p": self.o_min_p
|
|
}
|
|
|
|
def _interrogerRetourneReponse(self, reponse: str) -> str:
|
|
"""
|
|
Extraction de la réponse à partir du JSON retourné par Llama Vision
|
|
"""
|
|
try:
|
|
data = json.loads(reponse)
|
|
self.dernier_resultat = data
|
|
self.historique_resultats.append(data)
|
|
|
|
# Ollama retourne généralement la réponse dans la clé "response"
|
|
if "response" in data:
|
|
return data["response"]
|
|
else:
|
|
return str(data)
|
|
except Exception as e:
|
|
return f"Erreur lors de l'analyse de la réponse: {e}\n\nRéponse brute: {reponse}"
|
|
|
|
def fusionner_json_avec_resultats(self) -> Dict[str, Any]:
|
|
"""
|
|
Fusionne les données JSON existantes avec les résultats de l'analyse d'image
|
|
"""
|
|
if 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.Modele,
|
|
"reponse": self.dernier_resultat.get("response", ""),
|
|
"parametres": {
|
|
"temperature": self.o_temperature,
|
|
"top_p": self.o_top_p,
|
|
"num_ctx": self.o_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
|
|
"""
|
|
try:
|
|
resultats_fusionnes = self.fusionner_json_avec_resultats()
|
|
|
|
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 |