Import Vector lab project

This commit is contained in:
root
2026-06-06 18:31:55 +00:00
commit fcc22063ed
105 changed files with 31639 additions and 0 deletions
+159
View File
@@ -0,0 +1,159 @@
from fastapi import APIRouter, Depends, Query
from sqlalchemy.orm import Session
from pydantic import BaseModel
from typing import Dict, List, Optional, Literal
from database import get_db
from models import Case
from services.stats_service import (
get_dashboard_stats,
get_statistical_recommendation,
get_heatmap_with_cache,
DashboardStats,
StatisticalRecommendation
)
router = APIRouter()
class HeatmapPoint(BaseModel):
lat: float
lon: float
intensity: float
case_id: str
metadata: Dict
class HeatmapResponse(BaseModel):
points: List[HeatmapPoint]
total: int
filters_applied: Dict
class StatisticalRecommendationRequest(BaseModel):
age: int
season: Optional[str] = None
terrain_primary: Optional[str] = None
@router.get("/summary", response_model=DashboardStats)
async def get_summary(db: Session = Depends(get_db)):
"""
Получить агрегированную статистику для дашборда.
Возвращает:
- Общее количество случаев (всего, активных, закрытых)
- Распределение по полу, возрасту, психотипу, диагнозам, сезонам
- Средняя дистанция находки
- Средняя длительность поиска
- Процент выживаемости
"""
return get_dashboard_stats(db)
@router.post("/recommendation", response_model=StatisticalRecommendation)
async def get_recommendation(
request: StatisticalRecommendationRequest,
db: Session = Depends(get_db)
):
"""
Получить статистические рекомендации на основе похожих случаев.
Фильтры (в порядке приоритета):
1. Возраст ±2 года + сезон + terrain
2. Возраст ±2 года + сезон (если < 5 случаев)
3. Возраст ±2 года (если < 5 случаев)
4. Все случаи (если < 5 случаев)
Возвращает:
- Медианное расстояние находки
- Топ-3 направления с процентами
- Топ-5 типов локаций
- Процент выживаемости
- Размер выборки
- Использованные фильтры
"""
case_data = {
'age': request.age,
'season': request.season,
'terrain_primary': request.terrain_primary
}
return get_statistical_recommendation(case_data, db)
@router.get("/heatmap", response_model=HeatmapResponse)
async def get_heatmap(
map_type: Literal['all', 'age', 'season', 'outcome'] = Query(
'all',
description="Тип карты: all (все точки), age (по возрасту), season (по сезону), outcome (по исходу)"
),
age_group: Optional[str] = Query(
None,
description="Возрастная группа: 0-3, 4-7, 8-11, 12-14, 15-17, 18+"
),
season: Optional[str] = Query(
None,
description="Сезон: зима, весна, лето, осень"
),
year_from: Optional[int] = Query(
None,
description="Год начала периода (например, 2020)"
),
year_to: Optional[int] = Query(
None,
description="Год окончания периода (например, 2026)"
),
outcome: Optional[str] = Query(
None,
description="Исход: alive (выжил), deceased (погиб)"
),
db: Session = Depends(get_db)
):
"""
Получить данные для тепловой карты находок с кэшированием (1 час).
**Типы карт:**
- `all` - все точки с одинаковой интенсивностью
- `age` - интенсивность зависит от возраста (младше = выше)
- `season` - интенсивность зависит от сезона (зима = выше)
- `outcome` - интенсивность зависит от исхода (погиб = выше)
**Фильтры:**
- `age_group` - возрастная группа (0-3, 4-7, 8-11, 12-14, 15-17, 18+)
- `season` - сезон (зима, весна, лето, осень)
- `year_from`, `year_to` - период по годам
- `outcome` - исход (alive, deceased)
**Кэширование:**
Результаты кэшируются на 1 час для ускорения повторных запросов.
**Возвращает:**
- `points` - массив точек с координатами, интенсивностью и метаданными
- `total` - общее количество точек
- `filters_applied` - примененные фильтры
"""
result = get_heatmap_with_cache(
db=db,
map_type=map_type,
age_group=age_group,
season=season,
year_from=year_from,
year_to=year_to,
outcome=outcome
)
points = [
HeatmapPoint(
lat=p['lat'],
lon=p['lon'],
intensity=p['intensity'],
case_id=p['case_id'],
metadata=p['metadata']
)
for p in result['points']
]
return HeatmapResponse(
points=points,
total=result['total'],
filters_applied=result['filters_applied']
)