import gradio as gr import json from datetime import datetime, timezone from datasets import Dataset, load_dataset from huggingface_hub import login, HfApi import pandas as pd import os import time import tempfile import logging # Setup logging logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) # Authenticate with Hugging Face HF_TOKEN = os.environ.get("HF_TOKEN") if HF_TOKEN: login(token=HF_TOKEN) logger.info("βœ… Authenticated with Hugging Face") else: logger.warning("⚠️ HF_TOKEN not found - running without authentication") # Replace with your actual dataset name for Winter 2025 DATASET_NAME = "ysharma/gradio-hackathon-registrations-winter-2025" def get_countdown_html(): """Generate countdown HTML with current time values calculated in Python""" # Target date: November 13, 2025, 11:59 PM UTC target_date = datetime(2025, 11, 13, 23, 59, 59, tzinfo=timezone.utc) now = datetime.now(timezone.utc) difference = target_date - now if difference.total_seconds() > 0: total_seconds = int(difference.total_seconds()) days = total_seconds // (24 * 3600) hours = (total_seconds % (24 * 3600)) // 3600 minutes = (total_seconds % 3600) // 60 seconds = total_seconds % 60 else: days = hours = minutes = seconds = 0 # Calculate progress for circles (stroke-dashoffset calculation) # The circumference is 283, so we calculate the offset days_offset = 283 - min((days / 365) * 283, 283) hours_offset = 283 - ((hours / 24) * 283) minutes_offset = 283 - ((minutes / 60) * 283) seconds_offset = 283 - ((seconds / 60) * 283) return f""" Hackathon Countdown

Countdown to the Global Event Has Begun. Registrations are now open!

