openfree commited on
Commit
87488ac
ยท
verified ยท
1 Parent(s): 884b12b

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +274 -213
index.html CHANGED
@@ -3,7 +3,7 @@
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>HuggingFace & Replicate ์‹ค์‹œ๊ฐ„ ํŠธ๋ Œ๋”ฉ/์‹ ๊ทœ ๋ฆฌ์ŠคํŠธ</title>
7
  <style>
8
  * {
9
  box-sizing: border-box;
@@ -13,7 +13,7 @@
13
 
14
  body {
15
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
16
- background: #f5f5f5;
17
  min-height: 100vh;
18
  padding: 20px;
19
  }
@@ -25,95 +25,127 @@
25
 
26
  h1 {
27
  text-align: center;
28
- color: #333;
29
- margin-bottom: 30px;
30
- font-size: 2.5rem;
 
 
31
  }
32
 
33
  .category-tabs {
34
  display: flex;
35
- gap: 10px;
36
- margin-bottom: 20px;
37
  flex-wrap: wrap;
38
  justify-content: center;
39
  }
40
 
41
  .tab-button {
42
- padding: 12px 24px;
43
  border: none;
44
- background: #fff;
45
- color: #666;
46
- border-radius: 8px;
47
  cursor: pointer;
48
- font-size: 1rem;
49
- transition: all 0.3s ease;
50
- box-shadow: 0 2px 5px rgba(0,0,0,0.1);
 
 
51
  }
52
 
53
  .tab-button:hover {
54
- transform: translateY(-2px);
55
- box-shadow: 0 4px 10px rgba(0,0,0,0.15);
56
  }
57
 
58
  .tab-button.active {
59
  background: linear-gradient(135deg, #667eea, #764ba2);
60
  color: white;
 
61
  }
62
 
63
  .content-section {
64
  display: none;
 
65
  }
66
 
67
  .content-section.active {
68
  display: block;
69
  }
70
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
71
  .filter-buttons {
72
  display: flex;
73
- gap: 10px;
74
- margin-bottom: 20px;
75
  justify-content: center;
76
  }
77
 
78
  .filter-btn {
79
- padding: 8px 16px;
80
- border: 1px solid #ddd;
81
- background: white;
82
  color: #666;
83
- border-radius: 20px;
84
  cursor: pointer;
85
- font-size: 0.9rem;
 
86
  transition: all 0.3s ease;
 
 
 
 
 
 
87
  }
88
 
89
  .filter-btn.active {
90
  background: #667eea;
91
  color: white;
92
  border-color: #667eea;
 
93
  }
94
 
95
  .items-grid {
96
  display: grid;
97
- grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
98
- gap: 20px;
99
- margin-top: 20px;
100
  }
101
 
102
  .item-card {
103
- background: white;
104
- border-radius: 12px;
105
- padding: 20px;
106
- padding-top: 30px;
107
- box-shadow: 0 2px 10px rgba(0,0,0,0.08);
108
- transition: all 0.3s ease;
109
  cursor: pointer;
110
  position: relative;
111
  overflow: hidden;
 
 
112
  }
113
 
114
  .item-card:hover {
115
- transform: translateY(-5px);
116
- box-shadow: 0 5px 20px rgba(0,0,0,0.15);
117
  }
118
 
119
  .item-card::before {
@@ -122,26 +154,56 @@
122
  top: 0;
123
  left: 0;
124
  width: 100%;
125
- height: 4px;
126
- background: linear-gradient(90deg, #667eea, #764ba2);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
127
  }
128
 
129
  .item-header {
130
  display: flex;
131
  align-items: start;
132
- gap: 12px;
133
- margin-bottom: 12px;
134
  }
135
 
136
  .item-icon {
137
- width: 40px;
138
- height: 40px;
139
- background: #f0f0f0;
140
- border-radius: 8px;
141
  display: flex;
142
  align-items: center;
143
  justify-content: center;
144
- font-size: 1.5rem;
 
145
  }
146
 
147
  .item-info {
@@ -149,48 +211,71 @@
149
  }
150
 
151
  .item-title {
152
- font-weight: 600;
153
- color: #333;
154
- margin-bottom: 4px;
155
- font-size: 1.1rem;
156
  overflow: hidden;
157
  text-overflow: ellipsis;
158
  white-space: nowrap;
159
  }
160
 
161
  .item-author {
162
- color: #666;
163
- font-size: 0.9rem;
 
164
  }
165
 
166
  .item-stats {
167
  display: flex;
168
- gap: 15px;
169
- margin-top: 12px;
170
- font-size: 0.85rem;
171
  color: #666;
 
172
  }
173
 
174
  .stat {
175
  display: flex;
176
  align-items: center;
177
- gap: 5px;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
178
  }
179
 
180
  .loading {
181
  text-align: center;
182
- padding: 40px;
183
  color: #666;
184
  }
185
 
186
  .loading-spinner {
187
  display: inline-block;
188
- width: 40px;
189
- height: 40px;
190
- border: 4px solid #f3f3f3;
191
  border-top: 4px solid #667eea;
192
  border-radius: 50%;
193
  animation: spin 1s linear infinite;
 
194
  }
195
 
196
  @keyframes spin {
@@ -198,61 +283,50 @@
198
  100% { transform: rotate(360deg); }
199
  }
200
 
201
- .error {
202
- background: #fee;
203
- color: #c33;
204
- padding: 20px;
205
- border-radius: 8px;
206
- text-align: center;
207
- margin: 20px 0;
208
- }
209
-
210
  .refresh-btn {
211
  position: fixed;
212
- bottom: 30px;
213
- right: 30px;
214
- width: 60px;
215
- height: 60px;
216
  background: linear-gradient(135deg, #667eea, #764ba2);
217
  color: white;
218
  border: none;
219
  border-radius: 50%;
220
  cursor: pointer;
221
- font-size: 1.5rem;
222
- box-shadow: 0 4px 15px rgba(0,0,0,0.2);
223
- transition: all 0.3s ease;
224
  z-index: 100;
 
 
 
225
  }
226
 
227
  .refresh-btn:hover {
228
- transform: scale(1.1);
229
- box-shadow: 0 6px 20px rgba(0,0,0,0.3);
230
  }
231
 
232
- .note {
233
- background: #fef3c7;
234
- border: 1px solid #fbbf24;
235
- border-radius: 8px;
236
- padding: 15px;
237
- margin: 20px 0;
238
- color: #92400e;
239
- text-align: center;
240
- }
241
-
242
- @media (max-width: 600px) {
243
  .items-grid {
244
  grid-template-columns: 1fr;
245
  }
246
 
247
  h1 {
248
- font-size: 1.8rem;
 
 
 
 
 
249
  }
250
  }
251
  </style>
252
  </head>
253
  <body>
254
  <div class="container">
255
- <h1>๐Ÿš€ AI ๋ชจ๋ธ ํŠธ๋ Œ๋”ฉ ๋ฆฌ์ŠคํŠธ</h1>
256
 
257
  <div class="category-tabs">
258
  <button class="tab-button active" onclick="showCategory('hf-models')">
@@ -268,26 +342,26 @@
268
 
269
  <!-- HuggingFace Models Section -->
270
  <div id="hf-models" class="content-section active">
271
- <div style="text-align: center; margin-bottom: 20px;">
272
- <h2 style="color: #667eea;">๐Ÿ“ˆ Trending Models</h2>
273
  </div>
274
  <div id="hf-models-content" class="items-grid">
275
  <div class="loading">
276
  <div class="loading-spinner"></div>
277
- <p>๋ชจ๋ธ ๋กœ๋”ฉ ์ค‘...</p>
278
  </div>
279
  </div>
280
  </div>
281
 
282
  <!-- HuggingFace Spaces Section -->
283
  <div id="hf-spaces" class="content-section">
284
- <div style="text-align: center; margin-bottom: 20px;">
285
- <h2 style="color: #667eea;">๐Ÿ“ˆ Trending Spaces</h2>
286
  </div>
287
  <div id="hf-spaces-content" class="items-grid">
288
  <div class="loading">
289
  <div class="loading-spinner"></div>
290
- <p>์ŠคํŽ˜์ด์Šค ๋กœ๋”ฉ ์ค‘...</p>
291
  </div>
292
  </div>
293
  </div>
@@ -295,32 +369,13 @@
295
  <!-- Replicate Section -->
296
  <div id="replicate" class="content-section">
297
  <div class="filter-buttons">
298
- <button class="filter-btn active" onclick="loadReplicate('featured')">โญ Featured Models</button>
299
- <button class="filter-btn" onclick="loadReplicate('official')">โœ… Official Models</button>
300
  </div>
301
  <div id="replicate-content" class="items-grid">
302
  <div class="loading">
303
  <div class="loading-spinner"></div>
304
- <p>๋ชจ๋ธ ๋กœ๋”ฉ ์ค‘...</p>
305
- </div>
306
- </div>
307
- </div>
308
-
309
- <div class="note">
310
- โš ๏ธ <strong>API ์‚ฌ์šฉ ์•ˆ๋‚ด:</strong><br>
311
- โ€ข HuggingFace API๋Š” `likes7d`๋กœ 7์ผ๊ฐ„ ํŠธ๋ Œ๋”ฉ์„ ์ •ํ™•ํžˆ ์ถ”์ถœํ•ฉ๋‹ˆ๋‹ค<br>
312
- โ€ข CORS ์—๋Ÿฌ ๋ฐœ์ƒ ์‹œ ํ”„๋ก์‹œ ์„œ๋ฒ„ ์‚ฌ์šฉ์„ ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค<br>
313
- โ€ข Replicate์˜ Featured/Official ๋ชจ๋ธ์€ ๊ณต์‹ ์›น์‚ฌ์ดํŠธ์—์„œ ํ™•์ธ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค
314
- </div>
315
-
316
- <!-- API URLs Info -->
317
- <div style="margin-top: 30px; background: #f8f9fa; padding: 20px; border-radius: 10px;">
318
- <h3 style="margin-bottom: 15px; color: #333;">๐Ÿ“Œ API Endpoints</h3>
319
- <div style="display: grid; gap: 10px; font-size: 0.9rem;">
320
- <div><strong>HF Models (Trending):</strong> <code style="background: #e9ecef; padding: 2px 6px; border-radius: 4px;">https://huggingface.co/api/models?sort=likes7d&direction=-1&limit=30</code></div>
321
- <div><strong>HF Spaces (Trending):</strong> <code style="background: #e9ecef; padding: 2px 6px; border-radius: 4px;">https://huggingface.co/api/spaces?sort=likes7d&direction=-1&limit=30</code></div>
322
- <div style="margin-top: 10px; color: #666;">
323
- <strong>Note:</strong> Replicate Featured/Official ๋ชจ๋ธ์€ ์›น ํŽ˜์ด์ง€ ์Šคํฌ๋ž˜ํ•‘์ด๋‚˜ ์ธ์ฆ๋œ API ์•ก์„ธ์Šค๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.
324
  </div>
325
  </div>
326
  </div>
@@ -335,19 +390,16 @@
335
  function showCategory(category) {
336
  currentCategory = category;
337
 
338
- // ํƒญ ํ™œ์„ฑํ™”
339
  document.querySelectorAll('.tab-button').forEach(btn => {
340
  btn.classList.remove('active');
341
  });
342
  event.target.classList.add('active');
343
 
344
- // ์„น์…˜ ํ‘œ์‹œ
345
  document.querySelectorAll('.content-section').forEach(section => {
346
  section.classList.remove('active');
347
  });
348
  document.getElementById(category).classList.add('active');
349
 
350
- // ๋ฐ์ดํ„ฐ ๋กœ๋“œ
351
  if (category === 'hf-models') {
352
  loadHFModels();
353
  } else if (category === 'hf-spaces') {
@@ -360,29 +412,13 @@
360
  // HuggingFace Models ๋กœ๋“œ
361
  async function loadHFModels() {
362
  const container = document.getElementById('hf-models-content');
363
- container.innerHTML = '<div class="loading"><div class="loading-spinner"></div><p>๋ชจ๋ธ ๋กœ๋”ฉ ์ค‘...</p></div>';
364
 
365
  try {
366
- // HuggingFace API ์‚ฌ์šฉ - trending (7์ผ๊ฐ„ ์ข‹์•„์š” ๊ธฐ์ค€)
367
- const apiUrl = 'https://huggingface.co/api/models?sort=likes7d&direction=-1&limit=30';
368
-
369
- console.log(`๐Ÿ“ก API ํ˜ธ์ถœ ์ค‘: ${apiUrl}`);
370
- const response = await fetch(apiUrl, {
371
- method: 'GET',
372
- headers: {
373
- 'Accept': 'application/json',
374
- }
375
- });
376
-
377
- if (!response.ok) throw new Error('API ์š”์ฒญ ์‹คํŒจ');
378
-
379
  const data = await response.json();
380
- console.log(`โœ… ${data.length}๊ฐœ์˜ ๋ชจ๋ธ ๋กœ๋“œ ์™„๋ฃŒ`);
381
  displayHFModels(data, container);
382
  } catch (error) {
383
- console.error('โŒ API ์—๋Ÿฌ:', error);
384
- console.log('๐Ÿ”„ ํ”„๋ก์‹œ ์„œ๋ฒ„๋ฅผ ํ†ตํ•œ ์š”์ฒญ์„ ์‹œ๋„ํ•ฉ๋‹ˆ๋‹ค...');
385
- // CORS ์—๋Ÿฌ ์‹œ ํ”„๋ก์‹œ ์‚ฌ์šฉ ์‹œ๋„
386
  tryProxyRequest('models', container);
387
  }
388
  }
@@ -390,61 +426,93 @@
390
  // HuggingFace Spaces ๋กœ๋“œ
391
  async function loadHFSpaces() {
392
  const container = document.getElementById('hf-spaces-content');
393
- container.innerHTML = '<div class="loading"><div class="loading-spinner"></div><p>์ŠคํŽ˜์ด์Šค ๋กœ๋”ฉ ์ค‘...</p></div>';
394
 
395
  try {
396
- // HuggingFace API ์‚ฌ์šฉ - trending (7์ผ๊ฐ„ ์ข‹์•„์š” ๊ธฐ์ค€)
397
- const apiUrl = 'https://huggingface.co/api/spaces?sort=likes7d&direction=-1&limit=30';
398
-
399
- console.log(`๐Ÿ“ก API ํ˜ธ์ถœ ์ค‘: ${apiUrl}`);
400
- const response = await fetch(apiUrl, {
401
- method: 'GET',
402
- headers: {
403
- 'Accept': 'application/json',
404
- }
405
- });
406
-
407
- if (!response.ok) throw new Error('API ์š”์ฒญ ์‹คํŒจ');
408
-
409
  const data = await response.json();
410
- console.log(`โœ… ${data.length}๊ฐœ์˜ ์ŠคํŽ˜์ด์Šค ๋กœ๋“œ ์™„๋ฃŒ`);
411
  displayHFSpaces(data, container);
412
  } catch (error) {
413
- console.error('โŒ API ์—๋Ÿฌ:', error);
414
- console.log('๐Ÿ”„ ํ”„๋ก์‹œ ์„œ๋ฒ„๋ฅผ ํ†ตํ•œ ์š”์ฒญ์„ ์‹œ๋„ํ•ฉ๋‹ˆ๋‹ค...');
415
- // CORS ์—๋Ÿฌ ์‹œ ํ”„๋ก์‹œ ์‚ฌ์šฉ ์‹œ๋„
416
  tryProxyRequest('spaces', container);
417
  }
418
  }
419
 
420
- // ํ”„๋ก์‹œ๋ฅผ ํ†ตํ•œ ์š”์ฒญ ์‹œ๋„
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
421
  async function tryProxyRequest(type, container) {
422
  try {
423
- console.log('๐Ÿ”„ ํ”„๋ก์‹œ๋ฅผ ํ†ตํ•œ ์š”์ฒญ ์‹œ๋„ ์ค‘...');
424
- // ๊ณต๊ฐœ CORS ํ”„๋ก์‹œ ์‚ฌ์šฉ (์˜ˆ: cors-anywhere)
425
  const proxyUrl = 'https://api.allorigins.win/raw?url=';
426
- let targetUrl;
427
-
428
- if (type === 'models') {
429
- targetUrl = 'https://huggingface.co/api/models?sort=likes7d&direction=-1&limit=30';
430
- } else {
431
- targetUrl = 'https://huggingface.co/api/spaces?sort=likes7d&direction=-1&limit=30';
432
- }
433
 
434
- console.log(`๐Ÿ“ก ํ”„๋ก์‹œ URL: ${proxyUrl + encodeURIComponent(targetUrl)}`);
435
  const response = await fetch(proxyUrl + encodeURIComponent(targetUrl));
436
  const data = await response.json();
437
 
438
- console.log(`โœ… ํ”„๋ก์‹œ๋ฅผ ํ†ตํ•ด ${data.length}๊ฐœ์˜ ๋ฐ์ดํ„ฐ ๋กœ๋“œ ์™„๋ฃŒ`);
439
  if (type === 'models') {
440
  displayHFModels(data, container);
441
  } else {
442
  displayHFSpaces(data, container);
443
  }
444
  } catch (error) {
445
- console.error('โŒ ํ”„๋ก์‹œ ์š”์ฒญ๋„ ์‹คํŒจ:', error);
446
- console.log('๐Ÿ“Œ ์ƒ˜ํ”Œ ๋ฐ์ดํ„ฐ๋ฅผ ํ‘œ์‹œํ•ฉ๋‹ˆ๋‹ค.');
447
- // ๋ชจ๋“  ์‹œ๋„ ์‹คํŒจ ์‹œ ์ƒ˜ํ”Œ ๋ฐ์ดํ„ฐ ํ‘œ์‹œ
448
  if (type === 'models') {
449
  displaySampleHFModels(container);
450
  } else {
@@ -453,29 +521,6 @@
453
  }
454
  }
455
 
456
- // Replicate ๋ชจ๋ธ ๋กœ๋“œ
457
- async function loadReplicate(type) {
458
- const currentType = type || 'featured';
459
-
460
- // ํ•„ํ„ฐ ๋ฒ„ํŠผ ํ™œ์„ฑํ™”
461
- document.querySelectorAll('#replicate .filter-btn').forEach(btn => {
462
- btn.classList.remove('active');
463
- });
464
- if (event && event.target) {
465
- event.target.classList.add('active');
466
- } else {
467
- document.querySelector('#replicate .filter-btn').classList.add('active');
468
- }
469
-
470
- console.log(`๐Ÿš€ Replicate ${currentType} ๋ชจ๋ธ ๋กœ๋“œ ์‹œ์ž‘`);
471
- const container = document.getElementById('replicate-content');
472
- container.innerHTML = '<div class="loading"><div class="loading-spinner"></div><p>๋ชจ๋ธ ๋กœ๋”ฉ ์ค‘...</p></div>';
473
-
474
- // Replicate๋Š” ๊ณต๊ฐœ API๊ฐ€ ์ œํ•œ์ ์ด๋ฏ€๋กœ ์ƒ˜ํ”Œ ๋ฐ์ดํ„ฐ ํ‘œ์‹œ
475
- console.log(`โ„น๏ธ Replicate ${currentType} ๋ชจ๋ธ ์ƒ˜ํ”Œ ๋ฐ์ดํ„ฐ๋ฅผ ํ‘œ์‹œํ•ฉ๋‹ˆ๋‹ค.`);
476
- displaySampleReplicateModels(container, currentType);
477
- }
478
-
479
  // HuggingFace Models ํ‘œ์‹œ
480
  function displayHFModels(models, container) {
481
  container.innerHTML = '';
@@ -489,8 +534,7 @@
489
  tags: model.tags || [],
490
  pipeline_tag: model.pipeline_tag || '',
491
  url: `https://huggingface.co/${model.id || model.modelId}`,
492
- icon: '๐Ÿค–',
493
- updated: model.lastModified || model.created_at
494
  });
495
  container.appendChild(card);
496
  });
@@ -509,8 +553,24 @@
509
  emoji: space.emoji || '๐ŸŽฏ',
510
  url: `https://huggingface.co/spaces/${space.id}`,
511
  icon: space.emoji || '๐ŸŽฏ',
512
- hardware: space.hardware || 'CPU',
513
- updated: space.lastModified || space.created_at
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
514
  });
515
  container.appendChild(card);
516
  });
