""" MCP Server for Agricultural Weed Pressure Analysis Integrates tools, resources and prompts from the mcp/ folder """ import gradio as gr import pandas as pd import numpy as np import plotly.express as px from data_loader import AgriculturalDataLoader from agricultural_mcp.tools import WeedPressureAnalyzer, analyze_herbicide_trends, predict_future_weed_pressure, recommend_sensitive_crop_plots, explore_raw_data, get_available_plots, get_available_crops, get_available_interventions from agricultural_mcp.resources import AgriculturalResources import warnings warnings.filterwarnings('ignore') # Initialize analyzer and resources analyzer = WeedPressureAnalyzer() resources = AgriculturalResources() def create_mcp_interface(): """ Create the main MCP interface with 5 tabs: 1. Analyse Tendances - IFT herbicide analysis 2. Prédictions - Weed pressure predictions 2025-2027 3. Recommandations - Sensitive crop recommendations 4. Exploration Données - Raw data exploration 5. MCP Resources - Display resources.py content """ with gr.Blocks(title="Serveur MCP - Analyse Pression Adventices", theme=gr.themes.Soft()) as demo: gr.Markdown("# 🌾 Serveur MCP - Analyse Pression Adventices") gr.Markdown(""" **Analyse de la pression adventices et recommandations pour cultures sensibles** Ce serveur MCP (Model Context Protocol) fournit des outils d'analyse pour : - Calculer l'IFT (Indice de Fréquence de Traitement) des herbicides - Prédire la pression adventices pour 2025-2027 - Recommander des parcelles pour cultures sensibles (pois, haricot) - Explorer les données agricoles avec filtres avancés """) with gr.Tabs(): # Tab 1: Analyse Tendances with gr.Tab("📈 Analyse Tendances"): gr.Markdown("### Analyse des tendances IFT herbicides") gr.Markdown(""" **Méthode de calcul IFT :** - IFT = Nombre d'applications herbicides / Surface de la parcelle - Analyse de l'évolution temporelle par parcelle - Classification des niveaux de risque : Faible (IFT < 1.0), Modéré (1.0 ≤ IFT < 2.0), Élevé (IFT ≥ 2.0) """) with gr.Row(): with gr.Column(): year_start = gr.Slider( minimum=2014, maximum=2025, value=2014, step=1, label="Année de début" ) year_end = gr.Slider( minimum=2014, maximum=2025, value=2025, step=1, label="Année de fin" ) plot_filter = gr.Dropdown( choices=get_available_plots(), value="Toutes", label="Filtrer par parcelle" ) analyze_btn = gr.Button("📊 Analyser les Tendances", variant="primary") with gr.Row(): trend_plot = gr.Plot() trend_summary = gr.Markdown() analyze_btn.click( analyze_herbicide_trends, inputs=[year_start, year_end, plot_filter], outputs=[trend_plot, trend_summary] ) # Tab 2: Prédictions with gr.Tab("🔮 Prédictions"): gr.Markdown("### Prédictions de pression adventices 2025-2027") gr.Markdown(""" **Méthode de prédiction :** - Régression linéaire sur les données IFT historiques - Extrapolation pour les années 2025-2027 - Classification des niveaux de risque basée sur l'IFT prédit - Prise en compte de l'historique des cultures récentes """) with gr.Row(): predict_btn = gr.Button("🔮 Générer les Prédictions", variant="primary") with gr.Row(): pred_plot = gr.Plot() pred_summary = gr.Markdown() predict_btn.click( predict_future_weed_pressure, outputs=[pred_plot, pred_summary] ) # Tab 3: Recommandations with gr.Tab("🌱 Recommandations"): gr.Markdown("### Recommandations pour cultures sensibles") gr.Markdown(""" **Critères de recommandation :** - Parcelles avec IFT prédit < 1.0 (faible pression adventices) - Score de recommandation : 100 - (IFT_prédit × 30) - Cultures sensibles : pois, haricot - Prise en compte de l'historique cultural récent """) with gr.Row(): recommend_btn = gr.Button("🌱 Générer les Recommandations", variant="primary") with gr.Row(): rec_plot = gr.Plot() rec_summary = gr.Markdown() recommend_btn.click( recommend_sensitive_crop_plots, outputs=[rec_plot, rec_summary] ) # Tab 4: Exploration Données with gr.Tab("🔍 Exploration Données"): gr.Markdown("### Exploration des données brutes") gr.Markdown(""" **Filtres disponibles :** - Années : 2014-2025 - Parcelles : 106 parcelles disponibles - Cultures : 42 types de cultures - Types d'intervention : Herbicides, Fertilisation, Semis, etc. """) with gr.Row(): with gr.Column(): data_year_start = gr.Slider( minimum=2014, maximum=2025, value=2014, step=1, label="Année de début" ) data_year_end = gr.Slider( minimum=2014, maximum=2025, value=2025, step=1, label="Année de fin" ) data_plot_filter = gr.Dropdown( choices=get_available_plots(), value="Toutes", label="Filtrer par parcelle" ) data_crop_filter = gr.Dropdown( choices=get_available_crops(), value="Toutes", label="Filtrer par culture" ) data_intervention_filter = gr.Dropdown( choices=get_available_interventions(), value="Toutes", label="Filtrer par type d'intervention" ) explore_btn = gr.Button("🔍 Explorer les Données", variant="primary") with gr.Row(): data_plot = gr.Plot() data_summary = gr.Markdown() explore_btn.click( explore_raw_data, inputs=[data_year_start, data_year_end, data_plot_filter, data_crop_filter, data_intervention_filter], outputs=[data_plot, data_summary] ) # Tab 5: MCP Resources with gr.Tab("🔧 MCP Resources"): gr.Markdown("### Resources MCP disponibles") gr.Markdown(""" **Resources MCP exposées :** - `dataset://years` - Liste des millésimes disponibles - `exploitation://{siret}/{millesime}` - Informations d'exploitation - `parcelle://{millesime}/{numparcell}` - Informations de parcelle - `intervention://{millesime}/{numparcell}/{rang}` - Informations d'intervention - `intrant://{codeamm}` - Informations d'intrant - `materiel://{millesime}/{numparcell}/{rang}` - Informations de matériel - `maindoeuvre://{millesime}/{numparcell}/{rang}` - Informations de main d'œuvre """) with gr.Row(): with gr.Column(): gr.Markdown("#### Test des Resources MCP") # Test Years years_btn = gr.Button("📅 Liste des Années", variant="primary") # Test Exploitation with gr.Row(): siret_input = gr.Textbox( label="SIRET Exploitation", value="18560001000016", placeholder="18560001000016" ) siret_millesime_input = gr.Textbox( label="Millesime", value="2025", placeholder="2025" ) siret_btn = gr.Button("🏢 Test Exploitation", variant="secondary") # Test Parcelle with gr.Row(): parcelle_millesime_input = gr.Textbox( label="Millesime", value="2025", placeholder="2025" ) parcelle_input = gr.Textbox( label="Numéro Parcelle", value="12", placeholder="12" ) parcelle_btn = gr.Button("🏞️ Test Parcelle", variant="secondary") # Test Intervention with gr.Row(): intervention_millesime_input = gr.Textbox( label="Millesime", value="2025", placeholder="2025" ) intervention_parcelle_input = gr.Textbox( label="Num Parcelle", value="12", placeholder="12" ) intervention_rang_input = gr.Textbox( label="Rang", value="1", placeholder="1" ) intervention_btn = gr.Button("⚙️ Test Intervention", variant="secondary") # Test Intrant with gr.Row(): intrant_input = gr.Textbox( label="Code AMM Intrant", value="9100296", placeholder="9100296" ) intrant_millesime_input = gr.Textbox( label="Millesime (optionnel)", value="", placeholder="2025" ) intrant_btn = gr.Button("🧪 Test Intrant", variant="secondary") # Test Matériel with gr.Row(): materiel_millesime_input = gr.Textbox( label="Millesime", value="2025", placeholder="2025" ) materiel_parcelle_input = gr.Textbox( label="Num Parcelle", value="12", placeholder="12" ) materiel_rang_input = gr.Textbox( label="Rang", value="1", placeholder="1" ) materiel_btn = gr.Button("🔧 Test Matériel", variant="secondary") with gr.Column(): gr.Markdown("#### Résultat") resource_output = gr.JSON(label="Résultat de la resource") # Connexions des boutons years_btn.click( lambda: resources.list_years(), outputs=[resource_output] ) siret_btn.click( lambda siret, millesime: resources.get_exploitation(siret, millesime), inputs=[siret_input, siret_millesime_input], outputs=[resource_output] ) parcelle_btn.click( lambda millesime, parcelle: resources.get_parcelle(millesime, parcelle), inputs=[parcelle_millesime_input, parcelle_input], outputs=[resource_output] ) intervention_btn.click( lambda millesime, parcelle, rang: resources.get_intervention(millesime, parcelle, rang), inputs=[intervention_millesime_input, intervention_parcelle_input, intervention_rang_input], outputs=[resource_output] ) intrant_btn.click( lambda codeamm, millesime: resources.get_intrant(codeamm, millesime if millesime else None), inputs=[intrant_input, intrant_millesime_input], outputs=[resource_output] ) materiel_btn.click( lambda millesime, parcelle, rang: resources.get_materiel(millesime, parcelle, rang), inputs=[materiel_millesime_input, materiel_parcelle_input, materiel_rang_input], outputs=[resource_output] ) return demo