MMOON commited on
Commit
b528f28
·
verified ·
1 Parent(s): f989150

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +161 -155
app.py CHANGED
@@ -1,162 +1,168 @@
1
  import subprocess
2
  import json
 
3
  import gradio as gr
4
  import pandas as pd
5
-
6
- def fetch_pesticide_data(url, output_file):
7
- """
8
- Fetch data from the EU Pesticides Database API using curl.
9
- Args:
10
- url (str): The API endpoint URL.
11
- output_file (str): The file to save the JSON response.
12
- Returns:
13
- dict: JSON response from the API or an error dictionary.
14
- """
15
- try:
16
- # Command to execute curl and save the output to a file
17
- command = [
18
- 'curl', '-H', 'Content-Type: application/json',
19
- '-H', 'Cache-Control: no-cache',
20
- '-H', 'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
21
- url,
22
- '-o', output_file
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23
  ]
24
 
25
- # Execute the curl command
26
- subprocess.run(command, check=True)
27
-
28
- # Read the JSON data from the file
29
- with open(output_file, 'r') as file:
30
- data = json.load(file)
31
-
32
- return data
33
-
34
- except subprocess.CalledProcessError as e:
35
- return {"error": f"Curl command failed: {str(e)}"}
36
- except Exception as e:
37
- return {"error": str(e)}
38
-
39
- def fetch_products():
40
- """
41
- Fetch products from the EU Pesticides Database API.
42
- Returns:
43
- list: List of product names and IDs.
44
- """
45
- url = "https://api.datalake.sante.service.ec.europa.eu/sante/pesticides/pesticide_residues_products?format=json&language=EN&api-version=v2.0"
46
- output_file = "products.json"
47
- products_response = fetch_pesticide_data(url, output_file)
48
-
49
- if "error" in products_response:
50
- return []
51
-
52
- # Extract product names and IDs for display
53
- product_choices = [
54
- f"{product['product_name']} (ID: {product['product_id']})"
55
- for product in products_response.get("value", [])
56
- ]
57
- return product_choices
58
-
59
- def fetch_pesticide_residues(product_id):
60
- """
61
- Fetch pesticide residues for a specific product.
62
- Args:
63
- product_id (int): The ID of the product.
64
- Returns:
65
- dict: Pesticide residues data for the product.
66
- """
67
- url = f"https://api.datalake.sante.service.ec.europa.eu/sante/pesticides/pesticide_residues?format=json&pesticide_residue_lg=EN&api-version=v2.0"
68
- output_file = "pesticide_residues.json"
69
- residues_response = fetch_pesticide_data(url, output_file)
70
-
71
- if "error" in residues_response:
72
- return residues_response
73
-
74
- # Filter residues for the specific product
75
- residues = [
76
- residue for residue in residues_response.get("value", [])
77
- if residue.get("product_id") == product_id
78
- ]
79
- return residues
80
-
81
- def fetch_pesticide_mrls(product_id):
82
- """
83
- Fetch MRLs for a specific product.
84
- Args:
85
- product_id (int): The ID of the product.
86
- Returns:
87
- dict: MRL data for the product.
88
- """
89
- url = f"https://api.datalake.sante.service.ec.europa.eu/sante/pesticides/pesticide_residues_mrls?format=json&product_id={product_id}&api-version=v2.0"
90
- output_file = "pesticide_mrls.json"
91
- mrls_response = fetch_pesticide_data(url, output_file)
92
-
93
- if "error" in mrls_response:
94
- return mrls_response
95
-
96
- return mrls_response
97
-
98
- def create_pesticide_interface():
99
- """
100
- Create Gradio interface for Pesticide Database.
101
- """
102
- # Fetch initial products
103
- product_choices = fetch_products()
104
-
105
- def get_product_details(product_name, date_filter):
106
- """Get details for a specific product."""
107
- if not product_name:
108
- return {"error": "No product selected"}
109
-
110
- # Extract product ID from the product name
111
- product_id = int(product_name.split(" (ID: ")[1].split(")")[0])
112
-
113
- # Fetch pesticide residues
114
- residues = fetch_pesticide_residues(product_id)
115
- if "error" in residues:
116
- return residues
117
-
118
- # Fetch MRLs
119
- mrls = fetch_pesticide_mrls(product_id)
120
- if "error" in mrls:
121
- return mrls
122
-
123
- # Filter MRLs by date if a date filter is provided
124
- if date_filter:
125
- mrls["value"] = [
126
- mrl for mrl in mrls.get("value", [])
127
- if mrl.get("entry_into_force_date") == date_filter
128
- ]
129
-
130
- # Convert residues and MRLs to DataFrames for display
131
- residues_df = pd.DataFrame(residues)
132
- mrls_df = pd.DataFrame(mrls.get("value", []))
133
-
134
- return residues_df, mrls_df
135
-
136
- # Gradio Interface
137
- with gr.Blocks() as interface:
138
- gr.Markdown("## EU Pesticides Database Explorer")
139
- gr.Markdown("Fetch and view data from the EU Pesticides Database")
140
-
141
- with gr.Row():
142
- product_dropdown = gr.Dropdown(label="Select Product", choices=product_choices)
143
- date_filter = gr.Textbox(label="Filter by Entry into Force Date (YYYY-MM-DD)", placeholder="YYYY-MM-DD")
144
- fetch_btn = gr.Button("Get Details")
145
-
146
- with gr.Row():
147
- residues_table = gr.Dataframe(label="Pesticide Residues")
148
- mrls_table = gr.Dataframe(label="MRLs")
149
-
150
- # Get product details
151
- fetch_btn.click(
152
- fn=get_product_details,
153
- inputs=[product_dropdown, date_filter],
154
- outputs=[residues_table, mrls_table]
155
- )
156
-
157
- return interface
158
-
159
- # Launch the interface
160
  if __name__ == "__main__":
