|
|
import gradio as gr |
|
|
import pandas as pd |
|
|
from datasets import load_dataset |
|
|
from huggingface_hub import login |
|
|
import os |
|
|
import logging |
|
|
import re |
|
|
|
|
|
|
|
|
logging.basicConfig(level=logging.INFO) |
|
|
logger = logging.getLogger(__name__) |
|
|
|
|
|
|
|
|
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") |
|
|
|
|
|
|
|
|
DATASET_NAME = "ysharma/gradio-hackathon-registrations-winter-2025" |
|
|
|
|
|
|
|
|
_cached_df = None |
|
|
_cache_timestamp = None |
|
|
|
|
|
def load_registration_data(force_refresh=False): |
|
|
"""Load dataset with simple caching""" |
|
|
global _cached_df, _cache_timestamp |
|
|
import time |
|
|
|
|
|
|
|
|
if not force_refresh and _cached_df is not None and _cache_timestamp: |
|
|
if time.time() - _cache_timestamp < 300: |
|
|
return _cached_df |
|
|
|
|
|
try: |
|
|
dataset = load_dataset(DATASET_NAME, split="train") |
|
|
_cached_df = dataset.to_pandas() |
|
|
_cache_timestamp = time.time() |
|
|
logger.info(f"Loaded dataset with {len(_cached_df)} registrations") |
|
|
return _cached_df |
|
|
except Exception as e: |
|
|
logger.error(f"Failed to load dataset: {e}") |
|
|
return None |
|
|
|
|
|
def verify_email(email): |
|
|
""" |
|
|
Verify if an email is registered in the hackathon |
|
|
Returns simple confirmation without exposing other user details |
|
|
""" |
|
|
try: |
|
|
|
|
|
if not email or not email.strip(): |
|
|
return "β Please enter an email address" |
|
|
|
|
|
email = email.strip().lower() |
|
|
|
|
|
|
|
|
email_pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$' |
|
|
if not re.match(email_pattern, email): |
|
|
return "β Please enter a valid email address format" |
|
|
|
|
|
logger.info(f"Verification attempt for email: {email}") |
|
|
|
|
|
|
|
|
df = load_registration_data() |
|
|
if df is None: |
|
|
return "β Unable to verify at this time. Please try again later." |
|
|
|
|
|
|
|
|
match = df[df['email'].str.lower() == email] |
|
|
|
|
|
if len(match) > 0: |
|
|
registration = match.iloc[0] |
|
|
|
|
|
try: |
|
|
timestamp = pd.to_datetime(registration['timestamp']) |
|
|
reg_date = timestamp.strftime("%B %d, %Y") |
|
|
except: |
|
|
reg_date = "N/A" |
|
|
|
|
|
return f"""## β
Email Verified! |
|
|
|
|
|
This email is registered for **MCP's 1st Birthday Hackathon**. |
|
|
|
|
|
- **Registered On:** {reg_date} |
|
|
- **HF Username:** {registration['hf_username']} |
|
|
|
|
|
If this is you, you're all set! π""" |
|
|
else: |
|
|
return """## β Email Not Found |
|
|
|
|
|
This email is not registered for the hackathon. |
|
|
|
|
|
**Want to participate?** |
|
|
Register at: [MCP Birthday Registration](https://huggingface.co/spaces/MCP-1st-Birthday/gradio-hackathon-registration-winter25)""" |
|
|
|
|
|
except Exception as e: |
|
|
logger.error(f"Error during verification: {e}") |
|
|
return f"β An error occurred: {str(e)}" |
|
|
|
|
|
def bulk_verify_emails(emails_text): |
|
|
""" |
|
|
Verify multiple emails at once (comma or newline separated) |
|
|
Useful for sponsors to verify lists |
|
|
""" |
|
|
if not emails_text or not emails_text.strip(): |
|
|
return "β Please enter at least one email address" |
|
|
|
|
|
|
|
|
emails = re.split(r'[,;\n\s]+', emails_text.strip()) |
|
|
emails = [e.strip().lower() for e in emails if e.strip()] |
|
|
|
|
|
if not emails: |
|
|
return "β No valid emails found in input" |
|
|
|
|
|
if len(emails) > 100: |
|
|
return "β Please limit to 100 emails at a time" |
|
|
|
|
|
|
|
|
df = load_registration_data() |
|
|
if df is None: |
|
|
return "β Unable to verify at this time. Please try again later." |
|
|
|
|
|
registered_emails = set(df['email'].str.lower()) |
|
|
|
|
|
verified = [] |
|
|
not_found = [] |
|
|
|
|
|
for email in emails: |
|
|
if email in registered_emails: |
|
|
verified.append(email) |
|
|
else: |
|
|
not_found.append(email) |
|
|
|
|
|
result = f"""## Bulk Verification Results |
|
|
|
|
|
**Total Checked:** {len(emails)} |
|
|
**β
Registered:** {len(verified)} |
|
|
**β Not Found:** {len(not_found)} |
|
|
|
|
|
--- |
|
|
|
|
|
""" |
|
|
|
|
|
if verified: |
|
|
result += "### β
Registered Emails\n" |
|
|
result += "\n".join([f"- {e}" for e in verified]) |
|
|
result += "\n\n" |
|
|
|
|
|
if not_found: |
|
|
result += "### β Not Found\n" |
|
|
result += "\n".join([f"- {e}" for e in not_found]) |
|
|
|
|
|
return result |
|
|
|
|
|
|
|
|
custom_css = """ |
|
|
.gradio-container { |
|
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif; |
|
|
} |
|
|
#verify-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; |
|
|
} |
|
|
#verify-btn:hover { |
|
|
transform: translateY(-2px) !important; |
|
|
box-shadow: 0 6px 20px rgba(0, 0, 0, 0.25) !important; |
|
|
background: #B8CEC7 !important; |
|
|
} |
|
|
#bulk-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; |
|
|
transition: all 0.3s ease !important; |
|
|
} |
|
|
#bulk-btn:hover { |
|
|
transform: translateY(-2px) !important; |
|
|
background: #1a1a1a !important; |
|
|
} |
|
|
""" |
|
|
|
|
|
|
|
|
with gr.Blocks(title="MCP Birthday - Email Verification", css=custom_css, theme="ocean") as demo: |
|
|
|
|
|
gr.Markdown(""" |
|
|
# π§ MCP's 1st Birthday - Email Verification |
|
|
|
|
|
**π
Event Dates:** November 14-30, 2025 |
|
|
|
|
|
Quickly verify if an email is registered for the hackathon. |
|
|
""") |
|
|
|
|
|
gr.Markdown("---") |
|
|
|
|
|
with gr.Tabs(): |
|
|
|
|
|
with gr.Tab("π Single Email"): |
|
|
with gr.Row(): |
|
|
with gr.Column(): |
|
|
email_input = gr.Textbox( |
|
|
label="Email Address", |
|
|
placeholder="Enter email to verify", |
|
|
max_lines=1 |
|
|
) |
|
|
verify_btn = gr.Button("π Verify Email", variant="primary", size="lg", elem_id="verify-btn") |
|
|
|
|
|
with gr.Column(): |
|
|
gr.Markdown(""" |
|
|
### Quick Verification |
|
|
|
|
|
Enter an email address to check if it's registered for the MCP Birthday Hackathon. |
|
|
|
|
|
This is useful for: |
|
|
- Verifying your own registration |
|
|
- Sponsors confirming participant eligibility |
|
|
- Quick status checks |
|
|
""") |
|
|
|
|
|
single_output = gr.Markdown() |
|
|
|
|
|
verify_btn.click( |
|
|
fn=verify_email, |
|
|
inputs=[email_input], |
|
|
outputs=single_output |
|
|
) |
|
|
|
|
|
|
|
|
email_input.submit( |
|
|
fn=verify_email, |
|
|
inputs=[email_input], |
|
|
outputs=single_output |
|
|
) |
|
|
|
|
|
|
|
|
with gr.Tab("π Bulk Verify"): |
|
|
gr.Markdown(""" |
|
|
### Bulk Email Verification |
|
|
|
|
|
Verify multiple emails at once. Enter emails separated by commas, semicolons, or new lines. |
|
|
|
|
|
**Limit:** 100 emails per request |
|
|
""") |
|
|
|
|
|
bulk_input = gr.Textbox( |
|
|
label="Email List", |
|
|
placeholder="[email protected], [email protected]\[email protected]", |
|
|
lines=5 |
|
|
) |
|
|
|
|
|
bulk_btn = gr.Button("π Verify All Emails", variant="primary", size="lg", elem_id="bulk-btn") |
|
|
|
|
|
bulk_output = gr.Markdown() |
|
|
|
|
|
bulk_btn.click( |
|
|
fn=bulk_verify_emails, |
|
|
inputs=[bulk_input], |
|
|
outputs=bulk_output |
|
|
) |
|
|
|
|
|
|
|
|
gr.Markdown(""" |
|
|
--- |
|
|
**π Quick Links:** |
|
|
|
|
|
[Register for Hackathon](https://huggingface.co/spaces/MCP-1st-Birthday/gradio-hackathon-registration-winter25) | [Discord Community](https://discord.gg/92sEPT2Zhv) | [Hackathon Details](https://huggingface.co/MCP-1st-Birthday) |
|
|
""") |
|
|
|
|
|
if __name__ == "__main__": |
|
|
demo.launch() |