|
import gradio as gr |
|
import os |
|
from openai import OpenAI |
|
import json |
|
import requests |
|
from PIL import Image |
|
import io |
|
import base64 |
|
|
|
# Constants |
|
DEFAULT_MODEL = "opengvlab/internvl3-14b:free" |
|
# No need for placeholder text as we'll use password type input |
|
DEFAULT_SITE_URL = "https://dynamic-nature-trail-guide.app" |
|
DEFAULT_SITE_NAME = "Dynamic Nature Trail Guide" |
|
|
|
# Initialize system prompt for better nature guide responses |
|
SYSTEM_PROMPT = """ |
|
You are the Dynamic Nature Trail Guide, an expert in identifying and explaining natural elements |
|
found on nature trails. For any image sent, please: |
|
1. Identify all visible plants, animals, geological features, and ecosystems |
|
2. Provide educational information about identified elements |
|
3. Mention any seasonal characteristics visible in the image |
|
4. Note any ecological significance or conservation considerations |
|
5. Offer suggestions for what to observe or learn about next on the trail |
|
Keep explanations informative yet accessible to people of all ages and backgrounds. |
|
""" |
|
|
|
def encode_image_to_base64(image_path): |
|
"""Convert an image file to base64 encoding""" |
|
with open(image_path, "rb") as image_file: |
|
return base64.b64encode(image_file.read()).decode('utf-8') |
|
|
|
def analyze_image(api_key, image, prompt="What can you identify in this nature trail image? Provide detailed educational information.", site_url=DEFAULT_SITE_URL, site_name=DEFAULT_SITE_NAME, model=DEFAULT_MODEL): |
|
"""Analyze the uploaded image using the InternVL3 model via OpenRouter""" |
|
# Remove the placeholder text check |
|
if not api_key: |
|
return "Please provide an OpenRouter API key." |
|
|
|
if image is None: |
|
return "Please upload an image to analyze." |
|
|
|
# Save the image temporarily |
|
temp_image_path = "temp_image.jpg" |
|
image.save(temp_image_path) |
|
|
|
try: |
|
# Convert image to base64 |
|
base64_image = encode_image_to_base64(temp_image_path) |
|
|
|
# Initialize OpenAI client |
|
client = OpenAI( |
|
base_url="https://openrouter.ai/api/v1", |
|
api_key=api_key, |
|
) |
|
|
|
# Create message with image and text |
|
response = client.chat.completions.create( |
|
extra_headers={ |
|
"HTTP-Referer": site_url, |
|
"X-Title": site_name, |
|
}, |
|
model=model, |
|
messages=[ |
|
{"role": "system", "content": SYSTEM_PROMPT}, |
|
{ |
|
"role": "user", |
|
"content": [ |
|
{ |
|
"type": "text", |
|
"text": prompt |
|
}, |
|
{ |
|
"type": "image_url", |
|
"image_url": { |
|
"url": f"data:image/jpeg;base64,{base64_image}" |
|
} |
|
} |
|
] |
|
} |
|
] |
|
) |
|
|
|
analysis_result = response.choices[0].message.content |
|
return analysis_result |
|
|
|
except Exception as e: |
|
return f"Error analyzing image: {str(e)}" |
|
|
|
finally: |
|
# Clean up the temporary file |
|
if os.path.exists(temp_image_path): |
|
os.remove(temp_image_path) |
|
|
|
def build_custom_prompt(identification=True, education=True, seasonal=True, conservation=True, suggestions=True, additional_prompt=""): |
|
"""Build a custom prompt based on user preferences""" |
|
prompt_parts = [] |
|
|
|
if identification: |
|
prompt_parts.append("Identify all visible plants, animals, geological features, and ecosystems") |
|
|
|
if education: |
|
prompt_parts.append("Provide educational information about identified elements") |
|
|
|
if seasonal: |
|
prompt_parts.append("Mention any seasonal characteristics visible in the image") |
|
|
|
if conservation: |
|
prompt_parts.append("Note any ecological significance or conservation considerations") |
|
|
|
if suggestions: |
|
prompt_parts.append("Offer suggestions for what to observe or learn next on the trail") |
|
|
|
if additional_prompt: |
|
prompt_parts.append(additional_prompt) |
|
|
|
if not prompt_parts: |
|
return "What can you identify in this nature trail image?" |
|
|
|
numbered_prompt = "\n".join([f"{i+1}. {part}" for i, part in enumerate(prompt_parts)]) |
|
return f"For this nature trail image, please: \n{numbered_prompt}" |
|
|
|
def create_interface(): |
|
"""Create the Gradio interface for the Dynamic Nature Trail Guide""" |
|
with gr.Blocks(title="Dynamic Nature Trail Guide", theme=gr.themes.Soft()) as app: |
|
gr.Markdown(""" |
|
# ๐ฟ Dynamic Nature Trail Guide: Accessible Outdoor Education ๐ฟ |
|
|
|
Upload an image from your nature walk to identify plants, animals, geological features, and learn about the ecosystem. |
|
This application uses the advanced InternVL3 14B multimodal model for nature identification and education. |
|
""") |
|
|
|
with gr.Row(): |
|
with gr.Column(scale=1): |
|
api_key_input = gr.Textbox( |
|
label="OpenRouter API Key", |
|
placeholder="Enter your OpenRouter API key here...", |
|
type="password" |
|
) |
|
image_input = gr.Image(label="Upload Nature Image", type="pil") |
|
|
|
with gr.Accordion("Advanced Settings", open=False): |
|
site_url = gr.Textbox( |
|
label="Site URL (for OpenRouter)", |
|
value=DEFAULT_SITE_URL |
|
) |
|
site_name = gr.Textbox( |
|
label="Site Name (for OpenRouter)", |
|
value=DEFAULT_SITE_NAME |
|
) |
|
model_selection = gr.Dropdown( |
|
label="Model", |
|
choices=[DEFAULT_MODEL], |
|
value=DEFAULT_MODEL |
|
) |
|
|
|
with gr.Accordion("Customize Analysis", open=False): |
|
gr.Markdown("Select what information you want to receive about the image:") |
|
identification_checkbox = gr.Checkbox(label="Species & Feature Identification", value=True) |
|
education_checkbox = gr.Checkbox(label="Educational Information", value=True) |
|
seasonal_checkbox = gr.Checkbox(label="Seasonal Characteristics", value=True) |
|
conservation_checkbox = gr.Checkbox(label="Conservation Considerations", value=True) |
|
suggestions_checkbox = gr.Checkbox(label="Trail Suggestions", value=True) |
|
additional_prompt = gr.Textbox(label="Additional Instructions (Optional)") |
|
|
|
analyze_button = gr.Button("Analyze Nature Image", variant="primary") |
|
|
|
with gr.Column(scale=1): |
|
output_text = gr.Markdown(label="Analysis Results") |
|
|
|
# Set up the click event for the analyze button |
|
analyze_button.click( |
|
fn=lambda api_key, image, id_check, edu_check, season_check, conserve_check, suggest_check, add_prompt, site_url, site_name, model: |
|
analyze_image( |
|
api_key, |
|
image, |
|
build_custom_prompt(id_check, edu_check, season_check, conserve_check, suggest_check, add_prompt), |
|
site_url, |
|
site_name, |
|
model |
|
), |
|
inputs=[ |
|
api_key_input, |
|
image_input, |
|
identification_checkbox, |
|
education_checkbox, |
|
seasonal_checkbox, |
|
conservation_checkbox, |
|
suggestions_checkbox, |
|
additional_prompt, |
|
site_url, |
|
site_name, |
|
model_selection |
|
], |
|
outputs=output_text |
|
) |
|
|
|
# Example gallery |
|
with gr.Accordion("Example Images", open=False): |
|
gr.Markdown("Click on an example image to analyze it:") |
|
example_images = gr.Examples( |
|
examples=[ |
|
"examples/forest_trail.jpg", |
|
"examples/wetland_boardwalk.jpg", |
|
"examples/mountain_vista.jpg", |
|
"examples/coastal_trail.jpg", |
|
], |
|
inputs=image_input, |
|
label="Nature Trail Examples" |
|
) |
|
|
|
gr.Markdown(""" |
|
## How to Use This App |
|
|
|
1. Enter your OpenRouter API key (sign up at [openrouter.ai](https://openrouter.ai) if needed) |
|
2. Upload an image from your nature walk |
|
3. Customize what kind of information you want (optional) |
|
4. Click "Analyze Nature Image" |
|
5. Explore the detailed educational content about what you're seeing |
|
|
|
This application is designed to make nature more accessible and educational for everyone! |
|
""") |
|
|
|
return app |
|
|
|
# Create and launch the app |
|
if __name__ == "__main__": |
|
app = create_interface() |
|
app.launch() |