Commit Graph

17 Commits

Author SHA1 Message Date
Sadmin 98e8e58023 feat: водоёмы в зоне поиска на карте (рекомендации профилей → геослой)
- GET /api/v1/water/{case_id}: полигоны водоёмов/болот OSM вокруг ТНП
  (Overpass, natural=water+wetland, кэш 72ч, circuit breaker от geo_service);
  бейдж-предупреждение по профилям случая (РАС/эпилепсия/не умеет плавать)
- geo_service: цепочка зеркал Overpass (maps.mail.ru → overpass-api.de):
  основной сервер имеет AAAA, на хостах без IPv6-маршрута httpx падал
  ConnectError'ом до IPv4-фолбэка; на CT108 фапало стабильно
- SearchMap: слой водоёмов под зонами (синие полигоны, болота пунктиром),
  попапы с площадью/дистанцией от ТНП; AnalysisResult грузит слой,
  показывает предупреждение профиля и счётчик водоёмов
- проверено на CT108: РАС-кейс (Минск) — 43 объекта, витя-кейс
  (Каменец-борисовская обл.) — 7 объектов, включая водохранилище Загацце
2026-09-09 12:48:44 +03:00
Sadmin 2d264a5779 fix: коэффициенты времени суток по методичке ПСО «Экстремум» (§12.3.3, §12.3.5)
Сверка с методикой ПСР ред. 12.17 (Евдокимов, Лейтес):
- ночь: 0.5 → 0.0 — методичка §12.3.5 прямо даёт «ночь = 0 км»:
  без фонаря в лесу ночью пострадавший не перемещается.
  Ранее 0.5 ЗАВЫШАЛО радиус ночного поиска.
- сумерки/вечер: 0.7 → 0.5 — «за час до заката скорость 50% от обычной».
  B5 переносил 0.7 из старого фронта вопреки методичке.
- get_base_speed: документирована семантика «скорость смещения»
  (не асфальтовая НормС из §12.3.2) — оператору не нужно вводить
  асфальтовую скорость, она уже свёрнута; СП = поправка конкретной
  местности поверх базового среднего леса.

Тесты обновлены под методичку, добавлен тест ночи = 0.
201 passed, 0 failed.
2026-09-09 11:11:34 +03:00
Sadmin 1119793145 fix: обновить тесты distance_service под канон B5 (3e2692f)
Тесты проверяли старые бэкендовские скорости (1.0–5.5 км/ч), тогда как
B5 перенёс в живую копию services/distance_service.py каноничные
displacement-скорости фронта (0.3–2.5 км/ч, априоры ПСО «Экстремум»,
94% в 3 км) и сумерки 0.7.

Обновлены ожидания (пересчитаны все кейсы):
- TestBaseSpeed: 0.3/0.7/1.2/1.5/2.0/2.5/2.5/1.5 по возрастам
- 5 кейсов calculate_max_distance пересчитаны (5.12→1.92 и т.д.)
- test_twilight: 0.5 → 0.7
- test_statistics_values: base_speed 4.0 → 1.5
- test_fatigue_minimum: 27.0 → 13.5
- Добавлена контрольная точка B5: bike 8yo 2h лес = 5.4 км

Коэффициенты в services/ НЕ тронуты (B1-safe) — только тесты.

201 passed, 0 failed.
2026-09-09 10:56:28 +03:00
Sadmin 3e38aae2be feat: завершённые поиски — ручной ввод + детерминированный прогон модели (без ИИ)
Бэкенд:
- schemas.py: ClosedCaseCreate/Response — форма ~25 полей (субъект, среда,
  ресурсы, исход) для внесения завершённых поисков вручную
- routers/closed_cases.py: CRUD + POST {id}/reanalyze. _run_model() —
  тот же скоринг, что /analyze (WeightedScorer + distance_service +
  психотип), НО БЕЗ claude_service: urgency/behavior/actions по правилам
- _accuracy_note(): прогнозный радиус vs факт (в радиусе / мимо)
- main.py: роутер подключён

Фронтенд:
- pages/ClosedCases.jsx + .css: форма внесения (VCL-density, чипы диагнозов/
  рельефа), блок 'Прогноз vs факт', таблица архива (в радиусе/мимо)
- AdminDashboard.jsx: вкладки Кейсы | Завершённые поиски

Тесты: test_closed_cases.py — 6 passed. Существующие 15 failed
(test_distance_service) не связаны с изменениями — падали до них.
2026-09-09 10:41:33 +03:00
root 3e2692f8a5 B5: перенести расчёт анализа в бэкенд (единый источник правды)
AnalysisResult.jsx теперь тонкий клиент над POST /api/v1/analyze — локальные
формулы (calculateFullDistance / generateZonesWithPsychotype / getPsychotypeModifiers)
удалены. Бэкенд становится единственным источником правды.

