import os import joblib import pandas as pd from data_loader import DataLoader from feature_engineer import FeatureEngineer from rule_based_model import RuleBasedModel def get_predictions(model_dir='artifacts'): loader = DataLoader() rankings = loader.get_rankings() form = loader.get_team_form() teams = loader.get_teams() matches = loader.get_matches() try: manual_features = loader.get_manual_features() except Exception as e: print(f"WARNING: Could not load manual features: {e}") manual_features = None odds_summary = loader.get_latest_odds_summary() weather_summary = loader.get_latest_weather_summary() loader.close() engineer = FeatureEngineer(rankings, form, teams, manual_features) # Select upcoming matches upcoming = matches[matches['status'].isin(['scheduled', 'active'])].copy() if len(upcoming) == 0: return {"predictions": [], "skipped": []} X_pred, _ = engineer.build_dataset(upcoming) # Load model model_path = os.path.join(model_dir, 'rule_based_baseline.pkl') if not os.path.exists(model_path): raise FileNotFoundError(f"Model not found at {model_path}. Run train.py first.") clf = joblib.load(model_path) # Predict probabilities probs = clf.predict_proba(X_pred) X_pred['prob_away_win'] = probs[:, 0] X_pred['prob_draw'] = probs[:, 1] X_pred['prob_home_win'] = probs[:, 2] # Merge back to upcoming by match_id upcoming = upcoming.merge(X_pred[['match_id', 'prob_away_win', 'prob_draw', 'prob_home_win']], left_on='id', right_on='match_id', how='left') results = [] skipped = [] for _, row in upcoming.iterrows(): if pd.isna(row['prob_home_win']): # Determine reason reason = "unknown" if pd.isna(row['home_team_id']) or pd.isna(row['away_team_id']): reason = "missing_team_placeholder" else: reason = "missing_features" skipped.append({ "match_id": row['id'], "home_team_id": row['home_team_id'] if not pd.isna(row['home_team_id']) else None, "away_team_id": row['away_team_id'] if not pd.isna(row['away_team_id']) else None, "reason": reason }) continue # Check if manual features were applied applied = False if manual_features is not None and row['id'] in manual_features.index: applied = True odds_rows = [] if odds_summary is not None and not odds_summary.empty: match_odds = odds_summary[odds_summary['match_id'] == row['id']] for _, odds in match_odds.iterrows(): odds_rows.append({ "bookmaker_key": odds.get("bookmaker_key"), "bookmaker_title": odds.get("bookmaker_title"), "market_key": odds.get("market_key"), "market_title": odds.get("market_title"), "home_odds": float(odds["home_odds"]) if not pd.isna(odds.get("home_odds")) else None, "draw_odds": float(odds["draw_odds"]) if not pd.isna(odds.get("draw_odds")) else None, "away_odds": float(odds["away_odds"]) if not pd.isna(odds.get("away_odds")) else None, "last_update": str(odds.get("last_update")) if not pd.isna(odds.get("last_update")) else None, }) weather = None if weather_summary is not None and not weather_summary.empty and row['id'] in weather_summary.index: w = weather_summary.loc[row['id']] weather = { "forecast_time": str(w.get("forecast_time")) if not pd.isna(w.get("forecast_time")) else None, "temperature_c": float(w["temperature_c"]) if not pd.isna(w.get("temperature_c")) else None, "apparent_temperature_c": float(w["apparent_temperature_c"]) if not pd.isna(w.get("apparent_temperature_c")) else None, "humidity_pct": float(w["humidity_pct"]) if not pd.isna(w.get("humidity_pct")) else None, "precipitation_probability_pct": float(w["precipitation_probability_pct"]) if not pd.isna(w.get("precipitation_probability_pct")) else None, "precipitation_mm": float(w["precipitation_mm"]) if not pd.isna(w.get("precipitation_mm")) else None, "wind_speed_kmh": float(w["wind_speed_kmh"]) if not pd.isna(w.get("wind_speed_kmh")) else None, "wind_gusts_kmh": float(w["wind_gusts_kmh"]) if not pd.isna(w.get("wind_gusts_kmh")) else None, "weather_code": int(w["weather_code"]) if not pd.isna(w.get("weather_code")) else None, } results.append({ "match_id": row['id'], "home_team_id": row['home_team_id'], "away_team_id": row['away_team_id'], "prob_home_win": float(row['prob_home_win']), "prob_draw": float(row['prob_draw']), "prob_away_win": float(row['prob_away_win']), "manual_features_applied": applied, "odds": odds_rows, "weather": weather }) return { "predictions": results, "skipped": skipped } def run_predictions(): data = get_predictions() print("\nUpcoming Match Predictions:") for p in data['predictions']: print(f"Match {p['match_id']} | {p['home_team_id']} vs {p['away_team_id']} " f"| 1: {p['prob_home_win']:.2f} X: {p['prob_draw']:.2f} 2: {p['prob_away_win']:.2f}") if __name__ == "__main__": run_predictions()