maringetxway commited on
Commit
2a6ea32
Β·
verified Β·
1 Parent(s): db43b4a

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +73 -118
app.py CHANGED
@@ -21,8 +21,7 @@ if not os.path.exists(DATA_FILE) or os.path.getsize(DATA_FILE) == 0:
21
  # Country list
22
  ALL_COUNTRIES = sorted(list(set([
23
  "United States of America", "United Kingdom", "India", "France", "Germany", "Canada", "Australia", "Japan", "Brazil", "Mexico",
24
- # Add or reduce to most relevant countries only for dropdown
25
- ] + [ # Fallback: full list
26
  "Afghanistan", "Albania", "Algeria", "Andorra", "Angola", "Argentina", "Armenia", "Austria", "Azerbaijan",
27
  "Bangladesh", "Belgium", "Bhutan", "Bolivia", "Bosnia and Herzegovina", "Botswana", "Bulgaria", "Cambodia",
28
  "Chile", "China", "Colombia", "Croatia", "Cuba", "Czech Republic", "Denmark", "Dominican Republic", "Ecuador",
@@ -35,20 +34,23 @@ ALL_COUNTRIES = sorted(list(set([
35
  ])))
36
 
37
  # Backup
 
38
  def backup_data():
39
  os.makedirs(BACKUP_DIR, exist_ok=True)
40
  timestamp = datetime.datetime.now().strftime('%Y%m%d_%H%M%S')
41
  backup_file = os.path.join(BACKUP_DIR, f'teamup_data_backup_{timestamp}.json')
42
  shutil.copy(DATA_FILE, backup_file)
43
 
44
- # Safe save
 
45
  def atomic_save(data, path):
46
  tmp_path = path + ".tmp"
47
  with open(tmp_path, "w") as f:
48
  json.dump(data, f, indent=2)
49
  os.replace(tmp_path, path)
50
 
51
- # Profile submission
 
52
  def submit_profile(name, discord, city, country, address, looking, onlinecheck, languages, laptop, robot, skills, describe3, experience, idea):
53
  if not discord or not city or not country or not laptop or not robot:
54
  return "❌ Please fill in all required fields."
@@ -56,7 +58,6 @@ def submit_profile(name, discord, city, country, address, looking, onlinecheck,
56
  if not languages or not isinstance(languages, list):
57
  return "❌ Please select at least one language."
58
 
59
- # Normalize input
60
  city = city.strip().title()
61
  country = country.strip().title()
62
  discord = discord.strip()
@@ -107,7 +108,8 @@ def submit_profile(name, discord, city, country, address, looking, onlinecheck,
107
  except Exception as e:
108
  return f"❌ Failed to save: {e}"
109
 
110
- # City dropdown update
 
111
  def update_city_filter(country):
112
  with open(DATA_FILE, "r") as f:
113
  data = json.load(f)
@@ -119,7 +121,28 @@ def update_city_filter(country):
119
  cities = sorted(set(df["City"].dropna().unique()))
120
  return gr.update(choices=["All"] + cities, value="All")
121
 
122
- # Filter participants
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
123
  def filter_by_fields(selected_country, selected_city, selected_language):
124
  with open(DATA_FILE, "r") as f:
125
  data = json.load(f)
@@ -129,73 +152,36 @@ def filter_by_fields(selected_country, selected_city, selected_language):
129
 
130
  df = pd.DataFrame(data)
131
 
132
- # Normalize Country & City
133
  df["Country"] = df["Country"].astype(str).str.strip().str.title()
134
  df["City"] = df["City"].astype(str).str.strip().str.title()
 
135
 
136
- # Normalize Languages: always string, lowercase, comma-separated
137
- df["Languages"] = df["Languages"].apply(
138
- lambda x: ", ".join(x) if isinstance(x, list) else str(x)
139
- ).str.strip().str.lower()
140
-
141
- # Normalize filters
142
  if selected_country != "All":
143
- selected_country = selected_country.strip().title()
144
- df = df[df["Country"] == selected_country]
145
-
146
  if selected_city != "All":
147
- selected_city = selected_city.strip().title()
148
- df = df[df["City"] == selected_city]
149
-
150
  if selected_language != "All":
151
- selected_language = selected_language.strip().lower()
152
- df = df[df["Languages"].str.contains(selected_language, na=False)]
153
 
154
  if df.empty:
155
  return "<p>No participants match your filters.</p>"
156
 
157
- # Hide address if present
158
  if "Address" in df.columns:
159
  df = df.drop(columns=["Address"])
160
 
161
- display_names = {
162
- "Discord": "Discord",
163
- "Name": "Name",
164
- "City": "City",
165
- "Country": "Country",
166
- "Looking for Team": "Looking for Team",
167
- "Onlinecheck": "How?",
168
- "Languages": "Languages",
169
- "Laptop": "Laptop",
170
- "Robot": "Robot",
171
- "Skills": "Skills",
172
- "Describe3": "Description",
173
- "Experience": "Experience",
174
- "Project Idea": "Project Idea"
175
- }
176
-
177
- html = '<h3 style="margin-top:20px;">πŸ” Find your matching Teammates & Register your team <a href="https://forms.gle/gJEMGD4CEA2emhD18" target="_blank">here</a></h3>'
178
  html += "<table style='width:100%; border-collapse: collapse;'>"
179
-
180
- html += "<tr>"
181
- for col in df.columns:
182
- html += f"<th style='border: 1px solid #ccc; padding: 6px;'>{display_names.get(col, col)}</th>"
183
- html += "</tr>"
184
-
185
  for _, row in df.iterrows():
186
- html += "<tr>"
187
- for col in df.columns:
188
- val = row[col]
189
- if col == "Discord":
190
- val = f"<a href='https://discord.com/users/{val}' target='_blank'>{val}</a>"
191
- html += f"<td style='border: 1px solid #eee; padding: 6px;'>{val}</td>"
192
- html += "</tr>"
193
-
194
  html += "</table>"
195
  return html
196
 
 
197
 
198
- # Delete discord
199
  def delete_by_discord(discord, code):
200
  if code != ADMIN_CODE:
201
  return "❌ Invalid admin code."
@@ -206,11 +192,21 @@ def delete_by_discord(discord, code):
206
  json.dump(new_data, f, indent=2)
207
  return f"πŸ—‘οΈ Deleted user with Discord: {discord}"
208
 
 
 
 
 
 
 
 
 
 
 
 
209
 
210
- # Gradio Interface
211
  with gr.Blocks(css=".gr-dropdown { max-height: 100px; overflow-y: auto; font-size: 12px; }") as demo:
212
  gr.Markdown("# 🌍 LeRobot Worldwide Hackathon - Team-Up Dashboard")
213
- gr.Markdown("1. Submit or update your profile to find matching teammates and contact them on Discord. (Required fields marked with *.) ")
214
 
215
  with gr.Row():
216
  with gr.Column():
@@ -232,88 +228,47 @@ with gr.Blocks(css=".gr-dropdown { max-height: 100px; overflow-y: auto; font-siz
232
  status = gr.Textbox(label="", interactive=False)
233
 
234
  with gr.Column():
235
- gr.Markdown("🎯 2. Choose your preferences to find your teammates (country, city or language)")
236
  country_filter = gr.Dropdown(label="Filter by Country", choices=["All"] + ALL_COUNTRIES, value="All")
237
  city_filter = gr.Dropdown(label="Filter by City", choices=["All"], value="All")
238
  language_filter = gr.Dropdown(label="Filter by Language", choices=["All", "English", "French", "Spanish", "German", "Portuguese", "Chinese", "Arabic", "Hindi"], value="All")
239
  table_html = gr.HTML(label="Matching Participants")
240
 
241
-
242
- def update_dropdown_choices():
243
- with open(DATA_FILE, "r") as f:
244
- data = json.load(f)
245
- df = pd.DataFrame(data)
246
-
247
- country_choices = sorted(df["Country"].dropna().unique()) if "Country" in df else []
248
- city_choices = sorted(df["City"].dropna().unique()) if "City" in df else []
249
- language_set = set()
250
- if "Languages" in df:
251
- for lang_list in df["Languages"].dropna():
252
- if isinstance(lang_list, list):
253
- language_set.update(lang_list)
254
- elif isinstance(lang_list, str):
255
- language_set.update(lang_list.split(", "))
256
- return (
257
- gr.update(choices=["All"] + list(country_choices), value="All"),
258
- gr.update(choices=["All"] + list(city_choices), value="All"),
259
- gr.update(choices=["All"] + sorted(language_set), value="All")
260
- )
261
-
262
- with demo:
263
- demo.load(
264
- fn=lambda: filter_by_fields("All", "All", "All"),
265
- inputs=[],
266
- outputs=[table_html]
267
- )
268
  demo.load(fn=update_dropdown_choices, outputs=[country_filter, city_filter, language_filter])
269
 
270
-
271
  country_filter.change(fn=update_city_filter, inputs=[country_filter], outputs=[city_filter])
272
  country_filter.change(fn=filter_by_fields, inputs=[country_filter, city_filter, language_filter], outputs=[table_html])
273
  city_filter.change(fn=filter_by_fields, inputs=[country_filter, city_filter, language_filter], outputs=[table_html])
274
  language_filter.change(fn=filter_by_fields, inputs=[country_filter, city_filter, language_filter], outputs=[table_html])
275
-
276
- submit_btn.click(
277
- fn=submit_profile,
278
- inputs=[name, discord, city, country, address, looking, onlinecheck, languages, laptop, robot, skills, describe3, experience, idea],
279
- outputs=[status]
280
- ).then(
281
- fn=update_dropdown_choices,
282
- inputs=[],
283
- outputs=[country_filter, city_filter, language_filter]
284
- ).then(
285
- fn=filter_by_fields,
286
- inputs=[country_filter, city_filter, language_filter],
287
- outputs=[table_html]
288
- )
289
-
290
-
291
- def download_csv(code):
292
- if code != ADMIN_CODE:
293
- raise gr.Error("❌ Invalid admin code.")
294
- with open(DATA_FILE, "r") as f:
295
- data = json.load(f)
296
- df = pd.DataFrame(data)
297
- csv_path = os.path.join("data", "teamup_export.csv")
298
- df.to_csv(csv_path, index=False)
299
- return csv_path
300
-
301
-
302
 
 
 
 
 
 
 
 
 
 
 
 
 
 
303
 
304
  gr.Markdown("---\n### πŸ›‘οΈ Admin Panel (delete by Discord)")
305
  admin_discord = gr.Text(label="Discord Username")
306
  admin_code = gr.Text(label="Admin Code", type="password")
307
  del_btn = gr.Button("Delete Profile")
308
  del_status = gr.Textbox(label="Status", interactive=False)
309
- del_btn.click(delete_by_discord, inputs=[admin_discord, admin_code], outputs=del_status)
310
-
311
- # πŸ” CSV Download Section (admin-only)
312
- gr.Markdown("---\n### πŸ“₯ Admin Export CSV")
313
  export_code = gr.Text(label="Admin Code", type="password")
314
  download_btn = gr.Button("Generate and Download CSV")
315
  download_file = gr.File(label="CSV Export", interactive=False)
316
  download_btn.click(fn=download_csv, inputs=[export_code], outputs=[download_file])
317
 
318
- demo.launch()
 
319
 
 
21
  # Country list
22
  ALL_COUNTRIES = sorted(list(set([
23
  "United States of America", "United Kingdom", "India", "France", "Germany", "Canada", "Australia", "Japan", "Brazil", "Mexico",
24
+ ] + [ # Full list
 
25
  "Afghanistan", "Albania", "Algeria", "Andorra", "Angola", "Argentina", "Armenia", "Austria", "Azerbaijan",
26
  "Bangladesh", "Belgium", "Bhutan", "Bolivia", "Bosnia and Herzegovina", "Botswana", "Bulgaria", "Cambodia",
27
  "Chile", "China", "Colombia", "Croatia", "Cuba", "Czech Republic", "Denmark", "Dominican Republic", "Ecuador",
 
34
  ])))
35
 
36
  # Backup
37
+
38
  def backup_data():
39
  os.makedirs(BACKUP_DIR, exist_ok=True)
40
  timestamp = datetime.datetime.now().strftime('%Y%m%d_%H%M%S')
41
  backup_file = os.path.join(BACKUP_DIR, f'teamup_data_backup_{timestamp}.json')
42
  shutil.copy(DATA_FILE, backup_file)
43
 
44
+ # Save data safely
45
+
46
  def atomic_save(data, path):
47
  tmp_path = path + ".tmp"
48
  with open(tmp_path, "w") as f:
49
  json.dump(data, f, indent=2)
50
  os.replace(tmp_path, path)
51
 
52
+ # Submit profile
53
+
54
  def submit_profile(name, discord, city, country, address, looking, onlinecheck, languages, laptop, robot, skills, describe3, experience, idea):
55
  if not discord or not city or not country or not laptop or not robot:
56
  return "❌ Please fill in all required fields."
 
58
  if not languages or not isinstance(languages, list):
59
  return "❌ Please select at least one language."
60
 
 
61
  city = city.strip().title()
62
  country = country.strip().title()
63
  discord = discord.strip()
 
108
  except Exception as e:
109
  return f"❌ Failed to save: {e}"
110
 
111
+ # Filter dropdowns
112
+
113
  def update_city_filter(country):
114
  with open(DATA_FILE, "r") as f:
115
  data = json.load(f)
 
121
  cities = sorted(set(df["City"].dropna().unique()))
122
  return gr.update(choices=["All"] + cities, value="All")
123
 
124
+ def update_dropdown_choices():
125
+ with open(DATA_FILE, "r") as f:
126
+ data = json.load(f)
127
+ df = pd.DataFrame(data)
128
+
129
+ country_choices = sorted(df["Country"].dropna().unique()) if "Country" in df else []
130
+ city_choices = sorted(df["City"].dropna().unique()) if "City" in df else []
131
+ language_set = set()
132
+ if "Languages" in df:
133
+ for lang_list in df["Languages"].dropna():
134
+ if isinstance(lang_list, list):
135
+ language_set.update(lang_list)
136
+ elif isinstance(lang_list, str):
137
+ language_set.update(lang_list.split(", "))
138
+ return (
139
+ gr.update(choices=["All"] + list(country_choices), value="All"),
140
+ gr.update(choices=["All"] + list(city_choices), value="All"),
141
+ gr.update(choices=["All"] + sorted(language_set), value="All")
142
+ )
143
+
144
+ # Filter table
145
+
146
  def filter_by_fields(selected_country, selected_city, selected_language):
147
  with open(DATA_FILE, "r") as f:
148
  data = json.load(f)
 
152
 
153
  df = pd.DataFrame(data)
154
 
 
155
  df["Country"] = df["Country"].astype(str).str.strip().str.title()
156
  df["City"] = df["City"].astype(str).str.strip().str.title()
157
+ df["Languages"] = df["Languages"].apply(lambda x: ", ".join(x) if isinstance(x, list) else str(x)).str.strip().str.lower()
158
 
 
 
 
 
 
 
159
  if selected_country != "All":
160
+ df = df[df["Country"] == selected_country.strip().title()]
 
 
161
  if selected_city != "All":
162
+ df = df[df["City"] == selected_city.strip().title()]
 
 
163
  if selected_language != "All":
164
+ df = df[df["Languages"].str.contains(selected_language.strip().lower(), na=False)]
 
165
 
166
  if df.empty:
167
  return "<p>No participants match your filters.</p>"
168
 
 
169
  if "Address" in df.columns:
170
  df = df.drop(columns=["Address"])
171
 
172
+ html = '<h3 style="margin-top:20px;">\U0001f50d Find your matching Teammates & Register your team <a href="https://forms.gle/gJEMGD4CEA2emhD18" target="_blank">here</a></h3>'
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
173
  html += "<table style='width:100%; border-collapse: collapse;'>"
174
+ html += "<tr>" + "".join(f"<th style='border: 1px solid #ccc; padding: 6px;'>{col}</th>" for col in df.columns) + "</tr>"
 
 
 
 
 
175
  for _, row in df.iterrows():
176
+ html += "<tr>" + "".join(
177
+ f"<td style='border: 1px solid #eee; padding: 6px;'>" +
178
+ (f"<a href='https://discord.com/users/{val}' target='_blank'>{val}</a>" if col == "Discord" else str(val)) +
179
+ "</td>" for col, val in row.items()) + "</tr>"
 
 
 
 
180
  html += "</table>"
181
  return html
182
 
183
+ # Delete
184
 
 
185
  def delete_by_discord(discord, code):
186
  if code != ADMIN_CODE:
187
  return "❌ Invalid admin code."
 
192
  json.dump(new_data, f, indent=2)
193
  return f"πŸ—‘οΈ Deleted user with Discord: {discord}"
194
 
195
+ # CSV export
196
+
197
+ def download_csv(code):
198
+ if code != ADMIN_CODE:
199
+ raise gr.Error("❌ Invalid admin code.")
200
+ with open(DATA_FILE, "r") as f:
201
+ data = json.load(f)
202
+ df = pd.DataFrame(data)
203
+ csv_path = os.path.join("data", "teamup_export.csv")
204
+ df.to_csv(csv_path, index=False)
205
+ return csv_path
206
 
207
+ # Interface
208
  with gr.Blocks(css=".gr-dropdown { max-height: 100px; overflow-y: auto; font-size: 12px; }") as demo:
209
  gr.Markdown("# 🌍 LeRobot Worldwide Hackathon - Team-Up Dashboard")
 
210
 
211
  with gr.Row():
212
  with gr.Column():
 
228
  status = gr.Textbox(label="", interactive=False)
229
 
230
  with gr.Column():
231
+ gr.Markdown("\n\n🎯 2. Choose your preferences to find your teammates")
232
  country_filter = gr.Dropdown(label="Filter by Country", choices=["All"] + ALL_COUNTRIES, value="All")
233
  city_filter = gr.Dropdown(label="Filter by City", choices=["All"], value="All")
234
  language_filter = gr.Dropdown(label="Filter by Language", choices=["All", "English", "French", "Spanish", "German", "Portuguese", "Chinese", "Arabic", "Hindi"], value="All")
235
  table_html = gr.HTML(label="Matching Participants")
236
 
237
+ demo.load(fn=filter_by_fields, inputs=[country_filter, city_filter, language_filter], outputs=[table_html])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
238
  demo.load(fn=update_dropdown_choices, outputs=[country_filter, city_filter, language_filter])
239
 
 
240
  country_filter.change(fn=update_city_filter, inputs=[country_filter], outputs=[city_filter])
241
  country_filter.change(fn=filter_by_fields, inputs=[country_filter, city_filter, language_filter], outputs=[table_html])
242
  city_filter.change(fn=filter_by_fields, inputs=[country_filter, city_filter, language_filter], outputs=[table_html])
243
  language_filter.change(fn=filter_by_fields, inputs=[country_filter, city_filter, language_filter], outputs=[table_html])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
244
 
245
+ submit_btn.click(
246
+ fn=submit_profile,
247
+ inputs=[name, discord, city, country, address, looking, onlinecheck, languages, laptop, robot, skills, describe3, experience, idea],
248
+ outputs=[status]
249
+ ).then(
250
+ fn=update_dropdown_choices,
251
+ inputs=[],
252
+ outputs=[country_filter, city_filter, language_filter]
253
+ ).then(
254
+ fn=filter_by_fields,
255
+ inputs=[country_filter, city_filter, language_filter],
256
+ outputs=[table_html]
257
+ )
258
 
259
  gr.Markdown("---\n### πŸ›‘οΈ Admin Panel (delete by Discord)")
260
  admin_discord = gr.Text(label="Discord Username")
261
  admin_code = gr.Text(label="Admin Code", type="password")
262
  del_btn = gr.Button("Delete Profile")
263
  del_status = gr.Textbox(label="Status", interactive=False)
264
+ del_btn.click(delete_by_discord, inputs=[admin_discord, admin_code], outputs=[del_status])
265
+
266
+ gr.Markdown("---\n### πŸ“… Admin Export CSV")
 
267
  export_code = gr.Text(label="Admin Code", type="password")
268
  download_btn = gr.Button("Generate and Download CSV")
269
  download_file = gr.File(label="CSV Export", interactive=False)
270
  download_btn.click(fn=download_csv, inputs=[export_code], outputs=[download_file])
271
 
272
+ if __name__ == "__main__":
273
+ demo.launch()
274