Spaces:
GIZ
/
Running on CPU Upgrade

Romulan12 commited on
Commit
c71c0cf
·
1 Parent(s): ca952fb
Files changed (1) hide show
  1. app.py +326 -105
app.py CHANGED
@@ -1,11 +1,10 @@
1
  import gradio as gr
2
  import time
3
  import pandas as pd
4
- import asyncio
5
  from uuid import uuid4
6
  from gradio_client import Client, handle_file
7
 
8
- # Sample questions for examples
9
  SAMPLE_QUESTIONS = {
10
  "Deforestation Analysis": [
11
  "What are the main deforestation hotspots in Ecuador?",
@@ -24,130 +23,145 @@ SAMPLE_QUESTIONS = {
24
  ]
25
  }
26
 
27
- # ------------------------
28
- # NEW: Generate readable summary from WHISP API DataFrame
29
- # ------------------------
30
- def generate_summary(df: pd.DataFrame) -> str:
31
- """Generate human-readable summary from WHISP API output"""
32
- try:
33
- # Convert DataFrame to dict for easier access
34
- data = {row[0]: row[1] for row in df.values}
35
-
36
- country = data.get("Country", "Unknown")
37
- admin = data.get("Admin_Level_1", "Unknown region")
38
- area = data.get("Area", "Unknown")
39
- risk_level = data.get("Risk level", "Unknown")
40
- risk_pcrop = data.get("risk_pcrop", "Unknown")
41
- risk_acrop = data.get("risk_acrop", "Unknown")
42
- risk_timber = data.get("risk_timber", "Unknown")
43
- def_after_2020 = data.get("TMF_def_after_2020", "0")
44
-
45
- summary = f"""
46
- **Analysis Summary**
47
-
48
- The uploaded GeoJSON corresponds to a region in **{admin}, {country}**, covering about **{area} hectares**.
49
-
50
- - **Overall Deforestation Risk**: The area is classified as **{risk_level} risk**, meaning there is a likelihood that agricultural or timber activities are linked to deforestation.
51
- - **Perennial Crops Risk**: The risk from crops such as cocoa, coffee, and oil palm is **{risk_pcrop}**.
52
- - **Annual Crops Risk**: The risk from crops like maize or soy is **{risk_acrop}**.
53
- - **Timber Risk**: The risk linked to timber extraction is **{risk_timber}**.
54
- - **Recent Deforestation**: Since 2020, about **{def_after_2020} hectares** of natural forest have been cleared in this area.
55
-
56
- This indicates that while some crops may not be a major concern, perennial crops and timber extraction could present notable risks to deforestation-free compliance.
57
- """
58
- return summary
59
- except Exception as e:
60
- return f"⚠️ Could not generate summary: {str(e)}"
61
-
62
- # ------------------------
63
- # GeoJSON upload handler
64
- # ------------------------
65
  def handle_geojson_upload(file):
66
  """Handle GeoJSON file upload and call WHISP API"""
67
  if file is not None:
68
  try:
69
  # Initialize WHISP API client
70
  client = Client("https://giz-chatfed-whisp.hf.space/")
71
-
72
  # Call the API with the uploaded file
73
  result = client.predict(
74
  file=handle_file(file.name),
75
  api_name="/get_statistics"
76
  )
77
-
78
  # Convert result to DataFrame
79
  df = pd.DataFrame(result['data'], columns=result['headers'])
80
-
81
- # Generate human-readable summary
82
- summary = generate_summary(df)
83
-
84
  return (
85
  "✅ GeoJSON file processed successfully! Analysis results are displayed below.",
86
  gr.update(visible=True), # upload_status
87
- gr.update(value=df, visible=True), # results_table
88
- summary # NEW: summary to send into chatbot
89
  )
 
90
  except Exception as e:
91
  error_msg = f"❌ Error processing GeoJSON file: {str(e)}"
92
- return (error_msg, gr.update(visible=True), gr.update(visible=False), None)
 
 
 
 
93
  else:
94
- return ("", gr.update(visible=False), gr.update(visible=False), None)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
95
 
96
- # ------------------------
97
- # Chat functions
98
- # ------------------------
99
  def start_chat(query, history):
 
100
  history = history + [(query, None)]
101
  return gr.update(interactive=False), gr.update(selected=1), history
102
 
103
  def finish_chat():
 
104
  return gr.update(interactive=True, value="")
105
 
106
- async def chat_response(query, history, method, country, uploaded_file, geojson_summary):
 
 
 
107
  if method == "Upload GeoJSON":
108
  if uploaded_file is None:
109
  warning_message = "⚠️ **No GeoJSON file uploaded.** Please upload a GeoJSON file first."
110
  history[-1] = (query, warning_message)
111
  yield history, ""
112
  return
113
- else:
114
- if geojson_summary:
115
- full_response = geojson_summary
116
- else:
117
- full_response = f"Based on your uploaded GeoJSON file, I can help you analyze the deforestation patterns and EUDR compliance aspects in your area of interest."
118
- else:
119
  if not country:
120
  warning_message = "⚠️ **No country selected.** Please select a country to analyze reports."
121
  history[-1] = (query, warning_message)
122
  yield history, ""
123
  return
124
- else:
125
- full_response = f"Based on EUDR reports for {country}, I can help you understand deforestation patterns and compliance requirements."
126
-
127
  response = ""
 
 
 
 
 
 
128
  words = full_response.split()
129
  for word in words:
130
  response += word + " "
131
  history[-1] = (query, response)
132
  yield history, "**Sources:** Sample source documents would appear here..."
133
- await asyncio.sleep(0.02)
134
 
135
  def toggle_search_method(method):
 
136
  if method == "Upload GeoJSON":
137
- return (gr.update(visible=True), gr.update(visible=False), gr.update(value=None))
138
- else:
139
- return (gr.update(visible=False), gr.update(visible=True), gr.update())
 
 
 
 
 
 
 
 
140
 
141
  def change_sample_questions(key):
 
142
  keys = list(SAMPLE_QUESTIONS.keys())
143
  index = keys.index(key)
144
  visible_bools = [False] * len(keys)
145
  visible_bools[index] = True
146
  return [gr.update(visible=visible_bools[i]) for i in range(len(keys))]
147
 
148
- # ------------------------
149
- # UI Setup
150
- # ------------------------
151
  theme = gr.themes.Base(
152
  primary_hue="green",
153
  secondary_hue="blue",
@@ -155,14 +169,54 @@ theme = gr.themes.Base(
155
  text_size=gr.themes.utils.sizes.text_sm,
156
  )
157
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
158
  init_prompt = """
159
- Hello, I am EUDR Q&A, an AI-powered conversational assistant designed to help you understand EU Deforestation Regulation compliance and analysis.
160
- I will answer your questions by using **EUDR reports and uploaded GeoJSON files**.
 
 
 
 
 
 
161
  """
162
 
163
- with gr.Blocks(title="EUDR Q&A", theme=theme) as demo:
 
 
164
  with gr.Tab("EUDR Q&A"):
165
  with gr.Row():
 
166
  with gr.Column(scale=2):
167
  chatbot = gr.Chatbot(
168
  value=[(None, init_prompt)],
@@ -172,53 +226,194 @@ with gr.Blocks(title="EUDR Q&A", theme=theme) as demo:
172
  avatar_images=(None, "🌳"),
173
  height=500
174
  )
175
- textbox = gr.Textbox(
176
- placeholder="Ask me anything about EUDR compliance or upload your GeoJSON for analysis!",
177
- show_label=False,
178
- scale=7,
179
- lines=1,
180
- interactive=True
181
- )
182
-
 
 
 
 
 
 
 
 
 
 
 
 
 
183
  with gr.Column(scale=1, variant="panel"):
184
  with gr.Tabs() as tabs:
 
 
185
  with gr.Tab("Data Sources", id=2):
186
  search_method = gr.Radio(
187
  choices=["Upload GeoJSON", "Talk to Reports"],
188
  label="Choose data source",
189
- value="Upload GeoJSON"
 
190
  )
 
 
191
  with gr.Group(visible=True) as geojson_section:
192
- uploaded_file = gr.File(label="Upload GeoJSON File", file_types=[".geojson", ".json"], file_count="single")
 
 
 
 
193
  upload_status = gr.Markdown("", visible=False)
194
- results_table = gr.DataFrame(label="Analysis Results", visible=False, interactive=False, wrap=True)
 
 
 
 
 
 
 
 
 
 
195
  with gr.Group(visible=False) as reports_section:
196
- dropdown_country = gr.Dropdown(["Ecuador", "Guatemala"], label="Select Country", value=None, interactive=True)
 
 
 
 
 
 
 
197
  with gr.Tab("Examples", id=0):
198
  examples_hidden = gr.Textbox(visible=False)
 
199
  first_key = list(SAMPLE_QUESTIONS.keys())[0]
200
- dropdown_samples = gr.Dropdown(SAMPLE_QUESTIONS.keys(), value=first_key, interactive=True, show_label=True, label="Select a category of sample questions")
 
 
 
 
 
 
 
 
201
  sample_groups = []
202
  for i, (key, questions) in enumerate(SAMPLE_QUESTIONS.items()):
203
  examples_visible = True if i == 0 else False
204
  with gr.Row(visible=examples_visible) as group_examples:
205
- gr.Examples(questions, [examples_hidden], examples_per_page=8, run_on_click=False)
 
 
 
 
 
206
  sample_groups.append(group_examples)
 
 
207
  with gr.Tab("Sources", id=1):
208
- sources_textbox = gr.HTML(show_label=False, value="Source documents will appear here after you ask a question...")
209
-
210
- # Hidden state to store summary from WHISP API
211
- geojson_summary = gr.State()
212
-
213
- # Event handlers
214
- search_method.change(fn=toggle_search_method, inputs=[search_method], outputs=[geojson_section, reports_section, dropdown_country])
215
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
216
  uploaded_file.change(
217
  fn=handle_geojson_upload,
218
  inputs=[uploaded_file],
219
- outputs=[upload_status, upload_status, results_table, geojson_summary]
220
  )
221
-
 
222
  textbox.submit(
223
  start_chat,
224
  [textbox, chatbot],
@@ -226,12 +421,17 @@ with gr.Blocks(title="EUDR Q&A", theme=theme) as demo:
226
  queue=False
227
  ).then(
228
  chat_response,
229
- [textbox, chatbot, search_method, dropdown_country, uploaded_file, geojson_summary],
230
  [chatbot, sources_textbox]
231
  ).then(
232
- finish_chat, outputs=[textbox]
 
 
 
 
233
  )
234
-
 
235
  examples_hidden.change(
236
  start_chat,
237
  [examples_hidden, chatbot],
@@ -239,13 +439,34 @@ with gr.Blocks(title="EUDR Q&A", theme=theme) as demo:
239
  queue=False
240
  ).then(
241
  chat_response,
242
- [examples_hidden, chatbot, search_method, dropdown_country, uploaded_file, geojson_summary],
243
  [chatbot, sources_textbox]
244
  ).then(
245
- finish_chat, outputs=[textbox]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
246
  )
247
 
248
- dropdown_samples.change(change_sample_questions, [dropdown_samples], sample_groups)
249
-
250
  if __name__ == "__main__":
251
- demo.launch()
 
1
  import gradio as gr
2
  import time
3
  import pandas as pd
 
4
  from uuid import uuid4
5
  from gradio_client import Client, handle_file
6
 
7
+ # Sample questions for examples
8
  SAMPLE_QUESTIONS = {
9
  "Deforestation Analysis": [
10
  "What are the main deforestation hotspots in Ecuador?",
 
23
  ]
24
  }
25
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
26
  def handle_geojson_upload(file):
27
  """Handle GeoJSON file upload and call WHISP API"""
28
  if file is not None:
29
  try:
30
  # Initialize WHISP API client
31
  client = Client("https://giz-chatfed-whisp.hf.space/")
32
+
33
  # Call the API with the uploaded file
34
  result = client.predict(
35
  file=handle_file(file.name),
36
  api_name="/get_statistics"
37
  )
38
+
39
  # Convert result to DataFrame
40
  df = pd.DataFrame(result['data'], columns=result['headers'])
41
+
 
 
 
42
  return (
43
  "✅ GeoJSON file processed successfully! Analysis results are displayed below.",
44
  gr.update(visible=True), # upload_status
45
+ gr.update(value=df, visible=True) # results_table
 
46
  )
47
+
48
  except Exception as e:
49
  error_msg = f"❌ Error processing GeoJSON file: {str(e)}"
50
+ return (
51
+ error_msg,
52
+ gr.update(visible=True), # upload_status
53
+ gr.update(visible=False) # results_table
54
+ )
55
  else:
56
+ return (
57
+ "",
58
+ gr.update(visible=False), # upload_status
59
+ gr.update(visible=False) # results_table
60
+ )
61
+
62
+
63
+ def retrieve_paragraphs(query):
64
+
65
+ """Connect to retriever and retrieve paragraphs"""
66
+
67
+ if file is not None:
68
+ try:
69
+ # Initialize WHISP API client
70
+ client = Client("https://giz-eudr-retriever.hf.space/")
71
+
72
+ # Call the API with the uploaded file
73
+ result = client.predict(
74
+ file=handle_file(file.name),
75
+ api_name="/retrieve"
76
+ )
77
+
78
+ return (
79
+ "These are the most relevant findings.",
80
+ gr.update(visible=True), # upload_status
81
+ gr.update(value=results, visible=True) # results_table
82
+ )
83
+
84
+ except Exception as e:
85
+ error_msg = f"❌ Error creating a response {str(e)}"
86
+ return (
87
+ error_msg,
88
+ gr.update(visible=True), # upload_status
89
+ gr.update(visible=False) # results_table
90
+ )
91
+
92
+ else:
93
+ return (
94
+ "",
95
+ gr.update(visible=False), # upload_status
96
+ gr.update(visible=False) # results_table
97
+ )
98
+
99
 
 
 
 
100
  def start_chat(query, history):
101
+ """Start a new chat interaction"""
102
  history = history + [(query, None)]
103
  return gr.update(interactive=False), gr.update(selected=1), history
104
 
105
  def finish_chat():
106
+ """Finish chat and reset input"""
107
  return gr.update(interactive=True, value="")
108
 
109
+ async def chat_response(query, history, method, country, uploaded_file):
110
+ """Generate chat response based on method and inputs"""
111
+
112
+ # Validate inputs based on method
113
  if method == "Upload GeoJSON":
114
  if uploaded_file is None:
115
  warning_message = "⚠️ **No GeoJSON file uploaded.** Please upload a GeoJSON file first."
116
  history[-1] = (query, warning_message)
117
  yield history, ""
118
  return
119
+ else: # "Talk to Reports"
 
 
 
 
 
120
  if not country:
121
  warning_message = "⚠️ **No country selected.** Please select a country to analyze reports."
122
  history[-1] = (query, warning_message)
123
  yield history, ""
124
  return
125
+
126
+ # Simulate processing time
 
127
  response = ""
128
+ if method == "Upload GeoJSON":
129
+ full_response = f"Based on your uploaded GeoJSON file, I can help you analyze the deforestation patterns and EUDR compliance aspects in your area of interest. Your question: '{query}' is being processed against the geographic data you provided."
130
+ else:
131
+ full_response = f"Based on EUDR reports for {country}, I can help you understand deforestation patterns and compliance requirements. Your question: '{query}' is being analyzed against our {country} database."
132
+
133
+ # Simulate streaming response
134
  words = full_response.split()
135
  for word in words:
136
  response += word + " "
137
  history[-1] = (query, response)
138
  yield history, "**Sources:** Sample source documents would appear here..."
139
+ await asyncio.sleep(0.05)
140
 
141
  def toggle_search_method(method):
142
+ """Toggle between GeoJSON upload and country selection"""
143
  if method == "Upload GeoJSON":
144
+ return (
145
+ gr.update(visible=True), # geojson_section
146
+ gr.update(visible=False), # reports_section
147
+ gr.update(value=None), # dropdown_country
148
+ )
149
+ else: # "Talk to Reports"
150
+ return (
151
+ gr.update(visible=False), # geojson_section
152
+ gr.update(visible=True), # reports_section
153
+ gr.update(), # dropdown_country
154
+ )
155
 
156
  def change_sample_questions(key):
157
+ """Update visible examples based on selected category"""
158
  keys = list(SAMPLE_QUESTIONS.keys())
159
  index = keys.index(key)
160
  visible_bools = [False] * len(keys)
161
  visible_bools[index] = True
162
  return [gr.update(visible=visible_bools[i]) for i in range(len(keys))]
163
 
164
+ # Set up Gradio Theme
 
 
165
  theme = gr.themes.Base(
166
  primary_hue="green",
167
  secondary_hue="blue",
 
169
  text_size=gr.themes.utils.sizes.text_sm,
170
  )
171
 
172
+ # Custom CSS for DataFrame styling
173
+ custom_css = """
174
+ /* DataFrame text sizing - Modify these values to change text size */
175
+ .dataframe table {
176
+ font-size: 12px !important; /* Change this value (e.g., 10px, 14px, 16px) */
177
+ }
178
+
179
+ .dataframe th {
180
+ font-size: 13px !important; /* Header text size */
181
+ font-weight: 600 !important;
182
+ }
183
+
184
+ .dataframe td {
185
+ font-size: 12px !important; /* Cell text size */
186
+ padding: 8px !important; /* Cell padding */
187
+ }
188
+
189
+ /* Alternative size classes - change elem_classes="dataframe-small" in DataFrame component */
190
+ .dataframe-small table { font-size: 10px !important; }
191
+ .dataframe-small th { font-size: 11px !important; }
192
+ .dataframe-small td { font-size: 10px !important; }
193
+
194
+ .dataframe-medium table { font-size: 14px !important; }
195
+ .dataframe-medium th { font-size: 15px !important; }
196
+ .dataframe-medium td { font-size: 14px !important; }
197
+
198
+ .dataframe-large table { font-size: 16px !important; }
199
+ .dataframe-large th { font-size: 17px !important; }
200
+ .dataframe-large td { font-size: 16px !important; }
201
+ """
202
+
203
  init_prompt = """
204
+ Hello, I am EUDR Q&A, an AI-powered conversational assistant designed to help you understand EU Deforestation Regulation compliance and analysis. I will answer your questions by using **EUDR reports and uploaded GeoJSON files**.
205
+
206
+ 💡 **How to use (tabs on right)**
207
+ - **Data Sources**: Choose to either upload a GeoJSON file for analysis or talk to EUDR reports filtered by country.
208
+ - **Examples**: Select from curated example questions across different categories.
209
+ - **Sources**: View the content sources used to generate answers for fact-checking.
210
+
211
+ ⚠️ For limitations and data collection information, please check the **Disclaimer** tab.
212
  """
213
 
214
+ with gr.Blocks(title="EUDR Q&A", theme=theme, css=custom_css) as demo:
215
+
216
+ # Main Chat Interface
217
  with gr.Tab("EUDR Q&A"):
218
  with gr.Row():
219
+ # Left column - Chat interface (2/3 width)
220
  with gr.Column(scale=2):
221
  chatbot = gr.Chatbot(
222
  value=[(None, init_prompt)],
 
226
  avatar_images=(None, "🌳"),
227
  height=500
228
  )
229
+
230
+ # Feedback UI
231
+ with gr.Column():
232
+ with gr.Row(visible=False) as feedback_row:
233
+ gr.Markdown("Was this response helpful?")
234
+ with gr.Row():
235
+ okay_btn = gr.Button("👍 Okay", size="sm")
236
+ not_okay_btn = gr.Button("👎 Not to expectations", size="sm")
237
+ feedback_thanks = gr.Markdown("Thanks for the feedback!", visible=False)
238
+
239
+ # Input textbox
240
+ with gr.Row():
241
+ textbox = gr.Textbox(
242
+ placeholder="Ask me anything about EUDR compliance or upload your GeoJSON for analysis!",
243
+ show_label=False,
244
+ scale=7,
245
+ lines=1,
246
+ interactive=True
247
+ )
248
+
249
+ # Right column - Controls and tabs (1/3 width)
250
  with gr.Column(scale=1, variant="panel"):
251
  with gr.Tabs() as tabs:
252
+
253
+ # Data Sources Tab
254
  with gr.Tab("Data Sources", id=2):
255
  search_method = gr.Radio(
256
  choices=["Upload GeoJSON", "Talk to Reports"],
257
  label="Choose data source",
258
+ info="Upload a GeoJSON file for analysis or select country-specific EUDR reports",
259
+ value="Upload GeoJSON",
260
  )
261
+
262
+ # GeoJSON Upload Section
263
  with gr.Group(visible=True) as geojson_section:
264
+ uploaded_file = gr.File(
265
+ label="Upload GeoJSON File",
266
+ file_types=[".geojson", ".json"],
267
+ file_count="single"
268
+ )
269
  upload_status = gr.Markdown("", visible=False)
270
+
271
+ # Results table for WHISP API response
272
+ results_table = gr.DataFrame(
273
+ label="Analysis Results",
274
+ visible=False,
275
+ interactive=False,
276
+ wrap=True,
277
+ elem_classes="dataframe"
278
+ )
279
+
280
+ # Talk to Reports Section
281
  with gr.Group(visible=False) as reports_section:
282
+ dropdown_country = gr.Dropdown(
283
+ ["Ecuador", "Guatemala"],
284
+ label="Select Country",
285
+ value=None,
286
+ interactive=True,
287
+ )
288
+
289
+ # Examples Tab
290
  with gr.Tab("Examples", id=0):
291
  examples_hidden = gr.Textbox(visible=False)
292
+
293
  first_key = list(SAMPLE_QUESTIONS.keys())[0]
294
+ dropdown_samples = gr.Dropdown(
295
+ SAMPLE_QUESTIONS.keys(),
296
+ value=first_key,
297
+ interactive=True,
298
+ show_label=True,
299
+ label="Select a category of sample questions"
300
+ )
301
+
302
+ # Create example sections
303
  sample_groups = []
304
  for i, (key, questions) in enumerate(SAMPLE_QUESTIONS.items()):
305
  examples_visible = True if i == 0 else False
306
  with gr.Row(visible=examples_visible) as group_examples:
307
+ gr.Examples(
308
+ questions,
309
+ [examples_hidden],
310
+ examples_per_page=8,
311
+ run_on_click=False,
312
+ )
313
  sample_groups.append(group_examples)
314
+
315
+ # Sources Tab
316
  with gr.Tab("Sources", id=1):
317
+ sources_textbox = gr.HTML(
318
+ show_label=False,
319
+ value="Source documents will appear here after you ask a question..."
320
+ )
321
+
322
+ # Guidelines Tab
323
+ with gr.Tab("Guidelines"):
324
+ gr.Markdown("""
325
+ #### Welcome to EUDR Q&A!
326
+
327
+ This AI-powered assistant helps you understand EU Deforestation Regulation compliance and analyze geographic data.
328
+
329
+ ## 💬 How to Ask Effective Questions
330
+
331
+ | ❌ Less Effective | ✅ More Effective |
332
+ |------------------|-------------------|
333
+ | "What is deforestation?" | "What are the main deforestation hotspots in Ecuador?" |
334
+ | "Tell me about compliance" | "What EUDR requirements apply to coffee imports from Guatemala?" |
335
+ | "Show me data" | "What is the deforestation rate in the uploaded region?" |
336
+
337
+ ## 🔍 Using Data Sources
338
+
339
+ **Upload GeoJSON:** Upload your geographic data files for automatic analysis via WHISP API
340
+ **Talk to Reports:** Select Ecuador or Guatemala for country-specific EUDR analysis
341
+
342
+ ## ⭐ Best Practices
343
+
344
+ - Be specific about regions, commodities, or time periods
345
+ - Ask one question at a time for clearer answers
346
+ - Use follow-up questions to explore topics deeper
347
+ - Provide context when possible
348
+ """)
349
+
350
+ # About Tab
351
+ with gr.Tab("About"):
352
+ gr.Markdown("""
353
+ ## About EUDR Q&A
354
+
355
+ The **EU Deforestation Regulation (EUDR)** requires companies to ensure that specific commodities
356
+ placed on the EU market are deforestation-free and legally produced.
357
+
358
+ This AI-powered tool helps stakeholders:
359
+ - Understand EUDR compliance requirements
360
+ - Analyze geographic deforestation data using WHISP API
361
+ - Assess supply chain risks
362
+ - Navigate complex regulatory landscapes
363
+
364
+ **Developed by GIZ** to enhance accessibility and understanding of EUDR requirements
365
+ through advanced AI and geographic data processing capabilities.
366
+
367
+ ### Key Features:
368
+ - Automatic analysis of uploaded GeoJSON files via WHISP API
369
+ - Country-specific EUDR compliance guidance
370
+ - Real-time question answering with source citations
371
+ - User-friendly interface for complex regulatory information
372
+ """)
373
+
374
+ # Disclaimer Tab
375
+ with gr.Tab("Disclaimer"):
376
+ gr.Markdown("""
377
+ ## Important Disclaimers
378
+
379
+ ⚠️ **Scope & Limitations:**
380
+ - This tool is designed for EUDR compliance assistance and geographic data analysis
381
+ - Responses should not be considered official legal or compliance advice
382
+ - Always consult qualified professionals for official compliance decisions
383
+
384
+ ⚠️ **Data & Privacy:**
385
+ - Uploaded GeoJSON files are processed via external WHISP API for analysis
386
+ - We collect usage statistics to improve the tool
387
+ - Files are processed temporarily and not permanently stored
388
+
389
+ ⚠️ **AI Limitations:**
390
+ - Responses are AI-generated and may contain inaccuracies
391
+ - The tool is a prototype under continuous development
392
+ - Always verify important information with authoritative sources
393
+
394
+ **Data Collection:** We collect questions, answers, feedback, and anonymized usage statistics
395
+ to improve tool performance based on legitimate interest in service enhancement.
396
+
397
+ By using this tool, you acknowledge these limitations and agree to use responses responsibly.
398
+ """)
399
+
400
+ # Event Handlers
401
+
402
+ # Toggle search method
403
+ search_method.change(
404
+ fn=toggle_search_method,
405
+ inputs=[search_method],
406
+ outputs=[geojson_section, reports_section, dropdown_country]
407
+ )
408
+
409
+ # File upload - automatically process when file is uploaded
410
  uploaded_file.change(
411
  fn=handle_geojson_upload,
412
  inputs=[uploaded_file],
413
+ outputs=[upload_status, upload_status, results_table]
414
  )
415
+
416
+ # Chat functionality
417
  textbox.submit(
418
  start_chat,
419
  [textbox, chatbot],
 
421
  queue=False
422
  ).then(
423
  chat_response,
424
+ [textbox, chatbot, search_method, dropdown_country, uploaded_file],
425
  [chatbot, sources_textbox]
426
  ).then(
427
+ lambda: gr.update(visible=True),
428
+ outputs=[feedback_row]
429
+ ).then(
430
+ finish_chat,
431
+ outputs=[textbox]
432
  )
433
+
434
+ # Examples functionality
435
  examples_hidden.change(
436
  start_chat,
437
  [examples_hidden, chatbot],
 
439
  queue=False
440
  ).then(
441
  chat_response,
442
+ [examples_hidden, chatbot, search_method, dropdown_country, uploaded_file],
443
  [chatbot, sources_textbox]
444
  ).then(
445
+ lambda: gr.update(visible=True),
446
+ outputs=[feedback_row]
447
+ ).then(
448
+ finish_chat,
449
+ outputs=[textbox]
450
+ )
451
+
452
+ # Sample questions dropdown
453
+ dropdown_samples.change(
454
+ change_sample_questions,
455
+ [dropdown_samples],
456
+ sample_groups
457
+ )
458
+
459
+ # Feedback buttons
460
+ okay_btn.click(
461
+ lambda: (gr.update(visible=False), gr.update(visible=True)),
462
+ outputs=[feedback_row, feedback_thanks]
463
+ )
464
+
465
+ not_okay_btn.click(
466
+ lambda: (gr.update(visible=False), gr.update(visible=True)),
467
+ outputs=[feedback_row, feedback_thanks]
468
  )
469
 
470
+ # Launch the app
 
471
  if __name__ == "__main__":
472
+ demo.launch()