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 import time from pathlib import Path # 추가 # 스크린샷 캐시 디렉토리 설정 CACHE_DIR = Path("screenshot_cache") CACHE_DIR.mkdir(exist_ok=True) # 전역 변수로 스크린샷 캐시 선언 SCREENSHOT_CACHE = {} 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() return take_screenshot(url) def take_screenshot(url): """웹사이트 스크린샷 촬영 함수 (로딩 대기 시간 추가)""" if url in SCREENSHOT_CACHE: return SCREENSHOT_CACHE[url] if not url.startswith('http'): url = f"https://{url}" 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) # 명시적 대기: body 요소가 로드될 때까지 대기 (최대 10초) try: WebDriverWait(driver, 10).until( EC.presence_of_element_located((By.TAG_NAME, "body")) ) except TimeoutException: print(f"페이지 로딩 타임아웃: {url}") # 추가 대기 시간을 2초로 증가 time.sleep(2) # 1초에서 2초로 변경 # JavaScript 실행 완료 대기 driver.execute_script("return document.readyState") == "complete" # 스크린샷 촬영 screenshot = driver.get_screenshot_as_png() img = Image.open(BytesIO(screenshot)) buffered = BytesIO() img.save(buffered, format="PNG") base64_image = base64.b64encode(buffered.getvalue()).decode() # 캐시에 저장 SCREENSHOT_CACHE[url] = base64_image return base64_image except WebDriverException as e: print(f"스크린샷 촬영 실패: {str(e)} for URL: {url}") return None except Exception as e: print(f"예상치 못한 오류: {str(e)} for URL: {url}") return None finally: if 'driver' in locals(): driver.quit() def get_hardware_info(item: dict) -> tuple: """하드웨어 정보 추출""" hardware = item.get('hardware', {}) # CPU 정보 처리 cpu_info = hardware.get('cpu', 'Standard') # GPU 정보 처리 gpu_info = hardware.get('gpu', {}) if isinstance(gpu_info, dict): gpu_name = gpu_info.get('name', '') gpu_memory = gpu_info.get('memory', '') gpu_info = f"{gpu_name} ({gpu_memory}GB)" if gpu_name and gpu_memory else "None" elif isinstance(gpu_info, str): gpu_info = gpu_info if gpu_info else "None" else: gpu_info = "None" # SDK 정보 처리 sdk = item.get('sdk', 'N/A') return cpu_info, gpu_info, sdk def get_card(item: dict, index: int, card_type: str = "space") -> str: """통합 카드 HTML 생성""" item_id = item.get('id', '') author, title = item_id.split('/', 1) likes = format(item.get('likes', 0), ',') created = item.get('createdAt', '').split('T')[0] # URL 정의 if card_type == "space": url = f"https://huggingface.co/spaces/{item_id}" elif card_type == "model": url = f"https://huggingface.co/{item_id}" else: # dataset url = f"https://huggingface.co/datasets/{item_id}" # 메타데이터 처리 tags = item.get('tags', []) pipeline_tag = item.get('pipeline_tag', '') license = item.get('license', '') sdk = item.get('sdk', 'N/A') # 하드웨어 요구사항 처리 hardware = item.get('hardware', {}) cpu_info = hardware.get('cpu', 'Standard') gpu_info = hardware.get('gpu', 'None') if isinstance(gpu_info, dict): gpu_type = gpu_info.get('type', 'N/A') gpu_memory = gpu_info.get('memory', 'N/A') gpu_info = f"{gpu_type} ({gpu_memory}GB)" # 카드 타입별 그라데이션 설정 if card_type == "space": gradient_colors = """ rgba(255, 182, 193, 0.7), /* 파스텔 핑크 */ rgba(173, 216, 230, 0.7), /* 파스텔 블루 */ rgba(255, 218, 185, 0.7) /* 파스텔 피치 */ """ bg_content = f""" background-image: url(data:image/png;base64,{get_cached_screenshot(url) if get_cached_screenshot(url) else ''}); background-size: cover; background-position: center; """ content_bg = f""" background: linear-gradient(135deg, {gradient_colors}); backdrop-filter: blur(10px); """ type_icon = "🎯" type_label = "SPACE" elif card_type == "model": gradient_colors = """ rgba(110, 142, 251, 0.7), /* 모델 블루 */ rgba(130, 158, 251, 0.7), rgba(150, 174, 251, 0.7) """ bg_content = f""" background: linear-gradient(135deg, #6e8efb, #4a6cf7); padding: 15px; """ content_bg = f""" background: linear-gradient(135deg, {gradient_colors}); backdrop-filter: blur(10px); """ type_icon = "🤖" type_label = "MODEL" else: # dataset gradient_colors = """ rgba(255, 107, 107, 0.7), /* 데이터셋 레드 */ rgba(255, 127, 127, 0.7), rgba(255, 147, 147, 0.7) """ bg_content = f""" background: linear-gradient(135deg, #ff6b6b, #ff8787); padding: 15px; """ content_bg = f""" background: linear-gradient(135deg, {gradient_colors}); backdrop-filter: blur(10px); """ type_icon = "📊" type_label = "DATASET" # 하드웨어 정보 가져오기 cpu_info, gpu_info, sdk = get_hardware_info(item) # 하드웨어 정보 HTML hardware_info = f"""