gendesign/memory/_append_data_sources_v2.py
2026-04-26 15:21:53 +03:00

79 lines
11 KiB
Python
Raw Permalink 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.

"""Append v2 facts to DataSources_Analysis_Apr26 — deeper digging.
Visible script kept in repo for audit. Manually delete when no longer needed."""
import json
import pathlib
target = pathlib.Path(__file__).parent / "memory-gendesign.jsonl"
addendum = {
"type": "entity",
"name": "DataSources_DomRF_Catalog_Apr26",
"entityType": "research",
"observations": [
"Дата: 26.04.2026, продолжение анализа ДОМ.РФ. Расширил understanding API после копки в /сервисы/api/kn/* и /portal-kn/api/*",
"🎯 ГЛАВНЫЙ EXTRACT-FLOW для всех ЖК Свердл. обл. в один проход:",
"ШАГ 1: GET /portal-kn/api/sales/portal?flatStatus=free,booked&regions=66 → возвращает плоский массив всех objId с продажами в регионе. Например, для Свердл. обл. ~100-200 ЖК",
"ШАГ 2: для каждого objId: GET /сервисы/api/kn/object?objId={id} → полная карточка ЖК",
"Header: Authorization: Basic MTpxd2U= (тот же 1:qwe). Запросов ~150-200 чтобы скачать всю Свердл. обл, при rate-limit 5 RPS — 30-40 сек на полный sync",
"Структура ответа /сервисы/api/kn/object — 30+ полей: hobjId, objId, developer{devId, shortName, fullName, groupName, orgForm, companyGroup, devInn}, rpdRegionCd, objAddr, shortAddr, metro{id,name,line,color,time,isWalk}, freeFlatsInfo{priceMin,numberFlats}, objCommercNm (название ЖК), objFloorMin/Max, objElemLivingCnt (всего квартир), objReady100PercDt (дата сдачи), objSquareLiving (общая жилая площадь), latitude, longitude, siteStatus, objGuarantyEscrowFlg, residentialBuildings, rpdNum, pdId (ID проектной декларации), buildType, objStatus, hobjRenderPhotoUrl (рендер ЖК), objPriceAVG (средняя цена м² по ЖК!), objPublDt, aiDescription (AI-генерация — у них уже работает GPT)",
"Реальный пример (Екб, ЖК «РАЗУМ на Малышева»): objId=65136, devInn=3000007315, lat/lon=56.8346/60.6396, метро Площадь 1905 года 27 мин, 413 квартир, 19089 м², дата сдачи 2028-12-31, средняя цена 180828 ₽/м², numberFlats свободных = 52",
"objPriceAVG — золотое поле. Это среднее между всеми квартирами в ЖК, обновляется регулярно. Лучше чем priceMin (минимальная цена), который часто означает 'студия 25 м²'. Для финмодели использовать objPriceAVG",
"freeFlatsInfo.numberFlats — динамика этого числа во времени = velocity proxy. Если ЖК утром было 60 свободных, вечером 52 — продали 8 квартир за день. Для Site Finder Velocity Score это ровно то что нужно. Парсить раз в сутки в нашу БД, считать delta",
"🛠 Endpoints which work (status 200, returning JSON):",
"GET /portal-analytics/api/dashboard/by-region (агрегаты по всей РФ)",
"GET /portal-analytics/api/dashboard/by-region?regionId=66 (фильтр)",
"GET /portal-analytics/api/dashboard/by-room-count (распределение комнатностей)",
"GET /portal-analytics/api/dashboard/by-flat-area (распределение площадей)",
"GET /portal-analytics/api/dashboard/by-developer (топ застройщиков)",
"GET /portal-analytics/api/dictionaries/regions",
"GET /portal-analytics/api/dictionaries/developers",
"GET /portal-kn/api/sales/portal?flatStatus=free,booked&regions=66 (массив ID ЖК)",
"GET /portal-kn/api/kn/places (справочник мест)",
"GET /portal-kn/api/kn/places?regionCd=66",
"GET /сервисы/api/kn/object?objId={id} (per-объект, ОСНОВНОЙ endpoint)",
"GET /сервисы/api/kn/flats/map?latitudePoint1=...&latitudePoint2=...&longitudePoint1=...&longitudePoint2=...&flatStatus=free,booked&regions=66 (per-ЖК с координатами в bbox)",
"GET /сервисы/api/kn/flats/filters (диапазоны цен/площадей/этажей)",
"GET /сервисы/api/kn/dataForFilters (справочник UI)",
"GET /сервисы/api/kn/meta?place=66&objStatus=0 (доступные значения mechanism, energyEff, wall, dduFlg etc)",
"GET /сервисы/api/kn/developers?objStatus=0&place=66&offset=0&limit=30&sortField=devShortCleanNm",
"GET /сервисы/api/kn/devGk?place=66 (группы компаний)",
"GET /сервисы/api/kn/commissioning?place=66&objStatus=0 (даты сдач)",
"GET /сервисы/api/kn/metro?place=66 (метро в регионе)",
"GET /сервисы/api/kn/hru/groups?place=66",
"🚫 Endpoints с проблемами (требуют доп. разбора):",
"/сервисы/api/kn/freeFlats?objId={id} → 502 (proxy error, может быть путь неверный)",
"/сервисы/api/kn/object/{id}/flats → 502",
"/portal-kn/api/object/{id} → 500 INTERNAL_ERROR",
"/portal-kn/api/object/{id}/flats → 500",
"Для получения per-flat данных (отдельные квартиры в ЖК с их площадью/комнатностью/ценой) — пока не нашли работающий endpoint. Поле freeFlatsInfo.numberFlats даёт лишь количество, не детали. Возможно нужно искать через /api/kn/realt/* или другие поддомены",
"📋 Базовый клиент-стратегия для нашего backend:",
"1) cron-task daily_dom_rf_sync: для каждого региона из списка целей → /sales/portal → массив objId → batch fetch /object → upsert в нашу таблицу dom_rf_objects. Время на ~1000 ЖК (вся Свердл.+МО для пилотов): ~3-5 мин. Кладем в Redis cache на 6 ч",
"2) cron-task daily_velocity_snapshot: пробежать те же objId, сохранить freeFlatsInfo.numberFlats с timestamp → таблица dom_rf_velocity_history (objId, snapshot_dt, free_count). Из истории считаем absorption rate",
"3) on-demand: при запросе пользователя про участок → bbox 5км → /flats/map → топ-20 ЖК-аналогов → /object для каждого → median(objPriceAVG), median(objSquareLiving/objElemLivingCnt), avg(objReady100PercDt - objPublDt) (срок строительства)",
"💡 Использование в трёх плитках Plan A:",
"ПЛИТКА «ЧТО СТРОИТЬ»: для региона по /by-region+/by-flat-area получаем benchmark distribution. Для конкретного района (5км вокруг участка) — через /flats/map берем все objId, получаем для каждого freeFlatsInfo.numberFlats и objSquareLiving/objElemLivingCnt. Считаем: средний размер квартиры в районе = objSquareLiving / objElemLivingCnt (для каждого ЖК), distribution по комнатностям через /by-room-count?regionId=X. Smart unit-mix готов для любого участка",
"ПЛИТКА «ПО КАКОЙ ЦЕНЕ»: median(objPriceAVG) по ЖК-аналогам в радиусе. Сравнить с baseline Росстата для региона. Sensitivity: спред p10-p90",
"ПЛИТКА «ЗА КАКОЕ ВРЕМЯ ПРОДАСТСЯ»: для каждого ЖК-аналога взять daily snapshot freeFlatsInfo.numberFlats за последние 30 дней (нужно собирать). Получить velocity (квартир/мес проданных). Спроектировать на наш случай: при N квартирах в концепте, при таком же темпе = время поглощения. До накопления истории — использовать /аналитика/реализация_строящихся_квартир (там может быть готовая агрегация)",
"🔐 Юридический статус ДОМ.РФ scraping: ДОМ.РФ — государственный портал, ЕИСЖС обязан публиковать эти данные согласно 214-ФЗ. JSON API публичный, captcha нет, robots.txt разрешает (надо проверить). Авторизация Basic MTpqd2U= — публичный 'технический' токен фронта. С точки зрения ТОС — это 'использование данных в формате, в котором они доступны на сайте'. Декларируем в реестре ПО как 'интеграция с ЕИСЖС ДОМ.РФ'. Юридически чисто",
"User-Agent: ставить осмысленный (`GenDesign-DataSync/0.1 (https://gendsgn.ru; ops@gendsgn.ru)`). Если ДОМ.РФ когда-нибудь решит закрыть API — есть legal-fallback через их официальную форму обратной связи (nash@domrf.ru) на B2B-доступ к 'сервисы для бизнеса'",
"📦 SCHEMA для миграции (когда будет Stage 2a):",
"table dom_rf_objects (obj_id PK, hobj_id, dev_id FK, dev_inn, group_name, region_cd, obj_addr, obj_short_addr, latitude, longitude, metro_id, metro_name, metro_time, obj_commerc_nm, obj_floor_min, obj_floor_max, obj_elem_living_cnt, obj_ready_100perc_dt, obj_square_living, obj_price_avg, obj_publ_dt, site_status, escrow_flg, problem_flg, building_type, ai_description, render_url, raw_payload jsonb, last_synced_at)",
"table dom_rf_developers (dev_id PK, dev_inn, short_name, full_name, group_name, company_group, org_form_id)",
"table dom_rf_velocity_snapshots (obj_id, snapshot_dt, free_count, price_min, PK(obj_id, snapshot_dt))",
"Индексы: GIST на (latitude, longitude) → ST_DWithin для радиус-запросов в районе",
],
}
relations = [
{"type": "relation", "from": "DataSources_DomRF_Catalog_Apr26", "to": "DataSources_Analysis_Apr26", "relationType": "extends"},
{"type": "relation", "from": "DataSources_DomRF_Catalog_Apr26", "to": "PlanA_AnalyticsFirst_Apr25", "relationType": "operationalizes"},
{"type": "relation", "from": "DataSources_DomRF_Catalog_Apr26", "to": "Stages_MVP_v1", "relationType": "amends_stage_2a"},
]
with target.open("a", encoding="utf-8") as f:
f.write(json.dumps(addendum, ensure_ascii=False) + "\n")
for r in relations:
f.write(json.dumps(r, ensure_ascii=False) + "\n")
print(f"Appended 1 entity + {len(relations)} relations")
print(f"Final line count: {sum(1 for _ in target.open('r', encoding='utf-8'))}")