| import gradio as gr |
| import pandas as pd |
| import plotly.graph_objects as go |
| from datetime import datetime, timedelta |
| import json |
| import random |
|
|
| |
|
|
| |
| USERS = { |
| "admin": {"password": "admin123", "role": "Management"}, |
| "coach": {"password": "coach123", "role": "Coach"}, |
| "manager": {"password": "manager123", "role": "Manager"} |
| } |
|
|
| |
| 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 = [ |
| {"title": "Pre-Season Camp", "date": "2023-10-15", "type": "Training", "status": "Done"}, |
| {"title": "Regional Finals", "date": "2023-12-05", "type": "Match", "status": "Scheduled"} |
| ] |
|
|
| |
|
|
| 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?" |
|
|
| |
|
|
| 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: |
| |
| |
| user_state = gr.State(None) |
| schedule_state = gr.State(INITIAL_SCHEDULE) |
| |
| |
| gr.Markdown(""" |
| <div style='text-align: center; margin-bottom: 20px;'> |
| <h1 style='color: white; font-weight: 800; letter-spacing: -1px;'>ELITE TEAM OS</h1> |
| <p style='color: #94a3b8; font-size: 12px; text-transform: uppercase; letter-spacing: 2px;'>High Performance Management System</p> |
| </div> |
| """) |
|
|
| |
| with gr.Row(visible=True) as login_row: |
| with gr.Column(scale=1, min_width=400): |
| gr.Markdown("<h3 style='text-align:center; color:white;'>Secure Access</h3>") |
| 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) |
|
|
| |
| with gr.Row(visible=False) as app_row: |
| |
| |
| with gr.Column(scale=1, min_width=200): |
| |
| gr.Markdown("<div style='color:#94a3b8; font-size:10px; text-transform:uppercase; margin-bottom:10px;'>System Active</div>") |
| 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") |
|
|
| |
| with gr.Column(scale=5): |
| |
| |
| with gr.Column(visible=True) as view_hub: |
| gr.Markdown("<h2 style='color:white;'>Team Roster & Analytics</h2>") |
| |
| |
| roster_html = "" |
| for p in ROSTER: |
| trend_color = "#22c55e" if p['trend'] == 'up' else "#ef4444" if p['trend'] == 'down' else "#94a3b8" |
| roster_html += f""" |
| <div style='background: #1e293b; padding: 15px; border-radius: 8px; margin-bottom: 10px; border-left: 4px solid {trend_color};'> |
| <div style='display: flex; justify-content: space-between; align-items: center;'> |
| <div> |
| <span style='font-weight: bold; color: white;'>{p['name']}</span> |
| <span style='font-size: 10px; color: #64748b; margin-left: 5px;'>{p['pos']} | #{p['num']}</span> |
| </div> |
| <span style='font-size: 12px; font-weight: bold; color: {trend_color};'>{p['change']}</span> |
| </div> |
| <div style='margin-top: 8px;'> |
| <span style='font-size: 10px; color: #64748b;'>Focus: {p['focus']}/10</span> | |
| <span style='font-size: 10px; color: #64748b;'>Stamina: {p['stamina']}/10</span> |
| </div> |
| </div> |
| """ |
| gr.HTML(roster_html) |
|
|
| |
| gr.Markdown("<h3 style='color:white; margin-top:20px;'>Performance Trends</h3>") |
| with gr.Row(): |
| for p in ROSTER[:3]: |
| with gr.Column(): |
| gr.Markdown(f"<div style='color:white; font-size:12px; text-align:center;'>{p['name']}</div>") |
| spark = gr.Plot(value=create_sparkline(p['hist']), show_label=False) |
|
|
| |
| with gr.Column(visible=False) as view_advisor: |
| gr.Markdown("<h2 style='color:white;'>Tactical Advisor</h2>") |
| gr.Markdown("<p style='color:#94a3b8; font-size:12px;'>AI-powered coaching assistant. Ask about lineups, drills, or player psychology.</p>") |
| |
| 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) |
| |
| |
| with gr.Row(): |
| btn_strategy = gr.Button("Strategy Sync", size="sm") |
| btn_gym = gr.Button("Gym Plan", size="sm") |
|
|
| |
| with gr.Column(visible=False) as view_schedule: |
| gr.Markdown("<h2 style='color:white;'>Team Schedule</h2>") |
| 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") |
|
|
| |
|
|
| def handle_login(u, p): |
| if u in USERS and USERS[u]['password'] == p: |
| return ( |
| gr.Row(visible=False), |
| gr.Row(visible=True), |
| u |
| ) |
| 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 |
|
|
| |
| 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] |
| ) |
|
|
| |
| 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]) |
|
|
| |
| 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]) |
|
|
| |
| add_btn.click( |
| add_event, |
| [new_title, new_type, schedule_state], |
| [schedule_table, schedule_state] |
| ) |
|
|
| if __name__ == "__main__": |
| demo.launch() |