MTiryaki's picture
Rename app (4).py to app.py
dae5c7a verified
Raw
History Blame Contribute Delete
6.13 kB
"""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()