api-usage-demo / app.py
simrol's picture
New UKCEH logo, add user licence, warmup function speed up API
dba2162
import streamlit as st
import requests
import json
import os
from dotenv import load_dotenv
from streamlit_js_eval import get_geolocation
import threading
# Load environment variables from .env file
load_dotenv()
# Load the API key from environment variables
api_key = os.getenv("API_KEY",None)
base_url = os.getenv("API_URL",None)
url = f"{base_url}/predict" # Adjust if upload endpoint is different
warm_up_url = f"{base_url}/warmup"
headers = {
"Authorization": f"Key {api_key}",
"accept": "application/json"
}
# Warmup function this runs in a separate thread to avoid blocking the main app and to ensure the API is ready (model loaded from cache) when the user makes a request
def warmup():
print("Warming up the API...")
resp = requests.get(warm_up_url, headers=headers)
print("Warmup response:", resp.status_code)
@st.cache_resource
def start_warmup_thread():
thread = threading.Thread(target=warmup, daemon=True)
thread.start()
return "warmup_started"
start_warmup_thread()
st.set_page_config(page_title="AI-Hab Habitat Classifier", page_icon="static/img/ai-hab-logo-transparent.png", layout="centered")
st.title("AI-Hab Habitat Classifier")
st.markdown("AI-Hab is a habitat classification model developed by the [Laboratory of Vision Engineering](https://www.visioneng.org.uk/) at the [University of Lincoln](https://www.lincoln.ac.uk/) and the [UK Centre for Ecology & Hydrology](https://www.ceh.ac.uk/). It is based on the [UKHab](https://www.ukhab.org/) Habitat Classification system and uses computer vision to classify habitats from images. The model is trained on images from the [UKCEH Contryside Survey](https://www.ceh.ac.uk/our-science/projects/countryside-survey).")
# Take photo or upload
st.write("## Capture or Upload Image")
img = st.camera_input("Take a photo of the habitat") or st.file_uploader("Or upload a photo", type=["png", "jpg", "jpeg"])
location = get_geolocation()
if img:
# Send to API
with st.spinner("Analyzing habitat..."):
files = {"file": ("habitat.jpg", img.getvalue(), "image/jpeg")}
if location is not None:
params = {"latitude": location['coords']['latitude'],
"longitude": location['coords']['longitude'],
"top_n":3}
else:
params = {"top_n":3}
resp = requests.post(url, headers=headers, params = params, files=files)
data = resp.json()
# Display results
predictions = data["results"]["ukhab"]
col1, col2 = st.columns(2)
with col1:
st.image(img, caption="Uploaded image")
with col2:
if location is not None:
st.map([{"lat": location['coords']['latitude'], "lon": location['coords']['longitude']}], height=150)
else:
st.text("Location is not enabled.")
st.warning("**Note:** The model is still in development and may not be accurate.")
# Show secondary predictions
st.write("## Predictions")
st.write("Inference time: "+ str(data["inference_time_ms"]/1000) + " seconds" )
st.write("Message: "+ data["user_message"])
for pred in predictions[0:]:
with st.container(border=True):
st.subheader(f"{pred['code']} - {pred['name']}")
if(pred['confidence']> 0.5):
st.badge(f"**Confidence:** {pred['confidence']:.2%}",color="green")
else:
st.badge(f"**Confidence:** {pred['confidence']:.2%}",color="orange")
st.write("" + " > ".join([h['name'] for h in pred['primary_habitat_hierarchy']]))
st.write("## API Response")
with st.expander("Show response data"):
st.code(json.dumps(data, indent=2), language="json")
st.divider()
col1, col2 = st.columns(2)
with col1:
st.write(" ")
st.image("static/img/UKCEH.png")
with col2:
st.image("static/img/University-of-Lincoln.png")
st.markdown("Read the preprint: [Habitat Classification from Ground-Level Imagery Using Deep Neural Networks](https://arxiv.org/abs/2507.04017).")
st.markdown("View the code to this demonstrator app on [GitHub](https://github.com/NERC-CEH/aihab-streamlit-demo)")
# Load licence markdown (cached)
@st.cache_data
def load_licence():
with open("static/licence/licence.md", "r", encoding="utf-8") as f:
return f.read()
# Define a dialog using the new decorator
@st.dialog("Terms and Conditions for AI-Hab API access")
def licence_dialog():
st.markdown(load_licence())
st.button("Close", on_click=lambda: st.session_state.update(show_dialog=False))
# Create a button to open the dialog
if st.button("View Terms and Conditions"):
licence_dialog()