Yuxuan-Zhang-Dexter commited on
Commit
603247d
ยท
1 Parent(s): 6ebb0fb

update app.py

Browse files
Files changed (1) hide show
  1. app.py +774 -194
app.py CHANGED
@@ -1,204 +1,784 @@
1
  import gradio as gr
2
- from gradio_leaderboard import Leaderboard, ColumnFilter, SelectColumns
3
  import pandas as pd
4
- from apscheduler.schedulers.background import BackgroundScheduler
5
- from huggingface_hub import snapshot_download
6
-
7
- from src.about import (
8
- CITATION_BUTTON_LABEL,
9
- CITATION_BUTTON_TEXT,
10
- EVALUATION_QUEUE_TEXT,
11
- INTRODUCTION_TEXT,
12
- LLM_BENCHMARKS_TEXT,
13
- TITLE,
 
 
 
 
 
 
 
14
  )
15
- from src.display.css_html_js import custom_css
16
- from src.display.utils import (
17
- BENCHMARK_COLS,
18
- COLS,
19
- EVAL_COLS,
20
- EVAL_TYPES,
21
- AutoEvalColumn,
22
- ModelType,
23
- fields,
24
- WeightType,
25
- Precision
26
  )
27
- from src.envs import API, EVAL_REQUESTS_PATH, EVAL_RESULTS_PATH, QUEUE_REPO, REPO_ID, RESULTS_REPO, TOKEN
28
- from src.populate import get_evaluation_queue_df, get_leaderboard_df
29
- from src.submission.submit import add_new_eval
30
-
31
-
32
- def restart_space():
33
- API.restart_space(repo_id=REPO_ID)
34
-
35
- ### Space initialisation
36
- try:
37
- print(EVAL_REQUESTS_PATH)
38
- snapshot_download(
39
- repo_id=QUEUE_REPO, local_dir=EVAL_REQUESTS_PATH, repo_type="dataset", tqdm_class=None, etag_timeout=30, token=TOKEN
40
- )
41
- except Exception:
42
- restart_space()
43
- try:
44
- print(EVAL_RESULTS_PATH)
45
- snapshot_download(
46
- repo_id=RESULTS_REPO, local_dir=EVAL_RESULTS_PATH, repo_type="dataset", tqdm_class=None, etag_timeout=30, token=TOKEN
47
- )
48
- except Exception:
49
- restart_space()
50
-
51
-
52
- LEADERBOARD_DF = get_leaderboard_df(EVAL_RESULTS_PATH, EVAL_REQUESTS_PATH, COLS, BENCHMARK_COLS)
53
-
54
- (
55
- finished_eval_queue_df,
56
- running_eval_queue_df,
57
- pending_eval_queue_df,
58
- ) = get_evaluation_queue_df(EVAL_REQUESTS_PATH, EVAL_COLS)
59
-
60
- def init_leaderboard(dataframe):
61
- if dataframe is None or dataframe.empty:
62
- raise ValueError("Leaderboard DataFrame is empty or None.")
63
- return Leaderboard(
64
- value=dataframe,
65
- datatype=[c.type for c in fields(AutoEvalColumn)],
66
- select_columns=SelectColumns(
67
- default_selection=[c.name for c in fields(AutoEvalColumn) if c.displayed_by_default],
68
- cant_deselect=[c.name for c in fields(AutoEvalColumn) if c.never_hidden],
69
- label="Select Columns to Display:",
70
- ),
71
- search_columns=[AutoEvalColumn.model.name, AutoEvalColumn.license.name],
72
- hide_columns=[c.name for c in fields(AutoEvalColumn) if c.hidden],
73
- filter_columns=[
74
- ColumnFilter(AutoEvalColumn.model_type.name, type="checkboxgroup", label="Model types"),
75
- ColumnFilter(AutoEvalColumn.precision.name, type="checkboxgroup", label="Precision"),
76
- ColumnFilter(
77
- AutoEvalColumn.params.name,
78
- type="slider",
79
- min=0.01,
80
- max=150,
81
- label="Select the number of parameters (B)",
82
- ),
83
- ColumnFilter(
84
- AutoEvalColumn.still_on_hub.name, type="boolean", label="Deleted/incomplete", default=True
85
- ),
86
- ],
87
- bool_checkboxgroup_label="Hide models",
88
- interactive=False,
89
- )
90
-
91
-
92
- demo = gr.Blocks(css=custom_css)
93
- with demo:
94
- gr.HTML(TITLE)
95
- gr.Markdown(INTRODUCTION_TEXT, elem_classes="markdown-text")
96
-
97
- with gr.Tabs(elem_classes="tab-buttons") as tabs:
98
- with gr.TabItem("๐Ÿ… LLM Benchmark", elem_id="llm-benchmark-tab-table", id=0):
99
- leaderboard = init_leaderboard(LEADERBOARD_DF)
100
-
101
- with gr.TabItem("๐Ÿ“ About", elem_id="llm-benchmark-tab-table", id=2):
102
- gr.Markdown(LLM_BENCHMARKS_TEXT, elem_classes="markdown-text")
103
-
104
- with gr.TabItem("๐Ÿš€ Submit here! ", elem_id="llm-benchmark-tab-table", id=3):
105
- with gr.Column():
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
106
  with gr.Row():
