ScottzillaSystems's picture
Upload app.py with huggingface_hub
ff10de2 verified
import gradio as gr
from huggingface_hub import HfApi, list_models, list_spaces
from datetime import datetime
import json
# ── fetch repos ─────────────────────────────────────────────
AUTHOR = "ScottzillaSystems"
api = HfApi()
models_raw = list(list_models(author=AUTHOR, limit=500))
spaces_raw = list(list_spaces(author=AUTHOR, limit=500))
models = []
for m in models_raw:
models.append({
"id": m.modelId,
"task": m.pipeline_tag or "β€”",
"library": (m.library_name or "β€”"),
"downloads": m.downloads or 0,
"likes": m.likes or 0,
"tags": m.tags[:6] if m.tags else [],
"private": getattr(m, "private", False),
"created": getattr(m, "created_at", "β€”"),
"url": f"https://huggingface.co/{m.modelId}",
"type": "model",
})
spaces = []
for s in spaces_raw:
spaces.append({
"id": s.id,
"sdk": getattr(s, "sdk", "β€”"),
"likes": s.likes or 0,
"tags": s.tags[:6] if getattr(s, "tags", None) else [],
"private": getattr(s, "private", False),
"created": getattr(s, "created_at", "β€”"),
"url": f"https://huggingface.co/spaces/{s.id}",
"type": "space",
})
all_repos = models + spaces
# ── helpers ─────────────────────────────────────────────────
def _card(repo):
priv = "πŸ”’" if repo["private"] else ""
tags = " ".join(f"<span class='tag'>{t}</span>" for t in repo["tags"])
extra = ""
if repo["type"] == "model":
extra = f"<div class='meta'>⬇️ {repo['downloads']:,} | ❀️ {repo['likes']}</div>"
else:
extra = f"<div class='meta'>❀️ {repo['likes']} | SDK: {repo['sdk']}</div>"
return f"""
<a class='card' href='{repo['url']}' target='_blank'>
<h3>{priv} {repo['id'].split('/')[-1]}</h3>
<div class='type'>{repo['type'].upper()}</div>
{extra}
<div class='tags'>{tags}</div>
</a>
"""
def _header():
m_pub = sum(1 for r in models if not r["private"])
m_priv = sum(1 for r in models if r["private"])
s_pub = sum(1 for r in spaces if not r["private"])
s_priv = sum(1 for r in spaces if r["private"])
return f"""
<div class='header'>
<h1>πŸ€— ScottzillaSystems Hub Dashboard</h1>
<div class='stats'>
<div class='stat-box'><span class='stat-num'>{len(models)}</span><span>Models</span></div>
<div class='stat-box'><span class='stat-num green'>{m_pub}</span><span>Public Models</span></div>
<div class='stat-box'><span class='stat-num red'>{m_priv}</span><span>Private Models</span></div>
<div class='stat-box'><span class='stat-num'>{len(spaces)}</span><span>Spaces</span></div>
<div class='stat-box'><span class='stat-num green'>{s_pub}</span><span>Public Spaces</span></div>
<div class='stat-box'><span class='stat-num red'>{s_priv}</span><span>Private Spaces</span></div>
</div>
</div>
"""
CSS = """
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&display=swap');
body {font-family: 'Inter', sans-serif; background:#0f0f1a; color:#e0e0e0;}
.header {text-align:center; padding:2rem 1rem 1rem;}
.header h1 {font-size:2.2rem; margin-bottom:.5rem; color:#ffb86c;}
.stats {display:flex; flex-wrap:wrap; justify-content:center; gap:1rem; margin-top:1rem;}
.stat-box {background:#1a1a2e; border:1px solid #2a2a40; border-radius:12px; padding:1rem 1.4rem; text-align:center; min-width:110px;}
.stat-num {display:block; font-size:1.6rem; font-weight:700; color:#82aaff;}
.stat-num.green {color:#50fa7b;} .stat-num.red {color:#ff5555;}
#cards {display:grid; grid-template-columns:repeat(auto-fill, minmax(280px,1fr)); gap:1rem; padding:1rem;}
.card {background:#16162a; border:1px solid #2a2a45; border-radius:14px; padding:1.2rem; display:block; text-decoration:none; color:inherit; transition:transform .15s, box-shadow .15s;}
.card:hover {transform:translateY(-4px); box-shadow:0 8px 24px rgba(0,0,0,.45); border-color:#ffb86c;}
.card h3 {margin:0 0 .4rem; font-size:1.15rem; color:#f8f8f2;}
.card .type {font-size:.75rem; color:#ffb86c; font-weight:600; margin-bottom:.5rem; text-transform:uppercase; letter-spacing:.05em;}
.card .meta {font-size:.85rem; color:#a0a0c0; margin-bottom:.6rem;}
.tag {display:inline-block; background:#2a2a45; color:#c0c0e0; font-size:.7rem; padding:.2rem .5rem; border-radius:6px; margin:.15rem .15rem 0 0;}
.tags {margin-top:.4rem;}
"""
# ── filter logic ────────────────────────────────────────────
def update(q="", kind="All", visibility="All"):
q = q.lower().strip()
filtered = []
for r in all_repos:
if kind != "All" and r["type"] != kind.lower(): continue
if visibility != "All":
if visibility == "Public" and r["private"]: continue
if visibility == "Private" and not r["private"]: continue
if q and q not in r["id"].lower() and q not in " ".join(r["tags"]).lower(): continue
filtered.append(r)
html = _header() + "<div id='cards'>" + "".join(_card(r) for r in filtered) + "</div>"
return f"<style>{CSS}</style>{html}"
def show_all(): return update()
# ── Gradio UI ───────────────────────────────────────────────
with gr.Blocks(title="ScottzillaSystems Hub Dashboard") as demo:
with gr.Row():
search = gr.Textbox(label="πŸ”Ž Search", placeholder="repo name or tag …", scale=4)
kind_dd = gr.Dropdown(["All", "Model", "Space"], value="All", label="Type", scale=1)
vis_dd = gr.Dropdown(["All", "Public", "Private"], value="All", label="Visibility", scale=1)
out = gr.HTML(label="Dashboard")
demo.load(show_all, outputs=out)
search.change(update, inputs=[search, kind_dd, vis_dd], outputs=out)
kind_dd.change(update, inputs=[search, kind_dd, vis_dd], outputs=out)
vis_dd.change(update, inputs=[search, kind_dd, vis_dd], outputs=out)
gr.Markdown("<center>Built with ❀️ using Gradio β€’ Data refreshes on page load</center>")
if __name__ == "__main__":
demo.launch(server_name="0.0.0.0")