gendesign/backend/app/api/v1/concepts.py
Light1YT 8279b0ee1f fix(week-review): cross-file добивка код-ревью (#1338, #1363, #1419, #1421, #1424, #1480)
- #1338 concepts.py: geometry.generate вынесен в run_in_threadpool (не блокирует event loop)
- #1363 house_imv_backfill.py + scrape_pipeline.py: периодический heartbeat в долгих IMV-фазах (reap_zombies не помечает живой sweep zombie)
- #1419 site-finder-api.ts: placeholderData keepPreviousData для bbox-запроса (KPI не мигает «0/0» при пане/зуме)
- #1421 site-finder-api.ts: area_ha nullable + адаптер не подставляет 0; null-гейт потребителей EntryMap.tsx, ParcelDrawer.tsx
- #1424/#1480 EstimateResult.tsx: блок «Параметры объекта» скрыт при восстановлении по shared-ссылке (нет мусора «0 м²/Студия/Этаж 0 из 0»)

Верификация: tsc --noEmit 0 ошибок; py_compile OK.
2026-06-15 20:29:00 +05:00

33 lines
1.4 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import logging
from fastapi import APIRouter, HTTPException
from fastapi.concurrency import run_in_threadpool
from app.schemas.concept import ConceptInput, ConceptOutput
from app.services.generative import geometry
from app.services.generative.geometry import ParcelGeometryError
logger = logging.getLogger(__name__)
router = APIRouter()
@router.post("", response_model=ConceptOutput)
async def create_concept(payload: ConceptInput) -> ConceptOutput:
"""Generate 3 building variants for the given parcel polygon.
Stage 1a: Shapely parse + buildable area (setback) + placement grid.
Stage 1b: greedy section placement with STRtree collisions (3 strategies).
Stage 1c: real ТЭП + financial model attached to each variant.
A degenerate parcel (setback consumes everything, malformed geometry) yields a
422 rather than empty variants — that is a bad request, not a valid empty result.
"""
try:
# geometry.generate — синхронный CPU-bound (Shapely/STRtree), мостим через
# run_in_threadpool, чтобы НЕ блокировать event loop (тот же приём, что и в chat.py).
variants = await run_in_threadpool(geometry.generate, payload)
except ParcelGeometryError as exc:
logger.warning("concept generation rejected parcel: %s", exc)
raise HTTPException(status_code=422, detail=str(exc)) from exc
return ConceptOutput(variants=variants)