guy1eyal commited on
Commit
0762e1f
·
verified ·
1 Parent(s): 55968d1

Create app.py

Browse files

Added a functionality to allow the user to choose between hot papers (computed using hot score) and top papers, which chooses the papers with the most upvotes in a certain time frame (day/week/month year)

Note
1. I wasn't able to run locally https://huggingface.co/api/daily_papers?limit={} with a value large than 100. Please validate it works with a 1000
2. We might need to significantly increase the number of fetched papers to retrieve the top papers from the last year, or we could design some caching mechanism.

Files changed (1) hide show
  1. app.py +70 -52
app.py CHANGED
@@ -1,6 +1,6 @@
1
  import gradio as gr
2
  import requests
3
- from datetime import datetime, timezone
4
 
5
  API_URL = "https://huggingface.co/api/daily_papers"
6
 
@@ -10,8 +10,10 @@ class PaperManager:
10
  self.current_page = 1
11
  self.papers = []
12
  self.total_pages = 1
 
 
13
 
14
- def calculate_score(self, paper):
15
  """
16
  Calculate the score of a paper based on upvotes and age.
17
  This mimics the "hotness" algorithm used by platforms like Hacker News.
@@ -21,28 +23,53 @@ class PaperManager:
21
  try:
22
  published_time = datetime.fromisoformat(published_at_str.replace('Z', '+00:00'))
23
  except ValueError:
24
- # If parsing fails, use current time to minimize the impact on sorting
25
  published_time = datetime.now(timezone.utc)
26
 
27
  time_diff = datetime.now(timezone.utc) - published_time
28
- time_diff_hours = time_diff.total_seconds() / 3600 # Convert time difference to hours
29
 
30
- # Avoid division by zero and apply the hotness formula
31
  score = upvotes / ((time_diff_hours + 2) ** 1.5)
32
  return score
33
 
34
- def fetch_papers(self):
35
  try:
36
- response = requests.get(f"{API_URL}?limit=100")
37
  response.raise_for_status()
38
  data = response.json()
39
 
40
- # Sort papers by calculated score descending
41
- self.papers = sorted(
42
- data,
43
- key=lambda x: self.calculate_score(x),
44
- reverse=True
45
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
46
 
47
  self.total_pages = max((len(self.papers) + self.papers_per_page - 1) // self.papers_per_page, 1)
48
  self.current_page = 1
@@ -112,17 +139,12 @@ class PaperManager:
112
 
113
  paper_manager = PaperManager()
114
 
115
- def initialize_app():
116
- if paper_manager.fetch_papers():
117
- return paper_manager.render_papers()
118
  else:
119
- return "<div class='no-papers'>Failed to fetch papers. Please try again later.</div>"
120
 
121
- def refresh_papers():
122
- if paper_manager.fetch_papers():
123
- return paper_manager.render_papers()
124
- else:
125
- return "<div class='no-papers'>Failed to refresh papers. Please try again later.</div>"
126
 
127
  css = """
