""" Prediction model wrapper — loads Random Forest trained in the lab """ import os import joblib import pandas as pd from pathlib import Path MODELS_DIR = Path(os.path.dirname(os.path.dirname(__file__))) / "models" class MatchPredictor: def __init__(self): self.model = None self.team_stats = None self.feature_cols = None self._loaded = False def load(self): if self._loaded: return True try: model_path = MODELS_DIR / "match_predictor.pkl" data_path = MODELS_DIR / "team_data.pkl" if not model_path.exists() or not data_path.exists(): raise FileNotFoundError(f"Model files not found in {MODELS_DIR}") self.model = joblib.load(model_path) data = joblib.load(data_path) self.team_stats = data["team_stats"] self.feature_cols = data["feature_cols"] self._loaded = True return True except Exception as e: print(f"Model load error: {e}") return False def predict(self, team_a: str, team_b: str, is_neutral: bool = True, is_major_tournament: bool = True) -> dict: if not self._loaded: raise RuntimeError("Model not loaded") if team_a not in self.team_stats: raise ValueError(f"Unknown team: {team_a}") if team_b not in self.team_stats: raise ValueError(f"Unknown team: {team_b}") if team_a == team_b: raise ValueError("Teams must be different") a = self.team_stats[team_a] b = self.team_stats[team_b] row = pd.DataFrame([{ "team_a_winrate": a["winrate"], "team_b_winrate": b["winrate"], "team_a_goal_avg": a["goal_avg"], "team_b_goal_avg": b["goal_avg"], "team_a_recent_form": a["recent_form"], "team_b_recent_form": b["recent_form"], "is_neutral": int(is_neutral), "is_major_tournament": int(is_major_tournament), }])[self.feature_cols] proba = self.model.predict_proba(row)[0] return { "team_a": team_a, "team_b": team_b, "team_a_win_prob": round(float(proba[0]), 4), "draw_prob": round(float(proba[1]), 4), "team_b_win_prob": round(float(proba[2]), 4), "is_neutral": is_neutral, "is_major_tournament": is_major_tournament, "stats_a": { "winrate": round(a["winrate"], 4), "goal_avg": round(a["goal_avg"], 4), "recent_form": round(a["recent_form"], 4), "matches_played": a["matches_played"], }, "stats_b": { "winrate": round(b["winrate"], 4), "goal_avg": round(b["goal_avg"], 4), "recent_form": round(b["recent_form"], 4), "matches_played": b["matches_played"], }, } def get_team_names(self) -> list: if not self._loaded: return [] return sorted(self.team_stats.keys()) def get_feature_importances(self) -> list: if not self._loaded: return [] names = self.feature_cols imps = self.model.feature_importances_ return [{"name": n, "importance": round(float(i), 4)} for n, i in sorted(zip(names, imps), key=lambda x: -x[1])] # Singleton predictor = MatchPredictor()