161
- interface = create_pesticide_interface()
162
- interface.launch(share=True)
 
1
  import subprocess
2
  import json
3
+ from datetime import datetime, timedelta
4
  import gradio as gr
5
  import pandas as pd
6
+ from typing import Dict, List, Tuple, Optional
7
+ import logging
8
+
9
+ # Configuration du logging
10
+ logging.basicConfig(level=logging.INFO)
11
+ logger = logging.getLogger(__name__)
12
+
13
+ class PesticideDataFetcher:
14
+ """Classe pour gérer la récupération des données sur les pesticides."""
15
+
16
+ BASE_URL = "https://api.datalake.sante.service.ec.europa.eu/sante/pesticides"
17
+ HEADERS = {
18
+ 'Content-Type': 'application/json',
19
+ 'Cache-Control': 'no-cache',
20
+ 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
21
+ }
22
+
23
+ @staticmethod
24
+ def fetch_data(url: str, output_file: str) -> Dict:
25
+ """
26
+ Récupère les données depuis l'API avec gestion d'erreurs améliorée.
27
+ """
28
+ try:
29
+ command = ['curl'] + [
30
+ item for header, value in PesticideDataFetcher.HEADERS.items()
31
+ for item in ['-H', f'{header}: {value}']
32
+ ] + [url, '-o', output_file]
33
+
34
+ subprocess.run(command, check=True, capture_output=True)
35
+
36
+ with open(output_file, 'r') as file:
37
+ return json.load(file)
38
+
39
+ except Exception as e:
40
+ logger.error(f"Erreur lors de la récupération des données: {str(e)}")
41
+ return {"error": str(e)}
42
+
43
+ @classmethod
44
+ def get_products(cls) -> List[Dict]:
45
+ """Récupère la liste des produits."""
46
+ url = f"{cls.BASE_URL}/pesticide_residues_products?format=json&language=FR&api-version=v2.0"
47
+ response = cls.fetch_data(url, "products.json")
48
+ return response.get("value", [])
49
+
50
+ @classmethod
51
+ def get_residues(cls, product_id: int) -> List[Dict]:
52
+ """Récupère les résidus pour un produit spécifique."""
53
+ url = f"{cls.BASE_URL}/pesticide_residues?format=json&pesticide_residue_lg=FR&api-version=v2.0"
54
+ response = cls.fetch_data(url, "residues.json")
55
+ return [r for r in response.get("value", []) if r.get("product_id") == product_id]
56
+
57
+ @classmethod
58
+ def get_mrls(cls, product_id: int) -> List[Dict]:
59
+ """Récupère les LMR pour un produit spécifique."""
60
+ url = f"{cls.BASE_URL}/pesticide_residues_mrls?format=json&product_id={product_id}&api-version=v2.0"
61
+ response = cls.fetch_data(url, "mrls.json")
62
+ return response.get("value", [])
63
+
64
+ class PesticideInterface:
65
+ """Classe pour gérer l'interface utilisateur Gradio."""
66
+
67
+ def __init__(self):
68
+ self.fetcher = PesticideDataFetcher()
69
+ self.products = self.fetcher.get_products()
70
+ self.product_choices = {
71
+ f"{p['product_name']} (ID: {p['product_id']})": p['product_id']
72
+ for p in self.products
73
+ }
74
+
75
+ def filter_by_period(self, data: List[Dict], period: str) -> List[Dict]:
76
+ """Filtre les données selon la période sélectionnée."""
77
+ if period == "Toutes les dates":
78
+ return data
79
+
80
+ today = datetime.now()
81
+ if period == "Dernière semaine":
82
+ start_date = today - timedelta(days=7)
83
+ elif period == "Dernier mois":
84
+ start_date = today - timedelta(days=30)
85
+
86
+ return [
87
+ item for item in data
88
+ if datetime.strptime(item.get("entry_into_force_date", ""), "%Y-%m-%d") >= start_date
89
  ]
