Jacksonnavigator7 commited on
Commit
11d7ab7
·
verified ·
1 Parent(s): a375ce1

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +45 -84
app.py CHANGED
@@ -59,13 +59,9 @@ translations = {
59
 
60
  def clean_bird_name(name):
61
  """Clean bird name by removing numbers and special characters, and fix formatting"""
62
- # Remove numbers and dots at the beginning
63
  cleaned = re.sub(r'^\d+\.', '', name)
64
- # Replace underscores with spaces
65
  cleaned = cleaned.replace('_', ' ')
66
- # Remove any remaining special characters
67
  cleaned = re.sub(r'[^\w\s]', '', cleaned)
68
- # Fix spacing
69
  cleaned = ' '.join(cleaned.split())
70
  return cleaned
71
 
@@ -73,7 +69,6 @@ def get_bird_habitat_map(bird_name, check_tanzania=True):
73
  """Get habitat map locations for the bird using Groq API"""
74
  clean_name = clean_bird_name(bird_name)
75
 
76
- # First check if the bird is endemic to Tanzania
77
  if check_tanzania:
78
  tanzania_check_prompt = f"""
79
  Is the {clean_name} bird native to or commonly found in Tanzania?
@@ -87,12 +82,10 @@ def get_bird_habitat_map(bird_name, check_tanzania=True):
87
  )
88
  is_in_tanzania = "yes" in tanzania_check.choices[0].message.content.lower()
89
  except:
90
- # Default to showing Tanzania if we can't determine
91
  is_in_tanzania = True
92
  else:
93
  is_in_tanzania = True
94
 
95
- # Now get the habitat locations
96
  prompt = f"""
97
  Provide a JSON array of the main habitat locations for the {clean_name} bird in the world.
98
  Return ONLY a JSON array with 3-5 entries, each containing:
@@ -112,98 +105,70 @@ def get_bird_habitat_map(bird_name, check_tanzania=True):
112
 
113
  try:
114
  chat_completion = client.chat.completions.create(
115
- messages=[
116
- {
117
- "role": "user",
118
- "content": prompt,
119
- }
120
- ],
121
  model="llama-3.3-70b-versatile",
122
  )
123
  response = chat_completion.choices[0].message.content
124
 
125
- # Extract JSON from response (in case there's additional text)
126
- import json
127
- import re
128
-
129
- # Find JSON pattern in response
130
  json_match = re.search(r'\[.*\]', response, re.DOTALL)
131
  if json_match:
132
  locations = json.loads(json_match.group())
133
  else:
134
- # Fallback if JSON extraction fails
135
  locations = [
136
  {"name": "Primary habitat region", "lat": 0, "lon": 0,
137
  "description": "Could not retrieve specific habitat information for this bird."}
138
  ]
139
-
140
  return locations, is_in_tanzania
141
-
142
- except Exception as e:
143
  return [{"name": "Error retrieving data", "lat": 0, "lon": 0,
144
  "description": "Please try again or check your connection."}], False
145
 
146
  def create_habitat_map(habitat_locations):
147
  """Create a folium map with the habitat locations"""
148
- # Find center point based on valid coordinates
149
  valid_coords = [(loc.get("lat", 0), loc.get("lon", 0))
150
  for loc in habitat_locations
151
  if loc.get("lat", 0) != 0 or loc.get("lon", 0) != 0]
152
 
153
  if valid_coords:
154
- # Calculate the average of the coordinates
155
  avg_lat = sum(lat for lat, _ in valid_coords) / len(valid_coords)
156
  avg_lon = sum(lon for _, lon in valid_coords) / len(valid_coords)
157
- # Create map centered on the average coordinates
158
  m = folium.Map(location=[avg_lat, avg_lon], zoom_start=3)
159
  else:
160
- # Default world map if no valid coordinates
161
  m = folium.Map(location=[20, 0], zoom_start=2)
162
 
163
- # Add markers for each habitat location
164
  for location in habitat_locations:
165
  name = location.get("name", "Unknown")
166
  lat = location.get("lat", 0)
167
  lon = location.get("lon", 0)
168
  description = location.get("description", "No description available")
169
 
170
- # Skip invalid coordinates
171
  if lat == 0 and lon == 0:
172
  continue
173
 
174
- # Add marker
175
  folium.Marker(
176
  location=[lat, lon],
177
  popup=folium.Popup(f"<b>{name}</b><br>{description}", max_width=300),
178
  tooltip=name
179
  ).add_to(m)
180
 
181
- # Save map to HTML
182
  map_html = m._repr_html_()
183
  return map_html
184
 
185
  def format_bird_info(raw_info, language="en"):
186
  """Improve the formatting of bird information"""
187
- # Add proper line breaks between sections and ensure consistent heading levels
188
  formatted = raw_info
189
 
190
- # Get translation of warning text based on language
191
  warning_text = "NOT TYPICALLY FOUND IN TANZANIA"
192
  warning_translation = "HAPATIKANI SANA TANZANIA" if language == "sw" else warning_text
193
 
194
- # Fix heading levels (make all main sections h3)
195
  formatted = re.sub(r'#+\s+' + warning_text,
196
- f'<div class="alert alert-warning"><strong>⚠️ {warning_translation}</strong></div>',
197
- formatted)
198
 
199
- # Replace markdown headings with HTML headings for better control
200
  formatted = re.sub(r'#+\s+(.*)', r'<h3>\1</h3>', formatted)
201
-
202
- # Add paragraph tags for better spacing
203
  formatted = re.sub(r'\n\*\s+(.*)', r'<p>• \1</p>', formatted)
204
  formatted = re.sub(r'\n([^<\n].*)', r'<p>\1</p>', formatted)
205
 
206
- # Remove any duplicate paragraph tags
207
  formatted = formatted.replace('<p><p>', '<p>')
208
  formatted = formatted.replace('</p></p>', '</p>')
209
 
@@ -213,10 +178,7 @@ def get_bird_info(bird_name, language="en"):
213
  """Get detailed information about a bird using Groq API"""
214
  clean_name = clean_bird_name(bird_name)
215
 
216
- # Adjust language for the prompt
217
- lang_instruction = ""
218
- if language == "sw":
219
- lang_instruction = " Provide your response in Swahili language."
220
 
221
  prompt = f"""
222
  Provide detailed information about the {clean_name} bird, including:
@@ -233,12 +195,7 @@ def get_bird_info(bird_name, language="en"):
233
 
234
  try:
235
  chat_completion = client.chat.completions.create(
236
- messages=[
237
- {
238
- "role": "user",
239
- "content": prompt,
240
- }
241
- ],
242
  model="llama-3.3-70b-versatile",
243
  )
244
  return chat_completion.choices[0].message.content
@@ -248,38 +205,63 @@ def get_bird_info(bird_name, language="en"):
248
 
249
  def predict_and_get_info(img, language="en"):
250
  """Predict bird species and get detailed information"""
251
- # Get translations
252
  t = translations[language]
253
 
254
- # Process the image
255
  img = PILImage.create(img)
256
-
257
- # Get prediction
258
  pred, pred_idx, probs = learn.predict(img)
259
 
260
- # Get top 5 predictions (or all if less than 5)
261
  num_classes = min(5, len(labels))
262
  top_indices = probs.argsort(descending=True)[:num_classes]
263
  top_probs = probs[top_indices]
264
  top_labels = [labels[i] for i in top_indices]
265
 
266
- # Format as dictionary with cleaned names for display
267
  prediction_results = {clean_bird_name(top_labels[i]): float(top_probs[i]) for i in range(num_classes)}
268
 
269
- # Get top prediction (original format for info retrieval)
270
  top_bird = str(pred)
271
- # Also keep a clean version for display
272
  clean_top_bird = clean_bird_name(top_bird)
273
 
274
- # Get habitat locations and create map
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
275
  habitat_locations, is_in_tanzania = get_bird_habitat_map(top_bird)
276
  habitat_map_html = create_habitat_map(habitat_locations)
277
 
278
- # Get detailed information about the top predicted bird
279
  bird_info = get_bird_info(top_bird, language)
280
  formatted_info = format_bird_info(bird_info, language)
281
 
282
- # Create combined info with map at the top and properly formatted information
283
  custom_css = """
284
  <style>
285
  .bird-container {
@@ -344,10 +326,7 @@ def follow_up_question(question, bird_name, language="en"):
344
  if not question.strip() or not bird_name:
345
  return "Please identify a bird first and ask a specific question about it." if language == "en" else "Tafadhali tambua ndege kwanza na uulize swali maalum kuhusu ndege huyo."
346
 
347
- # Adjust language for the prompt
348
- lang_instruction = ""
349
- if language == "sw":
350
- lang_instruction = " Provide your response in Swahili language."
351
 
352
  prompt = f"""
353
  The researcher is asking about the {bird_name} bird: "{question}"
@@ -364,12 +343,7 @@ def follow_up_question(question, bird_name, language="en"):
364
 
365
  try:
366
  chat_completion = client.chat.completions.create(
367
- messages=[
368
- {
369
- "role": "user",
370
- "content": prompt,
371
- }
372
- ],
373
  model="llama-3.3-70b-versatile",
374
  )
375
  return chat_completion.choices[0].message.content
@@ -379,11 +353,9 @@ def follow_up_question(question, bird_name, language="en"):
379
 
380
  # Create the Gradio interface
381
  with gr.Blocks(theme=gr.themes.Soft()) as app:
382
- # Current language and bird state
383
  current_lang = gr.State("en")
384
  current_bird = gr.State("")
385
 
386
- # Header with language switcher
387
  with gr.Row():
388
  with gr.Column(scale=3):
389
  title_md = gr.Markdown(f"# {translations['en']['app_title']}")
@@ -394,10 +366,8 @@ with gr.Blocks(theme=gr.themes.Soft()) as app:
394
  value="English"
395
  )
396
 
397
- # App description
398
  description_md = gr.Markdown(f"{translations['en']['app_description']}")
399
 
400
- # Main identification section
401
  with gr.Row():
402
  with gr.Column(scale=1):
403
  input_image = gr.Image(type="pil", label=translations['en']['upload_label'])
@@ -407,10 +377,8 @@ with gr.Blocks(theme=gr.themes.Soft()) as app:
407
  prediction_output = gr.Label(label=translations['en']['predictions_label'], num_top_classes=5)
408
  bird_info_output = gr.HTML(label=translations['en']['bird_info_label'])
409
 
410
- # Clear divider
411
  gr.Markdown("---")
412
 
413
- # Follow-up question section with improved UI
414
  questions_header = gr.Markdown(f"## {translations['en']['research_questions']}")
415
 
416
  conversation_history = gr.Markdown("")
@@ -426,7 +394,6 @@ with gr.Blocks(theme=gr.themes.Soft()) as app:
426
  follow_up_btn = gr.Button(translations['en']['submit_question'], variant="primary")
427
  clear_btn = gr.Button(translations['en']['clear_conversation'])
428
 
429
- # Functions for event handlers
430
  def process_image(img, lang):
431
  if img is None:
432
  return None, translations[lang]['upload_prompt'], "", ""
@@ -446,7 +413,6 @@ with gr.Blocks(theme=gr.themes.Soft()) as app:
446
 
447
  answer = follow_up_question(question, bird_name, lang)
448
 
449
- # Format the conversation with clear separation
450
  new_exchange = f"""
451
  ### {t['question_title']}
452
  {question}
@@ -454,18 +420,15 @@ with gr.Blocks(theme=gr.themes.Soft()) as app:
454
  {answer}
455
  ---
456
  """
457
- updated_history = new_exchange + history
458
- return updated_history
459
 
460
  def clear_conversation_history():
461
  return ""
462
 
463
  def update_language(choice):
464
- # Convert selection to language code
465
  lang = "sw" if choice == "Kiswahili" else "en"
466
  t = translations[lang]
467
 
468
- # Return updated UI components based on selected language
469
  return (
470
  lang,
471
  f"# {t['app_title']}",
@@ -481,7 +444,6 @@ with gr.Blocks(theme=gr.themes.Soft()) as app:
481
  t['clear_conversation']
482
  )
483
 
484
- # Set up event handlers
485
  language_selector.change(
486
  update_language,
487
  inputs=[language_selector],
@@ -521,5 +483,4 @@ with gr.Blocks(theme=gr.themes.Soft()) as app:
521
  outputs=[conversation_history]
522
  )
523
 
524
- # Launch the app
525
  app.launch(share=True)
 
59
 
60
  def clean_bird_name(name):
61
  """Clean bird name by removing numbers and special characters, and fix formatting"""
 
62
  cleaned = re.sub(r'^\d+\.', '', name)
 
63
  cleaned = cleaned.replace('_', ' ')
 
64
  cleaned = re.sub(r'[^\w\s]', '', cleaned)
 
65
  cleaned = ' '.join(cleaned.split())
66
  return cleaned
67
 
 
69
  """Get habitat map locations for the bird using Groq API"""
70
  clean_name = clean_bird_name(bird_name)
71
 
 
72
  if check_tanzania:
73
  tanzania_check_prompt = f"""
74
  Is the {clean_name} bird native to or commonly found in Tanzania?
 
82
  )
83
  is_in_tanzania = "yes" in tanzania_check.choices[0].message.content.lower()
84
  except:
 
85
  is_in_tanzania = True
86
  else:
87
  is_in_tanzania = True
88
 
 
89
  prompt = f"""
90
  Provide a JSON array of the main habitat locations for the {clean_name} bird in the world.
91
  Return ONLY a JSON array with 3-5 entries, each containing:
 
105
 
106
  try:
107
  chat_completion = client.chat.completions.create(
108
+ messages=[{"role": "user", "content": prompt}],
 
 
 
 
 
109
  model="llama-3.3-70b-versatile",
110
  )
111
  response = chat_completion.choices[0].message.content
112
 
 
 
 
 
 
113
  json_match = re.search(r'\[.*\]', response, re.DOTALL)
114
  if json_match:
115
  locations = json.loads(json_match.group())
116
  else:
 
117
  locations = [
118
  {"name": "Primary habitat region", "lat": 0, "lon": 0,
119
  "description": "Could not retrieve specific habitat information for this bird."}
120
  ]
 
121
  return locations, is_in_tanzania
122
+ except:
 
123
  return [{"name": "Error retrieving data", "lat": 0, "lon": 0,
124
  "description": "Please try again or check your connection."}], False
125
 
126
  def create_habitat_map(habitat_locations):
127
  """Create a folium map with the habitat locations"""
 
128
  valid_coords = [(loc.get("lat", 0), loc.get("lon", 0))
129
  for loc in habitat_locations
130
  if loc.get("lat", 0) != 0 or loc.get("lon", 0) != 0]
131
 
132
  if valid_coords:
 
133
  avg_lat = sum(lat for lat, _ in valid_coords) / len(valid_coords)
134
  avg_lon = sum(lon for _, lon in valid_coords) / len(valid_coords)
 
135
  m = folium.Map(location=[avg_lat, avg_lon], zoom_start=3)
136
  else:
 
137
  m = folium.Map(location=[20, 0], zoom_start=2)
138
 
 
139
  for location in habitat_locations:
140
  name = location.get("name", "Unknown")
141
  lat = location.get("lat", 0)
142
  lon = location.get("lon", 0)
143
  description = location.get("description", "No description available")
144
 
 
145
  if lat == 0 and lon == 0:
146
  continue
147
 
 
148
  folium.Marker(
149
  location=[lat, lon],
150
  popup=folium.Popup(f"<b>{name}</b><br>{description}", max_width=300),
151
  tooltip=name
152
  ).add_to(m)
153
 
 
154
  map_html = m._repr_html_()
155
  return map_html
156
 
157
  def format_bird_info(raw_info, language="en"):
158
  """Improve the formatting of bird information"""
 
159
  formatted = raw_info
160
 
 
161
  warning_text = "NOT TYPICALLY FOUND IN TANZANIA"
162
  warning_translation = "HAPATIKANI SANA TANZANIA" if language == "sw" else warning_text
163
 
 
164
  formatted = re.sub(r'#+\s+' + warning_text,
165
+ f'<div class="alert alert-warning"><strong>⚠️ {warning_translation}</strong></div>',
166
+ formatted)
167
 
 
168
  formatted = re.sub(r'#+\s+(.*)', r'<h3>\1</h3>', formatted)
 
 
169
  formatted = re.sub(r'\n\*\s+(.*)', r'<p>• \1</p>', formatted)
170
  formatted = re.sub(r'\n([^<\n].*)', r'<p>\1</p>', formatted)
171
 
 
172
  formatted = formatted.replace('<p><p>', '<p>')
173
  formatted = formatted.replace('</p></p>', '</p>')
174
 
 
178
  """Get detailed information about a bird using Groq API"""
179
  clean_name = clean_bird_name(bird_name)
180
 
181
+ lang_instruction = "" if language == "en" else " Provide your response in Swahili language."
 
 
 
182
 
183
  prompt = f"""
184
  Provide detailed information about the {clean_name} bird, including:
 
195
 
196
  try:
197
  chat_completion = client.chat.completions.create(
198
+ messages=[{"role": "user", "content": prompt}],
 
 
 
 
 
199
  model="llama-3.3-70b-versatile",
200
  )
201
  return chat_completion.choices[0].message.content
 
205
 
206
  def predict_and_get_info(img, language="en"):
207
  """Predict bird species and get detailed information"""
 
208
  t = translations[language]
209
 
 
210
  img = PILImage.create(img)
 
 
211
  pred, pred_idx, probs = learn.predict(img)
212
 
 
213
  num_classes = min(5, len(labels))
214
  top_indices = probs.argsort(descending=True)[:num_classes]
215
  top_probs = probs[top_indices]
216
  top_labels = [labels[i] for i in top_indices]
217
 
 
218
  prediction_results = {clean_bird_name(top_labels[i]): float(top_probs[i]) for i in range(num_classes)}
219
 
 
220
  top_bird = str(pred)
 
221
  clean_top_bird = clean_bird_name(top_bird)
222
 
223
+ if top_bird.lower() == "other" and float(probs[pred_idx]) > 0.8:
224
+ message = (
225
+ "This image does not appear to match any bird species in our trained dataset. "
226
+ "Please upload a clear image of a bird for accurate identification."
227
+ ) if language == "en" else (
228
+ "Picha hii haionekani kulingana na spishi yoyote ya ndege katika seti yetu ya mafunzo. "
229
+ "Tafadhali pakia picha ya wazi ya ndege kwa utambuzi sahihi."
230
+ )
231
+
232
+ custom_css = """
233
+ <style>
234
+ .bird-container {
235
+ font-family: Arial, sans-serif;
236
+ padding: 10px;
237
+ }
238
+ .alert-info {
239
+ background-color: #d9edf7;
240
+ border: 1px solid #bce8f1;
241
+ color: #31708f;
242
+ padding: 10px;
243
+ margin-bottom: 15px;
244
+ border-radius: 4px;
245
+ }
246
+ </style>
247
+ """
248
+
249
+ combined_info = f"""
250
+ {custom_css}
251
+ <div class="bird-container">
252
+ <div class="alert-info">
253
+ <strong>ℹ️ {message}</strong>
254
+ </div>
255
+ </div>
256
+ """
257
+ return prediction_results, combined_info, ""
258
+
259
  habitat_locations, is_in_tanzania = get_bird_habitat_map(top_bird)
260
  habitat_map_html = create_habitat_map(habitat_locations)
261
 
 
262
  bird_info = get_bird_info(top_bird, language)
263
  formatted_info = format_bird_info(bird_info, language)
264
 
 
265
  custom_css = """
266
  <style>
267
  .bird-container {
 
326
  if not question.strip() or not bird_name:
327
  return "Please identify a bird first and ask a specific question about it." if language == "en" else "Tafadhali tambua ndege kwanza na uulize swali maalum kuhusu ndege huyo."
328
 
329
+ lang_instruction = "" if language == "en" else " Provide your response in Swahili language."
 
 
 
330
 
331
  prompt = f"""
332
  The researcher is asking about the {bird_name} bird: "{question}"
 
343
 
344
  try:
345
  chat_completion = client.chat.completions.create(
346
+ messages=[{"role": "user", "content": prompt}],
 
 
 
 
 
347
  model="llama-3.3-70b-versatile",
348
  )
349
  return chat_completion.choices[0].message.content
 
353
 
354
  # Create the Gradio interface
355
  with gr.Blocks(theme=gr.themes.Soft()) as app:
 
356
  current_lang = gr.State("en")
357
  current_bird = gr.State("")
358
 
 
359
  with gr.Row():
360
  with gr.Column(scale=3):
361
  title_md = gr.Markdown(f"# {translations['en']['app_title']}")
 
366
  value="English"
367
  )
