import os from textwrap import dedent from typing import Dict, List, Optional import gradio as gr from dotenv import load_dotenv from pydantic import BaseModel, Field from agno.agent import Agent from agno.models.openai import OpenAIChat from agno.tools.firecrawl import FirecrawlTools load_dotenv() # Variables d’environnement depuis Hugging Face "Secrets" os.environ["OPENAI_API_KEY"] = os.getenv("OPENAI_API_KEY") os.environ["FIRECRAWL_API_KEY"] = os.getenv("FIRECRAWL_API_KEY") # Modèle de réponse structuré class ContentSection(BaseModel): heading: Optional[str] = Field(None, description="Section heading") content: str = Field(..., description="Section content text") class PageInformation(BaseModel): url: str title: str description: Optional[str] features: Optional[List[str]] content_sections: Optional[List[ContentSection]] links: Optional[Dict[str, str]] contact_info: Optional[Dict[str, str]] metadata: Optional[Dict[str, str]] feedback: Optional[str] # Définition de l'agent agent = Agent( model=OpenAIChat(id="gpt-4.1"), tools=[FirecrawlTools(scrape=True, crawl=False)], instructions=dedent(""" Analysez la page fournie et extrayez les informations clés en respectant ce format : - Lisibilité - Ergonomie / navigation - Design - Sécurité - Pertinence des rubriques - Améliorations à suggérer Soyez clair et synthétique. Résumez les parties longues. """).strip(), response_model=PageInformation, ) # Fonction utilisée par Gradio def analyser_page(url: str): prompt = ( f"Analyse la page {url} selon les critères suivants : lisibilité, ergonomie/navigation, " "design, sécurité, pertinence des rubriques, améliorations à suggérer. Résume et structure la réponse." ) result = agent.run(prompt) print("DEBUG TYPE:", type(result)) print("DEBUG VALUE:", result) # Utilise le vrai contenu structuré 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}" # Construction d'un markdown structuré markdown = f"# Analyse de la page\n\n" markdown += f"**URL :** {data.get('url', url)}\n\n" if data.get("title"): markdown += f"**Titre :** {data['title']}\n\n" if data.get("description"): markdown += f"**Description :** {data['description']}\n\n" if data.get("features"): markdown += "## Fonctionnalités\n" for feat in data["features"]: markdown += f"- {feat}\n" markdown += "\n" if data.get("content_sections"): for section in data["content_sections"]: if section.get("heading"): markdown += f"## {section['heading']}\n" markdown += f"{section['content']}\n\n" if data.get("links"): markdown += "## Liens\n" for name, link in data["links"].items(): markdown += f"- [{name}]({link})\n" markdown += "\n" if data.get("contact_info"): markdown += "## Contact\n" for k, v in data["contact_info"].items(): markdown += f"- **{k}** : {v}\n" markdown += "\n" if data.get("metadata"): markdown += "## Métadonnées\n" for k, v in data["metadata"].items(): markdown += f"- **{k}** : {v}\n" markdown += "\n" if data.get("feedback"): markdown += f"## Feedback\n{data['feedback']}\n" return markdown # Interface Gradio demo = gr.Interface( fn=analyser_page, inputs=gr.Textbox(label="URL à analyser", placeholder="https://www.exemple.com"), outputs=gr.Markdown(), # Affichage markdown structuré title="🧠 Analyseur de Page Web", description="Entrez une URL à analyser selon des critères UX/UI.", ) if __name__ == "__main__": demo.launch()