Jacksonnavigator7 commited on
Commit
46c1415
·
verified ·
1 Parent(s): acce874

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +135 -166
app.py CHANGED
@@ -3,22 +3,15 @@ import gradio as gr
3
  import re
4
  import folium
5
  from fastai.vision.all import *
6
- from groq import Groq
7
  from PIL import Image
8
  import time
9
  import json
10
- import numpy as np
11
  from functools import lru_cache
12
 
13
  # Load the trained model
14
  learn = load_learner('export.pkl')
15
  labels = learn.dls.vocab
16
 
17
- # Initialize Groq client
18
- client = Groq(
19
- api_key=os.environ.get("GROQ_API_KEY"),
20
- )
21
-
22
  # Cache directory for API responses
23
  os.makedirs("cache", exist_ok=True)
24
 
@@ -72,7 +65,6 @@ translations = {
72
  }
73
  }
74
 
75
-
76
  def clean_bird_name(name):
77
  """Clean bird name by removing numbers and special characters, and fix formatting"""
78
  # Remove numbers and dots at the beginning
@@ -85,13 +77,11 @@ def clean_bird_name(name):
85
  cleaned = ' '.join(cleaned.split())
86
  return cleaned
87
 
88
-
89
  def get_cache_path(function_name, key):
90
  """Generate a cache file path"""
91
  safe_key = re.sub(r'[^\w]', '_', key)
92
  return f"cache/{function_name}_{safe_key}.json"
93
 
94
-
95
  def save_to_cache(function_name, key, data):
96
  """Save API response to cache"""
97
  try:
@@ -101,7 +91,6 @@ def save_to_cache(function_name, key, data):
101
  except Exception as e:
102
  print(f"Error saving to cache: {e}")
103
 
104
-
105
  def load_from_cache(function_name, key, max_age=86400): # Default max age: 1 day
106
  """Load API response from cache if it exists and is not too old"""
107
  try:
@@ -115,7 +104,6 @@ def load_from_cache(function_name, key, max_age=86400): # Default max age: 1 da
115
  print(f"Error loading from cache: {e}")
116
  return None
117
 
118
-
119
  def is_likely_bird_image(img):
120
  """Basic check to see if the image might contain a bird"""
121
  try:
@@ -142,98 +130,43 @@ def is_likely_bird_image(img):
142
  # If any error occurs during the check, assume it might be a bird
143
  return True
144
 
145
-
146
- def get_bird_habitat_map(bird_name, check_tanzania=True):
147
- """Get habitat map locations for the bird using Groq API with caching"""
148
  clean_name = clean_bird_name(bird_name)
149
 
150
- # Check cache for Tanzania check
151
- tanzania_cache_key = f"{clean_name}_tanzania"
152
- cached_tanzania = load_from_cache("tanzania_check", tanzania_cache_key)
153
- if cached_tanzania is not None:
154
- is_in_tanzania = cached_tanzania
155
- else:
156
- # First check if the bird is endemic to Tanzania
157
- if check_tanzania:
158
- tanzania_check_prompt = f"""
159
- Is the {clean_name} bird native to or commonly found in Tanzania?
160
- Answer with ONLY "yes" or "no".
161
- """
162
-
163
- try:
164
- tanzania_check = client.chat.completions.create(
165
- messages=[{"role": "user", "content": tanzania_check_prompt}],
166
- model="llama-3.3-70b-versatile",
167
- )
168
- is_in_tanzania = "yes" in tanzania_check.choices[0].message.content.lower()
169
- # Cache result
170
- save_to_cache("tanzania_check", tanzania_cache_key, is_in_tanzania)
171
- except:
172
- # Default to showing Tanzania if we can't determine
173
- is_in_tanzania = True
174
- else:
175
- is_in_tanzania = True
176
-
177
  # Check cache for habitat locations
178
  habitat_cache_key = f"{clean_name}_habitat"
179
  cached_habitat = load_from_cache("habitat", habitat_cache_key)
180
  if cached_habitat is not None:
181
- return cached_habitat, is_in_tanzania
182
-
183
- # Now get the habitat locations
184
- prompt = f"""
185
- Provide a JSON array of the main habitat locations for the {clean_name} bird in the world.
186
- Return ONLY a JSON array with 3-5 entries, each containing:
187
- 1. "name": Location name
188
- 2. "lat": Latitude (numeric value)
189
- 3. "lon": Longitude (numeric value)
190
- 4. "description": Brief description of why this is a key habitat (2-3 sentences)
191
-
192
- Example format:
193
- [
194
- {{"name": "Example Location", "lat": 12.34, "lon": 56.78, "description": "Brief description"}},
195
- ...
 
 
 
 
 
 
 
 
196
  ]
197
 
198
- {'' if is_in_tanzania else 'DO NOT include any locations in Tanzania as this bird is not native to or commonly found there.'}
199
- """
200
 