90
 
91
+ def get_product_details(self,
92
+ product_name: str,
93
+ period: str) -> Tuple[Optional[pd.DataFrame], Optional[pd.DataFrame]]:
94
+ """Récupère et formate les détails d'un produit."""
95
+ try:
96
+ if not product_name:
97
+ raise ValueError("Aucun produit sélectionné")
98
+
99
+ product_id = self.product_choices[product_name]
100
+
101
+ # Récupération des données
102
+ residues = self.fetcher.get_residues(product_id)
103
+ mrls = self.fetcher.get_mrls(product_id)
104
+
105
+ # Filtrage par période
106
+ filtered_mrls = self.filter_by_period(mrls, period)
107
+
108
+ # Création des DataFrames avec colonnes sélectionnées
109
+ residues_df = pd.DataFrame(residues)[['substance_name', 'residue_definition', 'notes']]
110
+ mrls_df = pd.DataFrame(filtered_mrls)[['substance_name', 'mrl_value', 'entry_into_force_date']]
111
+
112
+ # Formatage des DataFrames
113
+ residues_df.columns = ['Substance', 'Définition du résidu', 'Notes']
114
+ mrls_df.columns = ['Substance', 'Valeur LMR', 'Date d\'entrée en vigueur']
115
+
116
+ return residues_df, mrls_df
117
+
118
+ except Exception as e:
119
+ logger.error(f"Erreur lors de la récupération des détails: {str(e)}")
120
+ return None, None
121
+
122
+ def create_interface(self) -> gr.Blocks:
123
+ """Crée l'interface Gradio avec un design amélioré."""
124
+ with gr.Blocks(theme=gr.themes.Soft()) as interface:
125
+ gr.Markdown("# 🌿 Base de données des pesticides de l'UE")
126
+
127
+ with gr.Box():
128
+ gr.Markdown("### Sélectionnez un produit et une période")
129
+ with gr.Row():
130
+ with gr.Column(scale=2):
131
+ product_dropdown = gr.Dropdown(
132
+ choices=list(self.product_choices.keys()),
133
+ label="Produit",
134
+ info="Choisissez un produit dans la liste"
135
+ )
136
+ with gr.Column(scale=1):
137
+ period_radio = gr.Radio(
138
+ choices=["Dernière semaine", "Dernier mois", "Toutes les dates"],
139
+ value="Toutes les dates",
140
+ label="Période",
141
+ info="Sélectionnez la période d'analyse"
142
+ )
143
+
144
+ with gr.Row():
145
+ fetch_btn = gr.Button("📊 Analyser les données", variant="primary")
146
+
147
+ with gr.Tabs():
148
+ with gr.TabItem("Résidus de pesticides"):
149
+ residues_table = gr.DataFrame(label="")
150
+ with gr.TabItem("Limites Maximales de Résidus (LMR)"):
151
+ mrls_table = gr.DataFrame(label="")
152
+
153
+ # Event handler
154
+ fetch_btn.click(
155
+ fn=self.get_product_details,
156
+ inputs=[product_dropdown, period_radio],
157
+ outputs=[residues_table, mrls_table]
158
+ )
159
+
160
+ return interface
161
+
162
+ def main():
163
+ interface = PesticideInterface()
164
+ app = interface.create_interface()
165
+ app.launch(share=True)
166
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
167
  if __name__ == "__main__":
168
+ main()