openfree commited on
Commit
9ffe47e
·
verified ·
1 Parent(s): 14aed2b

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +60 -71
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
- USERNAME = "openfree"
17
- SCREENSHOT_CACHE = {}
 
18
 
19
- def take_screenshot(url):
20
- if url in SCREENSHOT_CACHE:
21
- return SCREENSHOT_CACHE[url]
22
-
23
- if not url.startswith('http'):
24
- url = f"https://{url}"
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
- img = Image.open(BytesIO(screenshot))
40
- buffered = BytesIO()
41
- img.save(buffered, format="PNG")
42
- base64_image = base64.b64encode(buffered.getvalue()).decode()
43
- SCREENSHOT_CACHE[url] = base64_image
44
- return base64_image
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 get_pastel_color(index):
53
- pastel_colors = [
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 = take_screenshot(url)
69
- bg_style = f"""
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
- {bg_style}
 
 
 
 
87
  transition: transform 0.3s ease;
88
- cursor: pointer;
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.9);
98
  padding: 15px;
99
  border-radius: 10px;
100
  backdrop-filter: blur(5px);'>
101
- <h3 style='margin: 0; color: #333;'>{title}</h3>
102
- <p style='margin: 5px 0; color: #666;'>Author: {author}</p>
103
- <p style='margin: 5px 0; color: #666;'>SDK: {sdk}</p>
104
  <p style='margin: 5px 0; color: #666;'>❤️ {likes}</p>
105
- <p style='margin: 5px 0; color: #666;'>Created: {created}</p>
106
- <a href='{url}' target='_blank' style='color: blue; text-decoration: none;'>🔗 View</a>
 
 
 
 
 
107
  </div>
108
  </div>
109
  """
110
 
111
- def get_user_spaces(progress=gr.Progress()) -> Tuple[str, str]:
112
- url = f"https://huggingface.co/api/spaces?author={USERNAME}&limit=500"
 
 
113
  try:
114
  progress(0, desc="Fetching spaces data...")
115
  response = requests.get(url)
116
  response.raise_for_status()
117
- spaces_data = response.json()
 
 
 
 
118
 
119
  progress(0.1, desc="Creating gallery...")
120
  html_content = """
121
- <div style='
122
- padding: 20px;
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
- total = len(spaces_data)
131
- for idx, space in enumerate(spaces_data):
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
- with gr.Blocks(title="Hugging Face Space Gallery") as interface:
145
- gr.Markdown("# 🤗 Hugging Face Space Gallery")
146
- gr.Markdown(f"Shows spaces by user: {USERNAME}")
 
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=update,
160
  outputs=[gallery_html, status],
161
  show_progress=True
162
  )
163
 
164
  interface.load(
165
- fn=update,
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