initial commit

This commit is contained in:
TheOnlyMace
2026-06-18 23:45:08 +02:00
commit 7ba9687619
96 changed files with 4309 additions and 0 deletions

View File

@@ -0,0 +1,114 @@
from __future__ import annotations
import hashlib
from typing import Any
from app.config import CACHE_TTL_GEOCODE, NOMINATIM_BASE_URL, NOMINATIM_USER_AGENT
from app.http_client import get_client
from app.database import get_cached_json, set_cached_json
def _query_hash(query: str) -> str:
return hashlib.sha256(query.strip().lower().encode("utf-8")).hexdigest()
async def _nominatim_get(path: str, params: dict[str, Any]) -> Any:
headers = {"User-Agent": NOMINATIM_USER_AGENT, "Accept-Language": "de"}
client = get_client()
response = await client.get(f"{NOMINATIM_BASE_URL}{path}", params=params, headers=headers, timeout=12.0)
response.raise_for_status()
return response.json()
async def search_places(query: str, limit: int = 8) -> list[dict[str, Any]]:
if len(query.strip()) < 2:
return []
qhash = _query_hash(f"search:{query}:{limit}")
cached = await get_cached_json("geocode_cache", {"query_hash": qhash}, CACHE_TTL_GEOCODE)
if cached is not None:
return cached
raw = await _nominatim_get(
"/search",
{
"q": query,
"format": "jsonv2",
"addressdetails": 1,
"limit": limit,
"countrycodes": "de,at,ch",
},
)
results = []
for item in raw:
address = item.get("address") or {}
label = item.get("display_name", "")
place = (
address.get("city")
or address.get("town")
or address.get("village")
or address.get("municipality")
or address.get("county")
or label.split(",")[0]
)
results.append(
{
"label": label,
"place": place,
"lat": float(item["lat"]),
"lon": float(item["lon"]),
"type": item.get("type"),
"postcode": address.get("postcode"),
"county": address.get("county"),
"state": address.get("state"),
}
)
await set_cached_json(
"geocode_cache",
{"query_hash": qhash, "query_text": query},
results,
)
return results
async def reverse_geocode(lat: float, lon: float) -> dict[str, Any]:
qhash = _query_hash(f"reverse:{lat:.4f}:{lon:.4f}")
cached = await get_cached_json("geocode_cache", {"query_hash": qhash}, CACHE_TTL_GEOCODE)
if cached is not None:
return cached
raw = await _nominatim_get(
"/reverse",
{"lat": lat, "lon": lon, "format": "jsonv2", "addressdetails": 1, "zoom": 10},
)
address = raw.get("address") or {}
payload = {
"label": raw.get("display_name"),
"place": address.get("city")
or address.get("town")
or address.get("village")
or address.get("municipality")
or address.get("county"),
"county": address.get("county"),
"state": address.get("state"),
"postcode": address.get("postcode"),
"admin_names": [
value
for value in [
address.get("city"),
address.get("town"),
address.get("village"),
address.get("municipality"),
address.get("county"),
address.get("state"),
]
if value
],
}
await set_cached_json(
"geocode_cache",
{"query_hash": qhash, "query_text": f"{lat},{lon}"},
payload,
)
return payload