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") target_models = { "openfree/flux-lora-korea-palace": "https://huggingface.co/openfree/flux-lora-korea-palace", "seawolf2357/hanbok": "https://huggingface.co/seawolf2357/hanbok", "LGAI-EXAONE/EXAONE-3.5-32B-Instruct": "https://huggingface.co/LGAI-EXAONE/EXAONE-3.5-32B-Instruct", "LGAI-EXAONE/EXAONE-3.5-2.4B-Instruct": "https://huggingface.co/LGAI-EXAONE/EXAONE-3.5-2.4B-Instruct", "LGAI-EXAONE/EXAONE-3.5-7.8B-Instruct": "https://huggingface.co/LGAI-EXAONE/EXAONE-3.5-7.8B-Instruct", "ginipick/flux-lora-eric-cat": "https://huggingface.co/ginipick/flux-lora-eric-cat", "seawolf2357/flux-lora-car-rolls-royce": "https://huggingface.co/seawolf2357/flux-lora-car-rolls-royce" } def get_models_data(progress=gr.Progress()): """모델 데이터 가져오기""" url = "https://huggingface.co/api/models" params = { 'full': 'true', 'limit': 300 # 스페이스와 동일하게 300개로 설정 } try: progress(0, desc="Fetching models data...") response = requests.get(url, params=params) if response.status_code != 200: print(f"API 요청 실패: {response.status_code}") print(f"Response: {response.text}") print(f"URL: {url}") return create_error_plot(), "
모델 데이터를 가져오는데 실패했습니다.
", pd.DataFrame() all_models = response.json() # target_models에 있는 모델만 필터링 filtered_models = [] for model in all_models: if model.get('id', '') in target_models: model['rank'] = len(filtered_models) + 1 filtered_models.append(model) if not filtered_models: return create_error_plot(), "
선택된 모델의 데이터를 찾을 수 없습니다.
", pd.DataFrame() progress(0.3, desc="Creating visualization...") # 시각화 생성 fig = go.Figure() # 데이터 준비 ids = [model['id'] for model in filtered_models] ranks = [model['rank'] for model in filtered_models] likes = [model.get('likes', 0) for model in filtered_models] # Y축 값을 반전 (300 - rank + 1) y_values = [301 - r for r in ranks] # 막대 그래프 생성 fig.add_trace(go.Bar( x=ids, y=y_values, text=[f"Rank: {r}
Likes: {l}" for r, l in zip(ranks, likes)], textposition='auto', marker_color='rgb(158,202,225)', opacity=0.8 )) fig.update_layout( title={ 'text': 'Hugging Face Models Rankings (Top 300)', 'y':0.95, 'x':0.5, 'xanchor': 'center', 'yanchor': 'top' }, xaxis_title='Model ID', yaxis_title='Rank', yaxis=dict( ticktext=[str(i) for i in range(1, 301, 20)], tickvals=[301 - i for i in range(1, 301, 20)], range=[0, 300] ), height=800, showlegend=False, template='plotly_white', xaxis_tickangle=-45 ) progress(0.6, desc="Creating model cards...") # HTML 카드 생성 html_content = """

Models Rankings

""" for model in filtered_models: model_id = model.get('id', '') rank = model.get('rank', 'N/A') likes = model.get('likes', 0) downloads = model.get('downloads', 0) html_content += f"""

Rank #{rank} - {model_id}

👍 Likes: {likes}

⬇️ Downloads: {downloads}

Visit Model 🔗
""" html_content += "
" # 데이터프레임 생성 df = pd.DataFrame([{ 'Rank': model.get('rank', 'N/A'), 'Model ID': model.get('id', ''), 'Likes': model.get('likes', 'N/A'), 'Downloads': model.get('downloads', 'N/A'), 'URL': target_models[model.get('id', '')] } for model in filtered_models]) progress(1.0, desc="Complete!") return fig, html_content, df except Exception as e: print(f"Error in get_models_data: {str(e)}") return create_error_plot(), f"
에러 발생: {str(e)}
", pd.DataFrame() # 관심 스페이스 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_spaces_data(sort_type="trending", progress=gr.Progress()): """스페이스 데이터 가져오기 (trending 또는 modes)""" url = f"https://huggingface.co/api/spaces" params = { 'full': 'true', 'limit': 300 } if sort_type == "modes": params['sort'] = 'likes' # modes는 좋아요 순으로 정렬 try: progress(0, desc=f"Fetching {sort_type} spaces data...") response = requests.get(url, params=params) response.raise_for_status() all_spaces = response.json() # 순위 정보 저장 space_ranks = {space['id']: idx + 1 for idx, space in enumerate(all_spaces)} # target_spaces 필터링 및 순위 정보 포함 spaces = [] for space in all_spaces: if space.get('id', '') in target_spaces: space['rank'] = space_ranks.get(space['id'], 'N/A') spaces.append(space) # 순위별로 정렬 spaces.sort(key=lambda x: x['rank']) progress(0.3, desc="Creating visualization...") # 시각화 생성 fig = go.Figure() # 데이터 준비 ids = [space['id'] for space in spaces] ranks = [space['rank'] for space in spaces] likes = [space.get('likes', 0) for space in spaces] # Y축 값을 반전 (300 - rank + 1) y_values = [301 - r for r in ranks] # 순위를 반전된 값으로 변환 # 막대 그래프 생성 fig.add_trace(go.Bar( x=ids, y=y_values, text=[f"Rank: {r}
Likes: {l}" for r, l in zip(ranks, likes)], textposition='auto', marker_color='rgb(158,202,225)', opacity=0.8 )) fig.update_layout( title={ 'text': f'Hugging Face Spaces {sort_type.title()} Rankings (Top 300)', 'y':0.95, 'x':0.5, 'xanchor': 'center', 'yanchor': 'top' }, xaxis_title='Space ID', yaxis_title='Rank', yaxis=dict( ticktext=[str(i) for i in range(1, 301, 20)], # 1부터 300까지 20 간격 tickvals=[301 - i for i in range(1, 301, 20)], # 반전된 값 range=[0, 300] # y축 범위 설정 ), height=800, showlegend=False, template='plotly_white', xaxis_tickangle=-45 ) progress(0.6, desc="Creating space cards...") # HTML 카드 생성 html_content = f"""

