Tschoui commited on
Commit
3f83cdc
·
1 Parent(s): bc721cc

:lipstick: Improve refresh button and control layout

Browse files
backend/api.py CHANGED
@@ -1,6 +1,7 @@
1
  import asyncio
2
  from typing import Dict, Any
3
  from .submission import process_submission
 
4
 
5
 
6
  # Sample data - replace with actual data loading
@@ -23,8 +24,14 @@ async def submit_model(
23
  pretraining: str = "",
24
  organization: str = ""
25
  ) -> Dict[str, Any]:
26
- """API endpoint for model submission."""
27
 
 
 
 
 
 
 
28
  record = await process_submission(
29
  model_name=model_name,
30
  hf_space_tag=hf_space_tag,
@@ -38,6 +45,9 @@ async def submit_model(
38
  true_labels=SAMPLE_LABELS
39
  )
40
 
 
 
 
41
  return record
42
 
43
 
 
1
  import asyncio
2
  from typing import Dict, Any
3
  from .submission import process_submission
4
+ from .rate_limiter import check_submission_limit, record_submission, get_submission_status
5
 
6
 
7
  # Sample data - replace with actual data loading
 
24
  pretraining: str = "",
25
  organization: str = ""
26
  ) -> Dict[str, Any]:
27
+ """API endpoint for model submission with rate limiting."""
28
 
29
+ # Check rate limit
30
+ if not check_submission_limit(hf_space_tag):
31
+ status = get_submission_status(hf_space_tag)
32
+ raise Exception(f"Daily submission limit exceeded. Used {status['submissions_today']}/{status['daily_limit']} submissions today. Try again tomorrow.")
33
+
34
+ # Process submission
35
  record = await process_submission(
36
  model_name=model_name,
37
  hf_space_tag=hf_space_tag,
 
45
  true_labels=SAMPLE_LABELS
46
  )
47
 
48
+ # Record successful submission for rate limiting
49
+ record_submission(hf_space_tag)
50
+
51
  return record
52
 
53
 
backend/rate_limiter.py ADDED
@@ -0,0 +1,99 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import json
2
+ import os
3
+ from datetime import datetime, date
4
+ from typing import Dict, Any
5
+ from config.settings import DAILY_SUBMISSION_LIMIT, DEBUG_MODE
6
+
7
+
8
+ RATE_LIMIT_FILE = "submission_tracking.json"
9
+
10
+
11
+ def load_submission_tracking() -> Dict[str, Any]:
12
+ """Load submission tracking data from file."""
13
+ if not os.path.exists(RATE_LIMIT_FILE):
14
+ return {}
15
+
16
+ with open(RATE_LIMIT_FILE, 'r') as f:
17
+ return json.load(f)
18
+
19
+
20
+ def save_submission_tracking(data: Dict[str, Any]) -> None:
21
+ """Save submission tracking data to file."""
22
+ with open(RATE_LIMIT_FILE, 'w') as f:
23
+ json.dump(data, f, indent=2)
24
+
25
+
26
+ def check_submission_limit(hf_space_tag: str) -> bool:
27
+ """
28
+ Check if the HF space can submit (hasn't exceeded daily limit).
29
+
30
+ Returns:
31
+ True if submission is allowed, False if rate limited
32
+ """
33
+
34
+ # Debug mode = unlimited submissions
35
+ if DEBUG_MODE:
36
+ return True
37
+
38
+ today = str(date.today())
39
+ data = load_submission_tracking()
40
+
41
+ # Initialize space tracking if not exists
42
+ if hf_space_tag not in data:
43
+ data[hf_space_tag] = {}
44
+
45
+ # Get today's submission count for this space
46
+ today_count = data[hf_space_tag].get(today, 0)
47
+
48
+ # Check if limit exceeded
49
+ return today_count < DAILY_SUBMISSION_LIMIT
50
+
51
+
52
+ def record_submission(hf_space_tag: str) -> None:
53
+ """Record a successful submission for rate limiting."""
54
+
55
+ today = str(date.today())
56
+ data = load_submission_tracking()
57
+
58
+ # Initialize space tracking if not exists
59
+ if hf_space_tag not in data:
60
+ data[hf_space_tag] = {}
61
+
62
+ # Increment today's count
63
+ data[hf_space_tag][today] = data[hf_space_tag].get(today, 0) + 1
64
+
65
+ # Clean up old dates (keep last 7 days for reference)
66
+ cleanup_old_entries(data)
67
+
68
+ save_submission_tracking(data)
69
+
70
+
71
+ def cleanup_old_entries(data: Dict[str, Any]) -> None:
72
+ """Remove entries older than 7 days to keep file small."""
73
+
74
+ from datetime import timedelta
75
+ cutoff_date = str(date.today() - timedelta(days=7))
76
+
77
+ for space_tag in data:
78
+ old_dates = [d for d in data[space_tag] if d < cutoff_date]
79
+ for old_date in old_dates:
80
+ del data[space_tag][old_date]
81
+
82
+
83
+ def get_submission_status(hf_space_tag: str) -> Dict[str, Any]:
84
+ """Get current submission status for a space."""
85
+
86
+ today = str(date.today())
87
+ data = load_submission_tracking()
88
+
89
+ today_count = data.get(hf_space_tag, {}).get(today, 0)
90
+ remaining = max(0, DAILY_SUBMISSION_LIMIT - today_count)
91
+
92
+ return {
93
+ "space": hf_space_tag,
94
+ "submissions_today": today_count,
95
+ "daily_limit": DAILY_SUBMISSION_LIMIT,
96
+ "remaining": remaining,
97
+ "debug_mode": DEBUG_MODE,
98
+ "can_submit": check_submission_limit(hf_space_tag)
99
+ }
config/settings.py CHANGED
@@ -33,9 +33,12 @@ APP_DESCRIPTION = "Leaderboard for molecular toxicity prediction on the Tox21 da
33
 
