openfree commited on
Commit
274bed6
ยท
verified ยท
1 Parent(s): a2806bd

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +497 -927
app.py CHANGED
@@ -8,6 +8,7 @@ import os
8
  import time
9
  from huggingface_hub import HfApi, list_spaces, list_models
10
  from functools import lru_cache
 
11
 
12
  # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
13
  # ๐Ÿ”ง ZeroGPU ์ดˆ๊ธฐํ™”
@@ -32,398 +33,17 @@ app_initialized = initialize_app()
32
  HF_TOKEN = os.getenv("HF_TOKEN")
33
  hf_api = HfApi(token=HF_TOKEN) if HF_TOKEN else HfApi()
34
 
35
- # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
36
- # ๐Ÿ“ฆ ์ถ”๊ฐ€ ์ŠคํŽ˜์ด์Šค ๋ชฉ๋ก (Featured Spaces)
37
- # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
38
-
39
- FEATURED_SPACES = {
40
- "ginigen/Fashion-Fit360": "https://huggingface.co/spaces/ginigen/Fashion-Fit360",
41
- "aiqtech/Nano-Banana-API": "https://huggingface.co/spaces/aiqtech/Nano-Banana-API",
42
- "ginigen/Nano-Banana-Video": "https://huggingface.co/spaces/ginigen/Nano-Banana-Video",
43
- "openfree/News-AI": "https://huggingface.co/spaces/openfree/News-AI",
44
- "openfree/Creative-Arena-Leaderboard": "https://huggingface.co/spaces/openfree/Creative-Arena-Leaderboard",
45
- "Heartsync/Nano-Banana": "https://huggingface.co/spaces/Heartsync/Nano-Banana",
46
- "ginigen/webtoon-studio": "https://huggingface.co/spaces/ginigen/webtoon-studio",
47
- "VIDraft/gpt-oss-RAG": "https://huggingface.co/spaces/VIDraft/gpt-oss-RAG",
48
- "openfree/OpenAI-gpt-oss": "https://huggingface.co/spaces/openfree/OpenAI-gpt-oss",
49
- "openfree/AGI-NOVEL": "https://huggingface.co/spaces/openfree/AGI-NOVEL",
50
- "cutechicken/3D-Airforce-Simulator": "https://huggingface.co/spaces/cutechicken/3D-Airforce-Simulator",
51
- "ginipick/Private-AI": "https://huggingface.co/spaces/ginipick/Private-AI",
52
- "openfree/Best-AI": "https://huggingface.co/spaces/openfree/Best-AI",
53
- "aiqtech/Heatmap-Leaderboard": "https://huggingface.co/spaces/aiqtech/Heatmap-Leaderboard",
54
- "ginigen/Seedance-Free": "https://huggingface.co/spaces/ginigen/Seedance-Free",
55
- "openfree/K-AI": "https://huggingface.co/spaces/openfree/K-AI",
56
- "VIDraft/SOMA-AGI": "https://huggingface.co/spaces/VIDraft/SOMA-AGI",
57
- "openfree/AI": "https://huggingface.co/spaces/openfree/AI",
58
- "openfree/Chart-GPT": "https://huggingface.co/spaces/openfree/Chart-GPT",
59
- "fantaxy/fantasy-novel": "https://huggingface.co/spaces/fantaxy/fantasy-novel",
60
- "VIDraft/Gemma-3-R1984-1B": "https://huggingface.co/spaces/VIDraft/Gemma-3-R1984-1B",
61
- "ginigen/FLUX-Ghibli-LoRA2": "https://huggingface.co/spaces/ginigen/FLUX-Ghibli-LoRA2",
62
- "ginigen/Flux-VIDEO": "https://huggingface.co/spaces/ginigen/Flux-VIDEO",
63
- "aiqcamp/deepseek-r1-0528": "https://huggingface.co/spaces/aiqcamp/deepseek-r1-0528",
64
- "VIDraft/BAGEL-Websearch": "https://huggingface.co/spaces/VIDraft/BAGEL-Websearch",
65
- "ginigen/3D-LLAMA-V1": "https://huggingface.co/spaces/ginigen/3D-LLAMA-V1",
66
- "ginipick/Change-Hair": "https://huggingface.co/spaces/ginipick/Change-Hair",
67
- "VIDraft/Voice-Clone-Podcast": "https://huggingface.co/spaces/VIDraft/Voice-Clone-Podcast",
68
- "ginipick/PDF-EXAM": "https://huggingface.co/spaces/ginipick/PDF-EXAM",
69
- "openfree/Naming": "https://huggingface.co/spaces/openfree/Naming",
70
- "VIDraft/ACE-Singer": "https://huggingface.co/spaces/VIDraft/ACE-Singer",
71
- "openfree/Live-Podcast": "https://huggingface.co/spaces/openfree/Live-Podcast",
72
- "openfree/AI-Podcast": "https://huggingface.co/spaces/openfree/AI-Podcast",
73
- "ginipick/AI-BOOK": "https://huggingface.co/spaces/ginipick/AI-BOOK",
74
- "openfree/Web-Manager": "https://huggingface.co/spaces/openfree/Web-Manager",
75
- "openfree/Game-Gallery": "https://huggingface.co/spaces/openfree/Game-Gallery",
76
- "openfree/RPG-GAME": "https://huggingface.co/spaces/openfree/RPG-GAME",
77
- "openfree/Evolution-Simulation": "https://huggingface.co/spaces/openfree/Evolution-Simulation",
78
- "ginigen/3D-VIDEO": "https://huggingface.co/spaces/ginigen/3D-VIDEO",
79
- "ginipick/Pharmacy": "https://huggingface.co/spaces/ginipick/Pharmacy",
80
- "openfree/Battle-Royale-GAME": "https://huggingface.co/spaces/openfree/Battle-Royale-GAME",
81
- "openfree/repo-graph": "https://huggingface.co/spaces/openfree/repo-graph",
82
- "openfree/Chain-of-Recursive-Thoughts": "https://huggingface.co/spaces/openfree/Chain-of-Recursive-Thoughts",
83
- "ginigen/Mistral-Perflexity": "https://huggingface.co/spaces/ginigen/Mistral-Perflexity",
84
- "ginigen/Every-Text": "https://huggingface.co/spaces/ginigen/Every-Text",
85
- "openfree/svg": "https://huggingface.co/spaces/openfree/svg",
86
- "VIDraft/phi-4-reasoning-plus": "https://huggingface.co/spaces/VIDraft/phi-4-reasoning-plus",
87
- "ginigen/VisualCloze": "https://huggingface.co/spaces/ginigen/VisualCloze",
88
- "ginigen/framepack-i2v": "https://huggingface.co/spaces/ginigen/framepack-i2v",
89
- "fantos/Physics-Playground": "https://huggingface.co/spaces/fantos/Physics-Playground",
90
- "fantos/EveryText": "https://huggingface.co/spaces/fantos/EveryText",
91
- "ginipick/Qwen3-32B": "https://huggingface.co/spaces/ginipick/Qwen3-32B",
92
- "ginipick/Qwen3-235B-A22B": "https://huggingface.co/spaces/ginipick/Qwen3-235B-A22B",
93
- "keeperballon/vibe-coding-tetris": "https://huggingface.co/spaces/keeperballon/vibe-coding-tetris",
94
- "keeperballon/multi-llm": "https://huggingface.co/spaces/keeperballon/multi-llm",
95
- "VIDraft/Qwen3-8B": "https://huggingface.co/spaces/VIDraft/Qwen3-8B",
96
- "ginigen/interior-design": "https://huggingface.co/spaces/ginigen/interior-design",
97
- "ginigen/perflexity-clone": "https://huggingface.co/spaces/ginigen/perflexity-clone",
98
- "ginigen/blogger": "https://huggingface.co/spaces/ginigen/blogger",
99
- "openfree/Badge": "https://huggingface.co/spaces/openfree/Badge",
100
- "openfree/ZeroGPU-Leader": "https://huggingface.co/spaces/openfree/ZeroGPU-Leader",
101
- "cutechicken/World-of-Tank-GAME": "https://huggingface.co/spaces/cutechicken/World-of-Tank-GAME",
102
- "openfree/Llama-4-Maverick-17B-Research": "https://huggingface.co/spaces/openfree/Llama-4-Maverick-17B-Research",
103
- "fantaxy/Model-Leaderboard": "https://huggingface.co/spaces/fantaxy/Model-Leaderboard",
104
- "ginigen/FLUX-Open-Ghibli-Studio": "https://huggingface.co/spaces/ginigen/FLUX-Open-Ghibli-Studio",
105
- "openfree/Gemma-3-R1984-12B": "https://huggingface.co/spaces/openfree/Gemma-3-R1984-12B",
106
- "openfree/Stock-Trading-Analysis": "https://huggingface.co/spaces/openfree/Stock-Trading-Analysis",
107
- "aiqtech/Contributors-Leaderboard": "https://huggingface.co/spaces/aiqtech/Contributors-Leaderboard",
108
- "VIDraft/Gemma-3-R1984-27B": "https://huggingface.co/spaces/VIDraft/Gemma-3-R1984-27B",
109
- "openfree/Deepseek-v3-0324-Research": "https://huggingface.co/spaces/openfree/Deepseek-v3-0324-Research",
110
- "openfree/Korean-Exam-Leaderboard": "https://huggingface.co/spaces/openfree/Korean-Exam-Leaderboard",
111
- "openfree/Idea-Transformer": "https://huggingface.co/spaces/openfree/Idea-Transformer",
112
- "VIDraft/Unique3D": "https://huggingface.co/spaces/VIDraft/Unique3D",
113
- "openfree/Compare-RAG-CHAT": "https://huggingface.co/spaces/openfree/Compare-RAG-CHAT",
114
- "openfree/AgentX-Travel": "https://huggingface.co/spaces/openfree/AgentX-Travel",
115
- "openfree/SonicOrbit": "https://huggingface.co/spaces/openfree/SonicOrbit",
116
- "VIDraft/Space-Leaderboard": "https://huggingface.co/spaces/VIDraft/Space-Leaderboard",
117
- "ginipick/3D-GAME": "https://huggingface.co/spaces/ginipick/3D-GAME",
118
- "ginigen/Graph-Mind": "https://huggingface.co/spaces/ginigen/Graph-Mind",
119
- "openfree/deepseek_r1_API": "https://huggingface.co/spaces/openfree/deepseek_r1_API",
120
- "openfree/Mouse2-HF": "https://huggingface.co/spaces/openfree/Mouse2-HF",
121
- "ginipick/open_Deep-Research": "https://huggingface.co/spaces/ginipick/open_Deep-Research",
122
- "ginigen/LLaDA": "https://huggingface.co/spaces/ginigen/LLaDA",
123
- "VIDraft/PHI4-Multimodal": "https://huggingface.co/spaces/VIDraft/PHI4-Multimodal",
124
- "openfree/Datasets-Convertor": "https://huggingface.co/spaces/openfree/Datasets-Convertor",
125
- "ginigen/Ovis2-8B": "https://huggingface.co/spaces/ginigen/Ovis2-8B",
126
- "ginigen/FLUX-Eternity": "https://huggingface.co/spaces/ginigen/FLUX-Eternity",
127
- "ginigen/OmniParser-v2-pro": "https://huggingface.co/spaces/ginigen/OmniParser-v2-pro",
128
- "ginigen/panorama-images": "https://huggingface.co/spaces/ginigen/panorama-images",
129
- "ginigen/Celebrity": "https://huggingface.co/spaces/ginigen/Celebrity",
130
- "ginigen/Fashion-Pose-Control": "https://huggingface.co/spaces/ginigen/Fashion-Pose-Control",
131
- "ginigen/VoiceClone-TTS": "https://huggingface.co/spaces/ginigen/VoiceClone-TTS",
132
- "openfree/Article-Generator": "https://huggingface.co/spaces/openfree/Article-Generator",
133
- "openfree/chess": "https://huggingface.co/spaces/openfree/chess",
134
- "fantos/Panorama": "https://huggingface.co/spaces/fantos/Panorama",
135
- "ginigen/Multi-LoRAgen": "https://huggingface.co/spaces/ginigen/Multi-LoRAgen",
136
- "ginigen/canvas-studio": "https://huggingface.co/spaces/ginigen/canvas-studio",
137
- "fantos/Magic-Drawings": "https://huggingface.co/spaces/fantos/Magic-Drawings",
138
- "ginigen/Lumina-Image-PLUS": "https://huggingface.co/spaces/ginigen/Lumina-Image-PLUS",
139
- "VIDraft/mouse-webgen": "https://huggingface.co/spaces/VIDraft/mouse-webgen",
140
- "immunobiotech/MUSIC-Jukebox": "https://huggingface.co/spaces/immunobiotech/MUSIC-Jukebox",
141
- "kolaslab/Binaural-Beat-Generator": "https://huggingface.co/spaces/kolaslab/Binaural-Beat-Generator",
142
- "ginigen/Flux-LayerDiffuse": "https://huggingface.co/spaces/ginigen/Flux-LayerDiffuse",
143
- "VIDraft/Portrait-Animation": "https://huggingface.co/spaces/VIDraft/Portrait-Animation",
144
- "ginigen/text3d-r1": "https://huggingface.co/spaces/ginigen/text3d-r1",
145
- "immunobiotech/drug-discovery": "https://huggingface.co/spaces/immunobiotech/drug-discovery",
146
- "openfree/VisionOCR-Chat": "https://huggingface.co/spaces/openfree/VisionOCR-Chat",
147
- "immunobiotech/MICHELIN": "https://huggingface.co/spaces/immunobiotech/MICHELIN",
148
- "ginipick/PharmAI-Korea": "https://huggingface.co/spaces/ginipick/PharmAI-Korea",
149
- "ginigen/MagicFace-V3": "https://huggingface.co/spaces/ginigen/MagicFace-V3",
150
- "aiqcamp/MindMap": "https://huggingface.co/spaces/aiqcamp/MindMap",
151
- "ginigen/3D-LLAMA": "https://huggingface.co/spaces/ginigen/3D-LLAMA",
152
- "openfree/VectorFlow": "https://huggingface.co/spaces/openfree/VectorFlow",
153
- "openfree/webtoon-gen": "https://huggingface.co/spaces/openfree/webtoon-gen",
154
- "VIDraft/topic-prediction": "https://huggingface.co/spaces/VIDraft/topic-prediction",
155
- "openfree/MoneyRadar2": "https://huggingface.co/spaces/openfree/MoneyRadar2",
156
- "openfree/trending-board-2025": "https://huggingface.co/spaces/openfree/trending-board-2025",
157
- "VIDraft/PapersImpact": "https://huggingface.co/spaces/VIDraft/PapersImpact",
158
- "VIDraft/EveryRAG": "https://huggingface.co/spaces/VIDraft/EveryRAG",
159
- "ginipick/Any3D": "https://huggingface.co/spaces/ginipick/Any3D",
160
- "ginigen/Canvas-pro": "https://huggingface.co/spaces/ginigen/Canvas-pro",
161
- "openfree/image-to-vector": "https://huggingface.co/spaces/openfree/image-to-vector",
162
- "ginipick/QR-Canvas-plus": "https://huggingface.co/spaces/ginipick/QR-Canvas-plus",
163
- "openfree/Korean-Leaderboard-2025": "https://huggingface.co/spaces/openfree/Korean-Leaderboard-2025",
164
- "ginipick/DeepSeekR1-LIVE": "https://huggingface.co/spaces/ginipick/DeepSeekR1-LIVE",
165
- "ginigen/ColPali-multi": "https://huggingface.co/spaces/ginigen/ColPali-multi",
166
- "ginigen/Janus-Pro-7B": "https://huggingface.co/spaces/ginigen/Janus-Pro-7B",
167
- "ginigen/Animagine": "https://huggingface.co/spaces/ginigen/Animagine",
168
- "ginipick/OpenSUNO": "https://huggingface.co/spaces/ginipick/OpenSUNO",
169
- "openfree/PDF-RAG": "https://huggingface.co/spaces/openfree/PDF-RAG",
170
- "fantos/Ranking-Tracker": "https://huggingface.co/spaces/fantos/Ranking-Tracker",
171
- "aiqcamp/Multilingual-Images": "https://huggingface.co/spaces/aiqcamp/Multilingual-Images",
172
- "aiqcamp/Gemini2-Flash-Thinking": "https://huggingface.co/spaces/aiqcamp/Gemini2-Flash-Thinking",
173
- "kolaslab/8bit-gamemusic": "https://huggingface.co/spaces/kolaslab/8bit-gamemusic",
174
- "openfree/pepe": "https://huggingface.co/spaces/openfree/pepe",
175
- "openfree/MoneyRadar": "https://huggingface.co/spaces/openfree/MoneyRadar",
176
- "ginipick/QR-Canvas": "https://huggingface.co/spaces/ginipick/QR-Canvas",
177
- "openfree/MagicFace": "https://huggingface.co/spaces/openfree/MagicFace",
178
- "openfree/pick-spaces": "https://huggingface.co/spaces/openfree/pick-spaces",
179
- "aiqcamp/diagram": "https://huggingface.co/spaces/aiqcamp/diagram",
180
- "openfree/korea-president-yoon": "https://huggingface.co/spaces/openfree/korea-president-yoon",
181
- "VIDraft/PaperImpact": "https://huggingface.co/spaces/VIDraft/PaperImpact",
182
- "openfree/CryptoVision": "https://huggingface.co/spaces/openfree/CryptoVision",
183
- "gunship999/Gunship-3D-FPS": "https://huggingface.co/spaces/gunship999/Gunship-3D-FPS",
184
- "fantos/VoiceClone": "https://huggingface.co/spaces/fantos/VoiceClone",
185
- "VIDraft/ChemGenesis": "https://huggingface.co/spaces/VIDraft/ChemGenesis",
186
- "openfree/webtoon": "https://huggingface.co/spaces/openfree/webtoon",
187
- "kolaslab/Quantum": "https://huggingface.co/spaces/kolaslab/Quantum",
188
- "openfree/ProteinGenesis": "https://huggingface.co/spaces/openfree/ProteinGenesis",
189
- "openfree/2025saju": "https://huggingface.co/spaces/openfree/2025saju",
190
- "kolaslab/VisionART": "https://huggingface.co/spaces/kolaslab/VisionART",
191
- "ginigen/CANVAS-o3": "https://huggingface.co/spaces/ginigen/CANVAS-o3",
192
- "kolaslab/world-sdr": "https://huggingface.co/spaces/kolaslab/world-sdr",
193
- "openfree/ultpixgen": "https://huggingface.co/spaces/openfree/ultpixgen",
194
- "ginigen/theater": "https://huggingface.co/spaces/ginigen/theater",
195
- "VIDraft/stock": "https://huggingface.co/spaces/VIDraft/stock",
196
- "ginipick/FLUX-Prompt-Generator": "https://huggingface.co/spaces/ginipick/FLUX-Prompt-Generator",
197
- "ginigen/Dokdo": "https://huggingface.co/spaces/ginigen/Dokdo",
198
- "aiqcamp/imagemagic": "https://huggingface.co/spaces/aiqcamp/imagemagic",
199
- "openfree/ColorRevive": "https://huggingface.co/spaces/openfree/ColorRevive",
200
- "VIDraft/RAGOndevice": "https://huggingface.co/spaces/VIDraft/RAGOndevice",
201
- "ginigen/FLUXllama-Multilingual": "https://huggingface.co/spaces/ginigen/FLUXllama-Multilingual",
202
- "aiqcamp/Fashion-FLUX": "https://huggingface.co/spaces/aiqcamp/Fashion-FLUX",
203
- "ginipick/StyleGen": "https://huggingface.co/spaces/ginipick/StyleGen",
204
- "openfree/StoryStar": "https://huggingface.co/spaces/openfree/StoryStar",
205
- "openfree/Korean-Leaderboard": "https://huggingface.co/spaces/openfree/Korean-Leaderboard",
206
- "ginipick/FLUXllama": "https://huggingface.co/spaces/ginipick/FLUXllama",
207
- "ginipick/SORA-3D": "https://huggingface.co/spaces/ginipick/SORA-3D",
208
- "fantaxy/Sound-AI-SFX": "https://huggingface.co/spaces/fantaxy/Sound-AI-SFX",
209
- "ginigen/Canvas": "https://huggingface.co/spaces/ginigen/Canvas",
210
- "ginipick/time-machine": "https://huggingface.co/spaces/ginipick/time-machine",
211
- "openfree/Tetris-Game": "https://huggingface.co/spaces/openfree/Tetris-Game",
212
- "openfree/everychat": "https://huggingface.co/spaces/openfree/everychat",
213
- "VIDraft/mouse1": "https://huggingface.co/spaces/VIDraft/mouse1",
214
- "kolaslab/alpha-go": "https://huggingface.co/spaces/kolaslab/alpha-go",
215
- "ginipick/text3d": "https://huggingface.co/spaces/ginipick/text3d",
216
- "openfree/trending-board": "https://huggingface.co/spaces/openfree/trending-board",
217
- "cutechicken/tankwar": "https://huggingface.co/spaces/cutechicken/tankwar",
218
- "openfree/game-jewel": "https://huggingface.co/spaces/openfree/game-jewel",
219
- "VIDraft/mouse-chat": "https://huggingface.co/spaces/VIDraft/mouse-chat",
220
- "ginipick/AccDiffusion": "https://huggingface.co/spaces/ginipick/AccDiffusion",
221
- "openfree/GiniGEN": "https://huggingface.co/spaces/openfree/GiniGEN",
222
- "openfree/trending-news-24": "https://huggingface.co/spaces/openfree/trending-news-24",
223
- "ginipick/Realtime-FLUX": "https://huggingface.co/spaces/ginipick/Realtime-FLUX",
224
- "VIDraft/prime-number": "https://huggingface.co/spaces/VIDraft/prime-number",
225
- "kolaslab/zombie-game": "https://huggingface.co/spaces/kolaslab/zombie-game",
226
- "kolaslab/shooting": "https://huggingface.co/spaces/kolaslab/shooting",
227
- "VIDraft/Mouse-Hackathon": "https://huggingface.co/spaces/VIDraft/Mouse-Hackathon",
228
- "cutechicken/TankWar3D": "https://huggingface.co/spaces/cutechicken/TankWar3D",
229
- "kolaslab/RC4-EnDecoder": "https://huggingface.co/spaces/kolaslab/RC4-EnDecoder",
230
- "kolaslab/simulator": "https://huggingface.co/spaces/kolaslab/simulator",
231
- "kolaslab/calculator": "https://huggingface.co/spaces/kolaslab/calculator",
232
-
233
- # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
234
- # seawolf2357 Collection - NEW Launch
235
- # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
236
- "VIDraft/NH-Prediction": "https://huggingface.co/spaces/VIDraft/NH-Prediction",
237
- "ginipick/NH-Korea": "https://huggingface.co/spaces/ginipick/NH-Korea",
238
- "fantaxy/playground25": "https://huggingface.co/spaces/fantaxy/playground25",
239
- "openfree/Cycle-Navigator": "https://huggingface.co/spaces/openfree/Cycle-Navigator",
240
- "openfree/Vibe-Game": "https://huggingface.co/spaces/openfree/Vibe-Game",
241
- "ginipick/IDEA-DESIGN": "https://huggingface.co/spaces/ginipick/IDEA-DESIGN",
242
- "openfree/DreamO-video": "https://huggingface.co/spaces/openfree/DreamO-video",
243
- "openfree/Pulsar-Display": "https://huggingface.co/spaces/openfree/Pulsar-Display",
244
- "immunobiotech/Gemini-MICHELIN-kr": "https://huggingface.co/spaces/immunobiotech/Gemini-MICHELIN-kr",
245
- "immunobiotech/Gemini-MICHELIN": "https://huggingface.co/spaces/immunobiotech/Gemini-MICHELIN",
246
- "aiqcamp/SEO-checker": "https://huggingface.co/spaces/aiqcamp/SEO-checker",
247
- "openfree/qwen3-235b-a22b-research": "https://huggingface.co/spaces/openfree/qwen3-235b-a22b-research",
248
- "aiqcamp/ENGLISH-Speaking-Scoring": "https://huggingface.co/spaces/aiqcamp/ENGLISH-Speaking-Scoring",
249
- "openfree/qwen3-30b-a3b-research": "https://huggingface.co/spaces/openfree/qwen3-30b-a3b-research",
250
- "aiqcamp/gemini-2.5-flash-preview": "https://huggingface.co/spaces/aiqcamp/gemini-2.5-flash-preview",
251
- "aiqcamp/MCP-kokoro": "https://huggingface.co/spaces/aiqcamp/MCP-kokoro",
252
- "VIDraft/Local-RAG-llama-3-8b": "https://huggingface.co/spaces/VIDraft/Local-RAG-llama-3-8b",
253
- "VIDraft/FramePack_rotate_landscape": "https://huggingface.co/spaces/VIDraft/FramePack_rotate_landscape",
254
- "yokoha/CSV": "https://huggingface.co/spaces/yokoha/CSV",
255
- "yokoha/CSV-Parquet-Convertors": "https://huggingface.co/spaces/yokoha/CSV-Parquet-Convertors",
256
- "openfree/Llama-4-Scout-17B-Research": "https://huggingface.co/spaces/openfree/Llama-4-Scout-17B-Research",
257
- "aiqtech/LLM-Token-Visual": "https://huggingface.co/spaces/aiqtech/LLM-Token-Visual",
258
- "VIDraft/ThinkFlow-llama": "https://huggingface.co/spaces/VIDraft/ThinkFlow-llama",
259
- "VIDraft/Flex-preview": "https://huggingface.co/spaces/VIDraft/Flex-preview",
260
- "VIDraft/Open-Meme-Studio": "https://huggingface.co/spaces/VIDraft/Open-Meme-Studio",
261
- "ginigen/Ghibli-Meme-Studio": "https://huggingface.co/spaces/ginigen/Ghibli-Meme-Studio",
262
- "ginigen/FLUX-Text-Tree-Image": "https://huggingface.co/spaces/ginigen/FLUX-Text-Tree-Image",
263
- "ginigen/SAJU": "https://huggingface.co/spaces/ginigen/SAJU",
264
- "ginipick/AgentX-Papers": "https://huggingface.co/spaces/ginipick/AgentX-Papers",
265
-
266
- # โ•โ•โ•โ•โ•โ•โ•๏ฟฝ๏ฟฝโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
267
- # Heartsync Spaces (humangen.ai)
268
- # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
269
- "Heartsync/Nano-Banana": "https://huggingface.co/spaces/Heartsync/Nano-Banana",
270
- "Heartsync/humangen": "https://huggingface.co/spaces/Heartsync/humangen",
271
- "Heartsync/EXAM-GEN": "https://huggingface.co/spaces/Heartsync/EXAM-GEN",
272
- "Heartsync/VEO3-RealTime": "https://huggingface.co/spaces/Heartsync/VEO3-RealTime",
273
- "Heartsync/Qwen-Image-2512-Fast": "https://huggingface.co/spaces/Heartsync/Qwen-Image-2512-Fast",
274
- "Heartsync/NSFW-Uncensored-video2": "https://huggingface.co/spaces/Heartsync/NSFW-Uncensored-video2",
275
- "Heartsync/Adult": "https://huggingface.co/spaces/Heartsync/Adult",
276
- "Heartsync/NSFW-Uncensored-photo": "https://huggingface.co/spaces/Heartsync/NSFW-Uncensored-photo",
277
- "Heartsync/NSFW-image": "https://huggingface.co/spaces/Heartsync/NSFW-image",
278
- "Heartsync/FREE-NSFW-HUB": "https://huggingface.co/spaces/Heartsync/FREE-NSFW-HUB",
279
- "Heartsync/NSFW-Uncensored-image": "https://huggingface.co/spaces/Heartsync/NSFW-Uncensored-image",
280
- "Heartsync/PornHUB": "https://huggingface.co/spaces/Heartsync/PornHUB",
281
- "Heartsync/NSFW-Uncensored-image2": "https://huggingface.co/spaces/Heartsync/NSFW-Uncensored-image2",
282
- "Heartsync/Hentai-Adult": "https://huggingface.co/spaces/Heartsync/Hentai-Adult",
283
- "Heartsync/Dream-wan2-2-faster-Pro": "https://huggingface.co/spaces/Heartsync/Dream-wan2-2-faster-Pro",
284
- "Heartsync/nsfwnovel": "https://huggingface.co/spaces/Heartsync/nsfwnovel",
285
- "Heartsync/nsfwt2i": "https://huggingface.co/spaces/Heartsync/nsfwt2i",
286
- "Heartsync/WAN2-1-fast-T2V-FusioniX": "https://huggingface.co/spaces/Heartsync/WAN2-1-fast-T2V-FusioniX",
287
- "Heartsync/nsfwadult": "https://huggingface.co/spaces/Heartsync/nsfwadult",
288
- "Heartsync/zlora": "https://huggingface.co/spaces/Heartsync/zlora",
289
- "Heartsync/multimodal-chat-mbti-INFJ": "https://huggingface.co/spaces/Heartsync/multimodal-chat-mbti-INFJ",
290
- "Heartsync/wan2-1-fast-security": "https://huggingface.co/spaces/Heartsync/wan2-1-fast-security",
291
- "Heartsync/NSFW-detection": "https://huggingface.co/spaces/Heartsync/NSFW-detection",
292
- "Heartsync/wan2_2-I2V-14B-FAST": "https://huggingface.co/spaces/Heartsync/wan2_2-I2V-14B-FAST",
293
- "Heartsync/FLUX-Vision": "https://huggingface.co/spaces/Heartsync/FLUX-Vision",
294
- "Heartsync/Qwen-Image-LORA": "https://huggingface.co/spaces/Heartsync/Qwen-Image-LORA",
295
- "Heartsync/Character": "https://huggingface.co/spaces/Heartsync/Character",
296
- "Heartsync/FLite-Texture-ULTRA": "https://huggingface.co/spaces/Heartsync/FLite-Texture-ULTRA",
297
- "Heartsync/Wan-2.1-T2V-1.3B-LoRA": "https://huggingface.co/spaces/Heartsync/Wan-2.1-T2V-1.3B-LoRA",
298
- "Heartsync/NSFW-novels": "https://huggingface.co/spaces/Heartsync/NSFW-novels",
299
- "Heartsync/pose-generator-space": "https://huggingface.co/spaces/Heartsync/pose-generator-space",
300
- "Heartsync/convert": "https://huggingface.co/spaces/Heartsync/convert",
301
- "Heartsync/NSFW-Uncensored-new": "https://huggingface.co/spaces/Heartsync/NSFW-Uncensored-new",
302
- "Heartsync/image-ip-composer": "https://huggingface.co/spaces/Heartsync/image-ip-composer",
303
- "Heartsync/Papers-Leaderboard": "https://huggingface.co/spaces/Heartsync/Papers-Leaderboard",
304
- "Heartsync/voteaide": "https://huggingface.co/spaces/Heartsync/voteaide",
305
- "Heartsync/modeld": "https://huggingface.co/spaces/Heartsync/modeld",
306
-
307
- # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
308
- # seawolf2357 Spaces
309
- # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
310
- "seawolf2357/REALVISXL-V5": "https://huggingface.co/spaces/seawolf2357/REALVISXL-V5",
311
- "seawolf2357/ocrlatex": "https://huggingface.co/spaces/seawolf2357/ocrlatex",
312
- "seawolf2357/sd-prompt-gen": "https://huggingface.co/spaces/seawolf2357/sd-prompt-gen",
313
- "seawolf2357/voicechat": "https://huggingface.co/spaces/seawolf2357/voicechat",
314
- "seawolf2357/Sparc3D": "https://huggingface.co/spaces/seawolf2357/Sparc3D",
315
- "seawolf2357/apsf": "https://huggingface.co/spaces/seawolf2357/apsf",
316
- "seawolf2357/Flowise-AI": "https://huggingface.co/spaces/seawolf2357/Flowise-AI",
317
- "seawolf2357/3D-Avatar-Generator": "https://huggingface.co/spaces/seawolf2357/3D-Avatar-Generator",
318
- "seawolf2357/Ghibli-Multilingual-Text-rendering": "https://huggingface.co/spaces/seawolf2357/Ghibli-Multilingual-Text-rendering",
319
-
320
- # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•๏ฟฝ๏ฟฝ๏ฟฝโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
321
- # shuja666 (๊ด€๋ จ ์ปค๋ฎค๋‹ˆํ‹ฐ)
322
- # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
323
- "shuja666/seawolf2357-hanbok": "https://huggingface.co/spaces/shuja666/seawolf2357-hanbok",
324
-
325
- # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
326
- # openfree Collection - [New] AI Technologies & Services
327
- # (์ค‘๋ณต ์ œ์™ธ ์‹ ๊ทœ ์ŠคํŽ˜์ด์Šค๋งŒ)
328
- # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
329
- "Heartsync/hwp": "https://huggingface.co/spaces/Heartsync/hwp",
330
- "ginipick/spaces-research-korea": "https://huggingface.co/spaces/ginipick/spaces-research-korea",
331
- "fantaxy/Space-Leaderboard": "https://huggingface.co/spaces/fantaxy/Space-Leaderboard",
332
- "ginigen/Workflow-Canvas": "https://huggingface.co/spaces/ginigen/Workflow-Canvas",
333
- "ginigen/deepseek-r1-0528-API": "https://huggingface.co/spaces/ginigen/deepseek-r1-0528-API",
334
- "VIDraft/money-radar-korea": "https://huggingface.co/spaces/VIDraft/money-radar-korea",
335
- "VIDraft/Agentic-AI-CHAT": "https://huggingface.co/spaces/VIDraft/Agentic-AI-CHAT",
336
- "VIDraft/Gemma-3-R1984-4B": "https://huggingface.co/spaces/VIDraft/Gemma-3-R1984-4B",
337
- "VIDraft/Gemma-3-R1984-12B": "https://huggingface.co/spaces/VIDraft/Gemma-3-R1984-12B",
338
- "ginigen/SFX-Sound-magic": "https://huggingface.co/spaces/ginigen/SFX-Sound-magic",
339
- "openfree/Multilingual-TTS": "https://huggingface.co/spaces/openfree/Multilingual-TTS",
340
- "ginipick/10m-marketing": "https://huggingface.co/spaces/ginipick/10m-marketing",
341
- "VIDraft/Mistral-RAG-BitSix": "https://huggingface.co/spaces/VIDraft/Mistral-RAG-BitSix",
342
- "aiqcamp/REMOVAL-TEXT-IMAGE": "https://huggingface.co/spaces/aiqcamp/REMOVAL-TEXT-IMAGE",
343
- "aiqcamp/Mistral-Devstral-API": "https://huggingface.co/spaces/aiqcamp/Mistral-Devstral-API",
344
- "aiqcamp/deepseek-r1-0528-qwen3-8b": "https://huggingface.co/spaces/aiqcamp/deepseek-r1-0528-qwen3-8b",
345
- "Heartsync/WAN-VIDEO-AUDIO": "https://huggingface.co/spaces/Heartsync/WAN-VIDEO-AUDIO",
346
- "VIDraft/Gemma-3-R1984-1B-0613": "https://huggingface.co/spaces/VIDraft/Gemma-3-R1984-1B-0613",
347
- "Heartsync/NSFW-Uncensored-REAL": "https://huggingface.co/spaces/Heartsync/NSFW-Uncensored-REAL",
348
- "VIDraft/Robo-Beam": "https://huggingface.co/spaces/VIDraft/Robo-Beam",
349
- "VIDraft/voice-trans": "https://huggingface.co/spaces/VIDraft/voice-trans",
350
- "Heartsync/WAN2-1-fast-T2V-FusioniX2": "https://huggingface.co/spaces/Heartsync/WAN2-1-fast-T2V-FusioniX2",
351
- "ginigen/VEO3-Directors": "https://huggingface.co/spaces/ginigen/VEO3-Directors",
352
- "ginigen/VEO3-Free": "https://huggingface.co/spaces/ginigen/VEO3-Free",
353
- "ginigen/VEO3-Free-mirror": "https://huggingface.co/spaces/ginigen/VEO3-Free-mirror",
354
- "openfree/Open-GAMMA": "https://huggingface.co/spaces/openfree/Open-GAMMA",
355
- "fantaxy/YTB-TEST": "https://huggingface.co/spaces/fantaxy/YTB-TEST",
356
- "VIDraft/MOUSE-Workflow": "https://huggingface.co/spaces/VIDraft/MOUSE-Workflow",
357
- "aiqtech/SOMA-Oriental": "https://huggingface.co/spaces/aiqtech/SOMA-Oriental",
358
- "VIDraft/AI": "https://huggingface.co/spaces/VIDraft/AI",
359
- "openfree/Model-Atlas": "https://huggingface.co/spaces/openfree/Model-Atlas",
360
- "aiqtech/fastvlm-webgpu": "https://huggingface.co/spaces/aiqtech/fastvlm-webgpu",
361
- "aiqtech/Wan_FusionX_with_Loras": "https://huggingface.co/spaces/aiqtech/Wan_FusionX_with_Loras",
362
- "VIDraft/DNA-CASINO": "https://huggingface.co/spaces/VIDraft/DNA-CASINO",
363
- "ginigen/Flux-Kontext-Style": "https://huggingface.co/spaces/ginigen/Flux-Kontext-Style",
364
- "ginigen/higgs_audio-Enhanced": "https://huggingface.co/spaces/ginigen/higgs_audio-Enhanced",
365
- "Heartsync/addit": "https://huggingface.co/spaces/Heartsync/addit",
366
- "ginigen/Flux-Kontext-FaceLORA": "https://huggingface.co/spaces/ginigen/Flux-Kontext-FaceLORA",
367
- "openfree/Korea-Leaderboard": "https://huggingface.co/spaces/openfree/Korea-Leaderboard",
368
- "openfree/AI-Calcurator": "https://huggingface.co/spaces/openfree/AI-Calcurator",
369
- "ginigen/AGI-Screenplay": "https://huggingface.co/spaces/ginigen/AGI-Screenplay",
370
- "openfree/AGI-Screenplay-Pro": "https://huggingface.co/spaces/openfree/AGI-Screenplay-Pro",
371
- "fantaxy/AGI-LEADERBOARD": "https://huggingface.co/spaces/fantaxy/AGI-LEADERBOARD",
372
- "openfree/AGI-WebNovel": "https://huggingface.co/spaces/openfree/AGI-WebNovel",
373
- "openfree/AGI-WebNovel-Gallery": "https://huggingface.co/spaces/openfree/AGI-WebNovel-Gallery",
374
- "ginigen/Wan-2.2-Enhanced": "https://huggingface.co/spaces/ginigen/Wan-2.2-Enhanced",
375
- "Heartsync/Wan-2.2-ADULT": "https://huggingface.co/spaces/Heartsync/Wan-2.2-ADULT",
376
- "aiqtech/NSFW-Real": "https://huggingface.co/spaces/aiqtech/NSFW-Real",
377
- "VIDraft/skin-disease-identification": "https://huggingface.co/spaces/VIDraft/skin-disease-identification",
378
- "ginigen/AGI-WebToon-KOREA": "https://huggingface.co/spaces/ginigen/AGI-WebToon-KOREA",
379
- "ginigen/Hair-Pick": "https://huggingface.co/spaces/ginigen/Hair-Pick",
380
- "VIDraft/DNA-Diffusion": "https://huggingface.co/spaces/VIDraft/DNA-Diffusion",
381
- "openfree/WAR-Game-Simul": "https://huggingface.co/spaces/openfree/WAR-Game-Simul",
382
- "VIDraft/News-Stream": "https://huggingface.co/spaces/VIDraft/News-Stream",
383
- "openfree/Face-blurring": "https://huggingface.co/spaces/openfree/Face-blurring",
384
- "openfree/Nano-Banana-Upscale": "https://huggingface.co/spaces/openfree/Nano-Banana-Upscale",
385
- "openfree/Free-Nano-Banana": "https://huggingface.co/spaces/openfree/Free-Nano-Banana",
386
- "ginigen/Nano-Banana-PRO": "https://huggingface.co/spaces/ginigen/Nano-Banana-PRO",
387
- "VIDraft/company": "https://huggingface.co/spaces/VIDraft/company",
388
- "VIDraft/Creative-Design": "https://huggingface.co/spaces/VIDraft/Creative-Design",
389
- "VIDraft/Github-HF": "https://huggingface.co/spaces/VIDraft/Github-HF",
390
- "VIDraft/ROBO-R1984": "https://huggingface.co/spaces/VIDraft/ROBO-R1984",
391
- "VIDraft/XRAY": "https://huggingface.co/spaces/VIDraft/XRAY",
392
- "openfree/Dots-OCR": "https://huggingface.co/spaces/openfree/Dots-OCR",
393
- "VIDraft/Darwin-Qwen3-4B": "https://huggingface.co/spaces/VIDraft/Darwin-Qwen3-4B",
394
- "ginigen/wan2_2-I2V-14B-FAST": "https://huggingface.co/spaces/ginigen/wan2_2-I2V-14B-FAST",
395
- "ginigen/Today": "https://huggingface.co/spaces/ginigen/Today",
396
- "ginigen/AI": "https://huggingface.co/spaces/ginigen/AI",
397
- "ginigen/SAJU-FAST": "https://huggingface.co/spaces/ginigen/SAJU-FAST",
398
- "ginipick/SAJU-Couple": "https://huggingface.co/spaces/ginipick/SAJU-Couple",
399
- "ginigen/Family": "https://huggingface.co/spaces/ginigen/Family",
400
- "ginigen/Markets": "https://huggingface.co/spaces/ginigen/Markets",
401
- "fantos/Heatmap-Leaderboard-KOREA": "https://huggingface.co/spaces/fantos/Heatmap-Leaderboard-KOREA",
402
- "VIDraft/AGI-Personals": "https://huggingface.co/spaces/VIDraft/AGI-Personals",
403
- "VIDraft/Yolo26": "https://huggingface.co/spaces/VIDraft/Yolo26",
404
- "VIDraft/video-background-remove": "https://huggingface.co/spaces/VIDraft/video-background-remove",
405
- "openfree/Polymarket": "https://huggingface.co/spaces/openfree/Polymarket",
406
- "VIDraft/clone-git-repo-to-space": "https://huggingface.co/spaces/VIDraft/clone-git-repo-to-space",
407
- "VIDraft/THEME-STYLE": "https://huggingface.co/spaces/VIDraft/THEME-STYLE",
408
- "openfree/leaderboard-korea": "https://huggingface.co/spaces/openfree/leaderboard-korea",
409
- }
410
-
411
  # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