107
- gr.Markdown(EVALUATION_QUEUE_TEXT, elem_classes="markdown-text")
108
-
109
- with gr.Column():
110
- with gr.Accordion(
111
- f"โœ… Finished Evaluations ({len(finished_eval_queue_df)})",
112
- open=False,
113
- ):
114
- with gr.Row():
115
- finished_eval_table = gr.components.Dataframe(
116
- value=finished_eval_queue_df,
117
- headers=EVAL_COLS,
118
- datatype=EVAL_TYPES,
119
- row_count=5,
120
- )
121
- with gr.Accordion(
122
- f"๐Ÿ”„ Running Evaluation Queue ({len(running_eval_queue_df)})",
123
- open=False,
124
- ):
125
- with gr.Row():
126
- running_eval_table = gr.components.Dataframe(
127
- value=running_eval_queue_df,
128
- headers=EVAL_COLS,
129
- datatype=EVAL_TYPES,
130
- row_count=5,
131
- )
132
-
133
- with gr.Accordion(
134
- f"โณ Pending Evaluation Queue ({len(pending_eval_queue_df)})",
135
- open=False,
136
- ):
137
- with gr.Row():
138
- pending_eval_table = gr.components.Dataframe(
139
- value=pending_eval_queue_df,
140
- headers=EVAL_COLS,
141
- datatype=EVAL_TYPES,
142
- row_count=5,
143
- )
144
- with gr.Row():
145
- gr.Markdown("# โœ‰๏ธโœจ Submit your model here!", elem_classes="markdown-text")
146
-
147
- with gr.Row():
148
- with gr.Column():
149
- model_name_textbox = gr.Textbox(label="Model name")
150
- revision_name_textbox = gr.Textbox(label="Revision commit", placeholder="main")
151
- model_type = gr.Dropdown(
152
- choices=[t.to_str(" : ") for t in ModelType if t != ModelType.Unknown],
153
- label="Model type",
154
- multiselect=False,
155
- value=None,
156
- interactive=True,
157
  )
158
 
159
- with gr.Column():
160
- precision = gr.Dropdown(
161
- choices=[i.value.name for i in Precision if i != Precision.Unknown],
162
- label="Precision",
163
- multiselect=False,
164
- value="float16",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
165
  interactive=True,
 
 
166
  )
167
- weight_type = gr.Dropdown(
168
- choices=[i.value.name for i in WeightType],
169
- label="Weights type",
170
- multiselect=False,
171
- value="Original",
172
- interactive=True,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
173
  )
174
- base_model_name_textbox = gr.Textbox(label="Base model (for delta or adapter weights)")
175
-
176
- submit_button = gr.Button("Submit Eval")
177
- submission_result = gr.Markdown()
178
- submit_button.click(
179
- add_new_eval,
180
- [
181
- model_name_textbox,
182
- base_model_name_textbox,
183
- revision_name_textbox,
184
- precision,
185
- weight_type,
186
- model_type,
187
- ],
188
- submission_result,
189
- )
190
-
191
- with gr.Row():
192
- with gr.Accordion("๐Ÿ“™ Citation", open=False):
193
- citation_button = gr.Textbox(
194
- value=CITATION_BUTTON_TEXT,
195
- label=CITATION_BUTTON_LABEL,
196
- lines=20,
197
- elem_id="citation-button",
198
- show_copy_button=True,
199
- )
200
-
201
- scheduler = BackgroundScheduler()
202
- scheduler.add_job(restart_space, "interval", seconds=1800)
203
- scheduler.start()
204
- demo.queue(default_concurrency_limit=40).launch()
 
1
  import gradio as gr
2
+ import os
3
  import pandas as pd
4
+ import json
5
+ from PIL import Image, ImageSequence
6
+ import io
7
+ from functools import reduce
8
+ import numpy as np
9
+ from datetime import datetime, timedelta
10
+ import matplotlib.pyplot as plt
11
+ from leaderboard_utils import (
12
+ get_organization,
13
+ get_mario_leaderboard,
14
+ get_sokoban_leaderboard,
15
+ get_2048_leaderboard,
16
+ get_candy_leaderboard,
17
+ get_tetris_leaderboard,
18
+ get_tetris_planning_leaderboard,
19
+ get_combined_leaderboard,
20
+ GAME_ORDER
21
  )
22
+ from data_visualization import (
23
+ get_combined_leaderboard_with_group_bar,
24
+ create_organization_radar_chart,
25
+ create_top_players_radar_chart,
26
+ create_player_radar_chart,
27
+ create_horizontal_bar_chart,
28
+ normalize_values
 
 
 
 
29
  )
