import gradio as gr import json, os, time, uuid from eval_utils import evaluate_submission from threading import Lock # Setup GROUND_TRUTH = "ground_truth.json" SUB_DIR = "submissions" RATE_LIMIT = 60 os.makedirs(SUB_DIR, exist_ok=True) user_last = {} lock = Lock() def show_form(profile: gr.OAuthProfile | None): visible = profile is not None welcome = (f"## 👋 Welcome, {profile.username}! Ready to submit?" if visible else "## 🚀 Please sign in to submit.") return welcome, gr.Textbox(visible=visible) , gr.File(visible=visible), \ gr.Checkbox(visible=visible), gr.Button(visible=visible) def submit(submission_id: str, submission_file: str, is_private: bool, profile: gr.OAuthProfile | None): if not profile: raise gr.Error("🔒 Please sign in first.") username = profile.username with lock: now = time.time() if now - user_last.get(username, 0) < RATE_LIMIT: remaining = int(RATE_LIMIT - (now - user_last[username])) raise gr.Error(f"⏱️ Wait {remaining}s before retrying.") user_last[username] = now with open(submission_file.name, "rb") as file: prediction_json = json.load(file) with open(GROUND_TRUTH, "rb") as file: ground_truth_json = json.load(file) score = evaluate_submission(prediction_json, ground_truth_json) if not is_private: sid = str(uuid.uuid4()) submission_record = f"{username}_{sid}_{submission_id}" json.dump({ "username": username, "identifier": submission_id, "timestamp": now, "submission": prediction_json }, open(os.path.join(SUB_DIR, submission_record + ".json"), "w")) return gr.Text(f"{score:.4f}", visible=True) def get_leaderboard(): records = [] # for fn in os.listdir(SUB_DIR): # r = json.load(open(os.path.join(SUB_DIR, fn))) # if not r.get("private", False): # records.append(r) records.sort(key=lambda x: -x["score"]) if not records: return "**No submissions yet**" lines = ["| User | Score | Time |", "|---|---|---|"] for r in records[:10]: t = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(r["timestamp"])) lines.append(f"| {r['username']} | {r['score']:.4f} | {t} |") return "\n".join(lines) with gr.Blocks() as demo: gr.LoginButton() welcome_md = gr.Markdown("Please sign in to be able to submit.") submission_file = gr.File(label="Prediction (.json)", visible=False) submission_id = gr.Textbox(label="Submission identifier", visible=False) private_flag = gr.Checkbox(label="Do not save my submission", value=False, visible=False) submit_btn = gr.Button("Submit", visible=False) result = gr.Textbox(label="✅ Your score", visible=False) leaderboard_heading_md = gr.Markdown("## 🏆 Public Leaderboard") leaderboard_md = gr.Markdown(get_leaderboard()) # Load login state → show/hide components demo.load(fn=show_form, inputs=[], outputs=[welcome_md, submission_id, submission_file, private_flag, submit_btn]) # Submit button only shown post-login submit_btn.click(fn=submit, inputs=[submission_id, submission_file, private_flag], outputs=result) demo.launch()