412
  # ๐Ÿ–ผ๏ธ ํ”„๋กœํ•„ ์‚ฌ์ง„ ์บ์‹œ ๋ฐ ์กฐํšŒ
413
  # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
414
 
415
- # ํ”„๋กœํ•„ ์‚ฌ์ง„ ์บ์‹œ (๋ฉ”๋ชจ๋ฆฌ)
416
  avatar_cache = {}
417
 
418
  def get_avatar_url(author: str) -> str:
419
- """
420
- HuggingFace ์‚ฌ์šฉ์ž/์กฐ์ง์˜ ์•„๋ฐ”ํƒ€ URL ์กฐํšŒ
421
- ์บ์‹œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ค‘๋ณต ์š”์ฒญ ๋ฐฉ์ง€
422
- """
423
  if not author:
424
  return get_default_avatar(author)
425
 
426
- # ์บ์‹œ ํ™•์ธ
427
  if author in avatar_cache:
428
  return avatar_cache[author]
429
 
@@ -434,7 +54,7 @@ def get_avatar_url(author: str) -> str:
434
  if HF_TOKEN:
435
  headers["Authorization"] = f"Bearer {HF_TOKEN}"
436
 
437
- # ๋ฐฉ๋ฒ• 1: ์กฐ์ง ์ •๋ณด ์กฐํšŒ
438
  try:
