OdiGo-Radar / app.py
Jofax's picture
Update app.py
c653d72 verified
import gradio as gr
import folium
from folium.plugins import FloatImage # kept but unused for now
# ────────────────────────────────────────────────
# DATA
# ────────────────────────────────────────────────
fleet_data = {
"Ice-9": {
"type": "Supply",
"loc": "N. Lhohi",
"lat": 5.86,
"lon": 73.45,
"contact": "7781552",
"load": 85,
"eta": "14:20 MVT",
"status": "Operational"
},
"Kinaaraa": {
"type": "Speedboat",
"loc": "V. Fulidhoo",
"lat": 3.68,
"lon": 73.41,
"contact": "7776406",
"load": 42,
"eta": "16:45 MVT",
"status": "Operational"
},
"Island 1": {
"type": "Speedboat",
"loc": "Male Harbor",
"lat": 4.17,
"lon": 73.51,
"contact": "7772658",
"load": 12,
"eta": "11:10 MVT",
"status": "Docked"
},
"Gems 5": {
"type": "Supply",
"loc": "Thilafushi",
"lat": 4.18,
"lon": 73.44,
"contact": "7785507",
"load": 91,
"eta": "19:30 MVT",
"status": "En Route"
}
}
USERS = {
"user_777": "Active",
"admin_001": "Active",
"guest_001": "Free",
"demo": "Trial"
}
# ────────────────────────────────────────────────
# THEME – modern cyber / radar aesthetic
# ────────────────────────────────────────────────
odigo_theme = gr.themes.Soft(
primary_hue=gr.themes.colors.cyan,
secondary_hue=gr.themes.colors.blue,
neutral_hue=gr.themes.colors.slate,
font=[
gr.themes.GoogleFont("JetBrains Mono"),
gr.themes.GoogleFont("Roboto Mono"),
"ui-monospace", "monospace"
],
).set(
body_background_fill="#05070e",
block_background_fill="#0d1526",
block_border_width="1px",
block_border_color="#00eaff33",
border_color_primary="#00f2ff66",
border_color_primary_dark="#00f2ff99",
button_primary_background_fill="#00f2ff",
button_primary_background_fill_hover="#00d9e6",
button_primary_text_color="#0a0f1a",
button_secondary_background_fill="#1e293b",
button_secondary_text_color="#e2e8f0",
input_background_fill="#0f172a",
input_border_color="#334155",
shadow_drop="rgba(0, 242, 255, 0.12) 0px 4px 16px",
shadow_drop_lg="rgba(0, 242, 255, 0.18) 0px 8px 32px",
)
# ────────────────────────────────────────────────
# LOGIC
# ────────────────────────────────────────────────
def create_radar_map(vessel_name):
if vessel_name not in fleet_data:
m = folium.Map(location=[4.0, 73.5], zoom_start=8, tiles="CartoDB dark_matter")
folium.Marker([4.0, 73.5], popup="No vessel selected").add_to(m)
else:
v = fleet_data[vessel_name]
m = folium.Map(
location=[v["lat"], v["lon"]],
zoom_start=13,
tiles="CartoDB dark_matter",
attr="Β© OpenStreetMap contributors | Β© CartoDB"
)
folium.Circle(
location=[v["lat"], v["lon"]],
radius=1800,
color="#00f2ff",
weight=2,
fill=False,
opacity=0.4,
popup=f"Radar sweep β€’ {vessel_name}"
).add_to(m)
folium.CircleMarker(
location=[v["lat"], v["lon"]],
radius=10,
color="#00f2ff",
weight=3,
fill=True,
fill_color="#00f2ff",
fill_opacity=0.7,
popup=f"<b>{vessel_name}</b><br>{v['type']}<br>{v['loc']}"
).add_to(m)
folium.Marker(
[v["lat"], v["lon"]],
icon=folium.DivIcon(html=f"""
<div style="font-size: 28px; color: #00f2ff; text-shadow: 0 0 10px #00f2ff;">
🚒
</div>
""")
).add_to(m)
folium_html = m._repr_html_()
folium_html = folium_html.replace('width:100%;height:100%', 'width:100%;height:100%')
iframe = f"""
<iframe
srcdoc="{folium_html.replace('"', '&quot;')}"
width="100%"
height="520px"
style="border: none; border-radius: 8px; overflow: hidden; background: #0d1526;"
allowfullscreen
sandbox="allow-scripts allow-same-origin allow-popups"
></iframe>
"""
return iframe
def get_intel(vessel_name, user_id):
user_id_clean = user_id.strip().lower()
user_status = next((status for uid, status in USERS.items() if uid.lower() == user_id_clean), None)
if user_status is None:
return "⚠ INVALID OPERATOR ID\nPlease check your SEA-PASS credentials."
if user_status != "Active":
return (
"πŸ”’ ACCESS DENIED\n"
"━━━━━━━━━━━━━━━━━━━\n"
"SEA-PASS LEVEL: Free / Trial\n"
"Required: Active Subscription (50 MVR)\n"
"Contact support@odigo.mv for upgrade."
)
if vessel_name not in fleet_data:
return "⚠ VESSEL NOT FOUND"
v = fleet_data[vessel_name]
return f"""πŸ›°οΈ RADAR LOCK CONFIRMED
━━━━━━━━━━━━━━━━━━━
VESSEL {vessel_name}
TYPE {v['type']}
LOCATION {v['loc']}
STATUS {v['status']}
LOAD {v['load']}%
ETA {v['eta']}
SIGNAL +960 {v['contact']}
LAST PING LIVE
━━━━━━━━━━━━━━━━━━━
OPERATOR: {user_id} β€’ {user_status}"""
def update_dashboard(vessel_name, user_id):
map_html = create_radar_map(vessel_name)
intel_text = get_intel(vessel_name, user_id)
return map_html, intel_text
# ────────────────────────────────────────────────
# UI
# ────────────────────────────────────────────────
with gr.Blocks(title="OdiGo Maritime Radar β€’ v2.7", fill_width=True) as demo: # removed theme= here
gr.Markdown(
"""
# πŸ›°οΈ ODIGO MARITIME RADAR v2.7
Real-time fleet tracking β€’ Maldives Exclusive
""",
elem_classes="text-center text-cyan-400 font-mono text-2xl mb-4"
)
with gr.Row(equal_height=True):
with gr.Column(scale=1, min_width=320):
with gr.Group():
gr.Markdown("**OPERATOR CONSOLE**", elem_classes="text-cyan-300 font-mono mb-3")
user_input = gr.Textbox(
label="OPERATOR ID (SEA-PASS)",
placeholder="e.g. user_777",
value="user_777",
info="Active subscription required for full intel",
)
vessel_select = gr.Dropdown(
choices=list(fleet_data.keys()),
value="Ice-9",
label="SELECT VESSEL",
elem_classes="font-mono",
)
with gr.Row():
scan_btn = gr.Button("INITIALIZE SCAN", variant="primary", scale=2)
refresh_btn = gr.Button("⟳ REFRESH", variant="secondary", scale=1)
with gr.Column(scale=4):
with gr.Tabs():
with gr.Tab("RADAR DISPLAY"):
map_output = gr.HTML(
value=create_radar_map("Ice-9"),
elem_classes="border border-cyan-700/50 rounded-lg overflow-hidden",
show_label=False
)
with gr.Tab("INTELLIGENCE REPORT"):
intel_box = gr.Textbox(
value=get_intel("Ice-9", "user_777"),
lines=14,
interactive=False,
buttons=["copy"], # ← Replaced show_copy_button=True
container=False,
elem_classes="font-mono whitespace-pre-wrap bg-slate-950/70 p-5 rounded-lg text-cyan-100"
)
scan_btn.click(
fn=update_dashboard,
inputs=[vessel_select, user_input],
outputs=[map_output, intel_box]
)
refresh_btn.click(
fn=update_dashboard,
inputs=[vessel_select, user_input],
outputs=[map_output, intel_box]
)
demo.load(
fn=update_dashboard,
inputs=[vessel_select, user_input],
outputs=[map_output, intel_box]
)
if __name__ == "__main__":
demo.launch(
server_name="0.0.0.0",
server_port=7860,
theme=odigo_theme, # ← Moved here
share=False
)