@@ -522,7 +582,6 @@
522
  card.className = 'item-card';
523
  card.onclick = () => window.open(data.url, '_blank');
524
 
525
- // ์ˆœ์œ„์— ๋”ฐ๋ฅธ ์ƒ‰์ƒ
526
  let rankColor = '#999';
527
  if (data.rank === 1) rankColor = '#FFD700';
528
  else if (data.rank === 2) rankColor = '#C0C0C0';
@@ -530,15 +589,15 @@
530
  else if (data.rank <= 10) rankColor = '#667eea';
531
 
532
  card.innerHTML = `
533
- <div class="rank-badge" style="position: absolute; top: 10px; right: 10px; background: ${rankColor}; color: white; width: 30px; height: 30px; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-weight: bold; font-size: 0.9rem;">
534
  ${data.rank}
535
  </div>
536
- ${data.badge ? `<div style="position: absolute; top: 10px; left: 10px; background: rgba(0,0,0,0.7); color: white; padding: 4px 8px; border-radius: 4px; font-size: 0.75rem;">${data.badge}</div>` : ''}
537
  <div class="item-header">
538
  <div class="item-icon">${data.icon}</div>
539
  <div class="item-info">
540
  <div class="item-title">${data.title}</div>
541
- <div class="item-author">by ${data.author}</div>
542
  </div>
543
  </div>
544
  <div class="item-stats">
@@ -547,11 +606,11 @@
547
  ${data.sdk ? `<div class="stat">๐Ÿ› ๏ธ ${data.sdk}</div>` : ''}
548
  ${data.hardware ? `<div class="stat">๐Ÿ’ป ${data.hardware}</div>` : ''}
549
  ${data.pipeline_tag ? `<div class="stat">๐Ÿท๏ธ ${data.pipeline_tag}</div>` : ''}
550
- ${data.runs !== undefined ? `<div class="stat">โ–ถ๏ธ ${formatNumber(data.runs)}</div>` : ''}
551
  </div>
552
  ${data.tags && data.tags.length > 0 ? `
