mirror of
https://github.com/zvx-echo6/recon.git
synced 2026-05-20 06:34:40 +02:00
feat(geocode): add viewport bias for location-aware search
- Add lat/lon/zoom params to geocode() and _retrieve_photon_freetext() - Update nav_tools.py wrapper to pass through viewport params - Add /api/geocode handler support for lat/lon/zoom query params - Add _safe_float() helper for param validation - Cast zoom to int for Photon compatibility Allows the frontend to pass current map center/zoom to bias search results toward the visible area. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
f35af18320
commit
2ed9335f4e
3 changed files with 29 additions and 12 deletions
|
|
@ -334,21 +334,20 @@ def _retrieve_photon_structured(parsed, limit=10):
|
||||||
return _parse_photon_features(data.get('features', []), 'photon')
|
return _parse_photon_features(data.get('features', []), 'photon')
|
||||||
|
|
||||||
|
|
||||||
def _retrieve_photon_freetext(query, limit=10):
|
def _retrieve_photon_freetext(query, limit=10, lat=None, lon=None, zoom=None):
|
||||||
"""Query Photon /api for free-text search with location bias."""
|
"""Query Photon /api for free-text search with location bias."""
|
||||||
try:
|
try:
|
||||||
params = {
|
params = {
|
||||||
'q': query,
|
'q': query,
|
||||||
'limit': limit,
|
'limit': limit,
|
||||||
'lat': GEOCODE_BIAS_LAT,
|
'lat': lat if lat is not None else GEOCODE_BIAS_LAT,
|
||||||
'lon': GEOCODE_BIAS_LON,
|
'lon': lon if lon is not None else GEOCODE_BIAS_LON,
|
||||||
'zoom': GEOCODE_BIAS_ZOOM,
|
'zoom': int(zoom) if zoom is not None else GEOCODE_BIAS_ZOOM,
|
||||||
}
|
}
|
||||||
resp = requests.get(f"{PHOTON_URL}/api", params=params, timeout=5)
|
resp = requests.get(f"{PHOTON_URL}/api", params=params, timeout=5)
|
||||||
resp.raise_for_status()
|
resp.raise_for_status()
|
||||||
data = resp.json()
|
data = resp.json()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.debug("Photon /api failed: %s", e)
|
|
||||||
return []
|
return []
|
||||||
|
|
||||||
return _parse_photon_features(data.get('features', []), 'photon')
|
return _parse_photon_features(data.get('features', []), 'photon')
|
||||||
|
|
@ -663,7 +662,7 @@ def _annotate_with_address_book(results):
|
||||||
# PUBLIC API
|
# PUBLIC API
|
||||||
# ═══════════════════════════════════════════════════════════════════
|
# ═══════════════════════════════════════════════════════════════════
|
||||||
|
|
||||||
def geocode(query, limit=10):
|
def geocode(query, limit=10, lat=None, lon=None, zoom=None):
|
||||||
"""
|
"""
|
||||||
Structured geocoding with multi-source retrieval and reranking.
|
Structured geocoding with multi-source retrieval and reranking.
|
||||||
|
|
||||||
|
|
@ -731,7 +730,7 @@ def geocode(query, limit=10):
|
||||||
# Parallel: Netsyms (structured) + Photon (freetext with expanded query)
|
# Parallel: Netsyms (structured) + Photon (freetext with expanded query)
|
||||||
netsyms_results = _retrieve_netsyms(parsed, limit=limit)
|
netsyms_results = _retrieve_netsyms(parsed, limit=limit)
|
||||||
photon_results = _retrieve_photon_freetext(
|
photon_results = _retrieve_photon_freetext(
|
||||||
parsed.get('expanded_query', q), limit=limit
|
parsed.get('expanded_query', q), limit=limit, lat=lat, lon=lon, zoom=zoom
|
||||||
)
|
)
|
||||||
# Also try Photon /structured for addresses
|
# Also try Photon /structured for addresses
|
||||||
photon_struct = _retrieve_photon_structured(parsed, limit=5)
|
photon_struct = _retrieve_photon_structured(parsed, limit=5)
|
||||||
|
|
@ -739,11 +738,11 @@ def geocode(query, limit=10):
|
||||||
|
|
||||||
elif intent == 'POSTCODE':
|
elif intent == 'POSTCODE':
|
||||||
netsyms_results = _retrieve_netsyms(parsed, limit=limit)
|
netsyms_results = _retrieve_netsyms(parsed, limit=limit)
|
||||||
photon_results = _retrieve_photon_freetext(q, limit=limit)
|
photon_results = _retrieve_photon_freetext(q, limit=limit, lat=lat, lon=lon, zoom=zoom)
|
||||||
candidates = netsyms_results + photon_results
|
candidates = netsyms_results + photon_results
|
||||||
|
|
||||||
elif intent in ('LOCALITY', 'POI', 'UNKNOWN'):
|
elif intent in ('LOCALITY', 'POI', 'UNKNOWN'):
|
||||||
candidates = _retrieve_photon_freetext(q, limit=limit)
|
candidates = _retrieve_photon_freetext(q, limit=limit, lat=lat, lon=lon, zoom=zoom)
|
||||||
|
|
||||||
# ── Deduplicate by (lat, lon) proximity ──
|
# ── Deduplicate by (lat, lon) proximity ──
|
||||||
deduped = []
|
deduped = []
|
||||||
|
|
|
||||||
|
|
@ -50,10 +50,10 @@ def _haversine_m(lat1, lon1, lat2, lon2):
|
||||||
return R * 2 * math.atan2(math.sqrt(a), math.sqrt(1 - a))
|
return R * 2 * math.atan2(math.sqrt(a), math.sqrt(1 - a))
|
||||||
|
|
||||||
|
|
||||||
def geocode(query: str, limit: int = 10):
|
def geocode(query: str, limit: int = 10, lat=None, lon=None, zoom=None):
|
||||||
"""Delegate to the structured geocode module. See lib/geocode.py."""
|
"""Delegate to the structured geocode module. See lib/geocode.py."""
|
||||||
from . import geocode as geocode_mod
|
from . import geocode as geocode_mod
|
||||||
return geocode_mod.geocode(query, limit=limit)
|
return geocode_mod.geocode(query, limit=limit, lat=lat, lon=lon, zoom=zoom)
|
||||||
|
|
||||||
|
|
||||||
def _geocode(query: str):
|
def _geocode(query: str):
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,19 @@ def api_netsyms_health():
|
||||||
return jsonify(netsyms.health())
|
return jsonify(netsyms.health())
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def _safe_float(val, lo, hi):
|
||||||
|
"""Parse val as float; return None if missing, non-numeric, or out of [lo, hi]."""
|
||||||
|
if val is None:
|
||||||
|
return None
|
||||||
|
try:
|
||||||
|
f = float(val)
|
||||||
|
if lo <= f <= hi:
|
||||||
|
return f
|
||||||
|
except (ValueError, TypeError):
|
||||||
|
pass
|
||||||
|
return None
|
||||||
|
|
||||||
@geocode_bp.route('/api/geocode')
|
@geocode_bp.route('/api/geocode')
|
||||||
def api_geocode():
|
def api_geocode():
|
||||||
"""
|
"""
|
||||||
|
|
@ -58,7 +71,12 @@ def api_geocode():
|
||||||
except (ValueError, TypeError):
|
except (ValueError, TypeError):
|
||||||
limit = 10
|
limit = 10
|
||||||
|
|
||||||
result = nav_tools.geocode(q, limit=limit)
|
# Viewport bias parameters (optional)
|
||||||
|
lat = _safe_float(request.args.get("lat"), -90, 90)
|
||||||
|
lon = _safe_float(request.args.get("lon"), -180, 180)
|
||||||
|
zoom = _safe_float(request.args.get("zoom"), 0, 22)
|
||||||
|
|
||||||
|
result = nav_tools.geocode(q, limit=limit, lat=lat, lon=lon, zoom=zoom)
|
||||||
return jsonify(result)
|
return jsonify(result)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue