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

272 lines
9.6 KiB
Python

import json
from typing import Dict, List, Any, Optional, Union, Tuple
from .llm import LLM
class DeepL(LLM):
"""
Classe pour l'intégration avec l'API DeepL
Cette classe hérite de la classe de base LLM et permet de faire des traductions
"""
def __init__(self):
"""
Initialisation des attributs spécifiques à DeepL
"""
super().__init__()
# Attributs spécifiques à DeepL
self.langueSource: str = "FR"
self.langueDesti: str = "EN"
self.context: str = ""
self.split_sentences: str = "0"
self.preserve_formatting: bool = True
self.formality: str = "default" # Options: more, less, prefer_more, prefer_less
self.show_billed_characters: bool = False
self.tag_handling: str = "" # Options: xml, html
self.outline_detection: bool = True
self.non_splitting_tags: List[str] = []
self.splitting_tags: List[str] = []
self.ignore_tags: List[str] = []
# Constantes publiques (modifiées en attributs en Python)
self.glossaire_id: Dict[str, str] = {} # tableau associatif (ccSansCasse) de chaînes
self._m_tabGlossaireListePaire: List[List[str]] = [] # tableau de 0 par 2 chaînes
# Initialisation par défaut
self.langueSource = "FR"
self.langueDesti = "EN"
self.Modele = "prefer_quality_optimized"
self.split_sentences = "0"
self.preserve_formatting = True
self.formality = "default"
self.show_billed_characters = False
self.tag_handling = ""
self.outline_detection = True
def commandeAutorisation(self) -> str:
"""
Retourne la commande d'autorisation pour DeepL
"""
return "DeepL-Auth-Key"
def cleAPI(self) -> str:
"""
Retourne la clé API DeepL
"""
return "d42ee2f7-f4e6-d437-3237-fa40b4f45e65"
def urlBase(self) -> str:
"""
Retourne l'URL de base de l'API DeepL
"""
return "https://api.deepl.com/v2/"
def urlFonction(self) -> str:
"""
Retourne l'URL de la fonction par défaut (translate)
"""
return "translate"
def model_list(self) -> List[str]:
"""
Retourne la liste des modèles disponibles pour DeepL
"""
return ["quality_optimized", "latency_optimized", "prefer_quality_optimized"]
def glossaire_liste_paire_possible(self) -> List[List[str]]:
"""
Récupère la liste des paires de langues possibles pour les glossaires
"""
import requests
if len(self._m_tabGlossaireListePaire) > 1:
return self._m_tabGlossaireListePaire
url = self.urlBase() + "glossary-language-pairs"
headers = {
"Content-Type": "application/json"
}
if self.cleAPI() != "":
headers["Authorization"] = f"{self.commandeAutorisation()} {self.cleAPI()}"
try:
response = requests.get(url=url, headers=headers)
if response.status_code == 200:
data = json.loads(response.text)
self._m_tabGlossaireListePaire = []
for item in data["supported_languages"]:
self._m_tabGlossaireListePaire.append([
item["source_lang"],
item["target_lang"]
])
else:
self._m_tabGlossaireListePaire.append([response.text])
except Exception as e:
self._m_tabGlossaireListePaire.append([str(e)])
return self._m_tabGlossaireListePaire
def _even_LLM_POST(self, question: str) -> None:
"""
Préparation du contenu de la requête pour DeepL
"""
# Paramètre principal - le texte à traduire
self._Contenu["text"] = [question]
self._Contenu["source_lang"] = self.langueSource
self._Contenu["target_lang"] = self.langueDesti
# Ajout du contexte si défini
if self.context:
self._Contenu["context"] = self.context
# Définition du modèle
self._Contenu["model_type"] = self.Modele
# Options supplémentaires
self._Contenu["split_sentences"] = self.split_sentences
self._Contenu["preserve_formatting"] = self.preserve_formatting
self._Contenu["formality"] = self.formality
# Ajout du glossaire si disponible
glossaire_id = self._glossaireRetrouveID(self.langueSource, self.langueDesti)
if glossaire_id:
self._Contenu["glossary_id"] = glossaire_id
# Options avancées
self._Contenu["show_billed_characters"] = self.show_billed_characters
self._Contenu["tag_handling"] = self.tag_handling
self._Contenu["outline_detection"] = self.outline_detection
# Ajout des tags non-splittants si définis
if self.non_splitting_tags:
self._Contenu["non_splitting_tags"] = self.non_splitting_tags
# Ajout des tags splittants si définis
if self.splitting_tags:
self._Contenu["splitting_tags"] = self.splitting_tags
# Ajout des tags à ignorer si définis
if self.ignore_tags:
self._Contenu["ignore_tags"] = self.ignore_tags
def _interrogerRetourneReponse(self, reponse: str) -> str:
"""
Extraction de la réponse à partir du JSON retourné par DeepL
"""
data = json.loads(reponse)
return data["translations"][0]["text"]
def glossaire_cree(self, sLanguageSource: str, sLangageDesti: str, sEntrees: str, sFormat: str = "tsv") -> str:
"""
Crée un glossaire avec les entrées fournies
Format des entrées:
- tsv : source<tab>cible<RC>
- csv : source,cible<RC>
"""
import requests
# Supprime le glossaire existant si présent
sID = self._glossaireRetrouveID(sLanguageSource, sLangageDesti)
if sID:
self._glossaireSupprime(sID)
url = self.urlBase() + "glossaries"
headers = {
"Content-Type": "application/json"
}
if self.cleAPI():
headers["Authorization"] = f"{self.commandeAutorisation()} {self.cleAPI()}"
# Préparation des paramètres
params = {
"name": f"{sLanguageSource.upper()}_{sLangageDesti.upper()}",
"entries": sEntrees,
"source_lang": sLanguageSource,
"target_lang": sLangageDesti,
"entries_format": sFormat
}
try:
response = requests.post(url=url, headers=headers, json=params)
if response.status_code == 201:
data = json.loads(response.text)
return data["glossary_id"]
else:
return response.text
except Exception as e:
return str(e)
def _glossaireRetrouveID(self, sLanguageSource: str, sLangageDesti: str) -> str:
"""
Récupère l'ID d'un glossaire existant pour une paire de langues
"""
import requests
# Création de la désignation pour la paire de langues
designation = f"{sLanguageSource.upper()}_{sLangageDesti.upper()}"
# Retourne l'ID du glossaire si déjà en cache
if designation in self.glossaire_id:
return self.glossaire_id[designation]
url = self.urlBase() + "glossaries"
headers = {
"Content-Type": "application/json"
}
if self.cleAPI():
headers["Authorization"] = f"{self.commandeAutorisation()} {self.cleAPI()}"
try:
response = requests.get(url=url, headers=headers)
if response.status_code == 200:
data = json.loads(response.text)
# Mise à jour du cache des glossaires
self.glossaire_id.clear()
for glossaire in data["glossaries"]:
glossaire_designation = f"{glossaire['source_lang'].upper()}_{glossaire['target_lang'].upper()}"
self.glossaire_id[glossaire_designation] = glossaire["glossary_id"]
# Retourne l'ID du glossaire demandé
designation = f"{sLanguageSource.upper()}_{sLangageDesti.upper()}"
return self.glossaire_id.get(designation, "")
else:
return response.text
except Exception as e:
return str(e)
def _glossaireSupprime(self, sID: str) -> str:
"""
Supprime un glossaire existant
"""
import requests
url = self.urlBase() + f"glossaries/{sID}"
headers = {
"Content-Type": "application/json"
}
if self.cleAPI():
headers["Authorization"] = f"{self.commandeAutorisation()} {self.cleAPI()}"
try:
response = requests.delete(url=url, headers=headers)
# Suppression de l'entrée dans le cache
for designation, id_en_cours in list(self.glossaire_id.items()):
if id_en_cours == sID:
del self.glossaire_id[designation]
if response.status_code == 204:
return ""
else:
return response.text
except Exception as e:
return str(e)