{days:02d}
Days
{hours:02d}
Hours
{minutes:02d}
Minutes
{seconds:02d}
Seconds
""" def safe_add_to_dataset(registration_data, max_retries=5, retry_delay=3): """ Safely add new registration data with bulletproof error handling NEVER creates new datasets - only adds to existing ones """ try: logger.info("Starting new registration process") # Create new row with updated fields new_row = { "timestamp": registration_data["timestamp"], "full_name": registration_data["personal_info"]["full_name"], "email": registration_data["personal_info"]["email"], "hf_username": registration_data["personal_info"]["hf_username"], "gradio_usage": registration_data["personal_info"]["gradio_usage"], "track_interest": str(registration_data["participation"]["track_interest"]), "previous_participation": registration_data["participation"]["previous_participation"], "experience_level": registration_data["participation"]["experience_level"], "how_heard": registration_data["participation"]["how_heard"], "project_description": registration_data["additional"]["project_description"] or "", } logger.info("Created new row data") # Multi-attempt loading with different strategies existing_df = None load_successful = False for attempt in range(max_retries): logger.info(f"Loading attempt {attempt + 1}/{max_retries}") try: # Strategy 1: Direct parquet file access (most reliable) api = HfApi() files = api.list_repo_files(DATASET_NAME, repo_type="dataset") parquet_files = [f for f in files if f.endswith('.parquet') and 'train' in f] if parquet_files: logger.info(f"Found parquet file: {parquet_files[0]}") # Download to temporary location with tempfile.TemporaryDirectory() as temp_dir: parquet_file = api.hf_hub_download( repo_id=DATASET_NAME, filename=parquet_files[0], repo_type="dataset", cache_dir=temp_dir, force_download=True ) existing_df = pd.read_parquet(parquet_file) logger.info(f"Successfully loaded {len(existing_df)} existing rows") load_successful = True break else: logger.warning("No parquet files found") except Exception as load_error: logger.warning(f"Attempt {attempt + 1} failed: {str(load_error)[:100]}") if attempt < max_retries - 1: logger.info(f"Waiting {retry_delay} seconds before retry...") time.sleep(retry_delay) continue # CRITICAL SAFETY CHECK: Never proceed without existing data if not load_successful or existing_df is None: error_msg = "🚨 CRITICAL SAFETY ERROR: Could not load existing dataset after multiple attempts." logger.error(error_msg) logger.error("🚨 REFUSING to proceed to prevent data loss!") logger.error("🚨 Please check dataset manually or contact administrators.") return False, ( "❌ Registration temporarily unavailable due to technical issues. " "Please try again in a few minutes. If the problem persists, contact support." ) # Check for duplicates duplicate_check = existing_df[ (existing_df['email'].str.lower() == new_row['email'].lower()) | (existing_df['hf_username'].str.lower() == new_row['hf_username'].lower()) ] if len(duplicate_check) > 0: logger.warning("Duplicate registration attempt detected") return False, "❌ Error: This email or Hugging Face username is already registered." # Add new row safely combined_df = pd.concat([existing_df, pd.DataFrame([new_row])], ignore_index=True) logger.info(f"Combined data now has {len(combined_df)} rows (was {len(existing_df)})") # Create timestamped backup before upload backup_timestamp = int(time.time()) try: # Convert to Dataset and upload logger.info("Converting to HuggingFace Dataset format...") updated_dataset = Dataset.from_pandas(combined_df) # Create backup first backup_name = f"{DATASET_NAME}-auto-backup-{backup_timestamp}" logger.info(f"Creating backup: {backup_name}") updated_dataset.push_to_hub(backup_name, private=True) logger.info("Pushing to main dataset...") updated_dataset.push_to_hub(DATASET_NAME, private=True) logger.info("βœ… Successfully saved new registration") logger.info(f"Total rows in dataset: {len(combined_df)}") # Quick verification time.sleep(2) try: verify_files = api.list_repo_files(DATASET_NAME, repo_type="dataset") logger.info("βœ… Upload verification: Files updated successfully") except: logger.warning("⚠️ Could not verify upload (this may be normal)") return True, "Registration successful!" except Exception as upload_error: error_msg = str(upload_error).lower() if any(indicator in error_msg for indicator in ['rate limit', '429', 'too many requests']): logger.warning("🚨 Rate limit hit - registration system temporarily busy") return False, "⏳ Registration temporarily unavailable due to high server load. Please try again in 10-15 minutes." else: logger.error(f"Upload failed: {upload_error}") return False, f"❌ Registration failed during upload: {str(upload_error)}" except Exception as e: logger.error(f"❌ Unexpected error in registration: {e}") import traceback traceback.print_exc() return False, f"❌ Registration failed: {str(e)}" def verify_registration(email, hf_username): """ Verify if a user is registered by checking both email and HF username Returns registration details if both match """ try: # Validate inputs if not email or not email.strip(): return "❌ Please enter your email address" if not hf_username or not hf_username.strip(): return "❌ Please enter your Hugging Face username" logger.info(f"Verification attempt for email: {email}") # Load dataset try: dataset = load_dataset(DATASET_NAME, split="train") df = dataset.to_pandas() logger.info(f"Loaded dataset with {len(df)} registrations") except Exception as load_error: logger.error(f"Failed to load dataset: {load_error}") return "❌ Unable to verify registration at this time. Please try again later." # Search for exact match (both email AND username must match) email_lower = email.strip().lower() username_lower = hf_username.strip().lower() match = df[ (df['email'].str.lower() == email_lower) & (df['hf_username'].str.lower() == username_lower) ] if len(match) == 0: # Check if email exists with different username email_exists = df[df['email'].str.lower() == email_lower] username_exists = df[df['hf_username'].str.lower() == username_lower] if len(email_exists) > 0 and len(username_exists) == 0: return "❌ Email found but Hugging Face username doesn't match. Please check your username." elif len(username_exists) > 0 and len(email_exists) == 0: return "❌ Hugging Face username found but email doesn't match. Please check your email." else: return "❌ No registration found with this email and Hugging Face username combination." # Registration found - format the details registration = match.iloc[0] # Parse timestamp try: timestamp = pd.to_datetime(registration['timestamp']) reg_date = timestamp.strftime("%B %d, %Y at %I:%M %p UTC") except: reg_date = registration['timestamp'] # Format track interests track_interest = registration['track_interest'] if isinstance(track_interest, str): # Clean up the string representation of list track_interest = track_interest.strip("[]'\"").replace("'", "") result = f""" ## βœ… Registration Confirmed! **Participant Details:** - **Full Name:** {registration['full_name']} - **Email:** {registration['email']} - **Hugging Face Username:** {registration['hf_username']} - **Registered On:** {reg_date} **Hackathon Participation:** - **Track Interest:** {track_interest} - **Gradio Usage:** {registration['gradio_usage']} - **Previous Participation:** {registration['previous_participation']} - **Experience Level:** {registration['experience_level']} - **How You Heard:** {registration['how_heard']} **Project Idea:** {registration['project_description'] if registration['project_description'] else '_No project description provided_'} --- **Next Steps:** - πŸ”‘ API and Compute credits will be distributed before or during the hackathon - πŸ’¬ Join our Discord community channel `mcp-1st-birthday-officialπŸ†`: https://discord.gg/92sEPT2Zhv - πŸ“§ Watch your email for important updates - πŸš€ Start planning your project! """ logger.info(f"βœ… Verification successful for {email}") return result except Exception as e: logger.error(f"Error during verification: {e}") import traceback traceback.print_exc() return f"❌ An error occurred during verification: {str(e)}" def submit_registration(full_name, email, hf_username, gradio_usage, track_interest, previous_participation, experience_level, how_heard, acknowledgment, project_description): """Process the registration form submission with enhanced validation""" # Enhanced validation if not full_name or not full_name.strip(): return "❌ Error: Please enter your full name" if not email or not email.strip(): return "❌ Error: Please enter your email address" if not hf_username or not hf_username.strip(): return "❌ Error: Please enter your Hugging Face username" if not gradio_usage: return "❌ Error: Please select how you're currently using Gradio" if not track_interest: return "❌ Error: Please select at least one track of interest" if not previous_participation: return "❌ Error: Please select your hackathon experience" if not experience_level: return "❌ Error: Please select your experience level" if not how_heard: return "❌ Error: Please select how you heard about this hackathon" if not acknowledgment: return "❌ Error: Please confirm your acknowledgment to participate" # Email format validation import re email_pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$' if not re.match(email_pattern, email.strip()): return "❌ Error: Please enter a valid email address" # Process the registration data registration_data = { "timestamp": datetime.now().isoformat(), "personal_info": { "full_name": full_name.strip(), "email": email.strip().lower(), "hf_username": hf_username.strip(), "gradio_usage": gradio_usage, }, "participation": { "track_interest": track_interest, "previous_participation": previous_participation, "experience_level": experience_level, "how_heard": how_heard, }, "additional": { "project_description": project_description.strip() if project_description else None, } } # Save to Hugging Face dataset with bulletproof error handling success, message = safe_add_to_dataset(registration_data) if not success: return f"❌ Registration failed: {message}" return f"""βœ… Registration Successful! Thank you, {full_name}! Your registration has been received and saved.
πŸ“§ You will receive information about API credits as we finalize sponsor partnerships.
πŸ”‘ API and Compute credits will be distributed before or during the Hackathon starting date.
πŸ’¬ Be sure to **join the Huggingface organization** for regular updates on the hackathon and **to submit your entries**. Join our Discord community channel `mcp-1st-birthday-officialπŸ†` for updates and support during the event: https://discord.gg/92sEPT2Zhv **See you at the hackathon! πŸš€**""" # Health check function def check_dataset_health(): """Check if the dataset is accessible and healthy""" try: api = HfApi() files = api.list_repo_files(DATASET_NAME, repo_type="dataset") parquet_files = [f for f in files if f.endswith('.parquet')] if parquet_files: logger.info(f"βœ… Dataset health check passed - found {len(parquet_files)} parquet files") return True else: logger.warning("⚠️ Dataset health check: No parquet files found") return False except Exception as e: logger.error(f"❌ Dataset health check failed: {e}") return False # Initialize with health check logger.info("πŸš€ Starting Gradio Hackathon Registration System - Winter 2025") logger.info(f"πŸ“Š Dataset: {DATASET_NAME}") if check_dataset_health(): logger.info("βœ… System ready - dataset is healthy") else: logger.warning("⚠️ System starting with dataset health warnings") # Custom CSS for MCP theme custom_css = """ .gradio-container { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif; } .header-gradient { color: #000000; } /* MCP-themed Submit Button Styling */ #gradient-submit-btn { background: #C8DDD7 !important; border: 2px solid #000000 !important; color: #000000 !important; font-weight: 600 !important; font-size: 18px !important; padding: 16px 32px !important; border-radius: 12px !important; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15) !important; transition: all 0.3s ease !important; text-transform: none !important; } #gradient-submit-btn:hover { transform: translateY(-2px) !important; box-shadow: 0 6px 20px rgba(0, 0, 0, 0.25) !important; background: #B8CEC7 !important; } #gradient-submit-btn:active { transform: translateY(0px) !important; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2) !important; } /* Disabled state for the button */ #gradient-submit-btn:disabled { opacity: 0.6 !important; cursor: not-allowed !important; transform: none !important; } /* Verify button styling - Inverted MCP theme */ #verify-btn { background: #000000 !important; border: 2px solid #C8DDD7 !important; color: #C8DDD7 !important; font-weight: 600 !important; font-size: 16px !important; padding: 12px 24px !important; border-radius: 8px !important; box-shadow: 0 3px 10px rgba(200, 221, 215, 0.3) !important; transition: all 0.3s ease !important; } #verify-btn:hover { transform: translateY(-2px) !important; box-shadow: 0 5px 15px rgba(200, 221, 215, 0.5) !important; background: #1a1a1a !important; border-color: #D8EDE7 !important; } """ # Function to update countdown periodically def update_countdown(): """Update the countdown HTML""" return gr.HTML(get_countdown_html()) # Create the Gradio interface with gr.Blocks(title="Gradio Agents & MCP Hackathon - Winter 2025", css=custom_css, theme="ocean") as demo: # Header gr.Markdown(""" # MCP's 1st Birthday - Hosted by Anthropic and Gradio **Join our [Discord Community](https://discord.gg/92sEPT2Zhv) channel `mcp-1st-birthday-officialπŸ†` for active support during the hackathon.** **NOTE: If the registration app says you are registered, then that information is correct and you don't need to send us anything else. NO CONFIRMATION EMAILS ARE SENT FROM OUR SIDE.** **πŸ“… Event Dates:** November 14-30, 2025 (17 days, 3 weekends) | **πŸ† Prizes: $17,000+ USD in cash prizes** | **πŸ’» Location:** Online & Global **🎁 FREE API & Compute Credits** (Details announced soon): - API credits from major AI providers - Access to latest and strongest LLMs - Compute resources for building your projects **The definitive Agents & MCP event is back!** OpenAI, Microsoft, Google DeepMind, and numerous startups have already adopted MCP. Join the community that launched the MCP developer movement. Participate and stand a chance to learn the latest AI technologies and also Win BIG! """) # Create countdown HTML component that will be updated countdown_display = gr.HTML(get_countdown_html()) gr.Markdown("---") # Create tabs with gr.Tabs(): # Registration Tab with gr.Tab("πŸ“ Register"): with gr.Row(): with gr.Column(): # Personal Information Section gr.Markdown("## 1. Personal Information") full_name = gr.Textbox( label="Full Name *", placeholder="Your full name as you'd like it on certificates", max_lines=1 ) email = gr.Textbox( label="Email Address *", placeholder="Primary contact email (we'll send important updates here)", max_lines=1 ) hf_username = gr.Textbox( label="Hugging Face Username *", placeholder="Required for organization access and submissions", max_lines=1 ) gradio_usage = gr.Radio( label="How are you currently using Gradio? *", choices=[ "Professional work - My company uses Gradio", "Personal projects - Building side projects", "Academic/Research - University or research work", "Learning - New to Gradio, want to learn", "Not using yet - Interested to start" ], info="Helps us understand our community better" ) with gr.Column(): # Hackathon Participation Section gr.Markdown("## 2. Hackathon Participation") track_interest = gr.CheckboxGroup( label="Which track interests you most? *", choices=[ "Track 1: Building MCP", "Track 2: MCP in Action (Agents)", ] ) previous_participation = gr.Radio( label="Hackathon experience *", choices=[ "I participated in June 2025 Agents & MCP Hackathon", "I've done other AI hackathons before", "This is my first AI hackathon" ] ) experience_level = gr.Radio( label="Your experience with AI/Agents development *", choices=[ "Beginner - New to AI development", "Intermediate - Some AI projects", "Advanced - Regular AI developer", "Expert - Professional AI engineer" ] ) how_heard = gr.Dropdown( label="How did you hear about this hackathon? *", choices=[ "Hugging Face email/newsletter", "Twitter/X", "LinkedIn", "Discord", "From a colleague/friend", "YouTube", "Reddit", "Sponsor announcement", "I participated in June 2025", "Other" ] ) with gr.Row(): with gr.Column(): # Additional Information Section gr.Markdown("## 3. Additional Information") project_description = gr.Textbox( label="What type of project are you most excited to build?", placeholder="Brief description of your project idea or what interests you most", lines=3 ) with gr.Column(): # Acknowledgment Section gr.Markdown("## 4. Acknowledgment") acknowledgment = gr.Checkbox( label="Acknowledgment *", info="""I commit to actively participate and submit a project by November 30, 2025. I understand that API/compute credits are provided to support hackathon participation and should be used for building my hackathon project. I commit to using these credits responsibly during the event period.""", ) # Submit button submit_btn = gr.Button("πŸš€ Register for Hackathon", variant="primary", size="lg", elem_id="gradient-submit-btn") # Output output = gr.Markdown() # Enhanced submit function def handle_registration_with_state(*args): try: result = submit_registration(*args) return result, gr.Button("πŸš€ Register for Hackathon", interactive=True, variant="primary") except Exception as e: logger.error(f"Registration handling error: {e}") return f"❌ An unexpected error occurred: {str(e)}", gr.Button("πŸš€ Register for Hackathon", interactive=True, variant="primary") # Click event with updated inputs submit_btn.click( fn=lambda *args: (gr.Button("⏳ Processing Registration...", interactive=False, variant="secondary"), ""), inputs=[ full_name, email, hf_username, gradio_usage, track_interest, previous_participation, experience_level, how_heard, acknowledgment, project_description, ], outputs=[submit_btn, output], queue=False ).then( fn=handle_registration_with_state, inputs=[ full_name, email, hf_username, gradio_usage, track_interest, previous_participation, experience_level, how_heard, acknowledgment, project_description, ], outputs=[output, submit_btn], queue=True ) # Verification Tab with gr.Tab("πŸ” Verify Registration"): gr.Markdown(""" ## Check Your Registration Status Enter your email address and Hugging Face username to verify your registration and view your details. **Note:** Both email and username must match exactly for security purposes. """) with gr.Row(): with gr.Column(): verify_email = gr.Textbox( label="Email Address", placeholder="Enter your registered email", max_lines=1 ) verify_hf_username = gr.Textbox( label="Hugging Face Username", placeholder="Enter your registered HF username", max_lines=1 ) verify_btn = gr.Button("πŸ” Check Registration Status", variant="primary", size="lg", elem_id="verify-btn") with gr.Column(): gr.Markdown(""" ### Need Help? - Make sure you enter the **exact** email and username you used during registration - Both fields are **case-insensitive** but must match your registration - If you can't find your registration, try registering again or contact support **Support:** - Discord: https://discord.gg/92sEPT2Zhv - Email: gradio-team@huggingface.co """) verify_output = gr.Markdown() # Verification click event verify_btn.click( fn=verify_registration, inputs=[verify_email, verify_hf_username], outputs=verify_output ) # Footer gr.Markdown(""" **Questions?** Join Huggingface [Discord](https://discord.gg/92sEPT2Zhv) or email: gradio-team@huggingface.co """) # Set up a timer to update the countdown every second # This will refresh the countdown display periodically demo.load(update_countdown, None, countdown_display, every=1) if __name__ == "__main__": demo.launch(allowed_paths=["."])