2025-03-27 17:59:10 +01:00

207 lines
9.7 KiB
Python

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Agent LLM pour la reformulation et l'adaptation de contenu
"""
import os
import time
import uuid
from typing import Dict, Optional, Union, List, Any
from .base import LLMBaseAgent
from utils.api_ollama import OllamaAPI
class RewriterAgent(LLMBaseAgent):
"""
Agent LLM spécialisé dans la reformulation et l'adaptation de texte
"""
def __init__(self, model_name: str, endpoint: str = "http://217.182.105.173:11434", **config):
"""
Initialise l'agent de reformulation
Args:
model_name (str): Nom du modèle de reformulation
endpoint (str): URL de l'API Ollama
**config: Paramètres de configuration supplémentaires
"""
super().__init__(model_name, endpoint, **config)
# Définir les modes de reformulation et leurs prompts
self.modes = {
"fr": {
"simplifier": "Reformule le texte suivant pour le rendre plus accessible "
"et facile à comprendre. Simplifie le vocabulaire et la structure "
"des phrases tout en préservant le sens original.\n\n"
"Texte original :\n{text}",
"détailler": "Développe et enrichis le texte suivant en ajoutant des détails, "
"des explications et des exemples pertinents. Garde le même ton "
"et le même style, mais rends le contenu plus complet.\n\n"
"Texte à développer :\n{text}",
"rag": "Reformule le texte suivant pour l'optimiser pour un système de RAG "
"(Retrieval Augmented Generation). Assure-toi qu'il contient des mots-clés "
"pertinents, qu'il est bien structuré pour la recherche sémantique, et "
"qu'il présente clairement les informations essentielles.\n\n"
"Texte à optimiser :\n{text}",
"formal": "Reformule le texte suivant dans un style plus formel et académique. "
"Utilise un vocabulaire précis, une structure de phrase soignée, et "
"un ton professionnel tout en préservant le contenu original.\n\n"
"Texte à formaliser :\n{text}",
"bullet": "Transforme le texte suivant en une liste à puces claire et concise. "
"Extrais les points essentiels et présente-les dans un format facile "
"à lire et à comprendre.\n\n"
"Texte à transformer :\n{text}"
},
"en": {
"simplify": "Rewrite the following text to make it more accessible "
"and easy to understand. Simplify vocabulary and sentence structure "
"while preserving the original meaning.\n\n"
"Original text:\n{text}",
"elaborate": "Expand and enrich the following text by adding relevant details, "
"explanations, and examples. Keep the same tone and style, "
"but make the content more comprehensive.\n\n"
"Text to expand:\n{text}",
"rag": "Rewrite the following text to optimize it for a RAG "
"(Retrieval Augmented Generation) system. Ensure it contains relevant "
"keywords, is well-structured for semantic search, and "
"clearly presents essential information.\n\n"
"Text to optimize:\n{text}",
"formal": "Rewrite the following text in a more formal and academic style. "
"Use precise vocabulary, careful sentence structure, and "
"a professional tone while preserving the original content.\n\n"
"Text to formalize:\n{text}",
"bullet": "Transform the following text into a clear and concise bullet point list. "
"Extract the essential points and present them in a format that is easy "
"to read and understand.\n\n"
"Text to transform:\n{text}"
}
}
# Création du répertoire pour les journaux de reformulation
self.log_dir = os.path.join("data", "rewrites")
os.makedirs(self.log_dir, exist_ok=True)
def generate(self, text: str, images: Optional[List[bytes]] = None, mode: str = "rag",
custom_prompt: Optional[str] = "", language: Optional[str] = None) -> str:
"""
Reformule un texte selon le mode spécifié
Args:
text (str): Texte à reformuler
images (List[bytes], optional): Non utilisé pour la reformulation
mode (str): Mode de reformulation (simplifier, détailler, rag, formal, bullet)
custom_prompt (str, optional): Prompt personnalisé pour la reformulation
language (str, optional): Langue du texte à reformuler
Returns:
str: Le texte reformulé
"""
if not text or not text.strip():
return "Erreur: Aucun texte fourni pour la reformulation"
# Déterminer la langue et le prompt à utiliser
lang = language or self.config.get("language", "fr")
# Génération d'un ID unique pour cette reformulation
rewrite_id = str(uuid.uuid4())[:8]
timestamp = time.strftime("%Y%m%d-%H%M%S")
if custom_prompt:
prompt_template = custom_prompt
mode_name = "custom"
else:
# Vérifier que le mode existe pour la langue spécifiée
if lang not in self.modes or mode not in self.modes[lang]:
# Fallback sur français et mode RAG si non disponible
lang = "fr"
mode = "rag"
prompt_template = self.modes[lang][mode]
mode_name = mode
# Formater le prompt avec le texte
prompt = prompt_template.format(text=text)
# Créer l'API Ollama pour l'appel direct
api = OllamaAPI(base_url=self.endpoint)
# Journaliser le prompt complet
print(f"Envoi du prompt de reformulation (mode {mode_name}) au modèle {self.model_name}")
try:
# Pour les modèles qui supportent le format de chat
if any(name in self.model_name.lower() for name in ["llama", "mistral", "deepseek", "qwen"]):
# Formater en tant que messages de chat
system_prompt = f"Tu es un expert en reformulation de texte spécialisé dans le mode '{mode_name}'."
messages = [
{"role": "system", "content": system_prompt},
{"role": "user", "content": prompt}
]
response = api.chat(
model=self.model_name,
messages=messages,
options={
"temperature": self.config.get("temperature", 0.3),
"top_p": self.config.get("top_p", 0.95),
"top_k": self.config.get("top_k", 40),
"num_predict": self.config.get("max_tokens", 2048)
}
)
if "message" in response and "content" in response["message"]:
result = response["message"]["content"]
else:
result = response.get("response", "Erreur: Format de réponse inattendu")
else:
# Format de génération standard pour les autres modèles
response = api.generate(
model=self.model_name,
prompt=prompt,
options={
"temperature": self.config.get("temperature", 0.3),
"top_p": self.config.get("top_p", 0.95),
"top_k": self.config.get("top_k", 40),
"num_predict": self.config.get("max_tokens", 2048)
}
)
result = response.get("response", "Erreur: Pas de réponse")
# Enregistrer la reformulation dans un fichier
rewrite_path = os.path.join(self.log_dir, f"{timestamp}_{rewrite_id}.txt")
with open(rewrite_path, "w", encoding="utf-8") as f:
f.write(f"Language: {lang}\n")
f.write(f"Mode: {mode_name}\n")
f.write(f"Model: {self.model_name}\n\n")
f.write(f"Original text:\n{text}\n\n")
f.write(f"Rewritten text:\n{result}")
print(f"Reformulation enregistrée dans: {rewrite_path}")
return result
except Exception as e:
error_msg = f"Erreur lors de la reformulation: {str(e)}"
print(error_msg)
# Enregistrer l'erreur
error_path = os.path.join(self.log_dir, f"{timestamp}_{rewrite_id}_error.txt")
with open(error_path, "w", encoding="utf-8") as f:
f.write(f"Language: {lang}\n")
f.write(f"Mode: {mode_name}\n")
f.write(f"Model: {self.model_name}\n\n")
f.write(f"Original text:\n{text}\n\n")
f.write(f"Error:\n{str(e)}")
return error_msg