feat(tradein/cian): expose chart+rent+change-pct on AggregatedEstimate

This commit is contained in:
lekss361 2026-05-24 17:10:25 +03:00
parent 591039493c
commit 3185c45a7b
2 changed files with 33 additions and 1 deletions

View file

@ -46,6 +46,20 @@ class AnalogLot(BaseModel):
distance_m: int | None = None # расстояние до целевой квартиры в метрах
class CianValuationSummary(BaseModel):
"""Cian Valuation Calculator данные для UI.
Источник: external_valuations table (source='cian_valuation').
Заполняется только при successful Cian Calculator call в estimator.py.
"""
sale_price_rub: int | None = None
rent_price_rub: int | None = None
chart: list[dict[str, Any]] = Field(default_factory=list)
chart_change_pct: float | None = None
chart_change_direction: Literal["increase", "decrease", "neutral"] | None = None
class AggregatedEstimate(BaseModel):
estimate_id: UUID
median_price_rub: int
@ -66,6 +80,7 @@ class AggregatedEstimate(BaseModel):
sources_used: list[str] = Field(default_factory=list) # ['avito', 'cian', 'rosreestr']
data_freshness_minutes: int | None = None # сколько минут назад был самый свежий парсинг
est_days_on_market: int | None = None # прогноз срока продажи (медиана по аналогам)
cian_valuation: CianValuationSummary | None = None
# ── Параметры оценённой квартиры — нужны, чтобы восстановить карточку
# при открытии оценки по ссылке (?id=), когда формы-инпута уже нет ──
area_m2: float | None = None

View file

@ -31,7 +31,12 @@ from uuid import uuid4
from sqlalchemy import text
from sqlalchemy.orm import Session
from app.schemas.trade_in import AggregatedEstimate, AnalogLot, TradeInEstimateInput
from app.schemas.trade_in import (
AggregatedEstimate,
AnalogLot,
CianValuationSummary,
TradeInEstimateInput,
)
from app.services.geocoder import GeocodeResult, geocode
from app.services.house_metadata import get_house_metadata
from app.services.scrapers.avito_imv import (
@ -865,6 +870,17 @@ async def estimate_quality(
sources_used=sources_used,
data_freshness_minutes=freshness_min,
est_days_on_market=_estimate_days_on_market(listings_clean, deals),
cian_valuation=(
CianValuationSummary(
sale_price_rub=int(cian_val.sale_price_rub) if cian_val.sale_price_rub else None,
rent_price_rub=int(cian_val.rent_price_rub) if cian_val.rent_price_rub else None,
chart=list(cian_val.chart or []),
chart_change_pct=cian_val.chart_change_pct,
chart_change_direction=cian_val.chart_change_direction,
)
if cian_val is not None
else None
),
area_m2=payload.area_m2,
rooms=payload.rooms,
floor=payload.floor,
@ -1598,4 +1614,5 @@ def _empty_estimate(
analogs=[],
actual_deals=[],
expires_at=expires_at,
cian_valuation=None,
)