Download backend/emergency_maps_service.py from SolutionChallenge/solution_challenge_backend: direct link, hf CLI and curl.
- Browser
- Download file 14.1 kB
-
https://huggingface.co/spaces/SolutionChallenge/solution_challenge_backend/resolve/main/backend/emergency_maps_service.py
- Command line
-
hf download hf://spaces/SolutionChallenge/solution_challenge_backend/backend/emergency_maps_service.py
-
curl -L -o emergency_maps_service.py https://huggingface.co/spaces/SolutionChallenge/solution_challenge_backend/resolve/main/backend/emergency_maps_service.py
14.1 kB
| """ | |
| OpenStreetMap and local simulation fallback for emergency resource intelligence. | |
| Traffic-aware ETA simulation, nearest services, and hexagonal coverage scoring. | |
| """ | |
| from __future__ import annotations | |
| import logging | |
| import math | |
| import os | |
| import requests | |
| from datetime import datetime, timezone | |
| from typing import Any | |
| logger = logging.getLogger(__name__) | |
| def _maps_api_key() -> str: | |
| return "" | |
| def _get_gmaps_client(): | |
| return None | |
| def maps_configured() -> bool: | |
| return False | |
| def maps_status_detail() -> dict[str, Any]: | |
| return { | |
| "configured": False, | |
| "provider": "simulated_osm", | |
| "key_present": False, | |
| "error": "Google Maps integration disabled. Using local OSM intelligence.", | |
| } | |
| SERVICE_TYPES: dict[str, dict[str, Any]] = { | |
| "hospital": { | |
| "place_type": "hospital", | |
| "keyword": "hospital", | |
| "size_filter": True, | |
| "min_ratings": 50, | |
| "icon": "H", | |
| "label": "Hospital", | |
| }, | |
| "fire_station": { | |
| "place_type": "fire_station", | |
| "keyword": "fire station", | |
| "size_filter": False, | |
| "min_ratings": 0, | |
| "icon": "F", | |
| "label": "Fire Station", | |
| }, | |
| "police": { | |
| "place_type": "police", | |
| "keyword": "police station", | |
| "size_filter": False, | |
| "min_ratings": 0, | |
| "icon": "P", | |
| "label": "Police Station", | |
| }, | |
| "ambulance": { | |
| "place_type": "establishment", | |
| "keyword": "ambulance service emergency", | |
| "size_filter": False, | |
| "min_ratings": 0, | |
| "icon": "A", | |
| "label": "Ambulance Service", | |
| }, | |
| "emergency_supplies": { | |
| "place_type": "pharmacy", | |
| "keyword": "pharmacy medical supply first aid", | |
| "size_filter": False, | |
| "min_ratings": 10, | |
| "icon": "S", | |
| "label": "Emergency Supplies", | |
| }, | |
| } | |
| _OSM_AMENITY_TO_SERVICE = { | |
| "hospital": "hospital", | |
| "fire_station": "fire_station", | |
| "police": "police", | |
| "ambulance_station": "ambulance", | |
| "clinic": "ambulance", | |
| "pharmacy": "emergency_supplies", | |
| "medical_supply": "emergency_supplies", | |
| } | |
| def _haversine_km(lat1: float, lon1: float, lat2: float, lon2: float) -> float: | |
| r = 6371 | |
| dlat = math.radians(lat2 - lat1) | |
| dlon = math.radians(lon2 - lon1) | |
| a = ( | |
| math.sin(dlat / 2) ** 2 | |
| + math.cos(math.radians(lat1)) | |
| * math.cos(math.radians(lat2)) | |
| * math.sin(dlon / 2) ** 2 | |
| ) | |
| return r * 2 * math.asin(math.sqrt(a)) | |
| def _fetch_emergency_nearby_sync(lat: float, lon: float, radius_m: int = 15000) -> list[dict[str, Any]]: | |
| """Query OSM Overpass API synchronously for emergency resources.""" | |
| query = f""" | |
| [out:json][timeout:15]; | |
| ( | |
| node["amenity"="hospital"](around:{radius_m},{lat},{lon}); | |
| node["amenity"="fire_station"](around:{radius_m},{lat},{lon}); | |
| node["amenity"="police"](around:{radius_m},{lat},{lon}); | |
| node["emergency"="ambulance_station"](around:{radius_m},{lat},{lon}); | |
| node["amenity"="clinic"]["emergency"="yes"](around:{radius_m},{lat},{lon}); | |
| node["amenity"="pharmacy"](around:{radius_m},{lat},{lon}); | |
| node["shop"="medical_supply"](around:{radius_m},{lat},{lon}); | |
| ); | |
| out body 80; | |
| """ | |
| mirrors = [ | |
| "https://overpass-api.de/api/interpreter", | |
| "https://overpass.kumi.systems/api/interpreter", | |
| ] | |
| for url in mirrors: | |
| try: | |
| resp = requests.post( | |
| url, | |
| data={"data": query}, | |
| headers={"User-Agent": "CepheusEmergencyConsole/1.0"}, | |
| timeout=12 | |
| ) | |
| if resp.status_code == 200: | |
| return resp.json().get("elements", []) | |
| except Exception as exc: | |
| logger.warning("Overpass sync mirror %s failed: %s", url, exc) | |
| logger.warning("All Overpass sync mirrors failed, generating synthetic mock data.") | |
| import random | |
| mock_elements = [] | |
| # Simplified mock generation for agent use | |
| for _ in range(5): | |
| dlat = (random.random() - 0.5) * 0.05 | |
| dlon = (random.random() - 0.5) * 0.05 | |
| mock_elements.append({ | |
| "type": "node", | |
| "id": random.randint(10000, 99999), | |
| "lat": lat + dlat, | |
| "lon": lon + dlon, | |
| "tags": { | |
| "name": f"Local Medical Center {random.randint(1, 100)}", | |
| "amenity": "hospital", | |
| "emergency": "yes", | |
| "phone": f"+1-555-{random.randint(1000, 9999)}" | |
| } | |
| }) | |
| return mock_elements | |
| def find_nearest_services( | |
| lat: float, | |
| lon: float, | |
| radius_m: int = 10000, | |
| top_n: int = 3, | |
| ) -> dict[str, Any]: | |
| """Nearest emergency services fetched via OSM Overpass with locally simulated driving metrics.""" | |
| elements = _fetch_emergency_nearby_sync(lat, lon, radius_m) | |
| results: dict[str, list[dict[str, Any]]] = {k: [] for k in SERVICE_TYPES} | |
| for el in elements: | |
| tags = el.get("tags", {}) | |
| amenity = tags.get("amenity") | |
| emergency_tag = tags.get("emergency") | |
| shop = tags.get("shop") | |
| service_key = _OSM_AMENITY_TO_SERVICE.get(amenity) | |
| if not service_key and emergency_tag == "ambulance_station": | |
| service_key = "ambulance" | |
| if not service_key and shop == "medical_supply": | |
| service_key = "emergency_supplies" | |
| if not service_key or service_key not in SERVICE_TYPES: | |
| continue | |
| plat = el.get("lat") | |
| plng = el.get("lon") | |
| if plat is None or plng is None: | |
| continue | |
| config = SERVICE_TYPES[service_key] | |
| dist_km = _haversine_km(lat, lon, plat, plng) | |
| # Simulate driving metrics | |
| drive_distance_m = int(dist_km * 1250) # driving distance usually ~25% longer than straight line | |
| duration_normal_s = int((drive_distance_m / 11) + 60) # average speed 40km/h + 1 min startup overhead | |
| duration_traffic_s = int(duration_normal_s * 1.18) # simulate moderate traffic (18% slower) | |
| delay_s = duration_traffic_s - duration_normal_s | |
| # Build enriched data | |
| results[service_key].append({ | |
| "place_id": f"osm-{el.get('id')}", | |
| "name": tags.get("name") or config["label"], | |
| "address": tags.get("addr:full") or ", ".join(filter(None, [tags.get("addr:street"), tags.get("addr:city")])) or tags.get("operator", "") or "Address unknown", | |
| "lat": plat, | |
| "lng": plng, | |
| "straight_line_km": round(dist_km, 2), | |
| "drive_distance_m": drive_distance_m, | |
| "drive_distance_text": f"{round(drive_distance_m / 1000, 1)} km", | |
| "duration_normal_s": duration_normal_s, | |
| "duration_normal_text": f"{max(1, duration_normal_s // 60)} mins", | |
| "duration_traffic_s": duration_traffic_s, | |
| "duration_traffic_text": f"{max(1, duration_traffic_s // 60)} mins", | |
| "rating": 4.5, | |
| "user_ratings_total": 20, | |
| "open_now": True, | |
| "phone": tags.get("phone") or tags.get("contact:phone") or "", | |
| "icon": config["icon"], | |
| "service_type": service_key, | |
| "label": config["label"], | |
| "traffic_delay_s": delay_s, | |
| "traffic_delay_text": f"+{delay_s // 60} min delay" if delay_s > 60 else "No significant delay", | |
| "traffic_severity": "heavy" if delay_s > 300 else "moderate" if delay_s > 120 else "light", | |
| }) | |
| for k in results: | |
| results[k].sort(key=lambda x: x["duration_traffic_s"]) | |
| results[k] = results[k][:top_n] | |
| return { | |
| "origin": {"lat": lat, "lng": lon}, | |
| "fetched_at": datetime.now(timezone.utc).isoformat(), | |
| "services": results, | |
| "source": "osm_simulation", | |
| } | |
| def get_directions_with_traffic( | |
| origin_lat: float, | |
| origin_lng: float, | |
| dest_lat: float, | |
| dest_lng: float, | |
| place_name: str = "", | |
| ) -> dict[str, Any]: | |
| """Generates simulated driving route step-by-step and driving metrics.""" | |
| dist_km = _haversine_km(origin_lat, origin_lng, dest_lat, dest_lng) | |
| drive_distance_m = int(dist_km * 1250) | |
| duration_normal_s = int((drive_distance_m / 11) + 60) | |
| duration_traffic_s = int(duration_normal_s * 1.18) | |
| steps = [ | |
| { | |
| "instruction": "Head toward main road", | |
| "distance": "200 m", | |
| "duration": "1 min", | |
| }, | |
| { | |
| "instruction": f"Drive along primary route for {round(dist_km, 1)} km", | |
| "distance": f"{round(drive_distance_m / 1000, 1)} km", | |
| "duration": f"{duration_normal_s // 60} mins", | |
| }, | |
| { | |
| "instruction": f"Turn into destination: {place_name or 'Emergency Service'}", | |
| "distance": "100 m", | |
| "duration": "1 min", | |
| } | |
| ] | |
| return { | |
| "destination_name": place_name, | |
| "distance": f"{round(drive_distance_m / 1000, 1)} km", | |
| "duration_normal": f"{duration_normal_s // 60} mins", | |
| "duration_traffic": f"{duration_traffic_s // 60} mins", | |
| "start_address": f"Location ({origin_lat:.4f}, {origin_lng:.4f})", | |
| "end_address": f"Location ({dest_lat:.4f}, {dest_lng:.4f})", | |
| "steps": steps, | |
| "overview_polyline": "", | |
| "maps_url": f"https://www.openstreetmap.org/directions?engine=fossgis_osrm_car&route={origin_lat},{origin_lng};{dest_lat},{dest_lng}", | |
| } | |
| def get_hexagonal_coverage_data( | |
| center_lat: float, | |
| center_lng: float, | |
| radius_km: float = 5.0, | |
| ) -> dict[str, Any]: | |
| """Calculates coverage grids dynamically using simulated OSM locations.""" | |
| sample_points: list[tuple[float, float]] = [] | |
| steps = 8 | |
| for i in range(-steps, steps + 1): | |
| for j in range(-steps, steps + 1): | |
| dlat = (i / steps) * (radius_km / 111) | |
| dlng = (j / steps) * (radius_km / (111 * math.cos(math.radians(center_lat)))) | |
| pt_lat = center_lat + dlat | |
| pt_lng = center_lng + dlng | |
| if _haversine_km(center_lat, center_lng, pt_lat, pt_lng) <= radius_km: | |
| sample_points.append((pt_lat, pt_lng)) | |
| services_data = find_nearest_services( | |
| center_lat, center_lng, radius_m=int(radius_km * 1000 * 2), top_n=3 | |
| ) | |
| all_service_locations: list[tuple[float, float, str]] = [] | |
| for svc_list in services_data.get("services", {}).values(): | |
| if isinstance(svc_list, list): | |
| for svc in svc_list: | |
| all_service_locations.append((svc["lat"], svc["lng"], svc["service_type"])) | |
| if not all_service_locations: | |
| return {"cells": [], "services": services_data, "center": {"lat": center_lat, "lng": center_lng}} | |
| scored_cells: list[dict[str, Any]] = [] | |
| for pt_lat, pt_lng in sample_points[:40]: | |
| reachable = 0 | |
| unique_types = set() | |
| for slat, slng, stype in all_service_locations: | |
| dist = _haversine_km(pt_lat, pt_lng, slat, slng) | |
| drive_m = dist * 1250 | |
| dur_s = (drive_m / 11) + 60 | |
| if dur_s <= 600: # reachable under 10 mins | |
| reachable += 1 | |
| unique_types.add(stype) | |
| coverage_score = min(100, (reachable * 10) + (len(unique_types) * 15)) | |
| scored_cells.append( | |
| { | |
| "lat": pt_lat, | |
| "lng": pt_lng, | |
| "coverage_score": coverage_score, | |
| "color": ( | |
| "#22c55e" if coverage_score >= 70 else "#eab308" if coverage_score >= 40 else "#ef4444" | |
| ), | |
| } | |
| ) | |
| return { | |
| "center": {"lat": center_lat, "lng": center_lng}, | |
| "cells": scored_cells, | |
| "services": services_data, | |
| "fetched_at": datetime.now(timezone.utc).isoformat(), | |
| } | |
| def recommend_emergency_dispatch( | |
| lat: float, | |
| lng: float, | |
| emergency_type: str, | |
| severity: str = "medium", | |
| ) -> dict[str, Any]: | |
| priority_map = { | |
| "fire": ["fire_station", "hospital", "ambulance"], | |
| "medical": ["ambulance", "hospital", "emergency_supplies"], | |
| "security": ["police", "ambulance", "hospital"], | |
| "crowd": ["police", "ambulance", "hospital"], | |
| "general": ["hospital", "police", "fire_station", "ambulance"], | |
| } | |
| data = find_nearest_services(lat, lng, top_n=3) | |
| services = data.get("services", {}) | |
| priority_types = priority_map.get(emergency_type, priority_map["general"]) | |
| recommendation: dict[str, Any] = { | |
| "emergency_type": emergency_type, | |
| "severity": severity, | |
| "primary_dispatch": [], | |
| "backup_dispatch": [], | |
| "total_response_time_estimate": None, | |
| } | |
| for svc_type in priority_types: | |
| svc_list = services.get(svc_type, []) | |
| if not svc_list or not isinstance(svc_list, list): | |
| continue | |
| best = svc_list[0] | |
| recommendation["primary_dispatch"].append( | |
| { | |
| "service_type": svc_type, | |
| "name": best["name"], | |
| "eta_with_traffic": best["duration_traffic_text"], | |
| "distance": best["drive_distance_text"], | |
| "traffic_severity": best["traffic_severity"], | |
| "address": best["address"], | |
| "lat": best["lat"], | |
| "lng": best["lng"], | |
| } | |
| ) | |
| if len(svc_list) > 1: | |
| backup = svc_list[1] | |
| recommendation["backup_dispatch"].append( | |
| { | |
| "service_type": svc_type, | |
| "name": backup["name"], | |
| "eta_with_traffic": backup["duration_traffic_text"], | |
| } | |
| ) | |
| max_eta_s = 0 | |
| for pt in priority_types: | |
| lst = services.get(pt) | |
| if lst and isinstance(lst, list) and lst: | |
| max_eta_s = max(max_eta_s, lst[0].get("duration_traffic_s", 0)) | |
| if max_eta_s: | |
| recommendation["total_response_time_estimate"] = f"{max_eta_s // 60} minutes" | |
| return recommendation | |