Spaces:
Sleeping
Sleeping
File size: 6,134 Bytes
d06bb34 | 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 | """Gradio leaderboard for the UQ competition (Hugging Face Space).
- Every submission is ADDED as its own row (no overwrite; multiple per team allowed).
- Baselines (Baseline 1, random) always shown, never stored, never deduped away.
- Submissions persist to a PRIVATE dataset so they survive restarts and are editable there.
- Admin accordion: remove a row by sid / remove a team by name / reset all (password-gated).
See README.md for setup."""
import os, datetime, uuid
import numpy as np, pandas as pd, gradio as gr
import scoring
from huggingface_hub import HfApi, hf_hub_download
# ---- config: set these as Space variables/secrets ----
LABELS_DATASET = os.environ.get("LABELS_DATASET", "") # private dataset holding test_labels.csv
SUBS_DATASET = os.environ.get("SUBS_DATASET", LABELS_DATASET) # where submissions.csv is stored (can be the same)
HF_TOKEN = os.environ.get("HF_TOKEN", "") # token with WRITE access to SUBS_DATASET
ADMIN_PW = os.environ.get("ADMIN_PW", "") # password for the admin controls
LABELS_FILE, SUBS_FILE = "test_labels.csv", "submissions.csv"
BOARD_COLS = ["sid", "team", "submitted_at", "Brier", "AUROC", "Accuracy", "n"]
api = HfApi(token=HF_TOKEN) if HF_TOKEN else None
# ---- hidden labels ----
def _read_labels():
if LABELS_DATASET and HF_TOKEN:
p = hf_hub_download(LABELS_DATASET, LABELS_FILE, repo_type="dataset", token=HF_TOKEN)
else:
p = LABELS_FILE # local fallback (private Space)
return pd.read_csv(p).set_index("id")["correct"].astype(int)
LABELS = _read_labels()
BASE_RATE = float(LABELS.mean())
# ---- persistence: read/write submissions.csv in the private dataset (else local file) ----
def load_board():
try:
if SUBS_DATASET and HF_TOKEN:
p = hf_hub_download(SUBS_DATASET, SUBS_FILE, repo_type="dataset",
token=HF_TOKEN, force_download=True)
else:
p = SUBS_FILE
df = pd.read_csv(p)
except Exception:
df = pd.DataFrame(columns=BOARD_COLS)
for c in BOARD_COLS:
if c not in df.columns:
df[c] = pd.Series(dtype=object)
return df[BOARD_COLS]
def save_board(df):
if SUBS_DATASET and HF_TOKEN:
api.upload_file(path_or_fileobj=df.to_csv(index=False).encode(),
path_in_repo=SUBS_FILE, repo_id=SUBS_DATASET,
repo_type="dataset", commit_message="update submissions")
else:
df.to_csv(SUBS_FILE, index=False)
# ---- baselines: recomputed every render, never stored, never deduped ----
def baseline_rows():
rng = np.random.default_rng(0); ids = LABELS.index
out = []
for name, p in {"π€ Baseline 1": np.full(len(ids), BASE_RATE),
"π€ random": rng.random(len(ids))}.items():
m = scoring.grade(pd.DataFrame({"id": ids.astype(str), "p_correct": p}), LABELS)
out.append({"sid": "β", "team": name, "submitted_at": "baseline", **m})
return pd.DataFrame(out)
def render():
board = pd.concat([load_board(), baseline_rows()], ignore_index=True)
board = board.sort_values("Brier", ascending=True).reset_index(drop=True)
board.insert(0, "rank", np.arange(1, len(board) + 1))
return board[["rank", "team", "Brier", "AUROC", "Accuracy", "submitted_at", "sid"]]
# ---- actions ----
def submit(team, file):
if not team or not team.strip():
return "β οΈ Enter a team name.", render()
team = team.strip()
if team.startswith("π€"):
return "β οΈ That prefix is reserved for baselines.", render()
if file is None:
return "β οΈ Upload your submission.csv.", render()
try:
m = scoring.grade(pd.read_csv(file.name), LABELS)
except Exception as e:
return f"β {e}", render()
sid = uuid.uuid4().hex[:6]
row = {"sid": sid, "team": team,
"submitted_at": datetime.datetime.utcnow().strftime("%Y-%m-%d %H:%M"), **m}
save_board(pd.concat([load_board(), pd.DataFrame([row])], ignore_index=True))
return (f"β
**{team}** β Brier **{m['Brier']}** (AUROC {m['AUROC']}, Acc {m['Accuracy']}). "
f"Entry id `{sid}`. Submit as many times as you like.", render())
def admin_remove(target, pw):
if not ADMIN_PW or pw != ADMIN_PW:
return "β οΈ Wrong or unset admin password.", render()
t = target.strip()
board = load_board()
keep = board[(board["sid"] != t) & (board["team"].astype(str).str.strip() != t)]
save_board(keep)
return f"Removed {len(board) - len(keep)} row(s) matching `{t}`.", render()
def admin_reset(pw):
if not ADMIN_PW or pw != ADMIN_PW:
return "β οΈ Wrong or unset admin password.", render()
save_board(pd.DataFrame(columns=BOARD_COLS))
return "Leaderboard cleared (baselines remain).", render()
with gr.Blocks(title="UQ Competition") as demo:
gr.Markdown("# π UQ Competition Leaderboard\n"
"Predict P(model's answer is correct). **Ranked by Brier β lower is better.** "
"You may submit as many times as you like; **every submission is added** as its own row.")
with gr.Row():
team = gr.Textbox(label="Team name", scale=2)
file = gr.File(label="submission.csv", file_types=[".csv"], scale=2)
btn = gr.Button("Submit", variant="primary")
status = gr.Markdown()
table = gr.Dataframe(value=render(), interactive=False, label="Leaderboard")
btn.click(submit, [team, file], [status, table])
with gr.Accordion("admin", open=False):
gr.Markdown("Remove one entry by its **sid** (last column), or remove all of a team by **name**.")
tgt = gr.Textbox(label="sid or team name to remove")
pw = gr.Textbox(label="admin password", type="password")
with gr.Row():
gr.Button("Remove").click(admin_remove, [tgt, pw], [status, table])
gr.Button("Reset ALL", variant="stop").click(admin_reset, [pw], [status, table])
demo.load(render, None, table)
if __name__ == "__main__":
demo.launch()
|