2025-03-24 17:34:55 +01:00

149 lines
4.7 KiB
Python

import abc
import json
import time
import requests
from datetime import datetime, timedelta
from typing import Dict, List, Any, Optional, Union
class LLM(abc.ABC):
"""Classe abstraite de base pour tous les modèles LLM"""
def __init__(self):
"""Initialisation des attributs communs"""
# Attributs publics
self.Modele: str = ""
self.prompt_system: str = ""
self.o_temperature: float = 0.8
self.o_top_k: int = 40
self.o_top_p: float = 0.9
# Constantes publiques
self.dureeTraitement: timedelta = timedelta()
self.reponseErreur: bool = False
# Attributs protégés
self._Contenu: Dict[str, Any] = {}
self._m_sUrlFonction: str = ""
self._stream: bool = False
self._m_sFormat: str = ""
self._heureDepart: Optional[datetime] = None
self._heureFin: Optional[datetime] = None
# Initialisation par défaut
self._stream = False
@property
def urlFonction(self) -> str:
"""Getter pour l'URL de la fonction"""
return self._m_sUrlFonction
@urlFonction.setter
def urlFonction(self, valeur: str):
"""Setter pour l'URL de la fonction"""
self._m_sUrlFonction = valeur
@property
def format(self) -> str:
"""Getter pour le format"""
return self._m_sFormat
@format.setter
def format(self, valeur: str):
"""Setter pour le format"""
self._m_sFormat = valeur
def model_list(self) -> List[str]:
"""Retourne la liste des modèles disponibles"""
return []
def commandeAutorisation(self) -> str:
"""Retourne la commande d'autorisation à utiliser pour les API"""
return "Bearer"
def Interroger(self, question: str) -> str:
"""Interroge le LLM avec une question et retourne la réponse"""
response = self.LLM_POST(question)
return response
def LLM_POST(self, question: str) -> str:
"""
Méthode interne pour communiquer avec l'API du LLM
Cette méthode gère les appels HTTP et le formattage de la réponse
"""
erreur = ""
reponse = ""
# Préparation de la requête
url = self.urlBase() + self.urlFonction
headers = {
"Content-Type": "application/json"
}
# Ajout de l'autorisation si nécessaire
if self.cleAPI() != "":
headers["Authorization"] = f"{self.commandeAutorisation()} {self.cleAPI()}"
# Préparation du contenu
self._Contenu = {}
if self.Modele != "":
self._Contenu["model"] = self.Modele
# Préparation spécifique à la classe fille
self._even_LLM_POST(question)
# Envoi de la requête
self._heureDepart = datetime.now()
try:
# Timeout de 2 minutes (équivalent à duréeNonRéponse = 2min)
response = requests.post(
url=url,
headers=headers,
json=self._Contenu,
timeout=120
)
self._heureFin = datetime.now()
self.dureeTraitement = self._heureFin - self._heureDepart
# Traitement de la réponse
if response.status_code in [200, 201]:
reponse = self._interrogerRetourneReponse(response.text)
self.reponseErreur = False
return reponse
else:
erreur = response.text
self.reponseErreur = True
return erreur
except Exception as e:
self._heureFin = datetime.now()
self.dureeTraitement = self._heureFin - self._heureDepart
self.reponseErreur = True
return str(e)
@abc.abstractmethod
def urlBase(self) -> str:
"""Retourne l'URL de base de l'API (à implémenter dans les classes filles)"""
pass
@abc.abstractmethod
def cleAPI(self) -> str:
"""Retourne la clé API à utiliser (à implémenter dans les classes filles)"""
pass
@abc.abstractmethod
def _even_LLM_POST(self, question: str) -> None:
"""
Méthode appelée lors de la préparation de la requête POST
Permet de personnaliser le contenu pour chaque type de LLM
"""
pass
@abc.abstractmethod
def _interrogerRetourneReponse(self, reponse: str) -> str:
"""
Méthode pour extraire la réponse du LLM à partir du JSON retourné
À implémenter selon le format de réponse spécifique à chaque LLM
"""
pass