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