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 : sourcecible - csv : source,cible """ 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)