| """ |
| domain/interfaces/services/model_service.py |
| ββββββββββββββββββββββββββββββββββββββββββββ |
| ModelService β abstract contract for AI model inference. |
| |
| Implementations include: |
| β’ MockModelService (testing / local dev, no GPU needed) |
| β’ GANVGTLNetService (production: GAN + VGTL-Net on GPU) |
| """ |
| from __future__ import annotations |
|
|
| from abc import ABC, abstractmethod |
|
|
| import numpy as np |
|
|
| from src.domain.entities.prediction import BPPrediction |
|
|
|
|
| class ModelService(ABC): |
| """ |
| AI model inference contract. |
| |
| Lifecycle: |
| await service.load_model() β loads weights into memory |
| prediction = await service.predict(ppg_signal_id, segments) |
| # repeat predict() as needed |
| """ |
|
|
| @abstractmethod |
| async def load_model(self) -> None: |
| """ |
| Load model weights and prepare for inference. |
| |
| This is intentionally async to allow loading from remote storage |
| (e.g. Hugging Face Hub, S3) without blocking the event loop. |
| |
| Should be idempotent β calling load_model() on an already-loaded |
| service must be a safe no-op. |
| """ |
| ... |
|
|
| @abstractmethod |
| async def predict( |
| self, |
| ppg_signal_id: str, |
| segments: np.ndarray, |
| ) -> BPPrediction: |
| """ |
| Run blood pressure inference on preprocessed PPG segments. |
| |
| Args: |
| ppg_signal_id: UUID of the source PPGSignal β stored in the result. |
| segments: 2-D NumPy array of shape ``(n_segments, window_size)`` |
| produced by SignalProcessor.process(). |
| |
| Returns: |
| BPPrediction domain entity containing predicted SBP, DBP, |
| inference timing, and model version. |
| |
| Raises: |
| PredictionOutOfRangeError: If the model output is physiologically |
| impossible (handled by BPPrediction.validate()). |
| RuntimeError: If the model has not been loaded (load_model() not called). |
| """ |
| ... |
|
|
| @abstractmethod |
| def is_loaded(self) -> bool: |
| """Return ``True`` if model weights are loaded and ready for inference.""" |
| ... |
|
|
| @property |
| @abstractmethod |
| def model_version(self) -> str: |
| """Version string identifying this model (stored in BPPrediction).""" |
| ... |
|
|