"""Prediction model adapters used through a small dependency-injection boundary.""" from __future__ import annotations from dataclasses import dataclass from typing import Protocol import pandas as pd from final_pipeline import ( DiagnosticModels, predict_test, train_models, validate_submission, ) from .errors import InferenceError @dataclass(frozen=True) class PredictionBundle: submission: pd.DataFrame diagnostics: pd.DataFrame class PredictionModel(Protocol): def predict(self, frame: pd.DataFrame) -> PredictionBundle: ... class SklearnPredictionModel: """Thin adapter around the frozen, validated competition pipeline.""" def __init__(self, models: DiagnosticModels) -> None: self._models = models @classmethod def train( cls, reference_frame: pd.DataFrame, *, random_state: int = 42, n_jobs: int = -1, ) -> "SklearnPredictionModel": try: models = train_models( reference_frame, random_state=random_state, n_jobs=n_jobs, ) except Exception as exc: raise InferenceError( "Nie udało się przygotować modelu referencyjnego.", hint="Sprawdź kompletność val.csv oraz zgodność wersji zależności.", ) from exc return cls(models) def predict(self, frame: pd.DataFrame) -> PredictionBundle: try: submission, diagnostics = predict_test(self._models, frame) validate_submission(submission, frame) except Exception as exc: raise InferenceError( "Model odrzucił pomiary podczas predykcji.", hint="Zweryfikuj kompletność silników oraz brak nietypowych wartości w widmie.", ) from exc return PredictionBundle(submission, diagnostics) class PrecomputedPredictionModel: """Read-only demo fallback; accepts only the exact precomputed key set.""" def __init__(self, submission: pd.DataFrame, diagnostics: pd.DataFrame) -> None: self._submission = submission.reset_index(drop=True).copy() self._diagnostics = diagnostics.reset_index(drop=True).copy() def predict(self, frame: pd.DataFrame) -> PredictionBundle: keys = ["engine_id", "cylinder"] if not frame[keys].reset_index(drop=True).equals(self._submission[keys]): raise InferenceError( "Tryb awaryjny obsługuje wyłącznie dołączony zestaw demonstracyjny.", hint="Przywróć val.csv i uruchom ponownie aplikację, aby diagnozować własne pliki.", ) return PredictionBundle( self._submission.copy(), self._diagnostics.copy(), )