Spaces:
Sleeping
Sleeping
File size: 8,727 Bytes
c4f2e45 61433d9 c4f2e45 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 |
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)
|