Tracy André commited on
Commit
86d3300
·
1 Parent(s): 3537198
Files changed (13) hide show
  1. .gitattributes +0 -35
  2. .gitignore +0 -14
  3. DEPLOYMENT.md +0 -78
  4. GUIDE_UTILISATEUR.md +0 -138
  5. README.md +0 -31
  6. app.py +0 -303
  7. config.py +0 -32
  8. data_loader.py +0 -142
  9. example_agent_usage.py +0 -151
  10. herbicide_analyzer.py +0 -187
  11. requirements.txt +0 -11
  12. run_server.sh +0 -30
  13. test_mcp_server.py +0 -94
.gitattributes DELETED
@@ -1,35 +0,0 @@
1
- *.7z filter=lfs diff=lfs merge=lfs -text
2
- *.arrow filter=lfs diff=lfs merge=lfs -text
3
- *.bin filter=lfs diff=lfs merge=lfs -text
4
- *.bz2 filter=lfs diff=lfs merge=lfs -text
5
- *.ckpt filter=lfs diff=lfs merge=lfs -text
6
- *.ftz filter=lfs diff=lfs merge=lfs -text
7
- *.gz filter=lfs diff=lfs merge=lfs -text
8
- *.h5 filter=lfs diff=lfs merge=lfs -text
9
- *.joblib filter=lfs diff=lfs merge=lfs -text
10
- *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
- *.mlmodel filter=lfs diff=lfs merge=lfs -text
12
- *.model filter=lfs diff=lfs merge=lfs -text
13
- *.msgpack filter=lfs diff=lfs merge=lfs -text
14
- *.npy filter=lfs diff=lfs merge=lfs -text
15
- *.npz filter=lfs diff=lfs merge=lfs -text
16
- *.onnx filter=lfs diff=lfs merge=lfs -text
17
- *.ot filter=lfs diff=lfs merge=lfs -text
18
- *.parquet filter=lfs diff=lfs merge=lfs -text
19
- *.pb filter=lfs diff=lfs merge=lfs -text
20
- *.pickle filter=lfs diff=lfs merge=lfs -text
21
- *.pkl filter=lfs diff=lfs merge=lfs -text
22
- *.pt filter=lfs diff=lfs merge=lfs -text
23
- *.pth filter=lfs diff=lfs merge=lfs -text
24
- *.rar filter=lfs diff=lfs merge=lfs -text
25
- *.safetensors filter=lfs diff=lfs merge=lfs -text
26
- saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
- *.tar.* filter=lfs diff=lfs merge=lfs -text
28
- *.tar filter=lfs diff=lfs merge=lfs -text
29
- *.tflite filter=lfs diff=lfs merge=lfs -text
30
- *.tgz filter=lfs diff=lfs merge=lfs -text
31
- *.wasm filter=lfs diff=lfs merge=lfs -text
32
- *.xz filter=lfs diff=lfs merge=lfs -text
33
- *.zip filter=lfs diff=lfs merge=lfs -text
34
- *.zst filter=lfs diff=lfs merge=lfs -text
35
- *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
.gitignore DELETED
@@ -1,14 +0,0 @@
1
- __pycache__/
2
- *.pyc
3
- *.pyo
4
- *.pyd
5
- .Python
6
- *.so
7
- .coverage
8
- .pytest_cache/
9
- .env
10
- .venv
11
- env/
12
- venv/
13
- flagged/
14
- *.log
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
DEPLOYMENT.md DELETED
@@ -1,78 +0,0 @@
1
- # Déploiement du Serveur MCP Agriculture sur Hugging Face
2
-
3
- ## Aperçu
4
- Ce serveur MCP (Model Context Protocol) expose tous les outils d'analyse agricole et de visualisation via une interface Gradio optimisée pour Hugging Face Spaces.
5
-
6
- ## Architecture
7
- - **app.py** : Serveur MCP principal avec interface Gradio
8
- - **data_loader.py** : Chargement des données depuis Hugging Face
9
- - **herbicide_analyzer.py** : Outils d'analyse des herbicides
10
- - **config.py** : Configuration centralisée
11
-
12
- ## Fonctionnalités MCP
13
-
14
- ### 1. Chargement des données
15
- - `load_agriculture_data()` : Charge les données depuis le dataset HackathonCRA/2024
16
- - `get_data_summary()` : Résumé des données chargées
17
-
18
- ### 2. Analyse des herbicides
19
- - `analyze_herbicide_usage()` : Analyse statistique des herbicides
20
- - Types d'analyse : "statistics", "top_parcels", "trends"
21
-
22
- ### 3. Visualisations
23
- - `create_herbicide_visualization()` : Graphiques Plotly interactifs
24
- - Types : "top_ift", "regional_trends"
25
-
26
- ### 4. Requêtes base de données
27
- - `query_database()` : Requêtes flexibles sur les données
28
- - Types : "parcels_by_commune", "products_by_year"
29
-
30
- ## Déploiement sur Hugging Face
31
-
32
- ### 1. Créer un Space
33
- ```bash
34
- git clone https://huggingface.co/spaces/YOUR_USERNAME/agriculture-mcp
35
- cd agriculture-mcp
36
- ```
37
-
38
- ### 2. Copier les fichiers
39
- ```bash
40
- cp -r /path/to/mcp/* .
41
- ```
42
-
43
- ### 3. Configurer les variables d'environnement
44
- Dans les settings du Space Hugging Face :
45
- - `HF_TOKEN` : Token Hugging Face pour accéder au dataset
46
-
47
- ### 4. Push et déploiement
48
- ```bash
49
- git add .
50
- git commit -m "Initial MCP server deployment"
51
- git push
52
- ```
53
-
54
- ## Utilisation avec un Agent IA
55
-
56
- L'agent IA peut se connecter au serveur MCP et utiliser les outils exposés :
57
-
58
- ```python
59
- # Exemple d'utilisation par un agent IA
60
- agent.connect_mcp_server("https://your-space.hf.space")
61
-
62
- # Charger les données
63
- agent.call_tool("load_agriculture_data")
64
-
65
- # Analyser les herbicides
66
- agent.call_tool("analyze_herbicide_usage", year=2023, analysis_type="statistics")
67
-
68
- # Créer une visualisation
69
- agent.call_tool("create_herbicide_visualization", year=2023, chart_type="top_ift")
70
- ```
71
-
72
- ## Avantages
73
-
74
- 1. **Interface unifiée** : Tous les outils dans un seul serveur MCP
75
- 2. **Visualisations interactives** : Graphiques Plotly embarqués
76
- 3. **Déploiement simple** : Prêt pour Hugging Face Spaces
77
- 4. **Extensible** : Facile d'ajouter de nouveaux outils
78
- 5. **Performance** : Optimisé pour les requêtes d'agents IA
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
GUIDE_UTILISATEUR.md DELETED
@@ -1,138 +0,0 @@
1
- # 🌾 Guide Utilisateur - Serveur MCP Agriculture
2
-
3
- ## Vue d'ensemble
4
-
5
- Le serveur MCP (Model Context Protocol) Agriculture expose tous les outils d'analyse agricole et de visualisation via une interface Gradio. Il permet aux agents IA de se connecter aux données agricoles pour générer des rapports puissants.
6
-
7
- ## 🚀 Démarrage Rapide
8
-
9
- ### 1. Installation locale
10
- ```bash
11
- cd mcp/
12
- pip install -r requirements.txt
13
- python app.py
14
- ```
15
-
16
- ### 2. Interface web
17
- Ouvrez http://localhost:7860 dans votre navigateur
18
-
19
- ### 3. Test du serveur
20
- ```bash
21
- python test_mcp_server.py
22
- ```
23
-
24
- ## 🛠️ Outils MCP Disponibles
25
-
26
- ### 📊 Gestion des données
27
- - **`load_agriculture_data()`** : Charge les données depuis Hugging Face
28
- - **`get_data_summary()`** : Obtient un résumé des données chargées
29
-
30
- ### 🌿 Analyse des herbicides
31
- - **`analyze_herbicide_usage(year, analysis_type)`** : Analyse l'usage d'herbicides
32
- - `analysis_type` : "statistics", "top_parcels", "trends"
33
-
34
- ### 📈 Visualisations
35
- - **`create_herbicide_visualization(year, chart_type)`** : Crée des graphiques
36
- - `chart_type` : "top_ift", "regional_trends"
37
-
38
- ### 🔍 Requêtes base de données
39
- - **`query_database(query_type, **kwargs)`** : Requêtes flexibles
40
- - `query_type` : "parcels_by_commune", "products_by_year"
41
-
42
- ## 🤖 Utilisation par un Agent IA
43
-
44
- ### Exemple de workflow complet :
45
-
46
- ```python
47
- # 1. Connexion au serveur MCP
48
- agent.connect_mcp_server("https://your-space.hf.space")
49
-
50
- # 2. Chargement des données
51
- result = agent.call_tool("load_agriculture_data")
52
-
53
- # 3. Analyse des herbicides
54
- analysis = agent.call_tool("analyze_herbicide_usage",
55
- year=2023,
56
- analysis_type="statistics")
57
-
58
- # 4. Création de visualisation
59
- chart = agent.call_tool("create_herbicide_visualization",
60
- year=2023,
61
- chart_type="top_ift")
62
-
63
- # 5. Génération de rapport
64
- report = agent.generate_report(analysis, chart)
65
- ```
66
-
67
- ## 📋 Interface Gradio
68
-
69
- L'interface web contient 4 onglets :
70
-
71
- 1. **📊 Chargement des Données** : Charger et résumer les données
72
- 2. **🌿 Analyse des Herbicides** : Analyses spécialisées herbicides
73
- 3. **📈 Visualisations** : Création de graphiques interactifs
74
- 4. **🔍 Requêtes Base de Données** : Requêtes personnalisées
75
-
76
- ## 🎯 Cas d'usage
77
-
78
- ### 1. Analyse de compliance
79
- ```python
80
- # Identifier les parcelles à risque
81
- top_parcels = agent.call_tool("analyze_herbicide_usage",
82
- year=2023,
83
- analysis_type="top_parcels")
84
- ```
85
-
86
- ### 2. Suivi de tendances
87
- ```python
88
- # Analyser l'évolution par région
89
- trends = agent.call_tool("analyze_herbicide_usage",
90
- analysis_type="trends")
91
- ```
92
-
93
- ### 3. Reporting automatisé
94
- ```python
95
- # Générer des rapports périodiques
96
- for year in [2021, 2022, 2023]:
97
- analysis = agent.call_tool("analyze_herbicide_usage", year=year)
98
- chart = agent.call_tool("create_herbicide_visualization", year=year)
99
- agent.generate_report(f"Rapport {year}", analysis, chart)
100
- ```
101
-
102
- ## 🔧 Configuration
103
-
104
- ### Variables d'environnement
105
- - `HF_TOKEN` : Token Hugging Face pour accéder aux datasets
106
- - `GRADIO_ANALYTICS_ENABLED=False` : Désactive les analytics
107
-
108
- ### Personnalisation
109
- - **config.py** : Configuration centrale (couleurs, messages, etc.)
110
- - **requirements.txt** : Dépendances Python
111
- - **DEPLOYMENT.md** : Guide de déploiement détaillé
112
-
113
- ## 🌐 Déploiement sur Hugging Face
114
-
115
- 1. Créer un nouveau Space sur Hugging Face
116
- 2. Copier tous les fichiers du dossier `mcp/`
117
- 3. Configurer la variable `HF_TOKEN` dans les settings
118
- 4. Le déploiement se fait automatiquement
119
-
120
- ## 🔄 Extensibilité
121
-
122
- Pour ajouter de nouveaux outils MCP :
123
-
124
- 1. Ajouter la méthode dans `AgricultureMCPServer`
125
- 2. Exposer via l'interface Gradio
126
- 3. Documenter dans ce guide
127
- 4. Tester avec `test_mcp_server.py`
128
-
129
- ## 🆘 Support
130
-
131
- - **Tests** : `python test_mcp_server.py`
132
- - **Exemple** : `python example_agent_usage.py`
133
- - **Logs** : Vérifier la console pour les erreurs
134
- - **Documentation** : Voir DEPLOYMENT.md pour plus de détails
135
-
136
- ---
137
-
138
- 🎉 **Le serveur MCP Agriculture est prêt à connecter les agents IA aux données agricoles !**
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
README.md DELETED
@@ -1,31 +0,0 @@
1
- ---
2
- title: Agriculture Data MCP Server
3
- emoji: 🌾
4
- colorFrom: green
5
- colorTo: blue
6
- sdk: gradio
7
- sdk_version: 5.46.0
8
- app_file: app.py
9
- pinned: false
10
- ---
11
-
12
- # Agriculture Data MCP Server
13
-
14
- Ce serveur MCP (Model Context Protocol) expose tous les outils d'analyse agricole et de visualisation de données via une interface Gradio. Il permet aux agents IA de se connecter aux données agricoles et de générer des rapports puissants.
15
-
16
- ## Fonctionnalités
17
-
18
- - **Analyse des herbicides** : Outils spécialisés pour analyser l'utilisation d'herbicides
19
- - **Visualisations** : Graphiques interactifs avec Plotly
20
- - **Base de données** : Requêtes sur les données agricoles Hugging Face
21
- - **Agent IA** : Interface pour connecter des LLM aux données et graphiques
22
-
23
- ## Utilisation
24
-
25
- 1. L'interface Gradio expose plusieurs outils MCP
26
- 2. Chaque outil peut être appelé par un agent IA
27
- 3. Les résultats incluent des visualisations et des analyses de données
28
-
29
- ## Déploiement
30
-
31
- Ce serveur est conçu pour être déployé sur Hugging Face Spaces avec le support MCP intégré.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app.py DELETED
@@ -1,303 +0,0 @@
1
- """
2
- Serveur MCP pour l'analyse des données agricoles
3
- Expose les outils d'analyse et de visualisation via Gradio avec support MCP
4
- """
5
- import os
6
- import json
7
- import traceback
8
- import pandas as pd
9
- import gradio as gr
10
- import plotly.express as px
11
- import plotly.graph_objects as go
12
- from plotly.subplots import make_subplots
13
-
14
- # Configuration pour désactiver les analytics Gradio
15
- os.environ["GRADIO_ANALYTICS_ENABLED"] = "False"
16
-
17
- # Import des modules locaux
18
- from data_loader import DataLoader
19
- from herbicide_analyzer import HerbicideAnalyzer
20
- from config import DATASET_ID, HF_TOKEN, PLOT_CONFIG
21
-
22
-
23
- class AgricultureMCPServer:
24
- """Serveur MCP pour l'analyse des données agricoles"""
25
-
26
- def __init__(self):
27
- self.data_loader = DataLoader()
28
- self.herbicide_analyzer = HerbicideAnalyzer()
29
- self.df = None
30
- self.is_data_loaded = False
31
-
32
- def load_agriculture_data(self) -> str:
33
- """
34
- Charge les données agricoles depuis Hugging Face
35
-
36
- Returns:
37
- str: Message de statut du chargement
38
- """
39
- try:
40
- status = self.data_loader.load_data()
41
- self.df = self.data_loader.get_data()
42
-
43
- if self.df is not None:
44
- self.herbicide_analyzer.set_data(self.df)
45
- self.is_data_loaded = True
46
- return f"✅ Données chargées: {len(self.df)} lignes, {len(self.df.columns)} colonnes"
47
- else:
48
- self.is_data_loaded = False
49
- return f"❌ Échec du chargement: {status}"
50
-
51
- except Exception as e:
52
- self.is_data_loaded = False
53
- return f"❌ Erreur lors du chargement: {str(e)}"
54
-
55
- def get_data_summary(self) -> str:
56
- """
57
- Obtient un résumé des données chargées
58
-
59
- Returns:
60
- str: JSON avec les statistiques des données
61
- """
62
- try:
63
- if not self.is_data_loaded or self.df is None:
64
- return json.dumps({"error": "Aucune donnée chargée. Utilisez load_agriculture_data() d'abord."})
65
-
66
- summary = {
67
- "nombre_lignes": len(self.df),
68
- "nombre_colonnes": len(self.df.columns),
69
- "colonnes": list(self.df.columns),
70
- "annees_disponibles": sorted(self.df['millesime'].unique().tolist()) if 'millesime' in self.df.columns else [],
71
- "nombre_parcelles": self.df['numparcell'].nunique() if 'numparcell' in self.df.columns else 0,
72
- "familles_produits": self.df['familleprod'].unique().tolist() if 'familleprod' in self.df.columns else []
73
- }
74
-
75
- return json.dumps(summary, indent=2, ensure_ascii=False)
76
-
77
- except Exception as e:
78
- return json.dumps({"error": f"Erreur lors du résumé: {str(e)}"})
79
-
80
- def analyze_herbicide_usage(self, year: int = 2023, analysis_type: str = "statistics") -> str:
81
- """
82
- Analyse l'utilisation des herbicides
83
-
84
- Args:
85
- year (int): Année à analyser
86
- analysis_type (str): Type d'analyse ("statistics", "top_parcels", "trends")
87
-
88
- Returns:
89
- str: JSON avec les résultats de l'analyse
90
- """
91
- try:
92
- if not self.is_data_loaded:
93
- return json.dumps({"error": "Données non chargées. Utilisez load_agriculture_data() d'abord."})
94
-
95
- if analysis_type == "statistics":
96
- stats, msg = self.herbicide_analyzer.get_herbicide_usage_statistics(year)
97
- if stats:
98
- return json.dumps({"status": msg, "data": stats}, indent=2, ensure_ascii=False)
99
- else:
100
- return json.dumps({"error": msg})
101
-
102
- elif analysis_type == "top_parcels":
103
- parcels, msg = self.herbicide_analyzer.get_top_ift_parcels_by_year(year, 10)
104
- if parcels is not None:
105
- # Convertir DataFrame en dict pour JSON
106
- return json.dumps({
107
- "status": msg,
108
- "data": parcels.to_dict('records')
109
- }, indent=2, ensure_ascii=False)
110
- else:
111
- return json.dumps({"error": msg})
112
-
113
- elif analysis_type == "trends":
114
- trends, msg = self.herbicide_analyzer.analyze_herbicide_trends_by_region()
115
- if trends is not None:
116
- return json.dumps({
117
- "status": msg,
118
- "data": trends.head(20).to_dict('records') # Limiter pour éviter des réponses trop longues
119
- }, indent=2, ensure_ascii=False)
120
- else:
121
- return json.dumps({"error": msg})
122
-
123
- else:
124
- return json.dumps({"error": f"Type d'analyse '{analysis_type}' non supporté"})
125
-
126
- except Exception as e:
127
- return json.dumps({"error": f"Erreur lors de l'analyse: {str(e)}"})
128
-
129
- def create_herbicide_visualization(self, year: int = 2023, chart_type: str = "top_ift") -> go.Figure:
130
- """
131
- Crée une visualisation des données herbicides
132
-
133
- Args:
134
- year (int): Année à analyser
135
- chart_type (str): Type de graphique ("top_ift", "regional_trends")
136
-
137
- Returns:
138
- plotly.graph_objects.Figure: Graphique Plotly
139
- """
140
- try:
141
- if not self.is_data_loaded:
142
- return self._create_error_plot("Données non chargées", "Utilisez load_agriculture_data() d'abord")
143
-
144
- return self.herbicide_analyzer.create_herbicide_visualization(
145
- analysis_type=chart_type,
146
- year=year,
147
- n_parcels=10
148
- )
149
-
150
- except Exception as e:
151
- return self._create_error_plot("Erreur de visualisation", f"Erreur: {str(e)}")
152
-
153
- def query_database(self, query_type: str, **kwargs) -> str:
154
- """
155
- Effectue une requête sur la base de données
156
-
157
- Args:
158
- query_type (str): Type de requête
159
- **kwargs: Paramètres de la requête
160
-
161
- Returns:
162
- str: JSON avec les résultats
163
- """
164
- try:
165
- if not self.is_data_loaded:
166
- return json.dumps({"error": "Données non chargées"})
167
-
168
- if query_type == "parcels_by_commune":
169
- commune = kwargs.get('commune', '')
170
- if 'nomcommune' in self.df.columns:
171
- results = self.df[self.df['nomcommune'].str.contains(commune, case=False, na=False)]
172
- return json.dumps({
173
- "count": len(results),
174
- "data": results.head(50).to_dict('records')
175
- }, ensure_ascii=False)
176
- else:
177
- return json.dumps({"error": "Colonne 'nomcommune' non disponible"})
178
-
179
- elif query_type == "products_by_year":
180
- year = kwargs.get('year', 2023)
181
- year_data = self.df[self.df['millesime'] == year]
182
- products = year_data['familleprod'].value_counts().to_dict() if 'familleprod' in year_data.columns else {}
183
- return json.dumps({
184
- "year": year,
185
- "products": products
186
- }, ensure_ascii=False)
187
-
188
- else:
189
- return json.dumps({"error": f"Type de requête '{query_type}' non supporté"})
190
-
191
- except Exception as e:
192
- return json.dumps({"error": f"Erreur de requête: {str(e)}"})
193
-
194
- def _create_error_plot(self, title: str, message: str) -> go.Figure:
195
- """Crée un graphique d'erreur"""
196
- fig = go.Figure()
197
- fig.add_annotation(
198
- text=message,
199
- xref="paper", yref="paper",
200
- x=0.5, y=0.5,
201
- showarrow=False,
202
- font=dict(size=14, color="red")
203
- )
204
- fig.update_layout(title=title, width=600, height=400)
205
- return fig
206
-
207
-
208
- # Initialisation du serveur MCP
209
- mcp_server = AgricultureMCPServer()
210
-
211
- # Interface Gradio avec support MCP
212
- with gr.Blocks(title="Agriculture Data MCP Server", theme=gr.themes.Soft()) as demo:
213
- gr.Markdown("""
214
- # 🌾 Agriculture Data MCP Server
215
-
216
- Ce serveur MCP expose des outils d'analyse des données agricoles via le Model Context Protocol.
217
- Connectez un agent IA pour analyser les données et générer des rapports puissants.
218
- """)
219
-
220
- with gr.Tab("📊 Chargement des Données"):
221
- load_btn = gr.Button("Charger les données depuis Hugging Face", variant="primary")
222
- load_output = gr.Textbox(label="Statut du chargement", lines=3)
223
-
224
- summary_btn = gr.Button("Obtenir le résumé des données")
225
- summary_output = gr.JSON(label="Résumé des données")
226
-
227
- with gr.Tab("🌿 Analyse des Herbicides"):
228
- with gr.Row():
229
- herb_year = gr.Number(value=2023, label="Année", precision=0)
230
- herb_analysis = gr.Dropdown(
231
- choices=["statistics", "top_parcels", "trends"],
232
- value="statistics",
233
- label="Type d'analyse"
234
- )
235
-
236
- herb_analyze_btn = gr.Button("Analyser les herbicides")
237
- herb_output = gr.JSON(label="Résultats de l'analyse")
238
-
239
- with gr.Tab("📈 Visualisations"):
240
- with gr.Row():
241
- viz_year = gr.Number(value=2023, label="Année", precision=0)
242
- viz_type = gr.Dropdown(
243
- choices=["top_ift", "regional_trends"],
244
- value="top_ift",
245
- label="Type de graphique"
246
- )
247
-
248
- viz_btn = gr.Button("Créer la visualisation")
249
- viz_output = gr.Plot(label="Graphique")
250
-
251
- with gr.Tab("🔍 Requêtes Base de Données"):
252
- with gr.Row():
253
- query_type = gr.Dropdown(
254
- choices=["parcels_by_commune", "products_by_year"],
255
- value="parcels_by_commune",
256
- label="Type de requête"
257
- )
258
- query_param = gr.Textbox(label="Paramètre (commune ou année)", value="")
259
-
260
- query_btn = gr.Button("Exécuter la requête")
261
- query_output = gr.JSON(label="Résultats de la requête")
262
-
263
- # Connexions des événements
264
- load_btn.click(
265
- fn=mcp_server.load_agriculture_data,
266
- outputs=load_output
267
- )
268
-
269
- summary_btn.click(
270
- fn=lambda: json.loads(mcp_server.get_data_summary()),
271
- outputs=summary_output
272
- )
273
-
274
- herb_analyze_btn.click(
275
- fn=lambda year, analysis: json.loads(mcp_server.analyze_herbicide_usage(int(year), analysis)),
276
- inputs=[herb_year, herb_analysis],
277
- outputs=herb_output
278
- )
279
-
280
- viz_btn.click(
281
- fn=mcp_server.create_herbicide_visualization,
282
- inputs=[viz_year, viz_type],
283
- outputs=viz_output
284
- )
285
-
286
- query_btn.click(
287
- fn=lambda qtype, param: json.loads(mcp_server.query_database(
288
- qtype,
289
- commune=param if qtype == "parcels_by_commune" else None,
290
- year=int(param) if qtype == "products_by_year" and param.isdigit() else 2023
291
- )),
292
- inputs=[query_type, query_param],
293
- outputs=query_output
294
- )
295
-
296
- # Lancement du serveur avec support MCP
297
- if __name__ == "__main__":
298
- demo.launch(
299
- server_name="0.0.0.0",
300
- server_port=7860,
301
- share=True,
302
- mcp_server=True # Active le support MCP
303
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
config.py DELETED
@@ -1,32 +0,0 @@
1
- """
2
- Configuration pour le serveur MCP Agriculture
3
- """
4
- import os
5
-
6
- # Configuration Hugging Face
7
- HF_TOKEN = os.environ.get("HF_TOKEN")
8
- DATASET_ID = "HackathonCRA/2024"
9
-
10
- # Colonnes requises dans le dataset
11
- REQUIRED_COLUMNS = ["numparcell", "surfparc", "millesime"]
12
-
13
- # Configuration des couleurs pour les graphiques
14
- RISK_COLORS = {
15
- 'high': '#FF4444',
16
- 'medium': '#FFA500',
17
- 'low': '#44AA44'
18
- }
19
-
20
- # Configuration des graphiques
21
- PLOT_CONFIG = {
22
- "width": 700,
23
- "height": 400,
24
- "template": "plotly_white"
25
- }
26
-
27
- # Messages constants
28
- MESSAGES = {
29
- "loading": "🔄 Chargement des données depuis Hugging Face...",
30
- "no_data": "❌ Impossible de charger les données",
31
- "success": "✅ Données chargées avec succès"
32
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
data_loader.py DELETED
@@ -1,142 +0,0 @@
1
- """
2
- Module de chargement des données depuis Hugging Face pour MCP
3
- """
4
- import os
5
- import traceback
6
- import pandas as pd
7
- from datasets import load_dataset
8
- from huggingface_hub import HfApi, hf_hub_download
9
- from config import HF_TOKEN, DATASET_ID, REQUIRED_COLUMNS, MESSAGES
10
-
11
-
12
- class DataLoader:
13
- """Classe responsable du chargement des données depuis différentes sources"""
14
-
15
- def __init__(self):
16
- self.df = None
17
-
18
- def load_data(self):
19
- """Charge les données du dataset avec gestion robuste des erreurs."""
20
- try:
21
- print(MESSAGES["loading"])
22
- print(f"📋 Dataset ID: {DATASET_ID}")
23
- print(f"📋 Token disponible: {'Oui' if HF_TOKEN else 'Non'}")
24
-
25
- self.df = None
26
-
27
- # Stratégie 1: Chargement direct Hugging Face
28
- print("🔄 Stratégie 1: chargement via datasets HF")
29
- hf_msg = self._safe_load_from_hf()
30
- if self.df is None:
31
- if hf_msg:
32
- print(f"❌ Chargement HF échoué: {hf_msg}")
33
-
34
- # Stratégie 2: Charger directement les fichiers du repo
35
- print("🔄 Stratégie 2: chargement via fichiers du dépôt")
36
- fallback_msg = self._fallback_load_from_repo_files()
37
- if self.df is None:
38
- if fallback_msg:
39
- print(f"❌ Chargement via fichiers échoué: {fallback_msg}")
40
- return MESSAGES["no_data"]
41
-
42
- if self.df is None:
43
- return MESSAGES["no_data"]
44
-
45
- print(f"📊 Données chargées: {len(self.df)} lignes")
46
- print(f"📊 Colonnes disponibles: {list(self.df.columns)}")
47
-
48
- # Validation des colonnes
49
- missing_cols = [col for col in REQUIRED_COLUMNS if col not in self.df.columns]
50
- if missing_cols:
51
- print(f"❌ Colonnes manquantes: {missing_cols}")
52
- self.df = None
53
- return f"❌ Colonnes manquantes: {missing_cols}"
54
-
55
- # Nettoyage
56
- initial_len = len(self.df)
57
- self.df = self.df.dropna(subset=REQUIRED_COLUMNS)
58
- print(f"📊 Après nettoyage: {len(self.df)} lignes (était {initial_len})")
59
-
60
- return MESSAGES["success"]
61
-
62
- except Exception as e:
63
- print(f"❌ Erreur générale: {str(e)}")
64
- print(f"❌ Traceback: {traceback.format_exc()}")
65
- return f"❌ Erreur: {str(e)}"
66
-
67
- def _safe_load_from_hf(self):
68
- """Chargement sécurisé depuis Hugging Face"""
69
- try:
70
- dataset = load_dataset(
71
- DATASET_ID,
72
- split="train",
73
- token=HF_TOKEN,
74
- trust_remote_code=True,
75
- )
76
- print(f"📊 Dataset chargé: {len(dataset)} exemples")
77
-
78
- try:
79
- self.df = dataset.to_pandas()
80
- print("✅ Conversion to_pandas() réussie")
81
- return None
82
- except Exception as pandas_error:
83
- print(f"❌ Erreur to_pandas(): {pandas_error}")
84
- print("🔄 Tentative de conversion manuelle...")
85
- data_list = []
86
- for i, item in enumerate(dataset):
87
- data_list.append(item)
88
- if i < 5:
89
- print(f"📋 Exemple {i}: {list(item.keys())}")
90
- self.df = pd.DataFrame(data_list)
91
- print(f"✅ Conversion manuelle réussie: {len(self.df)} lignes")
92
- return None
93
- except Exception as e:
94
- return f"Erreur HF: {str(e)}"
95
-
96
- def _fallback_load_from_repo_files(self):
97
- """Fallback pour charger les données en téléchargeant directement les fichiers du repo HF."""
98
- try:
99
- print("🔄 Tentative de chargement alternatif via fichiers du dépôt...")
100
- api = HfApi(token=HF_TOKEN)
101
- repo_files = api.list_repo_files(repo_id=DATASET_ID, repo_type="dataset")
102
-
103
- # Chercher des fichiers de données
104
- data_files = [f for f in repo_files if f.endswith(('.csv', '.parquet', '.tsv', '.json'))]
105
- print(f"📁 Fichiers de données trouvés: {data_files}")
106
-
107
- if not data_files:
108
- return "Aucun fichier de données trouvé"
109
-
110
- # Essayer de charger le premier fichier trouvé
111
- for file_path in data_files:
112
- try:
113
- print(f"📥 Téléchargement de {file_path}...")
114
- local_file = hf_hub_download(
115
- repo_id=DATASET_ID,
116
- filename=file_path,
117
- repo_type="dataset",
118
- token=HF_TOKEN
119
- )
120
-
121
- if file_path.endswith('.csv') or file_path.endswith('.tsv'):
122
- sep = '\t' if file_path.endswith('.tsv') else ','
123
- self.df = pd.read_csv(local_file, sep=sep)
124
- elif file_path.endswith('.parquet'):
125
- self.df = pd.read_parquet(local_file)
126
- elif file_path.endswith('.json'):
127
- self.df = pd.read_json(local_file)
128
-
129
- if self.df is not None and len(self.df) > 0:
130
- print(f"✅ Fichier {file_path} chargé avec succès: {len(self.df)} lignes")
131
- return None
132
- except Exception as file_error:
133
- print(f"❌ Erreur avec {file_path}: {file_error}")
134
- continue
135
-
136
- return "Impossible de charger aucun fichier"
137
- except Exception as e:
138
- return f"Erreur fallback: {str(e)}"
139
-
140
- def get_data(self):
141
- """Retourne les données chargées"""
142
- return self.df
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
example_agent_usage.py DELETED
@@ -1,151 +0,0 @@
1
- """
2
- Exemple d'utilisation du serveur MCP Agriculture par un agent IA
3
- """
4
- import json
5
- import requests
6
- import time
7
- from typing import Dict, Any
8
-
9
-
10
- class AIAgentMCPClient:
11
- """Client MCP pour agent IA"""
12
-
13
- def __init__(self, server_url: str = "http://localhost:7860"):
14
- self.server_url = server_url.rstrip('/')
15
- self.session = requests.Session()
16
-
17
- def call_mcp_tool(self, tool_name: str, **kwargs) -> Dict[str, Any]:
18
- """
19
- Appelle un outil MCP sur le serveur
20
-
21
- Args:
22
- tool_name (str): Nom de l'outil MCP
23
- **kwargs: Paramètres de l'outil
24
-
25
- Returns:
26
- Dict: Résultat de l'outil
27
- """
28
- try:
29
- # Pour ce serveur Gradio, nous simulons l'appel MCP
30
- # En production, ceci utiliserait le protocol MCP standard
31
-
32
- if tool_name == "load_agriculture_data":
33
- return {"status": "✅ Données chargées avec succès"}
34
-
35
- elif tool_name == "get_data_summary":
36
- return {
37
- "nombre_lignes": 50000,
38
- "nombre_colonnes": 15,
39
- "annees_disponibles": [2020, 2021, 2022, 2023],
40
- "familles_produits": ["Herbicides", "Fongicides", "Insecticides"]
41
- }
42
-
43
- elif tool_name == "analyze_herbicide_usage":
44
- return {
45
- "status": "✅ Analyse terminée",
46
- "data": {
47
- "nombre_parcelles": 12500,
48
- "surface_totale": 45678.9,
49
- "ift_moyen": 2.34,
50
- "nombre_communes": 156
51
- }
52
- }
53
-
54
- else:
55
- return {"error": f"Outil '{tool_name}' non trouvé"}
56
-
57
- except Exception as e:
58
- return {"error": f"Erreur d'appel MCP: {str(e)}"}
59
-
60
-
61
- def demonstrate_ai_agent_workflow():
62
- """Démontre un workflow typique d'agent IA avec le serveur MCP"""
63
-
64
- print("🤖 Démonstration d'un Agent IA avec MCP Agriculture")
65
- print("=" * 60)
66
-
67
- # Initialiser le client MCP
68
- agent = AIAgentMCPClient()
69
-
70
- # Scénario: L'agent doit analyser l'utilisation d'herbicides en 2023
71
- print("📋 Tâche: Analyser l'utilisation d'herbicides en 2023")
72
- print()
73
-
74
- # Étape 1: Charger les données
75
- print("1️⃣ Chargement des données...")
76
- result = agent.call_mcp_tool("load_agriculture_data")
77
- print(f" {result.get('status', result)}")
78
- print()
79
-
80
- # Étape 2: Obtenir un aperçu des données
81
- print("2️⃣ Obtention du résumé des données...")
82
- summary = agent.call_mcp_tool("get_data_summary")
83
- if "error" not in summary:
84
- print(f" 📊 {summary['nombre_lignes']} lignes de données")
85
- print(f" 📅 Années: {summary['annees_disponibles']}")
86
- print(f" 🧪 Produits: {', '.join(summary['familles_produits'])}")
87
- else:
88
- print(f" ❌ {summary['error']}")
89
- print()
90
-
91
- # Étape 3: Analyser les herbicides
92
- print("3️⃣ Analyse des herbicides pour 2023...")
93
- analysis = agent.call_mcp_tool("analyze_herbicide_usage", year=2023, analysis_type="statistics")
94
- if "error" not in analysis:
95
- data = analysis.get('data', {})
96
- print(f" 🌿 Parcelles analysées: {data.get('nombre_parcelles', 0):,}")
97
- print(f" 📏 Surface totale: {data.get('surface_totale', 0):,.1f} ha")
98
- print(f" 📊 IFT moyen: {data.get('ift_moyen', 0):.2f}")
99
- print(f" 🏘️ Communes: {data.get('nombre_communes', 0)}")
100
- else:
101
- print(f" ❌ {analysis['error']}")
102
- print()
103
-
104
- # Étape 4: Génération du rapport
105
- print("4️⃣ Génération du rapport...")
106
- report = generate_ai_report(summary, analysis)
107
- print(report)
108
- print()
109
-
110
- print("✅ Workflow d'agent IA terminé!")
111
-
112
-
113
- def generate_ai_report(summary: Dict, analysis: Dict) -> str:
114
- """Génère un rapport IA basé sur les données analysées"""
115
-
116
- if "error" in summary or "error" in analysis:
117
- return "❌ Impossible de générer le rapport à cause d'erreurs dans les données"
118
-
119
- data = analysis.get('data', {})
120
-
121
- report = f"""
122
- 📊 RAPPORT D'ANALYSE - HERBICIDES 2023
123
- {'='*50}
124
-
125
- 📈 DONNÉES GÉNÉRALES:
126
- • Dataset: {summary.get('nombre_lignes', 0):,} lignes de données
127
- • Couverture: {len(summary.get('annees_disponibles', []))} années
128
- • Types de produits: {len(summary.get('familles_produits', []))}
129
-
130
- 🌿 ANALYSE HERBICIDES:
131
- • Parcelles analysées: {data.get('nombre_parcelles', 0):,}
132
- • Surface totale: {data.get('surface_totale', 0):,.1f} hectares
133
- • IFT moyen: {data.get('ift_moyen', 0):.2f}
134
- • Communes concernées: {data.get('nombre_communes', 0)}
135
-
136
- 💡 INSIGHTS:
137
- • L'IFT moyen de {data.get('ift_moyen', 0):.2f} indique {'un usage modéré' if data.get('ift_moyen', 0) < 3 else 'un usage intensif'} d'herbicides
138
- • La couverture de {data.get('nombre_communes', 0)} communes offre une bonne représentativité territoriale
139
- • Les données couvrent {data.get('surface_totale', 0):,.0f} ha, soit un échantillon significatif
140
-
141
- 🎯 RECOMMANDATIONS:
142
- 1. Analyser les parcelles avec IFT élevé pour identifier les pratiques optimisables
143
- 2. Comparer les tendances entre régions pour partager les bonnes pratiques
144
- 3. Suivre l'évolution de l'IFT moyen sur plusieurs années
145
- """
146
-
147
- return report
148
-
149
-
150
- if __name__ == "__main__":
151
- demonstrate_ai_agent_workflow()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
herbicide_analyzer.py DELETED
@@ -1,187 +0,0 @@
1
- """
2
- Module d'analyse avancée des herbicides pour MCP
3
- """
4
- import pandas as pd
5
- import plotly.express as px
6
- import plotly.graph_objects as go
7
- from plotly.subplots import make_subplots
8
- import numpy as np
9
- from datetime import datetime, timedelta
10
-
11
-
12
- class HerbicideAnalyzer:
13
- """Classe spécialisée dans l'analyse avancée des herbicides"""
14
-
15
- def __init__(self, data=None):
16
- self.df = data
17
-
18
- def set_data(self, data):
19
- """Définit les données à analyser"""
20
- self.df = data
21
-
22
- def get_top_ift_parcels_by_year(self, year, n_parcels=10):
23
- """
24
- Retourne les N parcelles avec les IFT herbicides les plus élevés pour une année donnée
25
- """
26
- try:
27
- if self.df is None or len(self.df) == 0:
28
- return None, "❌ Aucune donnée disponible"
29
-
30
- # Filtrer par année et herbicides
31
- year_data = self.df[
32
- (self.df['millesime'] == year) &
33
- (self.df['familleprod'] == 'Herbicides')
34
- ].copy()
35
-
36
- if len(year_data) == 0:
37
- return None, f"❌ Aucune donnée d'herbicides pour l'année {year}"
38
-
39
- # Calculer l'IFT par parcelle
40
- if 'quantitetot' not in year_data.columns:
41
- return None, "❌ Colonne 'quantitetot' manquante pour le calcul de l'IFT"
42
-
43
- # Agrégation par parcelle
44
- ift_by_parcel = year_data.groupby('numparcell').agg({
45
- 'quantitetot': 'sum',
46
- 'surfparc': 'first',
47
- 'codeinsee': 'first',
48
- 'nomcommune': 'first' if 'nomcommune' in year_data.columns else 'first'
49
- }).reset_index()
50
-
51
- # Calcul de l'IFT (quantité totale / surface)
52
- ift_by_parcel['ift_herbicides'] = ift_by_parcel['quantitetot'] / ift_by_parcel['surfparc']
53
-
54
- # Top N parcelles
55
- top_parcels = ift_by_parcel.nlargest(n_parcels, 'ift_herbicides')
56
-
57
- return top_parcels, f"✅ Top {len(top_parcels)} parcelles avec IFT herbicides élevé trouvées"
58
-
59
- except Exception as e:
60
- return None, f"❌ Erreur dans l'analyse des IFT: {str(e)}"
61
-
62
- def analyze_herbicide_trends_by_region(self, years_range=None):
63
- """
64
- Analyse les tendances d'utilisation d'herbicides par région
65
- """
66
- try:
67
- if self.df is None or len(self.df) == 0:
68
- return None, "❌ Aucune donnée disponible"
69
-
70
- # Filtrer les herbicides
71
- herbicide_data = self.df[self.df['familleprod'] == 'Herbicides'].copy()
72
-
73
- if len(herbicide_data) == 0:
74
- return None, "❌ Aucune donnée d'herbicides trouvée"
75
-
76
- # Filtrer par années si spécifié
77
- if years_range:
78
- herbicide_data = herbicide_data[
79
- herbicide_data['millesime'].between(years_range[0], years_range[1])
80
- ]
81
-
82
- # Grouper par région et année
83
- if 'codeinsee' not in herbicide_data.columns:
84
- return None, "❌ Colonne 'codeinsee' manquante"
85
-
86
- regional_trends = herbicide_data.groupby(['codeinsee', 'millesime']).agg({
87
- 'quantitetot': 'sum',
88
- 'surfparc': 'sum',
89
- 'nomcommune': 'first' if 'nomcommune' in herbicide_data.columns else 'first'
90
- }).reset_index()
91
-
92
- # Calcul de l'IFT régional
93
- regional_trends['ift_regional'] = regional_trends['quantitetot'] / regional_trends['surfparc']
94
-
95
- return regional_trends, f"✅ Analyse des tendances pour {len(regional_trends)} régions/années"
96
-
97
- except Exception as e:
98
- return None, f"❌ Erreur dans l'analyse des tendances: {str(e)}"
99
-
100
- def get_herbicide_usage_statistics(self, year=None):
101
- """
102
- Retourne des statistiques détaillées sur l'utilisation d'herbicides
103
- """
104
- try:
105
- if self.df is None or len(self.df) == 0:
106
- return None, "❌ Aucune donnée disponible"
107
-
108
- herbicide_data = self.df[self.df['familleprod'] == 'Herbicides'].copy()
109
-
110
- if year:
111
- herbicide_data = herbicide_data[herbicide_data['millesime'] == year]
112
-
113
- if len(herbicide_data) == 0:
114
- return None, f"❌ Aucune donnée d'herbicides pour l'année {year if year else 'toutes'}"
115
-
116
- stats = {
117
- 'nombre_parcelles': herbicide_data['numparcell'].nunique(),
118
- 'surface_totale': herbicide_data['surfparc'].sum(),
119
- 'quantite_totale': herbicide_data['quantitetot'].sum(),
120
- 'ift_moyen': herbicide_data['quantitetot'].sum() / herbicide_data['surfparc'].sum(),
121
- 'nombre_communes': herbicide_data['codeinsee'].nunique() if 'codeinsee' in herbicide_data.columns else 0,
122
- 'annees_couvertes': sorted(herbicide_data['millesime'].unique().tolist())
123
- }
124
-
125
- return stats, "✅ Statistiques calculées avec succès"
126
-
127
- except Exception as e:
128
- return None, f"❌ Erreur dans le calcul des statistiques: {str(e)}"
129
-
130
- def create_herbicide_visualization(self, analysis_type="trends", **kwargs):
131
- """
132
- Crée des visualisations pour l'analyse des herbicides
133
- """
134
- try:
135
- if analysis_type == "top_ift":
136
- year = kwargs.get('year', 2023)
137
- n_parcels = kwargs.get('n_parcels', 10)
138
- data, msg = self.get_top_ift_parcels_by_year(year, n_parcels)
139
-
140
- if data is None:
141
- return self._create_error_plot("Erreur Top IFT", msg)
142
-
143
- fig = px.bar(
144
- data,
145
- x='numparcell',
146
- y='ift_herbicides',
147
- title=f'Top {n_parcels} Parcelles - IFT Herbicides {year}',
148
- labels={'ift_herbicides': 'IFT Herbicides', 'numparcell': 'Numéro Parcelle'}
149
- )
150
-
151
- elif analysis_type == "regional_trends":
152
- years_range = kwargs.get('years_range', None)
153
- data, msg = self.analyze_herbicide_trends_by_region(years_range)
154
-
155
- if data is None:
156
- return self._create_error_plot("Erreur Tendances Régionales", msg)
157
-
158
- fig = px.line(
159
- data,
160
- x='millesime',
161
- y='ift_regional',
162
- color='codeinsee',
163
- title='Tendances IFT Herbicides par Région',
164
- labels={'ift_regional': 'IFT Régional', 'millesime': 'Année'}
165
- )
166
-
167
- else:
168
- return self._create_error_plot("Type d'analyse non supporté", f"Type '{analysis_type}' non reconnu")
169
-
170
- fig.update_layout(width=800, height=500)
171
- return fig
172
-
173
- except Exception as e:
174
- return self._create_error_plot("Erreur de visualisation", f"Erreur: {str(e)}")
175
-
176
- def _create_error_plot(self, title, message):
177
- """Crée un graphique d'erreur"""
178
- fig = go.Figure()
179
- fig.add_annotation(
180
- text=message,
181
- xref="paper", yref="paper",
182
- x=0.5, y=0.5,
183
- showarrow=False,
184
- font=dict(size=14, color="red")
185
- )
186
- fig.update_layout(title=title, width=600, height=400)
187
- return fig
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
requirements.txt DELETED
@@ -1,11 +0,0 @@
1
- gradio[mcp]>=5.46.0
2
- pandas>=2.0.0
3
- numpy>=1.24.0
4
- plotly>=5.17.0
5
- seaborn>=0.12.0
6
- matplotlib>=3.7.0
7
- datasets>=2.14.0
8
- huggingface_hub>=0.17.0
9
- pyarrow>=12.0.0
10
- scikit-learn>=1.3.0
11
- textblob>=0.17.1
 
 
 
 
 
 
 
 
 
 
 
 
run_server.sh DELETED
@@ -1,30 +0,0 @@
1
- #!/bin/bash
2
-
3
- # Script de lancement du serveur MCP Agriculture
4
- echo "🌾 Lancement du serveur MCP Agriculture"
5
- echo "======================================"
6
-
7
- # Vérifier si Python est disponible
8
- if ! command -v python3 &> /dev/null; then
9
- echo "❌ Python3 n'est pas installé"
10
- exit 1
11
- fi
12
-
13
- # Installer les dépendances si nécessaire
14
- if [ ! -d "venv" ]; then
15
- echo "📦 Création de l'environnement virtuel..."
16
- python3 -m venv venv
17
- source venv/bin/activate
18
- pip install -r requirements.txt
19
- else
20
- echo "📦 Activation de l'environnement virtuel..."
21
- source venv/bin/activate
22
- fi
23
-
24
- # Tester le serveur
25
- echo "🧪 Test du serveur..."
26
- python test_mcp_server.py
27
-
28
- # Lancer le serveur Gradio
29
- echo "🚀 Lancement du serveur MCP sur http://localhost:7860"
30
- python app.py
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
test_mcp_server.py DELETED
@@ -1,94 +0,0 @@
1
- """
2
- Script de test pour le serveur MCP Agriculture
3
- """
4
- import json
5
- import sys
6
- import os
7
-
8
- # Ajouter le répertoire courant au path pour les imports
9
- sys.path.append(os.path.dirname(os.path.abspath(__file__)))
10
-
11
- from app import AgricultureMCPServer
12
-
13
-
14
- def test_mcp_server():
15
- """Test du serveur MCP"""
16
- print("🧪 Test du serveur MCP Agriculture")
17
- print("=" * 50)
18
-
19
- # Initialiser le serveur
20
- server = AgricultureMCPServer()
21
-
22
- # Test 1: Chargement des données
23
- print("📊 Test 1: Chargement des données")
24
- result = server.load_agriculture_data()
25
- print(f"Résultat: {result}")
26
- print()
27
-
28
- # Test 2: Résumé des données
29
- print("📋 Test 2: Résumé des données")
30
- summary = server.get_data_summary()
31
- try:
32
- summary_data = json.loads(summary)
33
- if "error" in summary_data:
34
- print(f"❌ Erreur: {summary_data['error']}")
35
- else:
36
- print(f"✅ Données disponibles: {summary_data.get('nombre_lignes', 0)} lignes")
37
- print(f" Colonnes: {len(summary_data.get('colonnes', []))}")
38
- print(f" Années: {summary_data.get('annees_disponibles', [])}")
39
- except json.JSONDecodeError:
40
- print(f"❌ Erreur de parsing JSON: {summary}")
41
- print()
42
-
43
- # Test 3: Analyse des herbicides
44
- print("🌿 Test 3: Analyse des herbicides")
45
- herb_result = server.analyze_herbicide_usage(2023, "statistics")
46
- try:
47
- herb_data = json.loads(herb_result)
48
- if "error" in herb_data:
49
- print(f"❌ Erreur: {herb_data['error']}")
50
- else:
51
- print(f"✅ Analyse réussie: {herb_data.get('status', 'OK')}")
52
- if "data" in herb_data:
53
- data = herb_data["data"]
54
- print(f" Parcelles: {data.get('nombre_parcelles', 0)}")
55
- print(f" Surface totale: {data.get('surface_totale', 0):.2f}")
56
- except json.JSONDecodeError:
57
- print(f"❌ Erreur de parsing JSON: {herb_result}")
58
- print()
59
-
60
- # Test 4: Visualisation
61
- print("📈 Test 4: Création de visualisation")
62
- try:
63
- fig = server.create_herbicide_visualization(2023, "top_ift")
64
- if fig and hasattr(fig, 'data'):
65
- print("✅ Visualisation créée avec succès")
66
- print(f" Type: {type(fig).__name__}")
67
- else:
68
- print("❌ Échec de création de la visualisation")
69
- except Exception as e:
70
- print(f"❌ Erreur lors de la visualisation: {str(e)}")
71
- print()
72
-
73
- # Test 5: Requête base de données
74
- print("🔍 Test 5: Requête base de données")
75
- query_result = server.query_database("products_by_year", year=2023)
76
- try:
77
- query_data = json.loads(query_result)
78
- if "error" in query_data:
79
- print(f"❌ Erreur: {query_data['error']}")
80
- else:
81
- print(f"✅ Requête réussie pour l'année {query_data.get('year', 2023)}")
82
- products = query_data.get('products', {})
83
- print(f" Produits trouvés: {len(products)}")
84
- for prod, count in list(products.items())[:3]: # Afficher les 3 premiers
85
- print(f" - {prod}: {count}")
86
- except json.JSONDecodeError:
87
- print(f"❌ Erreur de parsing JSON: {query_result}")
88
- print()
89
-
90
- print("🎉 Tests terminés!")
91
-
92
-
93
- if __name__ == "__main__":
94
- test_mcp_server()