import gradio as gr import requests import pandas as pd import plotly.graph_objects as go from datetime import datetime import os HF_TOKEN = os.getenv('HF_TOKEN') # 관심 스페이스 URL 리스트와 정보 target_spaces = { "ginipick/FLUXllama": "https://huggingface.co/spaces/ginipick/FLUXllama", "ginipick/SORA-3D": "https://huggingface.co/spaces/ginipick/SORA-3D", "fantaxy/Sound-AI-SFX": "https://huggingface.co/spaces/fantaxy/Sound-AI-SFX", "fantos/flx8lora": "https://huggingface.co/spaces/fantos/flx8lora", "ginigen/Canvas": "https://huggingface.co/spaces/ginigen/Canvas", "fantaxy/erotica": "https://huggingface.co/spaces/fantaxy/erotica", "ginipick/time-machine": "https://huggingface.co/spaces/ginipick/time-machine", "aiqcamp/FLUX-VisionReply": "https://huggingface.co/spaces/aiqcamp/FLUX-VisionReply", "openfree/Tetris-Game": "https://huggingface.co/spaces/openfree/Tetris-Game", "openfree/everychat": "https://huggingface.co/spaces/openfree/everychat", "VIDraft/mouse1": "https://huggingface.co/spaces/VIDraft/mouse1", "kolaslab/alpha-go": "https://huggingface.co/spaces/kolaslab/alpha-go", "ginipick/text3d": "https://huggingface.co/spaces/ginipick/text3d", "openfree/trending-board": "https://huggingface.co/spaces/openfree/trending-board", "cutechicken/tankwar": "https://huggingface.co/spaces/cutechicken/tankwar", "openfree/game-jewel": "https://huggingface.co/spaces/openfree/game-jewel", "VIDraft/mouse-chat": "https://huggingface.co/spaces/VIDraft/mouse-chat", "ginipick/AccDiffusion": "https://huggingface.co/spaces/ginipick/AccDiffusion", "aiqtech/Particle-Accelerator-Simulation": "https://huggingface.co/spaces/aiqtech/Particle-Accelerator-Simulation", "openfree/GiniGEN": "https://huggingface.co/spaces/openfree/GiniGEN", "kolaslab/3DAudio-Spectrum-Analyzer": "https://huggingface.co/spaces/kolaslab/3DAudio-Spectrum-Analyzer", "openfree/trending-news-24": "https://huggingface.co/spaces/openfree/trending-news-24", "ginipick/Realtime-FLUX": "https://huggingface.co/spaces/ginipick/Realtime-FLUX", "VIDraft/prime-number": "https://huggingface.co/spaces/VIDraft/prime-number", "kolaslab/zombie-game": "https://huggingface.co/spaces/kolaslab/zombie-game", "fantos/miro-game": "https://huggingface.co/spaces/fantos/miro-game", "kolaslab/shooting": "https://huggingface.co/spaces/kolaslab/shooting", "VIDraft/Mouse-Hackathon": "https://huggingface.co/spaces/VIDraft/Mouse-Hackathon", "upstage/open-ko-llm-leaderboard": "https://huggingface.co/spaces/upstage/open-ko-llm-leaderboard", "LGAI-EXAONE/EXAONE-3.5-Instruct-Demo": "https://huggingface.co/spaces/LGAI-EXAONE/EXAONE-3.5-Instruct-Demo", "NCSOFT/VARCO_Arena": "https://huggingface.co/spaces/NCSOFT/VARCO_Arena" } def get_trending_spaces(): try: url = "https://huggingface.co/api/spaces/sort/trending" headers = { 'Authorization': f'Bearer {HF_TOKEN}', 'Accept': 'application/json' } response = requests.get(url, headers=headers) if response.status_code == 200: return response.json() else: print(f"API 요청 실패: {response.status_code}") print(f"Response: {response.text}") return None except Exception as e: print(f"API 호출 중 에러 발생: {str(e)}") return None def create_error_plot(): fig = go.Figure() fig.add_annotation( text="데이터를 불러올 수 없습니다.\n(API 인증이 필요합니다)", xref="paper", yref="paper", x=0.5, y=0.5, showarrow=False, font=dict(size=20) ) fig.update_layout( title="Error Loading Data", height=400 ) return fig def create_trend_visualization(spaces_data): if not spaces_data: return create_error_plot() fig = go.Figure() # 타겟 스페이스들의 순위 찾기 ranks = [] for idx, space in enumerate(spaces_data, 1): space_id = space.get('id', '') if space_id in target_spaces: ranks.append({ 'id': space_id, 'rank': idx, 'likes': space.get('likes', 0) }) if not ranks: return create_error_plot() # 순위별로 정렬 ranks.sort(key=lambda x: x['rank']) # 플롯 데이터 생성 ids = [r['id'] for r in ranks] rank_values = [r['rank'] for r in ranks] likes = [r['likes'] for r in ranks] # 막대 그래프 생성 fig.add_trace(go.Bar( x=ids, y=rank_values, text=[f"Rank: {r}
Likes: {l}" for r, l in zip(rank_values, likes)], textposition='auto', marker_color='rgb(158,202,225)', opacity=0.8 )) fig.update_layout( title={ 'text': 'Current Trending Ranks', 'y':0.95, 'x':0.5, 'xanchor': 'center', 'yanchor': 'top' }, xaxis_title='Space ID', yaxis_title='Rank', yaxis_autorange='reversed', height=600, showlegend=False, template='plotly_white' ) return fig def create_space_info_html(spaces_data): if not spaces_data: return "

데이터를 불러오는데 실패했습니다.

" html_content = """

Current Rankings

""" for idx, space in enumerate(spaces_data, 1): space_id = space.get('id', '') if space_id in target_spaces: html_content += f"""

#{idx} - {space_id}

👍 Likes: {space.get('likes', 'N/A')}

{space.get('title', 'N/A')}

{space.get('description', 'N/A')[:100]}...

Visit Space 🔗
""" html_content += "
" return html_content def create_data_table(spaces_data): if not spaces_data: return pd.DataFrame() rows = [] for idx, space in enumerate(spaces_data, 1): space_id = space.get('id', '') if space_id in target_spaces: rows.append({ 'Rank': idx, 'Space ID': space_id, 'Likes': space.get('likes', 'N/A'), 'Title': space.get('title', 'N/A'), 'URL': target_spaces[space_id] }) return pd.DataFrame(rows) def refresh_data(): spaces_data = get_trending_spaces() if spaces_data: plot = create_trend_visualization(spaces_data) info = create_space_info_html(spaces_data) df = create_data_table(spaces_data) return plot, info, df else: return create_error_plot(), "
API 인증이 필요합니다.
", pd.DataFrame() # Gradio 인터페이스 생성 with gr.Blocks(theme=gr.themes.Soft()) as demo: gr.Markdown(""" # 🤗 HuggingFace Spaces Trending Analysis 실시간으로 Hugging Face Spaces의 트렌딩 순위를 분석합니다. """) with gr.Tab("Trending Analysis"): plot_output = gr.Plot() info_output = gr.HTML() with gr.Tab("Export Data"): df_output = gr.DataFrame() refresh_btn = gr.Button("🔄 Refresh Data", variant="primary") refresh_btn.click( refresh_data, outputs=[plot_output, info_output, df_output] ) # 초기 데이터 로드 initial_plot, initial_info, initial_df = refresh_data() plot_output.value = initial_plot info_output.value = initial_info df_output.value = initial_df # Gradio 앱 실행 demo.launch()