30
+
31
+ # Define time points and their corresponding data files
32
+ TIME_POINTS = {
33
+ "03/25/2025": "rank_data_03_25_2025.json",
34
+ # Add more time points here as they become available
35
+ }
36
+
37
+ # Load the initial JSON file with rank data
38
+ with open(TIME_POINTS["03/25/2025"], "r") as f:
39
+ rank_data = json.load(f)
40
+
41
+ # Add leaderboard state at the top level
42
+ leaderboard_state = {
43
+ "current_game": None,
44
+ "previous_overall": {
45
+ "Super Mario Bros": True,
46
+ "Sokoban": True,
47
+ "2048": True,
48
+ "Candy Crash": True,
49
+ "Tetris (complete)": True,
50
+ "Tetris (planning only)": True
51
+ },
52
+ "previous_details": {
53
+ "Super Mario Bros": False,
54
+ "Sokoban": False,
55
+ "2048": False,
56
+ "Candy Crash": False,
57
+ "Tetris (complete)": False,
58
+ "Tetris (planning only)": False
59
+ }
60
+ }
61
+
62
+ # Define GIF paths for the carousel
63
+ GIF_PATHS = [
64
+ "assets/super_mario_bros/super_mario.gif",
65
+ "assets/sokoban/sokoban.gif",
66
+ "assets/2048/2048.gif",
67
+ "assets/candy/candy.gif",
68
+ "assets/tetris/tetris.gif"
69
+ ]
70
+
71
+ # Print and verify GIF paths
72
+ print("\nChecking GIF paths:")
73
+ for gif_path in GIF_PATHS:
74
+ if os.path.exists(gif_path):
75
+ print(f"โœ“ Found: {gif_path}")
76
+ # Print file size
77
+ size = os.path.getsize(gif_path)
78
+ print(f" Size: {size / (1024*1024):.2f} MB")
79
+ else:
80
+ print(f"โœ— Missing: {gif_path}")
81
+
82
+ # Load video links and news data
83
+ with open('assets/game_video_link.json', 'r') as f:
84
+ VIDEO_LINKS = json.load(f)
85
+
86
+ with open('assets/news.json', 'r') as f:
87
+ NEWS_DATA = json.load(f)
88
+
89
+ def load_gif(gif_path):
90
+ """Load a GIF file and return it as a PIL Image"""
91
+ try:
92
+ img = Image.open(gif_path)
93
+ print(f"Successfully loaded GIF: {gif_path}")
94
+ return img
95
+ except Exception as e:
96
+ print(f"Error loading GIF {gif_path}: {e}")
97
+ return None
98
+
99
+ def create_gif_carousel():
100
+ """Create a custom HTML/JS component for GIF carousel"""
101
+ print("\nCreating GIF carousel with paths:", GIF_PATHS)
102
+ html = f"""
103
+ <div id="gif-carousel" style="width: 100%; height: 300px; position: relative; background-color: #f0f0f0;">
104
+ <img id="current-gif" style="width: 100%; height: 100%; object-fit: contain;" onerror="console.error('Failed to load GIF:', this.src);">
105
+ </div>
106
+ <script>
107
+ const gifs = {json.dumps(GIF_PATHS)};
108
+ let currentIndex = 0;
109
+
110
+ function updateGif() {{
111
+ const img = document.getElementById('current-gif');
112
+ console.log('Loading GIF:', gifs[currentIndex]);
113
+ img.src = gifs[currentIndex];
114
+ currentIndex = (currentIndex + 1) % gifs.length;
115
+ }}
116
+
117
+ // Update GIF every 5 seconds
118
+ setInterval(updateGif, 5000);
119
+ // Initial load
120
+ updateGif();
121
+ </script>
122
+ """
123
+ return gr.HTML(html)
124
+
125
+ def load_rank_data(time_point):
126
+ """Load rank data for a specific time point"""
127
+ if time_point in TIME_POINTS:
128
+ try:
129
+ with open(TIME_POINTS[time_point], "r") as f:
130
+ return json.load(f)
131
+ except FileNotFoundError:
132
+ return None
133
+ return None
134
+
135
+ def update_leaderboard(mario_overall, mario_details,
136
+ sokoban_overall, sokoban_details,
137
+ _2048_overall, _2048_details,
138
+ candy_overall, candy_details,
139
+ tetris_overall, tetris_details,
140
+ tetris_plan_overall, tetris_plan_details):
141
+ global leaderboard_state
142
+
143
+ # Convert current checkbox states to dictionary for easier comparison
144
+ current_overall = {
145
+ "Super Mario Bros": mario_overall,
146
+ "Sokoban": sokoban_overall,
147
+ "2048": _2048_overall,
148
+ "Candy Crash": candy_overall,
149
+ "Tetris (complete)": tetris_overall,
150
+ "Tetris (planning only)": tetris_plan_overall
151
+ }
152
+
153
+ current_details = {
154
+ "Super Mario Bros": mario_details,
155
+ "Sokoban": sokoban_details,
156
+ "2048": _2048_details,
157
+ "Candy Crash": candy_details,
158
+ "Tetris (complete)": tetris_details,
159
+ "Tetris (planning only)": tetris_plan_details
160
+ }
161
+
162
+ # Find which game's state changed
163
+ changed_game = None
164
+ for game in current_overall.keys():
165
+ if (current_overall[game] != leaderboard_state["previous_overall"][game] or
166
+ current_details[game] != leaderboard_state["previous_details"][game]):
167
+ changed_game = game
168
+ break
169
+
170
+ if changed_game:
171
+ # If a game's details checkbox was checked
172
+ if current_details[changed_game] and not leaderboard_state["previous_details"][changed_game]:
173
+ # Reset all other games' states
174
+ for game in current_overall.keys():
175
+ if game != changed_game:
176
+ current_overall[game] = False
177
+ current_details[game] = False
178
+ leaderboard_state["previous_overall"][game] = False
179
+ leaderboard_state["previous_details"][game] = False
180
+
181
+ # Update state for the selected game
182
+ leaderboard_state["current_game"] = changed_game
183
+ leaderboard_state["previous_overall"][changed_game] = True
184
+ leaderboard_state["previous_details"][changed_game] = True
185
+ current_overall[changed_game] = True
186
+
187
+ # If a game's overall checkbox was checked
188
+ elif current_overall[changed_game] and not leaderboard_state["previous_overall"][changed_game]:
189
+ # If we were in details view for another game, switch to overall view
190
+ if leaderboard_state["current_game"] and leaderboard_state["previous_details"][leaderboard_state["current_game"]]:
191
+ # Reset previous game's details
192
+ leaderboard_state["previous_details"][leaderboard_state["current_game"]] = False
193
+ current_details[leaderboard_state["current_game"]] = False
194
+ leaderboard_state["current_game"] = None
195
+
196
+ # Update state
197
+ leaderboard_state["previous_overall"][changed_game] = True
198
+ leaderboard_state["previous_details"][changed_game] = False
199
+
200
+ # If a game's overall checkbox was unchecked
201
+ elif not current_overall[changed_game] and leaderboard_state["previous_overall"][changed_game]:
202
+ # If we're in details view, don't allow unchecking the overall checkbox
203
+ if leaderboard_state["current_game"] == changed_game:
204
+ current_overall[changed_game] = True
205
+ else:
206
+ leaderboard_state["previous_overall"][changed_game] = False
207
+ if leaderboard_state["current_game"] == changed_game:
208
+ leaderboard_state["current_game"] = None
209
+
210
+ # If a game's details checkbox was unchecked
211
+ elif not current_details[changed_game] and leaderboard_state["previous_details"][changed_game]:
212
+ leaderboard_state["previous_details"][changed_game] = False
213
+ if leaderboard_state["current_game"] == changed_game:
214
+ leaderboard_state["current_game"] = None
215
+ # When exiting details view, reset to show all games
216
+ for game in current_overall.keys():
217
+ current_overall[game] = True
218
+ current_details[game] = False
219
+ leaderboard_state["previous_overall"][game] = True
220
+ leaderboard_state["previous_details"][game] = False
221
+
222
+ # Special case: If all games are selected and we're trying to view details
223
+ all_games_selected = all(current_overall.values()) and not any(current_details.values())
224
+ if all_games_selected and changed_game and current_details[changed_game]:
225
+ # Reset all other games' states
226
+ for game in current_overall.keys():
227
+ if game != changed_game:
228
+ current_overall[game] = False
229
+ current_details[game] = False
230
+ leaderboard_state["previous_overall"][game] = False
231
+ leaderboard_state["previous_details"][game] = False
232
+
233
+ # Update state for the selected game
234
+ leaderboard_state["current_game"] = changed_game
235
+ leaderboard_state["previous_overall"][changed_game] = True
236
+ leaderboard_state["previous_details"][changed_game] = True
237
+ current_overall[changed_game] = True
238
+
239
+ # Build dictionary for selected games
240
+ selected_games = {
241
+ "Super Mario Bros": current_overall["Super Mario Bros"],
242
+ "Sokoban": current_overall["Sokoban"],
243
+ "2048": current_overall["2048"],
244
+ "Candy Crash": current_overall["Candy Crash"],
245
+ "Tetris (complete)": current_overall["Tetris (complete)"],
246
+ "Tetris (planning only)": current_overall["Tetris (planning only)"]
247
+ }
248
+
249
+ # Get the appropriate DataFrame and chart based on current state
250
+ if leaderboard_state["current_game"]:
251
+ # For detailed view
252
+ if leaderboard_state["current_game"] == "Super Mario Bros":
253
+ df = get_mario_leaderboard(rank_data)
254
+ elif leaderboard_state["current_game"] == "Sokoban":
255
+ df = get_sokoban_leaderboard(rank_data)
256
+ elif leaderboard_state["current_game"] == "2048":
257
+ df = get_2048_leaderboard(rank_data)
258
+ elif leaderboard_state["current_game"] == "Candy Crash":
259
+ df = get_candy_leaderboard(rank_data)
260
+ elif leaderboard_state["current_game"] == "Tetris (complete)":
261
+ df = get_tetris_leaderboard(rank_data)
262
+ else: # Tetris (planning only)
263
+ df = get_tetris_planning_leaderboard(rank_data)
264
+
265
+ # Always create a new chart for detailed view
266
+ chart = create_horizontal_bar_chart(df, leaderboard_state["current_game"])
267
+ else:
268
+ # For overall view
269
+ df, chart = get_combined_leaderboard_with_group_bar(rank_data, selected_games)
270
+
271
+ # Return exactly 14 values to match the expected outputs
272
+ return (df, chart,
273
+ current_overall["Super Mario Bros"], current_details["Super Mario Bros"],
274
+ current_overall["Sokoban"], current_details["Sokoban"],
275
+ current_overall["2048"], current_details["2048"],
276
+ current_overall["Candy Crash"], current_details["Candy Crash"],
277
+ current_overall["Tetris (complete)"], current_details["Tetris (complete)"],
278
+ current_overall["Tetris (planning only)"], current_details["Tetris (planning only)"])
279
+
280
+ def update_leaderboard_with_time(time_point, mario_overall, mario_details,
281
+ sokoban_overall, sokoban_details,
282
+ _2048_overall, _2048_details,
283
+ candy_overall, candy_details,
284
+ tetris_overall, tetris_details,
285
+ tetris_plan_overall, tetris_plan_details):
286
+ # Load rank data for the selected time point
287
+ global rank_data
288
+ new_rank_data = load_rank_data(time_point)
289
+ if new_rank_data is not None:
290
+ rank_data = new_rank_data
291
+
292
+ # Use the existing update_leaderboard function
293
+ return update_leaderboard(mario_overall, mario_details,
294
+ sokoban_overall, sokoban_details,
295
+ _2048_overall, _2048_details,
296
+ candy_overall, candy_details,
297
+ tetris_overall, tetris_details,
298
+ tetris_plan_overall, tetris_plan_details)
299
+
300
+ def get_initial_state():
301
+ """Get the initial state for the leaderboard"""
302
+ return {
303
+ "current_game": None,
304
+ "previous_overall": {
305
+ "Super Mario Bros": True,
306
+ "Sokoban": True,
307
+ "2048": True,
308
+ "Candy Crash": True,
309
+ "Tetris (complete)": True,
310
+ "Tetris (planning only)": True
311
+ },
312
+ "previous_details": {
313
+ "Super Mario Bros": False,
314
+ "Sokoban": False,
315
+ "2048": False,
316
+ "Candy Crash": False,
317
+ "Tetris (complete)": False,
318
+ "Tetris (planning only)": False
319
+ }
320
+ }
321
+
322
+ def clear_filters():
323
+ global leaderboard_state
324
+
325
+ # Reset all checkboxes to default state
326
+ selected_games = {
327
+ "Super Mario Bros": True,
328
+ "Sokoban": True,
329
+ "2048": True,
330
+ "Candy Crash": True,
331
+ "Tetris (complete)": True,
332
+ "Tetris (planning only)": True
333
+ }
334
+
335
+ # Get the combined leaderboard and group bar chart
336
+ df, chart = get_combined_leaderboard_with_group_bar(rank_data, selected_games)
337
+
338
+ # Reset the leaderboard state to match the default checkbox states
339
+ leaderboard_state = get_initial_state()
340
+
341
+ # Return exactly 14 values to match the expected outputs
342
+ return (df, chart,
343
+ True, False, # mario
344
+ True, False, # sokoban
345
+ True, False, # 2048
346
+ True, False, # candy
347
+ True, False, # tetris
348
+ True, False) # tetris plan
349
+
350
+ def create_timeline_slider():
351
+ """Create a custom timeline slider component"""
352
+ timeline_html = """
353
+ <div class="timeline-container">
354
+ <style>
355
+ .timeline-container {
356
+ width: 85%; /* Increased from 70% to 85% */
357
+ padding: 8px;
358
+ font-family: Arial, sans-serif;
359
+ height: 40px;
360
+ display: flex;
361
+ align-items: center;
362
+ }
363
+ .timeline-track {
364
+ position: relative;
365
+ height: 6px;
366
+ background: #e0e0e0;
367
+ border-radius: 3px;
368
+ margin: 0;
369
+ width: 100%;
370
+ }
371
+ .timeline-progress {
372
+ position: absolute;
373
+ height: 100%;
374
+ background: #2196F3;
375
+ border-radius: 3px;
376
+ width: 100%;
377
+ }
378
+ .timeline-handle {
379
+ position: absolute;
380
+ right: 0;
381
+ top: 50%;
382
+ transform: translate(50%, -50%);
383
+ width: 20px;
384
+ height: 20px;
385
+ background: #2196F3;
386
+ border: 3px solid white;
387
+ border-radius: 50%;
388
+ cursor: pointer;
389
+ box-shadow: 0 2px 6px rgba(0,0,0,0.3);
390
+ }
391
+ .timeline-date {
392
+ position: absolute;
393
+ top: -25px;
394
+ transform: translateX(-50%);
395
+ background: #2196F3; /* Changed to match slider blue color */
396
+ color: #ffffff !important;
397
+ padding: 3px 8px;
398
+ border-radius: 4px;
399
+ font-size: 12px;
400
+ white-space: nowrap;
401
+ font-weight: 600;
402
+ box-shadow: 0 2px 6px rgba(0,0,0,0.2);
403
+ letter-spacing: 0.5px;
404
+ text-shadow: 0 1px 2px rgba(0,0,0,0.2);
405
+ }
406
+ </style>
407
+ <div class="timeline-track">
408
+ <div class="timeline-progress"></div>
409
+ <div class="timeline-handle">
410
+ <div class="timeline-date">03/25/2025</div>
411
+ </div>
412
+ </div>
413
+ </div>
414
+ <script>
415
+ (function() {
416
+ const container = document.querySelector('.timeline-container');
417
+ const track = container.querySelector('.timeline-track');
418
+ const handle = container.querySelector('.timeline-handle');
419
+ let isDragging = false;
420
+
421
+ // For now, we only have one time point
422
+ const timePoints = {
423
+ "03/25/2025": 1.0
424
+ };
425
+
426
+ function updatePosition(e) {
427
+ if (!isDragging) return;
428
+
429
+ const rect = track.getBoundingClientRect();
430
+ let x = (e.clientX - rect.left) / rect.width;
431
+ x = Math.max(0, Math.min(1, x));
432
+
433
+ // For now, snap to the only available time point
434
+ x = 1.0;
435
+
436
+ handle.style.right = `${(1 - x) * 100}%`;
437
+ }
438
+
439
+ handle.addEventListener('mousedown', (e) => {
440
+ isDragging = true;
441
+ e.preventDefault();
442
+ });
443
+
444
+ document.addEventListener('mousemove', updatePosition);
445
+ document.addEventListener('mouseup', () => {
446
+ isDragging = false;
447
+ });
448
+
449
+ // Prevent text selection while dragging
450
+ container.addEventListener('selectstart', (e) => {
451
+ if (isDragging) e.preventDefault();
452
+ });
453
+ })();
454
+ </script>
455
+ """
456
+ return gr.HTML(timeline_html)
457
+
458
+ def create_video_gallery():
459
+ """Create a custom HTML/JS component for video gallery"""
460
+ # Extract video IDs
461
+ mario_id = VIDEO_LINKS["super_mario"].split("?v=")[1]
462
+ sokoban_id = VIDEO_LINKS["sokoban"].split("?v=")[1]
463
+ game_2048_id = VIDEO_LINKS["2048"].split("?v=")[1]
464
+ candy_id = VIDEO_LINKS["candy"].split("?v=")[1]
465
+
466
+ # Generate news HTML
467
+ news_items = []
468
+ for item in NEWS_DATA["news"]:
469
+ video_id = item["video_link"].split("?v=")[1]
470
+ date_obj = datetime.strptime(item["date"], "%Y-%m-%d")
471
+ formatted_date = date_obj.strftime("%B %d, %Y")
472
+ news_items.append(f'''
473
+ <div class="news-item">
474
+ <div class="news-date">{formatted_date}</div>
475
+ <div class="news-content">
476
+ <div class="news-video">
477
+ <div class="video-wrapper">
478
+ <iframe src="https://www.youtube.com/embed/{video_id}"></iframe>
479
+ </div>
480
+ </div>
481
+ <div class="news-text">
482
+ <a href="{item["twitter_link"]}" target="_blank" class="twitter-link">
483
+ <span class="twitter-icon">๐Ÿ“ข</span>
484
+ {item["twitter_text"]}
485
+ </a>
486
+ </div>
487
+ </div>
488
+ </div>
489
+ ''')
490
+
491
+ news_html = '\n'.join(news_items)
492
+
493
+ gallery_html = f'''
494
+ <div class="video-gallery-container">
495
+ <style>
496
+ .video-gallery-container {{
497
+ width: 100%;
498
+ max-width: 1400px;
499
+ margin: 0 auto;
500
+ padding: 20px;
501
+ }}
502
+ .video-grid {{
503
+ display: grid;
504
+ grid-template-columns: repeat(2, 1fr);
505
+ gap: 20px;
506
+ margin-top: 20px;
507
+ margin-bottom: 40px;
508
+ }}
509
+ .video-card {{
510
+ background: #ffffff;
511
+ border-radius: 10px;
512
+ box-shadow: 0 2px 10px rgba(0,0,0,0.1);
513
+ overflow: hidden;
514
+ transition: transform 0.2s;
515
+ }}
516
+ .video-card:hover {{
517
+ transform: translateY(-5px);
518
+ }}
519
+ .video-wrapper {{
520
+ position: relative;
521
+ padding-bottom: 56.25%;
522
+ height: 0;
523
+ overflow: hidden;
524
+ }}
525
+ .video-wrapper iframe {{
526
+ position: absolute;
527
+ top: 0;
528
+ left: 0;
529
+ width: 100%;
530
+ height: 100%;
531
+ border: none;
532
+ }}
533
+ .video-title {{
534
+ padding: 15px;
535
+ font-size: 1.2em;
536
+ font-weight: bold;
537
+ color: #2c3e50;
538
+ text-align: center;
539
+ background: #f8f9fa;
540
+ border-top: 1px solid #eee;
541
+ }}
542
+ .news-section {{
543
+ margin-top: 40px;
544
+ border-top: 2px solid #e9ecef;
545
+ padding-top: 20px;
546
+ }}
547
+ .news-section-title {{
548
+ font-size: 1.8em;
549
+ font-weight: bold;
550
+ color: #2c3e50;
551
+ margin-bottom: 20px;
552
+ text-align: center;
553
+ }}
554
+ .news-item {{
555
+ background: #ffffff;
556
+ border-radius: 10px;
557
+ box-shadow: 0 2px 10px rgba(0,0,0,0.1);
558
+ margin-bottom: 20px;
559
+ overflow: hidden;
560
+ }}
561
+ .news-date {{
562
+ padding: 10px 20px;
563
+ background: #f8f9fa;
564
+ color: #666;
565
+ font-size: 0.9em;
566
+ border-bottom: 1px solid #eee;
567
+ }}
568
+ .news-content {{
569
+ display: flex;
570
+ padding: 20px;
571
+ align-items: center;
572
+ gap: 30px;
573
+ }}
574
+ .news-video {{
575
+ flex: 0 0 300px;
576
+ }}
577
+ .news-text {{
578
+ flex: 1;
579
+ display: flex;
580
+ align-items: center;
581
+ min-height: 169px; /* Match 16:9 video height */
582
+ }}
583
+ .twitter-link {{
584
+ color: #2c3e50;
585
+ text-decoration: none;
586
+ display: flex;
587
+ align-items: center;
588
+ gap: 15px;
589
+ font-size: 1.4em;
590
+ font-weight: 600;
591
+ line-height: 1.4;
592
+ }}
593
+ .twitter-link:hover {{
594
+ color: #1da1f2;
595
+ }}
596
+ .twitter-icon {{
597
+ font-size: 1.5em;
598
+ color: #1da1f2;
599
+ }}
600
+ </style>
601
+ <div class="video-grid">
602
+ <div class="video-card">
603
+ <div class="video-wrapper">
604
+ <iframe src="https://www.youtube.com/embed/{mario_id}"></iframe>
605
+ </div>
606
+ <div class="video-title">๐ŸŽฎ Super Mario Bros</div>
607
+ </div>
608
+ <div class="video-card">
609
+ <div class="video-wrapper">
610
+ <iframe src="https://www.youtube.com/embed/{sokoban_id}"></iframe>
611
+ </div>
612
+ <div class="video-title">๐Ÿ“ฆ Sokoban</div>
613
+ </div>
614
+ <div class="video-card">
615
+ <div class="video-wrapper">
616
+ <iframe src="https://www.youtube.com/embed/{game_2048_id}"></iframe>
617
+ </div>
618
+ <div class="video-title">๐Ÿ”ข 2048</div>
619
+ </div>
620
+ <div class="video-card">
621
+ <div class="video-wrapper">
622
+ <iframe src="https://www.youtube.com/embed/{candy_id}"></iframe>
623
+ </div>
624
+ <div class="video-title">๐Ÿฌ Candy Crash</div>
625
+ </div>
626
+ </div>
627
+ <div class="news-section">
628
+ <div class="news-section-title">๐Ÿ“ฐ Latest News</div>
629
+ {news_html}
630
+ </div>
631
+ </div>
632
+ '''
633
+ return gr.HTML(gallery_html)
634
+
635
+ def build_app():
636
+ with gr.Blocks(css="""
637
+ .visualization-container {
638
+ height: 85vh !important;
639
+ max-height: 900px !important;
640
+ min-height: 600px !important;
641
+ background-color: #f8f9fa;
642
+ border-radius: 10px;
643
+ padding: 25px; /* Increased padding */
644
+ box-shadow: 0 2px 4px rgba(0,0,0,0.1);
645
+ overflow: hidden;
646
+ margin: 0 auto !important; /* Center the visualization */
647
+ }
648
+ .visualization-container .plot {
649
+ height: 100% !important;
650
+ width: 100% !important;
651
+ }
652
+ .section-title {
653
+ font-size: 1.5em;
654
+ font-weight: bold;
655
+ color: #2c3e50;
656
+ margin-bottom: 15px;
657
+ padding-bottom: 10px;
658
+ border-bottom: 2px solid #e9ecef;
659
+ text-align: center; /* Center the title */
660
+ }
661
+ /* Add container for the entire app */
662
+ .container {
663
+ max-width: 1400px;
664
+ margin: 0 auto;
665
+ padding: 0 20px;
666
+ }
667
+ """) as demo:
668
+ gr.Markdown("# ๐ŸŽฎ Game Arena: Gaming Agent ๐ŸŽฒ")
669
+
670
+ with gr.Tabs():
671
+ with gr.Tab("๐Ÿ† Leaderboard"):
672
+ # Visualization section at the very top
673
  with gr.Row():
