Spaces:
Running
Running
Upload 2 files
Browse files- app/models/ecg.py +29 -0
- app/models/schemas.py +35 -0
app/models/ecg.py
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from datetime import datetime
|
| 2 |
+
|
| 3 |
+
from sqlalchemy import Column, DateTime, Float, Integer, String, func
|
| 4 |
+
from sqlalchemy.orm import declarative_base
|
| 5 |
+
|
| 6 |
+
from sqlalchemy import JSON as JSONType # type: ignore
|
| 7 |
+
|
| 8 |
+
Base = declarative_base()
|
| 9 |
+
|
| 10 |
+
|
| 11 |
+
class ECGSample(Base):
|
| 12 |
+
"""
|
| 13 |
+
Database model for storing ECG signals and associated metadata.
|
| 14 |
+
"""
|
| 15 |
+
|
| 16 |
+
__tablename__ = "ecg_samples"
|
| 17 |
+
|
| 18 |
+
id = Column(Integer, primary_key=True, index=True)
|
| 19 |
+
patient_id = Column(String, index=True, nullable=False)
|
| 20 |
+
created_at = Column(DateTime(timezone=True), server_default=func.now(), nullable=False)
|
| 21 |
+
signal = Column(JSONType, nullable=False)
|
| 22 |
+
label = Column(String, nullable=True)
|
| 23 |
+
score = Column(Float, nullable=True)
|
| 24 |
+
alert_level = Column(String, nullable=True)
|
| 25 |
+
hr = Column(Integer, nullable=True)
|
| 26 |
+
|
| 27 |
+
# Additional metadata fields
|
| 28 |
+
device_id = Column(String, nullable=True)
|
| 29 |
+
sampling_rate = Column(Float, nullable=True)
|
app/models/schemas.py
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from datetime import datetime
|
| 2 |
+
from typing import List, Optional
|
| 3 |
+
|
| 4 |
+
try:
|
| 5 |
+
from pydantic import BaseModel, Field, ConfigDict
|
| 6 |
+
_CONFIG_DICT_SUPPORTED = True
|
| 7 |
+
except ImportError: # pragma: no cover - Pydantic v1 fallback
|
| 8 |
+
from pydantic import BaseModel, Field # type: ignore
|
| 9 |
+
_CONFIG_DICT_SUPPORTED = False
|
| 10 |
+
|
| 11 |
+
|
| 12 |
+
class ECGInferenceRequest(BaseModel):
|
| 13 |
+
patient_id: str = Field(..., example="patient-123")
|
| 14 |
+
signal: List[float] = Field(..., min_items=1, example=[0.1, 0.2, 0.3])
|
| 15 |
+
device_id: Optional[str] = Field(None, example="device-abc")
|
| 16 |
+
sampling_rate: Optional[float] = Field(None, gt=0, example=250.0)
|
| 17 |
+
age: Optional[int] = Field(None, ge=0, example=70)
|
| 18 |
+
has_prior_stroke: Optional[bool] = Field(None, example=False)
|
| 19 |
+
|
| 20 |
+
|
| 21 |
+
class ECGInferenceResponse(BaseModel):
|
| 22 |
+
patient_id: str
|
| 23 |
+
label: str
|
| 24 |
+
score: float
|
| 25 |
+
alert_level: str
|
| 26 |
+
hr: Optional[int] = None
|
| 27 |
+
sample_id: int
|
| 28 |
+
created_at: datetime
|
| 29 |
+
explanations: List[str] = Field(default_factory=list)
|
| 30 |
+
|
| 31 |
+
if _CONFIG_DICT_SUPPORTED: # type: ignore
|
| 32 |
+
model_config = ConfigDict(from_attributes=True) # type: ignore
|
| 33 |
+
else:
|
| 34 |
+
class Config:
|
| 35 |
+
orm_mode = True
|