201
- try:
202
- chat_completion = client.chat.completions.create(
203
- messages=[
204
- {
205
- "role": "user",
206
- "content": prompt,
207
- }
208
- ],
209
- model="llama-3.3-70b-versatile",
210
- )
211
- response = chat_completion.choices[0].message.content
212
-
213
- # Extract JSON from response (in case there's additional text)
214
- import json
215
- import re
216
-
217
- # Find JSON pattern in response
218
- json_match = re.search(r'\[.*\]', response, re.DOTALL)
219
- if json_match:
220
- locations = json.loads(json_match.group())
221
- else:
222
- # Fallback if JSON extraction fails
223
- locations = [
224
- {"name": "Primary habitat region", "lat": 0, "lon": 0,
225
- "description": "Could not retrieve specific habitat information for this bird."}
226
- ]
227
-
228
- # Cache the result
229
- save_to_cache("habitat", habitat_cache_key, locations)
230
-
231
- return locations, is_in_tanzania
232
-
233
- except Exception as e:
234
- return [{"name": "Error retrieving data", "lat": 0, "lon": 0,
235
- "description": "Please try again or check your connection."}], False
236
-
237
 
238
  def create_habitat_map(habitat_locations):
239
  """Create a folium map with the habitat locations"""
@@ -274,7 +207,6 @@ def create_habitat_map(habitat_locations):
274
  map_html = m._repr_html_()
275
  return map_html
276
 
277
-
278
  def format_bird_info(raw_info, language="en"):
279
  """Improve the formatting of bird information"""
280
  # Add proper line breaks between sections and ensure consistent heading levels
@@ -302,9 +234,8 @@ def format_bird_info(raw_info, language="en"):
302
 
303
  return formatted
304
 
305
-
306
  def get_bird_info(bird_name, language="en"):
307
- """Get detailed information about a bird using Groq API with caching"""
308
  clean_name = clean_bird_name(bird_name)
309
 
310
  # Check cache first
@@ -313,42 +244,70 @@ def get_bird_info(bird_name, language="en"):
313
  if cached_info is not None:
314
  return cached_info
315
 
316
- # Adjust language for the prompt
317
- lang_instruction = ""
318
- if language == "sw":
319
- lang_instruction = " Provide your response in Swahili language."
320
 
321
- prompt = f"""
322
- Provide detailed information about the {clean_name} bird, including:
323
- 1. Physical characteristics and appearance
324
- 2. Habitat and distribution
325
- 3. Diet and behavior
326
- 4. Migration patterns (emphasize if this pattern has changed in recent years due to climate change)
327
- 5. Conservation status
328
 
329
- If this bird is not commonly found in Tanzania, explicitly flag that this bird is "NOT TYPICALLY FOUND IN TANZANIA" at the beginning of your response and explain why its presence might be unusual.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
330
 
331
- Format your response in markdown for better readability.{lang_instruction}
332
- """
 
 
 
333
 
334
- try:
335
- chat_completion = client.chat.completions.create(
336
- messages=[
337
- {
338
- "role": "user",
339
- "content": prompt,
340
- }
341
- ],
342
- model="llama-3.3-70b-versatile",
343
- )
344
- response = chat_completion.choices[0].message.content
345
- # Cache the result
346
- save_to_cache("bird_info", cache_key, response)
347
- return response
348
- except Exception as e:
349
- error_msg = "Hitilafu katika kupata taarifa" if language == "sw" else "Error fetching information"
350
- return f"{error_msg}: {str(e)}"
351
-
352
 
353
  def create_message_html(message, icon="🔍", language="en"):
354
  """Create a styled message container for notifications"""
