feat: add Python core and infra functions — PWA, geocoding, POI matching
Nuevas funciones Python: build_guide_prompt, generate_pwa_manifest, generate_service_worker, match_pois_to_interests (core), nominatim_reverse_geocode, ollama_chat, overpass_nearby_pois (infra). Incluye tests unitarios. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,74 @@
|
||||
"""Reverse geocoding usando Nominatim (OpenStreetMap)."""
|
||||
|
||||
import json
|
||||
import urllib.request
|
||||
import urllib.parse
|
||||
|
||||
|
||||
def nominatim_reverse_geocode(lat: float, lon: float, lang: str = "es") -> dict:
|
||||
"""Convierte coordenadas lat/lon a una dirección estructurada usando Nominatim.
|
||||
|
||||
Args:
|
||||
lat: Latitud en grados decimales.
|
||||
lon: Longitud en grados decimales.
|
||||
lang: Código de idioma para la respuesta (ISO 639-1). Por defecto "es".
|
||||
|
||||
Returns:
|
||||
Diccionario con campos normalizados de la dirección.
|
||||
|
||||
Raises:
|
||||
RuntimeError: Si la petición HTTP falla o el servidor retorna error.
|
||||
"""
|
||||
params = urllib.parse.urlencode({
|
||||
"format": "jsonv2",
|
||||
"lat": str(lat),
|
||||
"lon": str(lon),
|
||||
"accept-language": lang,
|
||||
"zoom": "18",
|
||||
})
|
||||
url = f"https://nominatim.openstreetmap.org/reverse?{params}"
|
||||
|
||||
req = urllib.request.Request(
|
||||
url,
|
||||
headers={"User-Agent": "fn_registry/1.0"},
|
||||
)
|
||||
|
||||
try:
|
||||
with urllib.request.urlopen(req, timeout=5) as resp:
|
||||
if resp.status != 200:
|
||||
raise RuntimeError(
|
||||
f"nominatim_reverse_geocode: HTTP {resp.status} para lat={lat}, lon={lon}"
|
||||
)
|
||||
data = json.loads(resp.read().decode("utf-8"))
|
||||
except urllib.error.HTTPError as e:
|
||||
raise RuntimeError(
|
||||
f"nominatim_reverse_geocode: HTTP {e.code} para lat={lat}, lon={lon}"
|
||||
) from e
|
||||
except urllib.error.URLError as e:
|
||||
raise RuntimeError(
|
||||
f"nominatim_reverse_geocode: error de red — {e.reason}"
|
||||
) from e
|
||||
|
||||
address = data.get("address", {})
|
||||
|
||||
city = (
|
||||
address.get("city")
|
||||
or address.get("town")
|
||||
or address.get("village")
|
||||
or ""
|
||||
)
|
||||
|
||||
return {
|
||||
"display_name": data.get("display_name", ""),
|
||||
"street": address.get("road", ""),
|
||||
"house_number": address.get("house_number", ""),
|
||||
"neighbourhood": address.get("neighbourhood", ""),
|
||||
"city": city,
|
||||
"state": address.get("state", ""),
|
||||
"country": address.get("country", ""),
|
||||
"postcode": address.get("postcode", ""),
|
||||
"lat": float(data.get("lat", lat)),
|
||||
"lon": float(data.get("lon", lon)),
|
||||
"osm_type": data.get("osm_type", ""),
|
||||
"osm_id": int(data.get("osm_id", 0)),
|
||||
}
|
||||
Reference in New Issue
Block a user