|
import os |
|
import gradio as gr |
|
import re |
|
from fastai.vision.all import * |
|
from groq import Groq |
|
from PIL import Image |
|
|
|
|
|
learn = load_learner('export.pkl') |
|
labels = learn.dls.vocab |
|
|
|
|
|
client = Groq( |
|
api_key=os.environ.get("GROQ_API_KEY"), |
|
) |
|
|
|
def clean_bird_name(name): |
|
"""Clean bird name by removing numbers and special characters, and fix formatting""" |
|
|
|
cleaned = re.sub(r'^\d+\.', '', name) |
|
|
|
cleaned = cleaned.replace('_', ' ') |
|
|
|
cleaned = re.sub(r'[^\w\s]', '', cleaned) |
|
|
|
cleaned = ' '.join(cleaned.split()) |
|
return cleaned |
|
|
|
def get_bird_info(bird_name): |
|
"""Get detailed information about a bird using Groq API""" |
|
clean_name = clean_bird_name(bird_name) |
|
|
|
prompt = f""" |
|
Provide detailed information about the {clean_name} bird, including: |
|
1. Physical characteristics and appearance |
|
2. Habitat and distribution |
|
3. Diet and behavior |
|
4. Migration patterns (emphasize if this pattern has changed in recent years due to climate change) |
|
5. Conservation status |
|
|
|
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. |
|
|
|
Format your response in markdown for better readability. |
|
""" |
|
|
|
try: |
|
chat_completion = client.chat.completions.create( |
|
messages=[ |
|
{ |
|
"role": "user", |
|
"content": prompt, |
|
} |
|
], |
|
model="llama-3.3-70b-versatile", |
|
) |
|
return chat_completion.choices[0].message.content |
|
except Exception as e: |
|
return f"Error fetching information: {str(e)}" |
|
|
|
def predict_and_get_info(img): |
|
"""Predict bird species and get detailed information""" |
|
|
|
img = PILImage.create(img) |
|
|
|
|
|
pred, pred_idx, probs = learn.predict(img) |
|
|
|
|
|
num_classes = min(5, len(labels)) |
|
top_indices = probs.argsort(descending=True)[:num_classes] |
|
top_probs = probs[top_indices] |
|
top_labels = [labels[i] for i in top_indices] |
|
|
|
|
|
prediction_results = {clean_bird_name(top_labels[i]): float(top_probs[i]) for i in range(num_classes)} |
|
|
|
|
|
top_bird = str(pred) |
|
|
|
clean_top_bird = clean_bird_name(top_bird) |
|
|
|
|
|
bird_info = get_bird_info(top_bird) |
|
|
|
return prediction_results, bird_info, clean_top_bird |
|
|
|
def follow_up_question(question, bird_name): |
|
"""Allow researchers to ask follow-up questions about the identified bird""" |
|
if not question.strip() or not bird_name: |
|
return "Please identify a bird first and ask a specific question about it." |
|
|
|
prompt = f""" |
|
The researcher is asking about the {bird_name} bird: "{question}" |
|
|
|
Provide a detailed, scientific answer focusing on accurate ornithological information. |
|
If the question relates to Tanzania or climate change impacts, emphasize those aspects in your response. |
|
|
|
IMPORTANT: Do not repeat basic introductory information about the bird that would have already been provided in a general description. |
|
Do not start your answer with phrases like "Introduction to the {bird_name}" or similar repetitive headers. |
|
Directly answer the specific question asked. |
|
|
|
Format your response in markdown for better readability. |
|
""" |
|
|
|
try: |
|
chat_completion = client.chat.completions.create( |
|
messages=[ |
|
{ |
|
"role": "user", |
|
"content": prompt, |
|
} |
|
], |
|
model="llama-3.3-70b-versatile", |
|
) |
|
return chat_completion.choices[0].message.content |
|
except Exception as e: |
|
return f"Error fetching information: {str(e)}" |
|
|
|
|
|
with gr.Blocks(theme=gr.themes.Soft()) as app: |
|
gr.Markdown("# Bird Species Identification for Researchers") |
|
gr.Markdown("Upload an image to identify bird species and get detailed information relevant to research in Tanzania and climate change studies.") |
|
|
|
|
|
current_bird = gr.State("") |
|
|
|
|
|
with gr.Row(): |
|
with gr.Column(scale=1): |
|
input_image = gr.Image(type="pil", label="Upload Bird Image") |
|
submit_btn = gr.Button("Identify Bird", variant="primary") |
|
|
|
with gr.Column(scale=2): |
|
prediction_output = gr.Label(label="Top 5 Predictions", num_top_classes=5) |
|
bird_info_output = gr.Markdown(label="Bird Information") |
|
|
|
|
|
gr.Markdown("---") |
|
|
|
|
|
gr.Markdown("## Research Questions") |
|
|
|
conversation_history = gr.Markdown("") |
|
|
|
with gr.Row(): |
|
follow_up_input = gr.Textbox( |
|
label="Ask a question about this bird", |
|
placeholder="Example: How has climate change affected this bird's migration pattern?", |
|
lines=2 |
|
) |
|
|
|
with gr.Row(): |
|
follow_up_btn = gr.Button("Submit Question", variant="primary") |
|
clear_btn = gr.Button("Clear Conversation") |
|
|
|
|
|
def process_image(img): |
|
if img is None: |
|
return None, "Please upload an image", "", "" |
|
|
|
try: |
|
pred_results, info, clean_bird_name = predict_and_get_info(img) |
|
return pred_results, info, clean_bird_name, "" |
|
except Exception as e: |
|
return None, f"Error processing image: {str(e)}", "", "" |
|
|
|
def update_conversation(question, bird_name, history): |
|
if not question.strip(): |
|
return history |
|
|
|
answer = follow_up_question(question, bird_name) |
|
|
|
|
|
new_exchange = f""" |
|
### Question: |
|
{question} |
|
|
|
### Answer: |
|
{answer} |
|
|
|
--- |
|
""" |
|
updated_history = new_exchange + history |
|
return updated_history |
|
|
|
def clear_conversation_history(): |
|
return "" |
|
|
|
submit_btn.click( |
|
process_image, |
|
inputs=[input_image], |
|
outputs=[prediction_output, bird_info_output, current_bird, conversation_history] |
|
) |
|
|
|
follow_up_btn.click( |
|
update_conversation, |
|
inputs=[follow_up_input, current_bird, conversation_history], |
|
outputs=[conversation_history] |
|
).then( |
|
lambda: "", |
|
outputs=follow_up_input |
|
) |
|
|
|
clear_btn.click( |
|
clear_conversation_history, |
|
outputs=[conversation_history] |
|
) |
|
|
|
|
|
app.launch(share=True) |