distance_service:
- get_base_speed: перенесены каноничные displacement-скорости фронта (0.3–2.5)
  вместо расходящихся значений бэкенда (1.0–5.5) — согласовано с априорами ПСО
- реализованы заглушки СКД (get_diagnosis_coefficient: эпилепсия 0.6, ЗПР 0.8,
  РАС 1.0, СДВГ 1.1, здоров 1.0) и СУ (get_transport_coefficient: bike ×5,
  car ×8, иное ×3, none ×1) — критичная безопасность bike×5 теперь в бэкендe
- get_time_of_day_coefficient: сумерки/вечер 0.7 (было 0.5)

analyze.py:
- _derive_profiles: профили (РАС/эпилепсия/СДВГ/ЗПР/велосипед/самокат) формируются
  из diagnosis_type + has_transport, закрывая рассинхрон bike/велосипед на границе
- _derive_time_of_day: время суток из loss_time (порт getTimeOfDay фронта)
- психотип детектится ДО claude_analyze, модификаторы прокидываются в score_zone
- _as_case_data: фильтр пустых контейнеров ([],{}) — фикс затирания данных карточки
  дефолтами payload (psychotype_answers={} затирал реальные ответы)
- в ответ добавлены coefficients, time_of_day, active_profiles, critical_warnings

scoring_service.score_zone: применяется множитель полосы психотипа по дистанции
(порт getPsychotypeModifiers; таблица уже есть в psychotype_service).

AnalysisResult.jsx: рендер бэкенд-ответа, адаптер primary_zones→SearchMap
(score из приоритета, reasoning←reason), локализация пола m/f→М/Ж, бейдж
fallback/ИИ, блоки активных профилей + критических предупреждений + рекомендаций
по психотипу, исправлены ключи отображения (loss_time/behavior_description/
temperature_c). Поведение сохранено (bike 8yo 2h лес = 5.4 км, как во фронте).

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-20 16:36:35 +00:00
root 8b3a2cbf7e B2: tolerant JSON extraction from Claude responses + graceful fallback
_extract_json_payload handles a json/JSON/bare fence, raw JSON and JSON
embedded in prose; any unparseable response or contract violation now
degrades to the deterministic scoring_service instead of raising.
Also guards the response envelope itself (content[0].text).

B3: single home for recommendation scoring

services/recommendation_service.py holds the rules; routers/stats.py and
backend/services/stats_service.py both delegate to it. Unified rules are the
union of the two old copies: same weights/threshold, substring matching
(superset of the old exact match), tolerant key aliases, health_flags rule
kept. Endpoint response contract unchanged.

Plus: Overpass circuit breaker and concurrent zone queries in geo_service -
128 sequential calls per analysis no longer each burn a connect timeout when
the host has no outbound network.

Tests: 152 -> 194 passed.
2026-07-25 13:01:02 +00:00
root 76278f5fe1 fix: apply A1/A2/A3 to the live services/ copy and ship it in the backend image
backend/routers/analyze.py imports services.* (root package), not
backend.services.* - so the earlier A1/A2/A3 edits landed in an unused
duplicate. Also COPY/mount services/ so the container can start at all
(ModuleNotFoundError: No module named services).
2026-07-25 12:31:07 +00:00
root cd65116a2a A2-A6: logging instead of print, claude-sonnet-5 model id, timezone-aware datetime, FastAPI lifespan, .docx parse errors -> HTTP 400 2026-07-25 11:57:03 +00:00
root 0de5beeb64 A7: enable pytest-asyncio (26 skipped async tests now run); fix stale distance assertion in test_geo_service 2026-07-25 11:49:53 +00:00
root 6ca59a04d0 A8: remove dead backend code (old api/ copy, models_* duplicates, .bak files) 2026-07-25 11:48:30 +00:00
Sadmin 5490f3c5f2 A1: guard None/empty args in distance_service coefficients 2026-07-23 21:41:40 +00:00
root 14b3f1af45 P3 auth cors and distance fixes 2026-06-08 16:38:01 +00:00
root 1755e9759b P2 tighten route auth 2026-06-08 16:34:28 +00:00
root 36123d784f P1 auth, CORS, and SQL filtering 2026-06-08 16:21:23 +00:00
root 4e80a0bdfe Make backend start on PostgreSQL 2026-06-08 11:50:29 +00:00
root 3548733019 Fix admin import chain and tests 2026-06-06 20:59:23 +00:00
root fcc22063ed Import Vector lab project 2026-06-06 18:31:55 +00:00