fix(site-finder): nearest_top3 metro from osm_poi_ekb (#1667) #1670

Merged
lekss361 merged 1 commit from fix/1667-metro-block into main 2026-06-17 17:13:18 +00:00

View file

@ -2127,8 +2127,44 @@ def analyze_parcel(
except Exception as e:
logger.warning("red_lines_block query failed for %s: %s", cad_num, e)
# B5-4) Metro placeholder — заполнится после merge 22h metro scraper
metro_block: dict[str, Any] = {"nearest_top3": None}
# B5-4) Metro — ближайшие 3 станции метро к участку.
# Данные уже в osm_poi_ekb (category='metro_stop', грузятся poi_loader.py:44),
# скрапер не нужен — прямой KNN-запрос по geom <-> centroid участка.
# nearest_top3=[] (НЕ None) когда метро не найдено: отличаем "посчитано, рядом
# нет" от "не реализовано". None только при ошибке запроса.
metro_block: dict[str, Any] = {"nearest_top3": []}
try:
with db.begin_nested():
metro_rows = (
db.execute(
text("""
SELECT name,
ST_Distance(
m.geom::geography,
ST_Centroid(ST_GeomFromText(:wkt, 4326))::geography
) AS dist_m
FROM osm_poi_ekb m
WHERE m.category = 'metro_stop'
ORDER BY m.geom <-> ST_Centroid(ST_GeomFromText(:wkt, 4326))
LIMIT 3
"""),
{"wkt": geom_wkt},
)
.mappings()
.all()
)
metro_block = {
"nearest_top3": [
{
"name": mr["name"],
"distance_m": round(float(mr["dist_m"])) if mr["dist_m"] is not None else None,
}
for mr in metro_rows
]
}
except Exception as e:
logger.warning("metro_block query failed for %s: %s", cad_num, e)
metro_block = {"nearest_top3": None}
# B5-5) District price ranges из objective_lots (SF-B5)
district_price_block: dict[str, Any] = {