File size: 11,310 Bytes
9ab539a
124bec5
9ab539a
 
 
 
fbd403a
9ab539a
 
 
 
 
 
 
 
f03f82b
9ab539a
 
 
 
 
 
 
 
124bec5
bccaf50
 
9ab539a
fbd403a
9ab539a
 
 
 
 
fbd403a
 
 
 
 
 
 
 
 
 
9ab539a
 
fbd403a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9ab539a
 
92edcfa
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
fbd403a
9ab539a
 
 
 
 
 
 
fbd403a
9ab539a
fbd403a
5fc842f
124bec5
fbd403a
 
92edcfa
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
124bec5
 
92edcfa
124bec5
 
 
 
 
 
92edcfa
124bec5
bccaf50
9ab539a
 
 
 
 
 
 
 
 
 
bccaf50
9ab539a
 
bccaf50
9ab539a
 
bccaf50
9ab539a
 
 
 
 
 
bccaf50
9ab539a
 
 
124bec5
9ab539a
 
 
 
 
 
bccaf50
9ab539a
 
 
124bec5
9ab539a
 
 
 
 
 
 
bccaf50
9ab539a
 
 
124bec5
9ab539a
 
 
 
 
 
bccaf50
9ab539a
 
 
bccaf50
 
 
 
 
9ab539a
 
 
 
 
 
bccaf50
 
 
92edcfa
 
9ab539a
 
bccaf50
 
9ab539a
bccaf50
9ab539a
 
 
 
bccaf50
 
 
 
 
 
9ab539a
 
 
 
 
da89e08
 
9ab539a
 
da89e08
9ab539a
da89e08
9ab539a
 
fbd403a
 
 
 
 
 
 
b5628ea
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
import gradio as gr
from gradio.components import Dataframe
from gradio_leaderboard import Leaderboard, ColumnFilter, SelectColumns
import pandas as pd
from apscheduler.schedulers.background import BackgroundScheduler
from huggingface_hub import snapshot_download
import os

from src.about import (
    CITATION_BUTTON_LABEL,
    CITATION_BUTTON_TEXT,
    EVALUATION_QUEUE_TEXT,
    INTRODUCTION_TEXT,
    LLM_BENCHMARKS_TEXT,
    TITLE,
    Tasks
)
from src.display.css_html_js import custom_css
from src.display.utils import (
    BENCHMARK_COLS,
    COLS,
    EVAL_COLS,
    EVAL_TYPES,
    AutoEvalColumn,
    auto_eval_column_attrs,
    LibraryType,
    Language,
)
from src.envs import API, EVAL_REQUESTS_PATH, EVAL_RESULTS_PATH, QUEUE_REPO, REPO_ID, RESULTS_REPO, TOKEN, LOCAL_MODE
from src.populate import get_evaluation_queue_df, get_leaderboard_df
from src.submission.submit import add_new_eval


def restart_space():
    """Restart the Hugging Face space"""
    if LOCAL_MODE:
        print("Running in local mode, skipping space restart")
        return
        
    try:
        API.restart_space(repo_id=REPO_ID)
    except Exception as e:
        print(f"Failed to restart space: {e}")
        print("Continuing without restart")

### Space initialisation
def initialize_data_directories():
    """Initialize directories for assessment data"""
    # Create local directories if they don't exist
    os.makedirs(EVAL_REQUESTS_PATH, exist_ok=True)
    os.makedirs(EVAL_RESULTS_PATH, exist_ok=True)
    
    if LOCAL_MODE:
        print("Running in local mode, using local directories only")
        return
    
    # Try to download from HF if not in local mode
    try:
        print(f"Downloading request data from {QUEUE_REPO} to {EVAL_REQUESTS_PATH}")
        snapshot_download(
            repo_id=QUEUE_REPO, local_dir=EVAL_REQUESTS_PATH, repo_type="dataset", 
            tqdm_class=None, etag_timeout=30, token=TOKEN
        )
    except Exception as e:
        print(f"Failed to download request data: {e}")
        print("Using local data only")
    
    try:
        print(f"Downloading result data from {RESULTS_REPO} to {EVAL_RESULTS_PATH}")
        snapshot_download(
            repo_id=RESULTS_REPO, local_dir=EVAL_RESULTS_PATH, repo_type="dataset", 
            tqdm_class=None, etag_timeout=30, token=TOKEN
        )
    except Exception as e:
        print(f"Failed to download result data: {e}")
        print("Using local data only")