368
 
 
369
  description_md = gr.Markdown(f"{translations['en']['app_description']}")
370
 
 
371
  with gr.Row():
372
  with gr.Column(scale=1):
373
  input_image = gr.Image(type="pil", label=translations['en']['upload_label'])
 
377
  prediction_output = gr.Label(label=translations['en']['predictions_label'], num_top_classes=5)
378
  bird_info_output = gr.HTML(label=translations['en']['bird_info_label'])
379
 
 
380
  gr.Markdown("---")
381
 
 
382
  questions_header = gr.Markdown(f"## {translations['en']['research_questions']}")
383
 
384
  conversation_history = gr.Markdown("")
 
394
  follow_up_btn = gr.Button(translations['en']['submit_question'], variant="primary")
395
  clear_btn = gr.Button(translations['en']['clear_conversation'])
396
 
 
397
  def process_image(img, lang):
398
  if img is None:
399
  return None, translations[lang]['upload_prompt'], "", ""
 
413
 
414
  answer = follow_up_question(question, bird_name, lang)
415
 
 
416
  new_exchange = f"""
417
  ### {t['question_title']}
418
  {question}
 
420
  {answer}
421
  ---
422
  """
423
+ return new_exchange + history
 
424
 
425
  def clear_conversation_history():
426
  return ""
427
 
428
  def update_language(choice):
 
429
  lang = "sw" if choice == "Kiswahili" else "en"
430
  t = translations[lang]
431
 
 
432
  return (
433
  lang,
434
  f"# {t['app_title']}",
 
444
  t['clear_conversation']
445
  )
446
 
 
447
  language_selector.change(
448
  update_language,
449
  inputs=[language_selector],
 
483
  outputs=[conversation_history]
484
  )
485
 
 
486
  app.launch(share=True)