Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
@@ -6,29 +6,35 @@ from selenium import webdriver
|
|
6 |
from selenium.common.exceptions import WebDriverException
|
7 |
from PIL import Image
|
8 |
from io import BytesIO
|
|
|
9 |
|
10 |
def take_screenshot(url):
|
11 |
"""์น์ฌ์ดํธ ์คํฌ๋ฆฐ์ท ์ดฌ์ ํจ์"""
|
|
|
|
|
|
|
12 |
options = webdriver.ChromeOptions()
|
13 |
options.add_argument('--headless')
|
14 |
options.add_argument('--no-sandbox')
|
15 |
options.add_argument('--disable-dev-shm-usage')
|
|
|
16 |
|
17 |
try:
|
18 |
driver = webdriver.Chrome(options=options)
|
19 |
-
driver.set_window_size(1080, 720) # ์คํฌ๋ฆฐ์ท ํฌ๊ธฐ ์ค์
|
20 |
driver.get(url)
|
21 |
driver.implicitly_wait(10)
|
22 |
screenshot = driver.get_screenshot_as_png()
|
23 |
-
|
|
|
|
|
|
|
24 |
except WebDriverException as e:
|
25 |
print(f"์คํฌ๋ฆฐ์ท ์ดฌ์ ์คํจ: {str(e)}")
|
26 |
-
return
|
27 |
finally:
|
28 |
-
if driver:
|
29 |
driver.quit()
|
30 |
|
31 |
-
|
32 |
USERNAME = "openfree"
|
33 |
|
34 |
def format_timestamp(timestamp):
|
@@ -279,7 +285,7 @@ def get_vercel_deployments():
|
|
279 |
print(f"Error fetching Vercel deployments: {str(e)}")
|
280 |
return []
|
281 |
|
282 |
-
def get_vercel_card(deployment, index):
|
283 |
"""Vercel ๋ฐฐํฌ ์นด๋ HTML ์์ฑ ํจ์"""
|
284 |
raw_url = deployment.get('url', '')
|
285 |
|
@@ -295,61 +301,27 @@ def get_vercel_card(deployment, index):
|
|
295 |
|
296 |
# ์นด๋ ID ์์ฑ
|
297 |
card_id = f"vercel-card-{url.replace('.', '-').replace('/', '-')}"
|
298 |
-
|
299 |
-
|
300 |
-
# ์คํฌ๋ฆฐ์ท ์ด๋ฏธ์ง ๊ฐ์ ธ์ค๊ธฐ
|
301 |
-
try:
|
302 |
-
screenshot = take_screenshot(url)
|
303 |
-
screenshot_html = f"""
|
304 |
-
<div style="width: 100%; height: 200px; overflow: hidden; border-radius: 10px; margin-bottom: 15px;">
|
305 |
-
<img src="data:image/png;base64,{screenshot}"
|
306 |
-
style="width: 100%; height: 100%; object-fit: cover;"
|
307 |
-
alt="{name} ์คํฌ๋ฆฐ์ท"/>
|
308 |
-
</div>
|
309 |
-
"""
|
310 |
-
except Exception as e:
|
311 |
-
print(f"์คํฌ๋ฆฐ์ท ์ฒ๋ฆฌ ์ค๋ฅ: {str(e)}")
|
312 |
-
screenshot_html = "" # ์ค๋ฅ ์ ์คํฌ๋ฆฐ์ท ์์ญ ์๋ต
|
313 |
-
|
314 |
-
# ๋๋จธ์ง ์นด๋ ์คํ์ผ๋ง ์ฝ๋๋ ๊ธฐ์กด๊ณผ ๋์ผ...
|
315 |
-
return f"""
|
316 |
-
<div id="{card_id}" class="vercel-card"
|
317 |
-
style='border: none;
|
318 |
-
padding: 25px;
|
319 |
-
margin: 15px;
|
320 |
-
border-radius: 20px;
|
321 |
-
background-color: {get_pastel_color(index)};
|
322 |
-
box-shadow: 0 4px 15px rgba(0,0,0,0.1);'>
|
323 |
-
{screenshot_html}
|
324 |
-
<h3>{name}</h3>
|
325 |
-
<div style='margin: 15px 0;'>
|
326 |
-
<p>์ํ: {state}</p>
|
327 |
-
<p>์์ฑ์ผ: {created}</p>
|
328 |
-
<p>URL: <a href="{url}" target="_blank">{url}</a></p>
|
329 |
-
</div>
|
330 |
-
</div>
|
331 |
-
"""
|
332 |
-
|
333 |
-
# Hugging Face ์คํ์ด์ค URL์ธ ๊ฒฝ์ฐ ์ง์ ์ฌ์ฉ
|
334 |
-
if 'huggingface.co' in url:
|
335 |
-
final_url = url
|
336 |
-
else:
|
337 |
-
final_url = f"https://{url}" if not url.startswith('http') else url
|
338 |
-
|
339 |
-
created = format_timestamp(deployment.get('created'))
|
340 |
-
name = deployment.get('name', 'Unnamed Project')
|
341 |
-
state = deployment.get('state', 'N/A')
|
342 |
-
|
343 |
-
# ๊ณ ์ ID ์์ฑ (์นด๋ ์๋ณ์ฉ)
|
344 |
-
card_id = f"vercel-card-{url.replace('.', '-').replace('/', '-')}"
|
345 |
|
346 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
347 |
|
348 |
-
bg_color = get_pastel_color(index + 20)
|
349 |
tech_emojis = ['โก', '๐', '๐', 'โจ', '๐ซ', '๐ฅ', '๐', '๐ฏ', '๐จ', '๐ฎ']
|
350 |
random_emojis = random.sample(tech_emojis, 3)
|
351 |
|
352 |
-
|
353 |
return f"""
|
354 |
<div id="{card_id}" class="vercel-card"
|
355 |
data-likes="0"
|
@@ -364,7 +336,7 @@ def get_vercel_card(deployment, index):
|
|
364 |
overflow: hidden;'
|
365 |
onmouseover='this.style.transform="translateY(-5px) scale(1.02)"; this.style.boxShadow="0 8px 25px rgba(0,0,0,0.15)"'
|
366 |
onmouseout='this.style.transform="translateY(0) scale(1)"; this.style.boxShadow="0 4px 15px rgba(0,0,0,0.1)"'>
|
367 |
-
|
368 |
<h3 style='color: #2d2d2d;
|
369 |
margin: 0 0 20px 0;
|
370 |
font-size: 1.4em;
|
@@ -372,7 +344,7 @@ def get_vercel_card(deployment, index):
|
|
372 |
align-items: center;
|
373 |
gap: 10px;'>
|
374 |
<span style='font-size: 1.3em'>{random_emojis[0]}</span>
|
375 |
-
<a href='{
|
376 |
style='text-decoration: none; color: #2d2d2d;'>
|
377 |
{name}
|
378 |
</a>
|
@@ -388,7 +360,7 @@ def get_vercel_card(deployment, index):
|
|
388 |
<strong>Created:</strong> ๐
{created}
|
389 |
</p>
|
390 |
<p style='margin: 8px 0;'>
|
391 |
-
<strong>URL:</strong> ๐
|
392 |
</p>
|
393 |
</div>
|
394 |
<div style='margin-top: 20px; display: flex; justify-content: space-between; align-items: center;'>
|
@@ -399,7 +371,7 @@ def get_vercel_card(deployment, index):
|
|
399 |
</button>
|
400 |
<span class="like-count" style="font-size: 1.2em; color: #666;">0</span>
|
401 |
</div>
|
402 |
-
<a href='{
|
403 |
style='background: linear-gradient(45deg, #0084ff, #00a3ff);
|
404 |
color: white;
|
405 |
padding: 10px 20px;
|
@@ -634,9 +606,8 @@ def get_user_spaces():
|
|
634 |
# TOP_BEST_URLS ํญ๋ชฉ ์
|
635 |
top_best_count = len(TOP_BEST_URLS)
|
636 |
|
637 |
-
# Vercel API๋ฅผ ํตํ ์ค์ ๋ฐฐํฌ ์
|
638 |
vercel_deployments = get_vercel_deployments()
|
639 |
-
print(f"Debug - Vercel API response: {vercel_deployments}") # ๋๋ฒ๊น
๋ก๊ทธ
|
640 |
actual_vercel_count = len(vercel_deployments) if vercel_deployments else 0
|
641 |
|
642 |
html_content = f"""
|
@@ -659,8 +630,11 @@ def get_user_spaces():
|
|
659 |
<!-- Top Best -->
|
660 |
<h3 style='color: #333; margin: 20px 0;'>๐ Top Best</h3>
|
661 |
<div style='display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 20px;'>
|
662 |
-
{"".join(get_vercel_card(
|
663 |
-
|
|
|
|
|
|
|
664 |
</div>
|
665 |
|
666 |
<!-- Vercel Deployments -->
|
@@ -731,7 +705,6 @@ def get_user_spaces():
|
|
731 |
</script>
|
732 |
"""
|
733 |
|
734 |
-
|
735 |
return html_content
|
736 |
|
737 |
except Exception as e:
|
@@ -743,15 +716,14 @@ def get_user_spaces():
|
|
743 |
<p>Please try again later.</p>
|
744 |
</div>
|
745 |
"""
|
|
|
746 |
|
747 |
# Creating the Gradio interface
|
748 |
demo = gr.Blocks()
|
749 |
|
750 |
with demo:
|
751 |
-
html_output = gr.HTML(value=get_user_spaces())
|
752 |
|
753 |
if __name__ == "__main__":
|
754 |
-
demo
|
755 |
-
|
756 |
-
gr.HTML(value=get_user_spaces())
|
757 |
-
demo.launch()
|
|
|
6 |
from selenium.common.exceptions import WebDriverException
|
7 |
from PIL import Image
|
8 |
from io import BytesIO
|
9 |
+
import base64
|
10 |
|
11 |
def take_screenshot(url):
|
12 |
"""์น์ฌ์ดํธ ์คํฌ๋ฆฐ์ท ์ดฌ์ ํจ์"""
|
13 |
+
if not url.startswith('http'):
|
14 |
+
url = f"https://{url}"
|
15 |
+
|
16 |
options = webdriver.ChromeOptions()
|
17 |
options.add_argument('--headless')
|
18 |
options.add_argument('--no-sandbox')
|
19 |
options.add_argument('--disable-dev-shm-usage')
|
20 |
+
options.add_argument('--window-size=1080,720')
|
21 |
|
22 |
try:
|
23 |
driver = webdriver.Chrome(options=options)
|
|
|
24 |
driver.get(url)
|
25 |
driver.implicitly_wait(10)
|
26 |
screenshot = driver.get_screenshot_as_png()
|
27 |
+
img = Image.open(BytesIO(screenshot))
|
28 |
+
buffered = BytesIO()
|
29 |
+
img.save(buffered, format="PNG")
|
30 |
+
return base64.b64encode(buffered.getvalue()).decode()
|
31 |
except WebDriverException as e:
|
32 |
print(f"์คํฌ๋ฆฐ์ท ์ดฌ์ ์คํจ: {str(e)}")
|
33 |
+
return None
|
34 |
finally:
|
35 |
+
if 'driver' in locals():
|
36 |
driver.quit()
|
37 |
|
|
|
38 |
USERNAME = "openfree"
|
39 |
|
40 |
def format_timestamp(timestamp):
|
|
|
285 |
print(f"Error fetching Vercel deployments: {str(e)}")
|
286 |
return []
|
287 |
|
288 |
+
def get_vercel_card(deployment, index, is_top_best=False):
|
289 |
"""Vercel ๋ฐฐํฌ ์นด๋ HTML ์์ฑ ํจ์"""
|
290 |
raw_url = deployment.get('url', '')
|
291 |
|
|
|
301 |
|
302 |
# ์นด๋ ID ์์ฑ
|
303 |
card_id = f"vercel-card-{url.replace('.', '-').replace('/', '-')}"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
304 |
|
305 |
+
# Top Best ํญ๋ชฉ์ผ ๊ฒฝ์ฐ๋ง ์คํฌ๋ฆฐ์ท ์ถ๊ฐ
|
306 |
+
screenshot_html = ""
|
307 |
+
if is_top_best:
|
308 |
+
try:
|
309 |
+
screenshot_base64 = take_screenshot(raw_url)
|
310 |
+
if screenshot_base64:
|
311 |
+
screenshot_html = f"""
|
312 |
+
<div style="width: 100%; height: 200px; overflow: hidden; border-radius: 10px; margin-bottom: 15px;">
|
313 |
+
<img src="data:image/png;base64,{screenshot_base64}"
|
314 |
+
style="width: 100%; height: 100%; object-fit: cover;"
|
315 |
+
alt="{name} ์คํฌ๋ฆฐ์ท"/>
|
316 |
+
</div>
|
317 |
+
"""
|
318 |
+
except Exception as e:
|
319 |
+
print(f"์คํฌ๋ฆฐ์ท ์ฒ๋ฆฌ ์ค๋ฅ: {str(e)}")
|
320 |
|
321 |
+
bg_color = get_pastel_color(index + (20 if not is_top_best else 0))
|
322 |
tech_emojis = ['โก', '๐', '๐', 'โจ', '๐ซ', '๐ฅ', '๐', '๐ฏ', '๐จ', '๐ฎ']
|
323 |
random_emojis = random.sample(tech_emojis, 3)
|
324 |
|
|
|
325 |
return f"""
|
326 |
<div id="{card_id}" class="vercel-card"
|
327 |
data-likes="0"
|
|
|
336 |
overflow: hidden;'
|
337 |
onmouseover='this.style.transform="translateY(-5px) scale(1.02)"; this.style.boxShadow="0 8px 25px rgba(0,0,0,0.15)"'
|
338 |
onmouseout='this.style.transform="translateY(0) scale(1)"; this.style.boxShadow="0 4px 15px rgba(0,0,0,0.1)"'>
|
339 |
+
{screenshot_html}
|
340 |
<h3 style='color: #2d2d2d;
|
341 |
margin: 0 0 20px 0;
|
342 |
font-size: 1.4em;
|
|
|
344 |
align-items: center;
|
345 |
gap: 10px;'>
|
346 |
<span style='font-size: 1.3em'>{random_emojis[0]}</span>
|
347 |
+
<a href='{url}' target='_blank'
|
348 |
style='text-decoration: none; color: #2d2d2d;'>
|
349 |
{name}
|
350 |
</a>
|
|
|
360 |
<strong>Created:</strong> ๐
{created}
|
361 |
</p>
|
362 |
<p style='margin: 8px 0;'>
|
363 |
+
<strong>URL:</strong> ๐ {url}
|
364 |
</p>
|
365 |
</div>
|
366 |
<div style='margin-top: 20px; display: flex; justify-content: space-between; align-items: center;'>
|
|
|
371 |
</button>
|
372 |
<span class="like-count" style="font-size: 1.2em; color: #666;">0</span>
|
373 |
</div>
|
374 |
+
<a href='{url}' target='_blank'
|
375 |
style='background: linear-gradient(45deg, #0084ff, #00a3ff);
|
376 |
color: white;
|
377 |
padding: 10px 20px;
|
|
|
606 |
# TOP_BEST_URLS ํญ๋ชฉ ์
|
607 |
top_best_count = len(TOP_BEST_URLS)
|
608 |
|
609 |
+
# Vercel API๋ฅผ ํตํ ์ค์ ๋ฐฐํฌ ์
|
610 |
vercel_deployments = get_vercel_deployments()
|
|
|
611 |
actual_vercel_count = len(vercel_deployments) if vercel_deployments else 0
|
612 |
|
613 |
html_content = f"""
|
|
|
630 |
<!-- Top Best -->
|
631 |
<h3 style='color: #333; margin: 20px 0;'>๐ Top Best</h3>
|
632 |
<div style='display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 20px;'>
|
633 |
+
{"".join(get_vercel_card(
|
634 |
+
{"url": url["url"], "created": url["created"], "name": url["name"], "state": url["state"]},
|
635 |
+
idx,
|
636 |
+
is_top_best=True
|
637 |
+
) for idx, url in enumerate(TOP_BEST_URLS))}
|
638 |
</div>
|
639 |
|
640 |
<!-- Vercel Deployments -->
|
|
|
705 |
</script>
|
706 |
"""
|
707 |
|
|
|
708 |
return html_content
|
709 |
|
710 |
except Exception as e:
|
|
|
716 |
<p>Please try again later.</p>
|
717 |
</div>
|
718 |
"""
|
719 |
+
|
720 |
|
721 |
# Creating the Gradio interface
|
722 |
demo = gr.Blocks()
|
723 |
|
724 |
with demo:
|
725 |
+
html_output = gr.HTML(value=get_user_spaces())
|
726 |
|
727 |
if __name__ == "__main__":
|
728 |
+
demo.launch()
|
729 |
+
|
|
|
|