@@ -382,7 +341,6 @@ def create_message_html(message, icon="🔍", language="en"):
382
  """
383
  return html
384
 
385
-
386
  def predict_and_get_info(img, language="en"):
387
  """Predict bird species and get detailed information"""
388
  # Get translations
@@ -513,7 +471,6 @@ def predict_and_get_info(img, language="en"):
513
  error_msg = "Hitilafu katika kuchakata picha" if language == "sw" else "Error processing image"
514
  return None, create_message_html(f"{error_msg}: {str(e)}", "⚠️", language), "", ""
515
 
516
-
517
  def follow_up_question(question, bird_name, language="en"):
518
  """Allow researchers to ask follow-up questions about the identified bird"""
519
  t = translations[language]
@@ -527,42 +484,54 @@ def follow_up_question(question, bird_name, language="en"):
527
  if cached_answer is not None:
528
  return cached_answer
529
 
530
- # Adjust language for the prompt
531
- lang_instruction = ""
532
- if language == "sw":
533
- lang_instruction = " Provide your response in Swahili language."
534
-
535
- prompt = f"""
536
- The researcher is asking about the {bird_name} bird: "{question}"
537
-
538
- Provide a detailed, scientific answer focusing on accurate ornithological information.
539
- If the question relates to Tanzania or climate change impacts, emphasize those aspects in your response.
540
-
541
- IMPORTANT: Do not repeat basic introductory information about the bird that would have already been provided in a general description.
542
- Do not start your answer with phrases like "Introduction to the {bird_name}" or similar repetitive headers.
543
- Directly answer the specific question asked.
 
 
 
 
 
 
 
 
 
 
544
 
