Tschoui commited on
Commit
1146e96
Β·
1 Parent(s): ad6df70

🚧 'Frontend development

Browse files
DEPLOYMENT.md ADDED
@@ -0,0 +1,92 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # HuggingFace Spaces Deployment Guide
2
+
3
+ ## Prerequisites
4
+ - βœ… HuggingFace account (`Tschoui`)
5
+ - βœ… Private datasets created:
6
+ - `Tschoui/tox21-requests`
7
+ - `Tschoui/tox21-results`
8
+ - βœ… HuggingFace token with access to both datasets
9
+
10
+ ## Step 1: Create the Space
11
+
12
+ 1. **Go to**: https://huggingface.co/new-space
13
+ 2. **Fill in**:
14
+ - **Space name**: `tox21-leaderboard`
15
+ - **License**: Apache 2.0
16
+ - **SDK**: Gradio
17
+ - **Hardware**: CPU basic (free)
18
+ - **Visibility**: Public (users can see the leaderboard)
19
+ 3. **Click "Create Space"**
20
+
21
+ ## Step 2: Upload Your Code
22
+
23
+ ### Option A: Git (Recommended)
24
+ ```bash
25
+ git clone https://huggingface.co/spaces/Tschoui/tox21-leaderboard
26
+ cd tox21-leaderboard
27
+ # Copy your files (excluding .env, .git, etc.)
28
+ git add .
29
+ git commit -m "Initial leaderboard setup"
30
+ git push
31
+ ```
32
+
33
+ ### Option B: Web Upload
34
+ 1. **Go to your Space**: `https://huggingface.co/spaces/Tschoui/tox21-leaderboard`
35
+ 2. **Files and versions** tab
36
+ 3. **Upload files** - upload everything EXCEPT `.env`
37
+
38
+ ## Step 3: Configure Space Secrets
39
+
40
+ 1. **Go to your Space settings**: `https://huggingface.co/spaces/Tschoui/tox21-leaderboard/settings`
41
+ 2. **Repository secrets** section
42
+ 3. **New secret**:
43
+ - **Name**: `HF_TOKEN`
44
+ - **Value**: Your HuggingFace token (the same one from `.env`)
45
+ 4. **Save**
46
+
47
+ ## Step 4: Update README.md
48
+
49
+ The Space needs proper metadata in `README.md`:
50
+
51
+ ```yaml
52
+ ---
53
+ title: Tox21 Leaderboard
54
+ emoji: πŸ§ͺ
55
+ colorFrom: green
56
+ colorTo: blue
57
+ sdk: gradio
58
+ app_file: app.py
59
+ pinned: false
60
+ license: apache-2.0
61
+ ---
62
+
63
+ # Tox21 Leaderboard
64
+
65
+ Molecular toxicity prediction leaderboard for the Tox21 dataset.
66
+ ```
67
+
68
+ ## Step 5: Deploy & Test
69
+
70
+ 1. **Push/Upload** your code
71
+ 2. **Space will build automatically**
72
+ 3. **Check logs** for any errors
73
+ 4. **Test** that it can connect to your datasets
74
+
75
+ ## Environment Handling
76
+
77
+ ### Local Development:
78
+ - Uses `.env` file with your token
79
+ - `load_dotenv()` loads the token
80
+
81
+ ### HuggingFace Spaces:
82
+ - Uses Spaces Secrets (`HF_TOKEN`)
83
+ - `.env` file not deployed (in `.gitignore`)
84
+ - `os.environ.get("HF_TOKEN")` gets token from Spaces
85
+
86
+ ## Security Notes
87
+
88
+ βœ… **Safe**: Token stored in Spaces Secrets (encrypted)
89
+ βœ… **Safe**: `.env` never pushed to git
90
+ βœ… **Safe**: Users never see your token
91
+ ❌ **Don't**: Hardcode tokens in source code
92
+ ❌ **Don't**: Make datasets public if you don't want users seeing raw data
app.py CHANGED
@@ -1,3 +1,11 @@
1
- import gradio as gr
2
- from gradio_leaderboard import Leaderboard, ColumnFilter, SelectColumns
3
- import pandas as pd
 
 
 
 
 
 
 
 
 
