Import Vector lab project
This commit is contained in:
@@ -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']
|
||||
)
|
||||
Reference in New Issue
Block a user