import gradio as gr import pandas as pd import plotly.graph_objects as go from datetime import datetime, timedelta import json import random # --- DATA & CONFIG --- # User Credentials USERS = { "admin": {"password": "admin123", "role": "Management"}, "coach": {"password": "coach123", "role": "Coach"}, "manager": {"password": "manager123", "role": "Manager"} } # The 14-Player Roster ROSTER = [ {"id": 1, "name": "Sofia Reyes", "pos": "OH", "num": 4, "trend": "up", "change": "+1.4", "hist": [8.2, 8.4, 8.6, 8.9, 9.1], "focus": 9, "stamina": 9, "spirit": 10}, {"id": 2, "name": "Liam Chen", "pos": "S", "num": 10, "trend": "stable", "change": "0.0", "hist": [8.5, 8.4, 8.5, 8.5, 8.5], "focus": 9, "stamina": 8, "spirit": 9}, {"id": 3, "name": "Marcus Johnson", "pos": "MB", "num": 15, "trend": "up", "change": "+0.8", "hist": [7.1, 7.4, 7.6, 7.9, 8.1], "focus": 8, "stamina": 8, "spirit": 7}, {"id": 4, "name": "Kenji Tanaka", "pos": "OP", "num": 7, "trend": "down", "change": "-0.4", "hist": [9.0, 8.8, 8.7, 8.5, 8.4], "focus": 7, "stamina": 8, "spirit": 6}, {"id": 5, "name": "Elena Volkov", "pos": "L", "num": 1, "trend": "up", "change": "+1.2", "hist": [8.0, 8.2, 8.8, 9.0, 9.2], "focus": 10, "stamina": 9, "spirit": 9}, {"id": 6, "name": "Isaiah Thomas", "pos": "OH", "num": 11, "trend": "stable", "change": "+0.1", "hist": [7.5, 7.5, 7.6, 7.5, 7.6], "focus": 7, "stamina": 8, "spirit": 7}, {"id": 7, "name": "Anna Müller", "pos": "MB", "num": 9, "trend": "up", "change": "+2.0", "hist": [6.5, 7.0, 7.8, 8.2, 8.5], "focus": 9, "stamina": 9, "spirit": 8}, {"id": 8, "name": "Carlos Silva", "pos": "DS", "num": 12, "trend": "stable", "change": "0.0", "hist": [7.8, 7.9, 7.8, 7.9, 7.9], "focus": 8, "stamina": 9, "spirit": 8}, {"id": 9, "name": "Sarah Jenkins", "pos": "OH", "num": 3, "trend": "down", "change": "-1.0", "hist": [8.8, 8.4, 8.1, 7.9, 7.8], "focus": 5, "stamina": 7, "spirit": 5}, {"id": 10, "name": "David Park", "pos": "S", "num": 2, "trend": "up", "change": "+0.5", "hist": [7.0, 7.2, 7.4, 7.5, 7.5], "focus": 8, "stamina": 8, "spirit": 8}, {"id": 11, "name": "Mia Williams", "pos": "OP", "num": 8, "trend": "stable", "change": "+0.2", "hist": [7.2, 7.3, 7.4, 7.4, 7.4], "focus": 7, "stamina": 7, "spirit": 7}, {"id": 12, "name": "James Wilson", "pos": "MB", "num": 14, "trend": "up", "change": "+1.5", "hist": [6.0, 6.5, 7.0, 7.5, 8.0], "focus": 8, "stamina": 8, "spirit": 7}, {"id": 13, "name": "Emily Davis", "pos": "L", "num": 5, "trend": "stable", "change": "0.0", "hist": [8.7, 8.7, 8.6, 8.7, 8.7], "focus": 10, "stamina": 9, "spirit": 10}, {"id": 14, "name": "Ryan Patel", "pos": "OH", "num": 6, "trend": "down", "change": "-0.3", "hist": [8.0, 7.9, 7.8, 7.7, 7.7], "focus": 6, "stamina": 7, "spirit": 6} ] # Initial Schedule Data INITIAL_SCHEDULE = [ {"title": "Pre-Season Camp", "date": "2023-10-15", "type": "Training", "status": "Done"}, {"title": "Regional Finals", "date": "2023-12-05", "type": "Match", "status": "Scheduled"} ] # --- LOGIC HELPERS --- def create_sparkline(data): """Creates a Plotly sparkline figure""" fig = go.Figure(go.Scatter( y=data, mode='lines', fill='tozeroy', line={'color': '#38bdf8', 'width': 2} )) fig.update_layout( margin=dict(l=0, r=0, t=0, b=0), paper_bgcolor='rgba(0,0,0,0)', plot_bgcolor='rgba(0,0,0,0)', xaxis=dict(visible=False), yaxis=dict(visible=False), height=40 ) return fig def get_ai_response(message): """Simulates the Tactical Advisor AI""" msg = message.lower() if "prayer" in msg or "spirit" in msg: return "Prayer is the pillar of discipline. I recommend a 10-minute mindfulness session post-training. 'Verily, with hardship comes ease.' (94:6)" elif "gym" in msg or "strength" in msg: return "I have generated a Plyometric plan:\n1. Box Jumps (4x8)\n2. Lateral Bounds (3x10)\nFocus on explosive landing mechanics." elif "lineup" in msg or "team" in msg: names = [p['name'] for p in random.sample(ROSTER, 6)] return f"Based on current form, I suggest starting: {', '.join(names)}. This combination maximizes court coverage and attack efficiency." elif "defense" in msg: return "Switching to Perimeter Defense. The middle blocker must read the setter's hands. Trust your back-row libero." else: return "Tactical Advisor Online. I have analyzed the roster metrics. We have 3 players with declining stamina trends. Shall I adjust the training load?" # --- GRADIO APP --- css = """ .gradio-container { background-color: #0f172a !important; } .card-bg { background-color: #1e293b !important; border-radius: 12px; padding: 16px; border: 1px solid #334155; height: 100%; } .table-bg { background-color: #1e293b !important; } input, textarea { background-color: #0f172a !important; color: white !important; border: 1px solid #334155 !important; } """ with gr.Blocks(css=css, theme=gr.themes.Soft(primary_hue="sky", neutral_hue="slate", font=gr.themes.GoogleFont("Inter"))) as demo: # --- STATE --- user_state = gr.State(None) schedule_state = gr.State(INITIAL_SCHEDULE) # --- HEADER --- gr.Markdown("""