674
+ gr.Markdown("### ๐Ÿ“Š Data Visualization")
675
+ with gr.Row():
676
+ visualization = gr.Plot(
677
+ value=get_combined_leaderboard_with_group_bar(rank_data, {
678
+ "Super Mario Bros": True,
679
+ "Sokoban": True,
680
+ "2048": True,
681
+ "Candy Crash": True,
682
+ "Tetris (complete)": True,
683
+ "Tetris (planning only)": True
684
+ })[1],
685
+ label="Performance Visualization",
686
+ elem_classes="visualization-container"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
687
  )
688
 
689
+ # Game selection section
690
+ with gr.Row():
691
+ gr.Markdown("### ๐ŸŽฎ Game Selection")
692
+ with gr.Row():
693
+ # For each game, we have two checkboxes: one for overall and one for detailed view.
694
+ with gr.Column():
695
+ gr.Markdown("**๐ŸŽฎ Super Mario Bros**")
696
+ mario_overall = gr.Checkbox(label="Super Mario Bros Score", value=True)
697
+ mario_details = gr.Checkbox(label="Super Mario Bros Details", value=False)
698
+ with gr.Column():
699
+ gr.Markdown("**๐Ÿ“ฆ Sokoban**")
700
+ sokoban_overall = gr.Checkbox(label="Sokoban Score", value=True)
701
+ sokoban_details = gr.Checkbox(label="Sokoban Details", value=False)
702
+ with gr.Column():
703
+ gr.Markdown("**๐Ÿ”ข 2048**")
704
+ _2048_overall = gr.Checkbox(label="2048 Score", value=True)
705
+ _2048_details = gr.Checkbox(label="2048 Details", value=False)
706
+ with gr.Column():
707
+ gr.Markdown("**๐Ÿฌ Candy Crash**")
708
+ candy_overall = gr.Checkbox(label="Candy Crash Score", value=True)
709
+ candy_details = gr.Checkbox(label="Candy Crash Details", value=False)
710
+ with gr.Column():
711
+ gr.Markdown("**๐ŸŽฏ Tetris (complete)**")
712
+ tetris_overall = gr.Checkbox(label="Tetris (complete) Score", value=True)
713
+ tetris_details = gr.Checkbox(label="Tetris (complete) Details", value=False)
714
+ with gr.Column():
715
+ gr.Markdown("**๐Ÿ“‹ Tetris (planning)**")
716
+ tetris_plan_overall = gr.Checkbox(label="Tetris (planning) Score", value=True)
717
+ tetris_plan_details = gr.Checkbox(label="Tetris (planning) Details", value=False)
718
+
719
+ # Time progression display and control buttons - Moved below game selection
720
+ with gr.Row():
721
+ with gr.Column(scale=2):
722
+ gr.Markdown("**โฐ Time Tracker**")
723
+ timeline = create_timeline_slider()
724
+ with gr.Column(scale=1):
725
+ gr.Markdown("**๐Ÿ”„ Controls**")
726
+ clear_btn = gr.Button("Reset Filters", variant="secondary")
727
+
728
+ # Leaderboard table section
729
+ with gr.Row():
730
+ gr.Markdown("### ๐Ÿ“‹ Detailed Results")
731
+ with gr.Row():
732
+ leaderboard_board = gr.DataFrame(
733
+ value=get_combined_leaderboard(rank_data, {
734
+ "Super Mario Bros": True,
735
+ "Sokoban": True,
736
+ "2048": True,
737
+ "Candy Crash": True,
738
+ "Tetris (complete)": True,
739
+ "Tetris (planning only)": True
740
+ }),
741
  interactive=True,
742
+ wrap=True,
743
+ label="Leaderboard"
744
  )
