alfaDF9's picture
Update app.py
8c9689f verified
import asyncio
from datetime import timedelta
from agno.agent import Agent
from agno.knowledge.pdf import PDFKnowledgeBase, PDFReader
from agno.vectordb.qdrant import Qdrant
from agno.memory.v2.memory import Memory
from agno.document.chunking.agentic import AgenticChunking
from agno.models.openai import OpenAIChat
from agno.tools.reasoning import ReasoningTools
import gradio as gr
import json
import pandas as pd
from docx import Document
import tempfile
from weasyprint import HTML
import tempfile
import markdown as md
import os
import tempfile
from PIL import Image
import io
from dotenv import load_dotenv
load_dotenv()
# Initialisation Qdrant
vector_db = Qdrant(
collection="directives_16J",
url=os.getenv("QDRANT_URL"),
api_key=os.getenv("QDRANT_API_KEY")
)
# Charger tous les PDF du dossier dans la base de connaissance
knowledge_base = PDFKnowledgeBase(
#path="/home/fallou/PROJECT/Repo-IA/AGNO/directive",
reader=PDFReader(chunk=True),
vector_db=vector_db,
chunking_strategy=AgenticChunking(),
)
agent = Agent(
model=OpenAIChat(id="gpt-4o"),
knowledge=knowledge_base,
search_knowledge=True,
debug_mode=False,
description=(
"Agent polyvalent spécialisé dans l'analyse, la génération et la vérification des directives de suivi des projets et programmes de l'État du Sénégal. "
"Il combine les rôles suivants : analyse des requêtes, recherche contextuelle, extraction des rôles, rédaction structurée et contrôle de conformité."
),
instructions=[
# === CONTEXTE GLOBAL ===
"### Contexte Global\n"
"- Les directives proviennent de toutes les sources officielles : Conseils Présidentiels, Conseils des Ministres, Conseils Interministériels et réunions gouvernementales.\n"
"- Extraire **toutes les directives** présentes, même implicites ou partiellement mentionnées.\n"
"- L’objectif est de fournir une base exhaustive et directement exploitable pour le suivi des projets et programmes de l’État.\n",
# === TÂCHE 1 : RECHERCHE ET EXTRACTION ===
"### Tâche : Extraction exhaustive des directives\n"
"- Identifier toutes les directives liées à `{query}` ou aux projets/programmes mentionnés dans les documents.\n"
"- Ne pas omettre les directives secondaires ou implicites (ex : relances, rappels, suivis techniques).\n"
"- Lister chaque directive de manière indépendante.\n",
# === FORMAT DE SORTIE OBLIGATOIRE ===
"### Format de sortie obligatoire\n"
"- La sortie doit être **en Markdown structuré** avec deux sections principales :\n"
"1. **Résumé Global** : courte synthèse expliquant le contexte et nombre de directives trouvées.\n"
"2. **Détails des Directives** sous forme de tableau Markdown avec colonnes suivantes :\n"
"| Autorité émettrice | Source | Date de publication | Description détaillée de la directive | Action(s) à entreprendre | Structures responsables | Parties prenantes | Statut | Priorité | Date limite | Actions spécifiques du BOCS |\n"
"- Chaque ligne représente une directive.\n"
"- Les dates doivent être formatées `JJ Mois AAAA` .\n"
"- Ne pas inclure de JSON ou code brut, uniquement résumé + tableau Markdown.\n",
# === TÂCHE 2 : MÉTADONNÉES ET STRUCTURATION ===
"### Tâche : Structuration des directives\n"
"- Pour chaque directive, fournir :\n"
" 1. **Autorité émettrice** : Auteur de la directive (PR, PM, SGG, Ministère, etc.)\n"
" 2. **Source** (type de conseil ou réunion)\n"
" 3. **Date de publication du document** (ou 'Date du conseil')\n"
" 4. **Description détaillée** de la directive\n"
" 5. **Actions à entreprendre** (liste détaillée)\n"
" 6. **Structures responsables** (entités principales)\n"
" 7. **Parties prenantes** (internes/externes)\n"
" 8. **Statut** (En cours, Démarré, Non démarré)\n"
" 9. **Priorité** (Très Haute, Haute, Moyenne, Basse)\n"
" 10. **Date limite** (ou 'Meilleurs delais')\n"
" 11. **Actions spécifiques du BOCS** (toujours présentes, détaillées)\n",
# === TÂCHE 4 : VÉRIFICATION ===
"### Vérification\n"
"- Vérifier que chaque directive contient **tous les champs**.\n"
"- Si une information manque au niveau de la date limite, préciser 'Meilleurs delais'.\n"
"- Garantir que la structure est prête à être utilisée sans retravail manuel."
],
tools=[ReasoningTools(add_instructions=True)],
add_history_to_messages=False,
)
# Vérifier si la collection Qdrant contient déjà des points
def is_collection_indexed(vector_db):
try:
info = vector_db.client.count(collection_name=vector_db.collection)
return info.count > 0
except Exception:
return False
# Charger la base de connaissance seulement si elle n'est pas déjà indexée
if not is_collection_indexed(vector_db):
agent.knowledge.load(recreate=False)
# -------------------------------
# Fonction principale : appel agent avec agent.run()
# -------------------------------
def generate_directives(query: str):
try:
prompt = f"Analyse toutes les directives en details en occurence avec la question du user : {query}"
result = agent.run(prompt)
content = getattr(result, "content", None)
if hasattr(content, "dict") and callable(content.dict):
data = content.dict()
elif isinstance(content, dict):
data = content
elif isinstance(content, str):
return f"Réponse brute :\n\n{content}"
else:
return f"Type inattendu pour content : {type(content)}\nValeur : {content}"
resume = data.get("resume")
directives = data.get("directives")
if not resume or not directives:
return "Le JSON ne contient pas 'resume' ou 'directives'."
# Générer seulement du Markdown
markdown_output = f"## Résumé\n- **Nombre de directives** : {resume.get('nombre_directives', 'Inconnu')}\n\n"
markdown_output += f"> {resume.get('contexte', '')}\n\n"
markdown_output += "## Directives détaillées\n"
for idx, directive in enumerate(directives, start=1):
markdown_output += f"### Directive {idx}\n"
for key, value in directive.items():
if isinstance(value, list):
value = ", ".join(value)
markdown_output += f"- **{key}** : {value}\n"
markdown_output += "\n"
return markdown_output
except Exception as e:
return f"Erreur inattendue : {str(e)}"
# --- Convertir Markdown en PDF ---
def export_to_pdf(markdown_text):
if not markdown_text:
return None
# Convertir Markdown en HTML
html_content = md.markdown(markdown_text)
tmp = tempfile.NamedTemporaryFile(delete=False, suffix=".pdf")
HTML(string=html_content).write_pdf(tmp.name)
return tmp.name
def export_to_html(markdown_text):
if not markdown_text:
return None
html_content = md.markdown(markdown_text)
tmp = tempfile.NamedTemporaryFile(delete=False, suffix=".html")
with open(tmp.name, "w", encoding="utf-8") as f:
f.write(f"<html><body>{html_content}</body></html>")
return tmp.name
# -------------------------------
# Interface Gradio avec deux onglets
# -------------------------------
with gr.Blocks() as demo:
gr.Markdown("# 🏛️ Assistant Suivi des Directives")
# Onglet Chat
with gr.Tab("Chat"):
with gr.Row():
query_input = gr.Textbox(
label="Votre requête",
placeholder="Ex: Détails spécifiques sur des directives individuelles. ",
lines=3
)
submit_btn = gr.Button("Générer Directives")
output_md = gr.Markdown(label="Résultat")
# Ici on relie directement la fonction
submit_btn.click(
fn=generate_directives,
inputs=query_input,
outputs=output_md
)
# Onglet Export (toujours à l’intérieur du même Blocks)
with gr.Tab("Export"):
gr.Markdown("### Exportez les directives générées")
export_pdf_btn = gr.Button("Télécharger PDF (.pdf)")
export_html_btn = gr.Button("Télécharger HTML (.html)")
pdf_file = gr.File(label="Fichier PDF", interactive=False)
html_file = gr.File(label="Fichier HTML", interactive=False)
export_pdf_btn.click(fn=export_to_pdf, inputs=output_md, outputs=pdf_file)
export_html_btn.click(fn=export_to_html, inputs=output_md, outputs=html_file)
demo.launch(server_name="0.0.0.0", server_port=7860)