# utils/geocoding.py — OSM/Nominatim geocoding for unknown places import os import re import tempfile import requests from models.city import DB, _norm OSM_URL = "https://nominatim.openstreetmap.org/search" STOPWORDS = { "depart", "départ", "arrival", "arrivee", "arrivée", "vol", "flight", "plane", "train", "bus", "boat", "cruise", "kayak", "velo", "vélo", "jeep", "en", "vers", "pour", "de", "da", "di", } def suggest_unknown_from_text(raw_text: str) -> str: known = set(DB.match_in_text(raw_text or "")) cand = re.findall(r"[A-ZÀ-ỴÂÊÔƠƯĐ][\wÀ-ỹ'-\-]+(?:\s+[A-ZÀ-ỴÂÊÔƠƯĐ][\wÀ-ỹ'-\-]+)*", raw_text or "") out, seen = [], set() for c in cand: n = _norm(c) if n in DB.alias2name: continue if any(_norm(k) == n for k in known): continue tokens = [t for t in _norm(c).split(" ") if t] if any(t in STOPWORDS for t in tokens): continue if c not in seen: out.append(c) seen.add(c) return "\n".join(out) def nominatim_geocode(q: str, lang="vi", countrycodes="vn,la,kh,th", limit=1): try: r = requests.get(OSM_URL, params={ "q": q, "format": "jsonv2", "limit": limit, "accept-language": lang, "countrycodes": countrycodes }, headers={"User-Agent": "Tonkin-Map-App/1.0"}) r.raise_for_status() js = r.json() if not js: return None item = js[0] lat = float(item.get("lat")) lon = float(item.get("lon")) cc = (item.get("address", {}).get("country_code", "") or "").upper() return {"name": q.strip(), "lat": lat, "lon": lon, "country": cc or "", "aliases": ""} except Exception: return None def geocode_unknown_list(text_list: str): names = [ln.strip() for ln in (text_list or "").splitlines() if ln.strip()] rows = [] for nm in names: g = nominatim_geocode(nm) if g: rows.append(g) fns = ["name", "lat", "lon", "country", "aliases", "label_ang", "label_dist"] lines = [",".join(fns)] for r in rows: lines.append(f"{r['name']},{r['lat']},{r['lon']},{r['country']},{r['aliases']},,") csv_text = "\n".join(lines) out_path = os.path.join(tempfile.gettempdir(), "cities_geocoded.csv") with open(out_path, "w", encoding="utf-8-sig") as f: f.write(csv_text) return csv_text, out_path, csv_text