Files
vector/backend/schemas.py
T
2026-06-06 18:31:55 +00:00

259 lines
8.5 KiB
Python
Raw 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.
from pydantic import BaseModel, Field, ConfigDict
from typing import Optional, List, Dict, Any
from datetime import datetime
from uuid import UUID
class CaseCreate(BaseModel):
"""Schema for creating a new case"""
# Ребёнок (Шаг 1)
child_name: Optional[str] = None
age_years: int = Field(..., ge=0, le=18)
gender: Optional[str] = Field(None, pattern="^[МЖ]$")
height_build: Optional[str] = None
clothes_upper: Optional[str] = None
clothes_lower: Optional[str] = None
shoes: Optional[str] = None
clothes_description: Optional[str] = None
special_marks: Optional[str] = None
phone_status: Optional[str] = Field(None, pattern="^(answers|silent|none)$")
# Здоровье (Шаг 2)
has_diagnosis: bool = False
diagnosis_type: Optional[List[str]] = None
fitness_level: Optional[str] = Field(None, pattern="^(low|medium|high)$")
has_transport: str = Field(default="none", pattern="^(none|bike|scooter|other)$")
cant_swim: bool = False
# Психотип (Шаг 2б)
psychotype: Optional[str] = None
psychotype_answers: Optional[Dict[str, Any]] = None
# Обстоятельства (Шаг 3)
loss_reason: Optional[str] = None
loss_time: Optional[datetime] = None
elapsed_hours: Optional[float] = Field(None, ge=0)
last_seen_direction: Optional[str] = None
last_seen_reliability: Optional[str] = Field(None, pattern="^(exact|approx|unknown)$")
last_seen_description: Optional[str] = None
behavior_description: Optional[str] = None
familiar_places: Optional[str] = None
lost_before: Optional[str] = Field(None, pattern="^(yes|no|unknown)$")
# Среда (Шаг 4)
season: Optional[str] = None
temperature_c: Optional[float] = None
precipitation: Optional[str] = None
visibility: Optional[str] = None
wind: Optional[str] = None
terrain: Optional[List[str]] = None
# GPS (Шаг 4)
tnp_lat: Optional[float] = Field(None, ge=-90, le=90)
tnp_lon: Optional[float] = Field(None, ge=-180, le=180)
tnp_address: Optional[str] = None
# Ресурсы (Шаг 5)
teams_count: Optional[int] = Field(None, ge=0)
team_size: Optional[int] = Field(None, ge=0)
has_dog: bool = False
extra_resources: Optional[List[str]] = None
model_config = ConfigDict(json_schema_extra={
"example": {
"child_name": "Иван",
"age_years": 8,
"gender": "М",
"loss_reason": "потерялся в лесу",
"season": "лето",
"temperature_c": 22.0,
"tnp_lat": 53.9,
"tnp_lon": 27.56,
"teams_count": 3,
"team_size": 5
}
})
class CaseOut(BaseModel):
"""Schema for case output"""
id: UUID
created_at: datetime
status: str
# Ребёнок
child_name: Optional[str] = None
age_years: int
gender: Optional[str] = None
height_build: Optional[str] = None
clothes_upper: Optional[str] = None
clothes_lower: Optional[str] = None
shoes: Optional[str] = None
clothes_description: Optional[str] = None
special_marks: Optional[str] = None
phone_status: Optional[str] = None
# Здоровье
has_diagnosis: bool
diagnosis_type: Optional[List[str]] = None
fitness_level: Optional[str] = None
has_transport: str
cant_swim: bool
# Психотип
psychotype: Optional[str] = None
psychotype_answers: Optional[Dict[str, Any]] = None
# Обстоятельства
loss_reason: Optional[str] = None
loss_time: Optional[datetime] = None
elapsed_hours: Optional[float] = None
last_seen_direction: Optional[str] = None
last_seen_reliability: Optional[str] = None
last_seen_description: Optional[str] = None
behavior_description: Optional[str] = None
familiar_places: Optional[str] = None
lost_before: Optional[str] = None
# Среда
season: Optional[str] = None
temperature_c: Optional[float] = None
precipitation: Optional[str] = None
visibility: Optional[str] = None
wind: Optional[str] = None
terrain: Optional[List[str]] = None
# GPS
tnp_lat: Optional[float] = None
tnp_lon: Optional[float] = None
tnp_address: Optional[str] = None
# Ресурсы
teams_count: Optional[int] = None
team_size: Optional[int] = None
has_dog: bool
extra_resources: Optional[List[str]] = None
# Исход
found_alive: Optional[bool] = None
found_distance_km: Optional[float] = None
found_direction: Optional[str] = None
found_location_type: Optional[str] = None
found_lat: Optional[float] = None
found_lon: Optional[float] = None
search_duration_hours: Optional[float] = None
who_found: Optional[str] = None
# Мета
confidence_avg: Optional[float] = None
raw_text: Optional[str] = None
analysis_log: Optional[Dict[str, Any]] = None
model_config = ConfigDict(from_attributes=True)
class SearchZone(BaseModel):
"""Search zone with priority and details"""
priority: int = Field(..., ge=1, le=3)
name: str
direction: str
distance_km: float
score: float
reasoning: str
coordinates: Optional[List[List[float]]] = None
class BehavioralProfile(BaseModel):
"""Active behavioral profile"""
type: str
title: str
recommendations: List[str]
modifiers: Dict[str, float]
class AnalysisResult(BaseModel):
"""Complete analysis result"""
case_id: UUID
urgency_level: str = Field(..., pattern="^(КРИТИЧЕСКИЙ|ВЫСОКИЙ|УМЕРЕННЫЙ)$")
urgency_reason: str
time_window_hours: Optional[float] = None
active_profiles: List[BehavioralProfile]
immediate_actions: List[str] = Field(..., min_length=3, max_length=3)
search_zones: List[SearchZone] = Field(..., min_length=1, max_length=3)
key_objects: List[str]
team_assignments: Optional[Dict[str, str]] = None
behavioral_forecast: str
dog_recommendations: Optional[List[str]] = None
max_distance_km: float
confidence_score: float = Field(..., ge=0, le=1)
created_at: datetime
execution_time: Optional[float] = None
model_config = ConfigDict(json_schema_extra={
"example": {
"case_id": "123e4567-e89b-12d3-a456-426614174000",
"urgency_level": "ВЫСОКИЙ",
"urgency_reason": "Ребёнок 8 лет, прошло 4 часа, температура +15°C",
"time_window_hours": 12.0,
"active_profiles": [
{
"type": "age_8_12",
"title": "Возраст 8-12 лет",
"recommendations": ["Радиус поиска до 3 км", "Проверить дороги и тропы"],
"modifiers": {"distance": 1.0, "roads": 1.2}
}
],
"immediate_actions": [
"Перекрыть все дороги в радиусе 2 км",
"Проверить водоёмы в радиусе 1 км",
"Организовать оклик по имени"
],
"search_zones": [
{
"priority": 1,
"name": "Лесной массив северо-восток",
"direction": "СВ",
"distance_km": 1.2,
"score": 0.85,
"reasoning": "Последнее направление движения, густой лес"
}
],
"key_objects": ["Озеро Круглое (800м СВ)", "Лесная дорога (500м С)"],
"behavioral_forecast": "Ребёнок скорее всего движется вдоль дороги или тропы",
"max_distance_km": 3.5,
"confidence_score": 0.82,
"created_at": "2026-05-04T13:45:00Z"
}
})
class UserCreate(BaseModel):
"""Schema for creating a new user"""
username: str = Field(..., min_length=3, max_length=100)
email: str = Field(..., pattern=r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$")
password: str = Field(..., min_length=8)
full_name: Optional[str] = None
role: str = Field(default="operator", pattern="^(operator|field|admin)$")
class UserOut(BaseModel):
"""Schema for user output"""
id: UUID
username: str
email: str
full_name: Optional[str] = None
role: str
is_active: bool
created_at: datetime
last_login: Optional[datetime] = None
model_config = ConfigDict(from_attributes=True)