# Initialize data
initialize_data_directories()

# Load data for leaderboard
LEADERBOARD_DF = get_leaderboard_df(EVAL_RESULTS_PATH, EVAL_REQUESTS_PATH, COLS, BENCHMARK_COLS)

# Extract unique languages for filtering
def get_unique_languages(df):
    """Extract all unique individual languages from the Language column"""
    if df.empty or auto_eval_column_attrs.language.name not in df.columns:
        return []
    
    all_languages = set()
    for value in df[auto_eval_column_attrs.language.name].unique():
        if isinstance(value, str):
            if "/" in value:
                languages = [lang.strip() for lang in value.split("/")]
                all_languages.update(languages)
            else:
                all_languages.add(value.strip())
    
    return sorted(list(all_languages))

# Create a mapping for language filtering
UNIQUE_LANGUAGES = get_unique_languages(LEADERBOARD_DF)

# Create a special column for individual language filtering
if not LEADERBOARD_DF.empty:
    # Create a column that contains all individual languages as a list
    LEADERBOARD_DF["_languages_list"] = LEADERBOARD_DF[auto_eval_column_attrs.language.name].apply(
        lambda x: [lang.strip() for lang in str(x).split("/")] if pd.notna(x) else []
    )
    
    # Create a text version of Active Maintenance for checkboxgroup filtering
    LEADERBOARD_DF["_maintenance_filter"] = LEADERBOARD_DF[auto_eval_column_attrs.availability.name].apply(
        lambda x: "Active" if x else "Inactive"
    )

# Load queue data
(
    finished_eval_queue_df,
    running_eval_queue_df,
    pending_eval_queue_df,
) = get_evaluation_queue_df(EVAL_REQUESTS_PATH, EVAL_COLS)

def init_leaderboard(dataframe):
    """Initialize the leaderboard component"""
    if dataframe is None or dataframe.empty:
        # Create an empty dataframe with the expected columns
        all_columns = COLS + [task.value.col_name for task in Tasks]
        empty_df = pd.DataFrame(columns=pd.Index(all_columns))
        print("Warning: Leaderboard DataFrame is empty. Using empty dataframe.")
        dataframe = empty_df
        
    # Create filter columns list with proper typing
    filter_columns = []
    
    # 1. Library types
    filter_columns.append(ColumnFilter(auto_eval_column_attrs.library_type.name, type="checkboxgroup", label="Library types"))
    
    # 2. Programming Language (checkboxgroup - OR filtering)
    filter_columns.append(ColumnFilter(auto_eval_column_attrs.language.name, type="checkboxgroup", label="Programming Language"))
    
    # 3. GitHub Stars
    filter_columns.append(ColumnFilter(
        auto_eval_column_attrs.stars.name,
        type="slider",
        min=0,
        max=50000,
        label="GitHub Stars",
    ))
    
    # 4. Maintenance Status (checkboxgroup - separate from languages)
    filter_columns.append(ColumnFilter("_maintenance_filter", type="checkboxgroup", label="Maintenance Status"))
    
    # Hide columns
    hidden_columns = [getattr(auto_eval_column_attrs, field).name for field in AutoEvalColumn.model_fields if getattr(auto_eval_column_attrs, field).hidden]
    hidden_columns.extend(["_languages_list", "_maintenance_filter", "_original_language"])  # Hide helper columns
    
    # Update datatypes
    datatypes = [getattr(auto_eval_column_attrs, field).type for field in AutoEvalColumn.model_fields]
    
    return Leaderboard(
        value=dataframe,
        datatype=datatypes,
        select_columns=SelectColumns(
            default_selection=[getattr(auto_eval_column_attrs, field).name for field in AutoEvalColumn.model_fields if getattr(auto_eval_column_attrs, field).displayed_by_default],
            cant_deselect=[getattr(auto_eval_column_attrs, field).name for field in AutoEvalColumn.model_fields if getattr(auto_eval_column_attrs, field).never_hidden],
            label="Select Columns to Display:",
        ),
        search_columns=[auto_eval_column_attrs.library.name, auto_eval_column_attrs.license_name.name],
        hide_columns=hidden_columns,
        filter_columns=filter_columns, # type: ignore
        bool_checkboxgroup_label="Filter libraries",
        interactive=False,
    )