745
+
746
+ # List of all checkboxes (in order)
747
+ checkbox_list = [mario_overall, mario_details,
748
+ sokoban_overall, sokoban_details,
749
+ _2048_overall, _2048_details,
750
+ candy_overall, candy_details,
751
+ tetris_overall, tetris_details,
752
+ tetris_plan_overall, tetris_plan_details]
753
+
754
+ # Initialize the leaderboard state when the app starts
755
+ demo.load(
756
+ fn=clear_filters,
757
+ inputs=[],
758
+ outputs=[leaderboard_board, visualization] + checkbox_list
759
+ )
760
+
761
+ # Update both the leaderboard and visualization when checkboxes change
762
+ for checkbox in checkbox_list:
763
+ checkbox.change(
764
+ fn=update_leaderboard,
765
+ inputs=checkbox_list,
766
+ outputs=[leaderboard_board, visualization] + checkbox_list
767
  )
768
+
769
+ # Update both when clear button is clicked
770
+ clear_btn.click(
771
+ fn=clear_filters,
772
+ inputs=[],
773
+ outputs=[leaderboard_board, visualization] + checkbox_list
774
+ )
775
+
776
+ with gr.Tab("๐ŸŽฅ Gallery"):
777
+ video_gallery = create_video_gallery()
778
+
779
+ return demo
780
+
781
+ if __name__ == "__main__":
782
+ demo_app = build_app()
783
+ # Add file serving configuration
784
+ demo_app.launch(debug=True, show_error=True, share=True)