solution_challenge_backend / backend /alert_routing.py
github-actions
Deploy to Hugging Face
c794b6b
Raw
History Blame Contribute Delete
3.45 kB
from __future__ import annotations
import math
from typing import Any
# Demo facility coordinates (Bengaluru) — replace with site blueprint GPS in production.
DEMO_ROUTING_DATA = True
ROOM_COORDINATES = {
"LOBBY": (12.9718, 77.5947),
"RESTAURANT B": (12.9721, 77.5954),
"FLOOR 3": (12.9725, 77.5950),
"POOL DECK": (12.9715, 77.5958),
"BALLROOM": (12.9719, 77.5961),
"SERVICE CORRIDOR": (12.9723, 77.5942),
}
RESPONDER_DIRECTORY = [
{
"id": "sec-team-alpha",
"name": "Security Alpha",
"role": "Security",
"channel": "radio://security-alpha",
"rooms": ["LOBBY", "SERVICE CORRIDOR"],
"lat": 12.9718,
"lng": 77.5944,
},
{
"id": "medic-team",
"name": "Medic Unit",
"role": "Medical",
"channel": "app://medic",
"rooms": ["BALLROOM", "POOL DECK", "RESTAURANT B"],
"lat": 12.9719,
"lng": 77.5959,
},
{
"id": "ops-control",
"name": "Ops Control",
"role": "Control",
"channel": "dashboard://command",
"rooms": ["LOBBY", "RESTAURANT B", "FLOOR 3", "POOL DECK", "BALLROOM", "SERVICE CORRIDOR"],
"lat": 12.9720,
"lng": 77.5951,
},
]
def _haversine_km(lat1: float, lng1: float, lat2: float, lng2: float) -> float:
radius = 6371.0
phi1 = math.radians(lat1)
phi2 = math.radians(lat2)
dphi = math.radians(lat2 - lat1)
dlambda = math.radians(lng2 - lng1)
a = math.sin(dphi / 2) ** 2 + math.cos(phi1) * math.cos(phi2) * math.sin(dlambda / 2) ** 2
return radius * (2 * math.atan2(math.sqrt(a), math.sqrt(1 - a)))
def infer_incident_coordinates(location: str | None, lat: float | None, lng: float | None) -> tuple[float | None, float | None]:
if lat is not None and lng is not None:
return float(lat), float(lng)
if not location:
return None, None
return ROOM_COORDINATES.get(location.upper(), (None, None))
def route_alert(alert_payload: dict[str, Any], radius_km: float = 0.45) -> list[dict[str, Any]]:
location = alert_payload.get("location")
lat = alert_payload.get("lat")
lng = alert_payload.get("lng")
incident_lat, incident_lng = infer_incident_coordinates(location, lat, lng)
resolved_location = (location or "").upper()
recipients: list[dict[str, Any]] = []
for responder in RESPONDER_DIRECTORY:
direct_room_match = bool(resolved_location and resolved_location in [room.upper() for room in responder["rooms"]])
nearby = False
distance_km = None
if incident_lat is not None and incident_lng is not None:
distance_km = _haversine_km(incident_lat, incident_lng, responder["lat"], responder["lng"])
nearby = distance_km <= radius_km
if direct_room_match or nearby or responder["role"] == "Control":
recipients.append(
{
"recipient_id": responder["id"],
"recipient_name": responder["name"],
"role": responder["role"],
"channel": responder["channel"],
"distance_km": round(distance_km, 3) if distance_km is not None else None,
"reason": "room-match" if direct_room_match else ("nearby-radius" if nearby else "control-fallback"),
"demo_routing": DEMO_ROUTING_DATA,
}
)
return recipients