feat(generative): POST /concepts/recompute — live финрасчёт по massing-program (#1965 Stage 2a) #2024

Merged
bot-backend merged 3 commits from feat/concept-recompute-1965-stage2a into main 2026-06-27 19:53:54 +00:00
Showing only changes of commit 7e824ce6e4 - Show all commits

View file

@ -34,6 +34,44 @@ export interface paths {
patch?: never;
trace?: never;
};
"/api/v1/concepts/recompute": {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
get?: never;
put?: never;
/**
* Recompute Massing
* @description Stage 2a (#1965, эпик #1953) LIVE-пересчёт экономики из 3D-массинга.
*
* Hot, debounced-эндпоинт для интерактивных слайдеров Stage 2b: фронтовый
* ``computeModel`` отдаёт агрегированную программу (суммарное пятно × этажность),
* мы синтезируем :class:`TEAP` (``synthesize_teap_from_program`` те же нормативные
* константы, что и обычная генерация) и прогоняем готовый чистый ``compute_financial``
* пересчитанный ТЭП + финмодель.
*
* Цена продажи жилья:
* * ``market_price_per_sqm`` в теле используется как есть (FAST path, БЕЗ БД)
* фронт резолвит цену один раз и шлёт её в каждом keystroke-запросе. Источник
* берём из ``payload.price_source`` (ПОДЛИННЫЙ source, который фронт получил из
* financial_estimate objective_geo_radius / objective_district_median /
* district_reference / class_norm); если фронт его не прислал дефолтный лейбл.
* НЕ хардкодим source иначе honest-флаг в UI/PDF врёт о происхождении цены.
* * иначе, если передан ``parcel_centroid_wkt`` ``_lookup_market_price`` по центроиду
* через ``run_in_threadpool`` (тот же приём, что и в ``create_concept``; sync SQLAlchemy
* не должен блокировать event loop). Падение lookup'а норматив класса, не 500.
* * иначе (нет ни цены, ни центроида) норматив класса (``price_source="class_norm"``).
*/
post: operations["recompute_massing_api_v1_concepts_recompute_post"];
delete?: never;
options?: never;
head?: never;
patch?: never;
trace?: never;
};
"/api/v1/chat/ask": {
parameters: {
query?: never;
@ -4065,6 +4103,82 @@ export interface components {
*/
updated_at: string;
};
/**
* MassingProgram
* @description Stage 2a (#1965) агрегированная массинг-программа для LIVE-пересчёта экономики.
*
* Контракт POST ``/api/v1/concepts/recompute``: вход уже СВЁРНУТАЯ программа из
* фронтового ``computeModel`` интерактивного 3D-массинга (суммарное пятно × этажность),
* без покомпонентной геометрии секций. Эндпоинт синтезирует из неё :class:`TEAP` и
* прогоняет готовый ``compute_financial`` пересчитанная экономика для дебаунс-слайдеров
* Stage 2b.
*
* Класс жилья / тип застройки те же Literal-множества, что у :class:`ConceptInput`
* и ``compute_financial`` (single source of truth по допустимым значениям).
*/
MassingProgram: {
/**
* Total Footprint Sqm
* @description Суммарное пятно застройки всех секций, кв.м (скаляр)
*/
total_footprint_sqm: number;
/**
* Floors
* @description Этажность программы
*/
floors: number;
/**
* Sections
* @description Число секций (метаданные программы)
* @default 1
*/
sections: number;
/**
* Site Area Sqm
* @description Площадь участка для плотности (FAR)
*/
site_area_sqm: number;
/**
* Housing Class
* @default comfort
* @enum {string}
*/
housing_class: "econom" | "comfort" | "business";
/**
* Development Type
* @default mid_rise
* @enum {string}
*/
development_type: "spot" | "mid_rise" | "high_rise";
/**
* Land Cost Rub
* @description Стоимость участка для финмодели (опционально)
*/
land_cost_rub?: number | null;
/**
* Market Price Per Sqm
* @description Предрезолвленная рыночная цена жилья, руб/кв.м (skip DB lookup)
*/
market_price_per_sqm?: number | null;
/**
* Price Source
* @description Подлинный источник предрезолвленной цены (forward из financial_estimate)
*/
price_source?: string | null;
/**
* Parcel Centroid Wkt
* @description WKT-точка центроида участка (WGS84) для DB-резолва цены при fallback
*/
parcel_centroid_wkt?: string | null;
};
/**
* MassingRecomputeOutput
* @description Stage 2a (#1965) результат LIVE-пересчёта: синтезированный ТЭП + финмодель.
*/
MassingRecomputeOutput: {
teap: components["schemas"]["TEAP"];
financial: components["schemas"]["FinancialModel"];
};
/**
* ObjectiveConfigUpdateRequest
* @description PATCH-style обновляет только переданные поля.
@ -4911,6 +5025,39 @@ export interface operations {
};
};
};
recompute_massing_api_v1_concepts_recompute_post: {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
requestBody: {
content: {
"application/json": components["schemas"]["MassingProgram"];
};
};
responses: {
/** @description Successful Response */
200: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["MassingRecomputeOutput"];
};
};
/** @description Validation Error */
422: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["HTTPValidationError"];
};
};
};
};
ask_api_v1_chat_ask_post: {
parameters: {
query?: never;