Update app.py
Browse files
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 |
-
|
197 |
-
|
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 |
-
|
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 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 |
-
|
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 |
-
|
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)
|