Spaces:
Running
Running
File size: 8,012 Bytes
03dcabd 93d180e d927a6e 93d180e b1a8e9d 93d180e fb08ce6 93d180e b1a8e9d 93d180e fbf1f3d cf37bae 93d180e 4372751 93d180e fb08ce6 93d180e fb08ce6 93d180e fb08ce6 93d180e b1a8e9d fb08ce6 93d180e fb08ce6 93d180e b1a8e9d 93d180e b1a8e9d 84739ea 93d180e fb08ce6 93d180e e2255ea |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 |
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. HELPERS: build embed & direct URLs from HF link โโโโโโโโโโโ
def space_embed_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()
return f"https://huggingface.co/spaces/{owner}/{name}/embed"
def space_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()
# dots/underscores โ dashes, lowercase
owner = owner.lower()
name = name.replace('.', '-').replace('_', '-').lower()
return f"https://{owner}-{name}.hf.space"
# โโโโโโโโโโโโโ 3. API: return spaces for a given category โโโโโโโโโโโโโโ
@app.route('/api/category')
def api_category():
cat = request.args.get('name', '')
urls = CATEGORIES.get(cat, [])
spaces = [{
"title": url.split('/')[-1],
"embedUrl": space_embed_url(url),
"directUrl": space_direct_url(url)
} for url in urls]
return jsonify({"spaces": spaces})
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโ 4. ROUTES โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
@app.route('/')
def home():
return render_template('index.html', categories=list(CATEGORIES.keys()))
# โโโโโโโโโโโโโ 5. CREATE index.html with tabbed UI (once) โโโโโโโโโโโโโโโ
if not os.path.exists('templates'):
os.makedirs('templates')
with open('templates/index.html', 'w', encoding='utf-8') as f:
f.write(r'''<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>Curated HF Spaces</title>
<style>
@import url('https://fonts.googleapis.com/css2?family=Nunito:wght@300;500;700&display=swap');
body{margin:0;font-family:Nunito,sans-serif;background:#f0f2f8;}
.tabs{display:flex;gap:6px;flex-wrap:wrap;padding:16px;}
.tab-btn{padding:8px 14px;border:none;border-radius:20px;background:#e2e8f0;cursor:pointer;font-weight:600}
.tab-btn.active{background:#c4b5fd;color:#1a202c}
.grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(340px,1fr));gap:14px;padding:0 16px 40px}
.card{background:#fff;border-radius:12px;box-shadow:0 2px 8px rgba(0,0,0,.06);overflow:hidden;display:flex;flex-direction:column;height:420px;position:relative}
.tag{position:absolute;top:6px;left:6px;background:#10b981;color:#fff;font-size:.65rem;font-weight:700;padding:2px 6px;border-radius:4px;z-index:2}
.frame{flex:1;overflow:hidden}
.frame iframe{position:absolute;width:166.667%;height:166.667%;transform:scale(.6);transform-origin:top left;border:0}
.foot{height:40px;background:#fafafa;display:flex;align-items:center;justify-content:center;border-top:1px solid #eee}
.foot a{font-size:.82rem;font-weight:600;color:#4a6dd8;text-decoration:none}
</style>
</head>
<body>
<div class="tabs" id="tabs"></div>
<div id="grid" class="grid"></div>
<script>
const cats={{ categories|tojson }};
const tabsEl=document.getElementById('tabs');
const gridEl=document.getElementById('grid');
let active='';
function loadTab(cat){
if(cat===active) return;
active=cat;
[...tabsEl.children].forEach(b=>b.classList.toggle('active',b.dataset.cat===cat));
gridEl.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(data=>{
gridEl.innerHTML='';
data.spaces.forEach(sp=>{
const card=document.createElement('div');
card.className='card';
card.innerHTML=`
<span class="tag">LIVE</span>
<div class="frame"><iframe src="${sp.embedUrl}" loading="lazy" allow="accelerometer; gyroscope;"></iframe></div>
<div class="foot"><a href="${sp.directUrl}" target="_blank">Open โ</a></div>
`;
gridEl.appendChild(card);
});
});
}
cats.forEach((c,i)=>{
const b=document.createElement('button');
b.textContent=c;
b.className='tab-btn';
b.dataset.cat=c;
b.onclick=()=>loadTab(c);
tabsEl.appendChild(b);
if(i===0) loadTab(c);
});
</script>
</body>
</html>''')
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ 6. RUN โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
if __name__ == '__main__':
app.run(host='0.0.0.0', port=7860)
|