34
  # Evaluation Settings
35
  DEFAULT_METRIC = "roc_auc"
36
- SUBMISSION_RATE_LIMIT = 5 # Max submissions per day per user
37
  EVALUATION_TIMEOUT = 3600 # 1 hour timeout for evaluations
38
 
 
 
 
 
39
  # Display Settings
40
  MAX_MODELS_DISPLAYED = 100
41
  DEFAULT_SORT_BY = "average_score"
 
33
 
34
  # Evaluation Settings
35
  DEFAULT_METRIC = "roc_auc"
 
36
  EVALUATION_TIMEOUT = 3600 # 1 hour timeout for evaluations
37
 
38
+ # Rate Limiting
39
+ DEBUG_MODE = os.environ.get("DEBUG_SUBMISSIONS", "false").lower() == "true"
40
+ DAILY_SUBMISSION_LIMIT = 999 if DEBUG_MODE else 5 # Per HF space per day
41
+
42
  # Display Settings
43
  MAX_MODELS_DISPLAYED = 100
44
  DEFAULT_SORT_BY = "average_score"
frontend/layout.py CHANGED
@@ -16,28 +16,31 @@ def create_leaderboard_tab(refresh_callback: Callable = None) -> gr.TabItem:
16
 
17
  with gr.TabItem("🏅 Leaderboard", elem_id="leaderboard-tab", id=0) as tab:
18
 
19
- # Header section with refresh button
20
- with gr.Row():
21
- gr.HTML(LeaderboardContent.get_header_html())
22
- refresh_btn = gr.Button("🔄 Refresh", variant="secondary", size="sm")
23
 
24
- # Load initial data
25
- result_data = refresh_leaderboard().reset_index(drop=True)
26
- result_data.columns = result_data.columns.map(str)
27
-
28
- leaderboard_table = Leaderboard(
29
- value=result_data,
30
- search_columns=["Model", "Model Description", "Publication"], # or e.g. ["Model", "Model Description", "Publication"]
31
- select_columns=[], # or e.g. ["Publication"]
32
- filter_columns=[], # or a list of valid column names/filters
33
- hide_columns=[], # keep explicit to be safe
34
- elem_id="leaderboard-table",
35
- height=480, # only controls vertical
36
- min_width=160, # doesn’t prevent horizontal scroll
37
- wrap=True,
38
- column_widths=[200, 300, 150, 100, 120, 100] + [80] * 12,
39
- )
40
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
41
 
42
  # Connect refresh button
43
  def refresh_data():
 
16
 
17
  with gr.TabItem("🏅 Leaderboard", elem_id="leaderboard-tab", id=0) as tab:
18
 
19
+ # Header section
20
+ header_html = gr.HTML(LeaderboardContent.get_header_html())
 
 
21
 
22
+ # Leaderboard with integrated refresh button
23
+ with gr.Row():
24
+ with gr.Column(scale=10):
25
+ # Load initial data
26
+ result_data = refresh_leaderboard().reset_index(drop=True)
27
+ result_data.columns = result_data.columns.map(str)
 
 
 
 
 
 
 
 
 
 
28
 
29
+ leaderboard_table = Leaderboard(
30
+ value=result_data,
31
+ search_columns=["Model", "Model Description", "Publication"],
32
+ select_columns=[],
33
+ filter_columns=[],
34
+ hide_columns=[],
35
+ elem_id="leaderboard-table",
36
+ height=480,
37
+ min_width=160,
38
+ wrap=True,
39
+ column_widths=[200, 300, 150, 100, 120, 100] + [80] * 12,
40
+ )
41
+
42
+ with gr.Column(scale=1, min_width=100):
43
+ refresh_btn = gr.Button("🔄 Refresh", variant="secondary", size="sm")
44
 
45
  # Connect refresh button
46
  def refresh_data():
submission_tracking.json ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ {
2
+ "test/space": {
3
+ "2025-08-30": 5
4
+ }
5
+ }