sahara / app.py
elmadany's picture
Update app.py
d8814af verified
raw
history blame
17.5 kB
import gradio as gr
from src.helper import *
# Custom CSS to replicate the Google-style card design from the image
custom_head_html = """
<link rel="stylesheet" href="https://africa.dlnlp.ai/sahara/font-awesome/css/font-awesome.min.css">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.0/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<link rel="stylesheet" type="text/css" href="./public/css/style.min.css">
<script defer src="./public/js/script.js"></script>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&family=Rubik:wght@400;600&display=swap" rel="stylesheet">
"""
new_header_html = """
<center>
<br><br><br>
<img src="https://africa.dlnlp.ai/sahara/img/sahara_web_main.jpg" alt="Sahara logo" width="60%">
</p>
</center>
<br style="height:1px;">
"""
google_style_css = """
/* Citation Block */
.citation-block {
position: relative;
background-color: #FDF6E3; /* Light cream background */
border-radius: 8px;
padding: 25px;
}
.citation-block pre {
background-color: transparent;
border: none;
padding: 0;
/* font-size: 14px; */
white-space: pre-wrap;
word-break: break-all;
}
.citation-block .btn-copy {
position: absolute;
top: 15px;
right: 15px;
background-color: #D97706;
border-color: #c56a05;
color: white;
}
.citation-block .btn-copy:hover, .citation-block .btn-copy:focus {
background-color: #c56a05;
color: white;
}
.fillable.svelte-15jxnnn.svelte-15jxnnn:not(.fill_width) {
/* min-width: 400px !important; */
max-width: 1580px !important;
}
.flat-navy-button {
background-color: #117b75 !important; /* Navy Blue */
color: #fff !important;
font-weight: bold !important;
border-radius: 5px !important; /* Slightly rounded corners */
border: none !important;
box-shadow: none !important;
}
.flat-navy-button:hover {
background-color: #117b75 !important; /* Lighter navy for hover */
color: #e8850e !important;
}
div[class*="gradio-container"] {
background:#FFFBF5 !important;
}
div.svelte-1nguped {
background: white !important;
}
/* Main Content Area */
.content-section {
padding: 60px 0;
}
.content-card {
background-color: #fff;
border-radius: 12px;
box-shadow: 0 10px 15px -3px rgba(0,0,0,0.1), 0 4px 6px -2px rgba(0,0,0,0.05);
padding: 40px;
margin-bottom: 40px;
}
.btn-cite {
color: #7d3561;
font-size: 16px;
margin: 0 3px; /* Add spacing between multiple icons */
}
.content-card h4 {
font-family: "Rubik", sans-serif;
color: #7d3561;
}
.content-card h2 {
font-family: "Rubik", sans-serif;
font-size: 30px;
font-weight: 600;
line-height: 1.25;
letter-spacing: -1px;
color: #2f3b7d;
text-transform:none;
/* font-size: 30px;
font-weight: bold;
color: #D97706; /* Brand Orange */
margin-top: 0;
margin-bottom: 20px; */
}
.content-card h3 {
font-size: 20px;
color: #2f3b7d;
}
.content-card h3 .title {
color: #7d3561;
}
.content-card p {
/* font-size: 18px; */
/* line-height: 1.7; */
}
div.svelte-wv8on1{
# border: 2px solid #074e4a !important;
border-top: 0 !important;
/* background-color: #fff2eb !important; */
padding: 10px !important;
}
.padding.svelte-phx28p {
padding:0 !important;
}
.tab-wrapper.svelte-1tcem6n.svelte-1tcem6n {
display: flex;
align-items: center;
justify-content: space-between;
position: relative;
height: 0 !important;
padding-bottom: 0 !important;
}
.selected.svelte-1tcem6n.svelte-1tcem6n {
background-color: #7d3561 !important;
color: #fff !important;
}
.tabs.svelte-1tcem6n.svelte-1tcem6n {
/* border: 1px solid #dca02a !important; */
border-top: 0 !important;
/* background-color: #dca02a !important; */
}
button.svelte-1tcem6n.svelte-1tcem6n {
color: #7d3561 !important;
/* border: 1px solid #dca02a !important; */
font-weight: bold;
/* font-size: 16px; */
padding: 8px 5px;
}
.tab-container.svelte-1tcem6n.svelte-1tcem6n:after {
content: "";
position: absolute;
bottom: 0;
left: 0;
right: 0;
height: 2px;
background-color: #7d3561 !important;
}
div[class*="gradio-container"] .prose table,
div[class*="gradio-container"] .prose tr,
div[class*="gradio-container"] .prose td,
div[class*="gradio-container"] .prose th {
border: 0 !important;
border-top: 2px solid #dca02a;
border-bottom: 2px solid #dca02a;
}
div[class*="gradio-container"] .prose table {
border-top: 2px solid #dca02a !important;
border-bottom: 2px solid #dca02a !important;
margin-bottom:20px;
margin-left: auto;
margin-right: auto;
width: 100%;
border-collapse: collapse;
table-layout: fixed;
}
div[class*="gradio-container"] .prose thead tr {
border-bottom: 2px solid #dca02a !important;
}
div[class*="gradio-container"] .prose th .rotate_div {
transform: rotate(-45deg) !important;
color: #7d3561;
padding-top: 10px !important;
padding-bottom: 5px !important;
font-weight: None !important;
font-size: 12px !important;
/*height: 30px !important; Give the cell enough height for the rotated text */
}
div[class*="gradio-container"] .prose th {
/* transform: rotate(-90deg) !important; */
color: #7d3561;
font-weight: bold;
/* font-size: 20px; */
padding: 8px 5px;
vertical-align: middle;
border: 0 !important;
}
div[class*="gradio-container"] .prose td {
/* font-size: 18px; */
padding: 8px 5px;
border: 0 !important;
vertical-align: middle;
}
div[class*="gradio-container"] .prose th:first-child,
div[class*="gradio-container"] .prose td:first-child {
transform: rotate(0deg) !important;
min-width: 400px !important;
/* max-width: 400px !important; */
width:400px !important;
text-align: left !important;
}
div[class*="gradio-container"] .prose th:not(:first-child),
div[class*="gradio-container"] .prose td:not(:first-child) {
min-width: 90px;
/* max-width: 140px; */
width:auto !important;
text-align: center;
}
"""
introduction_text = """
"""
# with gr.Blocks(title="Sahara Leaderboard", css=custom_css) as demo:
# with gr.Blocks(title="Sahara Leaderboard") as demo:
with gr.Blocks(title="Sahara Benchmark Leaderboards", css=google_style_css) as demo:
# Use elem_classes to apply our custom CSS to this group
gr.HTML(new_header_html)
# === UPDATED BUTTONS START ===
with gr.Row():
gr.Button("Official Website", link="https://africa.dlnlp.ai/sahara", elem_classes=['flat-navy-button'])
gr.Button("ACL 2025 Paper", link="https://aclanthology.org/2025.acl-long.1572", elem_classes=['flat-navy-button'])
gr.Button("Tasks", link="https://africa.dlnlp.ai/sahara/tasks", elem_classes=['flat-navy-button'])
# gr.Button("Submission Instructions", link="https://africa.dlnlp.ai/sahara/instructions", elem_classes=['flat-navy-button'])
# gr.Button("New Submission", link="https://africa.dlnlp.ai/sahara/submit", elem_classes=['flat-navy-button'])
# gr.Button("GitHub Repo", link="https://github.com/UBC-NLP/sahara", elem_classes=['flat-navy-button'])
# These buttons will now show an alert message
# submission_btn = gr.Button("Submission Instructions", elem_classes=['flat-navy-button'])
# new_submission_btn = gr.Button("New Submission", elem_classes=['flat-navy-button'])
# github_btn = gr.Button("GitHub Repo", elem_classes=['flat-navy-button'])
# # Function to display the alert
# def show_coming_soon_alert():
# gr.Info("Stay tuned! It will be ready soon.")
# # Link the click event of each button to the alert function
# submission_btn.click(fn=show_coming_soon_alert)
# new_submission_btn.click(fn=show_coming_soon_alert)
# github_btn.click(fn=show_coming_soon_alert)
# === UPDATED BUTTONS END ===
with gr.Group(elem_classes="content-card"):
gr.Markdown("<br>")
# Hidden component to trigger JavaScript on load
# url_trigger = gr.Textbox(visible=False)
# State to hold URL parameters
# url_params_state = gr.State({})
with gr.Tabs() as tabs:
# Main leaderboard
with gr.Tab("Main Leaderboard", id="main"):
gr.HTML("<br><br><center><h2>Main Leaderboard</h2></center><br>")
gr.HTML(df_to_html(main_overall_tab))
# Task Clusters leaderboards
with gr.Tab("Task-Cluster Leaderboard", id="clusters"):
gr.HTML("<br><br><center><h2>Task-Cluster Leaderboard</h2></center><br>")
CLUSTERS_NAME=[cname for cname, cdf in cluster_tabs.items()]
cname = CLUSTERS_NAME[0]
initial_cluster_title_html = f"<h3><span class='title'>Task-Cluster name:</span> {cname}</span></h3>"
# 2. Create a variable for the title component so it can be updated.
cluster_title_component = gr.HTML(initial_cluster_title_html)
clusters_dropdown = gr.Dropdown(
choices=CLUSTERS_NAME,
label="Select Task-CLuster",
interactive=True,
elem_id="cluster_dropdown",
value=CLUSTERS_NAME[0] # Set default value
)
def get_claster_table(cluster_name):
for cname, cdf in cluster_tabs.items():
if cname== cluster_name:
return cdf
return None
cluster_table_component = gr.HTML(df_to_html(get_claster_table(CLUSTERS_NAME[0])) if CLUSTERS_NAME else "<b>No cluser found</b>")
def update_cluster_table(cluster_name):
df = get_claster_table(cluster_name)
cluster_title_html = f"<h3><span class='title'>Task-Cluster name:</span> {cluster_name}</span></h3>"
return cluster_title_html, df_to_html(df) if df is not None else "<b>No data found</b>"
clusters_dropdown.change(update_cluster_table, clusters_dropdown, outputs=[cluster_title_component, cluster_table_component])
# Languages Leaderboards
# Task-Specific Leaderboards
with gr.Tab("Task-Specific Leaderboard", id="tasks"):
# --- MODIFIED ---
# 1. Define the initial title based on the first task in the list.
gr.HTML("<br><br><center><h2>Task-Specific Leaderboard (per langauge)</h2></center><br>")
initial_task_name = TASK_NAME_LIST[0]
tname=initial_task_name.split(' (')[0]
tid=initial_task_name.split(' (')[-1].split(')')[0]
initial_title_html = f"<h3><span class='title'>Task name:</span> {tname}<br> <span class='title'>Task identifier:</span> {tid}</h3>"
# 2. Create a variable for the title component so it can be updated.
task_title_component = gr.HTML(initial_title_html)
# Dropdown for selecting the task (remains the same)
task_dropdown = gr.Dropdown(choices=TASK_NAME_LIST, label="Select Task", interactive=True, value=initial_task_name)
# --- MODIFIED ---
# 3. Modify the update function to return TWO values: the new title and the new table.
def update_task_table(task_name_with_id):
# Create the new dynamic title HTML
tname=task_name_with_id.split(' (')[0]
tid=task_name_with_id.split(' (')[-1].split(')')[0]
new_title = f"<h3><span class='title'>Task name:</span> {tname}<br> <span class='title'>Task identifier:</span> {tid}</h3>"
# new_title = f"<br><br><center><h2>{task_name_with_id} Leaderboard</h2></center><br>"
# Parse the task key to get the data
task_key = task_name_with_id.split('(')[-1].strip(')')
df = get_task_leaderboard(task_key)
# Return both the new title and the HTML for the table
return new_title, df_to_html(df)
# Initial table display (remains the same)
initial_task_key = initial_task_name.split('(')[-1].strip(')')
task_table_component = gr.HTML(df_to_html(get_task_leaderboard(initial_task_key)))
# --- MODIFIED ---
# 4. Update the .change() event to send outputs to BOTH the title and table components.
task_dropdown.change(
fn=update_task_table,
inputs=task_dropdown,
outputs=[task_title_component, task_table_component]
)
with gr.Tab("Language-Specific Leaderboard", id="langs"):
gr.HTML("<br><br><center><h2>Language-Specific Leaderboard (per task)</h2></center><br>")
lang_name=LANG_NAME_LIST[0]
initial_lang_title_html = f"<h3><span class='title'>Language name:</span> {lang_name} <br> <span class='title'>Language ISO-3:</span> {next(iter(LANGNAME2ISOS.get(lang_name)))} </h3>"
# 2. Create a variable for the title component so it can be updated.
lang_title_component = gr.HTML(initial_lang_title_html)
lang_dropdown = gr.Dropdown(choices=LANG_NAME_LIST, label="Select Language", interactive=True)
lang_table_component = gr.HTML(df_to_html(get_lang_table(LANG_NAME_LIST[0])) if LANG_NAME_LIST else "<b>No languages found</b>")
def update_lang_table(lang_name):
df = get_lang_table(lang_name)
new_title = f"<h3><span class='title'>Language name:</span> {lang_name} <br> <span class='title'>Language ISO-3:</span> {next(iter(LANGNAME2ISOS.get(lang_name)))}</h3>"
return new_title, df_to_html(df)
lang_dropdown.change(update_lang_table, lang_dropdown, outputs=[lang_title_component, lang_table_component])
# --- NEW TAB FOR MODEL-SPECIFIC LEADERBOARD ---
with gr.Tab("Model-Specific Leaderboard", id="models"):
gr.HTML("<br><br><center><h2>Model-Specific Leaderboard (per task)</h2></center><br>")
initial_model_name = MODEL_NAME_LIST[0]
initial_model_title_html = f"<h3><span class='title'>Model name:</span> {initial_model_name}</h3>"
# Component to display the dynamic title
model_title_component = gr.HTML(initial_model_title_html)
# Dropdown for selecting the model
model_dropdown = gr.Dropdown(
choices=MODEL_NAME_LIST,
label="Select Model",
interactive=True,
value=initial_model_name
)
# Component to display the model's performance table
model_table_component = gr.HTML(df_to_html(get_model_table(initial_model_name)))
# Function to update the title and table based on dropdown selection
def update_model_table(model_name):
df = get_model_table(model_name)
new_title = f"<h3><span class='title'>Model name:</span> {model_name}</h3>"
return new_title, df_to_html(df)
# Link the dropdown's change event to the update function
model_dropdown.change(
fn=update_model_table,
inputs=model_dropdown,
outputs=[model_title_component, model_table_component]
)
with gr.Group(elem_classes="content-card"):
gr.Markdown("<br>")
gr.HTML("<h2>Citation</h2>If you use the Sahara benchmark for your scientific publication, or if you find the resources in this website useful, please cite our <a href='https://africa.dlnlp.ai/sahara/'>ACL2025 paper </a>as well as the papers of the <a href='https://africa.dlnlp.ai/sahara/tasks'>original authors</a>.")
gr.HTML("<center><img src='https://africa.dlnlp.ai/sahara//img/sahara_web_sponsers.jpg' width='25%'> </center>")
if __name__ == "__main__":
demo.launch(share=True)