import base64 import streamlit as st from datetime import datetime, timedelta import time import random from pathlib import Path import os # Choose one of these: # A) Env var: APP_ENV=prod on your server / cloud APP_ENV = os.getenv("natsar", "local").lower() # B) Or secrets: put env="prod" in .streamlit/secrets.toml on your server # APP_ENV = st.secrets.get("env", "local").lower() IS_LOCAL = True # … later, where you currently render your Deploy controls … if IS_LOCAL: st.markdown(""" """, unsafe_allow_html=True) def _image_to_data_url(path: str) -> str: p = Path(path) if not p.is_absolute(): p = Path(__file__).parent / p mime = "image/png" if p.suffix.lower() == ".png" else "image/jpeg" b64 = base64.b64encode(p.read_bytes()).decode() return f"data:{mime};base64,{b64}" # =============== Page setup =============== st.markdown(""" """, unsafe_allow_html=True) st.set_page_config( page_title="Satellite Tasking", layout="wide", initial_sidebar_state="expanded", # keep sidebar open ) # =============== Compact styling & header spacing (avoid cropping) =============== st.markdown(""" """, unsafe_allow_html=True) # =============== Sidebar navigation =============== with st.sidebar: logo_data_url = _image_to_data_url("../resources/images/lucid_insights_logo.png") st.markdown( f"""
Lucid Insights
""", unsafe_allow_html=True, ) st.markdown("---") st.page_link("app.py", label="Home") #st.page_link("pages/lost_at_sea.py", label="Lost at Sea") st.page_link("pages/signal_watch.py", label="Signal Watch") st.page_link("pages/bushland_beacon.py", label="Bushland Beacon") st.page_link("pages/misc_find.py", label="Misc Finder") st.markdown("---") st.page_link("pages/task_drone.py", label="Task Drone") st.page_link("pages/task_satellite.py", label="Satellite Tasking") st.page_link("pages/information.py", label="Survival Information") st.markdown("---") st.caption("SAR-X AI • Satellite Tasking Module") # =============== Header =============== st.markdown( "

SAR-Xai

" "

Satellite Tasking 🛰️

" "
", unsafe_allow_html=True, ) # =============== Top Row: Provider & Notes (single row) =============== satellite_providers = [ "Auto Select Lowest Cost", "Auto Select Fastest Turnaround", "BlackSky", "Planet Labs", "Maxar Technologies", "Airbus Defence and Space", "ICEYE", "Capella Space", "Satellogic", "Earth-i", "Umbra Space", "Spire Global" ] # Metadata for cost/turnaround heuristics provider_cost_multiplier = { "BlackSky": 1.00, "Planet Labs": 0.85, "Maxar Technologies": 1.40, "Airbus Defence and Space": 1.25, "ICEYE": 1.10, "Capella Space": 1.15, "Satellogic": 0.80, "Earth-i": 0.95, "Umbra Space": 1.05, "Spire Global": 0.90 } provider_turnaround_hours = { "BlackSky": 6, "Planet Labs": 8, "Maxar Technologies": 6, "Airbus Defence and Space": 7, "ICEYE": 5, "Capella Space": 5, "Satellogic": 7, "Earth-i": 8, "Umbra Space": 6, "Spire Global": 8 } # ===== Utility Functions ===== def resolve_provider(choice: str) -> str: if choice == "Auto Select Lowest Cost": return min(provider_cost_multiplier, key=provider_cost_multiplier.get) if choice == "Auto Select Fastest Turnaround": return min(provider_turnaround_hours, key=provider_turnaround_hours.get) return choice def estimate_cost(resolution: str, capture_type: str, priority: str, provider_choice: str) -> float: base_by_res = {"0.3 m": 3500, "0.5 m": 2500, "1 m": 1500, "3 m": 800, "10 m": 300} type_add = {"Optical": 0, "SAR (Radar)": 600, "Multispectral": 400, "Infrared": 500} priority_mult = {"Low": 1.00, "Medium": 1.10, "High": 1.25} prov = resolve_provider(provider_choice) prov_mult = provider_cost_multiplier.get(prov, 1.0) cost = (base_by_res[resolution] + type_add[capture_type]) * priority_mult[priority] * prov_mult return round(cost, 2) # ACST utilities def now_acst() -> datetime: return datetime.utcnow() + timedelta(hours=9, minutes=30) def eta_time_acst(hours_from_now: int) -> datetime: return now_acst() + timedelta(hours=hours_from_now) # =============== Provider & Notes Row =============== top_left, top_right = st.columns([0.32, 0.68]) with top_left: selected_provider = st.selectbox("Satellite Provider", satellite_providers, index=0) with top_right: additional_notes = st.text_area( "Provider Notes / Special Instructions", placeholder="Any special imaging parameters or constraints…" ) st.markdown("---") # =============== Bottom: Left (Form) / Right (Response) =============== left_col, right_col = st.columns(2) with left_col: st.subheader("Tasking Parameters", divider=False) # ---- FORM with specific row layout order ---- with st.form("task_satellite_form", clear_on_submit=False): # Row 1: Target area name target_name = st.text_input("Target Area Name", placeholder="e.g., Porepunkah, Victoria") # Row 2: Latitude & Longitude r2c1, r2c2 = st.columns(2) with r2c1: latitude = st.number_input("Latitude", format="%.6f", value=0.0) with r2c2: longitude = st.number_input("Longitude", format="%.6f", value=0.0) # Row 3: Capture Type & Resolution r3c1, r3c2 = st.columns(2) with r3c1: capture_type = st.selectbox("Capture Type", ["Optical", "SAR (Radar)", "Multispectral", "Infrared"]) with r3c2: resolution = st.selectbox("Desired Resolution", ["0.3 m", "0.5 m", "1 m", "3 m", "10 m"], index=1) # Row 4: Capture Date & Priority Level r4c1, r4c2 = st.columns(2) with r4c1: request_date = st.date_input("Preferred Capture Date", datetime.now().date()) with r4c2: priority = st.select_slider("Priority Level", ["Low", "Medium", "High"], value="Medium") # Row 5: Buttons b_l, b_r = st.columns([0.5, 0.5]) with b_l: estimate_clicked = st.form_submit_button("Estimate Time & Cost", use_container_width=True) with b_r: submitted = st.form_submit_button("Submit Satellite Task", use_container_width=True) # =============== Right Side: Response Section =============== with right_col: st.subheader("Tasking Information Response", divider=False) # --- Estimate Cost --- if 'estimate_clicked' in locals() and estimate_clicked and not submitted: resolved = resolve_provider(selected_provider) est = estimate_cost(resolution, capture_type, priority, selected_provider) indicative_hours = provider_turnaround_hours.get(resolved, 6) indicative_eta = eta_time_acst(indicative_hours).strftime("%Y-%m-%d %H:%M") st.info( f"💰 Estimated cost with **{resolved}**: **${est:,.2f}** \n" f"⏱️ Indicative delivery by **{indicative_eta} ACST (UTC+9:30)** " f"(**+{indicative_hours} hours**)." ) a, b = st.columns(2) with a: st.markdown(f"**Target:** {target_name or '—'}") st.markdown(f"**Resolution:** {resolution}") st.markdown(f"**Type:** {capture_type}") with b: st.markdown(f"**Priority:** {priority}") st.markdown(f"**Provider Choice:** {selected_provider} → **{resolved}**") if additional_notes.strip(): st.markdown("**Notes:**") st.caption(additional_notes) # --- Submit Task --- if 'submitted' in locals() and submitted: resolved = resolve_provider(selected_provider) st.success(f"✅ Task submitted to **{resolved}**") a, b = st.columns(2) with a: st.markdown(f"**Target:** {target_name or '—'}") st.markdown(f"**Date:** {request_date.strftime('%Y-%m-%d')}") st.markdown(f"**Coordinates:** ({latitude:.6f}, {longitude:.6f})") with b: st.markdown(f"**Resolution:** {resolution}") st.markdown(f"**Type:** {capture_type}") st.markdown(f"**Priority:** {priority}") if additional_notes.strip(): st.markdown("**Notes:**") st.caption(additional_notes) est = estimate_cost(resolution, capture_type, priority, selected_provider) st.markdown(f"**Estimated Cost:** ${est:,.2f}") with st.spinner("Contacting satellite provider…"): time.sleep(3) # Calculate ETA hours and timestamp if selected_provider == "Auto Select Fastest Turnaround": eta_hours = provider_turnaround_hours.get(resolved, 4) else: eta_hours = random.randint(4, 8) eta_local = eta_time_acst(eta_hours).strftime("%Y-%m-%d %H:%M") st.info( f"📩 {resolved} advises an ETA on image delivery **within {eta_hours} hours** — " f"approximately **{eta_local} ACST (UTC+9:30)** " f"(**+{eta_hours} hours**). \n" f"🕒 Current time (ACST): **{now_acst().strftime('%Y-%m-%d %H:%M')}**." ) elif not ('estimate_clicked' in locals() and estimate_clicked): st.caption("Use **Estimate Cost** to preview pricing or **Submit** to create the task and get an ETA here (shown in **ACST**).") # =============== Footer =============== st.markdown("---") st.caption("Task Satellite • SAR-X AI Satellite Imagery Request Interface · Times shown in **ACST (UTC+9:30)**")