import gradio as gr
import pandas as pd
import plotly.express as px
from dataclasses import dataclass, field
from typing import List, Dict, Tuple, Union
import json
import os
from collections import OrderedDict
@dataclass
class ScorecardCategory:
name: str
questions: List[Dict[str, Union[str, List[str]]]]
scores: Dict[str, int] = field(default_factory=dict)
def load_scorecard_templates(directory):
templates = []
for filename in os.listdir(directory):
if filename.endswith('.json'):
with open(os.path.join(directory, filename), 'r') as file:
data = json.load(file)
templates.append(ScorecardCategory(
name=data['name'],
questions=data['questions']
))
return templates
# Load scorecard templates
scorecard_template = load_scorecard_templates('scorecard_templates')
# Function to read JSON files and populate models dictionary
def load_models_from_json(directory):
models = {}
for filename in os.listdir(directory):
if filename.endswith('.json'):
with open(os.path.join(directory, filename), 'r') as file:
model_data = json.load(file)
model_name = model_data['metadata']['Name']
models[model_name] = model_data
# Sort the models alphabetically by name
return OrderedDict(sorted(models.items(), key=lambda x: x[0].lower()))
# Load models from JSON files
models = load_models_from_json('model_data')
css = """
.container {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
}
.container.svelte-1hfxrpf.svelte-1hfxrpf {
height: 0%;
}
.card {
width: calc(50% - 20px);
border: 1px solid #e0e0e0;
border-radius: 10px;
padding: 20px;
margin-bottom: 20px;
background-color: #ffffff;
box-shadow: 0 4px 6px rgba(0,0,0,0.1);
transition: all 0.3s ease;
}
.card:hover {
box-shadow: 0 6px 8px rgba(0,0,0,0.15);
transform: translateY(-5px);
}
.card-title {
font-size: 1.4em;
font-weight: bold;
margin-bottom: 15px;
color: #333;
border-bottom: 2px solid #e0e0e0;
padding-bottom: 10px;
}
.question {
margin-bottom: 20px;
padding: 15px;
border-radius: 5px;
}
.question h3 {
margin-top: 0;
color: #2c3e50;
}
.question-yes {
background-color: #e6ffe6;
}
.question-no {
background-color: #ffe6e6;
}
.question-na {
background-color: #fffde6;
}
.status {
font-weight: bold;
}
details {
margin-top: 10px;
}
summary {
cursor: pointer;
color: #3498db;
font-weight: bold;
}
summary:hover {
text-decoration: underline;
}
.category-score, .total-score {
background-color: #f0f8ff;
border: 1px solid #b0d4ff;
border-radius: 5px;
padding: 10px;
margin-top: 15px;
font-weight: bold;
text-align: center;
}
.total-score {
font-size: 1.2em;
background-color: #e6f3ff;
border-color: #80bdff;
}
.leaderboard-card {
width: 100%;
max-width: 800px;
margin: 0 auto;
}
.leaderboard-table {
width: 100%;
border-collapse: collapse;
}
.leaderboard-table th, .leaderboard-table td {
padding: 10px;
text-align: left;
border-bottom: 1px solid #e0e0e0;
}
.leaderboard-table th {
background-color: #f2f2f2;
font-weight: bold;
}
.leaderboard-table tr:last-child td {
border-bottom: none;
}
@media (max-width: 768px) {
.card {
width: 100%;
}
}
.dark {
/* General styles */
background-color: #1a1a1a;
color: #e0e0e0;
/* Card styles */
.card {
background-color: #2a2a2a;
border-color: #444;
box-shadow: 0 4px 6px rgba(0,0,0,0.3);
}
.card:hover {
box-shadow: 0 6px 8px rgba(0,0,0,0.4);
}
.card-title {
color: #fff;
border-bottom-color: #444;
}
/* Question styles */
.question {
background-color: #333;
}
.question h3 {
color: #e0e0e0;
}
.question-yes {
background-color: #1a3a1a;
}
.question-no {
background-color: #3a1a1a;
}
.question-na {
background-color: #3a3a1a;
}
/* Summary and details styles */
summary {
color: #3498db;
}
details {
background-color: #2a2a2a;
}
/* Score styles */
.category-score, .total-score {
background-color: #2c3e50;
border-color: #34495e;
}
.total-score {
background-color: #34495e;
border-color: #2c3e50;
}
/* Leaderboard styles */
.leaderboard-table th {
background-color: #2c3e50;
color: #fff;
}
.leaderboard-table td {
border-bottom-color: #444;
}
/* Gradio component styles */
.gradio-container {
background-color: #1a1a1a;
}
.input-group, .output-group {
background-color: #2a2a2a;
}
input, select, textarea {
background-color: #333;
color: #e0e0e0;
border-color: #444;
}
button {
background-color: #3498db;
color: #fff;
}
button:hover {
background-color: #2980b9;
}
}
"""
def create_leaderboard():
scores = []
for model, data in models.items():
total_score = 0
total_questions = 0
for category in data['scores']:
for question, details in data['scores'][category].items():
if details['status'] == 'Yes':
total_score += 1
total_questions += 1
score_percentage = (total_score / total_questions) * 100 if total_questions > 0 else 0
scores.append((model, score_percentage))
df = pd.DataFrame(scores, columns=['Model', 'Score Percentage'])
df = df.sort_values('Score Percentage', ascending=False).reset_index(drop=True)
html = "
"
html += "
AI Model Social Impact Leaderboard
"
html += "
"
html += "Rank | Model | Score Percentage |
"
for i, (_, row) in enumerate(df.iterrows(), 1):
html += f"{i} | {row['Model']} | {row['Score Percentage']:.2f}% |
"
html += "
"
return html
def create_category_chart(selected_models, selected_categories):
if not selected_models:
return px.bar(title='Please select at least one model for comparison')
data = []
for model in selected_models:
for category in selected_categories:
if category in models[model]['scores']:
total_questions = len(models[model]['scores'][category])
yes_count = sum(1 for q in models[model]['scores'][category].values() if q['status'] == 'Yes')
score_percentage = (yes_count / total_questions) * 100 if total_questions > 0 else 0
data.append({'Model': model, 'Category': category, 'Score Percentage': score_percentage})
df = pd.DataFrame(data)
if df.empty:
return px.bar(title='No data available for the selected models and categories')
fig = px.bar(df, x='Model', y='Score Percentage', color='Category',
title='AI Model Scores by Category',
labels={'Score Percentage': 'Score Percentage'},
category_orders={"Category": selected_categories})
return fig
def update_detailed_scorecard(model, selected_categories):
if not model: # Check if model is None or an empty string
return [
gr.update(value="Please select a model to view details.", visible=True),
gr.update(visible=False),
gr.update(visible=False)
]
metadata_md = f"## Model Metadata for {model}\n\n"
for key, value in models[model]['metadata'].items():
metadata_md += f"**{key}:** {value}\n\n"
total_yes = 0
total_no = 0
total_na = 0
all_cards_content = ""
for category in scorecard_template:
if category.name in selected_categories and category.name in models[model]['scores']:
category_data = models[model]['scores'][category.name]
card_content = f"
{category.name}
"
category_yes = 0
category_no = 0
category_na = 0
for question, details in category_data.items():
status = details['status']
source = details.get('source', 'N/A')
if status == 'Yes':
bg_class = 'question-yes'
category_yes += 1
total_yes += 1
elif status == 'No':
bg_class = 'question-no'
category_no += 1
total_no += 1
else:
bg_class = 'question-na'
category_na += 1
total_na += 1
card_content += f"
"
card_content += f"
{question}
\n\n"
card_content += f"
{status}
\n\n
Source: {source}
\n\n"
if details.get('applicable_evaluations'):
card_content += "
View Applicable Evaluations
\n\n"
card_content += ""
for eval in details['applicable_evaluations']:
card_content += f"- {eval}
"
card_content += "
\n"
card_content += "\n\n"
else:
card_content += "
View Applicable Evaluations
\n\n"
card_content += "No applicable evaluations.
\n"
card_content += "\n\n"
card_content += "
"
category_score = category_yes / (category_yes + category_no) * 100 if (category_yes + category_no) > 0 else 0
card_content += f"
Category Score: {category_score:.2f}% (Yes: {category_yes}, No: {category_no}, N/A: {category_na})
"
card_content += "
"
all_cards_content += card_content
all_cards_content += "
"
total_score = total_yes / (total_yes + total_no) * 100 if (total_yes + total_no) > 0 else 0
total_score_md = f"Total Score: {total_score:.2f}% (Yes: {total_yes}, No: {total_no}, N/A: {total_na})
"
return [
gr.update(value=metadata_md, visible=True),
gr.update(value=all_cards_content, visible=True),
gr.update(value=total_score_md, visible=True)
]
def update_dashboard(tab, selected_models, selected_model, selected_categories):
leaderboard_visibility = gr.update(visible=False)
category_chart_visibility = gr.update(visible=False)
detailed_scorecard_visibility = gr.update(visible=False)
model_chooser_visibility = gr.update(visible=False)
model_multi_chooser_visibility = gr.update(visible=False)
category_filter_visibility = gr.update(visible=False)
if tab == "Leaderboard":
leaderboard_visibility = gr.update(visible=True)
leaderboard_html = create_leaderboard()
return [leaderboard_visibility, category_chart_visibility, detailed_scorecard_visibility,
model_chooser_visibility, model_multi_chooser_visibility, category_filter_visibility,
gr.update(value=leaderboard_html), gr.update(), gr.update(), gr.update(), gr.update()]
elif tab == "Category Analysis":
category_chart_visibility = gr.update(visible=True)
model_multi_chooser_visibility = gr.update(visible=True)
category_filter_visibility = gr.update(visible=True)
category_chart = create_category_chart(selected_models or [], selected_categories)
return [leaderboard_visibility, category_chart_visibility, detailed_scorecard_visibility,
model_chooser_visibility, model_multi_chooser_visibility, category_filter_visibility,
gr.update(), gr.update(value=category_chart), gr.update(), gr.update(), gr.update()]
elif tab == "Detailed Scorecard":
detailed_scorecard_visibility = gr.update(visible=True)
model_chooser_visibility = gr.update(visible=True)
category_filter_visibility = gr.update(visible=True)
if selected_model:
scorecard_updates = update_detailed_scorecard(selected_model, selected_categories)
else:
scorecard_updates = [
gr.update(value="Please select a model to view details.", visible=True),
gr.update(visible=False),
gr.update(visible=False)
]
return [leaderboard_visibility, category_chart_visibility, detailed_scorecard_visibility,
model_chooser_visibility, model_multi_chooser_visibility, category_filter_visibility,
gr.update(), gr.update()] + scorecard_updates
with gr.Blocks(css=css) as demo:
gr.Markdown("# AI Model Social Impact Scorecard Dashboard")
with gr.Row():
tab_selection = gr.Radio(["Leaderboard", "Category Analysis", "Detailed Scorecard"],
label="Select Tab", value="Leaderboard")
with gr.Row():
model_chooser = gr.Dropdown(choices=[""] + list(models.keys()), # Add an empty option
label="Select Model for Details",
value="", # Set default value to empty string
interactive=True, visible=False)
model_multi_chooser = gr.Dropdown(choices=list(models.keys()),
label="Select Models for Comparison",
multiselect=True, interactive=True, visible=False)
category_filter = gr.CheckboxGroup(choices=[cat.name for cat in scorecard_template],
label="Filter Categories",
value=[cat.name for cat in scorecard_template],
visible=False)
with gr.Column(visible=True) as leaderboard_tab:
leaderboard_output = gr.HTML()
with gr.Column(visible=False) as category_analysis_tab:
category_chart = gr.Plot()
with gr.Column(visible=False) as detailed_scorecard_tab:
model_metadata = gr.Markdown()
all_category_cards = gr.HTML()
total_score = gr.Markdown()
# Initialize the dashboard with the leaderboard
leaderboard_output.value = create_leaderboard()
tab_selection.change(fn=update_dashboard,
inputs=[tab_selection, model_multi_chooser, model_chooser, category_filter],
outputs=[leaderboard_tab, category_analysis_tab, detailed_scorecard_tab,
model_chooser, model_multi_chooser, category_filter,
leaderboard_output, category_chart, model_metadata, all_category_cards, total_score])
model_chooser.change(fn=update_dashboard,
inputs=[tab_selection, model_multi_chooser, model_chooser, category_filter],
outputs=[leaderboard_tab, category_analysis_tab, detailed_scorecard_tab,
model_chooser, model_multi_chooser, category_filter,
leaderboard_output, category_chart, model_metadata, all_category_cards, total_score])
model_multi_chooser.change(fn=update_dashboard,
inputs=[tab_selection, model_multi_chooser, model_chooser, category_filter],
outputs=[leaderboard_tab, category_analysis_tab, detailed_scorecard_tab,
model_chooser, model_multi_chooser, category_filter,
leaderboard_output, category_chart, model_metadata, all_category_cards, total_score])
category_filter.change(fn=update_dashboard,
inputs=[tab_selection, model_multi_chooser, model_chooser, category_filter],
outputs=[leaderboard_tab, category_analysis_tab, detailed_scorecard_tab,
model_chooser, model_multi_chooser, category_filter,
leaderboard_output, category_chart, model_metadata, all_category_cards, total_score])
# Launch the app
if __name__ == "__main__":
demo.launch()