emp-admin's picture
Upload 9 files
56f192b verified
"""
Pydantic models β€” exact mirrors of Phoebe iOS Swift DTOs.
Field names = snake_case matching CodingKeys from:
- APIModels.swift (HeadacheLogSnapshotDTO, DailySnapshotDTO)
- InsightPayloadDTO.swift (HealthKitMetricsDTO, WeatherDataDTO, UserContextDTO)
"""
from __future__ import annotations
from pydantic import BaseModel, Field
from typing import List, Optional
from enum import Enum
# ── Enums ────────────────────────────────────────────────────────────
class MedicationResponseEnum(str, Enum):
horrible = "horrible"
worse = "worse"
same = "same"
better = "better"
excellent = "excellent"
# ── Diary sub-payloads ───────────────────────────────────────────────
class SymptomsPayload(BaseModel):
symptoms: List[str] = []
class TriggersPayload(BaseModel):
triggers: List[str] = []
class MedicationPayload(BaseModel):
medication_taken: List[str] = []
class TherapeuticPayload(BaseModel):
therapeutic_activities: List[str] = []
# ── HealthKit (from InsightPayloadDTO.swift) ─────────────────────────
class SleepAnalysisDTO(BaseModel):
total_duration_hours: Optional[float] = None
deep_sleep_minutes: Optional[float] = None
rem_sleep_minutes: Optional[float] = None
class HRVSummaryDTO(BaseModel):
average_ms: Optional[float] = None
class HealthKitMetricsDTO(BaseModel):
resting_heart_rate: Optional[float] = None
sleep_analysis: Optional[SleepAnalysisDTO] = None
hrv_summary: Optional[HRVSummaryDTO] = None
workout_minutes: Optional[int] = None
had_menstrual_flow: Optional[bool] = None
# ── Weather (from InsightPayloadDTO.swift) ───────────────────────────
class WeatherDataDTO(BaseModel):
barometric_pressure_mb: float = 1013.25
pressure_change_24h_mb: float = 0.0
humidity_percent: float = 50.0
temperature_celsius: float = 15.0
# ── Headache log (from APIModels.swift) ──────────────────────────────
class HeadacheLogSnapshotDTO(BaseModel):
severity: int = 0
duration_hours: float = 0.0
symptoms: SymptomsPayload = Field(default_factory=SymptomsPayload)
triggers: TriggersPayload = Field(default_factory=TriggersPayload)
notes: Optional[str] = None
input_date: str = ""
input_time: Optional[str] = None
end_date: Optional[str] = None
end_time: Optional[str] = None
pain_frontal: bool = False
pain_temporal_left: bool = False
pain_temporal_right: bool = False
pain_occipital: bool = False
pain_parietal: bool = False
pain_ocular_left: bool = False
pain_ocular_right: bool = False
pain_sinus: bool = False
mood: Optional[str] = None
medication_taken: Optional[MedicationPayload] = None
medication_response: Optional[MedicationResponseEnum] = None
therapeutic_activities: Optional[TherapeuticPayload] = None
# ── DailySnapshotDTO (top-level) ────────────────────────────────────
class DailySnapshotDTO(BaseModel):
headache_log: Optional[HeadacheLogSnapshotDTO] = None
health_kit_metrics: Optional[HealthKitMetricsDTO] = None
weather_data: Optional[WeatherDataDTO] = None
# ── UserContextDTO ──────────────────────────────────────────────────
class UserContextDTO(BaseModel):
age_range: Optional[str] = None
location_region: Optional[str] = None
# ── API request / response ──────────────────────────────────────────
class PredictionRequest(BaseModel):
user_context: Optional[UserContextDTO] = None
daily_snapshots: List[DailySnapshotDTO]
class DayPrediction(BaseModel):
day: int
date: Optional[str] = None
prediction: int
probability: float
risk_level: str
top_risk_factors: List[str] = []
class PredictionResponse(BaseModel):
predictions: List[DayPrediction]
model_version: str
threshold: float
# Legacy
class SinglePredictionRequest(BaseModel):
features: List[float]
class SinglePredictionResponse(BaseModel):
prediction: int
probability: float