fix(phase26): batch geocode endpoint for faster server trip scrubber

This commit is contained in:
Mathieu Moran
2026-08-11 04:44:37 -04:00
parent bdc7a9afb7
commit 5018c6c531
3 changed files with 64 additions and 19 deletions
+20
View File
@@ -193,6 +193,26 @@ def geocode_route():
label = _geocode_cached(int(round(lat, 4) * 10000), int(round(lon, 4) * 10000)) label = _geocode_cached(int(round(lat, 4) * 10000), int(round(lon, 4) * 10000))
return jsonify(label=label) return jsonify(label=label)
@app.route('/api/geocode/batch', methods=['POST'])
def geocode_batch_route():
body = request.get_json(silent=True) or {}
coords = body.get("coords")
if not isinstance(coords, list) or not coords:
return jsonify(error="expected {coords: [{lat, lon}, ...]}"), 400
result = {}
for item in coords:
try:
lat = float(item["lat"])
lon = float(item["lon"])
except (KeyError, ValueError, TypeError):
continue
lat4 = int(round(lat, 4) * 10000)
lon4 = int(round(lon, 4) * 10000)
label = _geocode_cached(lat4, lon4)
if label:
result[f"{lat:.3f},{lon:.3f}"] = label
return jsonify(result)
@app.route('/api/dash/devices') @app.route('/api/dash/devices')
def dash_devices(): def dash_devices():
devices = app_dash.list_usb_storage_partitions() devices = app_dash.list_usb_storage_partitions()
+24
View File
@@ -566,6 +566,30 @@ def geocode():
return jsonify(name=None), 204 return jsonify(name=None), 204
@app.post("/api/geocode/batch")
@require_login
def geocode_batch():
"""Batch geocode — returns {key: label} for all unique coords in one request."""
body = request.get_json(silent=True) or {}
coords = body.get("coords")
if not isinstance(coords, list) or not coords:
return jsonify(error="expected {coords: [{lat, lon}, ...]}"), 400
result = {}
for item in coords:
try:
lat = float(item["lat"])
lon = float(item["lon"])
except (KeyError, ValueError, TypeError):
continue
lat4 = int(round(lat, 4) * 10000)
lon4 = int(round(lon, 4) * 10000)
key = f"{lat:.3f},{lon:.3f}"
name = _geocode_cached(lat4, lon4)
if name:
result[key] = name
return jsonify(result)
# ── Uplink trigger (recompute trips after new batch) ────────────────────── # ── Uplink trigger (recompute trips after new batch) ──────────────────────
@app.post("/api/v1/portal/recompute-trips") @app.post("/api/v1/portal/recompute-trips")
+16 -15
View File
@@ -40,7 +40,6 @@
} }
function preloadGeocodes(points) { function preloadGeocodes(points) {
// Collect unique rounded coordinates and batch-fetch all labels upfront.
_geoCache = {}; _geoCache = {};
const seen = new Set(); const seen = new Set();
const queue = []; const queue = [];
@@ -50,25 +49,27 @@
seen.add(key); seen.add(key);
queue.push({ key, lat: p.latitude, lon: p.longitude }); queue.push({ key, lat: p.latitude, lon: p.longitude });
} }
if (!queue.length) return;
// Fetch in parallel with a small concurrency cap // Try batch endpoint first (server has it, Pi falls back to 404)
const CONCURRENCY = 4; const coords = queue.map(q => ({lat: q.lat, lon: q.lon}));
let idx = 0;
function next() {
if (idx >= queue.length) return;
const item = queue[idx++];
const ctrl = new AbortController(); const ctrl = new AbortController();
const t = setTimeout(() => ctrl.abort(), 4000); const t = setTimeout(() => ctrl.abort(), 15000);
return fetch(`/api/geocode?lat=${item.lat}&lon=${item.lon}`, { signal: ctrl.signal }) fetch('/api/geocode/batch', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({coords: coords}),
signal: ctrl.signal,
})
.then(r => { clearTimeout(t); return r.ok ? r.json() : null; }) .then(r => { clearTimeout(t); return r.ok ? r.json() : null; })
.then(data => { .then(data => {
_geoCache[item.key] = (data && data.label) || null; if (data) {
}) for (const q of queue) {
.catch(() => { clearTimeout(t); _geoCache[item.key] = null; }) if (data[q.key]) _geoCache[q.key] = data[q.key];
.finally(() => next());
} }
// Start initial batch }
for (let i = 0; i < CONCURRENCY && i < queue.length; i++) next(); })
.catch(() => { clearTimeout(t); });
} }
function geocodePoint(lat, lon) { function geocodePoint(lat, lon) {