import gradio as gr import requests def map_teams_roof_surface(df): # --- Fixed team mapping (stable across all datasets) --- team_map = { "ARI": 1, "ATL": 2, "BAL": 3, "BUF": 4, "CAR": 5, "CHI": 6, "CIN": 7, "CLE": 8, "DAL": 9, "DEN": 10, "DET": 11, "GB": 12, "HOU": 13, "IND": 14, "JAX": 15, "KC": 16, "LV": 17, "LAC": 18, "LAR": 19, "MIA": 20, "MIN": 21, "NE": 22, "NO": 23, "NYG": 24, "NYJ": 25, "PHI": 26, "PIT": 27, "SEA": 28, "SF": 29, "TB": 30, "TEN": 31, "WAS": 32 } # --- Aliases for older team abbreviations --- alias_map = { "OAK": "LV", "SD": "LAC", "STL": "LAR", "WSH": "WAS" } # --- Surface mapping --- surface_map = { "a_turf": 1, "grass": 2, "sportturf": 3, "fieldturf": 4, "matrixturf": 5, "astroturf": 6, "0": 0 # unknown/missing } import json import ast # Load player mappings with fallback for single-quoted JSON try: with open("receiver_to_player_id.json", 'r') as f: content = f.read() try: # Try normal JSON first receiver_to_player_id = json.loads(content) except json.JSONDecodeError: # Fallback: treat as Python dict literal receiver_to_player_id = ast.literal_eval(content) with open("passer_to_player_id.json", 'r') as f: content = f.read() try: passer_to_player_id = json.loads(content) except json.JSONDecodeError: passer_to_player_id = ast.literal_eval(content) print(f"✓ Loaded {len(receiver_to_player_id)} receivers and {len(passer_to_player_id)} passers") except Exception as e: print(f"Error loading player mappings: {e}") receiver_to_player_id = {} passer_to_player_id = {} receiver_choices = sorted(list(receiver_to_player_id.keys())) passer_choices = sorted(list(receiver_to_player_id.keys())) import requests from datetime import datetime, timedelta # Stadium coordinates STADIUM_COORDS = { "ARI": {"lat": 33.5276, "lon": -112.2626, "name": "State Farm Stadium"}, "ATL": {"lat": 33.7554, "lon": -84.4008, "name": "Mercedes-Benz Stadium"}, "BAL": {"lat": 39.2780, "lon": -76.6227, "name": "M&T Bank Stadium"}, "BUF": {"lat": 42.7738, "lon": -78.7870, "name": "Highmark Stadium"}, "CAR": {"lat": 35.2258, "lon": -80.8528, "name": "Bank of America Stadium"}, "CHI": {"lat": 41.8623, "lon": -87.6167, "name": "Soldier Field"}, "CIN": {"lat": 39.0954, "lon": -84.5160, "name": "Paycor Stadium"}, "CLE": {"lat": 41.5061, "lon": -81.6995, "name": "FirstEnergy Stadium"}, "DAL": {"lat": 32.7473, "lon": -97.0945, "name": "AT&T Stadium"}, "DEN": {"lat": 39.7439, "lon": -105.0201, "name": "Empower Field at Mile High"}, "DET": {"lat": 42.3400, "lon": -83.0456, "name": "Ford Field"}, "GB": {"lat": 44.5013, "lon": -88.0622, "name": "Lambeau Field"}, "HOU": {"lat": 29.6847, "lon": -95.4107, "name": "NRG Stadium"}, "IND": {"lat": 39.7601, "lon": -86.1639, "name": "Lucas Oil Stadium"}, "JAX": {"lat": 30.3239, "lon": -81.6373, "name": "EverBank Stadium"}, "KC": {"lat": 39.0489, "lon": -94.4839, "name": "Arrowhead Stadium"}, "LV": {"lat": 36.0908, "lon": -115.1833, "name": "Allegiant Stadium"}, "LAC": {"lat": 33.9535, "lon": -118.3390, "name": "SoFi Stadium"}, "LAR": {"lat": 33.9535, "lon": -118.3390, "name": "SoFi Stadium"}, "MIA": {"lat": 25.9580, "lon": -80.2389, "name": "Hard Rock Stadium"}, "MIN": {"lat": 44.9738, "lon": -93.2577, "name": "U.S. Bank Stadium"}, "NE": {"lat": 42.0909, "lon": -71.2643, "name": "Gillette Stadium"}, "NO": {"lat": 29.9511, "lon": -90.0812, "name": "Caesars Superdome"}, "NYG": {"lat": 40.8128, "lon": -74.0742, "name": "MetLife Stadium"}, "NYJ": {"lat": 40.8128, "lon": -74.0742, "name": "MetLife Stadium"}, "PHI": {"lat": 39.9008, "lon": -75.1675, "name": "Lincoln Financial Field"}, "PIT": {"lat": 40.4468, "lon": -80.0158, "name": "Acrisure Stadium"}, "SF": {"lat": 37.4032, "lon": -121.9698, "name": "Levi's Stadium"}, "SEA": {"lat": 47.5952, "lon": -122.3316, "name": "Lumen Field"}, "TB": {"lat": 27.9759, "lon": -82.5033, "name": "Raymond James Stadium"}, "TEN": {"lat": 36.1665, "lon": -86.7713, "name": "Nissan Stadium"}, "WAS": {"lat": 38.9076, "lon": -76.8645, "name": "FedEx Field"} } def get_weather_forecast(home_team, game_datetime): """ Get weather forecast for a stadium at game time. Uses Open-Meteo API (free, no API key needed) """ coords = STADIUM_COORDS.get(home_team) if not coords: return None # Open-Meteo API (free, no key required) url = "https://api.open-meteo.com/v1/forecast" params = { "latitude": coords["lat"], "longitude": coords["lon"], "hourly": "temperature_2m,relative_humidity_2m,wind_speed_10m,weather_code", "temperature_unit": "fahrenheit", "wind_speed_unit": "mph", "timezone": "America/New_York" } try: response = requests.get(url, params=params, timeout=10) response.raise_for_status() data = response.json() # Find the closest time to game time hourly = data.get("hourly", {}) times = hourly.get("time", []) # Find index closest to game time game_time_str = game_datetime.strftime("%Y-%m-%dT%H:%M") closest_idx = 0 for i, time_str in enumerate(times): if time_str >= game_time_str: closest_idx = i break temp = hourly["temperature_2m"][closest_idx] humidity = hourly["relative_humidity_2m"][closest_idx] wind = hourly["wind_speed_10m"][closest_idx] weather_code = hourly["weather_code"][closest_idx] # Interpret weather codes # https://open-meteo.com/en/docs is_rain = weather_code in [51, 53, 55, 61, 63, 65, 80, 81, 82] is_snow = weather_code in [71, 73, 75, 77, 85, 86] is_clear = weather_code in [0, 1, 2] return { "temp_f": temp, "humidity_pct": humidity, "wind_mph": wind, "is_rain": int(is_rain), "is_snow": int(is_snow), "is_clear": int(is_clear), "weather_code": weather_code } except Exception as e: print(f"Weather API error: {e}") return None # Example usage: game_time = datetime(2025, 10, 13, 13, 0) # Sunday 1pm ET weather = get_weather_forecast("ARI", game_time) print(weather) import requests from datetime import datetime def get_game_info_espn(home_team, away_team, week): """ Get game time, spread, and total from ESPN API. Free, no API key required. Args: home_team: Home team abbreviation away_team: Away team abbreviation week: NFL week number Returns: dict with game_datetime, pregame_spread, pregame_total """ result = { "game_datetime": None, "pregame_spread": 0, "pregame_total": 0 } try: url = f"https://site.api.espn.com/apis/site/v2/sports/football/nfl/scoreboard?seasontype=2&week={week}" response = requests.get(url, timeout=10) response.raise_for_status() data = response.json() for event in data.get('events', []): competition = event.get('competitions', [{}])[0] competitors = competition.get('competitors', []) if len(competitors) < 2: continue # ESPN puts home team first h_team = competitors[0]['team']['abbreviation'] a_team = competitors[1]['team']['abbreviation'] if h_team == home_team and a_team == away_team: # Get game time game_date_str = event.get('date') if game_date_str: result["game_datetime"] = datetime.fromisoformat(game_date_str.replace('Z', '+00:00')) # Get odds from competition odds_data = competition.get('odds', []) if odds_data and len(odds_data) > 0: spread = odds_data[0].get('spread') total = odds_data[0].get('overUnder') # ESPN's spread is from home team perspective result["pregame_spread"] = float(spread) if spread is not None else 0 result["pregame_total"] = float(total) if total is not None else 0 print(f"✓ Found game info from ESPN") print(f" {a_team} @ {h_team}") print(f" Game time: {result['game_datetime']}") print(f" Spread: {result['pregame_spread']}, Total: {result['pregame_total']}") return result print(f"⚠ Game not found: {away_team} @ {home_team} (Week {week})") except Exception as e: print(f"⚠ ESPN API error: {e}") return result def get_all_game_data(home_team, away_team, week): """ Get complete game data: time, odds, and weather forecast. Uses ESPN for odds/time and weather API for forecast. Completely free, no API keys needed. Args: home_team: Home team abbreviation away_team: Away team abbreviation week: NFL week number Returns: Complete game data dictionary """ # Get game time and odds from ESPN game_info = get_game_info_espn(home_team, away_team, week) # Get weather forecast if we have game time weather = None if game_info["game_datetime"]: weather = get_weather_forecast(home_team, game_info["game_datetime"]) # Check if dome dome_teams = ["ARI", "ATL", "DAL", "DET", "HOU", "IND", "LV", "LAR", "LAC", "MIN", "NO"] is_dome = home_team in dome_teams # Combine all data if weather: game_data = { "game_datetime": game_info["game_datetime"], "pregame_spread": game_info["pregame_spread"], "pregame_total": game_info["pregame_total"], "temp_f": weather["temp_f"], "humidity_pct": weather["humidity_pct"], "wind_mph": weather["wind_mph"], "is_dome": int(is_dome), "is_rain": weather["is_rain"] if not is_dome else 0, "is_snow": weather["is_snow"] if not is_dome else 0, "is_clear": weather["is_clear"] if not is_dome else 0 } else: # Defaults if no weather available game_data = { "game_datetime": game_info["game_datetime"], "pregame_spread": game_info["pregame_spread"], "pregame_total": game_info["pregame_total"], "temp_f": 72 if is_dome else 70, "humidity_pct": 50, "wind_mph": 0 if is_dome else 5, "is_dome": int(is_dome), "is_rain": 0, "is_snow": 0, "is_clear": 0 if is_dome else 1 } print(f"\n✓ Complete game data assembled") return game_data # Example usage - no API key needed! game_data = get_all_game_data( home_team="JAX", away_team="KC", week=5 ) print("\nFinal game data:") for key, value in game_data.items(): print(f" {key}: {value}") NFL_TEAMS = [ "ARI", "ATL", "BAL", "BUF", "CAR", "CHI", "CIN", "CLE", "DAL", "DEN", "DET", "GB", "HOU", "IND", "JAX", "KC", "LV", "LAC", "LAR", "MIA", "MIN", "NE", "NO", "NYG", "NYJ", "PHI", "PIT", "SEA", "SF", "TB", "TEN", "WAS" ] def create_model_input(home_team, away_team, receiver_on_home_team, receiver_name, passer_name, week, season): """ Create model input from user selections. """ try: # Determine which team the receiver is on receiver_team = home_team if receiver_on_home_team else away_team opponent_team = away_team if receiver_on_home_team else home_team # Normalize player names def normalize_name(name): parts = name.strip().split() if len(parts) == 0: return "" if len(parts) > 1: first_initial = parts[0][0].upper() + "." last_name = parts[-1] return f"{first_initial}{last_name}" return parts[0].title() wr_key = normalize_name(receiver_name) qb_key = normalize_name(passer_name) # Get player IDs receiver_id = receiver_to_player_id.get(wr_key) passer_id = passer_to_player_id.get(qb_key) if receiver_id is None: return f"Error: Could not find receiver '{wr_key}' in database" if passer_id is None: return f"Error: Could not find passer '{qb_key}' in database" # Get game data (weather, odds, time) game_data = get_all_game_data(home_team, away_team, week) if not game_data.get("game_datetime"): return f"Warning: Game not found for Week {week}. Using default values." # Team mappings team_map = { "ARI": 1, "ATL": 2, "BAL": 3, "BUF": 4, "CAR": 5, "CHI": 6, "CIN": 7, "CLE": 8, "DAL": 9, "DEN": 10, "DET": 11, "GB": 12, "HOU": 13, "IND": 14, "JAX": 15, "KC": 16, "LV": 17, "LAC": 18, "LAR": 19, "MIA": 20, "MIN": 21, "NE": 22, "NO": 23, "NYG": 24, "NYJ": 25, "PHI": 26, "PIT": 27, "SEA": 28, "SF": 29, "TB": 30, "TEN": 31, "WAS": 32 } # Surface mapping home_team_surface_map = { "ARI": "grass", "ATL": "fieldturf", "BAL": "grass", "BUF": "fieldturf", "CAR": "fieldturf", "CHI": "grass", "CIN": "fieldturf", "CLE": "grass", "DAL": "fieldturf", "DEN": "grass", "DET": "fieldturf", "GB": "grass", "HOU": "fieldturf", "IND": "fieldturf", "JAX": "grass", "KC": "grass", "LV": "grass", "LAC": "fieldturf", "LAR": "fieldturf", "MIA": "grass", "MIN": "fieldturf", "NE": "fieldturf", "NO": "fieldturf", "NYG": "fieldturf", "NYJ": "fieldturf", "PHI": "grass", "PIT": "grass", "SF": "grass", "SEA": "fieldturf", "TB": "grass", "TEN": "fieldturf", "WAS": "grass" } surface_map = { "a_turf": 1, "grass": 2, "sportturf": 3, "fieldturf": 4, "matrixturf": 5, "astroturf": 6, "0": 0 } # Get IDs posteam_id = team_map.get(receiver_team, 0) defteam_id = team_map.get(opponent_team, 0) home_team_id = team_map.get(home_team, 0) away_team_id = team_map.get(away_team, 0) # Get surface surface_type = home_team_surface_map.get(home_team, "grass") surface_id = surface_map.get(surface_type, 2) # Create model input model_input = { "receiver_player_id": receiver_id, "passer_player_id": passer_id, "posteam": posteam_id, "defteam": defteam_id, "surface": surface_id, "is_dome": game_data.get("is_dome", 0), "is_rain": game_data.get("is_rain", 0), "is_snow": game_data.get("is_snow", 0), "is_clear": game_data.get("is_clear", 1), "temp_f": game_data.get("temp_f", 70), "humidity_pct": game_data.get("humidity_pct", 50), "wind_mph": game_data.get("wind_mph", 5), "pregame_spread": game_data.get("pregame_spread", 0), "pregame_total": game_data.get("pregame_total", 0), "home_team": home_team_id, "away_team": away_team_id, } # Format output for display output = f""" 🏈 Model Input Created Successfully! 📋 Game Information: • Matchup: {away_team} @ {home_team} (Week {week}, {season}) • Game Time: {game_data.get('game_datetime', 'Unknown')} • Venue: {home_team} ({surface_type}, {'Indoor' if game_data.get('is_dome') else 'Outdoor'}) 👤 Players: • Receiver: {receiver_name} ({wr_key}) - ID: {receiver_id} • Passer: {passer_name} ({qb_key}) - ID: {passer_id} • Team: {receiver_team} vs {opponent_team} 🌤️ Weather Conditions: • Temperature: {game_data.get('temp_f', 70)}°F • Humidity: {game_data.get('humidity_pct', 50)}% • Wind: {game_data.get('wind_mph', 5)} mph • Conditions: {'Dome' if game_data.get('is_dome') else 'Rain' if game_data.get('is_rain') else 'Snow' if game_data.get('is_snow') else 'Clear'} 💰 Betting Lines: • Spread: {game_data.get('pregame_spread', 0)} • Total: {game_data.get('pregame_total', 0)} 📊 Model Input Dictionary: {model_input} """ return output, model_input except Exception as e: return f"Error: {str(e)}", None # Create Gradio interface def gradio_interface(home_team, away_team, receiver_on_home, receiver_name, passer_name, week, season): output_text, model_input = create_model_input( home_team, away_team, receiver_on_home, receiver_name, passer_name, week, season ) return output_text with gr.Blocks(title="NFL Receiver Prediction Input Generator") as app: gr.Markdown("# 🏈 NFL Receiver Prediction Input Generator") gr.Markdown("Generate model inputs for NFL receiver predictions with automatic weather and odds data.") with gr.Row(): with gr.Column(): home_team = gr.Dropdown( choices=NFL_TEAMS, label="Home Team", value="KC" ) away_team = gr.Dropdown( choices=NFL_TEAMS, label="Away Team", value="NO" ) with gr.Column(): week = gr.Number( label="Week", value=6, precision=0 ) season = gr.Number( label="Season", value=2025, precision=0 ) with gr.Row(): receiver_on_home = gr.Checkbox( label="Receiver is on Home Team", value=True ) with gr.Row(): with gr.Column(): receiver_name = gr.Dropdown( choices = receiver_choices, label="Receiver Name", value="" ) with gr.Column(): passer_name = gr.Dropdown( choices = passer_choices, label="Passer Name", value="" ) generate_btn = gr.Button("Generate Model Input", variant="primary") output = gr.Textbox( label="Model Input", lines=25, max_lines=30 ) generate_btn.click( fn=gradio_interface, inputs=[home_team, away_team, receiver_on_home, receiver_name, passer_name, week, season], outputs=output ) gr.Markdown(""" ### Instructions: 1. Select the home and away teams 2. Enter the week number and season 3. Check the box if the receiver plays for the home team 4. Enter the receiver and passer names (First Last format) 5. Click "Generate Model Input" The app will automatically fetch: - Weather forecast for the game - Betting lines (spread and total) - Stadium surface information - Player IDs from your database """) # Launch the app if __name__ == "__main__": app.launch()