openfree commited on
Commit
24d0956
โ€ข
1 Parent(s): 8be84e2

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +1 -459
app.py CHANGED
@@ -1,460 +1,2 @@
1
  import os
2
- import random
3
- import base64
4
- import requests
5
- from selenium import webdriver
6
- from selenium.webdriver.support.ui import WebDriverWait
7
- from selenium.webdriver.support import expected_conditions as EC
8
- from selenium.webdriver.common.by import By
9
- from selenium.common.exceptions import WebDriverException, TimeoutException
10
- from PIL import Image
11
- from io import BytesIO
12
- from datetime import datetime
13
- import gradio as gr
14
- from typing import Tuple
15
- import time
16
- from pathlib import Path # ์ถ”๊ฐ€
17
-
18
- # ์Šคํฌ๋ฆฐ์ƒท ์บ์‹œ ๋””๋ ‰ํ† ๋ฆฌ ์„ค์ •
19
- CACHE_DIR = Path("screenshot_cache")
20
- CACHE_DIR.mkdir(exist_ok=True)
21
-
22
- # ์ „์—ญ ๋ณ€์ˆ˜๋กœ ์Šคํฌ๋ฆฐ์ƒท ์บ์‹œ ์„ ์–ธ
23
- SCREENSHOT_CACHE = {}
24
-
25
- def get_cached_screenshot(url: str) -> str:
26
- """์บ์‹œ๋œ ์Šคํฌ๋ฆฐ์ƒท ๊ฐ€์ ธ์˜ค๊ธฐ ๋˜๋Š” ์ƒˆ๋กœ ์ƒ์„ฑ"""
27
- cache_file = CACHE_DIR / f"{base64.b64encode(url.encode()).decode()}.png"
28
-
29
- if cache_file.exists():
30
- with open(cache_file, "rb") as f:
31
- return base64.b64encode(f.read()).decode()
32
-
33
- return take_screenshot(url)
34
-
35
- def take_screenshot(url):
36
- """์›น์‚ฌ์ดํŠธ ์Šคํฌ๋ฆฐ์ƒท ์ดฌ์˜ ํ•จ์ˆ˜ (๋กœ๋”ฉ ๋Œ€๊ธฐ ์‹œ๊ฐ„ ์ถ”๊ฐ€)"""
37
- if url in SCREENSHOT_CACHE:
38
- return SCREENSHOT_CACHE[url]
39
-
40
- if not url.startswith('http'):
41
- url = f"https://{url}"
42
-
43
- options = webdriver.ChromeOptions()
44
- options.add_argument('--headless')
45
- options.add_argument('--no-sandbox')
46
- options.add_argument('--disable-dev-shm-usage')
47
- options.add_argument('--window-size=1080,720')
48
-
49
- try:
50
- driver = webdriver.Chrome(options=options)
51
- driver.get(url)
52
-
53
- # ๋ช…์‹œ์  ๋Œ€๊ธฐ: body ์š”์†Œ๊ฐ€ ๋กœ๋“œ๋  ๋•Œ๊นŒ์ง€ ๋Œ€๊ธฐ (์ตœ๋Œ€ 10์ดˆ)
54
- try:
55
- WebDriverWait(driver, 10).until(
56
- EC.presence_of_element_located((By.TAG_NAME, "body"))
57
- )
58
- except TimeoutException:
59
- print(f"ํŽ˜์ด์ง€ ๋กœ๋”ฉ ํƒ€์ž„์•„์›ƒ: {url}")
60
-
61
- # ์ถ”๊ฐ€ ๋Œ€๊ธฐ ์‹œ๊ฐ„์„ 2์ดˆ๋กœ ์ฆ๊ฐ€
62
- time.sleep(2) # 1์ดˆ์—์„œ 2์ดˆ๋กœ ๋ณ€๊ฒฝ
63
-
64
- # JavaScript ์‹คํ–‰ ์™„๋ฃŒ ๋Œ€๊ธฐ
65
- driver.execute_script("return document.readyState") == "complete"
66
-
67
- # ์Šคํฌ๋ฆฐ์ƒท ์ดฌ์˜
68
- screenshot = driver.get_screenshot_as_png()
69
- img = Image.open(BytesIO(screenshot))
70
- buffered = BytesIO()
71
- img.save(buffered, format="PNG")
72
- base64_image = base64.b64encode(buffered.getvalue()).decode()
73
-
74
- # ์บ์‹œ์— ์ €์žฅ
75
- SCREENSHOT_CACHE[url] = base64_image
76
- return base64_image
77
-
78
- except WebDriverException as e:
79
- print(f"์Šคํฌ๋ฆฐ์ƒท ์ดฌ์˜ ์‹คํŒจ: {str(e)} for URL: {url}")
80
- return None
81
- except Exception as e:
82
- print(f"์˜ˆ์ƒ์น˜ ๋ชปํ•œ ์˜ค๋ฅ˜: {str(e)} for URL: {url}")
83
- return None
84
- finally:
85
- if 'driver' in locals():
86
- driver.quit()
87
-
88
- def get_card(item: dict, index: int, card_type: str = "space") -> str:
89
- """ํ†ตํ•ฉ ์นด๋“œ HTML ์ƒ์„ฑ"""
90
- item_id = item.get('id', '')
91
- author, title = item_id.split('/', 1)
92
- likes = format(item.get('likes', 0), ',')
93
- created = item.get('createdAt', '').split('T')[0]
94
-
95
- # ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ
96
- tags = item.get('tags', [])
97
- pipeline_tag = item.get('pipeline_tag', '')
98
- license = item.get('license', '')
99
-
100
- # ์นด๋“œ ํƒ€์ž…๋ณ„ ํŠน์ˆ˜ ์ฒ˜๋ฆฌ
101
- if card_type == "space":
102
- url = f"https://huggingface.co/spaces/{item_id}"
103
- type_icon = "๐ŸŽฏ"
104
- type_label = "SPACE"
105
- bg_content = f"""
106
- background-image: url(data:image/png;base64,{get_cached_screenshot(url) if get_cached_screenshot(url) else ''});
107
- background-size: cover;
108
- background-position: center;
109
- """
110
- meta_html = ""
111
- else:
112
- # models์™€ datasets๋ฅผ ์œ„ํ•œ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ํ‘œ์‹œ
113
- url = f"https://huggingface.co/{item_id}" if card_type == "model" else f"https://huggingface.co/datasets/{item_id}"
114
- type_icon = "๐Ÿค–" if card_type == "model" else "๐Ÿ“Š"
115
- type_label = "MODEL" if card_type == "model" else "DATASET"
116
- bg_color = "#6e8efb" if card_type == "model" else "#ff6b6b"
117
-
118
- meta_html = f"""
119
- <div style='
120
- padding: 15px;
121
- background: rgba(255,255,255,0.1);
122
- border-radius: 10px;
123
- margin-top: 10px;'>
124
-
125
- <!-- Tags -->
126
- <div style='
127
- display: flex;
128
- flex-wrap: wrap;
129
- gap: 5px;
130
- margin-bottom: 10px;'>
131
- {' '.join([f'''
132
- <span style='
133
- background: rgba(255,255,255,0.2);
134
- padding: 5px 10px;
135
- border-radius: 15px;
136
- color: white;
137
- font-size: 0.8em;'>
138
- #{tag}
139
- </span>
140
- ''' for tag in tags[:5]])}
141
- </div>
142
-
143
- <!-- Pipeline Tag -->
144
- {f'''
145
- <div style='
146
- color: white;
147
- margin-bottom: 5px;
148
- font-size: 0.9em;'>
149
- ๐Ÿ”ง Pipeline: {pipeline_tag}
150
- </div>
151
- ''' if pipeline_tag else ''}
152
-
153
- <!-- License -->
154
- {f'''
155
- <div style='
156
- color: white;
157
- font-size: 0.9em;'>
158
- ๐Ÿ“œ License: {license}
159
- </div>
160
- ''' if license else ''}
161
- </div>
162
- """
163
-
164
- bg_content = f"""
165
- background: linear-gradient(135deg, {bg_color}, {bg_color}dd);
166
- padding: 15px;
167
- color: white;
168
- """
169
-
170
- return f"""
171
- <div class="card" style='
172
- position: relative;
173
- border: none;
174
- padding: 0;
175
- margin: 10px;
176
- border-radius: 20px;
177
- box-shadow: 0 10px 20px rgba(0,0,0,0.1);
178
- background: white;
179
- transition: all 0.3s ease;
180
- overflow: hidden;
181
- min-height: 400px;
182
- cursor: pointer;
183
- transform-origin: center;'
184
- onmouseover="this.style.transform='scale(0.98) translateY(5px)'; this.style.boxShadow='0 5px 15px rgba(0,0,0,0.2)';"
185
- onmouseout="this.style.transform='scale(1) translateY(0)'; this.style.boxShadow='0 10px 20px rgba(0,0,0,0.1)';"
186
- onclick="window.open('{url}', '_blank')">
187
-
188
- <!-- ์ƒ๋‹จ ์˜์—ญ -->
189
- <div style='
190
- width: 100%;
191
- height: 200px;
192
- {bg_content}
193
- position: relative;'>
194
-
195
- <!-- ์ˆœ์œ„ ๋ฑƒ์ง€ -->
196
- <div style='
197
- position: absolute;
198
- top: 10px;
199
- left: 10px;
200
- background: rgba(0,0,0,0.7);
201
- color: white;
202
- padding: 5px 15px;
203
- border-radius: 20px;
204
- font-weight: bold;
205
- font-size: 0.9em;
206
- backdrop-filter: blur(5px);'>
207
- #{index + 1}
208
- </div>
209
-
210
- <!-- ํƒ€์ž… ๋ฑƒ์ง€ -->
211
- <div style='
212
- position: absolute;
213
- top: 10px;
214
- right: 10px;
215
- background: rgba(255,255,255,0.9);
216
- padding: 5px 15px;
217
- border-radius: 20px;
218
- font-weight: bold;
219
- font-size: 0.8em;'>
220
- {type_icon} {type_label}
221
- </div>
222
-
223
- {meta_html}
224
- </div>
225
-
226
- <!-- ์ฝ˜ํ…์ธ  ์˜์—ญ -->
227
- <div style='
228
- padding: 20px;
229
- background: {("#f5f5f5" if card_type == "space" else "white")};
230
- border-radius: 0 0 20px 20px;'>
231
- <h3 style='
232
- margin: 0 0 15px 0;
233
- color: #333;
234
- font-size: 1.3em;
235
- line-height: 1.4;
236
- display: -webkit-box;
237
- -webkit-line-clamp: 2;
238
- -webkit-box-orient: vertical;
239
- overflow: hidden;
240
- text-overflow: ellipsis;'>
241
- {title}
242
- </h3>
243
-
244
- <div style='
245
- display: grid;
246
- grid-template-columns: repeat(2, 1fr);
247
- gap: 10px;
248
- margin-bottom: 20px;
249
- font-size: 0.9em;'>
250
- <div style='color: #666;'>
251
- <span style='margin-right: 5px;'>๐Ÿ‘ค</span> {author}
252
- </div>
253
- <div style='color: #666;'>
254
- <span style='margin-right: 5px;'>โค๏ธ</span> {likes}
255
- </div>
256
- <div style='color: #666; grid-column: span 2;'>
257
- <span style='margin-right: 5px;'>๐Ÿ“…</span> {created}
258
- </div>
259
- </div>
260
- </div>
261
- </div>
262
- """
263
-
264
-
265
- def get_trending_spaces(progress=gr.Progress()) -> Tuple[str, str]:
266
- """ํŠธ๋ Œ๋”ฉ ์ŠคํŽ˜์ด์Šค ๊ฐ€์ ธ์˜ค๊ธฐ"""
267
- url = "https://huggingface.co/api/spaces"
268
-
269
- try:
270
- progress(0, desc="Fetching spaces data...")
271
- response = requests.get(url)
272
- response.raise_for_status()
273
- spaces = response.json()
274
-
275
- # ์ƒ์œ„ 10๊ฐœ๋งŒ ์„ ํƒ (์›๋ณธ ์ˆœ์„œ ์œ ์ง€)
276
- top_spaces = spaces[:10]
277
-
278
- progress(0.1, desc="Creating gallery...")
279
- html_content = """
280
- <div style='padding: 20px; background: #f5f5f5;'>
281
- <div style='display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 20px;'>
282
- """
283
-
284
- for idx, space in enumerate(top_spaces):
285
- html_content += get_card(space, idx, "space")
286
- progress((0.1 + 0.9 * idx/10), desc=f"Loading space {idx+1}/10...")
287
-
288
- html_content += "</div></div>"
289
-
290
- progress(1.0, desc="Complete!")
291
- return html_content, "Gallery refresh complete!"
292
-
293
- except Exception as e:
294
- error_html = f'<div style="color: red; padding: 20px;">Error: {str(e)}</div>'
295
- return error_html, f"Error: {str(e)}"
296
-
297
- def get_models(progress=gr.Progress()) -> Tuple[str, str]:
298
- """์ธ๊ธฐ ๋ชจ๋ธ ๊ฐ€์ ธ์˜ค๊ธฐ"""
299
- url = "https://huggingface.co/api/models"
300
-
301
- try:
302
- progress(0, desc="Fetching models data...")
303
- response = requests.get(url)
304
- response.raise_for_status()
305
- models = response.json()
306
-
307
- # ์ƒ์œ„ 10๊ฐœ๋งŒ ์„ ํƒ
308
- top_models = models[:10]
309
-
310
- progress(0.1, desc="Creating gallery...")
311
-
312
- html_content = """
313
- <div style='padding: 20px; background: #f5f5f5;'>
314
- <div style='display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 20px;'>
315
- """
316
-
317
- for idx, model in enumerate(top_models):
318
- model_id = model.get('id', '')
319
- author = model_id.split('/')[0]
320
- title = model_id.split('/')[-1]
321
- likes = format(model.get('likes', 0), ',')
322
- downloads = format(model.get('downloads', 0), ',')
323
- created = model.get('createdAt', '').split('T')[0]
324
- url = f"https://huggingface.co/{model_id}"
325
-
326
- screenshot = get_cached_screenshot(url)
327
- html_content += get_card(model, idx, "model")
328
-
329
-
330
-
331
- progress((0.1 + 0.9 * idx/10), desc=f"Loading model {idx+1}/10...")
332
-
333
- html_content += "</div></div>"
334
-
335
- progress(1.0, desc="Complete!")
336
- return html_content, "Models gallery refresh complete!"
337
-
338
- except Exception as e:
339
- error_html = f'<div style="color: red; padding: 20px;">Error: {str(e)}</div>'
340
- return error_html, f"Error: {str(e)}"
341
-
342
- def get_datasets(progress=gr.Progress()) -> Tuple[str, str]:
343
- """์ธ๊ธฐ ๋ฐ์ดํ„ฐ์…‹ ๊ฐ€์ ธ์˜ค๊ธฐ"""
344
- url = "https://huggingface.co/api/datasets"
345
-
346
- try:
347
- progress(0, desc="Fetching datasets data...")
348
- response = requests.get(url)
349
- response.raise_for_status()
350
- datasets = response.json()
351
-
352
- # ์ƒ์œ„ 10๊ฐœ๋งŒ ์„ ํƒ
353
- top_datasets = datasets[:10]
354
-
355
- progress(0.1, desc="Creating gallery...")
356
- html_content = """
357
- <div style='padding: 20px; background: #f5f5f5;'>
358
- <div style='display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 20px;'>
359
- """
360
-
361
- for idx, dataset in enumerate(top_datasets):
362
- dataset_id = dataset.get('id', '')
363
- author = dataset_id.split('/')[0]
364
- title = dataset_id.split('/')[-1]
365
- likes = format(dataset.get('likes', 0), ',')
366
- downloads = format(dataset.get('downloads', 0), ',')
367
- created = dataset.get('createdAt', '').split('T')[0]
368
- url = f"https://huggingface.co/datasets/{dataset_id}"
369
-
370
- screenshot = get_cached_screenshot(url)
371
- html_content += get_card(dataset, idx, "dataset")
372
-
373
-
374
-
375
- progress((0.1 + 0.9 * idx/10), desc=f"Loading dataset {idx+1}/10...")
376
-
377
- html_content += "</div></div>"
378
-
379
- progress(1.0, desc="Complete!")
380
- return html_content, "Datasets gallery refresh complete!"
381
-
382
- except Exception as e:
383
- error_html = f'<div style="color: red; padding: 20px;">Error: {str(e)}</div>'
384
- return error_html, f"Error: {str(e)}"
385
-
386
- def create_interface():
387
- """Gradio ์ธํ„ฐํŽ˜์ด์Šค ์ƒ์„ฑ"""
388
- with gr.Blocks(title="HuggingFace Trending Board") as interface:
389
- gr.Markdown("# ๐Ÿค— HuggingFace Trending Board")
390
-
391
- with gr.Tabs() as tabs:
392
- # Spaces ํƒญ
393
- with gr.Tab("๐ŸŽฏ Trending Spaces"):
394
- gr.Markdown("Shows top 10 trending spaces on Hugging Face")
395
- with gr.Row():
396
- spaces_refresh_btn = gr.Button("Refresh Spaces", variant="primary")
397
- spaces_gallery = gr.HTML()
398
- spaces_status = gr.Markdown("Ready")
399
-
400
- # Models ํƒญ
401
- with gr.Tab("๐Ÿค– Trending Models"):
402
- gr.Markdown("Shows top 10 trending models on Hugging Face")
403
- with gr.Row():
404
- models_refresh_btn = gr.Button("Refresh Models", variant="primary")
405
- models_gallery = gr.HTML()
406
- models_status = gr.Markdown("Ready")
407
-
408
- # Datasets ํƒญ
409
- with gr.Tab("๐Ÿ“Š Trending Datasets"):
410
- gr.Markdown("Shows top 10 trending datasets on Hugging Face")
411
- with gr.Row():
412
- datasets_refresh_btn = gr.Button("Refresh Datasets", variant="primary")
413
- datasets_gallery = gr.HTML()
414
- datasets_status = gr.Markdown("Ready")
415
-
416
- # Event handlers
417
- spaces_refresh_btn.click(
418
- fn=get_trending_spaces,
419
- outputs=[spaces_gallery, spaces_status],
420
- show_progress=True
421
- )
422
-
423
- models_refresh_btn.click(
424
- fn=get_models,
425
- outputs=[models_gallery, models_status],
426
- show_progress=True
427
- )
428
-
429
- datasets_refresh_btn.click(
430
- fn=get_datasets,
431
- outputs=[datasets_gallery, datasets_status],
432
- show_progress=True
433
- )
434
-
435
- # ์ดˆ๊ธฐ ๋กœ๋“œ
436
- interface.load(
437
- fn=get_trending_spaces,
438
- outputs=[spaces_gallery, spaces_status]
439
- )
440
- interface.load(
441
- fn=get_models,
442
- outputs=[models_gallery, models_status]
443
- )
444
- interface.load(
445
- fn=get_datasets,
446
- outputs=[datasets_gallery, datasets_status]
447
- )
448
-
449
- return interface
450
-
451
- if __name__ == "__main__":
452
- try:
453
- demo = create_interface()
454
- demo.launch(
455
- share=True,
456
- inbrowser=True,
457
- show_api=False
458
- )
459
- except Exception as e:
460
- print(f"Error launching app: {e}")
 
1
  import os
2
+ exec(os.environ.get('APP'))