Spaces:
Building
on
CPU Upgrade
Building
on
CPU Upgrade
Update app.py
Browse files
app.py
CHANGED
@@ -12,17 +12,20 @@ from io import BytesIO
|
|
12 |
from datetime import datetime
|
13 |
import gradio as gr
|
14 |
from typing import Tuple
|
|
|
15 |
|
16 |
-
|
17 |
-
|
|
|
18 |
|
19 |
-
def
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
if
|
24 |
-
|
25 |
-
|
|
|
26 |
options = webdriver.ChromeOptions()
|
27 |
options.add_argument('--headless')
|
28 |
options.add_argument('--no-sandbox')
|
@@ -36,12 +39,12 @@ def take_screenshot(url):
|
|
36 |
EC.presence_of_element_located((By.TAG_NAME, "body"))
|
37 |
)
|
38 |
screenshot = driver.get_screenshot_as_png()
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
return
|
45 |
except Exception as e:
|
46 |
print(f"Screenshot error for {url}: {str(e)}")
|
47 |
return None
|
@@ -49,15 +52,8 @@ def take_screenshot(url):
|
|
49 |
if 'driver' in locals():
|
50 |
driver.quit()
|
51 |
|
52 |
-
def
|
53 |
-
|
54 |
-
'rgba(255, 230, 230, 0.8)', 'rgba(255, 230, 255, 0.8)',
|
55 |
-
'rgba(230, 230, 255, 0.8)', 'rgba(230, 255, 255, 0.8)',
|
56 |
-
'rgba(230, 255, 230, 0.8)'
|
57 |
-
]
|
58 |
-
return pastel_colors[index % len(pastel_colors)]
|
59 |
-
|
60 |
-
def get_space_card(space, index):
|
61 |
space_id = space.get('id', '')
|
62 |
author, title = space_id.split('/', 1)
|
63 |
likes = format(space.get('likes', 0), ',')
|
@@ -65,85 +61,82 @@ def get_space_card(space, index):
|
|
65 |
created = space.get('createdAt', '').split('T')[0]
|
66 |
url = f"https://huggingface.co/spaces/{space_id}"
|
67 |
|
68 |
-
screenshot =
|
69 |
-
|
70 |
-
background-image: linear-gradient(
|
71 |
-
{get_pastel_color(index)},
|
72 |
-
{get_pastel_color(index)}
|
73 |
-
), url(data:image/png;base64,{screenshot});
|
74 |
-
background-size: cover;
|
75 |
-
background-position: center;
|
76 |
-
background-blend-mode: overlay;
|
77 |
-
""" if screenshot else f"background-color: {get_pastel_color(index)};"
|
78 |
|
79 |
return f"""
|
80 |
-
<div style='
|
81 |
border: none;
|
82 |
padding: 20px;
|
83 |
margin: 10px;
|
84 |
border-radius: 15px;
|
85 |
box-shadow: 0 4px 8px rgba(0,0,0,0.1);
|
86 |
-
{
|
|
|
|
|
|
|
|
|
87 |
transition: transform 0.3s ease;
|
88 |
-
|
89 |
-
position: relative;
|
90 |
-
overflow: hidden;
|
91 |
-
min-height: 200px;'
|
92 |
-
onclick="window.open('{url}', '_blank')"
|
93 |
-
onmouseover="this.style.transform='scale(1.02)'"
|
94 |
-
onmouseout="this.style.transform='scale(1)'">
|
95 |
|
96 |
<div style='
|
97 |
-
background: rgba(255, 255, 255, 0.
|
98 |
padding: 15px;
|
99 |
border-radius: 10px;
|
100 |
backdrop-filter: blur(5px);'>
|
101 |
-
<
|
102 |
-
<p style='margin: 5px 0; color: #666;'
|
103 |
-
<p style='margin: 5px 0; color: #666;'
|
104 |
<p style='margin: 5px 0; color: #666;'>❤️ {likes}</p>
|
105 |
-
<p style='margin: 5px 0; color: #666;'
|
106 |
-
<a href='{url}' target='_blank'
|
|
|
|
|
|
|
|
|
|
|
107 |
</div>
|
108 |
</div>
|
109 |
"""
|
110 |
|
111 |
-
def
|
112 |
-
|
|
|
|
|
113 |
try:
|
114 |
progress(0, desc="Fetching spaces data...")
|
115 |
response = requests.get(url)
|
116 |
response.raise_for_status()
|
117 |
-
|
|
|
|
|
|
|
|
|
118 |
|
119 |
progress(0.1, desc="Creating gallery...")
|
120 |
html_content = """
|
121 |
-
<div style='
|
122 |
-
|
123 |
-
background: #f5f5f5;'>
|
124 |
-
<div style='
|
125 |
-
display: grid;
|
126 |
-
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
|
127 |
-
gap: 20px;'>
|
128 |
"""
|
129 |
|
130 |
-
|
131 |
-
|
132 |
-
progress((0.1 + 0.9 * idx/total), desc=f"Loading space {idx+1}/{total}...")
|
133 |
html_content += get_space_card(space, idx)
|
134 |
|
135 |
html_content += "</div></div>"
|
136 |
|
137 |
progress(1.0, desc="Complete!")
|
138 |
return html_content, "Gallery refresh complete!"
|
|
|
139 |
except Exception as e:
|
140 |
error_html = f'<div style="color: red; padding: 20px;">Error: {str(e)}</div>'
|
141 |
return error_html, f"Error: {str(e)}"
|
142 |
|
143 |
def create_interface():
|
144 |
-
|
145 |
-
|
146 |
-
gr.Markdown(
|
|
|
147 |
|
148 |
with gr.Row():
|
149 |
refresh_btn = gr.Button("Refresh Gallery", variant="primary")
|
@@ -151,18 +144,14 @@ def create_interface():
|
|
151 |
gallery_html = gr.HTML()
|
152 |
status = gr.Markdown("Ready")
|
153 |
|
154 |
-
def update():
|
155 |
-
html, status_text = get_user_spaces()
|
156 |
-
return [html, status_text]
|
157 |
-
|
158 |
refresh_btn.click(
|
159 |
-
fn=
|
160 |
outputs=[gallery_html, status],
|
161 |
show_progress=True
|
162 |
)
|
163 |
|
164 |
interface.load(
|
165 |
-
fn=
|
166 |
outputs=[gallery_html, status]
|
167 |
)
|
168 |
|
|
|
12 |
from datetime import datetime
|
13 |
import gradio as gr
|
14 |
from typing import Tuple
|
15 |
+
from pathlib import Path
|
16 |
|
17 |
+
# 스크린샷 캐시 디렉토리 설정
|
18 |
+
CACHE_DIR = Path("screenshot_cache")
|
19 |
+
CACHE_DIR.mkdir(exist_ok=True)
|
20 |
|
21 |
+
def get_cached_screenshot(url: str) -> str:
|
22 |
+
"""캐시된 스크린샷 가져오기 또는 새로 생성"""
|
23 |
+
cache_file = CACHE_DIR / f"{base64.b64encode(url.encode()).decode()}.png"
|
24 |
+
|
25 |
+
if cache_file.exists():
|
26 |
+
with open(cache_file, "rb") as f:
|
27 |
+
return base64.b64encode(f.read()).decode()
|
28 |
+
|
29 |
options = webdriver.ChromeOptions()
|
30 |
options.add_argument('--headless')
|
31 |
options.add_argument('--no-sandbox')
|
|
|
39 |
EC.presence_of_element_located((By.TAG_NAME, "body"))
|
40 |
)
|
41 |
screenshot = driver.get_screenshot_as_png()
|
42 |
+
|
43 |
+
# 캐시 파일 저장
|
44 |
+
with open(cache_file, "wb") as f:
|
45 |
+
f.write(screenshot)
|
46 |
+
|
47 |
+
return base64.b64encode(screenshot).decode()
|
48 |
except Exception as e:
|
49 |
print(f"Screenshot error for {url}: {str(e)}")
|
50 |
return None
|
|
|
52 |
if 'driver' in locals():
|
53 |
driver.quit()
|
54 |
|
55 |
+
def get_space_card(space: dict, index: int) -> str:
|
56 |
+
"""스페이스 카드 HTML 생성"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
57 |
space_id = space.get('id', '')
|
58 |
author, title = space_id.split('/', 1)
|
59 |
likes = format(space.get('likes', 0), ',')
|
|
|
61 |
created = space.get('createdAt', '').split('T')[0]
|
62 |
url = f"https://huggingface.co/spaces/{space_id}"
|
63 |
|
64 |
+
screenshot = get_cached_screenshot(url)
|
65 |
+
bg_color = f"rgba({random.randint(230,255)}, {random.randint(230,255)}, {random.randint(230,255)}, 0.8)"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
66 |
|
67 |
return f"""
|
68 |
+
<div class="space-card" style='
|
69 |
border: none;
|
70 |
padding: 20px;
|
71 |
margin: 10px;
|
72 |
border-radius: 15px;
|
73 |
box-shadow: 0 4px 8px rgba(0,0,0,0.1);
|
74 |
+
background-image: linear-gradient({bg_color}, {bg_color}),
|
75 |
+
url(data:image/png;base64,{screenshot if screenshot else ''});
|
76 |
+
background-size: cover;
|
77 |
+
background-position: center;
|
78 |
+
background-blend-mode: overlay;
|
79 |
transition: transform 0.3s ease;
|
80 |
+
min-height: 200px;'>
|
|
|
|
|
|
|
|
|
|
|
|
|
81 |
|
82 |
<div style='
|
83 |
+
background: rgba(255, 255, 255, 0.95);
|
84 |
padding: 15px;
|
85 |
border-radius: 10px;
|
86 |
backdrop-filter: blur(5px);'>
|
87 |
+
<div style='font-size: 1.2em; font-weight: bold; color: #333;'>#{index + 1} {title}</div>
|
88 |
+
<p style='margin: 5px 0; color: #666;'>👤 {author}</p>
|
89 |
+
<p style='margin: 5px 0; color: #666;'>🛠️ {sdk}</p>
|
90 |
<p style='margin: 5px 0; color: #666;'>❤️ {likes}</p>
|
91 |
+
<p style='margin: 5px 0; color: #666;'>📅 {created}</p>
|
92 |
+
<a href='{url}' target='_blank'
|
93 |
+
style='display: inline-block; margin-top: 10px; padding: 5px 10px;
|
94 |
+
background: #007bff; color: white; text-decoration: none;
|
95 |
+
border-radius: 5px;'>
|
96 |
+
🔗 View Space
|
97 |
+
</a>
|
98 |
</div>
|
99 |
</div>
|
100 |
"""
|
101 |
|
102 |
+
def get_trending_spaces(progress=gr.Progress()) -> Tuple[str, str]:
|
103 |
+
"""트렌딩 스페이스 가져오기"""
|
104 |
+
url = "https://huggingface.co/api/spaces"
|
105 |
+
|
106 |
try:
|
107 |
progress(0, desc="Fetching spaces data...")
|
108 |
response = requests.get(url)
|
109 |
response.raise_for_status()
|
110 |
+
spaces = response.json()
|
111 |
+
|
112 |
+
# 좋아요 수로 정렬하고 상위 10개만 선택
|
113 |
+
spaces.sort(key=lambda x: x.get('likes', 0), reverse=True)
|
114 |
+
top_spaces = spaces[:10]
|
115 |
|
116 |
progress(0.1, desc="Creating gallery...")
|
117 |
html_content = """
|
118 |
+
<div style='padding: 20px; background: #f5f5f5;'>
|
119 |
+
<div style='display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 20px;'>
|
|
|
|
|
|
|
|
|
|
|
120 |
"""
|
121 |
|
122 |
+
for idx, space in enumerate(top_spaces):
|
123 |
+
progress((0.1 + 0.9 * idx/10), desc=f"Loading space {idx+1}/10...")
|
|
|
124 |
html_content += get_space_card(space, idx)
|
125 |
|
126 |
html_content += "</div></div>"
|
127 |
|
128 |
progress(1.0, desc="Complete!")
|
129 |
return html_content, "Gallery refresh complete!"
|
130 |
+
|
131 |
except Exception as e:
|
132 |
error_html = f'<div style="color: red; padding: 20px;">Error: {str(e)}</div>'
|
133 |
return error_html, f"Error: {str(e)}"
|
134 |
|
135 |
def create_interface():
|
136 |
+
"""Gradio 인터페이스 생성"""
|
137 |
+
with gr.Blocks(title="Hugging Face Trending Spaces") as interface:
|
138 |
+
gr.Markdown("# 🤗 Hugging Face Trending Spaces")
|
139 |
+
gr.Markdown("Shows top 10 trending spaces on Hugging Face")
|
140 |
|
141 |
with gr.Row():
|
142 |
refresh_btn = gr.Button("Refresh Gallery", variant="primary")
|
|
|
144 |
gallery_html = gr.HTML()
|
145 |
status = gr.Markdown("Ready")
|
146 |
|
|
|
|
|
|
|
|
|
147 |
refresh_btn.click(
|
148 |
+
fn=get_trending_spaces,
|
149 |
outputs=[gallery_html, status],
|
150 |
show_progress=True
|
151 |
)
|
152 |
|
153 |
interface.load(
|
154 |
+
fn=get_trending_spaces,
|
155 |
outputs=[gallery_html, status]
|
156 |
)
|
157 |
|