gurumurthy3's picture
Create app.py
cca8612 verified
Raw
History Blame Contribute Delete
13.3 kB
"""
IPL Score Predictor – Hugging Face Space
app.py (entry point)
"""
import os, pickle, pathlib
import pandas as pd
import gradio as gr
from Mymodelfile import MyModel, ACTIVE_TEAMS, VENUE_NORM, SEASON_MAP
# ── paths ────────────────────────────────────────────────────────────────────
DATA_DIR = pathlib.Path(".")
MODEL_PATH = DATA_DIR / "ipl_svr_model.pkl"
MATCHES_CSV = DATA_DIR / "matches_updated_ipl_upto_2025.csv"
DELIVERIES_CSV = DATA_DIR / "deliveries_updated_ipl_upto_2025.csv"
PLAYERS_CSV = DATA_DIR / "ipl_players_uniqueid.csv"
# ── venue list (canonical names from VENUE_NORM values) ──────────────────────
VENUES = sorted(set(VENUE_NORM.values()))
# ── team list ─────────────────────────────────────────────────────────────────
TEAMS = sorted(ACTIVE_TEAMS)
# ── toss options ──────────────────────────────────────────────────────────────
TOSS_DECISIONS = ["bat", "field"]
# ── innings options ───────────────────────────────────────────────────────────
INNINGS = ["1", "2"]
# ── season (current / upcoming) ───────────────────────────────────────────────
SEASONS = sorted(SEASON_MAP.keys(), key=lambda x: SEASON_MAP[x])
# ─────────────────────────────────────────────────────────────────────────────
# Model loading / training
# ─────────────────────────────────────────────────────────────────────────────
def _train_and_save() -> MyModel:
print("Training model on provided CSVs …")
deliveries = pd.read_csv(DELIVERIES_CSV)
matches = pd.read_csv(MATCHES_CSV)
players = pd.read_csv(PLAYERS_CSV) if PLAYERS_CSV.exists() else None
mdl = MyModel()
mdl.fit(deliveries, players_df=players, matches_df=matches)
with open(MODEL_PATH, "wb") as f:
pickle.dump(mdl, f)
print("Model saved to", MODEL_PATH)
return mdl
def _load_model() -> MyModel:
if MODEL_PATH.exists():
print("Loading cached model …")
with open(MODEL_PATH, "rb") as f:
return pickle.load(f)
return _train_and_save()
# ─────────────────────────────────────────────────────────────────────────────
# Prediction helper
# ─────────────────────────────────────────────────────────────────────────────
def predict_score(
batting_team: str,
bowling_team: str,
toss_winner: str,
toss_decision: str,
venue: str,
wickets: int,
inning: str,
season: str,
) -> str:
if batting_team == bowling_team:
return "⚠️ Batting and bowling teams must be different."
test_df = pd.DataFrame([{
"id": 1,
"innings": int(inning),
"venue": venue,
"season": season,
"batting_team": batting_team,
"bowling_team": bowling_team,
"toss_winner": toss_winner,
"toss_decision": toss_decision,
# wickets encoded as comma-separated dummy player ids
"Batsman's Player Id": ",".join(["P"] * (wickets + 2)),
}])
result_df = MODEL.predict(test_df)
score = int(result_df.iloc[0]["predicted_score"])
return f"🏏 Predicted innings score: **{score}**"
# ─────────────────────────────────────────────────────────────────────────────
# Build the Gradio UI
# ─────────────────────────────────────────────────────────────────────────────
CSS = """
/* ── root palette ─────────────────────────────────────────────────────────── */
:root {
--ipl-blue: #0a1628;
--ipl-gold: #d4a017;
--ipl-cream: #f5efe0;
--ipl-red: #c0392b;
--card-bg: rgba(255,255,255,0.04);
--radius: 12px;
}
/* ── global ──────────────────────────────────────────────────────────────── */
body, .gradio-container {
background: var(--ipl-blue) !important;
font-family: 'Georgia', serif;
color: var(--ipl-cream) !important;
}
/* ── header band ─────────────────────────────────────────────────────────── */
#header {
text-align: center;
padding: 28px 0 10px;
border-bottom: 2px solid var(--ipl-gold);
margin-bottom: 24px;
}
#header h1 {
font-size: 2.4rem;
color: var(--ipl-gold);
letter-spacing: 0.08em;
margin: 0 0 4px;
text-shadow: 0 2px 12px rgba(212,160,23,.45);
}
#header p {
font-size: 0.95rem;
color: var(--ipl-cream);
opacity: .7;
margin: 0;
letter-spacing: 0.05em;
}
/* ── section labels ──────────────────────────────────────────────────────── */
.gr-form label, .gr-block label span {
color: var(--ipl-gold) !important;
font-size: 0.82rem;
letter-spacing: 0.06em;
text-transform: uppercase;
}
/* ── dropdowns / inputs ──────────────────────────────────────────────────── */
select, input[type=number] {
background: rgba(255,255,255,0.07) !important;
border: 1px solid rgba(212,160,23,.4) !important;
border-radius: var(--radius) !important;
color: var(--ipl-cream) !important;
padding: 8px 12px !important;
}
select:focus, input[type=number]:focus {
border-color: var(--ipl-gold) !important;
outline: none !important;
box-shadow: 0 0 0 2px rgba(212,160,23,.25) !important;
}
/* ── predict button ──────────────────────────────────────────────────────── */
#predict-btn {
background: linear-gradient(135deg, var(--ipl-gold) 0%, #b8860b 100%) !important;
color: var(--ipl-blue) !important;
font-weight: 700;
font-size: 1rem;
letter-spacing: 0.1em;
text-transform: uppercase;
border: none !important;
border-radius: var(--radius) !important;
padding: 14px 0 !important;
margin-top: 12px;
transition: transform .15s, box-shadow .15s;
}
#predict-btn:hover {
transform: translateY(-2px);
box-shadow: 0 6px 24px rgba(212,160,23,.45) !important;
}
/* ── result box ──────────────────────────────────────────────────────────── */
#result-box {
background: var(--card-bg) !important;
border: 1px solid var(--ipl-gold) !important;
border-radius: var(--radius) !important;
text-align: center;
font-size: 1.5rem !important;
color: var(--ipl-cream) !important;
padding: 18px !important;
min-height: 70px;
}
/* ── card wrappers ───────────────────────────────────────────────────────── */
.gr-group, .gr-box {
background: var(--card-bg) !important;
border: 1px solid rgba(212,160,23,.18) !important;
border-radius: var(--radius) !important;
}
/* ── note block ──────────────────────────────────────────────────────────── */
#note {
font-size: 0.78rem;
color: rgba(245,239,224,.5);
text-align: center;
margin-top: 8px;
}
"""
def build_ui() -> gr.Blocks:
with gr.Blocks(css=CSS, title="IPL Score Predictor") as demo:
# ── header ────────────────────────────────────────────────────────
gr.HTML("""
<div id="header">
<h1>🏏 IPL Score Predictor</h1>
<p>SVR model Β· trained on IPL 2007 – 2025 data</p>
</div>
""")
# ── inputs ────────────────────────────────────────────────────────
with gr.Row():
with gr.Column():
batting_team = gr.Dropdown(
choices=TEAMS,
label="Batting Team",
value=TEAMS[0],
)
bowling_team = gr.Dropdown(
choices=TEAMS,
label="Bowling Team",
value=TEAMS[1],
)
with gr.Column():
toss_winner = gr.Dropdown(
choices=TEAMS,
label="Toss Won By",
value=TEAMS[0],
)
toss_decision = gr.Dropdown(
choices=TOSS_DECISIONS,
label="Toss Decision",
value="bat",
)
with gr.Row():
venue = gr.Dropdown(
choices=VENUES,
label="Venue",
value=VENUES[0],
)
inning = gr.Dropdown(
choices=INNINGS,
label="Innings",
value="1",
)
season = gr.Dropdown(
choices=SEASONS,
label="Season",
value="2025",
)
wickets = gr.Number(
label="Wickets Fallen (0–10)",
value=0,
minimum=0,
maximum=10,
precision=0,
)
# ── predict button ─────────────────────────────────────────────────
predict_btn = gr.Button("Predict Score", elem_id="predict-btn")
# ── output ────────────────────────────────────────────────────────
result = gr.Markdown(
value="*Fill in the inputs above and click Predict Score.*",
elem_id="result-box",
)
gr.HTML("""
<p id="note">
Predictions are rounded up to the nearest 5. Model uses venue Γ— wickets Γ— h2h Γ— form features.
</p>
""")
# ── wiring ────────────────────────────────────────────────────────
predict_btn.click(
fn=predict_score,
inputs=[
batting_team, bowling_team,
toss_winner, toss_decision,
venue, wickets, inning, season,
],
outputs=result,
)
return demo
# ─────────────────────────────────────────────────────────────────────────────
# Entry point
# ─────────────────────────────────────────────────────────────────────────────
if __name__ == "__main__":
MODEL = _load_model()
app = build_ui()
app.launch()
else:
# When Hugging Face imports this module directly
MODEL = _load_model()
app = build_ui()