|
|
""" |
|
|
Intégration du système de mémoire dans l'outil de recherche |
|
|
""" |
|
|
|
|
|
from langchain_core.tools import tool |
|
|
from typing import Union |
|
|
import asyncio |
|
|
|
|
|
from src.agents.researcher_agent import ResearcherAgent |
|
|
from src.agents.content_extractor_agent import ContentExtractorAgent |
|
|
from src.agents.summarizer_agent import SummarizerAgent |
|
|
from src.agents.global_synthesizer_agent import GlobalSynthesizerAgent |
|
|
|
|
|
from src.models.research_models import ResearchQuery |
|
|
|
|
|
researcher_agent = ResearcherAgent() |
|
|
content_extractor_agent = ContentExtractorAgent() |
|
|
summarizer_agent = SummarizerAgent() |
|
|
global_synthesizer_agent = GlobalSynthesizerAgent() |
|
|
|
|
|
|
|
|
from .memory_integration import memory_system |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@tool |
|
|
def research_complete_pipeline_with_memory(topic: str, max_results: Union[int, str] = 3, use_cache: bool = True) -> str: |
|
|
"""Exécute un pipeline de recherche complet avec système de mémoire intégré. |
|
|
|
|
|
Ce tool intelligent : |
|
|
1. Vérifie si des recherches similaires existent en cache |
|
|
2. Utilise la mémoire vectorielle pour enrichir le contexte |
|
|
3. Exécute le pipeline complet de recherche si nécessaire |
|
|
4. Stocke tous les résultats pour réutilisation future |
|
|
5. Déduplique automatiquement les documents |
|
|
|
|
|
Args: |
|
|
topic: Le sujet de recherche |
|
|
max_results: Nombre de sources à analyser (2-10, défaut: 3) |
|
|
use_cache: Utiliser le cache si disponible (défaut: True) |
|
|
|
|
|
Returns: |
|
|
Un rapport complet enrichi par la mémoire contextuelle |
|
|
""" |
|
|
|
|
|
if isinstance(max_results, str): |
|
|
try: |
|
|
max_results = int(max_results) |
|
|
except ValueError: |
|
|
max_results = 3 |
|
|
max_results = max(2, min(max_results, 10)) |
|
|
|
|
|
async def run_pipeline_with_memory(): |
|
|
print(f"\n{'='*60}") |
|
|
print(f"🚀 PIPELINE DE RECHERCHE INTELLIGENT") |
|
|
print(f"📋 Sujet: {topic}") |
|
|
print(f"💾 Cache activé: {use_cache}") |
|
|
print(f"{'='*60}\n") |
|
|
|
|
|
|
|
|
print("🧠 [Phase 1] Récupération du contexte mémoriel...") |
|
|
context = memory_system.retrieve_context_for_query(topic, use_cache=use_cache) |
|
|
|
|
|
|
|
|
if context['cached_result'] and use_cache: |
|
|
print("✅ Résultat trouvé en cache (< 24h)") |
|
|
print("📊 Utilisation du résultat mémorisé") |
|
|
|
|
|
cached_report = context['cached_result'] |
|
|
if hasattr(cached_report, 'final_report'): |
|
|
return cached_report.final_report.formatted_outputs.get('markdown', str(cached_report)) |
|
|
|
|
|
|
|
|
if context['semantic_context']: |
|
|
print(f"📚 Contexte sémantique récupéré ({len(context['semantic_context'])} caractères)") |
|
|
|
|
|
if context['related_topics']: |
|
|
print(f"🔗 Topics similaires trouvés: {', '.join(context['related_topics'][:3])}") |
|
|
|
|
|
|
|
|
print(f"\n{'='*60}") |
|
|
print("🔬 [Phase 2] Exécution du pipeline de recherche") |
|
|
print(f"{'='*60}\n") |
|
|
|
|
|
|
|
|
print("🔍 [1/4] Recherche web en cours...") |
|
|
query = ResearchQuery( |
|
|
topic=topic, |
|
|
keywords=await researcher_agent.extract_keywords_with_llm(topic), |
|
|
max_results=max_results, |
|
|
search_depth="basic" |
|
|
) |
|
|
research_data = await researcher_agent.process(query) |
|
|
print(f"✅ Trouvé {research_data.total_found} sources") |
|
|
|
|
|
|
|
|
print("\n📄 [2/4] Extraction du contenu (avec déduplication)...") |
|
|
extraction_data = await content_extractor_agent.process_from_research_output( |
|
|
research_output=research_data |
|
|
) |
|
|
print(f"✅ Extrait {extraction_data.successful_extractions} documents") |
|
|
|
|
|
|
|
|
if extraction_data.documents: |
|
|
new_docs = [] |
|
|
duplicates = 0 |
|
|
for doc in extraction_data.documents: |
|
|
if not memory_system.vector_memory.is_duplicate(doc.content): |
|
|
new_docs.append(doc) |
|
|
else: |
|
|
duplicates += 1 |
|
|
|
|
|
if duplicates > 0: |
|
|
print(f"ℹ️ {duplicates} documents en doublon ignorés") |
|
|
|
|
|
extraction_data.documents = new_docs |
|
|
|
|
|
|
|
|
print("\n📝 [3/4] Création des résumés...") |
|
|
summarization_data = await summarizer_agent.process_from_extraction_result( |
|
|
extraction_result=extraction_data |
|
|
) |
|
|
print(f"✅ Généré {summarization_data.total_documents} résumés") |
|
|
|
|
|
|
|
|
print("\n🎯 [4/4] Synthèse globale (enrichie par le contexte)...") |
|
|
|
|
|
|
|
|
if context['semantic_context']: |
|
|
print("📚 Enrichissement avec le contexte mémoriel...") |
|
|
|
|
|
global_synthesis = await global_synthesizer_agent.process_from_summarization_output( |
|
|
summarization_output=summarization_data |
|
|
) |
|
|
print(f"✅ Rapport final généré ({global_synthesis.final_report.word_count} mots)") |
|
|
|
|
|
|
|
|
print(f"\n{'='*60}") |
|
|
print("💾 [Phase 3] Stockage en mémoire") |
|
|
print(f"{'='*60}\n") |
|
|
|
|
|
memory_system.process_research_result( |
|
|
topic=topic, |
|
|
extraction_result=extraction_data, |
|
|
summarization_result=summarization_data, |
|
|
global_synthesis=global_synthesis |
|
|
) |
|
|
|
|
|
|
|
|
final_report_text = global_synthesis.final_report.formatted_outputs.get('text', '')[:200] |
|
|
memory_system.agent_memory.add_conversation( |
|
|
user_message=f"Recherche sur: {topic}", |
|
|
assistant_response=final_report_text, |
|
|
metadata={'max_results': max_results, 'sources': research_data.total_found} |
|
|
) |
|
|
|
|
|
print(f"\n{'='*60}") |
|
|
print("✨ PIPELINE TERMINÉ AVEC SUCCÈS") |
|
|
print(f"📊 Statistiques:") |
|
|
print(f" - Sources analysées: {research_data.total_found}") |
|
|
print(f" - Documents stockés: {extraction_data.successful_extractions}") |
|
|
print(f" - Résumés générés: {summarization_data.total_documents}") |
|
|
print(f" - Mots du rapport: {global_synthesis.final_report.word_count}") |
|
|
print(f"{'='*60}\n") |
|
|
|
|
|
|
|
|
return global_synthesis.final_report.formatted_outputs.get('markdown', |
|
|
global_synthesis.final_report.formatted_outputs.get('text', |
|
|
str(global_synthesis))) |
|
|
|
|
|
return asyncio.run(run_pipeline_with_memory()) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@tool |
|
|
def search_in_memory(query: str, top_k: int = 5) -> str: |
|
|
"""Recherche sémantique dans la mémoire vectorielle. |
|
|
|
|
|
Utile pour retrouver des informations de recherches précédentes |
|
|
sans relancer une nouvelle recherche complète. |
|
|
|
|
|
Args: |
|
|
query: Requête de recherche |
|
|
top_k: Nombre de résultats à retourner |
|
|
|
|
|
Returns: |
|
|
Contexte pertinent trouvé dans la mémoire |
|
|
""" |
|
|
print(f"🔍 Recherche dans la mémoire: '{query}'") |
|
|
|
|
|
results = memory_system.vector_memory.semantic_search(query, k=top_k) |
|
|
|
|
|
if not results: |
|
|
return "Aucun résultat trouvé dans la mémoire." |
|
|
|
|
|
output = f"📚 {len(results)} résultats trouvés dans la mémoire:\n\n" |
|
|
|
|
|
for i, (doc, score) in enumerate(results, 1): |
|
|
output += f"[Résultat {i} - Pertinence: {score:.2%}]\n" |
|
|
output += f"Titre: {doc.metadata.get('title', 'N/A')}\n" |
|
|
output += f"Source: {doc.metadata.get('source', 'N/A')}\n" |
|
|
output += f"Contenu:\n{doc.page_content[:300]}...\n\n" |
|
|
|
|
|
return output |
|
|
|
|
|
|
|
|
@tool |
|
|
def get_research_history(n_last: int = 5) -> str: |
|
|
"""Récupère l'historique des dernières recherches effectuées. |
|
|
|
|
|
Args: |
|
|
n_last: Nombre de conversations récentes à retourner |
|
|
|
|
|
Returns: |
|
|
Historique formaté des recherches |
|
|
""" |
|
|
print(f"📜 Récupération des {n_last} dernières recherches...") |
|
|
|
|
|
history = list(memory_system.agent_memory.conversation_history)[-n_last:] |
|
|
|
|
|
if not history: |
|
|
return "Aucun historique de recherche disponible." |
|
|
|
|
|
output = f"📚 Historique des {len(history)} dernières recherches:\n\n" |
|
|
|
|
|
for i, conv in enumerate(history, 1): |
|
|
timestamp = conv.get('timestamp', 'N/A') |
|
|
user_msg = conv.get('user', '')[:100] |
|
|
metadata = conv.get('metadata', {}) |
|
|
|
|
|
output += f"[Recherche {i}] - {timestamp}\n" |
|
|
output += f"Topic: {user_msg}\n" |
|
|
if metadata: |
|
|
output += f"Détails: {metadata}\n" |
|
|
output += "\n" |
|
|
|
|
|
return output |
|
|
|
|
|
|
|
|
@tool |
|
|
def clear_memory(confirm: bool = False) -> str: |
|
|
"""Réinitialise complètement le système de mémoire. |
|
|
|
|
|
⚠️ ATTENTION: Cette action est irréversible! |
|
|
|
|
|
Args: |
|
|
confirm: Doit être True pour confirmer l'action |
|
|
|
|
|
Returns: |
|
|
Message de confirmation |
|
|
""" |
|
|
if not confirm: |
|
|
return "⚠️ Action non confirmée. Passez confirm=True pour réinitialiser la mémoire." |
|
|
|
|
|
print("🗑️ Réinitialisation de la mémoire...") |
|
|
memory_system.agent_memory.clear_all() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return "✅ Mémoire de conversation réinitialisée. Base vectorielle préservée." |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
tools_with_memory = [ |
|
|
research_complete_pipeline_with_memory, |
|
|
search_in_memory, |
|
|
get_research_history, |
|
|
clear_memory |
|
|
] |
|
|
|
|
|
print("✅ Outils avec mémoire initialisés:") |
|
|
print(" 1. research_complete_pipeline_with_memory - Pipeline complet avec cache") |
|
|
print(" 2. search_in_memory - Recherche dans la mémoire vectorielle") |
|
|
print(" 3. get_research_history - Historique des recherches") |
|
|
print(" 4. clear_memory - Réinitialisation de la mémoire") |