Spaces:
Running
Running
| import datetime | |
| import io | |
| import json | |
| import os | |
| import re | |
| import uuid | |
| import requests | |
| import gradio as gr | |
| import pandas as pd | |
| from huggingface_hub import HfApi, hf_hub_download | |
| APP_NAME = "MiniApp" | |
| HF_TOKEN = os.environ.get("HF_TOKEN") | |
| LEADERBOARD_DATASET = os.environ.get("LEADERBOARD_DATASET", "").strip() | |
| PENDING_PREFIX = "pending/" | |
| APPROVED_PREFIX = "approved/" | |
| RESEND_API_KEY = os.environ.get("RESEND_API_KEY", "").strip() | |
| NOTIFY_EMAIL_TO = os.environ.get("NOTIFY_EMAIL_TO", "").strip() | |
| NOTIFY_EMAIL_FROM = os.environ.get("NOTIFY_EMAIL_FROM", "").strip() | |
| COLUMNS = ["model name","model family","avg","easy","mid","hard","submitted_at"] | |
| NUMERIC_COLS = ["avg","easy","mid","hard"] | |
| def _api(): | |
| return HfApi(token=HF_TOKEN) | |
| def _slug(s: str): | |
| s = re.sub(r"[^a-z0-9]+", "-", (s or "").lower()) | |
| return s.strip("-") or "model" | |
| def _load_df(prefix: str): | |
| if not HF_TOKEN or not LEADERBOARD_DATASET: | |
| return pd.DataFrame(columns=COLUMNS) | |
| api = _api() | |
| try: | |
| files = api.list_repo_files(repo_id=LEADERBOARD_DATASET, repo_type="dataset") | |
| except Exception: | |
| return pd.DataFrame(columns=COLUMNS) | |
| files = [f for f in files if f.startswith(prefix) and f.endswith(".json")] | |
| rows = [] | |
| for f in files: | |
| try: | |
| path = hf_hub_download( | |
| repo_id=LEADERBOARD_DATASET, | |
| repo_type="dataset", | |
| filename=f, | |
| token=HF_TOKEN, | |
| ) | |
| with open(path, "r") as fp: | |
| rows.append(json.load(fp)) | |
| except Exception: | |
| continue | |
| if not rows: | |
| return pd.DataFrame(columns=COLUMNS) | |
| df = pd.DataFrame(rows) | |
| for c in COLUMNS: | |
| if c not in df.columns: | |
| df[c] = "" | |
| for c in NUMERIC_COLS: | |
| df[c] = pd.to_numeric(df[c], errors="coerce") | |
| df = df.sort_values(by="avg", ascending=False) | |
| return df[COLUMNS] | |
| def refresh(): | |
| return _load_df(APPROVED_PREFIX) | |
| def _today_utc(): | |
| return datetime.datetime.utcnow().date().isoformat() | |
| def _send_email_resend(subject: str, text: str): | |
| if not (RESEND_API_KEY and NOTIFY_EMAIL_TO and NOTIFY_EMAIL_FROM): | |
| return | |
| requests.post( | |
| "https://api.resend.com/emails", | |
| headers={"Authorization": f"Bearer {RESEND_API_KEY}", "Content-Type": "application/json"}, | |
| json={"from": NOTIFY_EMAIL_FROM, "to": [NOTIFY_EMAIL_TO], "subject": subject, "text": text}, | |
| timeout=20, | |
| ) | |
| def _already_submitted_today(api: HfApi, day: str, username: str) -> bool: | |
| marker = f"{PENDING_PREFIX}{day}/{username}/_submitted.json" | |
| try: | |
| files = api.list_repo_files(repo_id=LEADERBOARD_DATASET, repo_type="dataset") | |
| return marker in files | |
| except Exception: | |
| return True # 更安全:查不到就当提交过 | |
| # ✅ 改这里:用 profile 取 username | |
| def submit(model_name, model_family, zip_file, profile: gr.OAuthProfile): | |
| if profile is None or not getattr(profile, "username", None): | |
| return "Please sign in with Hugging Face first.", refresh() | |
| username = profile.username | |
| if not model_name or not model_family or zip_file is None: | |
| return "All fields are required.", refresh() | |
| if not zip_file.name.endswith(".zip"): | |
| return "Please upload a .zip file.", refresh() | |
| if not HF_TOKEN or not LEADERBOARD_DATASET: | |
| return "Server is not configured (HF_TOKEN / LEADERBOARD_DATASET).", refresh() | |
| api = _api() | |
| day = _today_utc() | |
| if _already_submitted_today(api, day, username): | |
| return f"Limit: you can only submit once per day. (user={username}, day={day})", refresh() | |
| now = datetime.datetime.utcnow().isoformat() + "Z" | |
| safe_model = _slug(model_name) | |
| nonce = uuid.uuid4().hex[:6] | |
| base_dir = f"{PENDING_PREFIX}{day}/{username}/" | |
| json_path = f"{base_dir}{now}-{safe_model}-{nonce}.json" | |
| zip_path = f"{base_dir}{now}-{safe_model}-{nonce}.zip" | |
| marker_path = f"{base_dir}_submitted.json" | |
| payload = { | |
| "model name": model_name, | |
| "model family": model_family, | |
| "avg": 0, "easy": 0, "mid": 0, "hard": 0, | |
| "submitted_at": now, | |
| "username": username, | |
| "day": day, | |
| } | |
| api.upload_file( | |
| repo_id=LEADERBOARD_DATASET, repo_type="dataset", | |
| path_or_fileobj=io.BytesIO(json.dumps(payload, indent=2).encode("utf-8")), | |
| path_in_repo=json_path, | |
| commit_message=f"submit {model_name} by {username}", | |
| ) | |
| api.upload_file( | |
| repo_id=LEADERBOARD_DATASET, repo_type="dataset", | |
| path_or_fileobj=zip_file, | |
| path_in_repo=zip_path, | |
| commit_message=f"upload zip {model_name} by {username}", | |
| ) | |
| api.upload_file( | |
| repo_id=LEADERBOARD_DATASET, repo_type="dataset", | |
| path_or_fileobj=io.BytesIO(json.dumps({"submitted_at": now, "username": username, "day": day}, indent=2).encode("utf-8")), | |
| path_in_repo=marker_path, | |
| commit_message=f"marker {day} {username}", | |
| ) | |
| _send_email_resend( | |
| subject=f"[{APP_NAME}] New submission from {username} ({day})", | |
| text=f"user: {username}\nday: {day}\nmodel: {model_name}\nfamily: {model_family}\njson: {json_path}\nzip: {zip_path}\n", | |
| ) | |
| return "Submitted. Waiting for review.", refresh() | |
| with gr.Blocks( | |
| title=f"{APP_NAME} leaderboard", | |
| css=""" | |
| .gradio-container { font-size: 18px; } | |
| /* 表格字号单独再加一层,确保生效 */ | |
| .gradio-container table { font-size: 18px; } | |
| """ | |
| ) as demo: | |
| gr.Markdown(f"# {APP_NAME} Leaderboard") | |
| leaderboard = gr.Dataframe(value=_load_df(APPROVED_PREFIX), interactive=False, wrap=True) | |
| refresh_btn = gr.Button("Refresh") | |
| gr.Markdown("## Submit") | |
| gr.Markdown( | |
| """ | |
| **Submission requirements** | |
| - Please **sign in with Hugging Face** before submitting. | |
| - **One submission per user per day** (UTC). | |
| - Upload a **.zip** file only. | |
| - The `.zip` must contain the HTML outputs for the **test set queries**. | |
| - Each file should be named using the query index: `<index>.html` (e.g., `1.html`, `2.html`, ...). | |
| - After you submit, we will update the result in 3 days. | |
| """, | |
| ) | |
| model_name = gr.Textbox(label="Model name", placeholder="e.g. MyModel v1") | |
| model_family = gr.Textbox(label="Model family", placeholder="e.g. Llama / Qwen / InternLM ...") | |
| zip_file = gr.File(label="Upload zip (.zip only)", file_types=[".zip"]) | |
| with gr.Row(): | |
| with gr.Column(scale=1, min_width=220): | |
| login_btn = gr.LoginButton() | |
| with gr.Column(scale=1, min_width=260): | |
| submit_btn = gr.Button("Submit", variant="primary") | |
| status = gr.Markdown() | |
| submit_btn.click(submit, inputs=[model_name, model_family, zip_file], outputs=[status, leaderboard]) | |
| demo.launch() | |