128
  body {
@@ -131,63 +153,51 @@ body {
131
  margin: 0;
132
  padding: 0;
133
  }
134
-
135
  a {
136
  color: #0000ff;
137
  text-decoration: none;
138
  }
139
-
140
  a:visited {
141
  color: #551A8B;
142
  }
143
-
144
  .container {
145
  width: 85%;
146
  margin: auto;
147
  }
148
-
149
  table {
150
  width: 100%;
151
  }
152
-
153
  .header-table {
154
  width: 100%;
155
  background-color: #ff6600;
156
  padding: 2px 10px;
157
  }
158
-
159
  .header-table a {
160
  color: black;
161
  font-weight: bold;
162
  font-size: 14pt;
163
  text-decoration: none;
164
  }
165
-
166
  .itemlist .athing {
167
  background-color: #f6f6ef;
168
  }
169
-
170
  .rank {
171
  font-size: 14pt;
172
  color: #828282;
173
  padding-right: 5px;
174
  }
175
-
176
  .storylink {
177
  font-size: 10pt;
178
  }
179
-
180
  .subtext {
181
  font-size: 8pt;
182
  color: #828282;
183
  padding-left: 40px;
184
  }
185
-
186
  .subtext a {
187
  color: #828282;
188
  text-decoration: none;
189
  }
190
-
191
  #refresh-button {
192
  background: none;
193
  border: none;
@@ -196,71 +206,56 @@ table {
196
  font-size: 14pt;
197
  cursor: pointer;
198
  }
199
-
200
  .no-papers {
201
  text-align: center;
202
  color: #828282;
203
  padding: 1rem;
204
  font-size: 14pt;
205
  }
206
-
207
  @media (max-width: 640px) {
208
  .header-table a {
209
  font-size: 12pt;
210
  }
211
-
212
  .storylink {
213
  font-size: 9pt;
214
  }
215
-
216
  .subtext {
217
  font-size: 7pt;
218
  }
219
  }
220
-
221
  /* Dark mode */
222
  @media (prefers-color-scheme: dark) {
223
  body {
224
  background-color: #121212;
225
  color: #e0e0e0;
226
  }
227
-
228
  a {
229
  color: #add8e6;
230
  }
231
-
232
  a:visited {
233
  color: #9370db;
234
  }
235
-
236
  .header-table {
237
  background-color: #ff6600;
238
  }
239
-
240
  .header-table a {
241
  color: black;
242
  }
243
-
244
  .itemlist .athing {
245
  background-color: #1e1e1e;
246
  }
247
-
248
  .rank {
249
  color: #b0b0b0;
250
  }
251
-
252
  .subtext {
253
  color: #b0b0b0;
254
  }
255
-
256
  .subtext a {
257
  color: #b0b0b0;
258
  }
259
-
260
  #refresh-button {
261
  color: #e0e0e0;
262
  }
263
-
264
  .no-papers {
265
  color: #b0b0b0;
266
  }
@@ -285,6 +280,7 @@ with demo:
285
  Once your paper is submitted, it will automatically appear in this demo.
286
  """)
287
  # Header with Refresh Button
 
288
  with gr.Row():
289
  gr.HTML("""
290
  <table border="0" cellpadding="0" cellspacing="0" class="header-table">
@@ -300,22 +296,44 @@ with demo:
300
  </tr>
301
  </table>
302
  """)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
303
  # Paper list
304
  paper_list = gr.HTML()
 
305
  # Navigation Buttons
306
  with gr.Row():
307
  prev_button = gr.Button("Prev")
308
  next_button = gr.Button("Next")
309
 
310
-
311
  # Load papers on app start
312
- demo.load(initialize_app, outputs=[paper_list])
 
 
 
 
313
 
314
  # Button clicks
315
  prev_button.click(paper_manager.prev_page, outputs=[paper_list])
316
  next_button.click(paper_manager.next_page, outputs=[paper_list])
317
  refresh_button = gr.Button("Refresh", visible=False, elem_id="refresh-hidden")
318
- refresh_button.click(refresh_papers, outputs=[paper_list])
319
 
320
  # Bind the visible Refresh button to the hidden one using JavaScript
321
  gr.HTML("""
 
1
  import gradio as gr
2
  import requests
3
+ from datetime import datetime, timezone, timedelta
4
 
5
  API_URL = "https://huggingface.co/api/daily_papers"
6
 
 
10
  self.current_page = 1
11
  self.papers = []
12
  self.total_pages = 1
13
+ self.sort_method = "hot"
14
+ self.time_period = "day"
15
 
16
+ def calculate_hot_score(self, paper):
17
  """
18
  Calculate the score of a paper based on upvotes and age.
19
  This mimics the "hotness" algorithm used by platforms like Hacker News.
 
23
  try:
24
  published_time = datetime.fromisoformat(published_at_str.replace('Z', '+00:00'))
25
  except ValueError:
 
26
  published_time = datetime.now(timezone.utc)
27
 
28
  time_diff = datetime.now(timezone.utc) - published_time
29
+ time_diff_hours = time_diff.total_seconds() / 3600
30
 
 
31
  score = upvotes / ((time_diff_hours + 2) ** 1.5)
32
  return score
33
 
34
+ def fetch_papers(self, sort_method, time_period=None):
35
  try:
36
+ response = requests.get(f"{API_URL}?limit=1000") # Increased limit to get more papers
37
  response.raise_for_status()
38
  data = response.json()
39
 
40
+ self.sort_method = sort_method
41
+ self.time_period = time_period if sort_method == "top" else None
42
+
43
+ if sort_method == "hot":
44
+ self.papers = sorted(
45
+ data,
46
+ key=lambda x: self.calculate_hot_score(x),
47
+ reverse=True
48
+ )
49
+ elif sort_method == "top":
50
+ current_time = datetime.now(timezone.utc)
51
+
52
+ if time_period == "day":
53
+ start_time = current_time - timedelta(days=1)
54
+ elif time_period == "week":
55
+ start_time = current_time - timedelta(days=7)
56
+ elif time_period == "month":
57
+ start_time = current_time - timedelta(days=30)
58
+ elif time_period == "year":
59
+ start_time = current_time - timedelta(days=365)
60
+ else:
61
+ start_time = datetime.min.replace(tzinfo=timezone.utc)
62
+
63
+ filtered_papers = [
64
+ paper for paper in data
65
+ if datetime.fromisoformat(paper.get('publishedAt', '').replace('Z', '+00:00')) >= start_time
66
+ ]
67
+
68
+ self.papers = sorted(
69
+ filtered_papers,
70
+ key=lambda x: x.get('paper', {}).get('upvotes', 0),
71
+ reverse=True
72
+ )
73
 
74
  self.total_pages = max((len(self.papers) + self.papers_per_page - 1) // self.papers_per_page, 1)
75
  self.current_page = 1
 
139
 
140
  paper_manager = PaperManager()
141
 
142
+ def update_papers(sort_method, time_period=None):
143
+ if paper_manager.fetch_papers(sort_method, time_period):
144
+ return paper_manager.render_papers(), gr.update(visible=(sort_method == "top"))
145
  else:
146
+ return "<div class='no-papers'>Failed to fetch papers. Please try again later.</div>", gr.update(visible=False)
147
 
 
 
 
 
 
148
 
149
  css = """
150
  body {
 
153
  margin: 0;
154
  padding: 0;
155
  }
 
156
  a {
157
  color: #0000ff;
158
  text-decoration: none;
159
  }
 
160
  a:visited {
161
  color: #551A8B;
162
  }
 
163
  .container {
164
  width: 85%;
165
  margin: auto;
166
  }
 
167
  table {
168
  width: 100%;
169
  }
 
170
  .header-table {
171
  width: 100%;
172
  background-color: #ff6600;
173
  padding: 2px 10px;
174
  }
 
175
  .header-table a {
176
  color: black;
177
  font-weight: bold;
178
  font-size: 14pt;
179
  text-decoration: none;
180
  }
 
181
  .itemlist .athing {
182
  background-color: #f6f6ef;
183
  }
 
184
  .rank {
185
  font-size: 14pt;
186
  color: #828282;
187
  padding-right: 5px;
188
  }
 
189
  .storylink {
190
  font-size: 10pt;
191
  }
 
192
  .subtext {
193
  font-size: 8pt;
194
  color: #828282;
195
  padding-left: 40px;
196
  }
 
197
  .subtext a {
198
  color: #828282;
199
  text-decoration: none;
200
  }
 
201
  #refresh-button {
202
  background: none;
203
  border: none;
 
206
  font-size: 14pt;
207
  cursor: pointer;
208
  }
 
