ThEyAtH commited on
Commit
f765fe5
Β·
1 Parent(s): 73e253a

OLA added

Browse files
Files changed (1) hide show
  1. backend/api/server.py +115 -24
backend/api/server.py CHANGED
@@ -66,42 +66,133 @@ app.add_middleware(
66
  )
67
 
68
 
69
- @app.get("/api/geocode")
70
- @limiter.limit("30/minute")
71
- async def geocode_proxy(request: Request, q: str = Query(..., min_length=2, max_length=200)):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
72
  token = os.environ.get("LOCATIONIQ_TOKEN")
73
  if not token:
74
- return JSONResponse(status_code=503, content={"error": "Geocoding not configured."})
75
- params = {
76
- "key": token, "q": q, "limit": 6, "dedupe": 1,
77
- "accept-language": "en", "countrycodes": "in",
78
- "lat": 22.7196, "lon": 75.8577,
79
- }
80
  try:
81
  async with httpx.AsyncClient(timeout=6.0) as client:
82
- res = await client.get("https://api.locationiq.com/v1/autocomplete", params=params)
83
- return res.json() if res.status_code == 200 else JSONResponse(status_code=res.status_code, content={"error": "Geocoding error."})
84
- except httpx.TimeoutException:
85
- return JSONResponse(status_code=504, content={"error": "Geocoding timed out."})
 
 
 
86
  except Exception as e:
87
- logging.error(f"[Geocode] {e}")
88
- return JSONResponse(status_code=500, content={"error": "Internal error."})
89
 
90
 
91
- @app.get("/api/reverse")
92
- @limiter.limit("30/minute")
93
- async def reverse_proxy(request: Request, lat: float = Query(...), lon: float = Query(...)):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
94
  token = os.environ.get("LOCATIONIQ_TOKEN")
95
  if not token:
96
- return JSONResponse(status_code=503, content={"error": "Geocoding not configured."})
97
  try:
98
  async with httpx.AsyncClient(timeout=6.0) as client:
99
- res = await client.get("https://us1.locationiq.com/v1/reverse",
100
- params={"key": token, "lat": lat, "lon": lon, "format": "json"})
101
- return res.json() if res.status_code == 200 else JSONResponse(status_code=res.status_code, content={"error": "Reverse geocoding error."})
 
 
102
  except Exception as e:
103
- logging.error(f"[Reverse] {e}")
104
- return JSONResponse(status_code=500, content={"error": "Internal error."})
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
105
 
106
 
107
  @app.get("/api/tiles/{style}/{z}/{x}/{y}.png")
 
66
  )
67
 
68
 
69
+ # ── Geocoding helpers ─────────────────────────────────────────────
70
+
71
+ async def _ola_geocode(q: str) -> list | None:
72
+ """Ola Maps text search β†’ normalized LocationIQ-style list."""
73
+ key = os.environ.get("OLA_MAPS_KEY")
74
+ if not key:
75
+ return None
76
+ try:
77
+ async with httpx.AsyncClient(timeout=6.0) as client:
78
+ res = await client.get(
79
+ "https://api.olamaps.io/places/v1/textsearch",
80
+ params={"input": f"{q} Indore", "api_key": key},
81
+ headers={"X-Request-Id": "eudora-geocode"},
82
+ )
83
+ if res.status_code != 200:
84
+ return None
85
+ data = res.json()
86
+ results = data.get("results") or data.get("predictions") or []
87
+ normalized = []
88
+ for r in results[:6]:
89
+ loc = r.get("geometry", {}).get("location", {})
90
+ lat = loc.get("lat") or loc.get("latitude")
91
+ lon = loc.get("lng") or loc.get("longitude")
92
+ if not lat or not lon:
93
+ continue
94
+ normalized.append({
95
+ "display_name": r.get("formatted_address") or r.get("description") or r.get("name", ""),
96
+ "lat": str(lat),
97
+ "lon": str(lon),
98
+ "place_id": r.get("place_id", ""),
99
+ })
100
+ return normalized if normalized else None
101
+ except Exception as e:
102
+ logging.warning(f"[Geocode/Ola] {e}")
103
+ return None
104
+
105
+
106
+ async def _locationiq_geocode(q: str) -> list | None:
107
+ """LocationIQ autocomplete fallback."""
108
  token = os.environ.get("LOCATIONIQ_TOKEN")