ELITE TEAM OS

High Performance Management System

""") # --- LOGIN SCREEN --- with gr.Row(visible=True) as login_row: with gr.Column(scale=1, min_width=400): gr.Markdown("

Secure Access

") login_user = gr.Textbox(label="Username", placeholder="admin") login_pass = gr.Textbox(label="Password", type="password", placeholder="admin123") login_btn = gr.Button("Enter System", variant="primary") login_err = gr.Markdown("", visible=False) # --- MAIN APP --- with gr.Row(visible=False) as app_row: # Sidebar Navigation with gr.Column(scale=1, min_width=200): # FIXED LINE BELOW: Removed the empty {} placeholder gr.Markdown("
System Active
") nav_hub = gr.Button("📈 Team Hub", variant="secondary") nav_advisor = gr.Button("🤖 Tactical Advisor", variant="secondary") nav_schedule = gr.Button("🗓️ Schedule", variant="secondary") logout_btn = gr.Button("Sign Out", variant="stop") # Content Area with gr.Column(scale=5): # VIEW 1: TEAM HUB with gr.Column(visible=True) as view_hub: gr.Markdown("

Team Roster & Analytics

") # Roster Grid roster_html = "" for p in ROSTER: trend_color = "#22c55e" if p['trend'] == 'up' else "#ef4444" if p['trend'] == 'down' else "#94a3b8" roster_html += f"""
{p['name']} {p['pos']} | #{p['num']}
{p['change']}
Focus: {p['focus']}/10 | Stamina: {p['stamina']}/10
""" gr.HTML(roster_html) # Performance Charts gr.Markdown("

Performance Trends

") with gr.Row(): for p in ROSTER[:3]: # Show top 3 for brevity with gr.Column(): gr.Markdown(f"
{p['name']}
") spark = gr.Plot(value=create_sparkline(p['hist']), show_label=False) # VIEW 2: ADVISOR with gr.Column(visible=False) as view_advisor: gr.Markdown("

Tactical Advisor

") gr.Markdown("

AI-powered coaching assistant. Ask about lineups, drills, or player psychology.

") chatbot = gr.Chatbot(height=400, show_label=False) with gr.Row(): txt = gr.Textbox(show_label=False, placeholder="Ask for tactics...", container=False, scale=9) btn = gr.Button("Send", variant="primary", scale=1) # Quick Actions with gr.Row(): btn_strategy = gr.Button("Strategy Sync", size="sm") btn_gym = gr.Button("Gym Plan", size="sm") # VIEW 3: SCHEDULE with gr.Column(visible=False) as view_schedule: gr.Markdown("

Team Schedule

") schedule_table = gr.Dataframe( value=pd.DataFrame(INITIAL_SCHEDULE), headers=["Title", "Date", "Type", "Status"], datatype=["str", "str", "str", "str"], row_count=5, col_count=(4, "fixed"), interactive=False ) with gr.Row(): new_title = gr.Textbox(label="New Event Title") new_type = gr.Dropdown(choices=["Training", "Match", "Gym"], label="Type") add_btn = gr.Button("Add Event") # --- FUNCTIONS --- def handle_login(u, p): if u in USERS and USERS[u]['password'] == p: return ( gr.Row(visible=False), # Hide login gr.Row(visible=True), # Show app u # Update state ) else: return gr.Row(visible=True), gr.Row(visible=False), None def handle_logout(): return gr.Row(visible=True), gr.Row(visible=False), None def switch_view(show_view): return { view_hub: gr.Column(visible=show_view == "hub"), view_advisor: gr.Column(visible=show_view == "advisor"), view_schedule: gr.Column(visible=show_view == "schedule") } def add_event(title, ev_type, current_schedule): new_event = { "title": title, "date": datetime.now().strftime("%Y-%m-%d"), "type": ev_type, "status": "Scheduled" } updated_schedule = current_schedule + [new_event] df = pd.DataFrame(updated_schedule) return df, updated_schedule def respond(message, chat_history): response = get_ai_response(message) chat_history.append((message, response)) return "", chat_history # --- EVENTS --- login_btn.click( handle_login, [login_user, login_pass], [login_row, app_row, user_state] ) logout_btn.click( handle_logout, None, [login_row, app_row, user_state] ) # Navigation nav_hub.click(lambda: switch_view("hub"), None, [view_hub, view_advisor, view_schedule]) nav_advisor.click(lambda: switch_view("advisor"), None, [view_hub, view_advisor, view_schedule]) nav_schedule.click(lambda: switch_view("schedule"), None, [view_hub, view_advisor, view_schedule]) # Chat Logic txt.submit(respond, [txt, chatbot], [txt, chatbot]) btn.click(respond, [txt, chatbot], [txt, chatbot]) btn_gym.click(lambda: respond("Give me a gym plan for vertical jump.", []), None, [txt, chatbot]) # Schedule Logic add_btn.click( add_event, [new_title, new_type, schedule_state], [schedule_table, schedule_state] ) if __name__ == "__main__": demo.launch()