"""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 (HTML -> PNG via the shared renderer Space) with the participant's verified-claim stats. """ import inspect import json import os import tempfile import urllib.parse import gradio as gr from gradio_client import Client, handle_file RENDERER_SPACE = "https://ysharma-hackathon-certificate-html-to-image.hf.space/" DISCUSSIONS_URL = "https://huggingface.co/spaces/ICML-2026-agent-repro/challenge/discussions" _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) _client = None def get_renderer(): global _client if _client is None: params = inspect.signature(Client.__init__).parameters kwargs = {} token = os.getenv("HF_TOKEN") if token: kwargs["hf_token" if "hf_token" in params else "token"] = token _client = Client(RENDERER_SPACE, **kwargs) return _client 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), 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), gr.update(visible=True), 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), gr.update(visible=False), 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)) with tempfile.NamedTemporaryFile("w", delete=False, suffix=".html", encoding="utf-8") as f: f.write(html) path = f.name try: image_path = get_renderer().predict(html_file=handle_file(path), api_name="/predict")[0] 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; } #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) with gr.Column(visible=False) as contact_box: pass demo.load(on_load, inputs=None, outputs=[main_box, contact_box, status, name_box]) gen_btn.click(create_certificate, inputs=[name_box], outputs=[cert_image, note, linkedin]) demo.launch()