import os
import base64
import requests
import gradio as gr
import pandas as pd
import folium
from src.gpx_parser import parse_gpx_file, haversine, save_enhanced_gpx
import src.llm as llm
import src.rag as rag
# Initialize cache and temp folders
os.makedirs("./temp", exist_ok=True)
# Preloaded route path
PRELOADED_ROUTE_PATH = r"C:\Users\skushwaha\Documents\hckthn\TrailHead\Routes\track_5-14724236830.gpx"
MAP_HTML_INITIALIZER = """
"""
MAP_INIT_JS = r"""
() => {
// 1. Dynamically append Leaflet CSS
if (!document.getElementById("leaflet-css")) {
var link = document.createElement("link");
link.id = "leaflet-css";
link.rel = "stylesheet";
link.href = "https://unpkg.com/leaflet@1.9.4/dist/leaflet.css";
document.head.appendChild(link);
}
// 2. Dynamically append Leaflet JS
if (!document.getElementById("leaflet-js")) {
var script = document.createElement("script");
script.id = "leaflet-js";
script.src = "https://unpkg.com/leaflet@1.9.4/dist/leaflet.js";
document.head.appendChild(script);
}
// 3. Wait for Leaflet to load and initialize map
var checkExist = setInterval(function() {
if (typeof L !== 'undefined' && L.map) {
var mapContainer = document.getElementById("trailhead-leaflet-map");
if (!mapContainer) return; // Wait for Gradio to mount the container
clearInterval(checkExist);
if (window.myLeafletMap) return; // Already initialized
var map = L.map("trailhead-leaflet-map").setView([46.0734974, 11.1717214], 13);
window.myLeafletMap = map;
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 19,
attribution: '© OpenStreetMap'
}).addTo(map);
window.mapLayers = L.layerGroup().addTo(map);
window.hikerMarker = null;
// Define window.routeDataChangeHandler
window.routeDataChangeHandler = function(routeJson) {
if (!routeJson) return;
try {
var data = JSON.parse(routeJson);
var map = window.myLeafletMap;
if (!map) return;
if (window.mapLayers) {
window.mapLayers.clearLayers();
}
if (window.hikerMarker) {
window.hikerMarker.remove();
window.hikerMarker = null;
}
var points = data.points || [];
var checkpoints = data.checkpoints || [];
var pois = data.pois || [];
if (points.length === 0) return;
var latlngs = points.map(p => [p.lat, p.lon]);
var polyline = L.polyline(latlngs, {
color: "#f59e0b",
weight: 5,
opacity: 0.85
}).addTo(window.mapLayers);
map.fitBounds(polyline.getBounds());
checkpoints.forEach(cp => {
var color = "cadetblue";
if (cp.name === "Start") color = "green";
else if (cp.name === "End") color = "red";
var popupText = `
${cp.name}
Distance: ${cp.cum_dist.toFixed(2)} km
Elevation: ${cp.ele.toFixed(1)} m
`;
L.circleMarker([cp.lat, cp.lon], {
radius: cp.name === "Start" || cp.name === "End" ? 8 : 6,
fillColor: color,
color: "#ffffff",
weight: 1.5,
fillOpacity: 0.9
})
.bindPopup(popupText)
.addTo(window.mapLayers);
});
pois.forEach(poi => {
var color = "purple";
var type = poi.type;
if (["drinking_water", "water_point", "fountain"].includes(type)) {
color = "#3b82f6";
} else if (type === "spring") {
color = "#60a5fa";
} else if (["alpine_hut", "wilderness_hut"].includes(type)) {
color = "#047857";
} else if (type === "camp_site") {
color = "#f97316";
} else if (type === "shelter") {
color = "#10b981";
} else if (type === "viewpoint") {
color = "#a855f7";
} else if (type === "peak") {
color = "#7c3aed";
} else if (type === "phone") {
color = "#ef4444";
}
var popupText = `
${poi.name}
Type: ${type.replace(/_/g, ' ').toUpperCase()}
Distance to Route: ${poi.distance.toFixed(1)} m
`;
L.circleMarker([poi.lat, poi.lon], {
radius: 5,
fillColor: color,
color: "#ffffff",
weight: 1.2,
fillOpacity: 0.95
})
.bindPopup(popupText)
.addTo(window.mapLayers);
});
} catch(e) {
console.error("Error drawing route:", e);
}
};
// Define window.updateHikerPosHandler
window.updateHikerPosHandler = function(coords) {
if (!coords) return;
try {
var data = JSON.parse(coords);
var map = window.myLeafletMap;
if (!map) return;
var pos = [data.lat, data.lon];
if (!window.hikerMarker) {
window.hikerMarker = L.circleMarker(pos, {
radius: 9,
fillColor: "#ef4444",
color: "#ffffff",
weight: 2.5,
fillOpacity: 1.0
}).addTo(map);
} else {
window.hikerMarker.setLatLng(pos);
}
var popupText = `
Current simulated position
Distance Walked: ${data.cum_dist.toFixed(2)} km
Altitude: ${data.ele.toFixed(1)} m
`;
window.hikerMarker.bindPopup(popupText);
map.panTo(pos);
} catch(e) {
console.error("Error updating hiker position:", e);
}
};
// Trigger handlers immediately with any pending data
if (window.pendingRouteData) {
window.routeDataChangeHandler(window.pendingRouteData);
}
if (window.pendingHikerCoords) {
window.updateHikerPosHandler(window.pendingHikerCoords);
}
}
}, 100);
}
"""
EMERGENCY_CARD = """
## 🚨 IMMEDIATE BACKCOUNTRY EMERGENCY CARD (OFFLINE)
If you encounter a medical crisis with no cellular signal, follow these basic steps:
1. **Severe Bleeding:** Apply direct pressure with clean dressing. Elevate limb. Use tourniquet if blood is spurting.
2. **Hypothermia:** Wrap in windproof shell/sleeping bag. Replace wet clothes. Provide warm sweet drinks.
3. **Heat Stroke:** Move to shade. Actively cool by wetting skin and fanning. Sip cool water.
4. **Altitude Illness (AMS/HAPE/HACE):** Descend immediately. Do not ascend. Administer oxygen if available.
5. **Ankle Sprain (R.I.C.E):** Rest the joint. Ice or apply cold pack. Compress with elastic bandage. Elevate limb.
*Disclaimer: This guide is for offline reference only. Always carry a PLB/satellite communicator on remote trails.*
"""
def generate_folium_map(points, checkpoints, pois, hiker_pos=None):
"""
Generate interactive folium map rendering track, checkpoints, POIs, and current hiker pos.
"""
if not points:
m = folium.Map(location=[46.0734974, 11.1717214], zoom_start=13)
return m._repr_html_()
# Center map on current hiker position or middle of track
if hiker_pos:
center_lat, center_lon = hiker_pos["lat"], hiker_pos["lon"]
zoom_val = 15
else:
mid_idx = len(points) // 2
center_lat, center_lon = points[mid_idx]["lat"], points[mid_idx]["lon"]
zoom_val = 14
m = folium.Map(location=[center_lat, center_lon], zoom_start=zoom_val)
# Draw track polyline
locations = [(p["lat"], p["lon"]) for p in points]
folium.PolyLine(locations, color="#f59e0b", weight=5, opacity=0.85).add_to(m)
# Draw checkpoints
for cp in checkpoints:
name = cp["name"]
lat = cp["lat"]
lon = cp["lon"]
ele = cp["ele"]
dist = cp["cum_dist"]
if name == "Start":
color = "green"
icon = "play"
elif name == "End":
color = "red"
icon = "flag"
else:
color = "cadetblue"
icon = "info-sign"
popup_text = f"""
{name}
Distance: {dist:.2f} km
Elevation: {ele:.1f} m
"""
folium.Marker(
location=[lat, lon],
popup=popup_text,
tooltip=name,
icon=folium.Icon(color=color, icon=icon)
).add_to(m)
# Draw POIs
for poi in pois:
poi_type = poi["type"]
icon_color = "purple"
icon_name = "info-sign"
# Color coding:
# - drinking_water / water_point / fountain -> blue / glass
# - spring -> lightblue / tint
# - alpine_hut / wilderness_hut -> darkgreen / home
# - camp_site -> orange / fire
# - shelter -> green / leaf
# - viewpoint -> purple / camera
# - peak -> darkpurple / flag
# - phone -> red / phone
if poi_type in ["drinking_water", "water_point", "fountain"]:
icon_color = "blue"
icon_name = "glass"
elif poi_type == "spring":
icon_color = "lightblue"
icon_name = "tint"
elif poi_type in ["alpine_hut", "wilderness_hut"]:
icon_color = "darkgreen"
icon_name = "home"
elif poi_type == "camp_site":
icon_color = "orange"
icon_name = "fire"
elif poi_type == "shelter":
icon_color = "green"
icon_name = "leaf"
elif poi_type == "viewpoint":
icon_color = "purple"
icon_name = "camera"
elif poi_type == "peak":
icon_color = "darkpurple"
icon_name = "flag"
elif poi_type == "phone":
icon_color = "red"
icon_name = "phone"
popup_text = f"""
{poi['name']}
Type: {poi_type.replace('_', ' ').title()}
Distance to Route: {poi['distance']:.1f} m
"""
folium.Marker(
location=[poi["lat"], poi["lon"]],
popup=popup_text,
tooltip=poi['name'],
icon=folium.Icon(color=icon_color, icon=icon_name)
).add_to(m)
return m._repr_html_()
def get_map_iframe(map_html):
"""
Helper to bundle raw HTML into a secure, sandboxed base64 data URI iframe.
"""
injected_js = """
"""
if "