1
+ from frontend.layout import create_main_interface
2
+ from frontend.leaderboard import refresh_leaderboard
3
+
4
+ # Create the main interface with callbacks
5
+ demo, leaderboard_table = create_main_interface(
6
+ refresh_callback=refresh_leaderboard
7
+ )
8
+
9
+ if __name__ == "__main__":
10
+ demo.launch(
11
+ )
assets/examples/test_example_request.json ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "model": "example-org/example-model",
3
+ "revision": "main",
4
+ "precision": "float16",
5
+ "status": "PENDING",
6
+ "submitted_time": "2024-01-01T12:00:00Z",
7
+ "model_type": "pretrained",
8
+ "private": false
9
+ }
assets/examples/test_example_result.json ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ {"config": {"model_name": "toy model 1", "hf_space": "user/space_name", "model_description": "this is a toy model", "publication_title": "mhnfs", "publication_url": "https://openreview.net/pdf?id=XrMWUuEevr", "parameters": 0.1, "date_added": "2025-08-28", "model_revision": "v 1.0"}, "results": {"overall_score": {"roc_auc": 0.847}, "NR-AR": {"roc_auc": 0.85}, "NR-AR-LBD": {"roc_auc": 0.78}, "NR-AhR": {"roc_auc": 0.82}, "NR-Aromatase": {"roc_auc": 0.75}, "NR-ER": {"roc_auc": 0.88}, "NR-ER-LBD": {"roc_auc": 0.79}, "NR-PPAR-gamma": {"roc_auc": 0.81}, "SR-ARE": {"roc_auc": 0.76}, "SR-ATAD5": {"roc_auc": 0.83}, "SR-HSE": {"roc_auc": 0.77}, "SR-MMP": {"roc_auc": 0.8}, "SR-p53": {"roc_auc": 0.84}}}
2
+ {"config": {"model_name": "toy model 2", "hf_space": "user/space_name2", "model_description": "this is another toy model with different scores", "publication_title": "Another Paper", "publication_url": "https://arxiv.org/abs/2301.00000", "parameters": 0.5, "date_added": "2025-08-28", "model_revision": "v 2.0"}, "results": {"overall_score": {"roc_auc": 0.792}, "NR-AR": {"roc_auc": 0.82}, "NR-AR-LBD": {"roc_auc": 0.75}, "NR-AhR": {"roc_auc": 0.79}, "NR-Aromatase": {"roc_auc": 0.72}, "NR-ER": {"roc_auc": 0.85}, "NR-ER-LBD": {"roc_auc": 0.76}, "NR-PPAR-gamma": {"roc_auc": 0.78}, "SR-ARE": {"roc_auc": 0.73}, "SR-ATAD5": {"roc_auc": 0.80}, "SR-HSE": {"roc_auc": 0.74}, "SR-MMP": {"roc_auc": 0.77}, "SR-p53": {"roc_auc": 0.81}}}
backend/__init__.py ADDED
File without changes
backend/data_loader.py ADDED
@@ -0,0 +1,57 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Data loading functionality for the Tox21 leaderboard.
3
+ Handles loading and processing results from HuggingFace datasets.
4
+ """
5
+
6
+ import pandas as pd
7
+ from datasets import load_dataset
8
+ from config.settings import RESULTS_DATASET, HF_TOKEN
9
+
10
+
11
+ def load_leaderboard_data() -> pd.DataFrame:
12
+ """
13
+ Load leaderboard data from HuggingFace dataset.
14
+ """
15
+ print(f"Loading dataset: {RESULTS_DATASET}")
16
+
17
+ # Load the dataset
18
+ dataset = load_dataset(RESULTS_DATASET, token=HF_TOKEN)
19
+ print(f"Dataset loaded successfully. Keys: {dataset.keys()}")
20
+
21
+ # Look for test split (more appropriate for results)
22
+ if 'test' in dataset:
23
+ results_data = dataset['test']
24
+ print(f"Test split has {len(results_data)} entries")
25
+ if len(results_data) > 0:
26
+ print(f"First entry keys: {results_data[0].keys()}")
27
+ print(f"First entry: {results_data[0]}")
28
+ else:
29
+ raise ValueError("Dataset does not contain a 'test' split.")
30
+
31
+ # Convert to DataFrame
32
+ rows = []
33
+ for entry in results_data:
34
+ config = entry['config']
35
+ results = entry['results']
36
+
37
+ # Create a row with all the data
38
+ row = {
39
+ 'Model': config['model_name'],
40
+ 'Model Description': config['model_description'],
41
+ 'Publication': config['publication_title'],
42
+ 'Parameters': config['parameters'],
43
+ 'Date Added': str(config['date_added']).split()[0], # Just the date part
44
+ 'Overall Score': results['overall_score']['roc_auc']
45
+ }
46
+
47
+ # Add individual task scores
48
+ for task_key, task_result in results.items():
49
+ if task_key != 'overall_score': # Skip overall score
50
+ row[task_key] = task_result['roc_auc']
51
+
52
+ rows.append(row)
53
+
54
+ df = pd.DataFrame(rows)
55
+ print(df)
56
+ print(f"Created DataFrame with shape: {df.shape}")
57
+ return df
backend/evaluator.py ADDED
File without changes
backend/validator.py ADDED
File without changes
config/__init__.py ADDED
File without changes
config/settings.py ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ from dotenv import load_dotenv
3
+
4
+ # Load environment variables from .env file (local development only)
5
+ # On HuggingFace Spaces, environment variables come from Secrets
6
+ try:
7
+ load_dotenv() # This will be ignored if .env doesn't exist (on server)
8
+ except:
9
+ pass
10
+
11
+ # HuggingFace Configuration
12
+ HUGGINGFACE_ORG = "Tschoui" # Your HuggingFace username/org
13
+ HF_TOKEN = os.environ.get("HF_TOKEN") # Local: from .env, Server: from Spaces Secrets
14
+
15
+ # Validate token exists
16
+ if not HF_TOKEN:
17
+ print("⚠️ Warning: HF_TOKEN not found. Please set it in .env (local) or Spaces Secrets (server)")
18
+ else:
19
+ print("βœ… HF_TOKEN loaded successfully")
20
+
21
+ # Dataset Repositories
22
+ REQUESTS_DATASET = f"{HUGGINGFACE_ORG}/tox21-requests"
23
+ RESULTS_DATASET = f"{HUGGINGFACE_ORG}/tox21-results"
24
+
25
+ # Local Cache Paths
26
+ CACHE_PATH = os.getenv("HF_HOME", ".")
27
+ EVAL_REQUESTS_PATH = os.path.join(CACHE_PATH, "eval-queue")
28
+ EVAL_RESULTS_PATH = os.path.join(CACHE_PATH, "eval-results")
29
+
30
+ # Application Settings
31
+ APP_TITLE = "Tox21 Leaderboard"
32
+ APP_DESCRIPTION = "Leaderboard for molecular toxicity prediction on the Tox21 dataset"
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"
42
+ SHOW_PENDING_EVALUATIONS = True
config/tasks.py ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from dataclasses import dataclass
2
+ from typing import List, Dict
3
+
4
+ @dataclass
5
+ class Task:
6
+ key: str
7
+ metric: str
8
+ display_name: str
9
+ description: str
10
+ group: str
11
+
12
+ # Tox21 Task Definitions
13
+ TOX21_TASKS = [
14
+ # Nuclear Receptors
15
+ Task("NR-AR", "roc_auc", "NR-AR", "Androgen receptor", "Nuclear Receptors"),
16
+ Task("NR-AR-LBD", "roc_auc", "NR-AR-LBD", "Androgen receptor ligand binding domain", "Nuclear Receptors"),
17
+ Task("NR-AhR", "roc_auc", "NR-AhR", "Aryl hydrocarbon receptor", "Nuclear Receptors"),
18
+ Task("NR-Aromatase", "roc_auc", "NR-Aromatase", "Aromatase enzyme", "Nuclear Receptors"),
19
+ Task("NR-ER", "roc_auc", "NR-ER", "Estrogen receptor", "Nuclear Receptors"),
20
+ Task("NR-ER-LBD", "roc_auc", "NR-ER-LBD", "Estrogen receptor ligand binding domain", "Nuclear Receptors"),
21
+ Task("NR-PPAR-gamma", "roc_auc", "NR-PPAR-gamma", "Peroxisome proliferator-activated receptor gamma", "Nuclear Receptors"),
22
+
23
+ # Stress Response Pathways
24
+ Task("SR-ARE", "roc_auc", "SR-ARE", "Antioxidant response element", "Stress Response"),
25
+ Task("SR-ATAD5", "roc_auc", "SR-ATAD5", "ATPase family AAA domain-containing protein 5", "Stress Response"),
26
+ Task("SR-HSE", "roc_auc", "SR-HSE", "Heat shock element", "Stress Response"),
27
+ Task("SR-MMP", "roc_auc", "SR-MMP", "Mitochondrial membrane potential", "Stress Response"),
28
+ Task("SR-p53", "roc_auc", "SR-p53", "Tumor protein p53", "Stress Response"),
29
+ ]
30
+
31
+ # Helper functions
32
+ def get_task_by_key(key: str) -> Task:
33
+ """Get task by its key identifier"""
34
+ for task in TOX21_TASKS:
35
+ if task.key == key:
36
+ return task
37
+ raise ValueError(f"Task {key} not found")
38
+
39
+ def get_tasks_by_group(group: str) -> List[Task]:
40
+ """Get all tasks in a specific group"""
41
+ return [task for task in TOX21_TASKS if task.group == group]
42
+
43
+ def get_all_task_keys() -> List[str]:
44
+ """Get list of all task keys"""
45
+ return [task.key for task in TOX21_TASKS]
46
+
47
+ def get_task_groups() -> Dict[str, List[Task]]:
48
+ """Get tasks organized by group"""
49
+ groups = {}
50
+ for task in TOX21_TASKS:
51
+ if task.group not in groups:
52
+ groups[task.group] = []
53
+ groups[task.group].append(task)
54
+ return groups
data/__init__.py ADDED
File without changes
data/models.py ADDED
File without changes
flagged/log.csv ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ x,output,flag,username,timestamp
2
+ test,Hello test!,,,2025-08-28 11:12:56.146286
frontend/__init__.py ADDED
File without changes
frontend/content.py ADDED
@@ -0,0 +1,85 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Content management for the Tox21 leaderboard frontend.
3
+ Contains all text, styling, and data formatting - separated from UI layout.
4
+ """
5
+ import pandas as pd
6
+ from typing import Dict, List
7
+ from config.tasks import TOX21_TASKS, get_task_groups
8
+ from config.settings import APP_TITLE, APP_DESCRIPTION
9
+
10
+
11
+ class LeaderboardContent:
12
+ """Content for the leaderboard tab"""
13
+
14
+ title = "πŸ§ͺ Tox21 Molecular Toxicity Leaderboard"
15
+ subtitle = "Ranking models by their performance on 12 toxicity prediction tasks"
16
+
17
+
18
+ @staticmethod
19
+ def get_header_html() -> str:
20
+ """Generate header HTML"""
21
+ return f"""
22
+ <div class="header-section">
23
+ <h2 class="header-title">{LeaderboardContent.title}</h2>
24
+ <p class="header-subtitle">
25
+ {LeaderboardContent.subtitle}
26
+ </p>
27
+ </div>
28
+ """
29
+
30
+ @staticmethod
31
+ def get_info_html() -> str:
32
+ """Generate info section HTML"""
33
+ return """
34
+ <div class="info-section">
35
+ <h4>ℹ️ How to Read the Leaderboard</h4>
36
+ <ul>
37
+ <li><strong>Average Score</strong>: Mean ROC-AUC across all 12 tasks</li>
38
+ <li><strong>Individual Tasks</strong>: ROC-AUC score (0.0 to 1.0, higher is better)</li>
39
+ <li><strong>Ranking</strong>: Models sorted by average score</li>
40
+ </ul>
41
+ </div>
42
+ """
43
+
44
+
45
+
46
+ class AboutContent:
47
+ """Content for the about tab"""
48
+
49
+ @staticmethod
50
+ def get_markdown_content() -> str:
51
+ """Generate about page markdown content"""
52
+ return f"""
53
+ # About the Tox21 Leaderboard
54
+
55
+ {APP_DESCRIPTION}
56
+
57
+ # TODO
58
+ add more text. Assumption: If content gets more, this tab will be displayed
59
+ more nicely.
60
+
61
+ ## Citation
62
+
63
+ If you use this leaderboard in your research, please cite:
64
+
65
+ ```bibtex
66
+ -
67
+ ```
68
+ """
69
+
70
+
71
+ class SubmissionContent:
72
+ """Content for the submission tab"""
73
+
74
+ title = "πŸš€ Submit Your Model"
75
+
76
+ @staticmethod
77
+ def get_instructions_html() -> str:
78
+ """Generate submission instructions HTML"""
79
+ return f"""
80
+ # TODO
81
+ add more text. Assumption: If content gets more, this tab will be displayed
82
+ more nicely.
83
+ """
84
+
85
+
frontend/layout.py ADDED
@@ -0,0 +1,137 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ UI Layout components for the Tox21 leaderboard.
3
+ Pure Gradio structure - no content or business logic.
4
+ """
5
+ import gradio as gr
6
+ from typing import Callable, Any
7
+ from .content import LeaderboardContent, AboutContent, SubmissionContent
8
+ from frontend.leaderboard import refresh_leaderboard
9
+ import os
10
+ import pandas as pd
11
+ from gradio_leaderboard import Leaderboard
12
+
13
+
14
+ def create_leaderboard_tab(refresh_callback: Callable = None) -> gr.TabItem:
15
+ """Create the leaderboard tab layout"""
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
+ # Load initial data
23
+ result_data = refresh_leaderboard().reset_index(drop=True)
24
+ result_data.columns = result_data.columns.map(str)
25
+
26
+ leaderboard_table = Leaderboard(
27
+ value=result_data,
28
+ search_columns=["Model", "Model Description", "Publication"], # or e.g. ["Model", "Model Description", "Publication"]
29
+ select_columns=[], # or e.g. ["Publication"]
30
+ filter_columns=[], # or a list of valid column names/filters
31
+ hide_columns=[], # keep explicit to be safe
32
+ elem_id="leaderboard-table",
33
+ height=480, # only controls vertical
34
+ min_width=160, # doesn’t prevent horizontal scroll
35
+ wrap=True,
36
+ column_widths=[200, 300, 150, 100, 120, 100] + [80] * 12,
37
+ )
38
+
39
+
40
+ # Info section
41
+ info_html = gr.HTML(LeaderboardContent.get_info_html())
42
+
43
+ return tab, leaderboard_table
44
+
45
+
46
+ def create_about_tab() -> gr.TabItem:
47
+ """Create the about tab layout"""
48
+
49
+ with gr.TabItem("πŸ“ About", elem_id="about-tab", id=1) as tab:
50
+ content_markdown = gr.Markdown(
51
+ AboutContent.get_markdown_content(),
52
+ elem_classes="markdown-text"
53
+ )
54
+
55
+ return tab
56
+
57
+
58
+ def create_submission_tab(submit_callback: Callable = None) -> gr.TabItem:
59
+ """Create the submission tab layout"""
60
+
61
+ with gr.TabItem("πŸš€ Submit", elem_id="submission-tab", id=2) as tab:
62
+
63
+ # Header
64
+ gr.HTML(f"<h2 style='text-align: center;'>{SubmissionContent.title}</h2>")
65
+
66
+ # Instructions
67
+ instructions_html = gr.HTML(SubmissionContent.get_instructions_html())
68
+
69
+ # Future form components (commented out for now)
70
+ """
71
+ with gr.Group():
72
+ model_name = gr.Textbox(
73
+ label=SubmissionContent.form_labels["model_name"],
74
+ placeholder=SubmissionContent.form_placeholders["model_name"]
75
+ )
76
+
77
+ with gr.Row():
78
+ model_revision = gr.Textbox(
79
+ label=SubmissionContent.form_labels["model_revision"],
80
+ placeholder=SubmissionContent.form_placeholders["model_revision"],
81
+ value="main"
82
+ )
83
+ model_type = gr.Dropdown(
84
+ choices=SubmissionContent.model_types,
85
+ label=SubmissionContent.form_labels["model_type"]
86
+ )
87
+ precision = gr.Dropdown(
88
+ choices=SubmissionContent.precisions,
89
+ label=SubmissionContent.form_labels["precision"],
90
+ value="float16"
91
+ )
92
+
93
+ description = gr.Textbox(
94
+ label=SubmissionContent.form_labels["description"],
95
+ placeholder=SubmissionContent.form_placeholders["description"],
96
+ lines=3
97
+ )
98
+
99
+ submit_btn = gr.Button("Submit Model", variant="primary")
100
+ result_msg = gr.HTML()
101
+
102
+ if submit_callback:
103
+ submit_btn.click(
104
+ fn=submit_callback,
105
+ inputs=[model_name, model_revision, model_type, precision, description],
106
+ outputs=result_msg
107
+ )
108
+ """
109
+
110
+ return tab
111
+
112
+
113
+ def create_main_interface(
114
+ refresh_callback: Callable = None,
115
+ submit_callback: Callable = None
116
+ ) -> gr.Blocks:
117
+ """Create the main application interface"""
118
+
119
+ # Load CSS from file
120
+ css_path = os.path.join(os.path.dirname(__file__), 'styles.css')
121
+ with open(css_path, 'r') as f:
122
+ css = f.read()
123
+
124
+ with gr.Blocks(css=css, title="Tox21 Leaderboard") as app:
125
+
126
+ # Main title
127
+ gr.HTML("<h1>πŸ§ͺ Tox21 Leaderboard</h1>")
128
+
129
+ # Tab container
130
+ with gr.Tabs(elem_classes="tab-nav") as tabs:
131
+
132
+ # Create all tabs
133
+ leaderboard_tab, leaderboard_table = create_leaderboard_tab(refresh_callback)
134
+ about_tab = create_about_tab()
135
+ submission_tab = create_submission_tab(submit_callback)
136
+
137
+ return app, leaderboard_table
frontend/leaderboard.py ADDED
@@ -0,0 +1,104 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Leaderboard-specific business logic.
3
+ Handles data processing, backend communication, and state management.
4
+ """
5
+ import pandas as pd
6
+ from typing import Optional
7
+
8
+ from .content import LeaderboardContent
9
+
10
+
11
+ def refresh_leaderboard() -> pd.DataFrame:
12
+ """
13
+ Refresh leaderboard data by fetching from backend.
14
+ Currently returns sample data - will connect to backend later.
15
+ """
16
+ print("= Refreshing leaderboard data...")
17
+
18
+ # Load data from backend
19
+ from backend.data_loader import load_leaderboard_data
20
+
21
+ results_data = load_leaderboard_data()
22
+ return results_data
23
+
24
+
25
+ def format_leaderboard_data(raw_data: dict) -> pd.DataFrame:
26
+ """
27
+ Format raw leaderboard data for display.
28
+
29
+ Args:
30
+ raw_data: Raw data from backend/datasets
31
+
32
+ Returns:
33
+ Formatted DataFrame for Gradio display
34
+ """
35
+ # TODO: Implement data formatting logic
36
+ # This will process raw evaluation results into the display format
37
+ pass
38
+
39
+
40
+ def calculate_average_score(task_scores: dict) -> float:
41
+ """
42
+ Calculate average ROC-AUC score across all tasks.
43
+
44
+ Args:
45
+ task_scores: Dictionary of task_name -> score
46
+
47
+ Returns:
48
+ Average score across all tasks
49
+ """
50
+ if not task_scores:
51
+ return 0.0
52
+
53
+ valid_scores = [score for score in task_scores.values() if score is not None]
54
+ if not valid_scores:
55
+ return 0.0
56
+
57
+ return sum(valid_scores) / len(valid_scores)
58
+
59
+
60
+ def sort_by_performance(leaderboard_data: pd.DataFrame) -> pd.DataFrame:
61
+ """
62
+ Sort leaderboard by average performance score.
63
+
64
+ Args:
65
+ leaderboard_data: DataFrame with leaderboard data
66
+
67
+ Returns:
68
+ Sorted DataFrame with rank column updated
69
+ """
70
+ # Sort by average score (descending)
71
+ sorted_data = leaderboard_data.sort_values(by="Average", ascending=False)
72
+
73
+ # Update rank column
74
+ sorted_data["Rank"] = range(1, len(sorted_data) + 1)
75
+
76
+ return sorted_data
77
+
78
+
79
+ def filter_leaderboard(
80
+ data: pd.DataFrame,
81
+ min_score: Optional[float] = None,
82
+ model_type: Optional[str] = None,
83
+ date_range: Optional[tuple] = None
84
+ ) -> pd.DataFrame:
85
+ """
86
+ Filter leaderboard data based on criteria.
87
+
88
+ Args:
89
+ data: Original leaderboard data
90
+ min_score: Minimum average score threshold
91
+ model_type: Filter by model type
92
+ date_range: Filter by submission date range
93
+
94
+ Returns:
95
+ Filtered DataFrame
96
+ """
97
+ filtered_data = data.copy()
98
+
99
+ if min_score is not None:
100
+ filtered_data = filtered_data[filtered_data["Average"] >= min_score]
101
+
102
+ # TODO: Add more filtering logic as needed
103
+
104
+ return filtered_data
frontend/styles.css ADDED
File without changes
frontend/submission.py ADDED
File without changes
frontend/utils.py ADDED
File without changes
tests/__init__.py ADDED
File without changes
tests/test_dataset_connection.py ADDED
@@ -0,0 +1,84 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from huggingface_hub import hf_hub_download, list_repo_files
2
+ import json
3
+ import sys
4
+ import os
5
+
6
+ # Add parent directory to path to import config
7
+ sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
8
+
9
+ from config.settings import REQUESTS_DATASET, RESULTS_DATASET, HF_TOKEN
10
+
11
+
12
+ def test_dataset_connection():
13
+ """Test connection to both datasets"""
14
+ print("Testing dataset connections...")
15
+
16
+ try:
17
+ # Test requests dataset
18
+ request_files = list_repo_files(
19
+ repo_id=REQUESTS_DATASET,
20
+ repo_type="dataset",
21
+ token=HF_TOKEN
22
+ )
23
+ print(f"βœ… Requests dataset connected: {REQUESTS_DATASET}")
24
+ print(f" Files: {request_files}")
25
+ except Exception as e:
26
+ print(f"❌ Requests dataset error: {e}")
27
+
28
+ try:
29
+ # Test results dataset
30
+ result_files = list_repo_files(
31
+ repo_id=RESULTS_DATASET,
32
+ repo_type="dataset",
33
+ token=HF_TOKEN
34
+ )
35
+ print(f"βœ… Results dataset connected: {RESULTS_DATASET}")
36
+ print(f" Files: {result_files}")
37
+ except Exception as e:
38
+ print(f"❌ Results dataset error: {e}")
39
+
40
+
41
+ def test_file_downloads():
42
+ """Test downloading example files"""
43
+ print("\nTesting file downloads...")
44
+
45
+ try:
46
+ # Download and load example request
47
+ file_path = hf_hub_download(
48
+ repo_id=REQUESTS_DATASET,
49
+ filename="example_request.json",
50
+ repo_type="dataset",
51
+ token=HF_TOKEN
52
+ )
53
+
54
+ with open(file_path, 'r') as f:
55
+ request_data = json.load(f)
56
+
57
+ print("βœ… Example request loaded:")
58
+ print(json.dumps(request_data, indent=2))
59
+
60
+ except Exception as e:
61
+ print(f"❌ Request file error: {e}")
62
+
63
+ try:
64
+ # Download and load example result
65
+ file_path = hf_hub_download(
66
+ repo_id=RESULTS_DATASET,
67
+ filename="example_result.json",
68
+ repo_type="dataset",
69
+ token=HF_TOKEN
70
+ )
71
+
72
+ with open(file_path, 'r') as f:
73
+ result_data = json.load(f)
74
+
75
+ print("βœ… Example result loaded:")
76
+ print(json.dumps(result_data, indent=2))
77
+
78
+ except Exception as e:
79
+ print(f"❌ Result file error: {e}")
80
+
81
+
82
+ if __name__ == "__main__":
83
+ test_dataset_connection()
84
+ test_file_downloads()