439
  org_url = f"https://huggingface.co/api/organizations/{author}"
440
  response = requests.get(org_url, headers=headers, timeout=10)
@@ -450,7 +70,7 @@ def get_avatar_url(author: str) -> str:
450
  except:
451
  pass
452
 
453
- # ๋ฐฉ๋ฒ• 2: ์‚ฌ์šฉ์ž ์ •๋ณด ์กฐํšŒ
454
  try:
455
  user_url = f"https://huggingface.co/api/users/{author}/overview"
456
  response = requests.get(user_url, headers=headers, timeout=10)
@@ -467,26 +87,9 @@ def get_avatar_url(author: str) -> str:
467
  except:
468
  pass
469
 
470
- # ๋ฐฉ๋ฒ• 3: ์ง์ ‘ ์‚ฌ์šฉ์ž API
471
- try:
472
- user_url = f"https://huggingface.co/api/users/{author}"
473
- response = requests.get(user_url, headers=headers, timeout=10)
474
-
475
- if response.status_code == 200:
476
- data = response.json()
477
- avatar_url = data.get('avatarUrl') or data.get('avatar_url')
478
- if avatar_url:
479
- if avatar_url.startswith('/'):
480
- avatar_url = f"https://huggingface.co{avatar_url}"
481
- avatar_cache[author] = avatar_url
482
- return avatar_url
483
- except:
484
- pass
485
-
486
  except Exception as e:
487
  print(f"[Avatar] Error fetching avatar for {author}: {e}")
488
 
489
- # ๋ชจ๋“  ๋ฐฉ๋ฒ• ์‹คํŒจ ์‹œ ๊ธฐ๋ณธ ์•„๋ฐ”ํƒ€
490
  default_avatar = get_default_avatar(author)
491
  avatar_cache[author] = default_avatar
492
  return default_avatar
@@ -506,22 +109,16 @@ def get_default_avatar(author: str = None) -> str:
506
  return "https://huggingface.co/front/assets/huggingface_logo-noborder.svg"
507
 
508
  def preload_avatars(authors: list, progress_callback=None):
509
- """์—ฌ๋Ÿฌ ์ €์ž์˜ ์•„๋ฐ”ํƒ€๋ฅผ ๋ฏธ๋ฆฌ ๋กœ๋“œ (๋ฐฐ์น˜ ์ฒ˜๋ฆฌ)"""
510
  unique_authors = list(set(author for author in authors if author))
511
  loaded = 0
512
- total = len(unique_authors)
513
-
514
- print(f"[Avatar] Starting to preload {total} unique authors...")
515
 
516
  for idx, author in enumerate(unique_authors):
517
  if author not in avatar_cache:
518
  get_avatar_url(author)
519
  loaded += 1
520
- if loaded % 5 == 0:
521
- time.sleep(0.2)
522
-
523
- if progress_callback and idx % 10 == 0:
524
- progress_callback(idx / total)
525
 
526
  print(f"[Avatar] Preloaded {loaded} new avatars, total cached: {len(avatar_cache)}")
527
 
@@ -567,7 +164,7 @@ def generate_unique_colors(count: int) -> list:
567
  # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
568
 