209
  .no-papers {
210
  text-align: center;
211
  color: #828282;
212
  padding: 1rem;
213
  font-size: 14pt;
214
  }
 
215
  @media (max-width: 640px) {
216
  .header-table a {
217
  font-size: 12pt;
218
  }
 
219
  .storylink {
220
  font-size: 9pt;
221
  }
 
222
  .subtext {
223
  font-size: 7pt;
224
  }
225
  }
 
226
  /* Dark mode */
227
  @media (prefers-color-scheme: dark) {
228
  body {
229
  background-color: #121212;
230
  color: #e0e0e0;
231
  }
 
232
  a {
233
  color: #add8e6;
234
  }
 
235
  a:visited {
236
  color: #9370db;
237
  }
 
238
  .header-table {
239
  background-color: #ff6600;
240
  }
 
241
  .header-table a {
242
  color: black;
243
  }
 
244
  .itemlist .athing {
245
  background-color: #1e1e1e;
246
  }
 
247
  .rank {
248
  color: #b0b0b0;
249
  }
 
250
  .subtext {
251
  color: #b0b0b0;
252
  }
 
253
  .subtext a {
254
  color: #b0b0b0;
255
  }
 
256
  #refresh-button {
257
  color: #e0e0e0;
258
  }
 
259
  .no-papers {
260
  color: #b0b0b0;
261
  }
 
280
  Once your paper is submitted, it will automatically appear in this demo.
281
  """)
282
  # Header with Refresh Button
283
+
284
  with gr.Row():
285
  gr.HTML("""
286
  <table border="0" cellpadding="0" cellspacing="0" class="header-table">
 
296
  </tr>
297
  </table>
298
  """)
299
+
300
+ # Sorting method selection
301
+ with gr.Row():
302
+ sort_method = gr.Radio(
303
+ choices=["hot", "top"],
304
+ value="hot",
305
+ label="Sort by:",
306
+ interactive=True
307
+ )
308
+
309
+ # Time Period Dropdown (only visible when "top" is selected)
310
+ time_period = gr.Dropdown(
311
+ choices=["day", "week", "month", "year"],
312
+ value="day",
313
+ label="Top papers from the last:",
314
+ visible=False
315
+ )
316
+
317
  # Paper list
318
  paper_list = gr.HTML()
319
+
320
  # Navigation Buttons
321
  with gr.Row():
322
  prev_button = gr.Button("Prev")
323
  next_button = gr.Button("Next")
324
 
 
325
  # Load papers on app start
326
+ demo.load(lambda: update_papers("hot"), outputs=[paper_list, time_period])
327
+
328
+ # Update papers when sorting method or time period changes
329
+ sort_method.change(update_papers, inputs=[sort_method, time_period], outputs=[paper_list, time_period])
330
+ time_period.change(lambda s, t: update_papers(s, t), inputs=[sort_method, time_period], outputs=[paper_list, time_period])
331
 
332
  # Button clicks
333
  prev_button.click(paper_manager.prev_page, outputs=[paper_list])
334
  next_button.click(paper_manager.next_page, outputs=[paper_list])
335
  refresh_button = gr.Button("Refresh", visible=False, elem_id="refresh-hidden")
336
+ refresh_button.click(update_papers, inputs=[sort_method, time_period], outputs=[paper_list, time_period])
337
 
338
  # Bind the visible Refresh button to the hidden one using JavaScript
339
  gr.HTML("""