545
- Format your response in markdown for better readability.{lang_instruction}
546
- """
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
547
 
548
- try:
549
- chat_completion = client.chat.completions.create(
550
- messages=[
551
- {
552
- "role": "user",
553
- "content": prompt,
554
- }
555
- ],
556
- model="llama-3.3-70b-versatile",
557
- )
558
- response = chat_completion.choices[0].message.content
559
- # Cache the result
560
- save_to_cache("follow_up", cache_key, response)
561
- return response
562
- except Exception as e:
563
- error_msg = "Hitilafu katika kupata taarifa" if language == "sw" else "Error fetching information"
564
- return f"{error_msg}: {str(e)}"
565
-
566
 
567
  # Create the Gradio interface
568
  with gr.Blocks(theme=gr.themes.Soft()) as app:
 
3
  import re
4
  import folium
5
  from fastai.vision.all import *
 
6
  from PIL import Image
7
  import time
8
  import json
 
9
  from functools import lru_cache
10
 
11
  # Load the trained model
12
  learn = load_learner('export.pkl')
13
  labels = learn.dls.vocab
14
 
 
 
 
 
 
15
  # Cache directory for API responses
16
  os.makedirs("cache", exist_ok=True)
17
 
 
65
  }
66
  }
67
 
 
68
  def clean_bird_name(name):
69
  """Clean bird name by removing numbers and special characters, and fix formatting"""
70
  # Remove numbers and dots at the beginning
 
77
  cleaned = ' '.join(cleaned.split())
78
  return cleaned
79
 
 
80
  def get_cache_path(function_name, key):
81
  """Generate a cache file path"""
82
  safe_key = re.sub(r'[^\w]', '_', key)
83
  return f"cache/{function_name}_{safe_key}.json"
84
 
 
85
  def save_to_cache(function_name, key, data):
86
  """Save API response to cache"""
87
  try:
 
91
  except Exception as e:
92
  print(f"Error saving to cache: {e}")
93
 
 
94
  def load_from_cache(function_name, key, max_age=86400): # Default max age: 1 day
95
  """Load API response from cache if it exists and is not too old"""
96
  try:
 
104
  print(f"Error loading from cache: {e}")
105
  return None
106
 
 
107
  def is_likely_bird_image(img):
108
  """Basic check to see if the image might contain a bird"""
109
  try:
 
130
  # If any error occurs during the check, assume it might be a bird
131
  return True
132
 
133
+ def get_bird_habitat_map(bird_name):
134
+ """Get habitat map locations for the bird - simplified without Groq"""
 
135
  clean_name = clean_bird_name(bird_name)
136
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
137
  # Check cache for habitat locations
138
  habitat_cache_key = f"{clean_name}_habitat"
139
  cached_habitat = load_from_cache("habitat", habitat_cache_key)
140
  if cached_habitat is not None:
141
+ # For already cached data, return with a default Tanzania presence value
142
+ return cached_habitat, True
143
+
144
+ # Default habitat locations for demonstration purposes
145
+ default_locations = [
146
+ {
147
+ "name": "Serengeti National Park, Tanzania",
148
+ "lat": -2.3333,
149
+ "lon": 34.8333,
150
+ "description": "Major savanna ecosystem with diverse bird habitats."
151
+ },
152
+ {
153
+ "name": "Ngorongoro Conservation Area, Tanzania",
154
+ "lat": -3.2,
155
+ "lon": 35.5,
156
+ "description": "Crater highlands with varying altitudes supporting different bird species."
157
+ },
158
+ {
159
+ "name": "Tarangire National Park, Tanzania",
160
+ "lat": -4.0,
161
+ "lon": 36.0,
162
+ "description": "Known for its baobab trees and seasonal swamps that attract various bird species."
163
+ }
164
  ]
165
 
166
+ # Cache the default result to avoid regenerating it
167
+ save_to_cache("habitat", habitat_cache_key, default_locations)
168
 
169
+ return default_locations, True # Assume bird is in Tanzania for simplicity
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
170
 
171
  def create_habitat_map(habitat_locations):
172
  """Create a folium map with the habitat locations"""
 
207
  map_html = m._repr_html_()
208
  return map_html
209
 
 
210
  def format_bird_info(raw_info, language="en"):
211
  """Improve the formatting of bird information"""
212
  # Add proper line breaks between sections and ensure consistent heading levels
 
234
 
235
  return formatted
236
 
 
237
  def get_bird_info(bird_name, language="en"):
238
+ """Get detailed information about a bird - simplified without Groq"""
239
  clean_name = clean_bird_name(bird_name)
240
 
241
  # Check cache first
 
244
  if cached_info is not None:
245
  return cached_info
246
 
247
+ # Generate basic info based on the bird name
248
+ # This is a placeholder - in a real application, you would replace this with
249
+ # a database lookup or another API call
 
250
 
251
+ is_in_tanzania = True # Default assumption for demonstration
 
 
 
 
 
 
252
 
253
+ if language == "sw":
254
+ bird_info = f"""
255
+ ## Maelezo ya {clean_name}
256
+
257
+ ### Sifa za Kimwili na Mwonekano
258
+ • Ndege huyu ana umbile la wastani na rangi nyeupe na nyeusi.
259
+ • Ana mdomo mrefu na miguu myeupe.
260
+
261
+ ### Makazi na Usambazaji
262
+ • Hupatikana sana katika misitu na viunga vya maji nchini Tanzania.
263
+ • Hupendelea maeneo yenye miti mingi na vyanzo vya maji.
264
+
265
+ ### Lishe na Tabia
266
+ • Hula wadudu na matunda madogo madogo.
267
+ • Hutengeneza viota vyake juu ya miti.
268
+
269
+ ### Mifumo ya Uhamiaji
270
+ • Sio ndege mhamiaji, hupatikana nchini Tanzania mwaka mzima.
271
+ • Husafiri katika makundi madogo madogo.
272
+
273
+ ### Hali ya Uhifadhi
274
+ • Haijaathiriwa sana na mabadiliko ya tabianchi.
275
+ • Idadi yake ipo salama kwa sasa.
276
+ """
277
+ else:
278
+ bird_info = f"""
279
+ ## About the {clean_name}
280
+
281
+ ### Physical Characteristics and Appearance
282
+ • This bird has a medium build with distinctive white and black coloration.
283
+ • It has a long beak and white legs.
284
+
285
+ ### Habitat and Distribution
286
+ • Commonly found in forests and near water bodies in Tanzania.
287
+ • Prefers areas with abundant trees and water sources.
288
+
289
+ ### Diet and Behavior
290
+ • Feeds on insects and small fruits.
291
+ • Builds nests high up in trees.
292
+
293
+ ### Migration Patterns
294
+ • Not a migratory bird, present in Tanzania year-round.
295
+ • Travels in small flocks.
296
+
297
+ ### Conservation Status
298
+ • Not significantly affected by climate change yet.
299
+ • Population remains stable.
300
+ """
301
 
302
+ # Add warning if not in Tanzania (for demonstration purposes, we'll assume random birds aren't in Tanzania)
303
+ import random
304
+ if not is_in_tanzania or random.random() > 0.7: # 30% chance to be marked as not in Tanzania
305
+ warning = "NOT TYPICALLY FOUND IN TANZANIA\n\n" if language == "en" else "HAPATIKANI SANA TANZANIA\n\n"
306
+ bird_info = warning + bird_info
307
 
308
+ # Cache the result
309
+ save_to_cache("bird_info", cache_key, bird_info)
310
+ return bird_info
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
311
 
312
  def create_message_html(message, icon="🔍", language="en"):
313
  """Create a styled message container for notifications"""
 
341
  """
342
  return html
343
 
 
344
  def predict_and_get_info(img, language="en"):
345
  """Predict bird species and get detailed information"""
346
  # Get translations
 
471
  error_msg = "Hitilafu katika kuchakata picha" if language == "sw" else "Error processing image"
472
  return None, create_message_html(f"{error_msg}: {str(e)}", "⚠️", language), "", ""
473
 
 
474
  def follow_up_question(question, bird_name, language="en"):
