""" Geocoding Service - Uses Nominatim (OpenStreetMap) for free geocoding """ import httpx from typing import Optional, Tuple import asyncio NOMINATIM_URL = "https://nominatim.openstreetmap.org/search" USER_AGENT = "NUMIDIUM/1.0 (Intelligence System)" async def geocode(location_name: str) -> Optional[Tuple[float, float]]: """ Convert a location name to coordinates using Nominatim. Returns (latitude, longitude) or None if not found. Note: Nominatim has rate limits (1 request/second), so be careful with batch operations. """ try: async with httpx.AsyncClient(timeout=10.0) as client: response = await client.get( NOMINATIM_URL, params={ "q": location_name, "format": "json", "limit": 1, "addressdetails": 0 }, headers={ "User-Agent": USER_AGENT } ) if response.status_code == 200: data = response.json() if data and len(data) > 0: lat = float(data[0]["lat"]) lon = float(data[0]["lon"]) return (lat, lon) return None except Exception as e: print(f"Geocoding error for '{location_name}': {e}") return None async def geocode_batch(location_names: list[str], delay: float = 1.0) -> dict[str, Tuple[float, float]]: """ Geocode multiple locations with proper rate limiting. Returns a dict mapping location names to (lat, lon) tuples. """ results = {} for name in location_names: coords = await geocode(name) if coords: results[name] = coords # Respect Nominatim rate limits await asyncio.sleep(delay) return results