109
  if not token:
110
+ return None
 
 
 
 
 
111
  try:
112
  async with httpx.AsyncClient(timeout=6.0) as client:
113
+ res = await client.get(
114
+ "https://api.locationiq.com/v1/autocomplete",
115
+ params={"key": token, "q": q, "limit": 6, "dedupe": 1,
116
+ "accept-language": "en", "countrycodes": "in",
117
+ "lat": 22.7196, "lon": 75.8577},
118
+ )
119
+ return res.json() if res.status_code == 200 else None
120
  except Exception as e:
121
+ logging.warning(f"[Geocode/LocationIQ] {e}")
122
+ return None
123
 
124
 
125
+ async def _ola_reverse(lat: float, lon: float) -> dict | None:
126
+ """Ola Maps reverse geocode β†’ normalized LocationIQ-style dict."""
127
+ key = os.environ.get("OLA_MAPS_KEY")
128
+ if not key:
129
+ return None
130
+ try:
131
+ async with httpx.AsyncClient(timeout=6.0) as client:
132
+ res = await client.get(
133
+ "https://api.olamaps.io/places/v1/reverse-geocode",
134
+ params={"latlng": f"{lat},{lon}", "api_key": key},
135
+ headers={"X-Request-Id": "eudora-reverse"},
136
+ )
137
+ if res.status_code != 200:
138
+ return None
139
+ data = res.json()
140
+ results = data.get("results") or []
141
+ if not results:
142
+ return None
143
+ top = results[0]
144
+ return {
145
+ "display_name": top.get("formatted_address", ""),
146
+ "lat": str(lat),
147
+ "lon": str(lon),
148
+ "address": top.get("address_components", {}),
149
+ }
150
+ except Exception as e:
151
+ logging.warning(f"[Reverse/Ola] {e}")
152
+ return None
153
+
154
+
155
+ async def _locationiq_reverse(lat: float, lon: float) -> dict | None:
156
+ """LocationIQ reverse geocode fallback."""
157
  token = os.environ.get("LOCATIONIQ_TOKEN")
158
  if not token:
159
+ return None
160
  try:
161
  async with httpx.AsyncClient(timeout=6.0) as client:
162
+ res = await client.get(
163
+ "https://us1.locationiq.com/v1/reverse",
164
+ params={"key": token, "lat": lat, "lon": lon, "format": "json"},
165
+ )
166
+ return res.json() if res.status_code == 200 else None
167
  except Exception as e:
168
+ logging.warning(f"[Reverse/LocationIQ] {e}")
169
+ return None
170
+
171
+
172
+ # ── Proxy endpoints ───────────────────────────────────────────────
173
+
174
+ @app.get("/api/geocode")
175
+ @limiter.limit("30/minute")
176
+ async def geocode_proxy(request: Request, q: str = Query(..., min_length=2, max_length=200)):
177
+ result = await _ola_geocode(q)
178
+ if result is None:
179
+ logging.info("[Geocode] Ola Maps failed or not configured β€” falling back to LocationIQ")
180
+ result = await _locationiq_geocode(q)
181
+ if result is None:
182
+ return JSONResponse(status_code=503, content={"error": "Geocoding unavailable."})
183
+ return result
184
+
185
+
186
+ @app.get("/api/reverse")
187
+ @limiter.limit("30/minute")
188
+ async def reverse_proxy(request: Request, lat: float = Query(...), lon: float = Query(...)):
189
+ result = await _ola_reverse(lat, lon)
190
+ if result is None:
191
+ logging.info("[Reverse] Ola Maps failed or not configured β€” falling back to LocationIQ")
192
+ result = await _locationiq_reverse(lat, lon)
193
+ if result is None:
194
+ return JSONResponse(status_code=503, content={"error": "Reverse geocoding unavailable."})
195
+ return result
196
 
197
 
198
  @app.get("/api/tiles/{style}/{z}/{x}/{y}.png")