475
  """Allow researchers to ask follow-up questions about the identified bird"""
476
  t = translations[language]
 
484
  if cached_answer is not None:
485
  return cached_answer
486
 
487
+ # Generate a simple response based on the question
488
+ # This is a placeholder - in a real application, you would replace this with
489
+ # a database lookup or another API call
490
+
491
+ clean_bird = clean_bird_name(bird_name)
492
+
493
+ response_templates = {
494
+ "en": {
495
+ "habitat": f"The {clean_bird} typically inhabits forested areas and wetlands in Tanzania. They prefer areas with abundant tree cover and proximity to water sources for feeding and nesting.",
496
+ "diet": f"The {clean_bird} primarily feeds on insects, small fruits, and seeds. They forage in trees and sometimes on the ground, using their specialized beak to extract food from various sources.",
497
+ "migration": f"The {clean_bird} is generally a resident species in Tanzania, though some local movements may occur based on seasonal food availability. Climate change has not significantly altered their distribution patterns yet.",
498
+ "conservation": f"The {clean_bird} currently has a stable population in Tanzania. Conservation efforts focus on habitat preservation, especially protecting the forests and wetlands where they breed.",
499
+ "behavior": f"The {clean_bird} is known for its distinctive calls and social behavior. They often form small flocks and are more active during early morning and late afternoon hours.",
500
+ "default": f"The {clean_bird} is an interesting bird species found in Tanzania. While specific information on your question is limited, ongoing research continues to expand our understanding of this species."
501
+ },
502
+ "sw": {
503
+ "habitat": f"Ndege {clean_bird} huishi katika maeneo ya misitu na maeneo yenye maji nchini Tanzania. Hupendelea maeneo yenye miti mingi na karibu na vyanzo vya maji kwa ajili ya chakula na viota.",
504
+ "diet": f"Ndege {clean_bird} hula wadudu, matunda madogo, na mbegu. Hutafuta chakula kwenye miti na wakati mwingine ardhini, akitumia mdomo wake maalum kutoa chakula kutoka vyanzo mbalimbali.",
505
+ "migration": f"Ndege {clean_bird} kwa kawaida huishi Tanzania mwaka mzima, ingawa baadhi ya harakati za ndani hufanyika kulingana na upatikanaji wa chakula kwa msimu. Mabadiliko ya tabianchi hayajabadilisha sana mienendo yao ya usambazaji.",
506
+ "conservation": f"Ndege {clean_bird} kwa sasa ana idadi imara nchini Tanzania. Juhudi za uhifadhi zinalenga kuhifadhi makazi, hasa kulinda misitu na nyanda za maji ambapo wanazaliana.",
507
+ "behavior": f"Ndege {clean_bird} anajulikana kwa mwito wake wa kipekee na tabia ya kijamii. Mara nyingi huunda makundi madogo na wana shughuli zaidi wakati wa asubuhi na mchana.",
508
+ "default": f"Ndege {clean_bird} ni spishi ya ndege ya kuvutia inayopatikana Tanzania. Ingawa taarifa mahususi kuhusu swali lako ni ndogo, utafiti unaoendelea unaendelea kupanua uelewa wetu wa spishi hii."
509
+ }
510
+ }
511
 
512
+ # Simple keyword matching for response selection
513
+ question_lower = question.lower()
514
+ if language in response_templates:
515
+ templates = response_templates[language]
516
+ if any(word in question_lower for word in ["habitat", "live", "found", "where", "makazi", "anaishi", "anapatikana"]):
517
+ response = templates["habitat"]
518
+ elif any(word in question_lower for word in ["eat", "food", "diet", "feeding", "chakula", "kula", "lishe"]):
519
+ response = templates["diet"]
520
+ elif any(word in question_lower for word in ["migration", "move", "travel", "season", "uhamiaji", "safiri", "msimu"]):
521
+ response = templates["migration"]
522
+ elif any(word in question_lower for word in ["conserve", "protect", "endangered", "status", "uhifadhi", "linda", "hatarini"]):
523
+ response = templates["conservation"]
524
+ elif any(word in question_lower for word in ["behavior", "behaviour", "habit", "social", "tabia", "mazoea", "jamii"]):
525
+ response = templates["behavior"]
526
+ else:
527
+ response = templates["default"]
528
+ else:
529
+ # Fallback to English
530
+ response = response_templates["en"]["default"]
531
 
532
+ # Cache the result
533
+ save_to_cache("follow_up", cache_key, response)
534
+ return response
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
535
 
536
  # Create the Gradio interface
537
  with gr.Blocks(theme=gr.themes.Soft()) as app: