Quazim0t0 commited on
Commit
4a823b5
·
verified ·
1 Parent(s): b6ddb3a

Upload 3 files

Browse files
Files changed (3) hide show
  1. app_token_auth.py +417 -0
  2. test_token_auth.py +58 -0
  3. token_auth.py +403 -0
app_token_auth.py ADDED
@@ -0,0 +1,417 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Main application for Dynamic Highscores system.
3
+
4
+ This file integrates all components into a unified application.
5
+ """
6
+
7
+ import os
8
+ import gradio as gr
9
+ import threading
10
+ import time
11
+ from database_schema import DynamicHighscoresDB
12
+ from auth import HuggingFaceAuth
13
+ from benchmark_selection import BenchmarkSelector, create_benchmark_selection_ui
14
+ from evaluation_queue import EvaluationQueue, create_model_submission_ui
15
+ from leaderboard import Leaderboard, create_leaderboard_ui
16
+ from sample_benchmarks import add_sample_benchmarks
17
+
18
+ # Initialize components in main thread
19
+ db = DynamicHighscoresDB()
20
+ auth_manager = HuggingFaceAuth(db)
21
+ benchmark_selector = BenchmarkSelector(db, auth_manager)
22
+ evaluation_queue = EvaluationQueue(db, auth_manager)
23
+ leaderboard = Leaderboard(db)
24
+
25
+ # Initialize sample benchmarks if none exist
26
+ print("Checking for existing benchmarks...")
27
+ benchmarks = db.get_benchmarks()
28
+ if not benchmarks or len(benchmarks) == 0:
29
+ print("No benchmarks found. Adding sample benchmarks...")
30
+ try:
31
+ # Make sure the database path is clear
32
+ print(f"Database path: {db.db_path}")
33
+
34
+ # Import and call the function directly
35
+ num_added = add_sample_benchmarks()
36
+ print(f"Added {num_added} sample benchmarks.")
37
+ except Exception as e:
38
+ print(f"Error adding sample benchmarks: {str(e)}")
39
+ # Try direct DB insertion as fallback
40
+ try:
41
+ print("Attempting direct benchmark insertion...")
42
+ db.add_benchmark(
43
+ name="MMLU (Massive Multitask Language Understanding)",
44
+ dataset_id="cais/mmlu",
45
+ description="Tests knowledge across 57 subjects"
46
+ )
47
+ print("Added fallback benchmark.")
48
+ except Exception as inner_e:
49
+ print(f"Fallback insertion failed: {str(inner_e)}")
50
+ else:
51
+ print(f"Found {len(benchmarks)} existing benchmarks.")
52
+
53
+ # Custom CSS with theme awareness
54
+ css = """
55
+ /* Theme-adaptive colored info box */
56
+ .info-text {
57
+ background-color: rgba(53, 130, 220, 0.1);
58
+ padding: 12px;
59
+ border-radius: 8px;
60
+ border-left: 4px solid #3498db;
61
+ margin: 12px 0;
62
+ }
63
+
64
+ /* High-contrast text for elements - works in light and dark themes */
65
+ .info-text, .header, .footer, .tab-content,
66
+ button, input, textarea, select, option,
67
+ .gradio-container *, .markdown-text {
68
+ color: var(--text-color, inherit) !important;
69
+ }
70
+
71
+ /* Container styling */
72
+ .container {
73
+ max-width: 1200px;
74
+ margin: 0 auto;
75
+ }
76
+
77
+ /* Header styling */
78
+ .header {
79
+ text-align: center;
80
+ margin-bottom: 20px;
81
+ font-weight: bold;
82
+ font-size: 24px;
83
+ }
84
+
85
+ /* Footer styling */
86
+ .footer {
87
+ text-align: center;
88
+ margin-top: 40px;
89
+ padding: 20px;
90
+ border-top: 1px solid var(--border-color-primary, #eee);
91
+ }
92
+
93
+ /* Login section styling */
94
+ .login-section {
95
+ padding: 10px;
96
+ margin-bottom: 15px;
97
+ border-radius: 8px;
98
+ background-color: rgba(250, 250, 250, 0.1);
99
+ text-align: center;
100
+ }
101
+
102
+ /* Token input styling */
103
+ .token-input {
104
+ margin: 10px 0;
105
+ padding: 8px;
106
+ border-radius: 4px;
107
+ border: 1px solid #ccc;
108
+ width: 100%;
109
+ }
110
+
111
+ /* Force high contrast on specific input areas */
112
+ input[type="text"], input[type="password"], textarea {
113
+ background-color: var(--background-fill-primary) !important;
114
+ color: var(--body-text-color) !important;
115
+ }
116
+
117
+ /* Force text visibility in multiple contexts */
118
+ .gradio-markdown p, .gradio-markdown h1, .gradio-markdown h2,
119
+ .gradio-markdown h3, .gradio-markdown h4, .gradio-markdown li {
120
+ color: var(--body-text-color) !important;
121
+ }
122
+
123
+ /* Fix dark mode text visibility */
124
+ @media (prefers-color-scheme: dark) {
125
+ input, textarea, select {
126
+ color: #ffffff !important;
127
+ }
128
+
129
+ ::placeholder {
130
+ color: rgba(255, 255, 255, 0.5) !important;
131
+ }
132
+ }
133
+ """
134
+
135
+ # Create token input UI
136
+ def create_token_input_ui():
137
+ with gr.Row():
138
+ with gr.Column():
139
+ gr.Markdown("### HuggingFace Token Authentication")
140
+ gr.Markdown("""
141
+ Enter your HuggingFace tokens to use this application.
142
+ You can find your tokens in your [HuggingFace settings](https://huggingface.co/settings/tokens).
143
+
144
+ - **Read Token**: Required for accessing models and datasets
145
+ - **Write Token**: Required for submitting evaluation results
146
+
147
+ Your tokens are stored only in your browser's local storage and are not saved on the server.
148
+ """)
149
+
150
+ read_token = gr.Textbox(
151
+ label="Read Token",
152
+ placeholder="Enter your HuggingFace read token",
153
+ type="password"
154
+ )
155
+ write_token = gr.Textbox(
156
+ label="Write Token",
157
+ placeholder="Enter your HuggingFace write token",
158
+ type="password"
159
+ )
160
+ save_button = gr.Button("Save Tokens")
161
+ clear_button = gr.Button("Clear Tokens")
162
+ token_status = gr.Markdown("Not authenticated")
163
+
164
+ # Hidden field to store the token status
165
+ token_state = gr.State(None)
166
+
167
+ # JavaScript to handle token storage
168
+ token_js = """
169
+ <script>
170
+ // Function to save tokens to localStorage
171
+ function saveTokens() {
172
+ const readToken = document.querySelector('input[placeholder="Enter your HuggingFace read token"]').value;
173
+ const writeToken = document.querySelector('input[placeholder="Enter your HuggingFace write token"]').value;
174
+
175
+ if (readToken && writeToken) {
176
+ localStorage.setItem("hf_read_token", readToken);
177
+ localStorage.setItem("hf_write_token", writeToken);
178
+
179
+ // Set token in cookie for server-side access
180
+ document.cookie = "hf_token=" + readToken + "; path=/; SameSite=Strict";
181
+
182
+ // Update status
183
+ const statusElement = document.querySelector('div[data-testid="markdown"] p');
184
+ if (statusElement) {
185
+ statusElement.textContent = "Authenticated with tokens";
186
+ statusElement.style.color = "green";
187
+ }
188
+
189
+ // Reload page to apply tokens
190
+ setTimeout(() => window.location.reload(), 1000);
191
+ } else {
192
+ alert("Please enter both read and write tokens");
193
+ }
194
+ }
195
+
196
+ // Function to clear tokens from localStorage
197
+ function clearTokens() {
198
+ localStorage.removeItem("hf_read_token");
199
+ localStorage.removeItem("hf_write_token");
200
+
201
+ // Clear token cookie
202
+ document.cookie = "hf_token=; path=/; max-age=0; SameSite=Strict";
203
+
204
+ // Update status
205
+ const statusElement = document.querySelector('div[data-testid="markdown"] p');
206
+ if (statusElement) {
207
+ statusElement.textContent = "Not authenticated";
208
+ statusElement.style.color = "red";
209
+ }
210
+
211
+ // Clear input fields
212
+ document.querySelector('input[placeholder="Enter your HuggingFace read token"]').value = "";
213
+ document.querySelector('input[placeholder="Enter your HuggingFace write token"]').value = "";
214
+
215
+ // Reload page to apply changes
216
+ setTimeout(() => window.location.reload(), 1000);
217
+ }
218
+
219
+ // Function to load tokens from localStorage
220
+ function loadTokens() {
221
+ const readToken = localStorage.getItem("hf_read_token");
222
+ const writeToken = localStorage.getItem("hf_write_token");
223
+
224
+ if (readToken && writeToken) {
225
+ document.querySelector('input[placeholder="Enter your HuggingFace read token"]').value = readToken;
226
+ document.querySelector('input[placeholder="Enter your HuggingFace write token"]').value = writeToken;
227
+
228
+ // Update status
229
+ const statusElement = document.querySelector('div[data-testid="markdown"] p');
230
+ if (statusElement) {
231
+ statusElement.textContent = "Authenticated with tokens";
232
+ statusElement.style.color = "green";
233
+ }
234
+
235
+ // Set token in cookie for server-side access if not already set
236
+ if (!document.cookie.includes("hf_token=")) {
237
+ document.cookie = "hf_token=" + readToken + "; path=/; SameSite=Strict";
238
+ }
239
+ }
240
+ }
241
+
242
+ // Add event listeners once DOM is loaded
243
+ document.addEventListener("DOMContentLoaded", function() {
244
+ // Load tokens from localStorage
245
+ loadTokens();
246
+
247
+ // Add event listeners to buttons
248
+ const saveButton = document.querySelector('button:nth-of-type(1)');
249
+ const clearButton = document.querySelector('button:nth-of-type(2)');
250
+
251
+ if (saveButton) {
252
+ saveButton.addEventListener("click", saveTokens);
253
+ }
254
+
255
+ if (clearButton) {
256
+ clearButton.addEventListener("click", clearTokens);
257
+ }
258
+ });
259
+ </script>
260
+ """
261
+
262
+ return read_token, write_token, save_button, clear_button, token_status, token_state, token_js
263
+
264
+ # Simple manual authentication check
265
+ def check_user(request: gr.Request):
266
+ if request:
267
+ # Check for token in cookies
268
+ token = request.cookies.get("hf_token")
269
+
270
+ if token:
271
+ try:
272
+ # Validate token with HuggingFace
273
+ user_info = auth_manager.hf_api.whoami(token=token)
274
+
275
+ if user_info:
276
+ username = user_info.get("name", "")
277
+ print(f"User authenticated via token: {username}")
278
+
279
+ # Check if user exists in our database, create if not
280
+ user = db.get_user_by_username(username)
281
+ if not user:
282
+ # Create user if they don't exist
283
+ print(f"Creating new user: {username}")
284
+ is_admin = (username == "Quazim0t0")
285
+ db.add_user(username, username, is_admin)
286
+ user = db.get_user_by_username(username)
287
+
288
+ return username
289
+ except Exception as e:
290
+ print(f"Token validation error: {e}")
291
+
292
+ return None
293
+
294
+ # Start evaluation queue worker
295
+ def start_queue_worker():
296
+ # Wait a moment to ensure app is initialized
297
+ time.sleep(2)
298
+ try:
299
+ print("Starting evaluation queue worker...")
300
+ evaluation_queue.start_worker()
301
+ except Exception as e:
302
+ print(f"Error starting queue worker: {e}")
303
+
304
+ # Create Gradio app
305
+ with gr.Blocks(css=css, title="Dynamic Highscores") as app:
306
+ # State to track user
307
+ user_state = gr.State(None)
308
+
309
+ # Token input UI
310
+ read_token, write_token, save_button, clear_button, token_status, token_state, token_js = create_token_input_ui()
311
+
312
+ # Add the token handling JavaScript
313
+ gr.HTML(token_js)
314
+
315
+ gr.Markdown("# 🏆 Dynamic Highscores", elem_classes=["header"])
316
+ gr.Markdown("""
317
+ Welcome to Dynamic Highscores - a community benchmark platform for evaluating and comparing language models.
318
+
319
+ - **Add your own benchmarks** from HuggingFace datasets
320
+ - **Submit your models** for CPU-only evaluation
321
+ - **Compare performance** across different models and benchmarks
322
+ - **Filter results** by model type (Merge, Agent, Reasoning, Coding, etc.)
323
+ """, elem_classes=["info-text"])
324
+
325
+ # Main tabs
326
+ with gr.Tabs() as tabs:
327
+ with gr.TabItem("📊 Leaderboard", id=0):
328
+ leaderboard_ui = create_leaderboard_ui(leaderboard, db)
329
+
330
+ with gr.TabItem("🚀 Submit Model", id=1):
331
+ submission_ui = create_model_submission_ui(evaluation_queue, auth_manager, db)
332
+
333
+ with gr.TabItem("🔍 Benchmarks", id=2):
334
+ benchmark_ui = create_benchmark_selection_ui(benchmark_selector, auth_manager)
335
+
336
+ with gr.TabItem("🌐 Community Framework", id=3):
337
+ # Create a simple placeholder for the Community Framework tab
338
+ gr.Markdown("""
339
+ # 🌐 Dynamic Highscores Community Framework
340
+
341
+ ## About Dynamic Highscores
342
+
343
+ Dynamic Highscores is an open-source community benchmark system for evaluating language models on any dataset. This project was created to fill the gap left by the retirement of HuggingFace's "Open LLM Leaderboards" which were discontinued due to outdated benchmarks.
344
+
345
+ ### Key Features
346
+
347
+ - **Flexible Benchmarking**: Test models against any HuggingFace dataset, not just predefined benchmarks
348
+ - **Community-Driven**: Anyone can add new benchmarks and submit models for evaluation
349
+ - **Modern Evaluation**: Focus on contemporary benchmarks that better reflect current model capabilities
350
+ - **CPU-Only Evaluation**: Ensures fair comparisons across different models
351
+ - **Daily Submission Limits**: Prevents system abuse (one benchmark per day per user)
352
+ - **Model Tagging**: Categorize models as Merge, Agent, Reasoning, Coding, etc.
353
+ - **Unified Leaderboard**: View all models with filtering capabilities by tags
354
+
355
+ ### Why This Project Matters
356
+
357
+ When HuggingFace retired their "Open LLM Leaderboards," the community lost a valuable resource for comparing model performance. The benchmarks used had become outdated and didn't reflect the rapid advances in language model capabilities.
358
+
359
+ Dynamic Highscores addresses this issue by allowing users to select from any benchmark on HuggingFace, including the most recent and relevant datasets. This ensures that models are evaluated on tasks that matter for current applications.
360
+
361
+ ## Model Configuration System (Coming Soon)
362
+
363
+ We're working on a modular system for model configurations that will allow users to:
364
+
365
+ - Create and apply predefined configurations for different model types
366
+ - Define parameters such as Temperature, Top-K, Min-P, Top-P, and Repetition Penalty
367
+ - Share optimal configurations with the community
368
+
369
+ ### Example Configuration (Gemma)
370
+
371
+ ```
372
+ Temperature: 1.0
373
+ Top_K: 64
374
+ Min_P: 0.01
375
+ Top_P: 0.95
376
+ Repetition Penalty: 1.0
377
+ ```
378
+
379
+ ## Contributing to the Project
380
+
381
+ We welcome contributions from the community! If you'd like to improve Dynamic Highscores, here are some ways to get involved:
382
+
383
+ - **Add New Features**: Enhance the platform with additional functionality
384
+ - **Improve Evaluation Methods**: Help make model evaluations more accurate and efficient
385
+ - **Fix Bugs**: Address issues in the codebase
386
+ - **Enhance Documentation**: Make the project more accessible to new users
387
+ - **Add Model Configurations**: Contribute optimal configurations for different model types
388
+
389
+ To contribute, fork the repository, make your changes, and submit a pull request. We appreciate all contributions, big or small!
390
+ """)
391
+
392
+ gr.Markdown("""
393
+ ### About Dynamic Highscores
394
+
395
+ This platform allows users to select benchmarks from HuggingFace datasets and evaluate models against them.
396
+ Each user can submit one benchmark per day (admin users are exempt from this limit).
397
+ All evaluations run on CPU only to ensure fair comparisons.
398
+
399
+ Created by Quazim0t0
400
+ """, elem_classes=["footer"])
401
+
402
+ # Check login on page load
403
+ app.load(
404
+ fn=check_user,
405
+ inputs=[],
406
+ outputs=[user_state]
407
+ )
408
+
409
+ # Launch the app
410
+ if __name__ == "__main__":
411
+ # Start queue worker in a separate thread
412
+ queue_thread = threading.Thread(target=start_queue_worker)
413
+ queue_thread.daemon = True
414
+ queue_thread.start()
415
+
416
+ # Launch the app
417
+ app.launch()
test_token_auth.py ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Test script for token-based authentication in Dynamic Highscores.
3
+
4
+ This script tests the token-based authentication functionality.
5
+ """
6
+
7
+ import os
8
+ import sys
9
+ import requests
10
+ from huggingface_hub import HfApi
11
+
12
+ def test_token_auth():
13
+ """Test token-based authentication with HuggingFace API."""
14
+
15
+ print("Testing token-based authentication...")
16
+
17
+ # Prompt for tokens
18
+ read_token = input("Enter your HuggingFace read token: ")
19
+ write_token = input("Enter your HuggingFace write token: ")
20
+
21
+ if not read_token or not write_token:
22
+ print("Error: Both read and write tokens are required.")
23
+ return False
24
+
25
+ # Initialize HuggingFace API
26
+ hf_api = HfApi()
27
+
28
+ # Test read token
29
+ print("\nTesting read token...")
30
+ try:
31
+ read_user_info = hf_api.whoami(token=read_token)
32
+ print(f"Read token valid. User: {read_user_info.get('name')}")
33
+ except Exception as e:
34
+ print(f"Error validating read token: {e}")
35
+ return False
36
+
37
+ # Test write token
38
+ print("\nTesting write token...")
39
+ try:
40
+ write_user_info = hf_api.whoami(token=write_token)
41
+ print(f"Write token valid. User: {write_user_info.get('name')}")
42
+ except Exception as e:
43
+ print(f"Error validating write token: {e}")
44
+ return False
45
+
46
+ # Check if tokens belong to the same user
47
+ if read_user_info.get("id") != write_user_info.get("id"):
48
+ print("Error: Tokens must belong to the same user.")
49
+ return False
50
+
51
+ print("\nToken authentication test successful!")
52
+ print(f"User: {read_user_info.get('name')}")
53
+ print(f"User ID: {read_user_info.get('id')}")
54
+
55
+ return True
56
+
57
+ if __name__ == "__main__":
58
+ test_token_auth()
token_auth.py ADDED
@@ -0,0 +1,403 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Authentication module for Dynamic Highscores system with token-based authentication.
3
+
4
+ This module handles user authentication with HuggingFace using direct token input,
5
+ user session management, and access control.
6
+ """
7
+
8
+ import os
9
+ import json
10
+ import time
11
+ import requests
12
+ import gradio as gr
13
+ from huggingface_hub import HfApi, login
14
+ from functools import wraps
15
+
16
+ class HuggingFaceTokenAuth:
17
+ """Authentication manager for HuggingFace integration using tokens."""
18
+
19
+ def __init__(self, db_manager):
20
+ """Initialize the authentication manager.
21
+
22
+ Args:
23
+ db_manager: Database manager instance for user storage
24
+ """
25
+ self.db_manager = db_manager
26
+ self.hf_api = HfApi()
27
+ self.admin_username = os.environ.get("ADMIN_USERNAME", "Quazim0t0")
28
+ self.running_in_space = 'SPACE_ID' in os.environ
29
+
30
+ print(f"Running in Space: {self.running_in_space}")
31
+
32
+ def validate_token(self, token):
33
+ """Validate a HuggingFace token.
34
+
35
+ Args:
36
+ token: HuggingFace API token
37
+
38
+ Returns:
39
+ dict: User information if token is valid, None otherwise
40
+ """
41
+ try:
42
+ # Validate token with HuggingFace
43
+ user_info = self.hf_api.whoami(token=token)
44
+ return user_info
45
+ except Exception as e:
46
+ print(f"Token validation error: {e}")
47
+ return None
48
+
49
+ def login_user(self, read_token, write_token=None):
50
+ """Log in a user with their HuggingFace tokens.
51
+
52
+ Args:
53
+ read_token: HuggingFace read API token
54
+ write_token: HuggingFace write API token (optional)
55
+
56
+ Returns:
57
+ dict: User information if login successful, None otherwise
58
+ """
59
+ try:
60
+ # Validate read token with HuggingFace
61
+ user_info = self.validate_token(read_token)
62
+
63
+ if not user_info:
64
+ return None
65
+
66
+ # Check if user exists in our database, create if not
67
+ username = user_info.get("name", user_info.get("fullname", ""))
68
+ hf_user_id = user_info.get("id", "")
69
+
70
+ if not hf_user_id:
71
+ return None
72
+
73
+ # Check if this is the admin account
74
+ is_admin = (username == self.admin_username)
75
+
76
+ # Add or get user from database
77
+ user_id = self.db_manager.add_user(username, hf_user_id, is_admin)
78
+
79
+ # Get complete user info from database
80
+ user = self.db_manager.get_user(hf_user_id)
81
+
82
+ if user:
83
+ # Add tokens to user info for session only (not stored in database)
84
+ user['read_token'] = read_token
85
+ if write_token:
86
+ user['write_token'] = write_token
87
+ return user
88
+
89
+ return None
90
+ except Exception as e:
91
+ print(f"Login error: {e}")
92
+ return None
93
+
94
+ def check_login(self, request: gr.Request):
95
+ """Check if a user is logged in from a Gradio request.
96
+
97
+ Args:
98
+ request: Gradio request object
99
+
100
+ Returns:
101
+ dict: User information if logged in, None otherwise
102
+ """
103
+ if not request:
104
+ return None
105
+
106
+ # Get token from cookies
107
+ token = request.cookies.get("hf_token")
108
+
109
+ if not token:
110
+ # Try to get token from headers
111
+ token = request.headers.get("HF-Token")
112
+
113
+ if not token:
114
+ return None
115
+
116
+ try:
117
+ # Validate token with HuggingFace
118
+ user_info = self.hf_api.whoami(token=token)
119
+
120
+ if not user_info:
121
+ return None
122
+
123
+ # Get user from database
124
+ hf_user_id = user_info.get("id", "")
125
+ user = self.db_manager.get_user(hf_user_id)
126
+
127
+ if user:
128
+ # Add token to user info for session only (not stored in database)
129
+ user['read_token'] = token
130
+ return user
131
+
132
+ return None
133
+ except Exception as e:
134
+ print(f"Check login error: {e}")
135
+ return None
136
+
137
+ def require_login(self, func):
138
+ """Decorator to require login for a function.
139
+
140
+ Args:
141
+ func: Function to decorate
142
+
143
+ Returns:
144
+ Function: Decorated function that requires login
145
+ """
146
+ @wraps(func)
147
+ def wrapper(*args, **kwargs):
148
+ # Find the request argument
149
+ request = None
150
+ for arg in args:
151
+ if isinstance(arg, gr.Request):
152
+ request = arg
153
+ break
154
+
155
+ if not request and 'request' in kwargs:
156
+ request = kwargs['request']
157
+
158
+ if not request:
159
+ return "Please enter your HuggingFace tokens to access this feature."
160
+
161
+ # Check if user is logged in
162
+ user = self.check_login(request)
163
+
164
+ if not user:
165
+ return "Please enter your HuggingFace tokens to access this feature."
166
+
167
+ # Add user to kwargs
168
+ kwargs['user'] = user
169
+
170
+ # Call the original function
171
+ return func(*args, **kwargs)
172
+
173
+ return wrapper
174
+
175
+ def require_admin(self, func):
176
+ """Decorator to require admin privileges for a function.
177
+
178
+ Args:
179
+ func: Function to decorate
180
+
181
+ Returns:
182
+ Function: Decorated function that requires admin privileges
183
+ """
184
+ @wraps(func)
185
+ def wrapper(*args, **kwargs):
186
+ # Find the request argument
187
+ request = None
188
+ for arg in args:
189
+ if isinstance(arg, gr.Request):
190
+ request = arg
191
+ break
192
+
193
+ if not request and 'request' in kwargs:
194
+ request = kwargs['request']
195
+
196
+ if not request:
197
+ return "Admin access required."
198
+
199
+ # Check if user is logged in
200
+ user = self.check_login(request)
201
+
202
+ if not user:
203
+ return "Admin access required."
204
+
205
+ # Check if user is admin
206
+ if not user.get('is_admin', False):
207
+ return "Admin access required."
208
+
209
+ # Add user to kwargs
210
+ kwargs['user'] = user
211
+
212
+ # Call the original function
213
+ return func(*args, **kwargs)
214
+
215
+ return wrapper
216
+
217
+ def can_submit_benchmark(self, user_id):
218
+ """Check if a user can submit a benchmark today.
219
+
220
+ Args:
221
+ user_id: User ID to check
222
+
223
+ Returns:
224
+ bool: True if user can submit, False otherwise
225
+ """
226
+ return self.db_manager.can_submit_today(user_id)
227
+
228
+ def update_submission_date(self, user_id):
229
+ """Update the last submission date for a user.
230
+
231
+ Args:
232
+ user_id: User ID to update
233
+ """
234
+ self.db_manager.update_submission_date(user_id)
235
+
236
+ # Token input UI components
237
+ def create_token_input_ui():
238
+ """Create the token input UI components.
239
+
240
+ Returns:
241
+ tuple: (read_token, write_token, save_button, clear_button, token_status, token_state, token_js)
242
+ """
243
+ with gr.Row():
244
+ with gr.Column():
245
+ gr.Markdown("### HuggingFace Token Authentication")
246
+ gr.Markdown("""
247
+ Enter your HuggingFace tokens to use this application.
248
+ You can find your tokens in your [HuggingFace settings](https://huggingface.co/settings/tokens).
249
+
250
+ - **Read Token**: Required for accessing models and datasets
251
+ - **Write Token**: Required for submitting evaluation results
252
+
253
+ Your tokens are stored only in your browser's local storage and are not saved on the server.
254
+ """)
255
+
256
+ read_token = gr.Textbox(
257
+ label="Read Token",
258
+ placeholder="Enter your HuggingFace read token",
259
+ type="password"
260
+ )
261
+ write_token = gr.Textbox(
262
+ label="Write Token",
263
+ placeholder="Enter your HuggingFace write token",
264
+ type="password"
265
+ )
266
+ save_button = gr.Button("Save Tokens")
267
+ clear_button = gr.Button("Clear Tokens")
268
+ token_status = gr.Markdown("Not authenticated")
269
+
270
+ # Hidden field to store the token status
271
+ token_state = gr.State(None)
272
+
273
+ # JavaScript to handle token storage
274
+ token_js = """
275
+ <script>
276
+ // Function to save tokens to localStorage
277
+ function saveTokens() {
278
+ const readToken = document.querySelector('input[placeholder="Enter your HuggingFace read token"]').value;
279
+ const writeToken = document.querySelector('input[placeholder="Enter your HuggingFace write token"]').value;
280
+
281
+ if (readToken && writeToken) {
282
+ localStorage.setItem("hf_read_token", readToken);
283
+ localStorage.setItem("hf_write_token", writeToken);
284
+
285
+ // Set token in cookie for server-side access
286
+ document.cookie = "hf_token=" + readToken + "; path=/; SameSite=Strict";
287
+
288
+ // Update status
289
+ const statusElement = document.querySelector('div[data-testid="markdown"] p');
290
+ if (statusElement) {
291
+ statusElement.textContent = "Authenticated with tokens";
292
+ statusElement.style.color = "green";
293
+ }
294
+
295
+ // Reload page to apply tokens
296
+ setTimeout(() => window.location.reload(), 1000);
297
+ } else {
298
+ alert("Please enter both read and write tokens");
299
+ }
300
+ }
301
+
302
+ // Function to clear tokens from localStorage
303
+ function clearTokens() {
304
+ localStorage.removeItem("hf_read_token");
305
+ localStorage.removeItem("hf_write_token");
306
+
307
+ // Clear token cookie
308
+ document.cookie = "hf_token=; path=/; max-age=0; SameSite=Strict";
309
+
310
+ // Update status
311
+ const statusElement = document.querySelector('div[data-testid="markdown"] p');
312
+ if (statusElement) {
313
+ statusElement.textContent = "Not authenticated";
314
+ statusElement.style.color = "red";
315
+ }
316
+
317
+ // Clear input fields
318
+ document.querySelector('input[placeholder="Enter your HuggingFace read token"]').value = "";
319
+ document.querySelector('input[placeholder="Enter your HuggingFace write token"]').value = "";
320
+
321
+ // Reload page to apply changes
322
+ setTimeout(() => window.location.reload(), 1000);
323
+ }
324
+
325
+ // Function to load tokens from localStorage
326
+ function loadTokens() {
327
+ const readToken = localStorage.getItem("hf_read_token");
328
+ const writeToken = localStorage.getItem("hf_write_token");
329
+
330
+ if (readToken && writeToken) {
331
+ document.querySelector('input[placeholder="Enter your HuggingFace read token"]').value = readToken;
332
+ document.querySelector('input[placeholder="Enter your HuggingFace write token"]').value = writeToken;
333
+
334
+ // Update status
335
+ const statusElement = document.querySelector('div[data-testid="markdown"] p');
336
+ if (statusElement) {
337
+ statusElement.textContent = "Authenticated with tokens";
338
+ statusElement.style.color = "green";
339
+ }
340
+
341
+ // Set token in cookie for server-side access if not already set
342
+ if (!document.cookie.includes("hf_token=")) {
343
+ document.cookie = "hf_token=" + readToken + "; path=/; SameSite=Strict";
344
+ }
345
+ }
346
+ }
347
+
348
+ // Add event listeners once DOM is loaded
349
+ document.addEventListener("DOMContentLoaded", function() {
350
+ // Load tokens from localStorage
351
+ loadTokens();
352
+
353
+ // Add event listeners to buttons
354
+ const saveButton = document.querySelector('button:nth-of-type(1)');
355
+ const clearButton = document.querySelector('button:nth-of-type(2)');
356
+
357
+ if (saveButton) {
358
+ saveButton.addEventListener("click", saveTokens);
359
+ }
360
+
361
+ if (clearButton) {
362
+ clearButton.addEventListener("click", clearTokens);
363
+ }
364
+ });
365
+ </script>
366
+ """
367
+
368
+ return read_token, write_token, save_button, clear_button, token_status, token_state, token_js
369
+
370
+ def validate_tokens(auth_manager, read_token, write_token):
371
+ """Validate HuggingFace tokens.
372
+
373
+ Args:
374
+ auth_manager: Authentication manager instance
375
+ read_token: HuggingFace read token
376
+ write_token: HuggingFace write token
377
+
378
+ Returns:
379
+ str: Status message
380
+ """
381
+ if not read_token or not write_token:
382
+ return "Please enter both read and write tokens"
383
+
384
+ # Validate read token
385
+ read_user_info = auth_manager.validate_token(read_token)
386
+ if not read_user_info:
387
+ return "Invalid read token"
388
+
389
+ # Validate write token
390
+ write_user_info = auth_manager.validate_token(write_token)
391
+ if not write_user_info:
392
+ return "Invalid write token"
393
+
394
+ # Check if tokens belong to the same user
395
+ if read_user_info.get("id") != write_user_info.get("id"):
396
+ return "Tokens must belong to the same user"
397
+
398
+ # Login user with tokens
399
+ user = auth_manager.login_user(read_token, write_token)
400
+ if not user:
401
+ return "Failed to authenticate user"
402
+
403
+ return f"Authenticated as {user.get('username')}"