Spaces:
Runtime error
Runtime error
from pathlib import Path | |
import gradio as gr | |
from datetime import datetime, timedelta | |
from fetch_paper import fetch_papers_with_daterange | |
from sorter import sort_by_upvotes, sort_by_comments, sort_by_date | |
from date import Date | |
import assets | |
def format_author(author): | |
"""Format author information""" | |
if not author: | |
return "" | |
hidden_status = " (hidden)" if author.hidden else "" | |
if author.name: | |
return f"<a href='https://scholar.google.com/citations?view_op=search_authors&mauthors={author.name.replace(' ', '+')}' target='_blank'>{author.name}</a>" | |
return "Anonymous author" | |
# 底部论文介绍 | |
def format_paper_info(article): | |
"""Generate HTML content for paper display""" | |
if not article.paper: | |
return "Paper information missing" | |
info = [] | |
# Title section | |
info.append(f"<h2 class='sf-paper-title' id='sf-flag'>{article.title or 'Untitled Paper'}</h2>") | |
info.append(f"<p style='text-align: center'>") | |
info.append(f"<a href='https://huggingface.co/papers/{article.paper.id}' target='_blank' class='sf-button'>Hugging Face{assets.SVG_LINK}</a>") | |
info.append(f"<a href='https://arxiv.org/abs/{article.paper.id}' target='_blank' class='sf-button'>arXiv{assets.SVG_LINK}</a>") | |
info.append(f"<a href='https://arxiv.org/pdf/{article.paper.id}' target='_blank' class='sf-button'>PDF{assets.SVG_LINK}</a>") | |
info.append(f"</p>") | |
# Thumbnail | |
if article.thumbnail: | |
info.append(f"<p><img src='{article.thumbnail}' style='max-width: 30em; width: 100%; margin: auto'/></p>") | |
# Basic information | |
info.append( | |
f"<p><strong>Paper ID</strong>: <a href='https://huggingface.co/papers/{article.paper.id}' target='_blank'>{article.paper.id or 'Unknown'}</a></p>") | |
info.append( | |
f"<p><strong>Published At</strong>: {article.paper.publishedAt.strftime('%Y-%m-%d %H:%M') if article.paper.publishedAt else 'Unknown'}</p>") | |
# Author information | |
authors = ", ".join([format_author(a) for a in article.paper.authors]) if article.paper.authors else "Author information not available" | |
info.append(f"<p><strong>Authors</strong>: {authors}</p>") | |
# Summary | |
if article.paper.summary: | |
summary = article.paper.summary.replace('{{', '{').replace('}}', '}').replace('\n', ' ') | |
info.append(f"<h3>Summary</h3><p>{summary}</p>") | |
# Discussion information | |
info.append(f"<p><strong>Upvotes</strong>: {article.paper.upvotes or 0}<span style='margin-left: .5rem'></span>") | |
info.append(f"<strong>Comments</strong>: {article.numComments or 0}</p>") | |
if article.paper.discussionId: | |
info.append( | |
f"<a href='https://huggingface.co/papers/{article.paper.id}#community' target='_blank' class='sf-button'>Join Discussion{assets.SVG_LINK}</a></p>") | |
# Submitter information | |
if article.submittedBy: | |
submitter = article.submittedBy | |
info.append(f"<hr><p><strong>Submitter</strong>: ") | |
avatar_url = submitter.avatarUrl if submitter.avatarUrl.startswith("http") else f"https://huggingface.co{submitter.avatarUrl}" | |
profile_url = f"https://huggingface.co/{submitter.name}" | |
info.append( | |
f"<span><img src='{avatar_url}' class='sf-author' /></span>{submitter.fullname}(<a href='{profile_url}' target='_blank'>@{submitter.name}</a>) ") | |
info.append(f"Followers: {submitter.followerCount or 0}</p>") | |
return "".join(info) | |
def generate_table_html(papers): | |
"""Generate table HTML with clickable titles and an extra column for arXiv abs link""" | |
html = ['<table class="paper-table"><thead><tr>' | |
'<th>Title</th>' | |
'<th>👍 Upvotes</th>' | |
'<th>💬 Comments</th>' | |
'<th>📅 Date</th>' | |
# '<th>Label</th>' | |
'<th></th>' | |
'</tr></thead><tbody>'] | |
for article in papers: | |
title = article.title or "Untitled" | |
upvotes = article.paper.upvotes or 0 | |
comments = article.numComments or 0 | |
date = article.paper.publishedAt.strftime("%Y-%m-%d") if article.paper.publishedAt else "Unknown" | |
paper_id = article.paper.id | |
# label = ", ".join(article.paper.label) or "" | |
# 构造 arXiv abs 链接 | |
arxiv_abs_link = f"https://huggingface.co/papers/{paper_id}" | |
row = f""" | |
<tr> | |
<td><a class="paper-title" href="{arxiv_abs_link}" target="_blank">{title}{assets.SVG_LINK}</a></td> | |
<td>{upvotes}</td> | |
<td>{comments}</td> | |
<td>{date}</td> | |
<td><a href="javascript:void(0)" onclick="showDetail('{paper_id}')" class="sf-button" style="margin: 0">Details{assets.SVG_LINK}</a></td> | |
</tr> | |
""" # <td>{label}</td> | |
html.append(row) | |
html.append("</tbody></table>") | |
return "".join(html) | |
def build_html(papers): | |
# Convert all papers to an HTML string, each paper wrapped in a div, with the div containing the paper's information, and the div's id being the paper's id | |
html = "" | |
for index, article in enumerate(papers): | |
article_html = format_paper_info(article) | |
html += f"<div id='smartflow-paper-{article.paper.id.replace('.', '-')}' style='{'' if index == 0 else 'display: none'}'>{article_html}</div>" | |
return html | |
def query_papers(start_date_str: str, end_date_str: str, sort_method: str): # Added sort_method parameter | |
"""Handle date range query""" | |
try: | |
start_date = Date(start_date_str) | |
end_date = Date(end_date_str) | |
papers = fetch_papers_with_daterange(start_date, end_date) | |
# Sort papers based on the selected sorting method | |
if sort_method == "Sort by upvotes ascending": | |
papers = sort_by_upvotes(papers, reverse=False) | |
elif sort_method == "Sort by upvotes descending": | |
papers = sort_by_upvotes(papers, reverse=True) | |
elif sort_method == "Sort by comments ascending": | |
papers = sort_by_comments(papers, reverse=False) | |
elif sort_method == "Sort by comments descending": | |
papers = sort_by_comments(papers, reverse=True) | |
elif sort_method == "Sort by date ascending": | |
papers = sort_by_date(papers, reverse=False) | |
elif sort_method == "Sort by date descending": | |
papers = sort_by_date(papers, reverse=True) | |
# elif sort_method == "Sort by label": | |
# papers = sorted(papers, key=lambda x: ", ".join(x.paper.label)) | |
return generate_table_html(papers), build_html(papers) | |
except Exception as e: | |
print(f"Query error: {e}") | |
return "<p>⚠️ Query failed, please check the date format (YYYY-MM-DD)</p>", "<p>⚠️ Query failed, please check the date format (YYYY-MM-DD)</p>" | |
# CSS 样式(可放入单独文件) | |
custom_css = """ | |
.detail-area { margin-top: 20px; padding: 20px; border: 1px solid #ddd; border-radius: 5px; } | |
.sf-paper-title { text-align: center; } | |
img.sf-author { | |
height: 1.3rem; | |
border: 1px solid #000; | |
vertical-align: middle; | |
border-radius: 50%; | |
display: inline; | |
margin: 0 0.1rem; | |
} | |
#paper-detail-area { | |
display: none; | |
} | |
#paper-detail-area:has(#sf-flag) { | |
display: block; | |
} | |
#query-results-html { min-height: 100px; } | |
""" | |
# 遍历./css文件夹下的所有文件,将文件内容作为CSS样式添加到页面中 | |
for css_file in Path("./css").glob("*.css"): | |
with open(css_file, "r") as f: | |
custom_css += "\n" + f.read() + "\n" | |
custom_js = """""" | |
# 遍历./css文件夹下的所有文件,将文件内容作为CSS样式添加到页面中 | |
for js_file in Path("./js").glob("*.js"): | |
with open(js_file, "r") as f: | |
custom_js += "\n" + f.read() + "\n" | |
def create_interface(): | |
"""Create a new interface layout""" | |
with gr.Blocks(title="Hugging Face Daily Paper", css=custom_css, head=f"<script>{custom_js}</script>") as app: | |
# Main interface | |
gr.HTML("<div style='text-align: center'><h1>📚 Hugging Face Weekly Paper</h1></div>") | |
gr.HTML("""<div style='text-align: center'> | |
<span style=""> | |
🔗 <a href='https://larkcommunity.feishu.cn/wiki/HSSTwsq7JiDur0kJrvjcnFZfnTe'>Contribute to this project</a> | |
</span> | |
<span style="margin-left: 1rem"> | |
Sponsor: <a href='https://internlm.intern-ai.org.cn/api/document'>InternLM</a> | |
</span> | |
</div>""") | |
# Query control area | |
with gr.Row(): | |
with gr.Column(): | |
with gr.Row(): | |
start_date = gr.Textbox(elem_id="start_date", label="Start Date", placeholder="YYYY-MM-DD", value=str(Date() + (-7))) | |
end_date = gr.Textbox(elem_id="end_date", label="End Date", placeholder="YYYY-MM-DD", value=str(Date())) | |
with gr.Column(): | |
with gr.Row(): | |
today_btn = gr.Button("Today") | |
last_week_btn = gr.Button("Last Week") | |
last_month_btn = gr.Button("Last Month") | |
query_btn = gr.Button("🔍 Query", variant="primary", elem_id="query_button") | |
with gr.Row(): | |
# Add sorting method selection | |
sort_method = gr.Radio( | |
label="Sort Method", | |
choices=[ | |
"Sort by upvotes descending", | |
"Sort by comments descending", | |
"Sort by date descending", | |
"Sort by upvotes ascending", | |
"Sort by comments ascending", | |
"Sort by date ascending", | |
# "Sort by label", | |
], | |
value="Sort by upvotes descending", | |
) | |
# Results display area | |
with gr.Column(visible=True): | |
results_html = gr.HTML(label="Query Results", elem_id="query-results-html") | |
# Paper details area | |
with gr.Column(visible=True, elem_classes="detail-area", elem_id="paper-detail-area"): | |
gr.Markdown("## Paper Details") | |
detail_html = gr.HTML(elem_id="detail-html") | |
# Event handling | |
query_btn.click( | |
fn=query_papers, | |
inputs=[start_date, end_date, sort_method], | |
outputs=[results_html, detail_html] | |
) | |
sort_method.change( | |
fn=query_papers, | |
inputs=[start_date, end_date, sort_method], | |
outputs=[results_html, detail_html] | |
) | |
# Add button event handling | |
today_btn.click( | |
fn=lambda: (str(Date()), str(Date())), | |
outputs=[start_date, end_date] | |
).then( | |
fn=query_papers, | |
inputs=[start_date, end_date, sort_method], | |
outputs=[results_html, detail_html] | |
) | |
last_week_btn.click( | |
fn=lambda: (str(Date() + (-7)), str(Date())), | |
outputs=[start_date, end_date] | |
).then( | |
fn=query_papers, | |
inputs=[start_date, end_date, sort_method], | |
outputs=[results_html, detail_html] | |
) | |
last_month_btn.click( | |
fn=lambda: (str(Date() + (-30)), str(Date())), | |
outputs=[start_date, end_date] | |
).then( | |
fn=query_papers, | |
inputs=[start_date, end_date, sort_method], | |
outputs=[results_html, detail_html] | |
) | |
return app | |