Spaces:
Sleeping
Sleeping
| from flask import Flask, render_template, request, jsonify | |
| import os, re, json | |
| app = Flask(__name__) | |
| # ββββββββββββββββββββββββββ 1. CURATED CATEGORIES ββββββββββββββββββββββββββ | |
| CATEGORIES = { | |
| "Productivity": [ | |
| "https://huggingface.co/spaces/ginigen/perflexity-clone", | |
| "https://huggingface.co/spaces/ginipick/IDEA-DESIGN", | |
| "https://huggingface.co/spaces/VIDraft/mouse-webgen", | |
| "https://huggingface.co/spaces/openfree/Vibe-Game", | |
| "https://huggingface.co/spaces/openfree/Game-Gallery", | |
| "https://huggingface.co/spaces/aiqtech/Contributors-Leaderboard", | |
| "https://huggingface.co/spaces/fantaxy/Model-Leaderboard", | |
| "https://huggingface.co/spaces/fantaxy/Space-Leaderboard", | |
| "https://huggingface.co/spaces/openfree/Korean-Leaderboard", | |
| ], | |
| "Multimodal": [ | |
| "https://huggingface.co/spaces/openfree/DreamO-video", | |
| "https://huggingface.co/spaces/Heartsync/NSFW-Uncensored-photo", | |
| "https://huggingface.co/spaces/Heartsync/NSFW-Uncensored", | |
| "https://huggingface.co/spaces/fantaxy/Sound-AI-SFX", | |
| "https://huggingface.co/spaces/ginigen/SFX-Sound-magic", | |
| "https://huggingface.co/spaces/ginigen/VoiceClone-TTS", | |
| "https://huggingface.co/spaces/aiqcamp/MCP-kokoro", | |
| "https://huggingface.co/spaces/aiqcamp/ENGLISH-Speaking-Scoring", | |
| ], | |
| "Professional": [ | |
| "https://huggingface.co/spaces/ginigen/blogger", | |
| "https://huggingface.co/spaces/VIDraft/money-radar", | |
| "https://huggingface.co/spaces/immunobiotech/drug-discovery", | |
| "https://huggingface.co/spaces/immunobiotech/Gemini-MICHELIN", | |
| "https://huggingface.co/spaces/Heartsync/Papers-Leaderboard", | |
| "https://huggingface.co/spaces/VIDraft/PapersImpact", | |
| "https://huggingface.co/spaces/ginipick/AgentX-Papers", | |
| "https://huggingface.co/spaces/openfree/Cycle-Navigator", | |
| ], | |
| "Image": [ | |
| "https://huggingface.co/spaces/ginigen/interior-design", | |
| "https://huggingface.co/spaces/ginigen/Workflow-Canvas", | |
| "https://huggingface.co/spaces/ginigen/Multi-LoRAgen", | |
| "https://huggingface.co/spaces/ginigen/Every-Text", | |
| "https://huggingface.co/spaces/ginigen/text3d-r1", | |
| "https://huggingface.co/spaces/ginipick/FLUXllama", | |
| "https://huggingface.co/spaces/Heartsync/FLUX-Vision", | |
| "https://huggingface.co/spaces/ginigen/VisualCloze", | |
| "https://huggingface.co/spaces/seawolf2357/Ghibli-Multilingual-Text-rendering", | |
| "https://huggingface.co/spaces/ginigen/Ghibli-Meme-Studio", | |
| "https://huggingface.co/spaces/VIDraft/Open-Meme-Studio", | |
| "https://huggingface.co/spaces/ginigen/3D-LLAMA", | |
| ], | |
| "LLM / VLM": [ | |
| "https://huggingface.co/spaces/VIDraft/Gemma-3-R1984-4B", | |
| "https://huggingface.co/spaces/VIDraft/Gemma-3-R1984-12B", | |
| "https://huggingface.co/spaces/ginigen/Mistral-Perflexity", | |
| "https://huggingface.co/spaces/aiqcamp/gemini-2.5-flash-preview", | |
| "https://huggingface.co/spaces/openfree/qwen3-30b-a3b-research", | |
| "https://huggingface.co/spaces/openfree/qwen3-235b-a22b-research", | |
| "https://huggingface.co/spaces/openfree/Llama-4-Maverick-17B-Research", | |
| ], | |
| } | |
| # βββββββββββββββ 2. URL HELPERS (iframe + screenshot) ββββββββββββββββ | |
| def direct_url(hf_url: str) -> str: | |
| m = re.match(r"https?://huggingface\.co/spaces/([^/]+)/([^/?#]+)", hf_url) | |
| if not m: | |
| return hf_url | |
| owner, name = m.groups() | |
| owner = owner.lower() | |
| name = name.replace('.', '-').replace('_', '-').lower() | |
| return f"https://{owner}-{name}.hf.space" | |
| def screenshot_url(hf_url: str) -> str: | |
| return f"https://image.thum.io/get/fullpage/{direct_url(hf_url)}" | |
| # ββββββββββββββββ 3. CATEGORY API (used by tabs) ββββββββββββββββ | |
| def api_category(): | |
| cat = request.args.get('name', '') | |
| urls = CATEGORIES.get(cat, []) | |
| data = [] | |
| for url in urls: | |
| m = re.match(r"https?://huggingface\.co/spaces/([^/]+)/([^/?#]+)", url) | |
| owner, name = m.groups() if m else ('', url.split('/')[-1]) | |
| data.append({ | |
| "title": name, | |
| "owner": owner, | |
| "name": name, | |
| "iframe": direct_url(url), | |
| "shot": screenshot_url(url), | |
| "hf": url | |
| }) | |
| return jsonify(data) | |
| # βββββββββββββββββββββ 4. FRONT PAGE ROUTE βββββββββββββββββββββ | |
| def home(): | |
| return render_template('index.html', cats=list(CATEGORIES.keys())) | |
| # βββββββββββββ 5. BUILD index.html (once) ββββββββββββββ | |
| os.makedirs('templates', exist_ok=True) | |
| with open('templates/index.html', 'w', encoding='utf-8') as fp: | |
| fp.write(r'''<!DOCTYPE html> | |
| <html><head><meta charset="utf-8"><meta name="viewport"content="width=device-width,initial-scale=1"> | |
| <title>Dynamic HF Spaces Gallery</title> | |
| <style> | |
| @import url('https://fonts.googleapis.com/css2?family=Nunito:wght@300;600&display=swap'); | |
| body{margin:0;font-family:Nunito,sans-serif;background:#f6f8fb} | |
| .tabs{display:flex;flex-wrap:wrap;gap:8px;padding:16px} | |
| .tab{padding:6px 14px;border:none;border-radius:18px;background:#e2e8f0;font-weight:600;cursor:pointer} | |
| .tab.active{background:#a78bfa;color:#1a202c} | |
| .grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(330px,1fr));gap:14px;padding:0 16px 60px} | |
| .card{background:#fff;border-radius:12px;box-shadow:0 2px 8px rgba(0,0,0,.08);overflow:hidden;height:420px;display:flex;flex-direction:column;position:relative} | |
| .frame{flex:1;position:relative;overflow:hidden} | |
| .frame iframe,.frame img{position:absolute;width:166.667%;height:166.667%;transform:scale(.6);transform-origin:top left;border:0} | |
| .err{display:none;align-items:center;justify-content:center;width:100%;height:100%;background:#fafafa;text-align:center;padding:10px;color:#666;font-size:.9rem} | |
| .foot{height:44px;background:#fafafa;display:flex;align-items:center;justify-content:center;border-top:1px solid #eee} | |
| .foot a{font-size:.82rem;font-weight:700;color:#4a6dd8;text-decoration:none} | |
| </style></head> | |
| <body> | |
| <div class="tabs" id="tabs"></div> | |
| <div class="grid" id="grid"></div> | |
| <script> | |
| // ----- helpers -------------------------------------------------- | |
| function createCard(sp){ | |
| const c=document.createElement('div');c.className='card'; | |
| const f=document.createElement('div');f.className='frame'; | |
| const ifr=document.createElement('iframe'); | |
| ifr.src=sp.iframe; ifr.loading='lazy'; f.appendChild(ifr); | |
| const err=document.createElement('div');err.className='err'; | |
| err.innerHTML=`Preview blocked.<br><a href="${sp.hf}" target="_blank">Open on HF β</a>`; | |
| f.appendChild(err); | |
| ifr.onerror=()=>toSnapshot(); | |
| // after 10 s fallback if still blank | |
| setTimeout(()=>{try{ | |
| const ok=ifr.contentWindow && ifr.contentWindow.document.body.innerHTML.length>30; | |
| if(!ok) toSnapshot();}catch(e){toSnapshot();}},10000); | |
| function toSnapshot(){ | |
| ifr.remove(); const img=new Image(); | |
| img.src=sp.shot; img.loading='lazy'; | |
| img.onerror=()=>{err.style.display='flex';}; | |
| f.prepend(img); | |
| } | |
| const foot=document.createElement('div');foot.className='foot'; | |
| foot.innerHTML=`<a href="${sp.iframe}" target="_blank">${sp.title}</a>`; | |
| c.appendChild(f); c.appendChild(foot); | |
| return c; | |
| } | |
| // ----- load tab ------------------------------------------------- | |
| const cats={{cats|tojson}}; | |
| const tabs=document.getElementById('tabs'); | |
| const grid=document.getElementById('grid'); | |
| let active=""; | |
| function load(cat){ | |
| if(cat===active)return; active=cat; | |
| [...tabs.children].forEach(b=>b.classList.toggle('active',b.dataset.c===cat)); | |
| grid.innerHTML='<p style="grid-column:1/-1;text-align:center;padding:40px">Loadingβ¦</p>'; | |
| fetch('/api/category?name='+encodeURIComponent(cat)) | |
| .then(r=>r.json()).then(arr=>{ | |
| grid.innerHTML=''; | |
| arr.forEach(sp=>grid.appendChild(createCard(sp))); | |
| }); | |
| } | |
| // tabs init | |
| cats.forEach((c,i)=>{ | |
| const b=document.createElement('button'); | |
| b.className='tab';b.textContent=c;b.dataset.c=c; | |
| b.onclick=()=>load(c);tabs.appendChild(b); | |
| if(i===0)load(c); | |
| }); | |
| </script> | |
| </body></html>''') | |
| # ββββββββββββββββββ 6. RUN APP ββββββββββββββββββ | |
| if __name__ == '__main__': | |
| # hugggingface spaces use 7860 by convention | |
| app.run(host='0.0.0.0', port=7860) | |