mirror of
https://github.com/Ladebeze66/llm_lab.git
synced 2025-12-13 10:46:50 +01:00
186 lines
7.0 KiB
Python
186 lines
7.0 KiB
Python
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):
|
|
def __init__(self):
|
|
model_name = "llama3.2-vision:90b"
|
|
engine = "Ollama"
|
|
|
|
self.api_url = "http://217.182.105.173:11434/api/chat"
|
|
|
|
default_params = {
|
|
# 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)
|
|
|
|
# Attributs spécifiques pour Llama Vision
|
|
self.image_data = None
|
|
self.json_data = {}
|
|
|
|
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()
|
|
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
|
|
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 generate(self, user_prompt: str, images: list = None, translate: bool = False):
|
|
prompt = self._format_prompt(user_prompt)
|
|
|
|
# Si des images sont fournies directement, utilisez-les
|
|
images_to_use = images if images else []
|
|
|
|
# Si image_data est défini et aucune image n'est fournie explicitement
|
|
if self.image_data is not None and not images:
|
|
# Encodage en base64 si ce n'est pas déjà fait
|
|
if isinstance(self.image_data, bytes):
|
|
encoded_image = base64.b64encode(self.image_data).decode('utf-8')
|
|
images_to_use = [encoded_image]
|
|
|
|
# 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_to_use
|
|
}
|
|
],
|
|
"options": self.params,
|
|
"stream": self.params.get("stream", False)
|
|
}
|
|
|
|
response = requests.post(self.api_url, json=payload)
|
|
|
|
if not response.ok:
|
|
raise Exception(f"Erreur API Ollama : {response.status_code} - {response.text}")
|
|
|
|
result_data = response.json()
|
|
result_text = result_data.get("message", {}).get("content", "")
|
|
|
|
self._log_result(user_prompt, result_text)
|
|
|
|
# Stockage du résultat pour fusion ultérieure
|
|
self.dernier_resultat = result_data
|
|
|
|
if translate:
|
|
result_fr = GoogleTranslator(source="auto", target="fr").translate(result_text)
|
|
return result_text, result_fr
|
|
|
|
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
|
|
"""
|
|
if not hasattr(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
|
|
"""
|
|
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 |