import os import random import base64 import requests from selenium import webdriver from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.common.by import By from selenium.common.exceptions import WebDriverException, TimeoutException from PIL import Image from io import BytesIO from datetime import datetime import gradio as gr from typing import Tuple from pathlib import Path # 스크린샷 캐시 디렉토리 설정 CACHE_DIR = Path("screenshot_cache") CACHE_DIR.mkdir(exist_ok=True) def get_cached_screenshot(url: str) -> str: """캐시된 스크린샷 가져오기 또는 새로 생성""" cache_file = CACHE_DIR / f"{base64.b64encode(url.encode()).decode()}.png" if cache_file.exists(): with open(cache_file, "rb") as f: return base64.b64encode(f.read()).decode() options = webdriver.ChromeOptions() options.add_argument('--headless') options.add_argument('--no-sandbox') options.add_argument('--disable-dev-shm-usage') options.add_argument('--window-size=1080,720') try: driver = webdriver.Chrome(options=options) driver.get(url) WebDriverWait(driver, 10).until( EC.presence_of_element_located((By.TAG_NAME, "body")) ) screenshot = driver.get_screenshot_as_png() # 캐시 파일 저장 with open(cache_file, "wb") as f: f.write(screenshot) return base64.b64encode(screenshot).decode() except Exception as e: print(f"Screenshot error for {url}: {str(e)}") return None finally: if 'driver' in locals(): driver.quit() def get_space_card(space: dict, index: int) -> str: """스페이스 카드 HTML 생성""" space_id = space.get('id', '') author, title = space_id.split('/', 1) likes = format(space.get('likes', 0), ',') sdk = space.get('sdk', 'N/A') created = space.get('createdAt', '').split('T')[0] url = f"https://huggingface.co/spaces/{space_id}" screenshot = get_cached_screenshot(url) bg_color = f"rgba({random.randint(230,255)}, {random.randint(230,255)}, {random.randint(230,255)}, 0.8)" return f"""
#{index + 1} {title}

👤 {author}

🛠️ {sdk}

❤️ {likes}

📅 {created}

🔗 View Space
""" def get_trending_spaces(progress=gr.Progress()) -> Tuple[str, str]: """트렌딩 스페이스 가져오기""" url = "https://huggingface.co/api/spaces" try: progress(0, desc="Fetching spaces data...") response = requests.get(url) response.raise_for_status() spaces = response.json() # 좋아요 수로 정렬하고 상위 10개만 선택 spaces.sort(key=lambda x: x.get('likes', 0), reverse=True) top_spaces = spaces[:10] progress(0.1, desc="Creating gallery...") html_content = """
""" for idx, space in enumerate(top_spaces): author, title = space['id'].split('/', 1) space_url = f"https://huggingface.co/spaces/{space['id']}" likes = format(space.get('likes', 0), ',') created = space.get('createdAt', '').split('T')[0] screenshot = get_cached_screenshot(space_url) bg_color = f"rgba({random.randint(230,255)}, {random.randint(230,255)}, {random.randint(230,255)}, 0.8)" html_content += f"""
#{idx + 1} {title}
👤 {author}
🛠️ {space.get('sdk', 'N/A')}
❤️ {likes}
📅 {created}
""" progress((0.1 + 0.9 * idx/10), desc=f"Loading space {idx+1}/10...") html_content += "
" progress(1.0, desc="Complete!") return html_content, "Gallery refresh complete!" except Exception as e: error_html = f'
Error: {str(e)}
' return error_html, f"Error: {str(e)}" def create_interface(): """Gradio 인터페이스 생성""" with gr.Blocks(title="Hugging Face Trending Spaces") as interface: gr.Markdown("# 🤗 Hugging Face Top 10 Trending Spaces") gr.Markdown("Shows top 10 most liked spaces on Hugging Face") with gr.Row(): refresh_btn = gr.Button("Refresh Gallery", variant="primary") gallery_html = gr.HTML() status = gr.Markdown("Ready") refresh_btn.click( fn=get_trending_spaces, outputs=[gallery_html, status], show_progress=True ) interface.load( fn=get_trending_spaces, outputs=[gallery_html, status] ) return interface if __name__ == "__main__": try: demo = create_interface() demo.launch( share=True, inbrowser=True, show_api=False ) except Exception as e: print(f"Error launching app: {e}")