553
- <div style="margin-top: 10px; display: flex; flex-wrap: wrap; gap: 5px;">
554
- ${data.tags.slice(0, 3).map(tag => `<span style="background: #f0f0f0; padding: 2px 8px; border-radius: 12px; font-size: 0.75rem; color: #666;">${tag}</span>`).join('')}
555
  </div>
556
  ` : ''}
557
  `;
@@ -566,9 +625,19 @@
566
  return num.toString();
567
  }
568
 
 
 
 
 
 
 
 
 
 
 
 
569
  // ์ƒ˜ํ”Œ ๋ฐ์ดํ„ฐ ํ‘œ์‹œ ํ•จ์ˆ˜๋“ค
570
  function displaySampleHFModels(container) {
571
- console.log(`๐Ÿ“Œ ํŠธ๋ Œ๋”ฉ ๋ชจ๋ธ ์ƒ˜ํ”Œ ๋ฐ์ดํ„ฐ๋ฅผ ํ‘œ์‹œํ•ฉ๋‹ˆ๋‹ค.`);
572
  const sampleData = [
573
  { rank: 1, title: 'Llama-3.3-70B-Instruct', author: 'meta-llama', likes: 177000, downloads: 1150000, icon: '๐Ÿค–', pipeline_tag: 'text-generation', tags: ['llama', '70b', 'instruct'] },
574
  { rank: 2, title: 'DeepSeek-R1-Distill-Qwen-32B', author: 'deepseek-ai', likes: 10400, downloads: 567000, icon: '๐Ÿค–', pipeline_tag: 'text-generation', tags: ['deepseek', 'reasoning'] },
@@ -590,7 +659,6 @@
590
  }
591
 
592
  function displaySampleHFSpaces(container) {
593
- console.log(`๐Ÿ“Œ ํŠธ๋ Œ๋”ฉ ์ŠคํŽ˜์ด์Šค ์ƒ˜ํ”Œ ๋ฐ์ดํ„ฐ๋ฅผ ํ‘œ์‹œํ•ฉ๋‹ˆ๋‹ค.`);
594
  const sampleData = [
595
  { rank: 1, title: 'stable-diffusion-webui', author: 'stabilityai', likes: 75500, sdk: 'Gradio', icon: '๐ŸŽจ', hardware: 'T4 GPU' },
596
  { rank: 2, title: 'chatgpt-clone', author: 'community', likes: 12300, sdk: 'Streamlit', icon: '๐Ÿ’ฌ', hardware: 'CPU' },
@@ -612,8 +680,6 @@
612
  }
613
 
614
  function displaySampleReplicateModels(container, type) {
615
- console.log(`๐Ÿ“Œ Replicate ${type} ๋ชจ๋ธ ์ƒ˜ํ”Œ ๋ฐ์ดํ„ฐ๋ฅผ ํ‘œ์‹œํ•ฉ๋‹ˆ๋‹ค.`);
616
-
617
  const featuredData = [
618
  { rank: 1, title: 'flux-1.1-pro', author: 'black-forest-labs', runs: 2910000, icon: '๐ŸŽจ', badge: 'โญ Featured' },
619
  { rank: 2, title: 'llama-3.3-70b-versatile', author: 'meta', runs: 1850000, icon: '๐Ÿค–', badge: 'โญ Featured' },
@@ -660,11 +726,6 @@
660
 
661
  // ์ดˆ๊ธฐ ๋กœ๋“œ
662
  window.addEventListener('DOMContentLoaded', () => {
663
- console.log('๐Ÿš€ HuggingFace & Replicate ํŠธ๋ Œ๋”ฉ ๋ฆฌ์ŠคํŠธ ๋กœ๋“œ ์‹œ์ž‘');
664
- console.log('๐Ÿ“Œ API Endpoints:');
665
- console.log('- HF Models (Trending): https://huggingface.co/api/models?sort=likes7d&direction=-1&limit=30');
666
- console.log('- HF Spaces (Trending): https://huggingface.co/api/spaces?sort=likes7d&direction=-1&limit=30');
667
-
668
  loadHFModels();
669
  });
670
  </script>
 
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>AI Models Trending Dashboard</title>
7
  <style>
8
  * {
9
  box-sizing: border-box;
 
13
 
14
  body {
15
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
16
+ background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
17
  min-height: 100vh;
18
  padding: 20px;
19
  }
 
25
 
26
  h1 {
27
  text-align: center;
28
+ color: #2c3e50;
29
+ margin-bottom: 40px;
30
+ font-size: 3rem;
31
+ text-shadow: 2px 2px 4px rgba(0,0,0,0.1);
32
+ letter-spacing: -0.5px;
33
  }
34
 
35
  .category-tabs {
36
  display: flex;
37
+ gap: 15px;
38
+ margin-bottom: 30px;
39
  flex-wrap: wrap;
40
  justify-content: center;
41
  }
42
 
43
  .tab-button {
44
+ padding: 15px 35px;
45
  border: none;
46
+ background: rgba(255, 255, 255, 0.9);
47
+ color: #555;
48
+ border-radius: 30px;
49
  cursor: pointer;
50
+ font-size: 1.1rem;
51
+ font-weight: 500;
52
+ transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
53
+ box-shadow: 0 4px 15px rgba(0,0,0,0.1);
54
+ backdrop-filter: blur(10px);
55
  }
56
 
57
  .tab-button:hover {
58
+ transform: translateY(-3px) scale(1.05);
59
+ box-shadow: 0 8px 25px rgba(0,0,0,0.15);
60
  }
61
 
62
  .tab-button.active {
63
  background: linear-gradient(135deg, #667eea, #764ba2);
64
  color: white;
65
+ transform: scale(1.05);
66
  }
67
 
68
  .content-section {
69
  display: none;
70
+ animation: fadeIn 0.5s ease-out;
71
  }
72
 
73
  .content-section.active {
74
  display: block;
75
  }
76
 
77
+ @keyframes fadeIn {
78
+ from { opacity: 0; transform: translateY(20px); }
79
+ to { opacity: 1; transform: translateY(0); }
80
+ }
81
+
82
+ .section-header {
83
+ text-align: center;
84
+ margin-bottom: 30px;
85
+ }
86
+
87
+ .section-header h2 {
88
+ color: #667eea;
89
+ font-size: 2rem;
90
+ margin-bottom: 10px;
91
+ }
92
+
93
  .filter-buttons {
94
  display: flex;
95
+ gap: 15px;
96
+ margin-bottom: 30px;
97
  justify-content: center;
98
  }
99
 
100
  .filter-btn {
101
+ padding: 10px 25px;
102
+ border: 2px solid #e0e0e0;
103
+ background: rgba(255, 255, 255, 0.8);
104
  color: #666;
105
+ border-radius: 25px;
106
  cursor: pointer;
107
+ font-size: 1rem;
108
+ font-weight: 500;
109
  transition: all 0.3s ease;
110
+ backdrop-filter: blur(5px);
111
+ }
112
+
113
+ .filter-btn:hover {
114
+ border-color: #667eea;
115
+ transform: translateY(-2px);
116
  }
117
 
118
  .filter-btn.active {
119
  background: #667eea;
120
  color: white;
121
  border-color: #667eea;
122
+ box-shadow: 0 4px 15px rgba(102, 126, 234, 0.3);
123
  }
124
 
125
  .items-grid {
126
  display: grid;
127
+ grid-template-columns: repeat(auto-fill, minmax(340px, 1fr));
128
+ gap: 25px;
129
+ margin-top: 30px;
130
  }
131
 
132
  .item-card {
133
+ background: rgba(255, 255, 255, 0.95);
134
+ border-radius: 20px;
135
+ padding: 25px;
136
+ padding-top: 35px;
137
+ box-shadow: 0 5px 20px rgba(0,0,0,0.08);
138
+ transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
139
  cursor: pointer;
140
  position: relative;
141
  overflow: hidden;
142
+ backdrop-filter: blur(10px);
143
+ border: 1px solid rgba(255, 255, 255, 0.8);
144
  }
145
 
146
  .item-card:hover {
147
+ transform: translateY(-10px) scale(1.02);
148
+ box-shadow: 0 15px 40px rgba(0,0,0,0.15);
149
  }
150
 
151
  .item-card::before {
 
154
  top: 0;
155
  left: 0;
156
  width: 100%;
157
+ height: 5px;
158
+ background: linear-gradient(90deg, #667eea, #764ba2, #f093fb);
159
+ opacity: 0.9;
160
+ }
161
+
162
+ .rank-badge {
163
+ position: absolute;
164
+ top: 15px;
165
+ right: 15px;
166
+ width: 40px;
167
+ height: 40px;
168
+ border-radius: 50%;
169
+ display: flex;
170
+ align-items: center;
171
+ justify-content: center;
172
+ font-weight: bold;
173
+ font-size: 1.1rem;
174
+ color: white;
175
+ box-shadow: 0 3px 10px rgba(0,0,0,0.2);
176
+ }
177
+
178
+ .badge-label {
179
+ position: absolute;
180
+ top: 15px;
181
+ left: 15px;
182
+ background: rgba(0,0,0,0.8);
183
+ color: white;
184
+ padding: 5px 12px;
185
+ border-radius: 20px;
186
+ font-size: 0.8rem;
187
+ font-weight: 500;
188
  }
189
 
190
  .item-header {
191
  display: flex;
192
  align-items: start;
193
+ gap: 15px;
194
+ margin-bottom: 15px;
195
  }
196
 
197
  .item-icon {
198
+ width: 50px;
199
+ height: 50px;
200
+ background: linear-gradient(135deg, #f5f7fa, #c3cfe2);
201
+ border-radius: 15px;
202
  display: flex;
203
  align-items: center;
204
  justify-content: center;
205
+ font-size: 1.8rem;
206
+ box-shadow: 0 3px 10px rgba(0,0,0,0.1);
207
  }
208
 
209
  .item-info {
 
211
  }
212
 
213
  .item-title {
214
+ font-weight: 700;
215
+ color: #2c3e50;
216
+ margin-bottom: 5px;
217
+ font-size: 1.2rem;
218
  overflow: hidden;
219
  text-overflow: ellipsis;
220
  white-space: nowrap;
221
  }
222
 
223
  .item-author {
224
+ color: #7f8c8d;
225
+ font-size: 0.95rem;
226
+ font-weight: 500;
227
  }
228
 
229
  .item-stats {
230
  display: flex;
231
+ gap: 20px;
232
+ margin-top: 15px;
233
+ font-size: 0.9rem;
234
  color: #666;
235
+ flex-wrap: wrap;
236
  }
237
 
238
  .stat {
239
  display: flex;
240
  align-items: center;
241
+ gap: 6px;
242
+ background: rgba(102, 126, 234, 0.1);
243
+ padding: 5px 12px;
244
+ border-radius: 15px;
245
+ font-weight: 500;
246
+ }
247
+
248
+ .tags-container {
249
+ margin-top: 12px;
250
+ display: flex;
251
+ flex-wrap: wrap;
252
+ gap: 6px;
253
+ }
254
+
255
+ .tag {
256
+ background: linear-gradient(135deg, #e0e7ff, #f0f4ff);
257
+ padding: 4px 12px;
258
+ border-radius: 15px;
259
+ font-size: 0.8rem;
260
+ color: #667eea;
261
+ font-weight: 500;
262
  }
263
 
264
  .loading {
265
  text-align: center;
266
+ padding: 60px;
267
  color: #666;
268
  }
269
 
270
  .loading-spinner {
271
  display: inline-block;
272
+ width: 50px;
273
+ height: 50px;
274
+ border: 4px solid rgba(102, 126, 234, 0.2);
275
  border-top: 4px solid #667eea;
276
  border-radius: 50%;
277
  animation: spin 1s linear infinite;
278
+ margin-bottom: 20px;
279
  }
280
 
281
  @keyframes spin {
 
283
  100% { transform: rotate(360deg); }
284
  }
285
 
 
 
 
 
 
 
 
 
 
286
  .refresh-btn {
287
  position: fixed;
288
+ bottom: 40px;
289
+ right: 40px;
290
+ width: 70px;
291
+ height: 70px;
292
  background: linear-gradient(135deg, #667eea, #764ba2);
293
  color: white;
294
  border: none;
295
  border-radius: 50%;
296
  cursor: pointer;
297
+ font-size: 1.8rem;
298
+ box-shadow: 0 5px 20px rgba(102, 126, 234, 0.4);
299
+ transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
300
  z-index: 100;
301
+ display: flex;
302
+ align-items: center;
303
+ justify-content: center;
304
  }
305
 
306
  .refresh-btn:hover {
307
+ transform: scale(1.1) rotate(180deg);
308
+ box-shadow: 0 8px 30px rgba(102, 126, 234, 0.5);
309
  }
310
 
311
+ @media (max-width: 768px) {
 
 
 
 
 
 
 
 
 
 
312
  .items-grid {
313
  grid-template-columns: 1fr;
314
  }
315
 
316
  h1 {
317
+ font-size: 2rem;
318
+ }
319
+
320
+ .tab-button {
321
+ padding: 12px 25px;
322
+ font-size: 1rem;
323
  }
324
  }
325
  </style>
326
  </head>
327
  <body>
328
  <div class="container">
329
+ <h1>๐Ÿš€ AI Models Trending Dashboard</h1>
330
 
331
  <div class="category-tabs">
332
  <button class="tab-button active" onclick="showCategory('hf-models')">
 
342
 
343
  <!-- HuggingFace Models Section -->
344
  <div id="hf-models" class="content-section active">
345
+ <div class="section-header">
346
+ <h2>๐Ÿ“ˆ Trending Models</h2>
347
  </div>
348
  <div id="hf-models-content" class="items-grid">
349
  <div class="loading">
350
  <div class="loading-spinner"></div>
351
+ <p>Loading trending models...</p>
352
  </div>
353
  </div>
354
  </div>
355
 
356
  <!-- HuggingFace Spaces Section -->
357
  <div id="hf-spaces" class="content-section">
358
+ <div class="section-header">
359
+ <h2>๐ŸŽฏ Trending Spaces</h2>
360
  </div>
361
  <div id="hf-spaces-content" class="items-grid">
362
  <div class="loading">
363
  <div class="loading-spinner"></div>
364
+ <p>Loading trending spaces...</p>
365
  </div>
366
  </div>
367
  </div>
 
369
  <!-- Replicate Section -->
370
  <div id="replicate" class="content-section">
371
  <div class="filter-buttons">
372
+ <button class="filter-btn active" onclick="loadReplicate('featured')">โญ Featured</button>
373
+ <button class="filter-btn" onclick="loadReplicate('official')">โœ… Official</button>
374
  </div>
375
  <div id="replicate-content" class="items-grid">
376
  <div class="loading">
377
  <div class="loading-spinner"></div>
378
+ <p>Loading models...</p>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
379
  </div>
380
  </div>
381
  </div>
 
390
  function showCategory(category) {
391
  currentCategory = category;
392
 
 
393
  document.querySelectorAll('.tab-button').forEach(btn => {
394
  btn.classList.remove('active');
395
  });
396
  event.target.classList.add('active');
397
 
 
398
  document.querySelectorAll('.content-section').forEach(section => {
399
  section.classList.remove('active');
400
  });
401
  document.getElementById(category).classList.add('active');
402
 
 
403
  if (category === 'hf-models') {
404
  loadHFModels();
405
  } else if (category === 'hf-spaces') {
 
412
  // HuggingFace Models ๋กœ๋“œ
413
  async function loadHFModels() {
414
  const container = document.getElementById('hf-models-content');
415
+ container.innerHTML = '<div class="loading"><div class="loading-spinner"></div><p>Loading trending models...</p></div>';
416
 
417
  try {
418
+ const response = await fetch('https://huggingface.co/api/models?sort=likes7d&direction=-1&limit=30');
 
 
 
 
 
 
 
 
 
 
 
 
419
  const data = await response.json();
 
420
  displayHFModels(data, container);
421
  } catch (error) {
 
 
 
422
  tryProxyRequest('models', container);
423
  }
424
  }
 
426
  // HuggingFace Spaces ๋กœ๋“œ
427
  async function loadHFSpaces() {
428
  const container = document.getElementById('hf-spaces-content');
429
+ container.innerHTML = '<div class="loading"><div class="loading-spinner"></div><p>Loading trending spaces...</p></div>';
430
 
431
  try {
432
+ const response = await fetch('https://huggingface.co/api/spaces?sort=likes7d&direction=-1&limit=30');
 
 
 
 
 
 
 
 
 
 
 
 
433
  const data = await response.json();
 
434
  displayHFSpaces(data, container);
435
  } catch (error) {
 
 
 
436
  tryProxyRequest('spaces', container);
437
  }
438
  }
439
 
440
+ // Replicate ๋ชจ๋ธ ๋กœ๋“œ
441
+ async function loadReplicate(type) {
442
+ const currentType = type || 'featured';
443
+
444
+ document.querySelectorAll('#replicate .filter-btn').forEach(btn => {
445
+ btn.classList.remove('active');
446
+ });
447
+ if (event && event.target) {
448
+ event.target.classList.add('active');
449
+ } else {
450
+ document.querySelector('#replicate .filter-btn').classList.add('active');
451
+ }
452
+
453
+ const container = document.getElementById('replicate-content');
454
+ container.innerHTML = '<div class="loading"><div class="loading-spinner"></div><p>Loading models...</p></div>';
455
+
456
+ if (currentType === 'official') {
457
+ try {
458
+ const proxyUrl = 'https://api.allorigins.win/raw?url=';
459
+ const targetUrl = 'https://replicate.com/collections/official';
460
+
461
+ const response = await fetch(proxyUrl + encodeURIComponent(targetUrl));
462
+ const html = await response.text();
463
+
464
+ const parser = new DOMParser();
465
+ const doc = parser.parseFromString(html, 'text/html');
466
+
467
+ const scriptTags = doc.querySelectorAll('script');
468
+ let modelsData = [];
469
+
470
+ for (const script of scriptTags) {
471
+ if (script.textContent.includes('__NEXT_DATA__')) {
472
+ try {
473
+ const jsonMatch = script.textContent.match(/{.*}/);
474
+ if (jsonMatch) {
475
+ const data = JSON.parse(jsonMatch[0]);
476
+ if (data.props?.pageProps?.models) {
477
+ modelsData = data.props.pageProps.models;
478
+ }
479
+ }
480
+ } catch (e) {
481
+ console.error(e);
482
+ }
483
+ }
484
+ }
485
+
486
+ if (modelsData.length > 0) {
487
+ displayReplicateModels(modelsData, container, 'official');
488
+ } else {
489
+ displaySampleReplicateModels(container, currentType);
490
+ }
491
+ } catch (error) {
492
+ displaySampleReplicateModels(container, currentType);
493
+ }
494
+ } else {
495
+ displaySampleReplicateModels(container, currentType);
496
+ }
497
+ }
498
+
499
+ // ํ”„๋ก์‹œ ์š”์ฒญ
500
  async function tryProxyRequest(type, container) {
501
  try {
 
 
502
  const proxyUrl = 'https://api.allorigins.win/raw?url=';
503
+ const targetUrl = type === 'models'
504
+ ? 'https://huggingface.co/api/models?sort=likes7d&direction=-1&limit=30'
505
+ : 'https://huggingface.co/api/spaces?sort=likes7d&direction=-1&limit=30';
 
 
 
 
506
 
 
507
  const response = await fetch(proxyUrl + encodeURIComponent(targetUrl));
508
  const data = await response.json();
509
 
 
510
  if (type === 'models') {
511
  displayHFModels(data, container);
512
  } else {
513
  displayHFSpaces(data, container);
514
  }
515
  } catch (error) {
 
 
 
516
  if (type === 'models') {
517
  displaySampleHFModels(container);
518
  } else {
 
521
  }
522
  }
523
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
524
  // HuggingFace Models ํ‘œ์‹œ
525
  function displayHFModels(models, container) {
526
  container.innerHTML = '';
 
534
  tags: model.tags || [],
535
  pipeline_tag: model.pipeline_tag || '',
536
  url: `https://huggingface.co/${model.id || model.modelId}`,
537
+ icon: '๐Ÿค–'
 
538
  });
539
  container.appendChild(card);
540
  });
 
553
  emoji: space.emoji || '๐ŸŽฏ',
554
  url: `https://huggingface.co/spaces/${space.id}`,
555
  icon: space.emoji || '๐ŸŽฏ',
556
+ hardware: space.hardware || 'CPU'
557
+ });
558
+ container.appendChild(card);
559
+ });
560
+ }
561
+
562
+ // Replicate ์‹ค์‹œ๊ฐ„ ๋ชจ๋ธ ํ‘œ์‹œ
563
+ function displayReplicateModels(models, container, type) {
564
+ container.innerHTML = '';
565
+ models.forEach((model, index) => {
566
+ const card = createModelCard({
567
+ rank: index + 1,
568
+ title: model.name || model.default_example?.model || 'Unknown',
569
+ author: model.owner || model.username || 'replicate',
570
+ runs: model.run_count || model.runs || 0,
571
+ icon: getModelIcon(model.name),
572
+ badge: type === 'official' ? 'โœ… Official' : 'โญ Featured',
573
+ url: model.url || `https://replicate.com/${model.owner || 'p'}/${model.name}`
574
  });
575
  container.appendChild(card);
576
  });
 
582
  card.className = 'item-card';
583
  card.onclick = () => window.open(data.url, '_blank');
584
 
 
585
  let rankColor = '#999';
586
  if (data.rank === 1) rankColor = '#FFD700';
587
  else if (data.rank === 2) rankColor = '#C0C0C0';
 
589
  else if (data.rank <= 10) rankColor = '#667eea';
590
 
591
  card.innerHTML = `
592
+ <div class="rank-badge" style="background: ${rankColor};">
593
  ${data.rank}
594
  </div>
595
+ ${data.badge ? `<div class="badge-label">${data.badge}</div>` : ''}
596
  <div class="item-header">
597
  <div class="item-icon">${data.icon}</div>
598
  <div class="item-info">
599
  <div class="item-title">${data.title}</div>
600
+ <div class="item-author">@${data.author}</div>
601
  </div>
602
  </div>
603
  <div class="item-stats">
 
606
  ${data.sdk ? `<div class="stat">๐Ÿ› ๏ธ ${data.sdk}</div>` : ''}
607
  ${data.hardware ? `<div class="stat">๐Ÿ’ป ${data.hardware}</div>` : ''}
608
  ${data.pipeline_tag ? `<div class="stat">๐Ÿท๏ธ ${data.pipeline_tag}</div>` : ''}
609
+ ${data.runs !== undefined ? `<div class="stat">โ–ถ๏ธ ${formatNumber(data.runs)} runs</div>` : ''}
610
  </div>
611
  ${data.tags && data.tags.length > 0 ? `
612
+ <div class="tags-container">
613
+ ${data.tags.slice(0, 3).map(tag => `<span class="tag">${tag}</span>`).join('')}
614
  </div>
615
  ` : ''}
616
  `;
 
625
  return num.toString();
626
  }
627
 
628
+ // ๋ชจ๋ธ ์•„์ด์ฝ˜ ๊ฒฐ์ •
629
+ function getModelIcon(name) {
630
+ if (!name) return '๐Ÿค–';
631
+ const lowerName = name.toLowerCase();
632
+ if (lowerName.includes('image') || lowerName.includes('diffusion') || lowerName.includes('flux')) return '๐ŸŽจ';
633
+ if (lowerName.includes('video')) return '๐ŸŽฌ';
634
+ if (lowerName.includes('audio') || lowerName.includes('music') || lowerName.includes('whisper')) return '๐ŸŽต';
635
+ if (lowerName.includes('llama') || lowerName.includes('chat') || lowerName.includes('gpt')) return '๐Ÿ’ฌ';
636
+ return '๐Ÿค–';
637
+ }
638
+
639
  // ์ƒ˜ํ”Œ ๋ฐ์ดํ„ฐ ํ‘œ์‹œ ํ•จ์ˆ˜๋“ค
640
  function displaySampleHFModels(container) {
 
641
  const sampleData = [
642
  { rank: 1, title: 'Llama-3.3-70B-Instruct', author: 'meta-llama', likes: 177000, downloads: 1150000, icon: '๐Ÿค–', pipeline_tag: 'text-generation', tags: ['llama', '70b', 'instruct'] },
643
  { rank: 2, title: 'DeepSeek-R1-Distill-Qwen-32B', author: 'deepseek-ai', likes: 10400, downloads: 567000, icon: '๐Ÿค–', pipeline_tag: 'text-generation', tags: ['deepseek', 'reasoning'] },
 
659
  }
660
 
661
  function displaySampleHFSpaces(container) {
 
662
  const sampleData = [
663
  { rank: 1, title: 'stable-diffusion-webui', author: 'stabilityai', likes: 75500, sdk: 'Gradio', icon: '๐ŸŽจ', hardware: 'T4 GPU' },
664
  { rank: 2, title: 'chatgpt-clone', author: 'community', likes: 12300, sdk: 'Streamlit', icon: '๐Ÿ’ฌ', hardware: 'CPU' },
 
680
  }
681
 
682
  function displaySampleReplicateModels(container, type) {
 
 
683
  const featuredData = [
684
  { rank: 1, title: 'flux-1.1-pro', author: 'black-forest-labs', runs: 2910000, icon: '๐ŸŽจ', badge: 'โญ Featured' },
685
  { rank: 2, title: 'llama-3.3-70b-versatile', author: 'meta', runs: 1850000, icon: '๐Ÿค–', badge: 'โญ Featured' },
 
726
 
727
  // ์ดˆ๊ธฐ ๋กœ๋“œ
728
  window.addEventListener('DOMContentLoaded', () => {
 
 
 
 
 
729
  loadHFModels();
730
  });
731
  </script>