| | import gradio as gr |
| | import pandas as pd |
| | from huggingface_hub import HfApi, hf_hub_download, upload_file |
| | import os |
| | from datetime import datetime |
| | from dotenv import load_dotenv |
| | import re |
| | from gradio_htmlplus import HTMLPlus |
| |
|
| | load_dotenv() |
| |
|
| | |
| | DATASET_REPO_ID = "MCP-1st-Birthday/hackathon-community-voting" |
| | PROJECTS_FILE = "projects.csv" |
| | VOTES_FILE = "votes.csv" |
| | HF_TOKEN = os.getenv("HF_TOKEN") |
| | api = HfApi(token=HF_TOKEN) |
| |
|
| | |
| | TRACKS = ["Track 1: Building MCP", "Track 2: MCP in Action"] |
| | CATEGORIES = ["Enterprise", "Consumer", "Creative"] |
| | LEADERBOARD_VIEWS = [ |
| | "Track 1 (Overall)", |
| | "Track 2 (Enterprise)", |
| | "Track 2 (Consumer)", |
| | "Track 2 (Creative)", |
| | ] |
| |
|
| |
|
| | |
| | def load_data(filename, repo_id): |
| | try: |
| | filepath = hf_hub_download( |
| | repo_id=repo_id, filename=filename, repo_type="dataset", token=HF_TOKEN |
| | ) |
| | return pd.read_csv(filepath, dtype={"track": str, "category": str}) |
| | except Exception: |
| | if filename == PROJECTS_FILE: |
| | return pd.DataFrame( |
| | columns=[ |
| | "space_url", |
| | "video_url", |
| | "track", |
| | "category", |
| | "submitted_by", |
| | "timestamp", |
| | ] |
| | ) |
| | elif filename == VOTES_FILE: |
| | return pd.DataFrame( |
| | columns=["space_url", "voted_by", "track", "category", "timestamp"] |
| | ) |
| | return pd.DataFrame() |
| |
|
| |
|
| | def save_data(df, filename, repo_id, commit_message): |
| | temp_path = f"./{filename}" |
| | df.to_csv(temp_path, index=False) |
| | upload_file( |
| | path_or_fileobj=temp_path, |
| | path_in_repo=filename, |
| | repo_id=repo_id, |
| | repo_type="dataset", |
| | token=HF_TOKEN, |
| | commit_message=commit_message, |
| | ) |
| | os.remove(temp_path) |
| |
|
| |
|
| | |
| |
|
| |
|
| | def get_username(request: gr.Request): |
| | return ( |
| | request.request.session.get("oauth_info", {}) |
| | .get("userinfo", {}) |
| | .get("preferred_username") |
| | ) |
| |
|
| |
|
| | def parse_view_to_context(filter_view: str): |
| | if "Track 1" in filter_view: |
| | return TRACKS[0], "Overall" |
| | if "Track 2" in filter_view: |
| | if "Enterprise" in filter_view: |
| | return TRACKS[1], "Enterprise" |
| | if "Consumer" in filter_view: |
| | return TRACKS[1], "Consumer" |
| | if "Creative" in filter_view: |
| | return TRACKS[1], "Creative" |
| | return None, None |
| |
|
| |
|
| | def render_leaderboard(request: gr.Request, filter_view: str): |
| | username = get_username(request) |
| | projects_df = load_data(PROJECTS_FILE, DATASET_REPO_ID) |
| | votes_df = load_data(VOTES_FILE, DATASET_REPO_ID) |
| | vote_context_str = f"βΉοΈ Your vote will be cast in the **'{filter_view}'** context." |
| |
|
| | if projects_df.empty: |
| | return ( |
| | "<h3>No projects submitted yet.</h3>", |
| | gr.update(choices=[], value=None), |
| | vote_context_str, |
| | gr.update(visible=False), |
| | ) |
| |
|
| | track_filter, category_filter = parse_view_to_context(filter_view) |
| | display_df = pd.DataFrame() |
| |
|
| | if track_filter == TRACKS[0]: |
| | track1_projects = projects_df[ |
| | projects_df["track"].str.contains(TRACKS[0], na=False) |
| | ].copy() |
| | if not track1_projects.empty: |
| | track1_projects["display_category"] = track1_projects[ |
| | "category" |
| | ].str.replace(";", " | ") |
| | track1_votes = votes_df[ |
| | (votes_df["track"] == TRACKS[0]) & (votes_df["category"] == "Overall") |
| | ] |
| | vote_counts = ( |
| | track1_votes.groupby("space_url").size().reset_index(name="votes") |
| | ) |
| | display_df = pd.merge( |
| | track1_projects, vote_counts, on="space_url", how="left" |
| | ).fillna(0) |
| | elif track_filter == TRACKS[1]: |
| | projects_df["track"] = projects_df["track"].str.split(";") |
| | exploded_tracks = projects_df.explode("track") |
| | exploded_tracks["category"] = exploded_tracks["category"].str.split(";") |
| | exploded_projects = exploded_tracks.explode("category") |
| | track2_filtered = exploded_projects[ |
| | (exploded_projects["track"] == track_filter) |
| | & (exploded_projects["category"] == category_filter) |
| | ] |
| | if not track2_filtered.empty: |
| | context_votes = votes_df[ |
| | (votes_df["track"] == track_filter) |
| | & (votes_df["category"] == category_filter) |
| | ] |
| | vote_counts = ( |
| | context_votes.groupby("space_url").size().reset_index(name="votes") |
| | ) |
| | display_df = pd.merge( |
| | track2_filtered, vote_counts, on="space_url", how="left" |
| | ).fillna(0) |
| | display_df["display_category"] = display_df["category"] |
| |
|
| | if display_df.empty: |
| | return ( |
| | f"<h3>No projects submitted for '{filter_view}' yet.</h3>", |
| | gr.update(choices=[], value=None), |
| | vote_context_str, |
| | gr.update(visible=False), |
| | ) |
| |
|
| | display_df["votes"] = display_df["votes"].astype(int) |
| | display_df["rank"] = ( |
| | display_df["votes"].rank(method="dense", ascending=False).astype(int) |
| | ) |
| | display_df = display_df.sort_values( |
| | by=["rank", "space_url"], ascending=True |
| | ).reset_index(drop=True) |
| |
|
| | html = "<div>" |
| | trophies = {1: "π₯", 2: "π₯", 3: "π₯"} |
| | for _, row in display_df.iterrows(): |
| | rank_num = row["rank"] |
| | rank_display = trophies.get(rank_num, f"<b>#{rank_num}</b>") |
| | space_name = re.sub(r"https://huggingface.co/spaces/", "", row["space_url"]) |
| | category_text = row["display_category"] |
| | submitter_name = row["submitted_by"] |
| |
|
| | video_link_html = "" |
| | if pd.notna(row["video_url"]) and str(row["video_url"]).strip() and str(row["video_url"]).strip() != '0': |
| | video_link_html = ( |
| | f' | <a href="{row["video_url"]}" target="_blank">π¬ Video</a>' |
| | ) |
| |
|
| | action_button_html = "" |
| | if username and row["submitted_by"] == username: |
| | action_button_html = f'<a href="#" class="edit-button" data-url="{row["space_url"]}" style="text-decoration: none; font-size: 20px; margin-left: 15px;" title="Edit this project">βοΈ</a>' |
| |
|
| | html += f""" |
| | <div style="display: flex; align-items: center; padding: 12px; border-bottom: 1px solid #eee; gap: 15px;" data-space-url="{row['space_url']}"> |
| | <div style="font-size: 24px; width: 50px;">{rank_display}</div> |
| | <div style="flex-grow: 1;"> |
| | <div style="font-weight: bold; font-size: 16px;">{space_name} <span style="font-weight: normal; color: #888; font-size: 14px;">({submitter_name})</span></div> |
| | <div style="font-size: 12px; color: #555;"> |
| | <a href="{row["space_url"]}" target="_blank">π Space</a> |
| | {video_link_html} |
| | | <span style="color: #777;">Track: {row["track"].split(';')[0].split(':')[0]} | Categories: {category_text}</span> |
| | </div> |
| | </div> |
| | <div style="font-size: 20px; font-weight: bold; color: #3B82F6;">{row["votes"]} votes</div> |
| | {action_button_html} |
| | </div> |
| | """ |
| | html += "</div>" |
| |
|
| | project_urls = display_df["space_url"].unique().tolist() |
| | return ( |
| | html, |
| | gr.update(choices=project_urls, value=None), |
| | vote_context_str, |
| | gr.update(visible=False), |
| | ) |
| |
|
| |
|
| | def submit_project( |
| | request: gr.Request, space_url, video_url, selected_tracks, selected_categories |
| | ): |
| | username = get_username(request) |
| | if not username: |
| | gr.Info("Error: You must be logged in to submit a project.") |
| | return gr.skip(), gr.skip(), gr.skip(), gr.skip() |
| |
|
| | if not all([space_url, selected_tracks, selected_categories]): |
| | gr.Info( |
| | "Error: Space URL, at least one Track, and at least one Category are required." |
| | ) |
| | return gr.skip(), gr.skip(), gr.skip(), gr.skip() |
| |
|
| | if not "huggingface.co/spaces/" in space_url: |
| | gr.Info("Error: Please enter a valid Hugging Face Space URL.") |
| | return gr.skip(), gr.skip(), gr.skip(), gr.skip() |
| |
|
| | projects_df = load_data(PROJECTS_FILE, DATASET_REPO_ID) |
| | if space_url in projects_df["space_url"].values: |
| | gr.Info("Error: This project has already been submitted.") |
| | return gr.skip(), gr.skip(), gr.skip(), gr.skip() |
| |
|
| | tracks_str = ";".join(selected_tracks) |
| | categories_str = ";".join(selected_categories) |
| | new_project = pd.DataFrame( |
| | [ |
| | { |
| | "space_url": space_url, |
| | "video_url": video_url, |
| | "track": tracks_str, |
| | "category": categories_str, |
| | "submitted_by": username, |
| | "timestamp": datetime.now().isoformat(), |
| | } |
| | ] |
| | ) |
| | updated_projects = pd.concat([projects_df, new_project], ignore_index=True) |
| | save_data( |
| | updated_projects, |
| | PROJECTS_FILE, |
| | DATASET_REPO_ID, |
| | f"Project submitted by {username}", |
| | ) |
| | gr.Info(f"β
Success! Project '{space_url.split('/')[-1]}' submitted.") |
| | html, dropdown, context, edit_box_visibility = render_leaderboard( |
| | request, LEADERBOARD_VIEWS[0] |
| | ) |
| | return f"Last action: Success.", html, dropdown, context |
| |
|
| |
|
| | def cast_vote(request: gr.Request, project_to_vote, filter_view): |
| | username = get_username(request) |
| | if not username: |
| | gr.Info("Error: You must be logged in to vote.") |
| | return gr.skip(), gr.skip(), gr.skip(), gr.skip() |
| | if not project_to_vote: |
| | gr.Info("Error: Please select a project to vote for.") |
| | return gr.skip(), gr.skip(), gr.skip(), gr.skip() |
| |
|
| | votes_df = load_data(VOTES_FILE, DATASET_REPO_ID) |
| | vote_track, vote_category = parse_view_to_context(filter_view) |
| | existing_vote = votes_df[ |
| | (votes_df["space_url"] == project_to_vote) |
| | & (votes_df["voted_by"] == username) |
| | & (votes_df["track"] == vote_track) |
| | & (votes_df["category"] == vote_category) |
| | ] |
| | if not existing_vote.empty: |
| | gr.Info( |
| | f"Notice: You have already voted for this project in the '{filter_view}' context." |
| | ) |
| | return gr.skip(), gr.skip(), gr.skip(), gr.skip() |
| |
|
| | new_vote = pd.DataFrame( |
| | [ |
| | { |
| | "space_url": project_to_vote, |
| | "voted_by": username, |
| | "track": vote_track, |
| | "category": vote_category, |
| | "timestamp": datetime.now().isoformat(), |
| | } |
| | ] |
| | ) |
| | updated_votes = pd.concat([votes_df, new_vote], ignore_index=True) |
| | save_data(updated_votes, VOTES_FILE, DATASET_REPO_ID, f"Vote cast by {username}") |
| | gr.Info( |
| | f"β
Vote successfully cast for '{project_to_vote.split('/')[-1]}' in '{filter_view}'!" |
| | ) |
| |
|
| | html, dropdown, context, _ = render_leaderboard(request, filter_view) |
| |
|
| | return f"Last action: Success.", html, dropdown, context |
| |
|
| |
|
| | def edit_project( |
| | request: gr.Request, |
| | old_space_url: str, |
| | new_space_url: str, |
| | new_video_url: str, |
| | filter_view: str, |
| | ): |
| | username = get_username(request) |
| | if not username: |
| | gr.Info("Error: Authentication failed. Please log in again.") |
| | return gr.skip(), gr.skip(), gr.skip(), gr.update(visible=False) |
| | projects_df = load_data(PROJECTS_FILE, DATASET_REPO_ID) |
| | votes_df = load_data(VOTES_FILE, DATASET_REPO_ID) |
| | project_index = projects_df[ |
| | (projects_df["space_url"] == old_space_url) |
| | & (projects_df["submitted_by"] == username) |
| | ].index |
| | if project_index.empty: |
| | gr.Info( |
| | "Error: You do not have permission to edit this project, or it no longer exists." |
| | ) |
| | return gr.skip(), gr.skip(), gr.skip(), gr.update(visible=False) |
| | projects_df.loc[project_index, "space_url"] = new_space_url |
| | projects_df.loc[project_index, "video_url"] = new_video_url |
| | save_data( |
| | projects_df, |
| | PROJECTS_FILE, |
| | DATASET_REPO_ID, |
| | f"Project edited by {username}: {old_space_url} -> {new_space_url}", |
| | ) |
| | if old_space_url != new_space_url: |
| | votes_df.loc[votes_df["space_url"] == old_space_url, "space_url"] = ( |
| | new_space_url |
| | ) |
| | save_data( |
| | votes_df, |
| | VOTES_FILE, |
| | DATASET_REPO_ID, |
| | f"Vote URLs updated for project edit by {username}", |
| | ) |
| | gr.Info("β
Project URLs updated successfully! Votes have been preserved.") |
| | html, dropdown, context, _ = render_leaderboard(request, filter_view) |
| | return "Project edited.", html, dropdown, context, gr.update(visible=False) |
| |
|
| |
|
| | |
| | theme = gr.themes.Default( |
| | primary_hue="blue", secondary_hue="yellow", neutral_hue="neutral" |
| | ).set( |
| | body_background_fill="*neutral_100", |
| | body_background_fill_dark="*neutral_800", |
| | body_text_color="*neutral_700", |
| | body_text_color_dark="*neutral_200", |
| | body_text_size="1.1em", |
| | code_background_fill="*neutral_100", |
| | code_background_fill_dark="*neutral_800", |
| | shadow_drop="2px 2px 4px *neutral_400", |
| | block_label_background_fill="*neutral_100", |
| | block_label_background_fill_dark="*neutral_800", |
| | block_label_text_color="*neutral_700", |
| | block_label_text_color_dark="*neutral_200", |
| | block_title_text_color="*primary_700", |
| | block_title_text_color_dark="*primary_300", |
| | panel_background_fill="*neutral_50", |
| | panel_background_fill_dark="*neutral_900", |
| | panel_border_color="*neutral_200", |
| | panel_border_color_dark="*neutral_700", |
| | checkbox_border_color="*neutral_300", |
| | checkbox_border_color_dark="*neutral_600", |
| | input_background_fill="white", |
| | input_background_fill_dark="*neutral_800", |
| | input_border_color="*neutral_300", |
| | input_border_color_dark="*neutral_600", |
| | slider_color="*primary_500", |
| | slider_color_dark="*primary_400", |
| | button_primary_background_fill="*primary_600", |
| | button_primary_background_fill_dark="*primary_500", |
| | button_primary_background_fill_hover="*primary_700", |
| | button_primary_background_fill_hover_dark="*primary_600", |
| | button_primary_text_color="white", |
| | button_primary_text_color_dark="white", |
| | button_secondary_background_fill="*secondary_400", |
| | button_secondary_background_fill_dark="*secondary_500", |
| | button_secondary_background_fill_hover="*secondary_500", |
| | button_secondary_background_fill_hover_dark="*secondary_600", |
| | button_secondary_text_color="*neutral_700", |
| | button_secondary_text_color_dark="*neutral_200", |
| | button_cancel_background_fill="*neutral_200", |
| | button_cancel_background_fill_dark="*neutral_700", |
| | button_cancel_background_fill_hover="*neutral_300", |
| | button_cancel_background_fill_hover_dark="*neutral_600", |
| | button_cancel_text_color="*neutral_700", |
| | button_cancel_text_color_dark="*neutral_200", |
| | ) |
| |
|
| | |
| | with gr.Blocks(theme=theme, title="Hackathon Community Choice") as app: |
| | gr.Markdown("# π Hackathon Community Choice Award") |
| | gr.Markdown( |
| | "Vote for your favorite hackathon projects! Please log in to participate." |
| | ) |
| | gr.LoginButton() |
| |
|
| | with gr.Tabs() as tabs: |
| | with gr.TabItem("π Leaderboard & Vote", id=0): |
| | leaderboard_filter = gr.Radio( |
| | LEADERBOARD_VIEWS, |
| | label="Select Leaderboard View", |
| | value=LEADERBOARD_VIEWS[0], |
| | ) |
| | with gr.Group(visible=False) as edit_group: |
| | gr.Markdown("### Edit Project URLs") |
| | edit_old_url = gr.Textbox(label="Original Space URL", interactive=False) |
| | edit_new_url = gr.Textbox(label="New Space URL") |
| | edit_new_video_url = gr.Textbox(label="New Video URL") |
| | with gr.Row(): |
| | save_edit_button = gr.Button("Save Changes", variant="primary") |
| | cancel_edit_button = gr.Button("Cancel") |
| |
|
| | with gr.Row(): |
| | with gr.Column(scale=2): |
| | leaderboard_html = HTMLPlus( |
| | "Please log in to load...", selectable_elements=[".edit-button"] |
| | ) |
| | with gr.Column(scale=1): |
| | gr.Markdown("### Cast Your Vote") |
| | vote_context_display = gr.Markdown() |
| | vote_status = gr.Markdown() |
| | project_dropdown = gr.Dropdown( |
| | label="Select a Project to Vote For", interactive=True |
| | ) |
| | vote_button = gr.Button( |
| | "π Vote for Selected Project", variant="primary" |
| | ) |
| |
|
| | with gr.TabItem("π Submit Your Project", id=1): |
| | gr.Markdown("### Register Your Project") |
| | submission_status = gr.Markdown() |
| | space_url_input = gr.Textbox( |
| | label="Your Hugging Face Space URL", |
| | placeholder="https://huggingface.co/spaces/...", |
| | ) |
| | |
| | video_url_input = gr.Textbox( |
| | label="Your Demo Video URL (Optional)", |
| | placeholder="https://www.youtube.com/watch?v=...", |
| | ) |
| | track_checkboxes = gr.CheckboxGroup(TRACKS, label="Select Your Track(s)") |
| | category_checkboxes = gr.CheckboxGroup( |
| | CATEGORIES, label="Select Your Category(s)" |
| | ) |
| | submit_button = gr.Button("Submit Project", variant="primary") |
| |
|
| | |
| | def handle_page_load(request: gr.Request, filter_view: str): |
| | username = get_username(request) |
| | if username: |
| | gr.Info(f"Welcome, {username}!") |
| | return render_leaderboard(request, filter_view) |
| |
|
| | def cancel_edit(): |
| | return gr.update(visible=False), "", "", "" |
| |
|
| | def handle_leaderboard_click(evt: gr.SelectData): |
| | if evt.index == ".edit-button": |
| | project_to_edit_url = evt.value.get("url") |
| | if project_to_edit_url: |
| | projects_df = load_data(PROJECTS_FILE, DATASET_REPO_ID) |
| | project_data = projects_df[ |
| | projects_df["space_url"] == project_to_edit_url |
| | ].iloc[0] |
| | return ( |
| | gr.update(visible=True), |
| | project_data["space_url"], |
| | project_data["space_url"], |
| | project_data["video_url"], |
| | ) |
| | return gr.skip(), gr.skip(), gr.skip(), gr.skip() |
| |
|
| | app.load( |
| | fn=handle_page_load, |
| | inputs=[leaderboard_filter], |
| | outputs=[leaderboard_html, project_dropdown, vote_context_display, edit_group], |
| | ) |
| | leaderboard_filter.change( |
| | fn=render_leaderboard, |
| | inputs=[leaderboard_filter], |
| | outputs=[leaderboard_html, project_dropdown, vote_context_display, edit_group], |
| | ) |
| | submit_button.click( |
| | fn=submit_project, |
| | inputs=[ |
| | space_url_input, |
| | video_url_input, |
| | track_checkboxes, |
| | category_checkboxes, |
| | ], |
| | outputs=[ |
| | submission_status, |
| | leaderboard_html, |
| | project_dropdown, |
| | vote_context_display, |
| | ], |
| | ) |
| | vote_button.click( |
| | fn=cast_vote, |
| | inputs=[project_dropdown, leaderboard_filter], |
| | outputs=[vote_status, leaderboard_html, project_dropdown, vote_context_display], |
| | ) |
| |
|
| | leaderboard_html.select( |
| | fn=handle_leaderboard_click, |
| | outputs=[edit_group, edit_old_url, edit_new_url, edit_new_video_url], |
| | ) |
| |
|
| | save_edit_button.click( |
| | fn=edit_project, |
| | inputs=[edit_old_url, edit_new_url, edit_new_video_url, leaderboard_filter], |
| | outputs=[ |
| | submission_status, |
| | leaderboard_html, |
| | project_dropdown, |
| | vote_context_display, |
| | edit_group, |
| | ], |
| | ) |
| | cancel_edit_button.click( |
| | fn=cancel_edit, |
| | outputs=[edit_group, edit_old_url, edit_new_url, edit_new_video_url], |
| | ) |
| |
|
| | app.launch() |
| |
|