akhaliq HF staff commited on
Commit
cf55fa7
1 Parent(s): 1712f8c

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +224 -1
app.py CHANGED
@@ -1,3 +1,227 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  demo = gr.Blocks(css=css)
2
 
3
  with demo:
@@ -13,7 +237,6 @@ with demo:
13
  page_info = gr.Markdown()
14
  next_button = gr.Button("Next →", interactive=True)
15
 
16
- # Initialize app and set button states
17
  demo.load(initialize_app, outputs=[paper_list, page_info, prev_button, next_button])
18
  search_input.change(paper_manager.search_papers, inputs=[search_input], outputs=[paper_list])
19
  refresh_button.click(refresh_papers, outputs=[paper_list, page_info, prev_button, next_button])
 
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
+
7
+ class PaperManager:
8
+ def __init__(self, papers_per_page=10):
9
+ self.papers_per_page = papers_per_page
10
+ self.current_page = 1
11
+ self.papers = []
12
+ self.total_pages = 1
13
+
14
+ def fetch_papers(self):
15
+ try:
16
+ response = requests.get(f"{API_URL}?limit=50")
17
+ response.raise_for_status()
18
+ data = response.json()
19
+ self.papers = sorted(data, key=lambda x: x.get('paper', {}).get('upvotes', 0), reverse=True)
20
+ self.total_pages = (len(self.papers) + self.papers_per_page - 1) // self.papers_per_page
21
+ self.current_page = 1
22
+ return True
23
+ except requests.RequestException as e:
24
+ print(f"Error fetching papers: {e}")
25
+ return False
26
+
27
+ def format_paper(self, paper):
28
+ title = paper.get('title', 'No title')
29
+ url = f"https://huggingface.co/papers/{paper['paper'].get('id', '')}"
30
+ authors = ', '.join([author.get('name', '') for author in paper['paper'].get('authors', [])])
31
+ upvotes = paper.get('paper', {}).get('upvotes', 0)
32
+ comments = paper.get('numComments', 0)
33
+ published_time = datetime.fromisoformat(paper.get('publishedAt', datetime.now(timezone.utc).isoformat()).replace('Z', '+00:00'))
34
+ time_ago = (datetime.now(timezone.utc) - published_time).days
35
+
36
+ return f"""
37
+ <div class="paper-item">
38
+ <h3><a href="{url}" target="_blank">{title}</a></h3>
39
+ <p class="paper-meta">
40
+ <span class="upvotes">{upvotes} ▲</span>
41
+ <span class="authors">{authors}</span>
42
+ <span class="time-ago">{time_ago}d</span>
43
+ <span class="comments">{comments}💬</span>
44
+ </p>
45
+ </div>
46
+ """
47
+
48
+ def render_papers(self):
49
+ start = (self.current_page - 1) * self.papers_per_page
50
+ end = start + self.papers_per_page
51
+ current_papers = self.papers[start:end]
52
+
53
+ if not current_papers:
54
+ return "<div class='no-papers'>No papers available for this page.</div>"
55
+
56
+ return "".join([self.format_paper(paper) for paper in current_papers])
57
+
58
+ def search_papers(self, query):
59
+ if not query:
60
+ self.current_page = 1
61
+ return self.render_papers()
62
+
63
+ filtered_papers = [paper for paper in self.papers if query.lower() in paper.get('title', '').lower()]
64
+ return "".join([self.format_paper(paper) for paper in filtered_papers[:self.papers_per_page]])
65
+
66
+ def next_page(self):
67
+ if self.current_page < self.total_pages:
68
+ self.current_page += 1
69
+ return self.render_papers(), f"Page {self.current_page} of {self.total_pages}"
70
+
71
+ def prev_page(self):
72
+ if self.current_page > 1:
73
+ self.current_page -= 1
74
+ return self.render_papers(), f"Page {self.current_page} of {self.total_pages}"
75
+
76
+ css = """
77
+ body {
78
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif;
79
+ background-color: #f0f2f5;
80
+ margin: 0;
81
+ padding: 0;
82
+ }
83
+ .container {
84
+ max-width: 100%;
85
+ margin: 0 auto;
86
+ background-color: white;
87
+ padding: 1rem;
88
+ }
89
+ .title {
90
+ text-align: center;
91
+ color: #1a202c;
92
+ font-size: 1.5rem;
93
+ margin-bottom: 1rem;
94
+ }
95
+ .search-row {
96
+ display: flex;
97
+ gap: 0.5rem;
98
+ margin-bottom: 1rem;
99
+ align-items: flex-end;
100
+ }
101
+ .search-row > div:first-child {
102
+ flex-grow: 1;
103
+ }
104
+ .paper-list {
105
+ max-height: 70vh;
106
+ overflow-y: auto;
107
+ border: 1px solid #e2e8f0;
108
+ border-radius: 8px;
109
+ padding: 0.5rem;
110
+ }
111
+ .paper-item {
112
+ border-bottom: 1px solid #e2e8f0;
113
+ padding: 0.5rem 0;
114
+ }
115
+ .paper-item:last-child {
116
+ border-bottom: none;
117
+ }
118
+ .paper-item h3 {
119
+ margin: 0 0 0.25rem 0;
120
+ font-size: 1rem;
121
+ }
122
+ .paper-item a {
123
+ color: #2b6cb0;
124
+ text-decoration: none;
125
+ font-weight: 600;
126
+ }
127
+ .paper-item a:hover {
128
+ text-decoration: underline;
129
+ }
130
+ .paper-meta {
131
+ font-size: 0.75rem;
132
+ color: #4a5568;
133
+ display: flex;
134
+ flex-wrap: wrap;
135
+ gap: 0.5rem;
136
+ }
137
+ .footer {
138
+ display: flex;
139
+ justify-content: space-between;
140
+ align-items: center;
141
+ margin-top: 0.5rem;
142
+ }
143
+ button, .button {
144
+ background-color: #4299e1;
145
+ color: white;
146
+ border: none;
147
+ padding: 0.25rem 0.5rem;
148
+ border-radius: 4px;
149
+ cursor: pointer;
150
+ transition: background-color 0.3s;
151
+ font-size: 0.875rem;
152
+ line-height: 1.25rem;
153
+ }
154
+ button:hover, .button:hover {
155
+ background-color: #3182ce;
156
+ }
157
+ .no-papers {
158
+ text-align: center;
159
+ color: #718096;
160
+ padding: 1rem;
161
+ }
162
+ #component-0 > div:first-child {
163
+ border-top-right-radius: 0;
164
+ border-bottom-right-radius: 0;
165
+ }
166
+ #component-1 {
167
+ height: 45px;
168
+ border-top-left-radius: 0;
169
+ border-bottom-left-radius: 0;
170
+ }
171
+
172
+ @media (min-width: 640px) {
173
+ .container {
174
+ max-width: 640px;
175
+ padding: 1.5rem;
176
+ }
177
+ .title {
178
+ font-size: 1.75rem;
179
+ }
180
+ .paper-item h3 {
181
+ font-size: 1.125rem;
182
+ }
183
+ .paper-meta {
184
+ font-size: 0.875rem;
185
+ }
186
+ }
187
+
188
+ @media (min-width: 768px) {
189
+ .container {
190
+ max-width: 768px;
191
+ }
192
+ }
193
+ """
194
+
195
+ paper_manager = PaperManager()
196
+
197
+ def initialize_app():
198
+ if paper_manager.fetch_papers():
199
+ prev_disabled = paper_manager.current_page == 1
200
+ next_disabled = paper_manager.current_page >= paper_manager.total_pages
201
+
202
+ return (
203
+ paper_manager.render_papers(),
204
+ f"Page {paper_manager.current_page} of {paper_manager.total_pages}",
205
+ prev_disabled,
206
+ next_disabled
207
+ )
208
+ else:
209
+ return "<div class='no-papers'>Failed to fetch papers. Please try again later.</div>", "Error", True, True
210
+
211
+ def refresh_papers():
212
+ if paper_manager.fetch_papers():
213
+ prev_disabled = paper_manager.current_page == 1
214
+ next_disabled = paper_manager.current_page >= paper_manager.total_pages
215
+
216
+ return (
217
+ paper_manager.render_papers(),
218
+ f"Page {paper_manager.current_page} of {paper_manager.total_pages}",
219
+ prev_disabled,
220
+ next_disabled
221
+ )
222
+ else:
223
+ return "<div class='no-papers'>Failed to refresh papers. Please try again later.</div>", "Error", True, True
224
+
225
  demo = gr.Blocks(css=css)
226
 
227
  with demo:
 
237
  page_info = gr.Markdown()
238
  next_button = gr.Button("Next →", interactive=True)
239
 
 
240
  demo.load(initialize_app, outputs=[paper_list, page_info, prev_button, next_button])
241
  search_input.change(paper_manager.search_papers, inputs=[search_input], outputs=[paper_list])
242
  refresh_button.click(refresh_papers, outputs=[paper_list, page_info, prev_button, next_button])