import gradio as gr
from df.PaperCentral import PaperCentral
from gradio_calendar import Calendar
from datetime import datetime, timedelta
from typing import Union, List, Optional, Tuple
from author_leaderboard_tab import author_leaderboard_tab
from pr_paper_central_tab import pr_paper_central_tab
from huggingface_hub import whoami
import json
import requests
from bs4 import BeautifulSoup
from author_leaderboard_contrib_tab import author_resource_leaderboard_tab
from paper_chat_tab import paper_chat_tab
from zoneinfo import ZoneInfo # Available in Python 3.9 and later
# Initialize the PaperCentral class instance
paper_central_df = PaperCentral()
def logging_flow(oauth_token: Optional[gr.OAuthToken]):
if oauth_token is None:
# User is not logged in
visibility_update = gr.update(visible=True)
user_info_update = gr.update(value="", label="User")
return visibility_update, user_info_update
try:
# Attempt to get user information
user_info = whoami(oauth_token.token)
visibility_update = gr.update(visible=False)
except requests.exceptions.HTTPError as e:
# If there's an error (e.g., token is invalid), treat as not logged in
visibility_update = gr.update(visible=True)
user_info_update = gr.update(value="", label="User")
return visibility_update, user_info_update
# Prepare user information for display
avatar_url = user_info.get("avatarUrl", "")
name = user_info.get("name", "")
avatar_html = f'''
{name}
Head to "Edit papers" tab to modify your paper!
'''
user_info_update = gr.update(value=avatar_html, label="User")
return visibility_update, user_info_update
# Create the Gradio Blocks app with custom CSS
with gr.Blocks(css_paths="style.css") as demo:
gr.Markdown("# Paper Central")
with gr.Row():
with gr.Column(scale=1):
login_button = gr.LoginButton(value="Add or edit your papers")
user_info_md = gr.HTML()
with gr.Column(scale=1):
with gr.Accordion(label="⭐Release notes", open=False):
gr.Markdown("""
- **November 21, 2024** – Neurips D&B 2024 proceedings added.
- **November 20, 2024** – Neurips 2024 proceedings added.
- **November 15, 2024** – EMNLP 2024 proceedings added.
- **October 24, 2024** – CoRL 2024 proceedings added.
- **October 20, 2024** – You can now add or edit papers.
- **October 19, 2024** – Papers with github now have github stars.
- **October 16, 2024** – Added functionality to filter papers by date ranges.
- **October 11, 2024** – Introduced leaderboards feature.
- **October 8, 2024** – MICCAI 2024 proceedings added.
- **October 7, 2024** – COLM 2024 proceedings added.
- **October 4, 2024** – Added functionality to filter papers by title.
""")
gr.Button(value="Use paper-central in datasets",
icon="https://huggingface.co/front/assets/huggingface_logo-noborder.svg",
size="sm",
link="https://huggingface.co/datasets/huggingface/paper-central-data")
with gr.Tabs() as tabs:
with gr.Tab("Chat With Paper", id="tab-chat-with-paper", visible=True) as tab_chat_paper:
gr.Markdown("## Chat with Paper")
arxiv_id = gr.State(value=None)
paper_from = gr.State(value=None)
paper_chat_tab(arxiv_id, paper_from, paper_central_df)
with gr.Tab("Paper-central", id="tab-paper-central"):
# Create a row for navigation buttons and calendar
with gr.Row():
with gr.Column(scale=1):
# Define the 'Next Day' and 'Previous Day' buttons
next_day_btn = gr.Button("Next Day")
prev_day_btn = gr.Button("Previous Day")
with gr.Column(scale=4):
# Define the calendar component for date selection
calendar = Calendar(
type="datetime",
label="Select a date",
info="Click the calendar icon to bring up the calendar.",
value=datetime.now(ZoneInfo('America/Los_Angeles')).strftime('%Y-%m-%d')
# Default to today's date in PST
)
# Add Radio buttons for date ranges
date_range_radio = gr.Radio(
label="Date Range",
choices=["This week", "This month", "This year", "All time"],
value=None,
)
# Create a row for Hugging Face options and Conference options
with gr.Row():
with gr.Column():
# Define the checkbox group for Hugging Face options
cat_options = gr.CheckboxGroup(
label="Category",
choices=[
'(ALL)',
'cs.*',
'eess.*',
'econ.*',
'math.*',
'astro-ph.*',
'cond-mat.*',
'gr-qc',
'hep-ex',
'hep-lat',
'hep-ph',
'hep-th',
'math-ph',
'nlin.*',
'nucl-ex',
'nucl-th',
'physics.*',
'quant-ph',
'q-bio.*',
'q-fin.*',
'stat.*',
],
value=["(ALL)"]
)
hf_options = gr.CheckboxGroup(
label="Hugging Face options",
choices=["🤗 artifacts", "datasets", "models", "spaces", "github", "project page"],
value=[],
elem_id="hf_options"
)
with gr.Column():
# Define the checkbox group for Conference options
conference_options = gr.CheckboxGroup(
label="Conference options",
choices=["ALL"] + PaperCentral.CONFERENCES
)
with gr.Row():
# Define a Textbox for author search
author_search = gr.Textbox(
label="Search Authors",
placeholder="Enter author name",
)
title_search = gr.Textbox(
label="Search Title",
placeholder="Enter keywords",
)
# Define the Dataframe component to display paper data
# List of columns in your DataFrame
columns = paper_central_df.COLUMNS_START_PAPER_PAGE
paper_central_component = gr.Dataframe(
label="Paper Data",
value=paper_central_df.df_prettified[columns],
datatype=[
paper_central_df.DATATYPES[column]
for column in columns
],
row_count=(0, "dynamic"),
interactive=False,
max_height=1000,
elem_id="table",
wrap=True,
)
with gr.Tab("Edit papers", id="tab-pr"):
pr_paper_central_tab(paper_central_df.df_raw)
with gr.Tab("Leaderboards", id="tab-leaderboards"):
with gr.Tab("Authors"):
author_leaderboard_tab()
with gr.Tab("Contributors"):
author_resource_leaderboard_tab()
# chat with paper
def get_selected(evt: gr.SelectData, dataframe_origin):
paper_id = gr.update(value=None)
paper_from = gr.update(value=None)
tab_chat_paper = gr.update(visible=True)
selected_tab = gr.Tabs()
try:
# Parse the HTML content
soup = BeautifulSoup(evt.value, "html.parser")
# Find all tags
a_tags = soup.find_all('a')
for a_tag in a_tags:
# Check if 'action_id' attribute exists and equals 'chat-with-paper'
if a_tag.get('action_id') == 'chat-with-paper':
paper_id = a_tag.get("paper_id")
paper_from = a_tag.get("paper_from")
tab_chat_paper = gr.update(visible=True)
selected_tab = gr.Tabs(selected="tab-chat-with-paper")
except Exception as e:
print("The content is not valid HTML or another error occurred:", str(e))
pass
return paper_id, paper_from, tab_chat_paper, selected_tab
paper_central_component.select(get_selected, inputs=[paper_central_component],
outputs=[arxiv_id, paper_from, tab_chat_paper, tabs])
# Define function to move to the next day
def go_to_next_day(
date: Union[str, datetime],
cat_options_list: List[str],
hf_options_list: List[str],
conference_options_list: List[str],
author_search_input: str,
title_search_input: str,
date_range_option: Optional[str],
) -> tuple:
"""
Moves the selected date to the next day and updates the data.
Returns:
tuple: The new date as a string and the updated Dataframe component.
"""
date_range_update = gr.update(value=None)
# Ensure the date is in string format
if isinstance(date, datetime):
date_str = date.strftime('%Y-%m-%d')
else:
date_str = date
# Parse the date string and add one day
new_date = datetime.strptime(date_str, '%Y-%m-%d') + timedelta(days=1)
new_date_str = new_date.strftime('%Y-%m-%d')
# Update the Dataframe
updated_data = paper_central_df.filter(
selected_date=new_date_str,
cat_options=cat_options_list,
hf_options=hf_options_list,
conference_options=conference_options_list,
author_search_input=author_search_input,
title_search_input=title_search_input,
date_range_option=date_range_option,
)
# Return the new date and updated Dataframe
return new_date_str, updated_data, date_range_update
# Define function to move to the previous day
def go_to_previous_day(
date: Union[str, datetime],
cat_options_list: List[str],
hf_options_list: List[str],
conference_options_list: List[str],
author_search_input: str,
title_search_input: str,
date_range_option: Optional[str],
) -> tuple:
"""
Moves the selected date to the previous day and updates the data.
Returns:
tuple: The new date as a string and the updated Dataframe component.
"""
# If date_range_option is selected, do nothing
date_range_update = gr.update(value=None)
# Ensure the date is in string format
if isinstance(date, datetime):
date_str = date.strftime('%Y-%m-%d')
else:
date_str = date
# Parse the date string and subtract one day
new_date = datetime.strptime(date_str, '%Y-%m-%d') - timedelta(days=1)
new_date_str = new_date.strftime('%Y-%m-%d')
# Update the Dataframe
updated_data = paper_central_df.filter(
selected_date=new_date_str,
cat_options=cat_options_list,
hf_options=hf_options_list,
conference_options=conference_options_list,
author_search_input=author_search_input,
title_search_input=title_search_input,
date_range_option=date_range_option,
)
# Return the new date and updated Dataframe
return new_date_str, updated_data, date_range_update
# Define function to update data when date or options change
def update_data(
date: Union[str, datetime],
cat_options_list: List[str],
hf_options_list: List[str],
conference_options_list: List[str],
author_search_input: str,
title_search_input: str,
date_range_option: Optional[str],
):
"""
Updates the data displayed in the Dataframe based on the selected date and options.
"""
return paper_central_df.filter(
selected_date=date,
cat_options=cat_options_list,
hf_options=hf_options_list,
conference_options=conference_options_list,
author_search_input=author_search_input,
title_search_input=title_search_input,
date_range_option=date_range_option,
)
# Function to handle conference options change
def on_conference_options_change(
date: Union[str, datetime],
cat_options_list: List[str],
hf_options_list: List[str],
conference_options_list: List[str],
author_search_input: str,
title_search_input: str,
date_range_option: Optional[str],
):
cat_options_update = gr.update()
paper_central_component_update = gr.update()
visible = True
# Some conference options are selected
# Update cat_options to empty list
if conference_options_list:
cat_options_update = gr.update(value=[])
paper_central_component_update = update_data(
date,
[],
hf_options_list,
conference_options_list,
author_search_input,
title_search_input,
None,
)
visible = False
calendar_update = gr.update(visible=visible)
next_day_btn_update = gr.update(visible=visible)
prev_day_btn_update = gr.update(visible=visible)
date_range_option_update = gr.update(visible=visible, value=None)
return paper_central_component_update, cat_options_update, calendar_update, next_day_btn_update, prev_day_btn_update, date_range_option_update
# Function to handle category options change
def on_cat_options_change(
date: Union[str, datetime],
cat_options_list: List[str],
hf_options_list: List[str],
conference_options_list: List[str],
author_search_input: str,
title_search_input: str,
date_range_option: Optional[str],
):
conference_options_update = gr.update()
paper_central_component_update = gr.update()
visible = False
# Some category options are selected
# Update conference_options to empty list
if cat_options_list:
conference_options_update = gr.update(value=[])
paper_central_component_update = update_data(
date,
cat_options_list,
hf_options_list,
[],
author_search_input,
title_search_input,
date_range_option,
)
visible = True
calendar_update = gr.update(visible=visible)
next_day_btn_update = gr.update(visible=visible)
prev_day_btn_update = gr.update(visible=visible)
date_range_option_update = gr.update(visible=visible)
return paper_central_component_update, conference_options_update, calendar_update, next_day_btn_update, prev_day_btn_update, date_range_option_update
# Include date_range_radio in the inputs
inputs = [
calendar,
cat_options,
hf_options,
conference_options,
author_search,
title_search,
date_range_radio,
]
# Set up the event listener for the author search
author_search.submit(
fn=update_data,
inputs=inputs,
outputs=paper_central_component,
api_name=False
)
title_search.submit(
fn=update_data,
inputs=inputs,
outputs=paper_central_component,
api_name=False
)
# Set up the event listener for the 'Next Day' button
next_day_btn.click(
fn=go_to_next_day,
inputs=inputs,
outputs=[calendar, paper_central_component, date_range_radio],
api_name=False
)
# Set up the event listener for the 'Previous Day' button
prev_day_btn.click(
fn=go_to_previous_day,
inputs=inputs,
outputs=[calendar, paper_central_component, date_range_radio],
api_name=False
)
# Set up the event listener for the calendar date change
calendar.change(
fn=update_data,
inputs=inputs,
outputs=paper_central_component,
api_name=False
)
# Set up the event listener for the Hugging Face options change
hf_options.change(
fn=update_data,
inputs=inputs,
outputs=paper_central_component,
api_name=False
)
# Event chaining for conference options change
conference_options.change(
fn=on_conference_options_change,
inputs=inputs,
outputs=[paper_central_component, cat_options, calendar, next_day_btn, prev_day_btn, date_range_radio],
api_name=False
)
# Event chaining for category options change
cat_options.change(
fn=on_cat_options_change,
inputs=inputs,
outputs=[paper_central_component, conference_options, calendar, next_day_btn, prev_day_btn, date_range_radio],
api_name=False
)
# Set up the event listener for the date range radio button change
date_range_radio.change(
fn=update_data,
inputs=inputs,
outputs=paper_central_component,
api_name=False
)
# Load the initial data when the app starts
request = gr.Request()
def echo(request: gr.Request):
"""
Echoes the input text and prints request details.
Args:
text (str): The input text from the user.
request (gr.Request): The HTTP request object.
Returns:
str: The echoed text.
"""
calendar = gr.update(datetime.today().strftime('%Y-%m-%d'))
date_range = gr.update(value=None)
conferences = gr.update(value=[])
hf_options = gr.update(value=[])
selected_tab = gr.Tabs()
paper_id = gr.update(value=None)
paper_from = gr.update(value=None)
tab_chat_paper = gr.update(visible=True)
if request:
# print("Request headers dictionary:", dict(request.headers))
# print("IP address:", request.client.host)
# print("Query parameters:", dict(request.query_params))
# print("Session hash:", request.session_hash)
if 'date' in request.query_params:
calendar = gr.update(value=request.query_params['date'])
if 'date_range' in request.query_params:
date_range = gr.update(value=request.query_params['date_range'])
if 'conferences' in request.query_params:
conferences = request.query_params['conferences']
try:
conferences = [value for value in conferences.split(',')]
except ValueError:
conferences = []
conferences = gr.update(value=conferences)
if "hf_options" in request.query_params:
hf_options = request.query_params['hf_options']
try:
hf_options = [value for value in hf_options.split(',')]
except ValueError:
hf_options = []
hf_options = gr.update(value=hf_options)
if "tab" in request.query_params:
tab = request.query_params['tab']
if tab == "tab-leaderboards":
selected_tab = gr.Tabs(selected="tab-leaderboards")
elif tab == "tab-chat-with-paper":
selected_tab = gr.Tabs(selected="tab-chat-with-paper")
if "paper_id" in request.query_params:
paper_id = request.query_params['paper_id']
tab_chat_paper = gr.update(visible=True)
paper_from = request.query_params['paper_from']
return calendar, date_range, conferences, hf_options, selected_tab, paper_id, paper_from, tab_chat_paper
demo.load(
fn=update_data,
inputs=inputs,
outputs=paper_central_component,
api_name="update_data",
).then(
fn=echo,
outputs=[calendar, date_range_radio, conference_options, hf_options, tabs, arxiv_id, paper_from,
tab_chat_paper],
api_name=False,
).then(
# New then to handle LoginButton and HTML components
fn=logging_flow,
outputs=[login_button, user_info_md],
api_name=False,
)
# Define the main function to launch the app
def main():
"""
Launches the Gradio app.
"""
demo.launch(ssr_mode=False)
# Run the main function when the script is executed
if __name__ == "__main__":
main()