569
  ORGANIZATIONS = [
570
- # ๋Œ€๊ธฐ์—… - ๋ธŒ๋žœ๋“œ ์ƒ‰์ƒ ์‚ฌ์šฉ
571
  {"color": "#03C75A", "authors": ["naver-hyperclovax", "naver-ellm", "naver", "navervision", "naver-clova-ix", "naver-clova-ocr", "naver-ai"]},
572
  {"color": "#FFD200", "authors": ["kakaocorp", "kakaobrain", "kakaobank"]},
573
  {"color": "#1428A0", "authors": ["SamsungResearch", "SamsungSDS-Research", "SamsungSAILMontreal"]},
@@ -625,7 +222,7 @@ def get_all_authors():
625
  return authors
626
 
627
  def get_author_color(author: str) -> str:
628
- """์ €์ž์˜ ์ƒ‰์ƒ ๋ฐ˜ํ™˜ (๋Œ€์†Œ๋ฌธ์ž ๊ตฌ๋ถ„ ์—†์Œ)"""
629
  author_lower = author.lower()
630
  for org in ORGANIZATIONS:
631
  for org_author in org["authors"]:
@@ -634,220 +231,226 @@ def get_author_color(author: str) -> str:
634
  return "#6d7b8d"
635
 
636
  # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
637
- # ๐ŸŒ HuggingFace Hub API๋ฅผ ํ†ตํ•œ ์ •ํ™•ํ•œ ๋ฐ์ดํ„ฐ ์กฐํšŒ
638
  # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
639
 
640
- def get_all_spaces_with_ranks(limit=2400, progress=None):
641
- """์ „์—ญ ์ŠคํŽ˜์ด์Šค ์ˆœ์œ„ ๋ชฉ๋ก ์กฐํšŒ (likes ๊ธฐ์ค€ ์ •๋ ฌ)"""
642
- print(f"[Spaces] Fetching top {limit} spaces by likes...")
643
- all_spaces = {}
644
-
645
- try:
646
- count = 0
647
- for idx, space in enumerate(list_spaces(
648
- sort="likes",
649
- direction=-1,
650
- limit=limit,
651
- full=True,
652
- token=HF_TOKEN
653
- )):
654
- space_id = space.id
655
- all_spaces[space_id] = {
656
- "rank": idx + 1,
657
- "id": space_id,
658
- "likes": space.likes if hasattr(space, 'likes') else 0,
659
- "title": space.cardData.get('title', 'No Title') if hasattr(space, 'cardData') and space.cardData else 'No Title',
660
- "author": space.author if hasattr(space, 'author') else space_id.split('/')[0],
661
- }
662
- count += 1
663
-
664
- if progress and count % 200 == 0:
665
- progress(count / limit * 0.5, desc=f"Loading spaces: {count}/{limit}")
666
-
667
- if count >= limit:
668
- break
669
-
670
- print(f"[Spaces] Loaded {len(all_spaces)} spaces")
671
- return all_spaces
672
-
673
- except Exception as e:
674
- print(f"[Spaces] Error with huggingface_hub, falling back to API: {e}")
675
- return get_all_spaces_with_ranks_api(limit, progress)
676
-
677
- def get_all_spaces_with_ranks_api(limit=2400, progress=None):
678
- """API ํด๋ฐฑ"""
679
- all_spaces = {}
680
 
681
  try:
682
- url = "https://huggingface.co/api/spaces"
683
  headers = {"Authorization": f"Bearer {HF_TOKEN}"} if HF_TOKEN else {}
 
684
 
685
  params = {
686
  "sort": "likes",
687
  "direction": -1,
688
- "limit": min(limit, 10000),
689
- "full": "true"
690
  }
691
 
692
- response = requests.get(url, params=params, headers=headers, timeout=120)
 
693
  if response.status_code == 200:
694
  spaces_list = response.json()
695
- print(f"[Spaces API] Got {len(spaces_list)} spaces")
696
 
697
- for idx, space in enumerate(spaces_list[:limit]):
698
  space_id = space.get('id', '')
699
  if space_id:
700
- all_spaces[space_id] = {
701
- "rank": idx + 1,
702
- "id": space_id,
703
- "likes": space.get('likes', 0),
704
- "title": space.get('cardData', {}).get('title') if space.get('cardData') else space.get('title', 'No Title'),
705
- "author": space_id.split('/')[0],
706
- }
707
-
708
- return all_spaces
709
-
710
- except Exception as e:
711
- print(f"[Spaces API] Error: {e}")
712
- return {}
713
-
714
- def get_all_models_with_ranks(limit=3000, progress=None):
715
- """์ „์—ญ ๋ชจ๋ธ ์ˆœ์œ„ ๋ชฉ๋ก ์กฐํšŒ (downloads ๊ธฐ์ค€ ์ •๋ ฌ)"""
716
- print(f"[Models] Fetching top {limit} models by downloads...")
717
- all_models = {}
718
-
719
- try:
720
- count = 0
721
- for idx, model in enumerate(list_models(
722
- sort="downloads",
723
- direction=-1,
724
- limit=limit,
725
- full=True,
726
- token=HF_TOKEN
727
- )):
728
- model_id = model.id
729
- all_models[model_id] = {
730
- "rank": idx + 1,
731
- "id": model_id,
732
- "downloads": model.downloads if hasattr(model, 'downloads') else 0,
733
- "likes": model.likes if hasattr(model, 'likes') else 0,
734
- "title": model.id.split('/')[-1] if '/' in model.id else model.id,
735
- "author": model.author if hasattr(model, 'author') else model_id.split('/')[0],
736
- }
737
- count += 1
738
 
739
- if progress and count % 300 == 0:
740
- progress(count / limit * 0.5, desc=f"Loading models: {count}/{limit}")
 
 
741
 
742
- if count >= limit:
743
- break
744
-
745
- print(f"[Models] Loaded {len(all_models)} models")
746
- return all_models
747
-
748
  except Exception as e:
749
- print(f"[Models] Error with huggingface_hub, falling back to API: {e}")
750
- return get_all_models_with_ranks_api(limit, progress)
 
751
 
752
- def get_all_models_with_ranks_api(limit=3000, progress=None):
753
- """API ํด๋ฐฑ"""
754
- all_models = {}
 
 
 
 
755
 
756
  try:
757
- url = "https://huggingface.co/api/models"
758
  headers = {"Authorization": f"Bearer {HF_TOKEN}"} if HF_TOKEN else {}
 
759
 
760
  params = {
761
  "sort": "downloads",
762
  "direction": -1,
763
- "limit": min(limit, 10000),
764
- "full": "true"
765
  }
766
 
767
- response = requests.get(url, params=params, headers=headers, timeout=120)
 
768
  if response.status_code == 200:
769
  models_list = response.json()
770
- print(f"[Models API] Got {len(models_list)} models")
771
 
772
- for idx, model in enumerate(models_list[:limit]):
773
  model_id = model.get('id', '')
774
  if model_id:
775
- all_models[model_id] = {
776
- "rank": idx + 1,
777
- "id": model_id,
778
- "downloads": model.get('downloads', 0),
779
- "likes": model.get('likes', 0),
780
- "title": model.get('title', model_id.split('/')[-1]),
781
- "author": model_id.split('/')[0],
782
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
783
 
784
- return all_models
785
 
 
 
 
 
 
 
 
 
 
 
 
 
 
786
  except Exception as e:
787
- print(f"[Models API] Error: {e}")
788
- return {}
 
789
 
790
- def get_space_info(space_id: str) -> dict:
791
- """๊ฐœ๋ณ„ ์ŠคํŽ˜์ด์Šค ์ •๋ณด ์กฐํšŒ"""
 
792
  try:
793
  headers = {"Authorization": f"Bearer {HF_TOKEN}"} if HF_TOKEN else {}
794
- url = f"https://huggingface.co/api/spaces/{space_id}"
795
- response = requests.get(url, headers=headers, timeout=10)
 
 
 
 
 
 
 
796
 
797
  if response.status_code == 200:
798
- data = response.json()
799
- return {
800
- "id": space_id,
801
- "likes": data.get('likes', 0),
802
- "title": data.get('cardData', {}).get('title', 'No Title') if data.get('cardData') else 'No Title',
803
- "author": space_id.split('/')[0],
804
- }
 
 
 
 
 
805
  except Exception as e:
806
- print(f"[Space Info] Error fetching {space_id}: {e}")
807
-
808
- return None
809
-
810
- def filter_korean_spaces(all_spaces_ranked: dict) -> list:
811
- """์ „์—ญ ์ˆœ์œ„ ๋ฐ์ดํ„ฐ์—์„œ ํ•œ๊ตญ ๊ด€๋ จ ์ŠคํŽ˜์ด์Šค๋งŒ ํ•„ํ„ฐ๋ง + Featured Spaces ์ถ”๊ฐ€"""
812
- korean_authors = set(author.lower() for author in get_all_authors())
813
- korean_spaces = []
814
- existing_ids = set()
815
-
816
- # 1. API์—์„œ ๊ฐ€์ ธ์˜จ ํ•œ๊ตญ ์ŠคํŽ˜์ด์Šค ์ถ”๊ฐ€
817
- for space_id, space_data in all_spaces_ranked.items():
818
- author = space_data.get('author', '').lower()
819
- if author in korean_authors:
820
- space_data['url'] = f"https://huggingface.co/spaces/{space_id}"
821
- space_data['source'] = 'api'
822
- korean_spaces.append(space_data)
823
- existing_ids.add(space_id)
824
-
825
- # 2. Featured Spaces ์ค‘ ์•„์ง ์ถ”๊ฐ€๋˜์ง€ ์•Š์€ ๊ฒƒ๋“ค ์ถ”๊ฐ€
826
- print(f"[Filter] Checking {len(FEATURED_SPACES)} featured spaces...")
827
- featured_added = 0
828
-
829
- for space_id in FEATURED_SPACES.keys():
830
- if space_id not in existing_ids:
831
- # API์—์„œ ์ŠคํŽ˜์ด์Šค ์ •๋ณด ์กฐํšŒ
832
- space_info = get_space_info(space_id)
833
- if space_info:
834
- space_info['rank'] = 99999 # Featured๋Š” ์ˆœ์œ„ ๋ฐ–
835
- space_info['url'] = f"https://huggingface.co/spaces/{space_id}"
836
- space_info['source'] = 'featured'
837
- korean_spaces.append(space_info)
838
- existing_ids.add(space_id)
839
- featured_added += 1
840
-
841
- # Rate limiting
842
- if featured_added % 10 == 0:
843
- time.sleep(0.3)
844
 
845
- print(f"[Filter] Added {featured_added} featured spaces")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
846
 
847
- # 3. ์ˆœ์œ„ ๊ธฐ์ค€ ์ •๋ ฌ (Featured๋Š” ๋’ค๋กœ)
848
- korean_spaces.sort(key=lambda x: (x['rank'] == 99999, x['rank'], -x.get('likes', 0)))
 
 
 
 
 
 
 
849
 
850
- # 4. ๊ณ„์ •๋ณ„ ์ˆœ์œ„ ๊ณ„์‚ฐ
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
851
  author_counts = {}
852
  for space in korean_spaces:
853
  author = space['author']
@@ -857,25 +460,32 @@ def filter_korean_spaces(all_spaces_ranked: dict) -> list:
857
  space['author_rank'] = author_counts[author]
858
 
859
  # ํ”„๋กœํ•„ ์‚ฌ์ง„ ๋ฏธ๋ฆฌ ๋กœ๋“œ
860
- authors = [s['author'] for s in korean_spaces]
861
  preload_avatars(authors)
862
 
863
- print(f"[Filter] Found {len(korean_spaces)} Korean spaces (API: {len(korean_spaces) - featured_added}, Featured: {featured_added})")
 
 
864
  return korean_spaces
865
 
866
- def filter_korean_models(all_models_ranked: dict) -> list:
867
- """์ „์—ญ ์ˆœ์œ„ ๋ฐ์ดํ„ฐ์—์„œ ํ•œ๊ตญ ๊ด€๋ จ ๋ชจ๋ธ๋งŒ ํ•„ํ„ฐ๋ง"""
868
- korean_authors = set(author.lower() for author in get_all_authors())
869
- korean_models = []
 
 
 
 
 
 
 
870
 
871
- for model_id, model_data in all_models_ranked.items():
872
- author = model_data.get('author', '').lower()
873
- if author in korean_authors:
874
- model_data['url'] = f"https://huggingface.co/{model_id}"
875
- model_data['source'] = 'api'
876
- korean_models.append(model_data)
877
 
878
- korean_models.sort(key=lambda x: x['rank'])
 
 
879
 
880
  # ๊ณ„์ •๋ณ„ ์ˆœ์œ„ ๊ณ„์‚ฐ
881
  author_counts = {}
@@ -887,10 +497,12 @@ def filter_korean_models(all_models_ranked: dict) -> list:
887
  model['author_rank'] = author_counts[author]
888
 
889
  # ํ”„๋กœํ•„ ์‚ฌ์ง„ ๋ฏธ๋ฆฌ ๋กœ๋“œ
890
- authors = [m['author'] for m in korean_models]
891
  preload_avatars(authors)
892
 
893
- print(f"[Filter] Found {len(korean_models)} Korean models in top rankings")
 
 
894
  return korean_models
895
 
896
  # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
@@ -918,70 +530,30 @@ def create_error_plot():
918
  def get_spaces_data(progress=gr.Progress()):
919
  """์ŠคํŽ˜์ด์Šค ๋ฐ์ดํ„ฐ ์กฐํšŒ ๋ฐ ์‹œ๊ฐํ™”"""
920
  try:
921
- progress(0, desc="Fetching global space rankings (Top 2400)...")
922
 
923
- all_spaces_ranked = get_all_spaces_with_ranks(limit=2400, progress=progress)
 
924
 
925
- progress(0.6, desc="Filtering Korean spaces and adding featured...")
926
 
927
- korean_spaces = filter_korean_spaces(all_spaces_ranked)
 
928
 
929
- progress(0.8, desc="Creating visualization...")
930
 
931
- fig = go.Figure()
 
932
 
933
- if korean_spaces:
934
- # API ์†Œ์Šค์ธ ๊ฒƒ๋งŒ ์ฐจํŠธ์— ํ‘œ์‹œ (์ˆœ์œ„๊ฐ€ ์žˆ๋Š” ๊ฒƒ)
935
- api_spaces = [s for s in korean_spaces if s.get('source') == 'api']
936
- colors = [get_author_color(s['author']) for s in api_spaces]
937
-
938
- fig.add_trace(go.Bar(
939
- x=[s['id'] for s in api_spaces],
940
- y=[2401 - s['rank'] for s in api_spaces],
941
- text=[f"Global: #{s['rank']}<br>Author: #{s.get('author_rank', '-')}<br>Likes: {s['likes']}"
942
- for s in api_spaces],
943
- textposition='auto',
944
- marker_color=colors,
945
- opacity=0.85,
946
- hovertemplate="<b>%{x}</b><br>%{text}<extra></extra>"
947
- ))
948
-
949
- fig.update_layout(
950
- title={
951
- 'text': f'๐Ÿ† Korean Spaces Global Rankings (Top 2400) - Found: {len(korean_spaces)} (API: {len(api_spaces)})',
952
- 'y': 0.95, 'x': 0.5,
953
- 'xanchor': 'center', 'yanchor': 'top',
954
- 'font': {'size': 20, 'color': '#5a6677'}
955
- },
956
- xaxis_title='Space ID',
957
- yaxis_title='Global Rank',
958
- yaxis=dict(
959
- ticktext=[f"#{i}" for i in range(1, 2401, 100)],
960
- tickvals=[2401 - i for i in range(1, 2401, 100)],
961
- range=[0, 2400]
962
- ),
963
- height=500,
964
- showlegend=False,
965
- paper_bgcolor='#e0e5ec',
966
- plot_bgcolor='#e0e5ec',
967
- xaxis_tickangle=-45,
968
- font=dict(color='#6d7b8d'),
969
- margin=dict(l=60, r=30, t=60, b=100)
970
- )
971
-
972
- html_content = generate_space_cards_html(korean_spaces)
973
-
974
- df = pd.DataFrame([{
975
- 'Global Rank': f"#{s['rank']}" if s['rank'] != 99999 else "Featured",
976
- 'Author Rank': f"#{s.get('author_rank', '-')}",
977
- 'Space ID': s['id'],
978
- 'Title': s.get('title', 'N/A'),
979
- 'Likes': s['likes'],
980
- 'Source': s.get('source', 'api').upper(),
981
- 'URL': s['url']
982
- } for s in korean_spaces])
983
 
984
  progress(1.0, desc="Complete!")
 
985
  return fig, html_content, df
986
 
987
  except Exception as e:
@@ -993,68 +565,30 @@ def get_spaces_data(progress=gr.Progress()):
993
  def get_models_data(progress=gr.Progress()):
994
  """๋ชจ๋ธ ๋ฐ์ดํ„ฐ ์กฐํšŒ ๋ฐ ์‹œ๊ฐํ™”"""
995
  try:
996
- progress(0, desc="Fetching global model rankings (Top 3000)...")
997
 
998
- all_models_ranked = get_all_models_with_ranks(limit=3000, progress=progress)
 
999
 
1000
- progress(0.6, desc="Filtering Korean models...")
1001
 
1002
- korean_models = filter_korean_models(all_models_ranked)
 
1003
 
1004
- progress(0.8, desc="Creating visualization...")
1005
 
1006
- fig = go.Figure()
 
1007
 
1008
- if korean_models:
1009
- colors = [get_author_color(m['author']) for m in korean_models]
1010
-
1011
- fig.add_trace(go.Bar(
1012
- x=[m['id'] for m in korean_models],
1013
- y=[3001 - m['rank'] for m in korean_models],
1014
- text=[f"Global: #{m['rank']}<br>Author: #{m.get('author_rank', '-')}<br>Downloads: {m['downloads']:,}"
1015
- for m in korean_models],
1016
- textposition='auto',
1017
- marker_color=colors,
1018
- opacity=0.85,
1019
- hovertemplate="<b>%{x}</b><br>%{text}<extra></extra>"
1020
- ))
1021
-
1022
- fig.update_layout(
1023
- title={
1024
- 'text': f'๐Ÿ† Korean Models Global Rankings (Top 3000) - Found: {len(korean_models)}',
1025
- 'y': 0.95, 'x': 0.5,
1026
- 'xanchor': 'center', 'yanchor': 'top',
1027
- 'font': {'size': 20, 'color': '#5a6677'}
1028
- },
1029
- xaxis_title='Model ID',
1030
- yaxis_title='Global Rank',
1031
- yaxis=dict(
1032
- ticktext=[f"#{i}" for i in range(1, 3001, 200)],
1033
- tickvals=[3001 - i for i in range(1, 3001, 200)],
1034
- range=[0, 3000]
1035
- ),
1036
- height=500,
1037
- showlegend=False,
1038
- paper_bgcolor='#e0e5ec',
1039
- plot_bgcolor='#e0e5ec',
1040
- xaxis_tickangle=-45,
1041
- font=dict(color='#6d7b8d'),
1042
- margin=dict(l=60, r=30, t=60, b=100)
1043
- )
1044
-
1045
- html_content = generate_model_cards_html(korean_models)
1046
-
1047
- df = pd.DataFrame([{
1048
- 'Global Rank': f"#{m['rank']}",
1049
- 'Author Rank': f"#{m.get('author_rank', '-')}",
1050
- 'Model ID': m['id'],
1051
- 'Title': m.get('title', 'N/A'),
1052
- 'Downloads': f"{m['downloads']:,}",
1053
- 'Likes': m['likes'],
1054
- 'URL': m['url']
1055
- } for m in korean_models])
1056
 
1057
  progress(1.0, desc="Complete!")
 
1058
  return fig, html_content, df
1059
 
1060
  except Exception as e:
@@ -1063,58 +597,155 @@ def get_models_data(progress=gr.Progress()):
1063
  traceback.print_exc()
1064
  return create_error_plot(), f"<div style='color: #c00;'>Error: {e}</div>", pd.DataFrame()
1065
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1066
  # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
1067
- # ๐ŸŽด HTML ์นด๋“œ ์ƒ์„ฑ (ํ”„๋กœํ•„ ์‚ฌ์ง„ + ๊ณ„์ •๋ณ„ ์ˆœ์œ„ ํฌํ•จ)
1068
  # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
1069
 
1070
  def generate_space_cards_html(spaces: list) -> str:
1071
- """์ŠคํŽ˜์ด์Šค ์นด๋“œ HTML ์ƒ์„ฑ - ํ”„๋กœํ•„ ์‚ฌ์ง„ + ๊ณ„์ •๋ณ„ ์ˆœ์œ„ ํฌํ•จ"""
1072
 
1073
- # API ์†Œ์Šค์™€ Featured ์†Œ์Šค ๋ถ„๋ฆฌ
1074
- api_spaces = [s for s in spaces if s.get('source') == 'api']
1075
- featured_spaces = [s for s in spaces if s.get('source') == 'featured']
1076
 
1077
  html = f"""
1078
  <div style='padding: 20px; background: #e0e5ec; border-radius: 20px;
1079
  box-shadow: inset 4px 4px 8px #b8bec5, inset -4px -4px 8px #ffffff;'>
1080
  <h2 style='color: #5a6677; text-shadow: 2px 2px 4px #ffffff, -1px -1px 3px rgba(0,0,0,0.1);
1081
  margin-bottom: 20px; font-size: 24px;'>
1082
- ๐Ÿš€ Korean Spaces in Global Top 2400 (Total: {len(spaces)} | API: {len(api_spaces)} | Featured: {len(featured_spaces)})
1083
  </h2>
1084
  """
1085
 
1086
- # API Spaces ์„น์…˜
1087
- if api_spaces:
1088
- html += f"""
1089
- <h3 style='color: #5a6677; margin: 20px 0 15px 0; font-size: 18px;'>
1090
- ๐Ÿ“Š Global Ranked Spaces ({len(api_spaces)})
1091
- </h3>
1092
- <div style='display: grid; grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); gap: 20px;'>
1093
- """
1094
-
1095
- for space in api_spaces:
1096
- html += generate_space_card_html(space, show_global_rank=True)
1097
-
1098
- html += "</div>"
1099
 
1100
- # Featured Spaces ์„น์…˜
1101
- if featured_spaces:
1102
- html += f"""
1103
- <h3 style='color: #5a6677; margin: 30px 0 15px 0; font-size: 18px;'>
1104
- โญ Featured Spaces ({len(featured_spaces)})
1105
- </h3>
1106
- <div style='display: grid; grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); gap: 20px;'>
1107
- """
1108
-
1109
- for space in featured_spaces:
1110
- html += generate_space_card_html(space, show_global_rank=False)
1111
-
1112
- html += "</div>"
1113
 
1114
- html += "</div>"
 
 
 
1115
  return html
1116
 
1117
- def generate_space_card_html(space: dict, show_global_rank: bool = True) -> str:
1118
  """๊ฐœ๋ณ„ ์ŠคํŽ˜์ด์Šค ์นด๋“œ HTML ์ƒ์„ฑ"""
1119
  color = get_author_color(space['author'])
1120
  avatar_url = get_avatar_url(space['author'])
@@ -1123,54 +754,30 @@ def generate_space_card_html(space: dict, show_global_rank: bool = True) -> str:
1123
  color_hex = color.replace("#", "")
1124
  fallback_url = f"https://ui-avatars.com/api/?name={initials}&background={color_hex}&color=fff&size=128&bold=true"
1125
 
1126
- # ๋žญํ‚น ๋ฐฐ์ง€ ํ…์ŠคํŠธ
1127
- if show_global_rank and space['rank'] != 99999:
1128
- rank_badge = f"""
1129
- <div style='display: flex; gap: 8px;'>
1130
- <div style='
1131
- background: #e0e5ec;
1132
- border-radius: 12px;
1133
- padding: 8px 12px;
1134
- box-shadow: inset 4px 4px 8px #b8bec5, inset -4px -4px 8px #ffffff;
1135
- '>
1136
- <span style='color: #5a6677; font-weight: 800; font-size: 14px;'>
1137
- ๐ŸŒ #{space['rank']}
1138
- </span>
1139
- </div>
1140
- <div style='
1141
- background: {color}22;
1142
- border-radius: 12px;
1143
- padding: 8px 12px;
1144
- border: 2px solid {color};
1145
- '>
1146
- <span style='color: {color}; font-weight: 800; font-size: 14px;'>
1147
- ๐Ÿ‘ค #{space.get('author_rank', '-')}
1148
- </span>
1149
- </div>
1150
  </div>
1151
  """
1152
  else:
1153
- rank_badge = f"""
1154
- <div style='display: flex; gap: 8px;'>
1155
- <div style='
1156
- background: linear-gradient(135deg, #fbbf24, #f59e0b);
1157
- border-radius: 12px;
1158
- padding: 8px 12px;
1159
- '>
1160
- <span style='color: white; font-weight: 800; font-size: 14px;'>
1161
- โญ Featured
1162
- </span>
1163
- </div>
1164
- <div style='
1165
- background: {color}22;
1166
- border-radius: 12px;
1167
- padding: 8px 12px;
1168
- border: 2px solid {color};
1169
- '>
1170
- <span style='color: {color}; font-weight: 800; font-size: 14px;'>
1171
- ๐Ÿ‘ค #{space.get('author_rank', '-')}
1172
- </span>
1173
- </div>
1174
  </div>
1175
  """
1176
 
@@ -1207,7 +814,28 @@ def generate_space_card_html(space: dict, show_global_rank: bool = True) -> str:
1207
  </a>
1208
 
1209
  <!-- ๋žญํ‚น ๋ฐฐ์ง€ -->
1210
- {rank_badge}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1211
  </div>
1212
 
1213
  <!-- ์ €์ž ์ด๋ฆ„ -->
@@ -1242,7 +870,7 @@ def generate_space_card_html(space: dict, show_global_rank: bool = True) -> str:
1242
 
1243
  <!-- Likes -->
1244
  <p style='color: #6d7b8d; margin-bottom: 16px; font-size: 14px;'>
1245
- ๐Ÿ‘ Likes: <strong>{space['likes']:,}</strong>
1246
  </p>
1247
 
1248
  <!-- Visit ๋ฒ„ํŠผ -->
@@ -1263,18 +891,22 @@ def generate_space_card_html(space: dict, show_global_rank: bool = True) -> str:
1263
  """
1264
 
1265
  def generate_model_cards_html(models: list) -> str:
1266
- """๋ชจ๋ธ ์นด๋“œ HTML ์ƒ์„ฑ - ํ”„๋กœํ•„ ์‚ฌ์ง„ + ๊ณ„์ •๋ณ„ ์ˆœ์œ„ ํฌํ•จ"""
 
 
 
1267
  html = f"""
1268
  <div style='padding: 20px; background: #e0e5ec; border-radius: 20px;
1269
  box-shadow: inset 4px 4px 8px #b8bec5, inset -4px -4px 8px #ffffff;'>
1270
  <h2 style='color: #5a6677; text-shadow: 2px 2px 4px #ffffff, -1px -1px 3px rgba(0,0,0,0.1);
1271
  margin-bottom: 20px; font-size: 24px;'>
1272
- ๐Ÿค– Korean Models in Global Top 3000 (Found: {len(models)})
1273
  </h2>
1274
  <div style='display: grid; grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); gap: 20px;'>
1275
  """
1276
 
1277
- for model in models:
 
1278
  color = get_author_color(model['author'])
1279
  avatar_url = get_avatar_url(model['author'])
1280
 
@@ -1282,6 +914,33 @@ def generate_model_cards_html(models: list) -> str:
1282
  color_hex = color.replace("#", "")
1283
  fallback_url = f"https://ui-avatars.com/api/?name={initials}&background={color_hex}&color=fff&size=128&bold=true"
1284
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1285
  html += f"""
1286
  <div style='
1287
  background: #e0e5ec;
@@ -1291,9 +950,8 @@ def generate_model_cards_html(models: list) -> str:
1291
  transition: all 0.3s ease;
1292
  border-left: 4px solid {color};
1293
  '>
1294
- <!-- ํ—ค๋”: ํ”„๋กœํ•„ ์‚ฌ์ง„ + ๋žญํ‚น -->
1295
  <div style='display: flex; align-items: center; justify-content: space-between; margin-bottom: 16px;'>
1296
- <!-- ํ”„๋กœํ•„ ์‚ฌ์ง„ -->
1297
  <a href='https://huggingface.co/{model["author"]}' target='_blank' style='text-decoration: none;'>
1298
  <div style='
1299
  width: 56px;
@@ -1314,18 +972,17 @@ def generate_model_cards_html(models: list) -> str:
1314
  </div>
1315
  </a>
1316
 
1317
- <!-- ๋žญํ‚น ๋ฐฐ์ง€ -->
1318
- <div style='display: flex; gap: 8px;'>
1319
  <div style='
1320
- background: #e0e5ec;
1321
  border-radius: 12px;
1322
  padding: 8px 12px;
1323
- box-shadow: inset 4px 4px 8px #b8bec5, inset -4px -4px 8px #ffffff;
1324
  '>
1325
- <span style='color: #5a6677; font-weight: 800; font-size: 14px;'>
1326
- ๐ŸŒ #{model['rank']}
1327
  </span>
1328
  </div>
 
1329
  <div style='
1330
  background: {color}22;
1331
  border-radius: 12px;
@@ -1339,45 +996,24 @@ def generate_model_cards_html(models: list) -> str:
1339
  </div>
1340
  </div>
1341
 
1342
- <!-- ์ €์ž ์ด๋ฆ„ -->
1343
  <a href='https://huggingface.co/{model["author"]}' target='_blank'
1344
  style='text-decoration: none;'>
1345
- <p style='
1346
- color: {color};
1347
- font-weight: 700;
1348
- font-size: 14px;
1349
- margin: 0 0 8px 0;
1350
- display: flex;
1351
- align-items: center;
1352
- gap: 6px;
1353
- '>
1354
  ๐Ÿ‘ค {model['author']}
1355
  </p>
1356
  </a>
1357
 
1358
- <!-- Model ID -->
1359
  <h3 style='color: #5a6677; margin: 8px 0; font-size: 15px; word-break: break-all;'>
1360
  {model['id']}
1361
  </h3>
1362
 
1363
- <!-- ํƒ€์ดํ‹€ -->
1364
- <h4 style='
1365
- color: {color};
1366
- margin: 8px 0 16px 0;
1367
- font-size: 13px;
1368
- text-shadow: 1px 1px 2px #ffffff;
1369
- opacity: 0.9;
1370
- '>{model.get('title', 'N/A')}</h4>
1371
-
1372
- <!-- Downloads & Likes -->
1373
  <p style='color: #6d7b8d; margin-bottom: 8px; font-size: 14px;'>
1374
  โฌ‡๏ธ Downloads: <strong>{model['downloads']:,}</strong>
1375
  </p>
1376
  <p style='color: #6d7b8d; margin-bottom: 16px; font-size: 14px;'>
1377
- ๐Ÿ‘ Likes: <strong>{model['likes']:,}</strong>
1378
  </p>
1379
 
1380
- <!-- Visit ๋ฒ„ํŠผ -->
1381
  <a href='{model['url']}' target='_blank' style='
1382
  display: inline-block;
1383
  padding: 12px 24px;
@@ -1387,7 +1023,6 @@ def generate_model_cards_html(models: list) -> str:
1387
  border-radius: 50px;
1388
  font-weight: 700;
1389
  box-shadow: 6px 6px 12px #b8bec5, -6px -6px 12px #ffffff;
1390
- transition: all 0.2s ease;
1391
  '>
1392
  Visit Model ๐Ÿ”—
1393
  </a>
@@ -1401,27 +1036,32 @@ def generate_model_cards_html(models: list) -> str:
1401
  # ๐Ÿ“ˆ ํ†ต๊ณ„ ์ฐจํŠธ ์ƒ์„ฑ
1402
  # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
1403
 
1404
- def create_pie_chart(df: pd.DataFrame, total_count: int, type_name: str = "Spaces"):
1405
- """ํŒŒ์ด ์ฐจํŠธ ์ƒ์„ฑ"""
1406
  try:
1407
- korean_count = len(df) if not df.empty else 0
1408
- other_count = total_count - korean_count
 
 
 
 
1409
 
1410
- limit_label = "2400" if type_name == "Spaces" else "3000"
 
1411
 
1412
  fig = go.Figure(data=[go.Pie(
1413
- labels=[f'Korean {type_name}', f'Other {type_name}'],
1414
- values=[korean_count, other_count],
1415
  hole=.4,
1416
- marker_colors=['#6366f1', '#a5b4fc'],
1417
  textinfo='percent+value',
1418
  textfont=dict(color='#5a6677'),
1419
- hovertemplate="<b>%{label}</b><br>Count: %{value}<br>Percentage: %{percent}<extra></extra>"
1420
  )])
1421
 
1422
  fig.update_layout(
1423
  title={
1424
- 'text': f"๐Ÿ“Š Korean vs Global {type_name} (Top {limit_label})",
1425
  'font': {'size': 16, 'color': '#5a6677'}
1426
  },
1427
  showlegend=True,
@@ -1429,7 +1069,6 @@ def create_pie_chart(df: pd.DataFrame, total_count: int, type_name: str = "Space
1429
  paper_bgcolor='#e0e5ec',
1430
  plot_bgcolor='#e0e5ec',
1431
  font=dict(color='#6d7b8d'),
1432
- legend=dict(font=dict(color='#6d7b8d')),
1433
  margin=dict(l=20, r=20, t=50, b=20)
1434
  )
1435
 
@@ -1448,7 +1087,7 @@ def create_bar_chart(df: pd.DataFrame, type_name: str = "Spaces"):
1448
  if id_col not in df.columns:
1449
  return create_error_plot()
1450
 
1451
- registrations = df[id_col].apply(lambda x: x.split('/')[0] if '/' in str(x) else str(x)).value_counts()
1452
 
1453
  colors = [get_author_color(author) for author in registrations.index]
1454
 
@@ -1463,7 +1102,7 @@ def create_bar_chart(df: pd.DataFrame, type_name: str = "Spaces"):
1463
 
1464
  fig.update_layout(
1465
  title={
1466
- 'text': f"๐Ÿ‘ฅ {type_name} by Creator",
1467
  'font': {'size': 16, 'color': '#5a6677'}
1468
  },
1469
  xaxis_title="Creator",
@@ -1492,10 +1131,10 @@ def refresh_all_data():
1492
  spaces_results = get_spaces_data()
1493
  models_results = get_models_data()
1494
 
1495
- spaces_pie = create_pie_chart(spaces_results[2], 2400, "Spaces")
1496
  spaces_bar = create_bar_chart(spaces_results[2], "Spaces")
1497
 
1498
- models_pie = create_pie_chart(models_results[2], 3000, "Models")
1499
  models_bar = create_bar_chart(models_results[2], "Models")
1500
 
1501
  return [
@@ -1641,41 +1280,19 @@ table td {
1641
  border-radius: 20px !important;
1642
  overflow: hidden !important;
1643
  }
1644
-
1645
- .markdown-text {
1646
- background: transparent !important;
1647
- }
1648
-
1649
- .row, .column {
1650
- gap: 20px !important;
1651
- }
1652
-
1653
- .dataframe {
1654
- border-radius: 15px !important;
1655
- overflow: hidden !important;
1656
- }
1657
-
1658
- .profile-avatar {
1659
- transition: transform 0.2s ease, box-shadow 0.2s ease;
1660
- }
1661
-
1662
- .profile-avatar:hover {
1663
- transform: scale(1.05);
1664
- box-shadow: 6px 6px 12px var(--neu-shadow-dark), -6px -6px 12px var(--neu-shadow-light) !important;
1665
- }
1666
  """
1667
 
1668
  def create_org_legend_html():
1669
- """์กฐ์ง ๋ฒ”๋ก€ HTML ์ƒ์„ฑ - ํ”„๋กœํ•„ ์‚ฌ์ง„ ํฌํ•จ"""
1670
 
1671
  categories = {
1672
  "๐Ÿข ๋Œ€๊ธฐ์—…": [
1673
- {"color": "#03C75A", "name": "NAVER", "authors": ["naver-hyperclovax", "naver-ellm", "naver", "navervision", "naver-clova-ix", "naver-clova-ocr", "naver-ai"]},
1674
- {"color": "#FFD200", "name": "Kakao", "authors": ["kakaocorp", "kakaobrain", "kakaobank"]},
1675
- {"color": "#1428A0", "name": "Samsung", "authors": ["SamsungResearch", "SamsungSDS-Research", "SamsungSAILMontreal"]},
1676
  {"color": "#D70026", "name": "SK Telecom", "authors": ["skt", "skt-ai"]},
1677
- {"color": "#A50034", "name": "LG AI", "authors": ["LGAI-EXAONE", "lg-ai"]},
1678
- {"color": "#FF6B00", "name": "NCSOFT", "authors": ["NCSOFT", "nc-ai-consortium", "NC-AI-consortium-VAETKI"]},
1679
  {"color": "#E11D48", "name": "KRAFTON", "authors": ["KRAFTON"]},
1680
  ],
1681
  "๐Ÿš€ AI ์Šคํƒ€ํŠธ์—…": [
@@ -1683,23 +1300,13 @@ def create_org_legend_html():
1683
  {"color": "#2563EB", "name": "VIDraft", "authors": ["VIDraft"]},
1684
  {"color": "#1D4ED8", "name": "Ginigen", "authors": ["ginigen", "ginipick"]},
1685
  {"color": "#F59E0B", "name": "Trillion Labs", "authors": ["trillionlabs"]},
1686
- {"color": "#8B5CF6", "name": "Moreh/MOTIF", "authors": ["Motif-Technologies", "moreh"]},
1687
- {"color": "#0EA5E9", "name": "TELEPIX", "authors": ["telepix"]},
1688
- {"color": "#EC4899", "name": "Supertone", "authors": ["Supertone"]},
1689
- {"color": "#84CC16", "name": "HAERAE", "authors": ["HAERAE-HUB", "KOREAson"]},
1690
  {"color": "#C026D3", "name": "Nari Labs", "authors": ["nari-labs"]},
1691
- {"color": "#DB2777", "name": "Onoma AI", "authors": ["OnomaAIResearch"]},
1692
- {"color": "#EF4444", "name": "K-intelligence", "authors": ["K-intelligence"]},
1693
- {"color": "#F97316", "name": "LDCC", "authors": ["LDCC"]},
1694
  ],
1695
  "๐ŸŽ“ ์—ฐ๊ตฌ๊ธฐ๊ด€": [
1696
- {"color": "#10B981", "name": "ETRI", "authors": ["etri-vilab", "etri-xainlp", "etri-lirs", "etri"]},
1697
  {"color": "#14B8A6", "name": "KAIST", "authors": ["kaist-ai", "kaist-nlp"]},
1698
- {"color": "#06B6D4", "name": "SNU", "authors": ["snunlp", "snu-ai"]},
1699
  {"color": "#7C3AED", "name": "NLP AI Lab", "authors": ["nlpai-lab"]},
1700
- {"color": "#9333EA", "name": "Bllossom", "authors": ["Bllossom", "MLP-KTLim"]},
1701
- {"color": "#E11D48", "name": "Dnotitia", "authors": ["dnotitia"]},
1702
- {"color": "#F43F5E", "name": "Maywell", "authors": ["maywell"]},
1703
  ],
1704
  "๐Ÿ‘ฅ ์ปค๋ฎค๋‹ˆํ‹ฐ": [
1705
  {"color": "#3B82F6", "name": "openfree", "authors": ["openfree"]},
@@ -1712,20 +1319,9 @@ def create_org_legend_html():
1712
  {"color": "#EC4899", "name": "cutechicken", "authors": ["cutechicken"]},
1713
  {"color": "#F472B6", "name": "kolaslab", "authors": ["kolaslab"]},
1714
  {"color": "#FB7185", "name": "immunobiotech", "authors": ["immunobiotech"]},
1715
- {"color": "#F87171", "name": "yokoha", "authors": ["yokoha"]},
1716
- {"color": "#FBBF24", "name": "gunship999", "authors": ["gunship999"]},
1717
- {"color": "#A3E635", "name": "keeperballon", "authors": ["keeperballon"]},
1718
- {"color": "#22D3EE", "name": "shuja666", "authors": ["shuja666"]},
1719
  ],
1720
  }
1721
 
1722
- # ๋ชจ๋“  ์ €์ž์˜ ์•„๋ฐ”ํƒ€ ๋ฏธ๋ฆฌ ๋กœ๋“œ
1723
- all_authors_for_legend = []
1724
- for orgs in categories.values():
1725
- for org in orgs:
1726
- all_authors_for_legend.extend(org["authors"])
1727
- preload_avatars(all_authors_for_legend)
1728
-
1729
  html = """
1730
  <details style='background: #e0e5ec; border-radius: 20px;
1731
  box-shadow: 8px 8px 16px #b8bec5, -8px -8px 16px #ffffff; margin: 20px 0;'>
@@ -1744,12 +1340,6 @@ def create_org_legend_html():
1744
  """
1745
  for org in orgs:
1746
  main_author = org["authors"][0]
1747
- avatar_url = get_avatar_url(main_author)
1748
-
1749
- initials = main_author[:2].upper()
1750
- color_hex = org["color"].replace("#", "")
1751
- fallback_url = f"https://ui-avatars.com/api/?name={initials}&background={color_hex}&color=fff&size=64&bold=true"
1752
-
1753
  html += f"""
1754
  <a href='https://huggingface.co/{main_author}' target='_blank' style='text-decoration: none;'>
1755
  <div style='
@@ -1764,32 +1354,13 @@ def create_org_legend_html():
1764
  font-weight: 600;
1765
  transition: all 0.2s ease;
1766
  cursor: pointer;
1767
- ' onmouseover="this.style.boxShadow='2px 2px 4px #b8bec5, -2px -2px 4px #ffffff'"
1768
- onmouseout="this.style.boxShadow='4px 4px 8px #b8bec5, -4px -4px 8px #ffffff'">
1769
- <!-- ํ”„๋กœํ•„ ์ด๋ฏธ์ง€ -->
1770
- <div style='
1771
- width: 28px;
1772
- height: 28px;
1773
- border-radius: 50%;
1774
- margin-right: 8px;
1775
- overflow: hidden;
1776
- border: 2px solid {org["color"]};
1777
- box-shadow: inset 2px 2px 4px rgba(0,0,0,0.1);
1778
- background: linear-gradient(145deg, #f0f5fc, #d0d5dc);
1779
- '>
1780
- <img src='{avatar_url}'
1781
- alt='{org["name"]}'
1782
- style='width: 100%; height: 100%; object-fit: cover;'
1783
- onerror="this.onerror=null; this.src='{fallback_url}';">
1784
- </div>
1785
- <!-- ์ƒ‰์ƒ ํ‘œ์‹œ ์  -->
1786
  <span style='
1787
  width: 10px;
1788
  height: 10px;
1789
  border-radius: 50%;
1790
  background: {org["color"]};
1791
  margin-right: 6px;
1792
- box-shadow: inset 1px 1px 2px rgba(0,0,0,0.2);
1793
  '></span>
1794
  {org["name"]}
1795
  </div>
@@ -1809,46 +1380,45 @@ with gr.Blocks(title="Korean HuggingFace Leaderboard", head=f"<style>{CUSTOM_CSS
1809
  gr.Markdown("""
1810
  # ๐Ÿค— Korean HuggingFace Leaderboard
1811
 
1812
- **HuggingFace์˜ Spaces(Top 2400)์™€ Models(Top 3000) ์‹ค์‹œ๊ฐ„ ์ธ๊ธฐ ์ˆœ์œ„์—์„œ ํ•œ๊ตญ ๊ด€๋ จ ํ•ญ๋ชฉ์„ ๋ถ„์„ํ•ฉ๋‹ˆ๋‹ค.**
1813
 
1814
- - ๐ŸŒ **Global Rank**: HuggingFace ์ „์ฒด ์ˆœ์œ„
 
1815
  - ๐Ÿ‘ค **Author Rank**: ํ•ด๋‹น ๊ณ„์ • ๋‚ด ์ˆœ์œ„
1816
- - โญ **Featured**: Top 2400์—๋Š” ์—†์ง€๋งŒ ์ฃผ๋ชฉํ•  ๋งŒํ•œ ์ŠคํŽ˜์ด์Šค
1817
 
1818
  ยฉ ํ•œ๊ตญ์ธ๊ณต์ง€๋Šฅ์ง„ํฅํ˜‘ํšŒ / ๋ฌธ์˜: arxivgpt@gmail.com
1819
  """)
1820
 
1821
- # ์กฐ์ง ๋ฒ”๋ก€
1822
  gr.HTML(create_org_legend_html())
1823
 
1824
  refresh_btn = gr.Button("๐Ÿ”„ ์ƒˆ๋กœ ๊ณ ์นจ", variant="primary", elem_classes=["neu-button"])
1825
 
1826
- with gr.Tab("๐Ÿš€ Spaces Trending (Top 2400 + Featured)"):
1827
- spaces_plot = gr.Plot(label="Spaces Rankings (Top 2400)")
1828
  with gr.Row():
1829
  with gr.Column(scale=1):
1830
- spaces_pie_chart = gr.Plot(label="Distribution")
1831
  with gr.Column(scale=2):
1832
  spaces_bar_chart = gr.Plot(label="By Creator")
1833
  spaces_info = gr.HTML()
1834
  spaces_df = gr.DataFrame(
1835
- headers=["Global Rank", "Author Rank", "Space ID", "Title", "Likes", "Source", "URL"],
1836
- datatype=["str", "str", "str", "str", "number", "str", "str"],
1837
  row_count=(10, "dynamic"),
1838
  wrap=True
1839
  )
1840
 
1841
- with gr.Tab("๐Ÿค– Models Trending (Top 3000)"):
1842
- models_plot = gr.Plot(label="Models Rankings (Top 3000)")
1843
  with gr.Row():
1844
  with gr.Column(scale=1):
1845
- models_pie_chart = gr.Plot(label="Distribution")
1846
  with gr.Column(scale=2):
1847
  models_bar_chart = gr.Plot(label="By Creator")
1848
  models_info = gr.HTML()
1849
  models_df = gr.DataFrame(
1850
- headers=["Global Rank", "Author Rank", "Model ID", "Title", "Downloads", "Likes", "URL"],
1851
- datatype=["str", "str", "str", "str", "str", "number", "str"],
1852
  row_count=(10, "dynamic"),
1853
  wrap=True
1854
  )
 
8
  import time
9
  from huggingface_hub import HfApi, list_spaces, list_models
10
  from functools import lru_cache
11
+ from concurrent.futures import ThreadPoolExecutor, as_completed
12
 
13
  # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
14
  # ๐Ÿ”ง ZeroGPU ์ดˆ๊ธฐํ™”
 
33
  HF_TOKEN = os.getenv("HF_TOKEN")
34
  hf_api = HfApi(token=HF_TOKEN) if HF_TOKEN else HfApi()
35
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
36
  # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
37
  # ๐Ÿ–ผ๏ธ ํ”„๋กœํ•„ ์‚ฌ์ง„ ์บ์‹œ ๋ฐ ์กฐํšŒ
38
  # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
39
 
 
40
  avatar_cache = {}
41
 
42
  def get_avatar_url(author: str) -> str:
43
+ """HuggingFace ์‚ฌ์šฉ์ž/์กฐ์ง์˜ ์•„๋ฐ”ํƒ€ URL ์กฐํšŒ"""
 
 
 
44
  if not author:
45
  return get_default_avatar(author)
46
 
 
47
  if author in avatar_cache:
48
  return avatar_cache[author]
49
 
 
54
  if HF_TOKEN:
55
  headers["Authorization"] = f"Bearer {HF_TOKEN}"
56
 
57
+ # ์กฐ์ง ์ •๋ณด ์กฐํšŒ
58
  try:
59
  org_url = f"https://huggingface.co/api/organizations/{author}"
60
  response = requests.get(org_url, headers=headers, timeout=10)
 
70
  except:
71
  pass
72
 
73
+ # ์‚ฌ์šฉ์ž ์ •๋ณด ์กฐํšŒ
74
  try:
75
  user_url = f"https://huggingface.co/api/users/{author}/overview"
76
  response = requests.get(user_url, headers=headers, timeout=10)
 
87
  except:
88
  pass
89
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
90
  except Exception as e:
91
  print(f"[Avatar] Error fetching avatar for {author}: {e}")
92
 
 
93
  default_avatar = get_default_avatar(author)
94
  avatar_cache[author] = default_avatar
95
  return default_avatar
 
109
  return "https://huggingface.co/front/assets/huggingface_logo-noborder.svg"
110
 
111
  def preload_avatars(authors: list, progress_callback=None):
112
+ """์—ฌ๋Ÿฌ ์ €์ž์˜ ์•„๋ฐ”ํƒ€๋ฅผ ๋ฏธ๋ฆฌ ๋กœ๋“œ"""
113
  unique_authors = list(set(author for author in authors if author))
114
  loaded = 0
 
 
 
115
 
116
  for idx, author in enumerate(unique_authors):
117
  if author not in avatar_cache:
118
  get_avatar_url(author)
119
  loaded += 1
120
+ if loaded % 10 == 0:
121
+ time.sleep(0.1)
 
 
 
122
 
123
  print(f"[Avatar] Preloaded {loaded} new avatars, total cached: {len(avatar_cache)}")
124
 
 
164
  # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
165
 
166
  ORGANIZATIONS = [
167
+ # ๋Œ€๊ธฐ์—…
168
  {"color": "#03C75A", "authors": ["naver-hyperclovax", "naver-ellm", "naver", "navervision", "naver-clova-ix", "naver-clova-ocr", "naver-ai"]},
169
  {"color": "#FFD200", "authors": ["kakaocorp", "kakaobrain", "kakaobank"]},
170
  {"color": "#1428A0", "authors": ["SamsungResearch", "SamsungSDS-Research", "SamsungSAILMontreal"]},
 
222
  return authors
223
 
224
  def get_author_color(author: str) -> str:
225
+ """์ €์ž์˜ ์ƒ‰์ƒ ๋ฐ˜ํ™˜"""
226
  author_lower = author.lower()
227
  for org in ORGANIZATIONS:
228
  for org_author in org["authors"]:
 
231
  return "#6d7b8d"
232
 
233
  # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
234
+ # ๐ŸŒ HuggingFace API - ์ „์—ญ ์ˆœ์œ„ ์กฐํšŒ (likes ๊ธฐ์ค€)
235
  # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
236
 
237
+ def get_global_space_ranks(limit=10000, progress=None):
238
+ """
239
+ ์ „์—ญ ์ŠคํŽ˜์ด์Šค ์ˆœ์œ„ ์กฐํšŒ - likes ๊ธฐ์ค€
240
+ space_id -> global_rank ๋งคํ•‘ ๋ฐ˜ํ™˜
241
+ """
242
+ print(f"[Global Ranks] Fetching top {limit} spaces by likes...")
243
+ global_ranks = {}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
244
 
245
  try:
 
246
  headers = {"Authorization": f"Bearer {HF_TOKEN}"} if HF_TOKEN else {}
247
+ url = "https://huggingface.co/api/spaces"
248
 
249
  params = {
250
  "sort": "likes",
251
  "direction": -1,
252
+ "limit": limit,
253
+ "full": "false" # ๋น ๋ฅธ ์กฐํšŒ๋ฅผ ์œ„ํ•ด ๊ธฐ๋ณธ ์ •๋ณด๋งŒ
254
  }
255
 
256
+ response = requests.get(url, params=params, headers=headers, timeout=180)
257
+
258
  if response.status_code == 200:
259
  spaces_list = response.json()
260
+ print(f"[Global Ranks] Got {len(spaces_list)} spaces from API")
261
 
262
+ for idx, space in enumerate(spaces_list):
263
  space_id = space.get('id', '')
264
  if space_id:
265
+ global_ranks[space_id] = idx + 1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
266
 
267
+ if progress:
268
+ progress(0.3, desc=f"Loaded {len(global_ranks)} global rankings")
269
+ else:
270
+ print(f"[Global Ranks] API error: {response.status_code}")
271
 
 
 
 
 
 
 
272
  except Exception as e:
273
+ print(f"[Global Ranks] Error: {e}")
274
+
275
+ return global_ranks
276
 
277
+ def get_global_model_ranks(limit=10000, progress=None):
278
+ """
279
+ ์ „์—ญ ๋ชจ๋ธ ์ˆœ์œ„ ์กฐํšŒ - downloads ๊ธฐ์ค€
280
+ model_id -> global_rank ๋งคํ•‘ ๋ฐ˜ํ™˜
281
+ """
282
+ print(f"[Global Model Ranks] Fetching top {limit} models by downloads...")
283
+ global_ranks = {}
284
 
285
  try:
 
286
  headers = {"Authorization": f"Bearer {HF_TOKEN}"} if HF_TOKEN else {}
287
+ url = "https://huggingface.co/api/models"
288
 
289
  params = {
290
  "sort": "downloads",
291
  "direction": -1,
292
+ "limit": limit,
293
+ "full": "false"
294
  }
295
 
296
+ response = requests.get(url, params=params, headers=headers, timeout=180)
297
+
298
  if response.status_code == 200:
299
  models_list = response.json()
300
+ print(f"[Global Model Ranks] Got {len(models_list)} models from API")
301
 
302
+ for idx, model in enumerate(models_list):
303
  model_id = model.get('id', '')
304
  if model_id:
305
+ global_ranks[model_id] = idx + 1
306
+
307
+ if progress:
308
+ progress(0.3, desc=f"Loaded {len(global_ranks)} global model rankings")
309
+ else:
310
+ print(f"[Global Model Ranks] API error: {response.status_code}")
311
+
312
+ except Exception as e:
313
+ print(f"[Global Model Ranks] Error: {e}")
314
+
315
+ return global_ranks
316
+
317
+ # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
318
+ # ๐Ÿ” ํ•œ๊ตญ ์ €์ž๋ณ„ ์ŠคํŽ˜์ด์Šค/๋ชจ๋ธ ์ง์ ‘ ์กฐํšŒ
319
+ # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
320
+
321
+ def get_spaces_by_author(author: str) -> list:
322
+ """ํŠน์ • ์ €์ž์˜ ๋ชจ๋“  ์ŠคํŽ˜์ด์Šค ์กฐํšŒ"""
323
+ spaces = []
324
+ try:
325
+ headers = {"Authorization": f"Bearer {HF_TOKEN}"} if HF_TOKEN else {}
326
+ url = f"https://huggingface.co/api/spaces"
327
+
328
+ params = {
329
+ "author": author,
330
+ "full": "true",
331
+ "limit": 500
332
+ }
333
 
334
+ response = requests.get(url, params=params, headers=headers, timeout=30)
335
 
336
+ if response.status_code == 200:
337
+ spaces_data = response.json()
338
+ for space in spaces_data:
339
+ space_id = space.get('id', '')
340
+ if space_id:
341
+ spaces.append({
342
+ "id": space_id,
343
+ "likes": space.get('likes', 0),
344
+ "title": space.get('cardData', {}).get('title', 'No Title') if space.get('cardData') else space.get('title', 'No Title'),
345
+ "author": author,
346
+ "url": f"https://huggingface.co/spaces/{space_id}",
347
+ "createdAt": space.get('createdAt', ''),
348
+ })
349
  except Exception as e:
350
+ print(f"[Spaces by Author] Error for {author}: {e}")
351
+
352
+ return spaces
353
 
354
+ def get_models_by_author(author: str) -> list:
355
+ """ํŠน์ • ์ €์ž์˜ ๋ชจ๋“  ๋ชจ๋ธ ์กฐํšŒ"""
356
+ models = []
357
  try:
358
  headers = {"Authorization": f"Bearer {HF_TOKEN}"} if HF_TOKEN else {}
359
+ url = f"https://huggingface.co/api/models"
360
+
361
+ params = {
362
+ "author": author,
363
+ "full": "true",
364
+ "limit": 500
365
+ }
366
+
367
+ response = requests.get(url, params=params, headers=headers, timeout=30)
368
 
369
  if response.status_code == 200:
370
+ models_data = response.json()
371
+ for model in models_data:
372
+ model_id = model.get('id', '')
373
+ if model_id:
374
+ models.append({
375
+ "id": model_id,
376
+ "downloads": model.get('downloads', 0),
377
+ "likes": model.get('likes', 0),
378
+ "title": model_id.split('/')[-1] if '/' in model_id else model_id,
379
+ "author": author,
380
+ "url": f"https://huggingface.co/{model_id}",
381
+ })
382
  except Exception as e:
383
+ print(f"[Models by Author] Error for {author}: {e}")
384
+
385
+ return models
386
+
387
+ def get_all_korean_spaces(progress=None) -> list:
388
+ """๋ชจ๋“  ํ•œ๊ตญ ์ €์ž์˜ ์ŠคํŽ˜์ด์Šค ์กฐํšŒ"""
389
+ all_spaces = []
390
+ authors = get_all_authors()
391
+ total = len(authors)
392
+
393
+ print(f"[Korean Spaces] Fetching spaces for {total} Korean authors...")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
394
 
395
+ for idx, author in enumerate(authors):
396
+ spaces = get_spaces_by_author(author)
397
+ all_spaces.extend(spaces)
398
+
399
+ if progress and idx % 5 == 0:
400
+ progress(0.3 + (idx / total) * 0.4, desc=f"Fetching {author}... ({len(all_spaces)} spaces)")
401
+
402
+ # Rate limiting
403
+ if idx % 10 == 0:
404
+ time.sleep(0.2)
405
+
406
+ print(f"[Korean Spaces] Total: {len(all_spaces)} spaces from {total} authors")
407
+ return all_spaces
408
+
409
+ def get_all_korean_models(progress=None) -> list:
410
+ """๋ชจ๋“  ํ•œ๊ตญ ์ €์ž์˜ ๋ชจ๋ธ ์กฐํšŒ"""
411
+ all_models = []
412
+ authors = get_all_authors()
413
+ total = len(authors)
414
+
415
+ print(f"[Korean Models] Fetching models for {total} Korean authors...")
416
 
417
+ for idx, author in enumerate(authors):
418
+ models = get_models_by_author(author)
419
+ all_models.extend(models)
420
+
421
+ if progress and idx % 5 == 0:
422
+ progress(0.3 + (idx / total) * 0.4, desc=f"Fetching {author}... ({len(all_models)} models)")
423
+
424
+ if idx % 10 == 0:
425
+ time.sleep(0.2)
426
 
427
+ print(f"[Korean Models] Total: {len(all_models)} models from {total} authors")
428
+ return all_models
429
+
430
+ # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
431
+ # ๐Ÿ“Š ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ ๋ฐ ์ˆœ์œ„ ๊ณ„์‚ฐ
432
+ # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
433
+
434
+ def process_spaces_data(korean_spaces: list, global_ranks: dict, progress=None) -> list:
435
+ """
436
+ ํ•œ๊ตญ ์ŠคํŽ˜์ด์Šค ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ
437
+ - ์ „์—ญ ์ˆœ์œ„ ๋งคํ•‘
438
+ - likes ๊ธฐ์ค€ ์ •๋ ฌ
439
+ - ๊ณ„์ •๋ณ„ ์ˆœ์œ„ ๊ณ„์‚ฐ
440
+ """
441
+ # ์ „์—ญ ์ˆœ์œ„ ๋งคํ•‘
442
+ for space in korean_spaces:
443
+ space_id = space['id']
444
+ space['global_rank'] = global_ranks.get(space_id, None)
445
+
446
+ # likes ๊ธฐ์ค€ ์ •๋ ฌ (๋‚ด๋ฆผ์ฐจ์ˆœ)
447
+ korean_spaces.sort(key=lambda x: (-x['likes'], x['id']))
448
+
449
+ # ํ•œ๊ตญ ๋‚ด ์ˆœ์œ„ ๊ณ„์‚ฐ
450
+ for idx, space in enumerate(korean_spaces):
451
+ space['korean_rank'] = idx + 1
452
+
453
+ # ๊ณ„์ •๋ณ„ ์ˆœ์œ„ ๊ณ„์‚ฐ
454
  author_counts = {}
455
  for space in korean_spaces:
456
  author = space['author']
 
460
  space['author_rank'] = author_counts[author]
461
 
462
  # ํ”„๋กœํ•„ ์‚ฌ์ง„ ๋ฏธ๋ฆฌ ๋กœ๋“œ
463
+ authors = list(set(s['author'] for s in korean_spaces))
464
  preload_avatars(authors)
465
 
466
+ if progress:
467
+ progress(0.9, desc="Processing complete")
468
+
469
  return korean_spaces
470
 
471
+ def process_models_data(korean_models: list, global_ranks: dict, progress=None) -> list:
472
+ """
473
+ ํ•œ๊ตญ ๋ชจ๋ธ ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ
474
+ - ์ „์—ญ ์ˆœ์œ„ ๋งคํ•‘
475
+ - downloads ๊ธฐ์ค€ ์ •๋ ฌ
476
+ - ๊ณ„์ •๋ณ„ ์ˆœ์œ„ ๊ณ„์‚ฐ
477
+ """
478
+ # ์ „์—ญ ์ˆœ์œ„ ๋งคํ•‘
479
+ for model in korean_models:
480
+ model_id = model['id']
481
+ model['global_rank'] = global_ranks.get(model_id, None)
482
 
483
+ # downloads ๊ธฐ์ค€ ์ •๋ ฌ (๋‚ด๋ฆผ์ฐจ์ˆœ)
484
+ korean_models.sort(key=lambda x: (-x['downloads'], x['id']))
 
 
 
 
485
 
486
+ # ํ•œ๊ตญ ๋‚ด ์ˆœ์œ„ ๊ณ„์‚ฐ
487
+ for idx, model in enumerate(korean_models):
488
+ model['korean_rank'] = idx + 1
489
 
490
  # ๊ณ„์ •๋ณ„ ์ˆœ์œ„ ๊ณ„์‚ฐ
491
  author_counts = {}
 
497
  model['author_rank'] = author_counts[author]
498
 
499
  # ํ”„๋กœํ•„ ์‚ฌ์ง„ ๋ฏธ๋ฆฌ ๋กœ๋“œ
500
+ authors = list(set(m['author'] for m in korean_models))
501
  preload_avatars(authors)
502
 
503
+ if progress:
504
+ progress(0.9, desc="Processing complete")
505
+
506
  return korean_models
507
 
508
  # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
 
530
  def get_spaces_data(progress=gr.Progress()):
531
  """์ŠคํŽ˜์ด์Šค ๋ฐ์ดํ„ฐ ์กฐํšŒ ๋ฐ ์‹œ๊ฐํ™”"""
532
  try:
533
+ progress(0, desc="Fetching global space rankings...")
534
 
535
+ # 1. ์ „์—ญ ์ˆœ์œ„ ์กฐํšŒ (์ตœ๋Œ€ 10000๊ฐœ)
536
+ global_ranks = get_global_space_ranks(limit=10000, progress=progress)
537
 
538
+ progress(0.2, desc="Fetching Korean spaces...")
539
 
540
+ # 2. ํ•œ๊ตญ ์ €์ž ์ŠคํŽ˜์ด์Šค ์ง์ ‘ ์กฐํšŒ
541
+ korean_spaces = get_all_korean_spaces(progress=progress)
542
 
543
+ progress(0.7, desc="Processing data...")
544
 
545
+ # 3. ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ
546
+ processed_spaces = process_spaces_data(korean_spaces, global_ranks, progress)
547
 
548
+ progress(0.85, desc="Creating visualization...")
549
+
550
+ # 4. ์‹œ๊ฐํ™”
551
+ fig = create_spaces_chart(processed_spaces)
552
+ html_content = generate_space_cards_html(processed_spaces)
553
+ df = create_spaces_dataframe(processed_spaces)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
554
 
555
  progress(1.0, desc="Complete!")
556
+
557
  return fig, html_content, df
558
 
559
  except Exception as e:
 
565
  def get_models_data(progress=gr.Progress()):
566
  """๋ชจ๋ธ ๋ฐ์ดํ„ฐ ์กฐํšŒ ๋ฐ ์‹œ๊ฐํ™”"""
567
  try:
568
+ progress(0, desc="Fetching global model rankings...")
569
 
570
+ # 1. ์ „์—ญ ์ˆœ์œ„ ์กฐํšŒ
571
+ global_ranks = get_global_model_ranks(limit=10000, progress=progress)
572
 
573
+ progress(0.2, desc="Fetching Korean models...")
574
 
575
+ # 2. ํ•œ๊ตญ ์ €์ž ๋ชจ๋ธ ์ง์ ‘ ์กฐํšŒ
576
+ korean_models = get_all_korean_models(progress=progress)
577
 
578
+ progress(0.7, desc="Processing data...")
579
 
580
+ # 3. ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ
581
+ processed_models = process_models_data(korean_models, global_ranks, progress)
582
 
583
+ progress(0.85, desc="Creating visualization...")
584
+
585
+ # 4. ์‹œ๊ฐํ™”
586
+ fig = create_models_chart(processed_models)
587
+ html_content = generate_model_cards_html(processed_models)
588
+ df = create_models_dataframe(processed_models)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
589
 
590
  progress(1.0, desc="Complete!")
591
+
592
  return fig, html_content, df
593
 
594
  except Exception as e:
 
597
  traceback.print_exc()
598
  return create_error_plot(), f"<div style='color: #c00;'>Error: {e}</div>", pd.DataFrame()
599
 
600
+ def create_spaces_chart(spaces: list):
601
+ """์ŠคํŽ˜์ด์Šค ์ฐจํŠธ ์ƒ์„ฑ"""
602
+ fig = go.Figure()
603
+
604
+ if not spaces:
605
+ return create_error_plot()
606
+
607
+ # ์ƒ์œ„ 50๊ฐœ๋งŒ ์ฐจํŠธ์— ํ‘œ์‹œ
608
+ top_spaces = spaces[:50]
609
+ colors = [get_author_color(s['author']) for s in top_spaces]
610
+
611
+ # ์ „์—ญ ์ˆœ์œ„๊ฐ€ ์žˆ๋Š” ๊ฒƒ๊ณผ ์—†๋Š” ๊ฒƒ ๊ตฌ๋ถ„
612
+ global_ranked = [s for s in top_spaces if s.get('global_rank')]
613
+
614
+ fig.add_trace(go.Bar(
615
+ x=[s['id'] for s in top_spaces],
616
+ y=[s['likes'] for s in top_spaces],
617
+ text=[f"๐Ÿ‡ฐ๐Ÿ‡ท #{s['korean_rank']}<br>๐ŸŒ #{s['global_rank'] if s.get('global_rank') else 'N/A'}<br>โค๏ธ {s['likes']:,}"
618
+ for s in top_spaces],
619
+ textposition='auto',
620
+ marker_color=colors,
621
+ opacity=0.85,
622
+ hovertemplate="<b>%{x}</b><br>%{text}<extra></extra>"
623
+ ))
624
+
625
+ fig.update_layout(
626
+ title={
627
+ 'text': f'๐Ÿ† Korean Spaces by Likes (Total: {len(spaces)} | Top 50 shown)',
628
+ 'y': 0.95, 'x': 0.5,
629
+ 'xanchor': 'center', 'yanchor': 'top',
630
+ 'font': {'size': 20, 'color': '#5a6677'}
631
+ },
632
+ xaxis_title='Space ID',
633
+ yaxis_title='Likes',
634
+ height=500,
635
+ showlegend=False,
636
+ paper_bgcolor='#e0e5ec',
637
+ plot_bgcolor='#e0e5ec',
638
+ xaxis_tickangle=-45,
639
+ font=dict(color='#6d7b8d'),
640
+ margin=dict(l=60, r=30, t=60, b=100)
641
+ )
642
+
643
+ return fig
644
+
645
+ def create_models_chart(models: list):
646
+ """๋ชจ๋ธ ์ฐจํŠธ ์ƒ์„ฑ"""
647
+ fig = go.Figure()
648
+
649
+ if not models:
650
+ return create_error_plot()
651
+
652
+ # ์ƒ์œ„ 50๊ฐœ๋งŒ ์ฐจํŠธ์— ํ‘œ์‹œ
653
+ top_models = models[:50]
654
+ colors = [get_author_color(m['author']) for m in top_models]
655
+
656
+ fig.add_trace(go.Bar(
657
+ x=[m['id'] for m in top_models],
658
+ y=[m['downloads'] for m in top_models],
659
+ text=[f"๐Ÿ‡ฐ๐Ÿ‡ท #{m['korean_rank']}<br>๐ŸŒ #{m['global_rank'] if m.get('global_rank') else 'N/A'}<br>๏ฟฝ๏ฟฝ๏ฟฝ๏ธ {m['downloads']:,}"
660
+ for m in top_models],
661
+ textposition='auto',
662
+ marker_color=colors,
663
+ opacity=0.85,
664
+ hovertemplate="<b>%{x}</b><br>%{text}<extra></extra>"
665
+ ))
666
+
667
+ fig.update_layout(
668
+ title={
669
+ 'text': f'๐Ÿ† Korean Models by Downloads (Total: {len(models)} | Top 50 shown)',
670
+ 'y': 0.95, 'x': 0.5,
671
+ 'xanchor': 'center', 'yanchor': 'top',
672
+ 'font': {'size': 20, 'color': '#5a6677'}
673
+ },
674
+ xaxis_title='Model ID',
675
+ yaxis_title='Downloads',
676
+ height=500,
677
+ showlegend=False,
678
+ paper_bgcolor='#e0e5ec',
679
+ plot_bgcolor='#e0e5ec',
680
+ xaxis_tickangle=-45,
681
+ font=dict(color='#6d7b8d'),
682
+ margin=dict(l=60, r=30, t=60, b=100)
683
+ )
684
+
685
+ return fig
686
+
687
+ def create_spaces_dataframe(spaces: list) -> pd.DataFrame:
688
+ """์ŠคํŽ˜์ด์Šค ๋ฐ์ดํ„ฐํ”„๋ ˆ์ž„ ์ƒ์„ฑ"""
689
+ return pd.DataFrame([{
690
+ 'Korean Rank': f"#{s['korean_rank']}",
691
+ 'Global Rank': f"#{s['global_rank']}" if s.get('global_rank') else "N/A",
692
+ 'Author Rank': f"#{s.get('author_rank', '-')}",
693
+ 'Space ID': s['id'],
694
+ 'Title': s.get('title', 'N/A'),
695
+ 'Likes': s['likes'],
696
+ 'URL': s['url']
697
+ } for s in spaces])
698
+
699
+ def create_models_dataframe(models: list) -> pd.DataFrame:
700
+ """๋ชจ๋ธ ๋ฐ์ดํ„ฐํ”„๋ ˆ์ž„ ์ƒ์„ฑ"""
701
+ return pd.DataFrame([{
702
+ 'Korean Rank': f"#{m['korean_rank']}",
703
+ 'Global Rank': f"#{m['global_rank']}" if m.get('global_rank') else "N/A",
704
+ 'Author Rank': f"#{m.get('author_rank', '-')}",
705
+ 'Model ID': m['id'],
706
+ 'Title': m.get('title', 'N/A'),
707
+ 'Downloads': f"{m['downloads']:,}",
708
+ 'Likes': m['likes'],
709
+ 'URL': m['url']
710
+ } for m in models])
711
+
712
  # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
713
+ # ๐ŸŽด HTML ์นด๋“œ ์ƒ์„ฑ
714
  # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
715
 
716
  def generate_space_cards_html(spaces: list) -> str:
717
+ """์ŠคํŽ˜์ด์Šค ์นด๋“œ HTML ์ƒ์„ฑ"""
718
 
719
+ # ์ „์—ญ ์ˆœ์œ„๊ฐ€ ์žˆ๋Š” ๊ฒƒ๊ณผ ์—†๋Š” ๊ฒƒ ๋ถ„๋ฆฌ
720
+ global_ranked = [s for s in spaces if s.get('global_rank')]
721
+ not_ranked = [s for s in spaces if not s.get('global_rank')]
722
 
723
  html = f"""
724
  <div style='padding: 20px; background: #e0e5ec; border-radius: 20px;
725
  box-shadow: inset 4px 4px 8px #b8bec5, inset -4px -4px 8px #ffffff;'>
726
  <h2 style='color: #5a6677; text-shadow: 2px 2px 4px #ffffff, -1px -1px 3px rgba(0,0,0,0.1);
727
  margin-bottom: 20px; font-size: 24px;'>
728
+ ๐Ÿš€ Korean Spaces Leaderboard (Total: {len(spaces)} | Global Ranked: {len(global_ranked)})
729
  </h2>
730
  """
731
 
732
+ # Top Spaces (์ƒ์œ„ 100๊ฐœ๋งŒ ์นด๋“œ๋กœ ํ‘œ์‹œ)
733
+ top_spaces = spaces[:100]
 
 
 
 
 
 
 
 
 
 
 
734
 
735
+ html += f"""
736
+ <h3 style='color: #5a6677; margin: 20px 0 15px 0; font-size: 18px;'>
737
+ ๐Ÿ“Š Top 100 Korean Spaces by Likes
738
+ </h3>
739
+ <div style='display: grid; grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); gap: 20px;'>
740
+ """
 
 
 
 
 
 
 
741
 
742
+ for space in top_spaces:
743
+ html += generate_space_card_html(space)
744
+
745
+ html += "</div></div>"
746
  return html
747
 
748
+ def generate_space_card_html(space: dict) -> str:
749
  """๊ฐœ๋ณ„ ์ŠคํŽ˜์ด์Šค ์นด๋“œ HTML ์ƒ์„ฑ"""
750
  color = get_author_color(space['author'])
751
  avatar_url = get_avatar_url(space['author'])
 
754
  color_hex = color.replace("#", "")
755
  fallback_url = f"https://ui-avatars.com/api/?name={initials}&background={color_hex}&color=fff&size=128&bold=true"
756
 
757
+ # ์ „์—ญ ์ˆœ์œ„ ๋ฐฐ์ง€
758
+ if space.get('global_rank'):
759
+ global_badge = f"""
760
+ <div style='
761
+ background: linear-gradient(135deg, #10b981, #059669);
762
+ border-radius: 12px;
763
+ padding: 8px 12px;
764
+ '>
765
+ <span style='color: white; font-weight: 800; font-size: 14px;'>
766
+ ๐ŸŒ #{space['global_rank']}
767
+ </span>
 
 
 
 
 
 
 
 
 
 
 
 
 
768
  </div>
769
  """
770
  else:
771
+ global_badge = f"""
772
+ <div style='
773
+ background: #e0e5ec;
774
+ border-radius: 12px;
775
+ padding: 8px 12px;
776
+ box-shadow: inset 2px 2px 4px #b8bec5, inset -2px -2px 4px #ffffff;
777
+ '>
778
+ <span style='color: #9ca3af; font-weight: 600; font-size: 12px;'>
779
+ Not in Top 10K
780
+ </span>
 
 
 
 
 
 
 
 
 
 
 
781
  </div>
782
  """
783
 
 
814
  </a>
815
 
816
  <!-- ๋žญํ‚น ๋ฐฐ์ง€ -->
817
+ <div style='display: flex; gap: 8px; flex-wrap: wrap;'>
818
+ <div style='
819
+ background: linear-gradient(135deg, #6366f1, #4f46e5);
820
+ border-radius: 12px;
821
+ padding: 8px 12px;
822
+ '>
823
+ <span style='color: white; font-weight: 800; font-size: 14px;'>
824
+ ๐Ÿ‡ฐ๐Ÿ‡ท #{space['korean_rank']}
825
+ </span>
826
+ </div>
827
+ {global_badge}
828
+ <div style='
829
+ background: {color}22;
830
+ border-radius: 12px;
831
+ padding: 8px 12px;
832
+ border: 2px solid {color};
833
+ '>
834
+ <span style='color: {color}; font-weight: 800; font-size: 14px;'>
835
+ ๐Ÿ‘ค #{space.get('author_rank', '-')}
836
+ </span>
837
+ </div>
838
+ </div>
839
  </div>
840
 
841
  <!-- ์ €์ž ์ด๋ฆ„ -->
 
870
 
871
  <!-- Likes -->
872
  <p style='color: #6d7b8d; margin-bottom: 16px; font-size: 14px;'>
873
+ โค๏ธ Likes: <strong>{space['likes']:,}</strong>
874
  </p>
875
 
876
  <!-- Visit ๋ฒ„ํŠผ -->
 
891
  """
892
 
893
  def generate_model_cards_html(models: list) -> str:
894
+ """๋ชจ๋ธ ์นด๋“œ HTML ์ƒ์„ฑ"""
895
+
896
+ global_ranked = [m for m in models if m.get('global_rank')]
897
+
898
  html = f"""
899
  <div style='padding: 20px; background: #e0e5ec; border-radius: 20px;
900
  box-shadow: inset 4px 4px 8px #b8bec5, inset -4px -4px 8px #ffffff;'>
901
  <h2 style='color: #5a6677; text-shadow: 2px 2px 4px #ffffff, -1px -1px 3px rgba(0,0,0,0.1);
902
  margin-bottom: 20px; font-size: 24px;'>
903
+ ๐Ÿค– Korean Models Leaderboard (Total: {len(models)} | Global Ranked: {len(global_ranked)})
904
  </h2>
905
  <div style='display: grid; grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); gap: 20px;'>
906
  """
907
 
908
+ # ์ƒ์œ„ 100๊ฐœ๋งŒ ํ‘œ์‹œ
909
+ for model in models[:100]:
910
  color = get_author_color(model['author'])
911
  avatar_url = get_avatar_url(model['author'])
912
 
 
914
  color_hex = color.replace("#", "")
915
  fallback_url = f"https://ui-avatars.com/api/?name={initials}&background={color_hex}&color=fff&size=128&bold=true"
916
 
917
+ # ์ „์—ญ ์ˆœ์œ„ ๋ฐฐ์ง€
918
+ if model.get('global_rank'):
919
+ global_badge = f"""
920
+ <div style='
921
+ background: linear-gradient(135deg, #10b981, #059669);
922
+ border-radius: 12px;
923
+ padding: 8px 12px;
924
+ '>
925
+ <span style='color: white; font-weight: 800; font-size: 14px;'>
926
+ ๐ŸŒ #{model['global_rank']}
927
+ </span>
928
+ </div>
929
+ """
930
+ else:
931
+ global_badge = f"""
932
+ <div style='
933
+ background: #e0e5ec;
934
+ border-radius: 12px;
935
+ padding: 8px 12px;
936
+ box-shadow: inset 2px 2px 4px #b8bec5, inset -2px -2px 4px #ffffff;
937
+ '>
938
+ <span style='color: #9ca3af; font-weight: 600; font-size: 12px;'>
939
+ Not in Top 10K
940
+ </span>
941
+ </div>
942
+ """
943
+
944
  html += f"""
945
  <div style='
946
  background: #e0e5ec;
 
950
  transition: all 0.3s ease;
951
  border-left: 4px solid {color};
952
  '>
953
+ <!-- ํ—ค๋” -->
954
  <div style='display: flex; align-items: center; justify-content: space-between; margin-bottom: 16px;'>
 
955
  <a href='https://huggingface.co/{model["author"]}' target='_blank' style='text-decoration: none;'>
956
  <div style='
957
  width: 56px;
 
972
  </div>
973
  </a>
974
 
975
+ <div style='display: flex; gap: 8px; flex-wrap: wrap;'>
 
976
  <div style='
977
+ background: linear-gradient(135deg, #6366f1, #4f46e5);
978
  border-radius: 12px;
979
  padding: 8px 12px;
 
980
  '>
981
+ <span style='color: white; font-weight: 800; font-size: 14px;'>
982
+ ๐Ÿ‡ฐ๐Ÿ‡ท #{model['korean_rank']}
983
  </span>
984
  </div>
985
+ {global_badge}
986
  <div style='
987
  background: {color}22;
988
  border-radius: 12px;
 
996
  </div>
997
  </div>
998
 
 
999
  <a href='https://huggingface.co/{model["author"]}' target='_blank'
1000
  style='text-decoration: none;'>
1001
+ <p style='color: {color}; font-weight: 700; font-size: 14px; margin: 0 0 8px 0;'>
 
 
 
 
 
 
 
 
1002
  ๐Ÿ‘ค {model['author']}
1003
  </p>
1004
  </a>
1005
 
 
1006
  <h3 style='color: #5a6677; margin: 8px 0; font-size: 15px; word-break: break-all;'>
1007
  {model['id']}
1008
  </h3>
1009
 
 
 
 
 
 
 
 
 
 
 
1010
  <p style='color: #6d7b8d; margin-bottom: 8px; font-size: 14px;'>
1011
  โฌ‡๏ธ Downloads: <strong>{model['downloads']:,}</strong>
1012
  </p>
1013
  <p style='color: #6d7b8d; margin-bottom: 16px; font-size: 14px;'>
1014
+ โค๏ธ Likes: <strong>{model['likes']:,}</strong>
1015
  </p>
1016
 
 
1017
  <a href='{model['url']}' target='_blank' style='
1018
  display: inline-block;
1019
  padding: 12px 24px;
 
1023
  border-radius: 50px;
1024
  font-weight: 700;
1025
  box-shadow: 6px 6px 12px #b8bec5, -6px -6px 12px #ffffff;
 
1026
  '>
1027
  Visit Model ๐Ÿ”—
1028
  </a>
 
1036
  # ๐Ÿ“ˆ ํ†ต๊ณ„ ์ฐจํŠธ ์ƒ์„ฑ
1037
  # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
1038
 
1039
+ def create_pie_chart(df: pd.DataFrame, type_name: str = "Spaces"):
1040
+ """ํŒŒ์ด ์ฐจํŠธ ์ƒ์„ฑ - ์ „์—ญ ์ˆœ์œ„ ์œ ๋ฌด"""
1041
  try:
1042
+ if df.empty:
1043
+ return create_error_plot()
1044
+
1045
+ global_col = 'Global Rank'
1046
+ if global_col not in df.columns:
1047
+ return create_error_plot()
1048
 
1049
+ ranked = len(df[df[global_col] != "N/A"])
1050
+ not_ranked = len(df) - ranked
1051
 
1052
  fig = go.Figure(data=[go.Pie(
1053
+ labels=['Global Top 10K', 'Not in Top 10K'],
1054
+ values=[ranked, not_ranked],
1055
  hole=.4,
1056
+ marker_colors=['#10b981', '#9ca3af'],
1057
  textinfo='percent+value',
1058
  textfont=dict(color='#5a6677'),
1059
+ hovertemplate="<b>%{label}</b><br>Count: %{value}<br>%{percent}<extra></extra>"
1060
  )])
1061
 
1062
  fig.update_layout(
1063
  title={
1064
+ 'text': f"๐Ÿ“Š Korean {type_name} Global Ranking Status",
1065
  'font': {'size': 16, 'color': '#5a6677'}
1066
  },
1067
  showlegend=True,
 
1069
  paper_bgcolor='#e0e5ec',
1070
  plot_bgcolor='#e0e5ec',
1071
  font=dict(color='#6d7b8d'),
 
1072
  margin=dict(l=20, r=20, t=50, b=20)
1073
  )
1074
 
 
1087
  if id_col not in df.columns:
1088
  return create_error_plot()
1089
 
1090
+ registrations = df[id_col].apply(lambda x: x.split('/')[0] if '/' in str(x) else str(x)).value_counts().head(20)
1091
 
1092
  colors = [get_author_color(author) for author in registrations.index]
1093
 
 
1102
 
1103
  fig.update_layout(
1104
  title={
1105
+ 'text': f"๐Ÿ‘ฅ Top 20 Creators by {type_name} Count",
1106
  'font': {'size': 16, 'color': '#5a6677'}
1107
  },
1108
  xaxis_title="Creator",
 
1131
  spaces_results = get_spaces_data()
1132
  models_results = get_models_data()
1133
 
1134
+ spaces_pie = create_pie_chart(spaces_results[2], "Spaces")
1135
  spaces_bar = create_bar_chart(spaces_results[2], "Spaces")
1136
 
1137
+ models_pie = create_pie_chart(models_results[2], "Models")
1138
  models_bar = create_bar_chart(models_results[2], "Models")
1139
 
1140
  return [
 
1280
  border-radius: 20px !important;
1281
  overflow: hidden !important;
1282
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1283
  """
1284
 
1285
  def create_org_legend_html():
1286
+ """์กฐ์ง ๋ฒ”๋ก€ HTML ์ƒ์„ฑ"""
1287
 
1288
  categories = {
1289
  "๐Ÿข ๋Œ€๊ธฐ์—…": [
1290
+ {"color": "#03C75A", "name": "NAVER", "authors": ["naver-hyperclovax", "naver-ellm", "naver"]},
1291
+ {"color": "#FFD200", "name": "Kakao", "authors": ["kakaocorp", "kakaobrain"]},
1292
+ {"color": "#1428A0", "name": "Samsung", "authors": ["SamsungResearch"]},
1293
  {"color": "#D70026", "name": "SK Telecom", "authors": ["skt", "skt-ai"]},
1294
+ {"color": "#A50034", "name": "LG AI", "authors": ["LGAI-EXAONE"]},
1295
+ {"color": "#FF6B00", "name": "NCSOFT", "authors": ["NCSOFT"]},
1296
  {"color": "#E11D48", "name": "KRAFTON", "authors": ["KRAFTON"]},
1297
  ],
1298
  "๐Ÿš€ AI ์Šคํƒ€ํŠธ์—…": [
 
1300
  {"color": "#2563EB", "name": "VIDraft", "authors": ["VIDraft"]},
1301
  {"color": "#1D4ED8", "name": "Ginigen", "authors": ["ginigen", "ginipick"]},
1302
  {"color": "#F59E0B", "name": "Trillion Labs", "authors": ["trillionlabs"]},
 
 
 
 
1303
  {"color": "#C026D3", "name": "Nari Labs", "authors": ["nari-labs"]},
 
 
 
1304
  ],
1305
  "๐ŸŽ“ ์—ฐ๊ตฌ๊ธฐ๊ด€": [
1306
+ {"color": "#10B981", "name": "ETRI", "authors": ["etri-vilab", "etri"]},
1307
  {"color": "#14B8A6", "name": "KAIST", "authors": ["kaist-ai", "kaist-nlp"]},
1308
+ {"color": "#06B6D4", "name": "SNU", "authors": ["snunlp"]},
1309
  {"color": "#7C3AED", "name": "NLP AI Lab", "authors": ["nlpai-lab"]},
 
 
 
1310
  ],
1311
  "๐Ÿ‘ฅ ์ปค๋ฎค๋‹ˆํ‹ฐ": [
1312
  {"color": "#3B82F6", "name": "openfree", "authors": ["openfree"]},
 
1319
  {"color": "#EC4899", "name": "cutechicken", "authors": ["cutechicken"]},
1320
  {"color": "#F472B6", "name": "kolaslab", "authors": ["kolaslab"]},
1321
  {"color": "#FB7185", "name": "immunobiotech", "authors": ["immunobiotech"]},
 
 
 
 
1322
  ],
1323
  }
1324
 
 
 
 
 
 
 
 
1325
  html = """
1326
  <details style='background: #e0e5ec; border-radius: 20px;
1327
  box-shadow: 8px 8px 16px #b8bec5, -8px -8px 16px #ffffff; margin: 20px 0;'>
 
1340
  """
1341
  for org in orgs:
1342
  main_author = org["authors"][0]
 
 
 
 
 
 
1343
  html += f"""
1344
  <a href='https://huggingface.co/{main_author}' target='_blank' style='text-decoration: none;'>
1345
  <div style='
 
1354
  font-weight: 600;
1355
  transition: all 0.2s ease;
1356
  cursor: pointer;
1357
+ '>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1358
  <span style='
1359
  width: 10px;
1360
  height: 10px;
1361
  border-radius: 50%;
1362
  background: {org["color"]};
1363
  margin-right: 6px;
 
1364
  '></span>
1365
  {org["name"]}
1366
  </div>
 
1380
  gr.Markdown("""
1381
  # ๐Ÿค— Korean HuggingFace Leaderboard
1382
 
1383
+ **ํ•œ๊ตญ ๊ด€๋ จ HuggingFace Spaces์™€ Models์˜ ์‹ค์‹œ๊ฐ„ ์ธ๊ธฐ ์ˆœ์œ„๋ฅผ ๋ถ„์„ํ•ฉ๋‹ˆ๋‹ค.**
1384
 
1385
+ - ๐Ÿ‡ฐ๐Ÿ‡ท **Korean Rank**: ํ•œ๊ตญ ์ €์ž ๋‚ด ์ˆœ์œ„ (likes/downloads ๊ธฐ์ค€)
1386
+ - ๐ŸŒ **Global Rank**: HuggingFace ์ „์ฒด Top 10,000 ๋‚ด ์ˆœ์œ„
1387
  - ๐Ÿ‘ค **Author Rank**: ํ•ด๋‹น ๊ณ„์ • ๋‚ด ์ˆœ์œ„
 
1388
 
1389
  ยฉ ํ•œ๊ตญ์ธ๊ณต์ง€๋Šฅ์ง„ํฅํ˜‘ํšŒ / ๋ฌธ์˜: arxivgpt@gmail.com
1390
  """)
1391
 
 
1392
  gr.HTML(create_org_legend_html())
1393
 
1394
  refresh_btn = gr.Button("๐Ÿ”„ ์ƒˆ๋กœ ๊ณ ์นจ", variant="primary", elem_classes=["neu-button"])
1395
 
1396
+ with gr.Tab("๐Ÿš€ Spaces Trending"):
1397
+ spaces_plot = gr.Plot(label="Spaces by Likes")
1398
  with gr.Row():
1399
  with gr.Column(scale=1):
1400
+ spaces_pie_chart = gr.Plot(label="Global Ranking Status")
1401
  with gr.Column(scale=2):
1402
  spaces_bar_chart = gr.Plot(label="By Creator")
1403
  spaces_info = gr.HTML()
1404
  spaces_df = gr.DataFrame(
1405
+ headers=["Korean Rank", "Global Rank", "Author Rank", "Space ID", "Title", "Likes", "URL"],
1406
+ datatype=["str", "str", "str", "str", "str", "number", "str"],
1407
  row_count=(10, "dynamic"),
1408
  wrap=True
1409
  )
1410
 
1411
+ with gr.Tab("๐Ÿค– Models Trending"):
1412
+ models_plot = gr.Plot(label="Models by Downloads")
1413
  with gr.Row():
1414
  with gr.Column(scale=1):
1415
+ models_pie_chart = gr.Plot(label="Global Ranking Status")
1416
  with gr.Column(scale=2):
1417
  models_bar_chart = gr.Plot(label="By Creator")
1418
  models_info = gr.HTML()
1419
  models_df = gr.DataFrame(
1420
+ headers=["Korean Rank", "Global Rank", "Author Rank", "Model ID", "Title", "Downloads", "Likes", "URL"],
1421
+ datatype=["str", "str", "str", "str", "str", "str", "number", "str"],
1422
  row_count=(10, "dynamic"),
1423
  wrap=True
1424
  )