demo = gr.Blocks(css=custom_css)
with demo:
    gr.HTML(TITLE)
    gr.Markdown(INTRODUCTION_TEXT, elem_classes="markdown-text")

    with gr.Tabs(elem_classes="tab-buttons") as tabs:
        with gr.TabItem("πŸ… Vulnerability Leaderboard", elem_id="vulnerability-leaderboard-tab", id=0):
            leaderboard = init_leaderboard(LEADERBOARD_DF)

        with gr.TabItem("πŸ“ About", elem_id="about-tab", id=2):
            gr.Markdown(LLM_BENCHMARKS_TEXT, elem_classes="markdown-text")

        with gr.TabItem("πŸš€ Submit Library", elem_id="submit-library-tab", id=3):
            with gr.Column():
                with gr.Row():
                    gr.Markdown(EVALUATION_QUEUE_TEXT, elem_classes="markdown-text")

                with gr.Column():
                    with gr.Accordion(
                        f"βœ… Completed Assessments ({len(finished_eval_queue_df)})",
                        open=False,
                    ):
                        with gr.Row():
                            finished_eval_table = Dataframe(
                                value=finished_eval_queue_df,
                                headers=EVAL_COLS,
                                datatype=EVAL_TYPES,
                                row_count=5,
                            )
                    with gr.Accordion(
                        f"πŸ”„ In Progress Assessments ({len(running_eval_queue_df)})",
                        open=False,
                    ):
                        with gr.Row():
                            running_eval_table = Dataframe(
                                value=running_eval_queue_df,
                                headers=EVAL_COLS,
                                datatype=EVAL_TYPES,
                                row_count=5,
                            )

                    with gr.Accordion(
                        f"⏳ Pending Assessment Queue ({len(pending_eval_queue_df)})",
                        open=False,
                    ):
                        with gr.Row():
                            pending_eval_table = Dataframe(
                                value=pending_eval_queue_df,
                                headers=EVAL_COLS,
                                datatype=EVAL_TYPES,
                                row_count=5,
                            )
            with gr.Row():
                gr.Markdown("# βœ‰οΈβœ¨ Submit a library for vulnerability assessment", elem_classes="markdown-text")

            with gr.Row():
                with gr.Column():
                    library_name_textbox = gr.Textbox(label="Library name (org/repo format)")
                    library_version_textbox = gr.Textbox(label="Version", placeholder="v1.0.0")
                    library_type = gr.Dropdown(
                        choices=[t.to_str(" : ") for t in LibraryType if t != LibraryType.Unknown],
                        label="Library type",
                        multiselect=False,
                        value=None,
                        interactive=True,
                    )

                with gr.Column():
                    language = gr.Dropdown(
                        choices=[i.value.name for i in Language if i != Language.Other],
                        label="Programming Language",
                        multiselect=True,
                        value=["Python"],
                        interactive=True,
                    )
                    framework = gr.Textbox(label="Framework/Ecosystem (e.g., PyTorch, React)")
                    repository_url = gr.Textbox(label="Repository URL")

            submit_button = gr.Button("Submit for Assessment")
            submission_result = gr.Markdown()
            submit_button.click(
                add_new_eval,
                [
                    library_name_textbox,
                    library_version_textbox,
                    repository_url,
                    language,
                    framework,
                    library_type,
                ],
                submission_result,
            )

    with gr.Row():
        with gr.Accordion("πŸ“™ Citation", open=True):
            citation_button = gr.Code(
                value=CITATION_BUTTON_TEXT,
                label=CITATION_BUTTON_LABEL,
                lines=6,
                elem_id="citation-button",
                language="latex",
            )

# Only schedule space restarts if not in local mode
if not LOCAL_MODE:
    scheduler = BackgroundScheduler()
    scheduler.add_job(restart_space, "interval", seconds=1800)
    scheduler.start()

# Launch the app
demo.queue(default_concurrency_limit=40).launch(show_error=True)