mirror of
https://github.com/zvx-echo6/recon.git
synced 2026-05-20 06:34:40 +02:00
Inverts the /api/geocode chain. Photon is now the primary search
engine; the hand-rolled Netsyms free-text parser is removed.
Address book short-circuits nicknames only ("home", "work") —
full-address queries flow through Photon and address book
entries within 75m annotate matching results with labeled_as.
Coordinate strings detected before search.
Response shape: /api/geocode now returns a ranked candidates
list (always 200 OK, empty list if no match). No more 404 for
unmatched queries. Users can type messy input — wrong case,
missing punctuation, abbreviations, typos — and get results
or close matches.
Netsyms preserved at /api/netsyms/lookup for direct access.
USPS plus4 enrichment of Photon street-address hits is a
planned follow-up.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
62 lines
1.8 KiB
Python
62 lines
1.8 KiB
Python
"""
|
|
RECON Netsyms API + Geocode — Flask Blueprints.
|
|
|
|
GET /api/netsyms/lookup?q=<free text>&country=<optional>
|
|
GET /api/netsyms/health
|
|
GET /api/geocode?q=<query>&limit=<N> (Photon-first search with ranked results)
|
|
"""
|
|
|
|
from flask import Blueprint, request, jsonify
|
|
|
|
from . import netsyms
|
|
from . import address_book
|
|
from . import nav_tools
|
|
from .utils import setup_logging
|
|
|
|
logger = setup_logging('recon.netsyms_api')
|
|
|
|
netsyms_bp = Blueprint('netsyms', __name__)
|
|
geocode_bp = Blueprint('geocode', __name__)
|
|
|
|
|
|
@netsyms_bp.route('/api/netsyms/lookup')
|
|
def api_netsyms_lookup():
|
|
q = request.args.get('q', '').strip()
|
|
if not q:
|
|
return jsonify({'error': 'Missing q parameter'}), 400
|
|
|
|
country = request.args.get('country', '').strip() or None
|
|
results = netsyms.lookup_free_text(q, country_hint=country)
|
|
return jsonify({'results': results, 'count': len(results), 'query': q})
|
|
|
|
|
|
@netsyms_bp.route('/api/netsyms/health')
|
|
def api_netsyms_health():
|
|
return jsonify(netsyms.health())
|
|
|
|
|
|
@geocode_bp.route('/api/geocode')
|
|
def api_geocode():
|
|
"""
|
|
Photon-first geocoding with ranked candidates.
|
|
|
|
GET /api/geocode?q=<query>&limit=<N>
|
|
|
|
Always returns 200 OK with:
|
|
{query, results: [{name, lat, lon, source, confidence, type, raw, ...}], count}
|
|
|
|
- source: "address_book" | "coordinates" | "photon"
|
|
- confidence: "exact" | "high" | "medium" | "low"
|
|
- type: "nickname" | "coordinates" | "street_address" | "poi" | "locality"
|
|
- labeled_as: present when result is within 75m of an address book entry
|
|
- Empty results array is valid (no match). No 404s.
|
|
"""
|
|
q = request.args.get('q', '').strip()
|
|
limit = request.args.get('limit', '10')
|
|
try:
|
|
limit = max(1, min(int(limit), 20))
|
|
except (ValueError, TypeError):
|
|
limit = 10
|
|
|
|
result = nav_tools.geocode(q, limit=limit)
|
|
return jsonify(result)
|