Spaces:
Runtime error
Runtime error
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")
|