Spaces:
Sleeping
Sleeping
import gradio as gr | |
import json | |
import pandas as pd | |
import os | |
DATA_FILE = os.path.join("data", "teamup_data.json") | |
ADMIN_CODE = os.getenv("ADMIN_CODE", "") | |
# Ensure data file exists | |
os.makedirs("data", exist_ok=True) | |
if not os.path.exists(DATA_FILE) or os.path.getsize(DATA_FILE) == 0: | |
with open(DATA_FILE, "w") as f: | |
json.dump([], f) | |
def submit_profile(name, discord, city, country, address, looking, onlinecheck, languages, laptop, robot, skills, describe3, experience, idea): | |
print("π’ Submit button clicked.") | |
print(f"Incoming: {discord=}, {city=}, {country=}, {languages=}, {laptop=}, {robot=}") | |
if not discord or not city or not country or not laptop or not robot: | |
return "β Please fill in all required fields." | |
if not languages or not isinstance(languages, list) or len(languages) == 0: | |
return "β Please select at least one language." | |
# Ensure country is stored as a string (in case form allows lists) | |
if isinstance(country, list): | |
country = country[0] if country else "" | |
with open(DATA_FILE, "r") as f: | |
data = json.load(f) | |
for d in data: | |
if d["Discord"].lower() == discord.lower(): | |
d.update({ | |
"Name": name, | |
"City": city, | |
"Country": country, | |
"Address": address, | |
"Looking for Team": looking, | |
"Onlinecheck": onlinecheck, | |
"Languages": languages, | |
"Laptop": laptop, | |
"Robot": robot, | |
"Skills": skills, | |
"Describe3": describe3, | |
"Experience": experience, | |
"Project Idea": idea | |
}) | |
break | |
else: | |
data.append({ | |
"Name": name, | |
"Discord": discord, | |
"City": city, | |
"Country": country, | |
"Address": address, | |
"Looking for Team": looking, | |
"Onlinecheck": onlinecheck, | |
"Languages": languages, | |
"Laptop": laptop, | |
"Robot": robot, | |
"Skills": skills, | |
"Describe3": describe3, | |
"Experience": experience, | |
"Project Idea": idea | |
}) | |
try: | |
with open(DATA_FILE, "w") as f: | |
json.dump(data, f, indent=2) | |
print(f"β Successfully wrote {len(data)} profiles to {DATA_FILE}") | |
except Exception as e: | |
print(f"β Failed to write to {DATA_FILE}: {e}") | |
return "β Error saving your profile. Please try again." | |
return "β Profile saved!" | |
def filter_by_fields(selected_country, selected_city, selected_language): | |
with open(DATA_FILE, "r") as f: | |
data = json.load(f) | |
df = pd.DataFrame(data) | |
# Convert list values to readable strings | |
df["Languages"] = df["Languages"].apply(lambda langs: ", ".join(langs) if isinstance(langs, list) else langs) | |
if df.empty or "Country" not in df.columns or "Languages" not in df.columns: | |
return "<p>No participants found.</p>" | |
if selected_country != "All": | |
df = df[df["Country"] == selected_country] | |
if selected_city != "All": | |
df = df[df["City"] == selected_city] | |
if selected_language != "All": | |
df = df[df["Languages"].apply(lambda langs: selected_language in langs)] | |
# Hide address | |
if "Address" in df.columns: | |
df = df.drop(columns=["Address"]) | |
# Rename column headers for display only | |
display_names = { | |
"Discord": "Discord", | |
"Name": "Name", | |
"City": "City", | |
"Country": "Country", | |
"Looking for Team": "Looking for Team", | |
"Onlinecheck": "How?", | |
"Languages": "Languages", | |
"Laptop": "Laptop", | |
"Robot": "Robot", | |
"Skills": "Skills", | |
"Describe3": "Describe", | |
"Experience": "Experience", | |
"Project Idea": "Project Idea" | |
} | |
html = '<h3 style="margin-top:20px;">π Find your matching Teammates & Register your team <a href="https://forms.gle/gJEMGD4CEA2emhD18" target="_blank">here</a>ππ</h3>' | |
html += "<table style='width:100%; border-collapse: collapse;'>" | |
# Header row | |
html += "<tr>" + "".join( | |
f"<th style='border: 1px solid #ccc; padding: 6px;'>{display_names.get(col, col)}</th>" | |
for col in df.columns | |
) + "</tr>" | |
# Data rows | |
for _, row in df.iterrows(): | |
html += "<tr>" | |
for col in df.columns: | |
val = row[col] | |
if col == "Discord": | |
val = f"<a href='https://discord.com/users/{val}' target='_blank'>{val}</a>" | |
html += f"<td style='border: 1px solid #eee; padding: 6px;'>{val}</td>" | |
html += "</tr>" | |
html += "</table>" | |
return html | |
def update_dropdowns(): | |
with open(DATA_FILE, "r") as f: | |
data = json.load(f) | |
if not data: | |
return ["All"], ["All"], ["All"] | |
df = pd.DataFrame(data) | |
if "Country" not in df.columns or "Languages" not in df.columns or "City" not in df.columns: | |
return ["All"], ["All"], ["All"] | |
country_choices = sorted(list(df["Country"].dropna().unique())) | |
city_choices = sorted(list(df["City"].dropna().unique())) | |
language_set = set() | |
for lang_list in df["Languages"].dropna(): | |
language_set.update(lang_list) | |
return ( | |
["All"] + country_choices, | |
["All"] + sorted(language_set), | |
["All"] + city_choices | |
) | |
def delete_by_discord(discord, code): | |
if code != ADMIN_CODE: | |
return "β Invalid admin code." | |
with open(DATA_FILE, "r") as f: | |
data = json.load(f) | |
new_data = [d for d in data if d["Discord"].lower() != discord.lower()] | |
with open(DATA_FILE, "w") as f: | |
json.dump(new_data, f, indent=2) | |
return f"ποΈ Deleted user with Discord: {discord}" | |
with gr.Blocks() as demo: | |
gr.Markdown("# π LeRobot Worldwide Hackathon - Team-Up Dashboard") | |
gr.Markdown("Submit or update your profile. Required fields marked with *. Find matching teammates and contact them on Discord.") | |
with gr.Row(): | |
with gr.Column(): | |
name = gr.Text(label="Name") | |
discord = gr.Text(label="π€ Discord Username *") | |
city = gr.Text(label="π City *") | |
country = gr.Text(label="π Country *") | |
address = gr.Text(label="Address (optional)") | |
looking = gr.Radio(["Yes", "No"], label="π Looking for a team?") | |
onlinecheck = gr.Radio(["Participate Online", "Join a Local Hackathon"], label="π I will...") | |
languages = gr.CheckboxGroup(choices=["English", "French", "Spanish", "German", "Portuguese", "Chinese", "Arabic", "Hindi"], label="Languages Spoken *") | |
laptop = gr.Text(label="π» Laptop Setup *") | |
robot = gr.Text(label="Robot Setup *") | |
skills = gr.Text(label="π§ Your Skills (comma separated)") | |
describe3 = gr.Text(label="π€ 3 Words That Describe You") | |
experience = gr.Dropdown(choices=["Beginner", "Intermediate", "Advanced"], label="Experience Level", value="Beginner") | |
idea = gr.Textbox(label="Project Idea (optional)") | |
submit_btn = gr.Button("Submit or Update Profile β ") | |
status = gr.Textbox(label="", interactive=False) | |
with gr.Column(): | |
gr.Markdown("π― Choose your preferences to find your teammates (country, city or language)") | |
country_filter = gr.Dropdown(label="Filter by Country", choices=["All"], value="All", allow_custom_value=False) | |
city_filter = gr.Dropdown(label="Filter by City", choices=["All"], value="All", allow_custom_value=False) | |
language_filter = gr.Dropdown(label="Filter by Language", choices=["All"], value="All", allow_custom_value=False) | |
table_html = gr.HTML(label="Matching Participants") | |
submit_btn.click( | |
submit_profile, | |
inputs=[name, discord, city, country, address, looking, onlinecheck, languages, laptop, robot, skills, describe3, experience, idea], | |
outputs=[status] | |
) | |
def update_dropdown_choices(): | |
with open(DATA_FILE, "r") as f: | |
data = json.load(f) | |
df = pd.DataFrame(data) | |
country_choices = sorted(df["Country"].dropna().unique()) if "Country" in df else [] | |
city_choices = sorted(df["City"].dropna().unique()) if "City" in df else [] | |
language_set = set() | |
if "Languages" in df: | |
for lang_list in df["Languages"].dropna(): | |
if isinstance(lang_list, list): | |
language_set.update(lang_list) | |
elif isinstance(lang_list, str): | |
language_set.update(lang_list.split(", ")) | |
return ( | |
gr.update(choices=["All"] + list(country_choices), value="All"), | |
gr.update(choices=["All"] + list(city_choices), value="All"), | |
gr.update(choices=["All"] + sorted(language_set), value="All") | |
) | |
def download_csv(code): | |
if code != ADMIN_CODE: | |
raise gr.Error("β Invalid admin code.") | |
with open(DATA_FILE, "r") as f: | |
data = json.load(f) | |
df = pd.DataFrame(data) | |
csv_path = os.path.join("data", "teamup_export.csv") | |
df.to_csv(csv_path, index=False) | |
return csv_path | |
with demo: | |
demo.load( | |
fn=lambda: filter_by_fields("All", "All", "All"), | |
inputs=[], | |
outputs=[table_html] | |
) | |
demo.load(fn=update_dropdown_choices, outputs=[country_filter, city_filter, language_filter]) | |
country_filter.change(fn=filter_by_fields, inputs=[country_filter, city_filter, language_filter], outputs=table_html) | |
city_filter.change(fn=filter_by_fields, inputs=[country_filter, city_filter, language_filter], outputs=table_html) | |
language_filter.change(fn=filter_by_fields, inputs=[country_filter, city_filter, language_filter], outputs=table_html) | |
gr.Markdown("---\n### π‘οΈ Admin Panel (delete by Discord)") | |
admin_discord = gr.Text(label="Discord Username") | |
admin_code = gr.Text(label="Admin Code", type="password") | |
del_btn = gr.Button("Delete Profile") | |
del_status = gr.Textbox(label="Status", interactive=False) | |
del_btn.click(delete_by_discord, inputs=[admin_discord, admin_code], outputs=del_status) | |
# π CSV Download Section (admin-only) | |
gr.Markdown("---\n### π₯ Admin Export CSV") | |
export_code = gr.Text(label="Admin Code", type="password") | |
download_btn = gr.Button("Generate and Download CSV") | |
download_file = gr.File(label="CSV Export", interactive=False) | |
download_btn.click(fn=download_csv, inputs=[export_code], outputs=[download_file]) | |
demo.launch() | |