Spaces:
Sleeping
Sleeping
| 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() |