"""ICML 2026 Open Reproductions — Certificate Generator ======================================================= 1. Sign in with Hugging Face (OAuth). 2. Eligibility is checked against the frozen challenge verdicts: every participant with at least one claim judged `verified` qualifies (baked into eligible.json at challenge close — 267 participants). 3. The display name is editable; the certificate renders to PNG with headless Chromium (installed via packages.txt) — no external renderer dependency. """ import json import os import shutil import subprocess import tempfile import urllib.parse import gradio as gr DISCUSSIONS_URL = "https://huggingface.co/spaces/ICML-2026-agent-repro/challenge/discussions" CANVAS = (2000, 1414) # must match the body size in certificate_template.html _HERE = os.path.dirname(__file__) with open(os.path.join(_HERE, "certificate_template.html"), encoding="utf-8") as f: TEMPLATE = f.read() with open(os.path.join(_HERE, "eligible.json"), encoding="utf-8") as f: ELIGIBLE = json.load(f) def find_chromium(): candidates = [ "chromium", "chromium-browser", "google-chrome", "google-chrome-stable", "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome", # local dev ] for c in candidates: path = shutil.which(c) or (c if os.path.exists(c) else None) if path: return path raise RuntimeError("No Chromium binary found — is `chromium` in packages.txt?") def render_html(html: str) -> str: out = os.path.join(tempfile.mkdtemp(), "certificate.png") with tempfile.NamedTemporaryFile("w", delete=False, suffix=".html", encoding="utf-8") as f: f.write(html) src = f.name try: subprocess.run( [find_chromium(), "--headless=new", "--no-sandbox", "--disable-gpu", "--hide-scrollbars", "--force-device-scale-factor=1", f"--window-size={CANVAS[0]},{CANVAS[1]}", f"--screenshot={out}", f"file://{src}"], check=True, capture_output=True, timeout=120, ) finally: try: os.unlink(src) except OSError: pass return out def plural(n, word): return f"{n} {word}" + ("" if n == 1 else "s") def stats_line(rec): return (f"{plural(rec['verified_claims'], 'claim')} verified across " f"{plural(rec['verified_papers'], 'paper')}") def on_load(profile: gr.OAuthProfile | None): if profile is None: return (gr.update(visible=False), "### 👋 Sign in with Hugging Face to check your eligibility.", "") rec = ELIGIBLE.get(profile.username.lower()) if rec is None: return (gr.update(visible=False), f"### Sorry @{profile.username} — no verified logbook found.\n" "Certificates go to participants with at least one claim judged " "**verified** by the Logbook Judge before the Aug 2 deadline. " f"If you believe this is an error, please open a thread in the " f"[challenge discussions]({DISCUSSIONS_URL}).", "") return (gr.update(visible=True), f"### 🎉 Congratulations @{profile.username} — you qualify!\n" f"Your record: **{stats_line(rec)}** ({plural(rec['logbooks'], 'logbook')} judged). " "Adjust how your name should appear, then generate your certificate.", profile.name or profile.username) def linkedin_url(name): p = { "startTask": "CERTIFICATION_NAME", "name": "ICML 2026 Open Reproductions — Certificate of Participation", "organizationName": "Hugging Face", "issueYear": "2026", "issueMonth": "8", "certUrl": "https://huggingface.co/spaces/ICML-2026-agent-repro/certificate-generator", } return "https://www.linkedin.com/profile/add?" + urllib.parse.urlencode(p) def create_certificate(display_name, profile: gr.OAuthProfile | None): if profile is None: return None, "❌ Please sign in first.", gr.update(visible=False) rec = ELIGIBLE.get(profile.username.lower()) if rec is None: return None, "❌ No verified logbook found for your account.", gr.update(visible=False) name = (display_name or "").strip() or profile.name or profile.username html = TEMPLATE.replace("{participant_name}", name).replace("{stats_line}", stats_line(rec)) try: image_path = render_html(html) except Exception as e: return None, f"❌ Rendering failed: {e}. Please try again in a minute.", gr.update(visible=False) btn = (f'Add to LinkedIn profile →') return image_path, "🎉 Your certificate is ready — download it below.", gr.update(value=btn, visible=True) THEME = gr.themes.Base( primary_hue=gr.themes.colors.orange, neutral_hue=gr.themes.colors.stone, ) CSS = """ .gradio-container { background-color: #fdfcf9 !important; background-image: linear-gradient(rgba(31,41,55,.045) 1px, transparent 1px), linear-gradient(90deg, rgba(31,41,55,.045) 1px, transparent 1px); background-size: 26px 26px; } .dark .gradio-container { background-color: #17181c !important; background-image: linear-gradient(rgba(253,252,249,.04) 1px, transparent 1px), linear-gradient(90deg, rgba(253,252,249,.04) 1px, transparent 1px); } #hero h1 { font-family: ui-serif, "Iowan Old Style", Georgia, serif; } """ with gr.Blocks(title="ICML 2026 Open Reproductions — Certificates", theme=THEME, css=CSS) as demo: gr.Markdown("# 🎓 ICML 2026 Open Reproductions — Certificate of Participation", elem_id="hero") gr.Markdown( "Every participant with **at least one claim judged `verified`** in the challenge " "(July 15 – August 2, 2026) can generate their certificate here." ) login = gr.LoginButton() status = gr.Markdown() with gr.Column(visible=False) as main_box: name_box = gr.Textbox(label="Name on the certificate") gen_btn = gr.Button("Generate my certificate 🎓", variant="primary") cert_image = gr.Image(label="Your certificate", type="filepath", interactive=False) note = gr.Markdown() linkedin = gr.HTML(visible=False) demo.load(on_load, inputs=None, outputs=[main_box, status, name_box]) gen_btn.click(create_certificate, inputs=[name_box], outputs=[cert_image, note, linkedin]) demo.launch()