siro1's picture
siro1 HF Staff
Fix: remove print
8c3ba86
from typing import Callable
import gradio as gr
import asyncio
import time
import threading
from src.retrieve_data import (
get_gpus_for_leaderboard,
get_leaderboard_names,
get_leaderboard_submissions,
get_submission_count,
)
from src.envs import CACHE_TIMEOUT, BACKGROUND_REFRESH_INTERVAL
# key: func_name:args:kwargs, value: (timestamp, data)
cache = {}
active_selections = {
"leaderboard": None,
"gpu": None,
}
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
background_refresh_running = True
def cached_fetch(
func: Callable, *args, force_refresh=False, limit=None, offset=0, **kwargs
):
"""Fetch data with caching to avoid redundant API calls"""
cache_key = (
f"{func.__name__}:{str(args)}:{str(kwargs)}:limit={limit}:offset={offset}"
)
current_time = time.time()
if not force_refresh and cache_key in cache:
timestamp, data = cache[cache_key]
if current_time - timestamp < CACHE_TIMEOUT:
return data
print(f"Fetching {cache_key}")
if func.__name__ == "get_leaderboard_submissions":
result = loop.run_until_complete(
func(*args, limit=limit, offset=offset, **kwargs)
)
else:
result = loop.run_until_complete(func(*args, **kwargs))
cache[cache_key] = (current_time, result)
return result
def invalidate_cache(prefix=None):
"""Invalidate all cache entries or those matching a prefix"""
global cache
if prefix is None:
cache = {}
else:
cache = {k: v for k, v in cache.items() if not k.startswith(prefix)}
def background_refresh():
"""Background thread to refresh active data periodically"""
while background_refresh_running:
try:
time.sleep(BACKGROUND_REFRESH_INTERVAL)
lb_name = active_selections["leaderboard"]
gpu_name = active_selections["gpu"]
if lb_name and gpu_name:
cached_fetch(
get_leaderboard_submissions, lb_name, gpu_name, force_refresh=True
)
cached_fetch(get_gpus_for_leaderboard, lb_name, force_refresh=True)
cached_fetch(get_leaderboard_names, force_refresh=True)
except Exception as e:
print(f"Background refresh error: {e}")
def build_ui():
# Define the function first before using it
def create_table_for_lb_with_global_rank(lb_data, offset):
"""Create table with global ranks instead of page-specific ranks"""
headers = [
"Rank",
"User Name",
"Submission ID",
"Submission Name",
"Runtime (ms)",
"Submission Date",
]
rows = []
for i, result in enumerate(lb_data.results, 1):
# Calculate global rank by adding offset
global_rank = i + offset
# Only show medals for the top 3 overall and only on the first page
if offset == 0 and global_rank <= 3: # first page and top 3
if global_rank == 1:
rank_display = "๐Ÿฅ‡ 1"
elif global_rank == 2:
rank_display = "๐Ÿฅˆ 2"
elif global_rank == 3:
rank_display = "๐Ÿฅ‰ 3"
else:
rank_display = str(global_rank)
score = float(result.submission_score) * 1000
rows.append(
[
rank_display,
result.user_name,
str(result.submission_id), # Add submission ID as a new column
result.submission_name,
f"{score:.4f}",
result.submission_time.strftime("%Y-%m-%d %H:%M:%S"),
]
)
# Apply different class based on whether it's the first page or not
elem_classes = "" if offset == 0 else "non-first-page-table"
df = gr.Dataframe(
headers=headers,
datatype=[
"str",
"str",
"str", # Submission ID
"str",
"str",
"timestamp",
],
value=rows,
interactive=False,
elem_classes=elem_classes,
)
return df
with gr.Blocks(
title="ML Leaderboards",
theme=gr.themes.Soft(),
css="""
/* Apply medal colors to all tables by default */
.gradio-container table tr:nth-child(1) {
background-color: rgba(255, 215, 0, 0.2) !important; /* Gold */
}
.gradio-container table tr:nth-child(2) {
background-color: rgba(192, 192, 192, 0.2) !important; /* Silver */
}
.gradio-container table tr:nth-child(3) {
background-color: rgba(205, 127, 50, 0.2) !important; /* Bronze */
}
/* Remove medal colors for non-first pages */
.non-first-page-table tr:nth-child(1),
.non-first-page-table tr:nth-child(2),
.non-first-page-table tr:nth-child(3) {
background-color: inherit !important;
}
.pagination-controls {
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 10px;
width: 100%;
}
.pagination-info {
text-align: center;
flex-grow: 1;
}
.pagination-button {
min-width: 100px;
}
""",
) as app:
gr.Markdown("# ๐Ÿฟ KernelBot Leaderboard ๐Ÿฟ")
lb_names = cached_fetch(get_leaderboard_names)
selected_lb = lb_names[0]
gpu_names = cached_fetch(get_gpus_for_leaderboard, selected_lb)
selected_gpu = gpu_names[0]
# Set default pagination values
items_per_page = 10
current_page = 1
data = cached_fetch(
get_leaderboard_submissions,
selected_lb,
selected_gpu,
limit=items_per_page,
offset=0,
)
total_count = cached_fetch(get_submission_count, selected_lb, selected_gpu)
total_pages = (total_count + items_per_page - 1) // items_per_page
with gr.Row():
with gr.Column(scale=1):
lb_dropdown = gr.Dropdown(
choices=lb_names,
label="Select Leaderboard",
interactive=True,
value=selected_lb,
)
gpu_dropdown = gr.Dropdown(
choices=gpu_names,
label="Select GPU",
interactive=True,
value=selected_gpu,
)
with gr.Row():
# Initial table is first page
results_table = create_table_for_lb_with_global_rank(data, 0)
with gr.Row(elem_classes="pagination-controls"):
with gr.Column(scale=1, min_width=100, elem_classes="pagination-button"):
prev_btn = gr.Button("โ† Previous", interactive=(current_page > 1))
with gr.Column(scale=2, elem_classes="pagination-info"):
page_info = gr.Markdown(f"Page {current_page} of {total_pages}")
with gr.Column(scale=1, min_width=100, elem_classes="pagination-button"):
next_btn = gr.Button("Next โ†’", interactive=(current_page < total_pages))
def on_lb_change(lb_name):
gpu_choices = cached_fetch(get_gpus_for_leaderboard, lb_name)
active_selections["leaderboard"] = lb_name
if gpu_choices:
active_selections["gpu"] = gpu_choices[0]
# Reset to page 1 when changing leaderboard
data = cached_fetch(
get_leaderboard_submissions,
lb_name,
gpu_choices[0] if gpu_choices else None,
limit=items_per_page,
offset=0,
)
# Get total count for pagination
total_count = cached_fetch(
get_submission_count, lb_name, gpu_choices[0] if gpu_choices else None
)
total_pages = (total_count + items_per_page - 1) // items_per_page
return (
gr.update(
choices=gpu_choices, value=gpu_choices[0] if gpu_choices else None
),
create_table_for_lb_with_global_rank(data, 0),
gr.update(value=f"Page 1 of {total_pages}"),
gr.update(interactive=False), # prev button disabled on page 1
gr.update(
interactive=(total_pages > 1)
), # next button enabled if more than 1 page
)
def update_table(lb_name, gpu_name, page=1):
if not gpu_name:
return None, gr.update(), gr.update(), gr.update()
active_selections["gpu"] = gpu_name
offset = (page - 1) * items_per_page
data = cached_fetch(
get_leaderboard_submissions,
lb_name,
gpu_name,
limit=items_per_page,
offset=offset,
)
# Get total count for pagination
total_count = cached_fetch(get_submission_count, lb_name, gpu_name)
total_pages = (total_count + items_per_page - 1) // items_per_page
# Create table with global ranks
table = create_table_for_lb_with_global_rank(data, offset)
return (
table,
gr.update(value=f"Page {page} of {total_pages}"),
gr.update(interactive=(page > 1)),
gr.update(interactive=(page < total_pages)),
)
def next_page():
nonlocal current_page
lb_name = active_selections["leaderboard"]
gpu_name = active_selections["gpu"]
# Get total count to check if we can go to next page
total_count = cached_fetch(get_submission_count, lb_name, gpu_name)
total_pages = (total_count + items_per_page - 1) // items_per_page
if current_page < total_pages:
current_page += 1
return update_table(lb_name, gpu_name, current_page)
return update_table(lb_name, gpu_name, current_page)
def prev_page():
nonlocal current_page
if current_page > 1:
current_page -= 1
lb_name = active_selections["leaderboard"]
gpu_name = active_selections["gpu"]
return update_table(lb_name, gpu_name, current_page)
lb_dropdown.change(
fn=on_lb_change,
inputs=[lb_dropdown],
outputs=[gpu_dropdown, results_table, page_info, prev_btn, next_btn],
)
gpu_dropdown.change(
fn=lambda lb, gpu: update_table(lb, gpu, 1), # Reset to page 1
inputs=[lb_dropdown, gpu_dropdown],
outputs=[results_table, page_info, prev_btn, next_btn],
)
next_btn.click(
fn=next_page,
inputs=[],
outputs=[results_table, page_info, prev_btn, next_btn],
)
prev_btn.click(
fn=prev_page,
inputs=[],
outputs=[results_table, page_info, prev_btn, next_btn],
)
return app
if __name__ == "__main__":
try:
background_thread = threading.Thread(target=background_refresh, daemon=True)
background_thread.start()
app = build_ui()
app.launch()
finally:
background_refresh_running = False
background_thread.join(timeout=1.0)
loop.close()