ginipick commited on
Commit
b867b8e
·
verified ·
1 Parent(s): 6171c3e

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +323 -0
app.py ADDED
@@ -0,0 +1,323 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import pandas as pd
3
+ import plotly.express as px
4
+ from datetime import datetime, timedelta
5
+ import requests
6
+ from io import BytesIO
7
+
8
+ def create_trend_chart(space_id, daily_ranks_df):
9
+ if space_id is None or daily_ranks_df.empty:
10
+ return None
11
+
12
+ try:
13
+ space_data = daily_ranks_df[daily_ranks_df['id'] == space_id].copy()
14
+ if space_data.empty:
15
+ return None
16
+
17
+ space_data = space_data.sort_values('date')
18
+
19
+ fig = px.line(
20
+ space_data,
21
+ x='date',
22
+ y='rank',
23
+ title=f'Daily Rank Trend for {space_id}',
24
+ labels={'date': 'Date', 'rank': 'Rank'},
25
+ markers=True,
26
+ height=400
27
+ )
28
+
29
+ fig.update_layout(
30
+ xaxis_title="Date",
31
+ yaxis_title="Rank",
32
+ yaxis=dict(
33
+ range=[100, 1],
34
+ tickmode='linear',
35
+ tick0=1,
36
+ dtick=10
37
+ ),
38
+ hovermode='x unified',
39
+ plot_bgcolor='white',
40
+ paper_bgcolor='white',
41
+ showlegend=False,
42
+ margin=dict(t=50, r=20, b=40, l=40)
43
+ )
44
+
45
+ fig.update_xaxes(showgrid=True, gridwidth=1, gridcolor='lightgray')
46
+ fig.update_yaxes(showgrid=True, gridwidth=1, gridcolor='lightgray')
47
+
48
+ fig.update_traces(
49
+ line_color='#2563eb',
50
+ line_width=2,
51
+ marker=dict(size=8, color='#2563eb')
52
+ )
53
+
54
+ return fig
55
+ except Exception as e:
56
+ print(f"Error creating chart: {e}")
57
+ return None
58
+
59
+ def get_duplicate_spaces(top_100_spaces):
60
+ # ID별 등장 횟수 계산
61
+ id_counts = top_100_spaces['id'].value_counts()
62
+ # 2회 이상 등장하는 ID만 필터링하고 내림차순 정렬
63
+ duplicates = id_counts[id_counts >= 2].sort_values(ascending=False)
64
+ return duplicates
65
+
66
+ def create_duplicates_chart(duplicates):
67
+ if duplicates.empty:
68
+ return None
69
+
70
+ # 데이터프레임으로 변환하여 그래프 생성
71
+ df = pd.DataFrame({'id': duplicates.index, 'count': duplicates.values}).reset_index(drop=True)
72
+
73
+ fig = px.bar(
74
+ df,
75
+ x='count',
76
+ y='id',
77
+ orientation='h', # 수평 막대 그래프
78
+ title="Spaces with Multiple Entries in Top 100",
79
+ labels={'count': 'Number of Entries', 'id': 'Space ID'},
80
+ height=400,
81
+ text='count' # 값 표시
82
+ )
83
+
84
+ fig.update_layout(
85
+ showlegend=False,
86
+ margin=dict(t=50, r=20, b=40, l=200), # 왼쪽 여백 증가
87
+ plot_bgcolor='white',
88
+ paper_bgcolor='white',
89
+ yaxis={'categoryorder': 'total ascending'}, # ID를 값에 따라 정렬
90
+ xaxis_title="Number of Entries",
91
+ yaxis_title="Space ID",
92
+ hoverlabel=dict(bgcolor="white"),
93
+ hovermode='y'
94
+ )
95
+
96
+ fig.update_traces(
97
+ marker_color='#4CAF50',
98
+ textposition='outside',
99
+ textfont=dict(size=12)
100
+ )
101
+
102
+ # 그리드 추가
103
+ fig.update_xaxes(showgrid=True, gridwidth=1, gridcolor='lightgray')
104
+
105
+ return fig
106
+
107
+ def update_display(selection):
108
+ global daily_ranks_df
109
+
110
+ if not selection:
111
+ return None, gr.HTML(value="<div style='text-align: center; padding: 20px; color: #666;'>Select a space to view details</div>")
112
+
113
+ try:
114
+ space_id = selection
115
+
116
+ latest_data = daily_ranks_df[
117
+ daily_ranks_df['id'] == space_id
118
+ ].sort_values('date').iloc[-1]
119
+
120
+ info_text = f"""
121
+ <div style="padding: 16px; background-color: white; border-radius: 8px; box-shadow: 0 1px 3px rgba(0,0,0,0.1);">
122
+ <h3 style="margin: 0 0 12px 0;">Space Details</h3>
123
+ <p style="margin: 4px 0;"><strong>ID:</strong> {space_id}</p>
124
+ <p style="margin: 4px 0;"><strong>Current Rank:</strong> {int(latest_data['rank'])}</p>
125
+ <p style="margin: 4px 0;"><strong>Trending Score:</strong> {latest_data['trendingScore']:.2f}</p>
126
+ <p style="margin: 4px 0;"><strong>Created At:</strong> {latest_data['createdAt'].strftime('%Y-%m-%d')}</p>
127
+ <p style="margin: 12px 0 0 0;">
128
+ <a href="https://huggingface.co/spaces/{space_id}"
129
+ target="_blank"
130
+ style="color: #2563eb; text-decoration: none;">
131
+ View Space ↗
132
+ </a>
133
+ </p>
134
+ </div>
135
+ """
136
+
137
+ chart = create_trend_chart(space_id, daily_ranks_df)
138
+
139
+ return chart, gr.HTML(value=info_text)
140
+
141
+ except Exception as e:
142
+ print(f"Error in update_display: {e}")
143
+ return None, gr.HTML(value=f"<div style='color: red;'>Error processing data: {str(e)}</div>")
144
+
145
+ def load_and_process_data():
146
+ try:
147
+ url = "https://huggingface.co/datasets/cfahlgren1/hub-stats/resolve/main/spaces.parquet"
148
+ response = requests.get(url)
149
+ df = pd.read_parquet(BytesIO(response.content))
150
+
151
+ thirty_days_ago = datetime.now() - timedelta(days=30)
152
+ df['createdAt'] = pd.to_datetime(df['createdAt'])
153
+ df = df[df['createdAt'] >= thirty_days_ago].copy()
154
+
155
+ dates = pd.date_range(start=thirty_days_ago, end=datetime.now(), freq='D')
156
+ daily_ranks = []
157
+
158
+ for date in dates:
159
+ date_data = df[df['createdAt'].dt.date <= date.date()].copy()
160
+ date_data = date_data.sort_values(['trendingScore', 'id'], ascending=[False, True])
161
+ date_data['rank'] = range(1, len(date_data) + 1)
162
+ date_data['date'] = date.date()
163
+ daily_ranks.append(
164
+ date_data[['id', 'date', 'rank', 'trendingScore', 'createdAt']]
165
+ )
166
+
167
+ daily_ranks_df = pd.concat(daily_ranks, ignore_index=True)
168
+
169
+ latest_date = daily_ranks_df['date'].max()
170
+ top_100_spaces = daily_ranks_df[
171
+ (daily_ranks_df['date'] == latest_date) &
172
+ (daily_ranks_df['rank'] <= 100)
173
+ ].sort_values('rank').copy()
174
+
175
+ return daily_ranks_df, top_100_spaces
176
+ except Exception as e:
177
+ print(f"Error loading data: {e}")
178
+ return pd.DataFrame(), pd.DataFrame()
179
+
180
+ # 데이터 로드
181
+ print("Loading initial data...")
182
+ daily_ranks_df, top_100_spaces = load_and_process_data()
183
+ print("Data loaded successfully!")
184
+
185
+ # Gradio 인터페이스 생성
186
+ with gr.Blocks(theme=gr.themes.Soft()) as demo:
187
+ gr.Markdown("""
188
+ # HF Space Ranking Tracker
189
+
190
+ Track, analyze, and discover trending AI applications in the Hugging Face ecosystem. Our service continuously monitors and ranks all Spaces over a 30-day period, providing detailed analytics and daily ranking changes for the top 100 performers.
191
+ """)
192
+
193
+ with gr.Tabs():
194
+ with gr.Tab("Dashboard"):
195
+ with gr.Row(variant="panel"):
196
+ with gr.Column(scale=7):
197
+ trend_plot = gr.Plot(
198
+ label="Daily Rank Trend",
199
+ container=True
200
+ )
201
+ with gr.Column(scale=3):
202
+ duplicates_chart = create_duplicates_chart(get_duplicate_spaces(top_100_spaces))
203
+ duplicates_plot = gr.Plot(
204
+ value=duplicates_chart,
205
+ label="Multiple Entries Analysis",
206
+ container=True
207
+ )
208
+
209
+ with gr.Row():
210
+ info_box = gr.HTML(
211
+ value="<div style='text-align: center; padding: 20px; color: #666;'>Select a space to view details</div>"
212
+ )
213
+
214
+ # 라디오 버튼을 먼저 정의
215
+ space_selection = gr.Radio(
216
+ choices=[row['id'] for _, row in top_100_spaces.iterrows()],
217
+ value=None,
218
+ visible=False
219
+ )
220
+
221
+ # HTML에서 JavaScript 이벤트를 직접 처리
222
+ html_content = """
223
+ <div style='display: flex; flex-wrap: wrap; gap: 16px; justify-content: center;'>
224
+ """ + "".join([
225
+ f"""
226
+ <div class="space-card"
227
+ data-space-id="{row['id']}"
228
+ style="
229
+ border: 1px solid #e5e7eb;
230
+ border-radius: 8px;
231
+ padding: 16px;
232
+ margin: 8px;
233
+ background-color: hsl(210, {max(30, 90 - (row['rank'] / 100 * 60))}%, {min(97, 85 + (row['rank'] / 100 * 10))}%);
234
+ box-shadow: 0 1px 3px rgba(0,0,0,0.1);
235
+ display: inline-block;
236
+ width: 250px;
237
+ vertical-align: top;
238
+ cursor: pointer;
239
+ transition: all 0.2s;
240
+ "
241
+ onmouseover="this.style.transform='translateY(-2px)';this.style.boxShadow='0 4px 6px rgba(0,0,0,0.1)';"
242
+ onmouseout="this.style.transform='none';this.style.boxShadow='0 1px 3px rgba(0,0,0,0.1)';"
243
+ >
244
+ <div style="font-size: 1.2em; font-weight: bold; margin-bottom: 8px;">
245
+ #{int(row['rank'])}
246
+ </div>
247
+ <div style="margin-bottom: 8px;">
248
+ {row['id']}
249
+ </div>
250
+ <div style="color: #666; margin-bottom: 12px;">
251
+ Score: {row['trendingScore']:.2f}
252
+ </div>
253
+ <div style="display: flex; gap: 8px;">
254
+ <a href="https://huggingface.co/spaces/{row['id']}"
255
+ target="_blank"
256
+ style="padding: 6px 12px; background-color: white; color: #2563eb; text-decoration: none; border-radius: 4px; font-size: 0.9em; border: 1px solid #2563eb;"
257
+ onclick="event.stopPropagation();">
258
+ View Space ↗
259
+ </a>
260
+ <button onclick="event.preventDefault(); gradioEvent('{row['id']}');"
261
+ style="padding: 6px 12px; background-color: #2563eb; color: white; border: none; border-radius: 4px; cursor: pointer; font-size: 0.9em;">
262
+ View Trend
263
+ </button>
264
+ </div>
265
+ </div>
266
+ """
267
+ for _, row in top_100_spaces.iterrows()
268
+ ]) + """
269
+ </div>
270
+ <script>
271
+ function gradioEvent(spaceId) {
272
+ const radio = document.querySelector(`input[type="radio"][value="${spaceId}"]`);
273
+ if (radio) {
274
+ radio.checked = true;
275
+ const event = new Event('change');
276
+ radio.dispatchEvent(event);
277
+ }
278
+ }
279
+ </script>
280
+ """
281
+
282
+ with gr.Row():
283
+ space_grid = gr.HTML(value=html_content)
284
+
285
+ with gr.Tab("About"):
286
+ gr.Markdown("""
287
+ ### Our Tracking System
288
+
289
+ #### What We Track
290
+ - Daily ranking changes for all Hugging Face Spaces
291
+ - Comprehensive trending scores based on 30-day activity
292
+ - Detailed performance metrics for top 100 Spaces
293
+ - Historical ranking data with daily granularity
294
+
295
+ #### Key Features
296
+ - **Real-time Rankings**: Stay updated with daily rank changes
297
+ - **Interactive Visualizations**: Track ranking trajectories over time
298
+ - **Trend Analysis**: Identify emerging popular AI applications
299
+ - **Direct Access**: Quick links to explore trending Spaces
300
+ - **Performance Metrics**: Detailed trending scores and statistics
301
+
302
+ ### Why Use HF Space Ranking Tracker?
303
+ - Discover trending AI demos and applications
304
+ - Monitor your Space's performance and popularity
305
+ - Identify emerging trends in the AI community
306
+ - Make data-driven decisions about your AI projects
307
+ - Stay ahead of the curve in AI application development
308
+
309
+ Our dashboard provides a comprehensive view of the Hugging Face Spaces ecosystem, helping developers, researchers, and enthusiasts track and understand the dynamics of popular AI applications. Whether you're monitoring your own Space's performance or discovering new trending applications, HF Space Ranking Tracker offers the insights you need.
310
+
311
+ Experience the pulse of the AI community through our daily updated rankings and discover what's making waves in the world of practical AI applications.
312
+ """)
313
+
314
+ # 라디오 버튼 변경 이벤트 연결
315
+ space_selection.change(
316
+ fn=update_display,
317
+ inputs=[space_selection],
318
+ outputs=[trend_plot, info_box],
319
+ api_name="update_display"
320
+ )
321
+
322
+ if __name__ == "__main__":
323
+ demo.launch(share=True)