{sort_type.title()} Rankings

""" for space in spaces: space_id = space.get('id', '') rank = space.get('rank', 'N/A') likes = space.get('likes', 0) title = space.get('title', 'No Title') description = space.get('description', 'No Description')[:100] html_content += f"""

Rank #{rank} - {space_id}

👍 Likes: {likes}

{title}

{description}...

Visit Space 🔗
""" html_content += "
" # 데이터프레임 생성 df = pd.DataFrame([{ 'Rank': space.get('rank', 'N/A'), 'Space ID': space.get('id', ''), 'Likes': space.get('likes', 'N/A'), 'Title': space.get('title', 'N/A'), 'URL': target_spaces[space.get('id', '')] } for space in spaces]) progress(1.0, desc="Complete!") return fig, html_content, df except Exception as e: error_html = f'
Error: {str(e)}
' error_plot = create_error_plot() return error_plot, error_html, pd.DataFrame() 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), 'title': space.get('title', 'N/A'), 'views': space.get('views', 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] views = [r['views'] for r in ranks] # 막대 그래프 생성 fig.add_trace(go.Bar( x=ids, y=rank_values, text=[f"Rank: {r}
Likes: {l}
Views: {v}" for r, l, v in zip(rank_values, likes, views)], textposition='auto', marker_color='rgb(158,202,225)', opacity=0.8 )) fig.update_layout( title={ 'text': 'Current Trending Ranks (All Target Spaces)', 'y':0.95, 'x':0.5, 'xanchor': 'center', 'yanchor': 'top' }, xaxis_title='Space ID', yaxis_title='Trending Rank', yaxis_autorange='reversed', height=800, showlegend=False, template='plotly_white', xaxis_tickangle=-45 ) return fig # 토큰이 없는 경우를 위한 대체 함수 def get_trending_spaces_without_token(): try: url = "https://huggingface.co/api/spaces" params = { 'sort': 'likes', 'direction': -1, 'limit': 1000, 'full': 'true' } response = requests.get(url, params=params) 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 # API 토큰 설정 및 함수 선택 if not HF_TOKEN: get_trending_spaces = get_trending_spaces_without_token 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_space_info_html(spaces_data): if not spaces_data: return "

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

" html_content = """

Current Trending Rankings

""" # 모든 target spaces를 포함하도록 수정 for space_id in target_spaces.keys(): space_info = next((s for s in spaces_data if s.get('id') == space_id), None) if space_info: rank = next((idx for idx, s in enumerate(spaces_data, 1) if s.get('id') == space_id), 'N/A') html_content += f"""

#{rank} - {space_id}

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

👀 Views: {space_info.get('views', 'N/A')}

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

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

Visit Space 🔗
""" else: html_content += f"""

{space_id}

Not in trending

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() with gr.Blocks(theme=gr.themes.Soft()) as demo: gr.Markdown(""" # 🤗 허깅페이스 '한국 리더보드' 실시간으로 Hugging Face의 Spaces와 Models 인기 순위를 분석합니다. 신규 등록 요청: arxivgpt@gmail.com """) with gr.Tab("Spaces Trending"): trending_plot = gr.Plot() trending_info = gr.HTML() trending_df = gr.DataFrame() with gr.Tab("Models Trending"): models_plot = gr.Plot() models_info = gr.HTML() models_df = gr.DataFrame() refresh_btn = gr.Button("🔄 Refresh Data", variant="primary") def refresh_all_data(): spaces_results = get_spaces_data("trending") models_results = get_models_data() return [*spaces_results, *models_results] refresh_btn.click( refresh_all_data, outputs=[ trending_plot, trending_info, trending_df, models_plot, models_info, models_df ] ) # 초기 데이터 로드 spaces_results = get_spaces_data("trending") models_results = get_models_data() trending_plot.value, trending_info.value, trending_df.value = spaces_results models_plot.value, models_info.value, models_df.value = models_results # Gradio 앱 실행 demo.launch( server_name="0.0.0.0", server_port=7860, share=False )