Spaces:
Running
on
CPU Upgrade
Running
on
CPU Upgrade
Update app.
Browse files
app.py
CHANGED
@@ -7,7 +7,7 @@ from gradio.themes import Base, colors, sizes
|
|
7 |
from gradio_leaderboard import Leaderboard, SelectColumns
|
8 |
from huggingface_hub import whoami
|
9 |
|
10 |
-
#
|
11 |
from src.about import CITATION_BUTTON_LABEL, CITATION_BUTTON_TEXT, EVALUATION_QUEUE_TEXT, WHAT_IS_F1_HTML
|
12 |
from src.datamodel.data import F1Data
|
13 |
from src.display.css_html_js import custom_css
|
@@ -21,8 +21,8 @@ from src.validation.validate import MAX_INPUT_LENGTH, MIN_INPUT_LENGTH, is_submi
|
|
21 |
|
22 |
logger = get_logger(__name__)
|
23 |
|
24 |
-
ENSURE_ALL_PRESENT = False
|
25 |
-
SPLIT = "warmup"
|
26 |
|
27 |
lbdb = F1Data(
|
28 |
cp_ds_name=CODE_PROBLEMS_REPO,
|
@@ -32,6 +32,7 @@ lbdb = F1Data(
|
|
32 |
)
|
33 |
|
34 |
leaderboard_df = None
|
|
|
35 |
logger.info("Initialized LBDB")
|
36 |
|
37 |
|
@@ -41,23 +42,29 @@ def restart_space():
|
|
41 |
|
42 |
|
43 |
def refresh_leaderboard_data():
|
|
|
44 |
global leaderboard_df
|
45 |
try:
|
46 |
logger.info("Loading leaderboard data...")
|
47 |
new_leaderboard_df = get_leaderboard_df(RESULTS_REPO)
|
|
|
48 |
if new_leaderboard_df is not None:
|
49 |
logger.info("Leaderboard data refreshed successfully")
|
50 |
leaderboard_df = new_leaderboard_df
|
51 |
else:
|
52 |
logger.warning("No new leaderboard data found")
|
|
|
53 |
except Exception as e:
|
54 |
logger.error(f"Error refreshing leaderboard data: {e}")
|
|
|
55 |
|
56 |
|
57 |
def init_leaderboard(dataframe: pd.DataFrame):
|
|
|
58 |
if dataframe is None:
|
59 |
raise ValueError("Leaderboard DataFrame is None.")
|
60 |
-
|
|
|
61 |
value=dataframe,
|
62 |
datatype=[c.type for c in fields(AutoEvalColumn)],
|
63 |
select_columns=SelectColumns(
|
@@ -70,6 +77,8 @@ def init_leaderboard(dataframe: pd.DataFrame):
|
|
70 |
bool_checkboxgroup_label="Hide models",
|
71 |
interactive=False,
|
72 |
)
|
|
|
|
|
73 |
|
74 |
|
75 |
def add_solution_cbk(
|
@@ -80,33 +89,67 @@ def add_solution_cbk(
|
|
80 |
profile: gr.OAuthProfile | None,
|
81 |
oauth_token: gr.OAuthToken | None,
|
82 |
):
|
|
|
|
|
|
|
|
|
83 |
if profile is None or oauth_token is None:
|
84 |
return styled_error("Please sign in with Hugging Face before submitting.")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
85 |
user_info = fetch_user_info(oauth_token)
|
|
|
86 |
stable_id = user_info.get("id") if user_info else None
|
|
|
|
|
87 |
if not stable_id:
|
88 |
return styled_error("Could not retrieve your stable user ID. Please try signing in again.")
|
|
|
|
|
89 |
if not profile.username:
|
90 |
return styled_error("Could not retrieve username. Please try signing in again.")
|
|
|
|
|
|
|
91 |
try:
|
|
|
92 |
if not submission_path:
|
93 |
return styled_error("Please upload JSONL submission file.")
|
94 |
-
|
|
|
|
|
|
|
|
|
95 |
return styled_error("Failed to read JSONL submission file. Please try again later.")
|
96 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
97 |
if len(val) == 0:
|
98 |
return styled_error(f"Please fill in the '{val_name}' field.")
|
|
|
99 |
if not is_valid(val):
|
100 |
return styled_error(
|
101 |
-
f"{val_name} is invalid! Must only contain characters [a-zA-Z0-9], spaces,
|
|
|
|
|
102 |
)
|
103 |
except Exception:
|
104 |
logger.warning("Failed to process user submission", exc_info=True)
|
105 |
-
return styled_error("An error occurred. Please try again later.")
|
|
|
106 |
return add_new_solutions(
|
107 |
lbdb,
|
108 |
profile.username,
|
109 |
-
|
110 |
system_name,
|
111 |
org,
|
112 |
sys_type,
|
@@ -117,32 +160,46 @@ def add_solution_cbk(
|
|
117 |
|
118 |
|
119 |
def gate_submission(oauth_token: gr.OAuthToken | None):
|
|
|
|
|
|
|
|
|
120 |
if oauth_token is None:
|
|
|
121 |
return gr.update(visible=True), gr.update(visible=False)
|
122 |
try:
|
123 |
whoami(oauth_token.token)
|
|
|
124 |
return gr.update(visible=False), gr.update(visible=True)
|
125 |
except Exception:
|
|
|
126 |
return gr.update(visible=True), gr.update(visible=False)
|
127 |
|
128 |
|
129 |
def get_theme():
|
130 |
-
|
131 |
-
|
132 |
-
|
133 |
-
|
134 |
-
|
|
|
|
|
|
|
|
|
135 |
spacing_size=sizes.spacing_md,
|
136 |
radius_size=sizes.radius_md,
|
137 |
).set(
|
138 |
-
|
139 |
-
|
140 |
-
|
|
|
141 |
)
|
|
|
142 |
|
143 |
|
144 |
blocks = gr.Blocks(css=custom_css, theme=get_theme())
|
145 |
with blocks:
|
|
|
146 |
gr.Image(
|
147 |
"assets/banner.png",
|
148 |
interactive=False,
|
@@ -152,24 +209,37 @@ with blocks:
|
|
152 |
elem_classes=["banner_image"],
|
153 |
)
|
154 |
|
155 |
-
#
|
|
|
|
|
156 |
with gr.Tabs(elem_classes="tab-buttons") as tabs:
|
|
|
157 |
with gr.TabItem("What is FormulaOne", id=0):
|
158 |
gr.HTML(WHAT_IS_F1_HTML)
|
159 |
|
160 |
-
|
161 |
-
|
162 |
-
|
|
|
163 |
leaderboard_component = init_leaderboard(leaderboard_df)
|
164 |
|
165 |
-
|
|
|
|
|
166 |
with gr.Column():
|
167 |
-
gr.
|
|
|
|
|
|
|
168 |
gr.Markdown("# ✉️✨ Submit your solutions", elem_classes="markdown-text")
|
|
|
|
|
169 |
login_box = gr.Group(visible=True)
|
170 |
with login_box:
|
171 |
gr.Markdown("Please sign in with Hugging Face to submit")
|
172 |
gr.LoginButton()
|
|
|
|
|
173 |
submit_panel = gr.Group(visible=False)
|
174 |
with submit_panel:
|
175 |
with gr.Row():
|
@@ -183,25 +253,45 @@ with blocks:
|
|
183 |
value=ModelType.LLM.to_str(),
|
184 |
interactive=True,
|
185 |
)
|
|
|
186 |
submission_file = gr.File(label="JSONL solutions file", file_types=[".jsonl"])
|
|
|
|
|
187 |
submit_button = gr.Button("Submit", variant="primary")
|
188 |
submission_result = gr.Markdown()
|
|
|
189 |
submit_button.click(
|
190 |
add_solution_cbk,
|
191 |
-
[
|
|
|
|
|
|
|
|
|
|
|
192 |
submission_result,
|
193 |
)
|
194 |
|
195 |
with gr.Row():
|
|
|
196 |
with gr.Accordion(CITATION_BUTTON_LABEL, open=False):
|
197 |
-
gr.Code(
|
|
|
|
|
|
|
198 |
|
|
|
|
|
199 |
blocks.load(lambda: leaderboard_df, inputs=[], outputs=[leaderboard_component])
|
|
|
|
|
200 |
blocks.load(gate_submission, inputs=None, outputs=[login_box, submit_panel])
|
201 |
|
|
|
|
|
202 |
scheduler = BackgroundScheduler()
|
203 |
scheduler.add_job(restart_space, "interval", seconds=1800)
|
204 |
scheduler.add_job(refresh_leaderboard_data, "interval", seconds=120)
|
205 |
scheduler.start()
|
206 |
-
|
207 |
blocks.queue(default_concurrency_limit=40).launch()
|
|
|
|
7 |
from gradio_leaderboard import Leaderboard, SelectColumns
|
8 |
from huggingface_hub import whoami
|
9 |
|
10 |
+
# MODIFICATION: Changed imports from `about.py`
|
11 |
from src.about import CITATION_BUTTON_LABEL, CITATION_BUTTON_TEXT, EVALUATION_QUEUE_TEXT, WHAT_IS_F1_HTML
|
12 |
from src.datamodel.data import F1Data
|
13 |
from src.display.css_html_js import custom_css
|
|
|
21 |
|
22 |
logger = get_logger(__name__)
|
23 |
|
24 |
+
ENSURE_ALL_PRESENT = False # TODO: Switch to True.
|
25 |
+
SPLIT = "warmup" # TODO temp
|
26 |
|
27 |
lbdb = F1Data(
|
28 |
cp_ds_name=CODE_PROBLEMS_REPO,
|
|
|
32 |
)
|
33 |
|
34 |
leaderboard_df = None
|
35 |
+
|
36 |
logger.info("Initialized LBDB")
|
37 |
|
38 |
|
|
|
42 |
|
43 |
|
44 |
def refresh_leaderboard_data():
|
45 |
+
"""Refresh the leaderboard data from the latest results"""
|
46 |
global leaderboard_df
|
47 |
try:
|
48 |
logger.info("Loading leaderboard data...")
|
49 |
new_leaderboard_df = get_leaderboard_df(RESULTS_REPO)
|
50 |
+
|
51 |
if new_leaderboard_df is not None:
|
52 |
logger.info("Leaderboard data refreshed successfully")
|
53 |
leaderboard_df = new_leaderboard_df
|
54 |
else:
|
55 |
logger.warning("No new leaderboard data found")
|
56 |
+
return None
|
57 |
except Exception as e:
|
58 |
logger.error(f"Error refreshing leaderboard data: {e}")
|
59 |
+
return None
|
60 |
|
61 |
|
62 |
def init_leaderboard(dataframe: pd.DataFrame):
|
63 |
+
|
64 |
if dataframe is None:
|
65 |
raise ValueError("Leaderboard DataFrame is None.")
|
66 |
+
|
67 |
+
lb = Leaderboard(
|
68 |
value=dataframe,
|
69 |
datatype=[c.type for c in fields(AutoEvalColumn)],
|
70 |
select_columns=SelectColumns(
|
|
|
77 |
bool_checkboxgroup_label="Hide models",
|
78 |
interactive=False,
|
79 |
)
|
80 |
+
lb.col_count = (1, "fixed")
|
81 |
+
return lb
|
82 |
|
83 |
|
84 |
def add_solution_cbk(
|
|
|
89 |
profile: gr.OAuthProfile | None,
|
90 |
oauth_token: gr.OAuthToken | None,
|
91 |
):
|
92 |
+
logger.info("Fetching user details for submission")
|
93 |
+
logger.info("PROFILE %s", profile)
|
94 |
+
logger.info("TOKEN %s", oauth_token)
|
95 |
+
|
96 |
if profile is None or oauth_token is None:
|
97 |
return styled_error("Please sign in with Hugging Face before submitting.")
|
98 |
+
|
99 |
+
# Display handle and display name (may change over time)
|
100 |
+
logger.info(f"User handle: {profile.username}")
|
101 |
+
display_name = profile.name or profile.username
|
102 |
+
logger.info(f"Display name: {display_name}")
|
103 |
+
|
104 |
+
# Stable account id
|
105 |
user_info = fetch_user_info(oauth_token)
|
106 |
+
logger.info("Logged in user info: %s", user_info)
|
107 |
stable_id = user_info.get("id") if user_info else None
|
108 |
+
logger.info(f"User stable ID: {stable_id}")
|
109 |
+
|
110 |
if not stable_id:
|
111 |
return styled_error("Could not retrieve your stable user ID. Please try signing in again.")
|
112 |
+
user_id = stable_id
|
113 |
+
|
114 |
if not profile.username:
|
115 |
return styled_error("Could not retrieve username. Please try signing in again.")
|
116 |
+
# We rely on underscores as separators in submission ID, replace it with "-".
|
117 |
+
# user_id = profile.username.replace("_", "-")
|
118 |
+
|
119 |
try:
|
120 |
+
# Validating the submission file.
|
121 |
if not submission_path:
|
122 |
return styled_error("Please upload JSONL submission file.")
|
123 |
+
|
124 |
+
if not is_submission_file_valid(
|
125 |
+
submission_path,
|
126 |
+
is_warmup_dataset=(SPLIT == "warmup"),
|
127 |
+
):
|
128 |
return styled_error("Failed to read JSONL submission file. Please try again later.")
|
129 |
+
|
130 |
+
# Validating all user-supplied arguments.
|
131 |
+
for val, val_name in [
|
132 |
+
(system_name, "System name"),
|
133 |
+
(org, "Organisation name"),
|
134 |
+
(sys_type, "System type"),
|
135 |
+
]:
|
136 |
if len(val) == 0:
|
137 |
return styled_error(f"Please fill in the '{val_name}' field.")
|
138 |
+
|
139 |
if not is_valid(val):
|
140 |
return styled_error(
|
141 |
+
f"{val_name} is invalid! Must only contain characters [a-zA-Z0-9], spaces, "
|
142 |
+
+ "or the special characters '-' and '.', and be of length between "
|
143 |
+
+ f"{MIN_INPUT_LENGTH} and {MAX_INPUT_LENGTH}."
|
144 |
)
|
145 |
except Exception:
|
146 |
logger.warning("Failed to process user submission", exc_info=True)
|
147 |
+
return styled_error("An error occurred. Please try again later.") # Intentionally vague.
|
148 |
+
|
149 |
return add_new_solutions(
|
150 |
lbdb,
|
151 |
profile.username,
|
152 |
+
user_id,
|
153 |
system_name,
|
154 |
org,
|
155 |
sys_type,
|
|
|
160 |
|
161 |
|
162 |
def gate_submission(oauth_token: gr.OAuthToken | None):
|
163 |
+
"""
|
164 |
+
@brief Toggles the visibility of the login box and submission panel based on the user's login status.
|
165 |
+
"""
|
166 |
+
logger.info("GATE TOKEN %s", oauth_token)
|
167 |
if oauth_token is None:
|
168 |
+
logger.info("GATE: NO TOKEN")
|
169 |
return gr.update(visible=True), gr.update(visible=False)
|
170 |
try:
|
171 |
whoami(oauth_token.token)
|
172 |
+
logger.info("GATE: TOKEN IS VALID")
|
173 |
return gr.update(visible=False), gr.update(visible=True)
|
174 |
except Exception:
|
175 |
+
logger.info("GATE: TOKEN HAS EXPIRED")
|
176 |
return gr.update(visible=True), gr.update(visible=False)
|
177 |
|
178 |
|
179 |
def get_theme():
|
180 |
+
cyber_theme = Base(
|
181 |
+
# neon-ish accents driven by hues (affects tabs, primary buttons, sliders, etc.)
|
182 |
+
primary_hue=colors.cyan, # selected tab / primary controls
|
183 |
+
secondary_hue=colors.pink, # secondary accents
|
184 |
+
neutral_hue=colors.gray, # keep neutrals subtle
|
185 |
+
# # techno font
|
186 |
+
# font=gr.themes.GoogleFont("Orbitron"),
|
187 |
+
# font_mono=gr.themes.GoogleFont("JetBrains Mono"),
|
188 |
+
text_size=sizes.text_md, # keep defaults
|
189 |
spacing_size=sizes.spacing_md,
|
190 |
radius_size=sizes.radius_md,
|
191 |
).set(
|
192 |
+
# keep overrides minimal—dark canvas; let hues do the rest
|
193 |
+
body_background_fill="#0b0f14", # deep blue-black
|
194 |
+
background_fill_primary="#0b0f14", # panels
|
195 |
+
background_fill_secondary="#0e141a", # subtle contrast
|
196 |
)
|
197 |
+
return cyber_theme
|
198 |
|
199 |
|
200 |
blocks = gr.Blocks(css=custom_css, theme=get_theme())
|
201 |
with blocks:
|
202 |
+
|
203 |
gr.Image(
|
204 |
"assets/banner.png",
|
205 |
interactive=False,
|
|
|
209 |
elem_classes=["banner_image"],
|
210 |
)
|
211 |
|
212 |
+
# MODIFICATION: Removed the top-level gr.HTML(TITLE) and gr.Markdown(INTRODUCTION_TEXT)
|
213 |
+
# The entire layout is now inside the gr.Tabs component.
|
214 |
+
|
215 |
with gr.Tabs(elem_classes="tab-buttons") as tabs:
|
216 |
+
# MODIFICATION: Added a new TabItem for the "What is FormulaOne" page
|
217 |
with gr.TabItem("What is FormulaOne", id=0):
|
218 |
gr.HTML(WHAT_IS_F1_HTML)
|
219 |
|
220 |
+
# MODIFICATION: Changed the label and ID for the Leaderboard tab
|
221 |
+
with gr.TabItem("🏅 FormulaOne Leaderboard", elem_id="formulaone-leaderboard-tab-table", id=1):
|
222 |
+
refresh_leaderboard_data() # updates leaderboard_df
|
223 |
+
assert leaderboard_df is not None
|
224 |
leaderboard_component = init_leaderboard(leaderboard_df)
|
225 |
|
226 |
+
# MODIFICATION: Changed the label and ID for the Submit Solutions tab
|
227 |
+
with gr.TabItem("🚀 Submit Solutions", elem_id="formulaone-submit-tab-table", id=2):
|
228 |
+
logger.info("Tab submission")
|
229 |
with gr.Column():
|
230 |
+
with gr.Row():
|
231 |
+
gr.Markdown(EVALUATION_QUEUE_TEXT, elem_classes="markdown-text")
|
232 |
+
|
233 |
+
with gr.Row():
|
234 |
gr.Markdown("# ✉️✨ Submit your solutions", elem_classes="markdown-text")
|
235 |
+
|
236 |
+
# Shown when logged OUT
|
237 |
login_box = gr.Group(visible=True)
|
238 |
with login_box:
|
239 |
gr.Markdown("Please sign in with Hugging Face to submit")
|
240 |
gr.LoginButton()
|
241 |
+
|
242 |
+
# Shown when logged IN
|
243 |
submit_panel = gr.Group(visible=False)
|
244 |
with submit_panel:
|
245 |
with gr.Row():
|
|
|
253 |
value=ModelType.LLM.to_str(),
|
254 |
interactive=True,
|
255 |
)
|
256 |
+
|
257 |
submission_file = gr.File(label="JSONL solutions file", file_types=[".jsonl"])
|
258 |
+
|
259 |
+
logger.info("Submit button")
|
260 |
submit_button = gr.Button("Submit", variant="primary")
|
261 |
submission_result = gr.Markdown()
|
262 |
+
|
263 |
submit_button.click(
|
264 |
add_solution_cbk,
|
265 |
+
[
|
266 |
+
system_name_textbox,
|
267 |
+
org_textbox,
|
268 |
+
sys_type_dropdown,
|
269 |
+
submission_file,
|
270 |
+
],
|
271 |
submission_result,
|
272 |
)
|
273 |
|
274 |
with gr.Row():
|
275 |
+
logger.info("Citation")
|
276 |
with gr.Accordion(CITATION_BUTTON_LABEL, open=False):
|
277 |
+
gr.Code(
|
278 |
+
value=CITATION_BUTTON_TEXT.strip(),
|
279 |
+
elem_id="citation-block",
|
280 |
+
)
|
281 |
|
282 |
+
# UI refresh triggers latest data swap.
|
283 |
+
# The work already happened in the background - refresh_leaderboard_data().
|
284 |
blocks.load(lambda: leaderboard_df, inputs=[], outputs=[leaderboard_component])
|
285 |
+
|
286 |
+
# On initial load (and after OAuth redirect), toggle the UI based on login status.
|
287 |
blocks.load(gate_submission, inputs=None, outputs=[login_box, submit_panel])
|
288 |
|
289 |
+
|
290 |
+
logger.info("Scheduler")
|
291 |
scheduler = BackgroundScheduler()
|
292 |
scheduler.add_job(restart_space, "interval", seconds=1800)
|
293 |
scheduler.add_job(refresh_leaderboard_data, "interval", seconds=120)
|
294 |
scheduler.start()
|
295 |
+
logger.info("Launch")
|
296 |
blocks.queue(default_concurrency_limit=40).launch()
|
297 |
+
logger.info("Done")
|