gradiospace / app.py
james-kramer's picture
Update app.py
1cddede verified
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()