File size: 12,750 Bytes
80fb917
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8e602aa
 
80fb917
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
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("""
    <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>
    """)

    # --- LOGIN SCREEN ---
    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)

    # --- 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("<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")

        # Content Area
        with gr.Column(scale=5):
            
            # VIEW 1: TEAM HUB
            with gr.Column(visible=True) as view_hub:
                gr.Markdown("<h2 style='color:white;'>Team Roster & Analytics</h2>")
                
                # 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"""
                    <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)

                # Performance Charts
                gr.Markdown("<h3 style='color:white; margin-top:20px;'>Performance Trends</h3>")
                with gr.Row():
                    for p in ROSTER[:3]: # Show top 3 for brevity
                        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)

            # VIEW 2: ADVISOR
            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)
                
                # 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("<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")

    # --- 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()