File size: 3,947 Bytes
41be7ed
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
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.")