LIBRE / src /application /dto /prediction_dto.py
RyZ
feat: adding predicted ecg
75b7786
Raw
History Blame Contribute Delete
3.39 kB
"""
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.")