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'''
Avatar {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(share=True) # Run the main function when the script is executed if __name__ == "__main__": main()