| """ |
| application/dto/prediction_dto.py |
| βββββββββββββββββββββββββββββββββββ |
| Pydantic DTO for BP prediction responses. |
| """ |
| from __future__ import annotations |
|
|
| from datetime import datetime |
| from typing import Optional |
|
|
| from pydantic import BaseModel, Field |
|
|
|
|
| class PredictionResponse(BaseModel): |
| """ |
| Outgoing payload returned to the frontend for a blood pressure prediction. |
| |
| Derived from the BPPrediction domain entity, but formatted for API consumers. |
| """ |
|
|
| id: str = Field(description="UUID of the prediction record.") |
| ppg_signal_id: str = Field(description="UUID of the source PPG signal.") |
| predicted_sbp: float = Field(description="Predicted Systolic Blood Pressure (mmHg).") |
| predicted_dbp: float = Field(description="Predicted Diastolic Blood Pressure (mmHg).") |
| predicted_ecg: Optional[list] = Field( |
| default=None, |
| description=( |
| "Synthetic ECG signal windows produced by CardioGAN. " |
| "Format: list of segments, each segment is a list of float samples (224 samples @ 125 Hz)." |
| ), |
| ) |
| mean_arterial_pressure: float = Field(description="Computed MAP: DBP + (SBP-DBP)/3 (mmHg).") |
| pulse_pressure: float = Field(description="SBP - DBP (mmHg).") |
| hypertension_stage: str = Field( |
| description="Classification: Normal | Elevated | Stage 1 | Stage 2 | Crisis" |
| ) |
| model_version: str = Field(description="Model version that produced this prediction.") |
| inference_time_ms: float = Field(description="Wall-clock inference duration (ms).") |
| sa_log: Optional[dict] = Field( |
| default=None, |
| description="Logs of the Simulated Annealing optimization process.", |
| ) |
| created_at: datetime = Field(description="UTC timestamp of when the prediction was made.") |
|
|
| model_config = { |
| "json_schema_extra": { |
| "example": { |
| "id": "7ba85f64-5717-4562-b3fc-2c963f66afa9", |
| "ppg_signal_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", |
| "predicted_sbp": 118.5, |
| "predicted_dbp": 76.2, |
| "predicted_ecg": [[0.12, -0.05, 0.33], [0.09, -0.11, 0.28]], |
| "mean_arterial_pressure": 90.3, |
| "pulse_pressure": 42.3, |
| "hypertension_stage": "Normal", |
| "model_version": "gan-vgtlnet-v1.0", |
| "inference_time_ms": 142.7, |
| "created_at": "2026-05-30T12:00:00Z", |
| } |
| } |
| } |
|
|
|
|
| class PredictionHistoryResponse(BaseModel): |
| """Paginated list of predictions for a user.""" |
|
|
| user_id: str |
| total: int |
| predictions: list[PredictionResponse] |
|
|
| @classmethod |
| def from_predictions( |
| cls, |
| user_id: str, |
| predictions: list[PredictionResponse], |
| ) -> "PredictionHistoryResponse": |
| return cls(user_id=user_id, total=len(predictions), predictions=predictions) |
|
|
|
|
| class DateRangeRequest(BaseModel): |
| """Optional query parameters for date-range filtering.""" |
|
|
| start: Optional[datetime] = Field(default=None, description="Start of range (UTC).") |
| end: Optional[datetime] = Field(default=None, description="End of range (UTC).") |
| limit: int = Field(default=50, ge=1, le=500, description="Max records to return.") |
| offset: int = Field(default=0, ge=0, description="Records to skip.") |
|
|