AIagent/llm_classes/llama_vision.py
2025-03-24 17:34:55 +01:00

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