| 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() |