"""SafetyCard web app (Gradio). Instant file scan runs on a free CPU Space; deep scan needs a GPU (run this app locally on a machine with a GPU).""" import glob import json import os import gradio as gr import pandas as pd import torch from safetycard import __version__, report HAS_GPU = torch.cuda.is_available() ALLOW_CPU_DEEP = os.environ.get("SAFETYCARD_ALLOW_CPU", "0") == "1" RESULTS_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), "results") SPACE_ID = os.environ.get("SPACE_ID", "NAMESPACE/SafetyCard") # set automatically on HF Spaces LOCAL_RUN = (f"git clone https://huggingface.co/spaces/{SPACE_ID} && cd SafetyCard\n" "pip install -r requirements.txt\n") def instant_scan(repo_id): repo_id = (repo_id or "").strip() if not repo_id: return "Enter a model id, e.g. `Qwen/Qwen2.5-1.5B-Instruct`.", None try: card = report.build(repo_id, deep=False) except Exception as e: return f"Could not scan `{repo_id}`: {e}", None return report.to_markdown(card), card def deep_scan(repo_id, base_id): if not (HAS_GPU or ALLOW_CPU_DEEP): return ("No GPU on this Space. Run the deep scan free on your own GPU:\n\n" "```bash\n" + LOCAL_RUN + "python -m safetycard.cli scan " + (repo_id or "org/model") + " --deep --out card.json\n```\nor run `python app.py` on a machine with a GPU."), None repo_id = (repo_id or "").strip() try: card = report.build(repo_id, base_id=(base_id or "").strip() or None, deep=True) except Exception as e: return f"Deep scan failed for `{repo_id}`: {e}", None path = os.path.join("/tmp", repo_id.replace("/", "__") + ".safetycard.json") report.save(card, path) return report.to_markdown(card), path def leaderboard(): rows = [] for p in sorted(glob.glob(os.path.join(RESULTS_DIR, "*.json"))): try: c = json.load(open(p)) except Exception: continue s, g = c.get("safety", {}), c.get("lineage", {}) rows.append({"Model": c["model"], "File grade": c["files"]["grade"], "Parent": c.get("parent_model") or "", "Lineage": g.get("verdict", ""), "Weight change": g.get("overall_rel_change", ""), "Safety d′": s.get("dprime_mean", ""), "d′ range": f"{s.get('dprime_min', '')}–{s.get('dprime_max', '')}" if s else "", "vs parent": s.get("vs_parent", ""), "Version": c.get("version", ""), "Scanned": c.get("scanned_at", "")[:10]}) return pd.DataFrame(rows) ABOUT = open(os.path.join(os.path.dirname(os.path.abspath(__file__)), "ABOUT.md")).read() \ if os.path.exists(os.path.join(os.path.dirname(os.path.abspath(__file__)), "ABOUT.md")) else "" with gr.Blocks(title="SafetyCard: free safety report card for Hugging Face LLMs") as demo: gr.Markdown(f"# šŸ›”ļø SafetyCard\n**A free safety report card for any Hugging Face language model.** " f"Check file safety in seconds, then run deep checks on your own GPU. v{__version__}") with gr.Tab("⚔ Instant file scan"): gr.Markdown("Inspects the repo's files and metadata. **Downloads no weights**, so it is safe and fast.") rid = gr.Textbox(label="Model id", placeholder="Qwen/Qwen2.5-1.5B-Instruct") btn = gr.Button("Scan files", variant="primary") out_md = gr.Markdown() out_json = gr.JSON(label="Raw card") btn.click(instant_scan, rid, [out_md, out_json]) with gr.Tab("šŸ”¬ Deep scan (your GPU)"): gr.Markdown("Compares weights with the parent model and measures the model's internal safety " "structure. Safetensors only, never `trust_remote_code`, no text generated." + ("" if HAS_GPU else "\n\n**This Space has no GPU.** Run it on a GPU machine, " "or clone it and run locally (instructions appear when you click).")) rid2 = gr.Textbox(label="Model id") base2 = gr.Textbox(label="Parent model (optional, default: declared base_model)") btn2 = gr.Button("Run deep scan", variant="primary") out2 = gr.Markdown() file2 = gr.File(label="Your SafetyCard JSON (submit it to the leaderboard)") btn2.click(deep_scan, [rid2, base2], [out2, file2]) with gr.Tab("šŸ† Leaderboard"): gr.Markdown("Community-submitted SafetyCards. Add yours by opening a pull request with your " "`card.json` in `results/` on this Space.") table = gr.Dataframe(leaderboard(), interactive=False, wrap=True) gr.Button("Refresh").click(leaderboard, None, table) with gr.Tab("ā“ How it works"): gr.Markdown(ABOUT) if __name__ == "__main__": demo.launch()