Spaces:
Configuration error
Configuration error
| import os | |
| import streamlit as st | |
| from streamlit_folium import st_folium | |
| import folium | |
| from app.utils import load_image, image_to_base64_jpeg, get_env | |
| from app.plant_id_client import PlantIdClient | |
| from app.location import find_observations_in_hyd, observations_to_markers, hyderabad_bbox | |
| st.set_page_config(page_title="Plant Identifier β Hyderabad Locator", page_icon="πΏ", layout="wide") | |
| st.title("πΏ Plant Identifier β Hyderabad Locator") | |
| st.write("Upload a plant photo, identify it with AI, and see where it was observed in Hyderabad.") | |
| with st.sidebar: | |
| st.header("Settings") | |
| api_key = st.text_input("Plant.id API Key", value=get_env("PLANT_ID_API_KEY"), type="password") | |
| st.caption("You can also put this in a `.env` file as `PLANT_ID_API_KEY`.") | |
| st.divider() | |
| st.markdown("**Tip:** Better results with a clear leaf/flower close-up, good lighting, and neutral background.") | |
| uploaded = st.file_uploader("Upload a plant photo (JPG/PNG)", type=["jpg", "jpeg", "png"]) | |
| if uploaded and api_key: | |
| image = load_image(uploaded) | |
| st.image(image, caption="Uploaded image", use_column_width=True) | |
| b64 = image_to_base64_jpeg(image) | |
| client = PlantIdClient(api_key) | |
| with st.spinner("Identifying plant via Plant.id..."): | |
| try: | |
| result = client.identify([b64]) | |
| except Exception as e: | |
| st.error(f"Plant.id API error: {e}") | |
| st.stop() | |
| candidates = client.parse_top_candidates(result) | |
| if not candidates: | |
| st.warning("No candidates returned. Try a clearer image.") | |
| st.stop() | |
| st.subheader("Top Matches") | |
| top = None | |
| for idx, c in enumerate(candidates, start=1): | |
| with st.expander(f"{idx}. {c['scientific_name']} (confidence: {c['probability']:.2%})", expanded=(idx == 1)): | |
| if idx == 1: | |
| top = c | |
| st.write("**Scientific name:**", c["scientific_name"] or "β") | |
| st.write("**Common names:**", ", ".join(c["common_names"]) if c["common_names"] else "β") | |
| if c["wiki"]: | |
| st.write("**About:**", c["wiki"]) | |
| if c["url"]: | |
| st.write(f"[More details]({c['url']})") | |
| # Map Hyderabad occurrences for the top candidate | |
| if top and top.get("scientific_name"): | |
| st.subheader(f"π Observations in Hyderabad: {top['scientific_name']}") | |
| with st.spinner("Fetching observations from iNaturalist..."): | |
| try: | |
| observations = find_observations_in_hyd(top["scientific_name"], per_page=100) | |
| except Exception as e: | |
| st.error(f"iNaturalist API error: {e}") | |
| observations = [] | |
| markers = observations_to_markers(observations) | |
| swlat, swlng, nelat, nelng = hyderabad_bbox() | |
| # Create a Folium map centered roughly in Hyderabad | |
| center_lat = (swlat + nelat) / 2.0 | |
| center_lng = (swlng + nelng) / 2.0 | |
| fmap = folium.Map(location=[center_lat, center_lng], zoom_start=11) | |
| for lat, lng, o in markers: | |
| popup_lines = [] | |
| if o.get("species_guess"): | |
| popup_lines.append(f"<b>{o['species_guess']}</b>") | |
| if o.get("observed_on"): | |
| popup_lines.append(f"Date: {o['observed_on']}") | |
| if o.get("place_guess"): | |
| popup_lines.append(f"Place: {o['place_guess']}") | |
| popup_html = "<br/>".join(popup_lines) if popup_lines else "iNaturalist observation" | |
| folium.Marker([lat, lng], popup=popup_html).add_to(fmap) | |
| # draw bbox | |
| folium.Rectangle( | |
| bounds=[[swlat, swlng], [nelat, nelng]], | |
| fill=False | |
| ).add_to(fmap) | |
| st_map = st_folium(fmap, width=1000, height=600) | |
| st.caption("Map shows iNaturalist community observations within a Hyderabad bounding box.") | |
| else: | |
| st.info("Enter your Plant.id API key in the sidebar and upload an image to begin.") | |