Ryan McConville
fix sorting with medal icons
1bacdcc
raw
history blame
4.52 kB
import json
import os
import pandas as pd
from src.display.formatting import has_no_nan_values, make_clickable_model
from src.display.utils import AutoEvalColumn, EvalQueueColumn
from src.leaderboard.read_evals import get_raw_eval_results
def get_leaderboard_df(results_path):
df = pd.read_csv(results_path)
# numeric formatting
df["ha_rag_rate"] = df["ha_rag_rate"].round(2)
df["ha_non_rag_rate"] = df["ha_non_rag_rate"].round(2)
# --- map to pretty headers just before returning ---
pretty = {
"Models": "Models",
"ha_rag_rate": "RAG Hallucination Rate (%)",
"ha_non_rag_rate": "Non-RAG Hallucination Rate (%)",
}
df = df.rename(columns=pretty) # this is what the UI will use
# ----------- Average column & ranking ---------------------------------------------
df["Average Hallucination Rate (%)"] = df[
["RAG Hallucination Rate (%)", "Non-RAG Hallucination Rate (%)"]
].mean(axis=1).round(2)
# sort so *lower* average = better (true leaderboard style)
df = df.sort_values("Average Hallucination Rate (%)", ascending=True).reset_index(drop=True)
# # Rank & medal
medal_map = {1: "πŸ₯‡", 2: "πŸ₯ˆ", 3: "πŸ₯‰"}
def medal_html(rank):
"""Return an HTML span with the medal icon for the top 3 ranks.
The numeric rank is stored in the data-order attribute equal to the numerical rank so that
DataTables (used under-the-hood by the gradio_leaderboard component)
can sort the column by this hidden numeric value while still
displaying the pretty medal icon. For ranks > 3 we just return the
integer so the column remains fully numeric.
"""
medal = medal_map.get(rank)
if medal:
# Prepend a hidden numeric span so string sorting still works numerically.
return (
f'<span style="display:none">{rank:04}</span>' # zero-padded for stable string sort
f'<span style="font-size:2.0rem;">{medal}</span>'
)
# For other ranks, also zero-pad to keep width and ensure proper string sort
return f'<span style="display:none">{rank:04}</span>{rank}'
df["Rank"] = df.index + 1
df["Rank"] = df["Rank"].apply(medal_html)
# ----------- column ordering ------------------------------------------------------
df = df[[
"Rank", # pretty column user sees
"Models",
"Average Hallucination Rate (%)",
"RAG Hallucination Rate (%)",
"Non-RAG Hallucination Rate (%)",
]]
return df
def get_evaluation_queue_df(save_path: str, cols: list) -> list[pd.DataFrame]:
"""Creates the different dataframes for the evaluation queues requestes"""
entries = [entry for entry in os.listdir(save_path) if not entry.startswith(".")]
all_evals = []
for entry in entries:
if ".json" in entry:
file_path = os.path.join(save_path, entry)
with open(file_path) as fp:
data = json.load(fp)
data[EvalQueueColumn.model.name] = make_clickable_model(data["model"])
data[EvalQueueColumn.revision.name] = data.get("revision", "main")
all_evals.append(data)
elif ".md" not in entry:
# this is a folder
sub_entries = [e for e in os.listdir(f"{save_path}/{entry}") if os.path.isfile(e) and not e.startswith(".")]
for sub_entry in sub_entries:
file_path = os.path.join(save_path, entry, sub_entry)
with open(file_path) as fp:
data = json.load(fp)
data[EvalQueueColumn.model.name] = make_clickable_model(data["model"])
data[EvalQueueColumn.revision.name] = data.get("revision", "main")
all_evals.append(data)
pending_list = [e for e in all_evals if e["status"] in ["PENDING", "RERUN"]]
running_list = [e for e in all_evals if e["status"] == "RUNNING"]
finished_list = [e for e in all_evals if e["status"].startswith("FINISHED") or e["status"] == "PENDING_NEW_EVAL"]
df_pending = pd.DataFrame.from_records(pending_list, columns=cols)
df_running = pd.DataFrame.from_records(running_list, columns=cols)
df_finished = pd.DataFrame.from_records(finished_list, columns=cols)
return df_finished[cols], df_running[cols], df_pending[cols]