diff --git a/app.py b/app.py index 165d4f0..5ad0954 100644 --- a/app.py +++ b/app.py @@ -89,6 +89,35 @@ def trip_route(trip_id): return jsonify(error=f"Trip not found: {trip_id}"), 404 return jsonify(trip) +import functools +import urllib.request + +@functools.lru_cache(maxsize=512) +def _geocode_cached(lat3, lon3): + """Try Nominatim first (street-level), fall back to reverse_geocoder (city).""" + lat = lat3 / 1000.0 + lon = lon3 / 1000.0 + try: + url = f"https://nominatim.openstreetmap.org/reverse?format=jsonv2&lat={lat}&lon={lon}&accept-language=en" + req = urllib.request.Request(url, headers={"User-Agent": "yaris-obd/1.0"}) + with urllib.request.urlopen(req, timeout=4) as resp: + data = json.loads(resp.read()) + a = data.get("address", {}) + road = a.get("road") or a.get("hamlet") or a.get("suburb") or "" + city = a.get("city") or a.get("town") or a.get("village") or a.get("municipality") or "" + label = ", ".join(p for p in [road, city] if p) + if label: + return label + except Exception: + pass + # Offline fallback + import reverse_geocoder as rg + results = rg.search([(lat, lon)], mode=1, verbose=False) + if results: + r = results[0] + return ", ".join(p for p in [r.get("name", ""), r.get("admin1", "")] if p) + return f"{lat:.5f}, {lon:.5f}" + @app.route('/api/geocode') def geocode_route(): try: @@ -96,14 +125,8 @@ def geocode_route(): lon = float(request.args['lon']) except (KeyError, ValueError): return jsonify(error="lat and lon required"), 400 - import reverse_geocoder as rg - results = rg.search([(lat, lon)], mode=1, verbose=False) - if results: - r = results[0] - parts = [r.get('name', ''), r.get('admin1', '')] - label = ', '.join(p for p in parts if p) - else: - label = f"{lat:.5f}, {lon:.5f}" + # Round to 3 decimals (~111m precision) for cache key + label = _geocode_cached(round(lat, 3) * 1000 // 1, round(lon, 3) * 1000 // 1) return jsonify(label=label) @app.route('/api/dash/devices')