Spaces:
Running
Running
openhands commited on
Commit ·
974f31f
1
Parent(s): 361b5c2
Add timer-based auto-refresh for leaderboard data
Browse filesWhen background data refresh occurs, the UI now automatically updates
within 60 seconds without requiring a page reload. This fixes the issue
where new results pushed to the GitHub repo weren't reflected on the
live site until the HF Space container was restarted.
Changes:
- Add data version tracking to detect when cache is cleared
- Add gr.Timer() that checks for data updates every 60 seconds
- Automatically refresh DataFrame and Plot components when new data is available
- ui_components.py +85 -2
ui_components.py
CHANGED
|
@@ -365,6 +365,13 @@ plot_legend_html = f"""
|
|
| 365 |
CACHED_VIEWERS = {}
|
| 366 |
CACHED_TAG_MAPS = {}
|
| 367 |
_cache_lock = __import__('threading').Lock()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 368 |
|
| 369 |
|
| 370 |
def clear_viewer_cache():
|
|
@@ -372,11 +379,12 @@ def clear_viewer_cache():
|
|
| 372 |
Clear all cached viewers and tag maps.
|
| 373 |
Called when data is refreshed from the background scheduler.
|
| 374 |
"""
|
| 375 |
-
global CACHED_VIEWERS, CACHED_TAG_MAPS
|
| 376 |
with _cache_lock:
|
| 377 |
CACHED_VIEWERS.clear()
|
| 378 |
CACHED_TAG_MAPS.clear()
|
| 379 |
-
|
|
|
|
| 380 |
|
| 381 |
|
| 382 |
# Register the cache clear callback with the data refresh system
|
|
@@ -457,7 +465,13 @@ def create_leaderboard_display(
|
|
| 457 |
"""
|
| 458 |
This UI factory takes pre-loaded data and renders the main DataFrame and Plot
|
| 459 |
for a given category (e.g., "Overall" or "Literature Understanding").
|
|
|
|
|
|
|
|
|
|
| 460 |
"""
|
|
|
|
|
|
|
|
|
|
| 461 |
# 1. Instantiate the transformer and get the specific view for this category.
|
| 462 |
# The function no longer loads data itself; it filters the data it receives.
|
| 463 |
transformer = DataTransformer(full_df, tag_map)
|
|
@@ -664,6 +678,75 @@ def create_leaderboard_display(
|
|
| 664 |
|
| 665 |
legend_markdown = create_legend_markdown(category_name)
|
| 666 |
gr.HTML(value=legend_markdown, elem_id="legend-markdown")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 667 |
|
| 668 |
# Return the components so they can be referenced elsewhere.
|
| 669 |
return plot_component, dataframe_component
|
|
|
|
| 365 |
CACHED_VIEWERS = {}
|
| 366 |
CACHED_TAG_MAPS = {}
|
| 367 |
_cache_lock = __import__('threading').Lock()
|
| 368 |
+
_data_version = 0 # Incremented when data is refreshed
|
| 369 |
+
|
| 370 |
+
|
| 371 |
+
def get_data_version():
|
| 372 |
+
"""Get the current data version number."""
|
| 373 |
+
global _data_version
|
| 374 |
+
return _data_version
|
| 375 |
|
| 376 |
|
| 377 |
def clear_viewer_cache():
|
|
|
|
| 379 |
Clear all cached viewers and tag maps.
|
| 380 |
Called when data is refreshed from the background scheduler.
|
| 381 |
"""
|
| 382 |
+
global CACHED_VIEWERS, CACHED_TAG_MAPS, _data_version
|
| 383 |
with _cache_lock:
|
| 384 |
CACHED_VIEWERS.clear()
|
| 385 |
CACHED_TAG_MAPS.clear()
|
| 386 |
+
_data_version += 1
|
| 387 |
+
print(f"[CACHE] Viewer cache cleared after data refresh (version: {_data_version})")
|
| 388 |
|
| 389 |
|
| 390 |
# Register the cache clear callback with the data refresh system
|
|
|
|
| 465 |
"""
|
| 466 |
This UI factory takes pre-loaded data and renders the main DataFrame and Plot
|
| 467 |
for a given category (e.g., "Overall" or "Literature Understanding").
|
| 468 |
+
|
| 469 |
+
The display includes a timer that periodically checks for data updates and
|
| 470 |
+
refreshes the UI when new data is available.
|
| 471 |
"""
|
| 472 |
+
# Track the data version when this display was created
|
| 473 |
+
initial_data_version = get_data_version()
|
| 474 |
+
|
| 475 |
# 1. Instantiate the transformer and get the specific view for this category.
|
| 476 |
# The function no longer loads data itself; it filters the data it receives.
|
| 477 |
transformer = DataTransformer(full_df, tag_map)
|
|
|
|
| 678 |
|
| 679 |
legend_markdown = create_legend_markdown(category_name)
|
| 680 |
gr.HTML(value=legend_markdown, elem_id="legend-markdown")
|
| 681 |
+
|
| 682 |
+
# Add a timer to periodically check for data updates and refresh the UI
|
| 683 |
+
# This runs every 60 seconds to check if new data is available
|
| 684 |
+
def check_and_refresh_data(current_checkbox_state):
|
| 685 |
+
"""Check if data has been refreshed and return updated data if so."""
|
| 686 |
+
current_version = get_data_version()
|
| 687 |
+
if current_version > initial_data_version:
|
| 688 |
+
# Data has been refreshed, reload it
|
| 689 |
+
print(f"[REFRESH] Data version changed from {initial_data_version} to {current_version}, reloading...")
|
| 690 |
+
new_df, new_tag_map = get_full_leaderboard_data(split_name)
|
| 691 |
+
if not new_df.empty:
|
| 692 |
+
new_transformer = DataTransformer(new_df, new_tag_map)
|
| 693 |
+
new_df_view_full, _ = new_transformer.view(tag=category_name, use_plotly=True)
|
| 694 |
+
|
| 695 |
+
# Prepare both complete and all entries versions
|
| 696 |
+
if 'Categories Attempted' in new_df_view_full.columns:
|
| 697 |
+
new_df_view_complete = new_df_view_full[new_df_view_full['Categories Attempted'] == '5/5'].copy()
|
| 698 |
+
else:
|
| 699 |
+
new_df_view_complete = new_df_view_full.copy()
|
| 700 |
+
|
| 701 |
+
new_df_display_complete = prepare_df_for_display(new_df_view_complete)
|
| 702 |
+
new_df_display_all = prepare_df_for_display(new_df_view_full)
|
| 703 |
+
|
| 704 |
+
# Create new scatter plots
|
| 705 |
+
new_scatter_complete = create_scatter_plot(new_df_view_complete) if len(new_df_display_complete) > 0 else go.Figure()
|
| 706 |
+
new_scatter_all = create_scatter_plot(new_df_view_full)
|
| 707 |
+
|
| 708 |
+
# Return the appropriate data based on checkbox state
|
| 709 |
+
if current_checkbox_state:
|
| 710 |
+
return new_df_display_all, new_scatter_all
|
| 711 |
+
else:
|
| 712 |
+
return new_df_display_complete, new_scatter_complete
|
| 713 |
+
|
| 714 |
+
# No change, return current values
|
| 715 |
+
if current_checkbox_state:
|
| 716 |
+
return df_display_all, scatter_plot_all
|
| 717 |
+
else:
|
| 718 |
+
return df_display_complete, scatter_plot_complete
|
| 719 |
+
|
| 720 |
+
# Create a timer that checks for updates every 60 seconds
|
| 721 |
+
refresh_timer = gr.Timer(value=60)
|
| 722 |
+
|
| 723 |
+
# Connect the timer to the refresh function
|
| 724 |
+
if show_incomplete_checkbox is not None:
|
| 725 |
+
refresh_timer.tick(
|
| 726 |
+
fn=check_and_refresh_data,
|
| 727 |
+
inputs=[show_incomplete_checkbox],
|
| 728 |
+
outputs=[dataframe_component, plot_component]
|
| 729 |
+
)
|
| 730 |
+
else:
|
| 731 |
+
# If no checkbox, always show all data
|
| 732 |
+
def check_and_refresh_all():
|
| 733 |
+
current_version = get_data_version()
|
| 734 |
+
if current_version > initial_data_version:
|
| 735 |
+
print(f"[REFRESH] Data version changed, reloading...")
|
| 736 |
+
new_df, new_tag_map = get_full_leaderboard_data(split_name)
|
| 737 |
+
if not new_df.empty:
|
| 738 |
+
new_transformer = DataTransformer(new_df, new_tag_map)
|
| 739 |
+
new_df_view_full, _ = new_transformer.view(tag=category_name, use_plotly=True)
|
| 740 |
+
new_df_display_all = prepare_df_for_display(new_df_view_full)
|
| 741 |
+
new_scatter_all = create_scatter_plot(new_df_view_full)
|
| 742 |
+
return new_df_display_all, new_scatter_all
|
| 743 |
+
return df_display_all, scatter_plot_all
|
| 744 |
+
|
| 745 |
+
refresh_timer.tick(
|
| 746 |
+
fn=check_and_refresh_all,
|
| 747 |
+
inputs=[],
|
| 748 |
+
outputs=[dataframe_component, plot_component]
|
| 749 |
+
)
|
| 750 |
|
| 751 |
# Return the components so they can be referenced elsewhere.
|
| 752 |
return plot_component, dataframe_component
|