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 load_dotenv() # CONFIGURATION DATASET_REPO_ID = "elismasilva/hackathon-community-voting" PROJECTS_FILE = "projects.csv" VOTES_FILE = "votes.csv" # Authentication with the token from Space secrets HF_TOKEN = os.getenv("HF_TOKEN") api = HfApi(token=HF_TOKEN) # Hackathon Structure 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)"] # DATA HANDLING FUNCTIONS def load_data(filename, repo_id): """Loads a CSV from the dataset, or creates an empty DataFrame if it doesn't exist.""" try: filepath = hf_hub_download(repo_id=repo_id, filename=filename, repo_type="dataset", token=HF_TOKEN) return pd.read_csv(filepath) 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", "timestamp"]) return pd.DataFrame() def save_data(df, filename, repo_id, commit_message): """Saves a DataFrame as a CSV to the dataset.""" 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) # CORE LOGIC def render_leaderboard(request: gr.Request, filter_view: str): """ Renders the leaderboard HTML. It gets the user identity from the request object. This is a "pure" rendering function without side-effects. """ username = request.request.session['oauth_info']['userinfo']['preferred_username'] if hasattr(request.request, "session") and len(request.request.session) > 0 and 'userinfo' in request.request.session['oauth_info'] else None if not username: return "

Please log in to view and vote on projects!

", gr.update(choices=[], value=None) projects_df = load_data(PROJECTS_FILE, DATASET_REPO_ID) votes_df = load_data(VOTES_FILE, DATASET_REPO_ID) if projects_df.empty: return "

No projects have been submitted yet. Be the first!

", gr.update(choices=[], value=None) vote_counts = votes_df['space_url'].value_counts().reset_index() vote_counts.columns = ['space_url', 'votes'] full_leaderboard_df = pd.merge(projects_df, vote_counts, on="space_url", how="left").fillna(0) full_leaderboard_df['votes'] = full_leaderboard_df['votes'].astype(int) # Filtering logic... if filter_view == "Track 1 (Overall)": filtered_df = full_leaderboard_df[full_leaderboard_df['track'] == TRACKS[0]] elif filter_view == "Track 2 (Enterprise)": filtered_df = full_leaderboard_df[(full_leaderboard_df['track'] == TRACKS[1]) & (full_leaderboard_df['category'] == 'Enterprise')] elif filter_view == "Track 2 (Consumer)": filtered_df = full_leaderboard_df[(full_leaderboard_df['track'] == TRACKS[1]) & (full_leaderboard_df['category'] == 'Consumer')] elif filter_view == "Track 2 (Creative)": filtered_df = full_leaderboard_df[(full_leaderboard_df['track'] == TRACKS[1]) & (full_leaderboard_df['category'] == 'Creative')] else: filtered_df = full_leaderboard_df[full_leaderboard_df['track'] == TRACKS[0]] if filtered_df.empty: return f"

No projects submitted for this view ('{filter_view}') yet.

", gr.update(choices=[], value=None) filtered_df = filtered_df.sort_values(by="votes", ascending=False).reset_index(drop=True) html = "
" # HTML generation remains the same... trophies = {0: "🥇", 1: "🥈", 2: "🥉"} for index, row in filtered_df.iterrows(): rank = trophies.get(index, f"#{index + 1}") space_name = re.sub(r'https://huggingface.co/spaces/', '', row['space_url']) html += f"""
{rank}
{space_name}
🚀 Space | 🎬 Video | Track: {row['track'].split(':')[0]} | Category: {row['category']}
{row['votes']} votes
""" html += "
" project_urls = filtered_df['space_url'].tolist() return html, gr.update(choices=project_urls, value=None) def submit_project(request: gr.Request, space_url, video_url, track, category): """Adds a new project.""" username = request.request.session['oauth_info']['userinfo']['preferred_username'] if hasattr(request.request, "session") and len(request.request.session) > 0 and 'userinfo' in request.request.session['oauth_info'] else None if not username: gr.Info("Error: You must be logged in to submit a project.") return gr.skip(), gr.skip(), gr.skip() if not all([space_url, video_url, track, category]): gr.Info("Error: All fields are required.") return gr.skip(), gr.skip(), gr.skip() if not ("huggingface.co/spaces/" in space_url and ("youtube.com/" in video_url or "youtu.be/" in video_url)): gr.Info("Error: Please enter valid URLs from Hugging Face Spaces and YouTube.") return 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() new_project = pd.DataFrame([{"space_url": space_url, "video_url": video_url, "track": track, "category": category, "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.") # After submission, refresh the leaderboard html, dropdown_update = render_leaderboard(request, LEADERBOARD_VIEWS[0]) return f"Last action: Success.", html, dropdown_update def cast_vote(request: gr.Request, project_to_vote, filter_view): """Registers a vote.""" username = request.request.session['oauth_info']['userinfo']['preferred_username'] if hasattr(request.request, "session") and len(request.request.session) > 0 and 'userinfo' in request.request.session['oauth_info'] else None if not username: gr.Info("Error: You must be logged in to vote.") return 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() votes_df = load_data(VOTES_FILE, DATASET_REPO_ID) if not votes_df[(votes_df['space_url'] == project_to_vote) & (votes_df['voted_by'] == username)].empty: gr.Info(f"Notice: You have already voted for '{project_to_vote.split('/')[-1]}'.") return gr.skip(), gr.skip(), gr.skip() new_vote = pd.DataFrame([{"space_url": project_to_vote, "voted_by": username, "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]}'!") # After voting, refresh the leaderboard with the current filter html, dropdown_update = render_leaderboard(request, filter_view) return f"Last action: Success.", html, dropdown_update 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(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.Row(): with gr.Column(scale=2): leaderboard_html = gr.HTML("Please log in to load...") with gr.Column(scale=1): gr.Markdown("### Cast Your Vote!") 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 (YouTube)", placeholder="https://www.youtube.com/watch?v=...") track_radio = gr.Radio(TRACKS, label="Select Your Track") category_dropdown = gr.Dropdown(CATEGORIES, label="Select Your Category") submit_button = gr.Button("Submit Project", variant="primary") # Event Handling def handle_page_load(request: gr.Request, filter_view: str): """Called only on app.load. Gives welcome message and renders.""" username = request.request.session['oauth_info']['userinfo']['preferred_username'] if hasattr(request.request, "session") and len(request.request.session) > 0 and 'userinfo' in request.request.session['oauth_info'] else None if username: gr.Info(f"Welcome, {username}!") return render_leaderboard(request, filter_view) # The page load triggers the first render and welcome message. app.load( fn=handle_page_load, inputs=[leaderboard_filter], outputs=[leaderboard_html, project_dropdown] ) # When the user changes the filter, re-render the leaderboard (no welcome message). leaderboard_filter.change( fn=render_leaderboard, inputs=[leaderboard_filter], outputs=[leaderboard_html, project_dropdown] ) submit_button.click( fn=submit_project, inputs=[space_url_input, video_url_input, track_radio, category_dropdown], outputs=[submission_status, leaderboard_html, project_dropdown] ) vote_button.click( fn=cast_vote, inputs=[project_dropdown, leaderboard_filter], outputs=[vote_status, leaderboard_html, project_dropdown] ) app.launch(theme=theme)