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

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +104 -189
app.py CHANGED
@@ -1,27 +1,41 @@
1
  import gradio as gr
2
- import json
3
  import pandas as pd
 
4
  import os
5
- import shutil
6
  import datetime
7
 
8
  # Paths
9
- DATA_DIR = "data"
10
- DATA_FILE = os.path.join(DATA_DIR, "teamup_data.json")
11
- BACKUP_DIR = os.path.join(DATA_DIR, "backup")
12
- os.makedirs(DATA_DIR, exist_ok=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13
 
14
  ADMIN_CODE = os.getenv("ADMIN_CODE", "")
15
 
16
- # Init data file
17
- if not os.path.exists(DATA_FILE) or os.path.getsize(DATA_FILE) == 0:
18
- with open(DATA_FILE, "w") as f:
19
- json.dump([], f)
20
-
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",
@@ -33,178 +47,103 @@ ALL_COUNTRIES = sorted(list(set([
33
  "Zambia", "Zimbabwe"
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."
57
 
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()
64
-
65
- with open(DATA_FILE, "r") as f:
66
- data = json.load(f)
67
-
68
- for entry in data:
69
- if entry["Discord"].lower() == discord.lower():
70
- entry.update({
71
- "Name": name,
72
- "City": city,
73
- "Country": country,
74
- "Address": address,
75
- "Looking for Team": looking,
76
- "Onlinecheck": onlinecheck,
77
- "Languages": languages if isinstance(languages, list) else [languages],
78
- "Laptop": laptop,
79
- "Robot": robot,
80
- "Skills": skills,
81
- "Describe3": describe3,
82
- "Experience": experience,
83
- "Project Idea": idea
84
- })
85
- break
86
- else:
87
- data.append({
88
- "Name": name,
89
- "Discord": discord,
90
- "City": city,
91
- "Country": country,
92
- "Address": address,
93
- "Looking for Team": looking,
94
- "Onlinecheck": onlinecheck,
95
- "Languages": languages if isinstance(languages, list) else [languages],
96
- "Laptop": laptop,
97
- "Robot": robot,
98
- "Skills": skills,
99
- "Describe3": describe3,
100
- "Experience": experience,
101
- "Project Idea": idea
102
- })
103
-
104
- try:
105
- atomic_save(data, DATA_FILE)
106
- backup_data()
107
- return "βœ… Profile saved!"
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)
116
- df = pd.DataFrame(data)
117
-
118
- if country != "All":
119
- df = df[df["Country"].str.title() == country.title()]
120
-
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)
 
149
 
150
- if not data:
151
  return "<p>No data available.</p>"
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."
188
- with open(DATA_FILE, "r") as f:
189
- data = json.load(f)
190
- new_data = [d for d in data if d["Discord"].lower() != discord.lower()]
191
- with open(DATA_FILE, "w") as f:
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
 
@@ -217,7 +156,7 @@ with gr.Blocks(css=".gr-dropdown { max-height: 100px; overflow-y: auto; font-siz
217
  address = gr.Text(label="Address (optional)")
218
  looking = gr.Radio(["Yes", "No"], label="πŸ” Looking for a team?")
219
  onlinecheck = gr.Radio(["Participate Online", "Join a Local Hackathon"], label="πŸš€ I will...")
220
- languages = gr.CheckboxGroup(choices=["English", "French", "Spanish", "German", "Portuguese", "Chinese", "Arabic", "Hindi"], label="Languages Spoken *")
221
  laptop = gr.Text(label="πŸ’» Laptop Setup *")
222
  robot = gr.Text(label="πŸ€– Robot Setup *")
223
  skills = gr.Text(label="🧠 Skills (comma separated)")
@@ -228,47 +167,23 @@ with gr.Blocks(css=".gr-dropdown { max-height: 100px; overflow-y: auto; font-siz
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
-
 
1
  import gradio as gr
 
2
  import pandas as pd
3
+ import sqlite3
4
  import os
 
5
  import datetime
6
 
7
  # Paths
8
+ DB_FILE = "data/teamup.db"
9
+ os.makedirs("data", exist_ok=True)
10
+
11
+ # Initialize database
12
+ conn = sqlite3.connect(DB_FILE)
13
+ c = conn.cursor()
14
+ c.execute('''
15
+ CREATE TABLE IF NOT EXISTS teamup (
16
+ discord TEXT PRIMARY KEY,
17
+ name TEXT,
18
+ city TEXT,
19
+ country TEXT,
20
+ address TEXT,
21
+ looking TEXT,
22
+ onlinecheck TEXT,
23
+ languages TEXT,
24
+ laptop TEXT,
25
+ robot TEXT,
26
+ skills TEXT,
27
+ describe3 TEXT,
28
+ experience TEXT,
29
+ idea TEXT
30
+ )
31
+ ''')
32
+ conn.commit()
33
+ conn.close()
34
 
35
  ADMIN_CODE = os.getenv("ADMIN_CODE", "")
36
 
 
 
 
 
 
 
37
  ALL_COUNTRIES = sorted(list(set([
38
  "United States of America", "United Kingdom", "India", "France", "Germany", "Canada", "Australia", "Japan", "Brazil", "Mexico",
 
39
  "Afghanistan", "Albania", "Algeria", "Andorra", "Angola", "Argentina", "Armenia", "Austria", "Azerbaijan",
40
  "Bangladesh", "Belgium", "Bhutan", "Bolivia", "Bosnia and Herzegovina", "Botswana", "Bulgaria", "Cambodia",
41
  "Chile", "China", "Colombia", "Croatia", "Cuba", "Czech Republic", "Denmark", "Dominican Republic", "Ecuador",
 
47
  "Zambia", "Zimbabwe"
48
  ])))
49
 
50
+ LANGUAGES = ["English", "French", "Spanish", "German", "Portuguese", "Chinese", "Arabic", "Hindi"]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
51
 
52
+ # Insert or update profile
53
  def submit_profile(name, discord, city, country, address, looking, onlinecheck, languages, laptop, robot, skills, describe3, experience, idea):
54
  if not discord or not city or not country or not laptop or not robot:
55
  return "❌ Please fill in all required fields."
56
 
57
+ lang_str = ", ".join(languages) if isinstance(languages, list) else languages
58
+
59
+ conn = sqlite3.connect(DB_FILE)
60
+ c = conn.cursor()
61
+ c.execute("""
62
+ INSERT INTO teamup (discord, name, city, country, address, looking, onlinecheck, languages, laptop, robot, skills, describe3, experience, idea)
63
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
64
+ ON CONFLICT(discord) DO UPDATE SET
65
+ name=excluded.name,
66
+ city=excluded.city,
67
+ country=excluded.country,
68
+ address=excluded.address,
69
+ looking=excluded.looking,
70
+ onlinecheck=excluded.onlinecheck,
71
+ languages=excluded.languages,
72
+ laptop=excluded.laptop,
73
+ robot=excluded.robot,
74
+ skills=excluded.skills,
75
+ describe3=excluded.describe3,
76
+ experience=excluded.experience,
77
+ idea=excluded.idea
78
+ """, (discord, name, city.title(), country.title(), address, looking, onlinecheck, lang_str.lower(), laptop, robot, skills, describe3, experience, idea))
79
+ conn.commit()
80
+ conn.close()
81
+ return "βœ… Profile saved!"
82
+
83
+ # Filter and return HTML table
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
84
  def filter_by_fields(selected_country, selected_city, selected_language):
85
+ conn = sqlite3.connect(DB_FILE)
86
+ df = pd.read_sql_query("SELECT * FROM teamup", conn)
87
+ conn.close()
88
 
89
+ if df.empty:
90
  return "<p>No data available.</p>"
91
 
92
+ df["City"] = df["city"].str.title()
93
+ df["Country"] = df["country"].str.title()
94
+ df["Languages"] = df["languages"]
 
 
95
 
96
  if selected_country != "All":
97
+ df = df[df["Country"] == selected_country.title()]
98
  if selected_city != "All":
99
+ df = df[df["City"] == selected_city.title()]
100
  if selected_language != "All":
101
+ df = df[df["Languages"].str.contains(selected_language.lower(), na=False)]
102
 
103
  if df.empty:
104
  return "<p>No participants match your filters.</p>"
105
 
106
+ html = "<table style='width:100%; border-collapse: collapse;'><tr>"
107
+ headers = ["Discord", "Name", "City", "Country", "Looking", "Onlinecheck", "Languages", "Laptop", "Robot", "Skills", "Describe3", "Experience", "Idea"]
108
+ for col in headers:
109
+ html += f"<th style='border:1px solid #ccc; padding:6px;'>{col}</th>"
110
+ html += "</tr>"
111
 
 
 
 
112
  for _, row in df.iterrows():
113
+ html += "<tr>"
114
+ for col in ["discord", "name", "City", "Country", "looking", "onlinecheck", "Languages", "laptop", "robot", "skills", "describe3", "experience", "idea"]:
115
+ val = row[col]
116
+ if col == "discord":
117
+ val = f"<a href='https://discord.com/users/{val}' target='_blank'>{val}</a>"
118
+ html += f"<td style='border:1px solid #eee; padding:6px;'>{val}</td>"
119
+ html += "</tr>"
120
+
121
  html += "</table>"
122
  return html
123
 
124
+ # Update city dropdown
125
+ def update_city_filter(country):
126
+ conn = sqlite3.connect(DB_FILE)
127
+ c = conn.cursor()
128
+ if country == "All":
129
+ c.execute("SELECT DISTINCT city FROM teamup")
130
+ else:
131
+ c.execute("SELECT DISTINCT city FROM teamup WHERE country = ?", (country.title(),))
132
+ cities = [r[0].title() for r in c.fetchall() if r[0]]
133
+ conn.close()
134
+ return gr.update(choices=["All"] + sorted(cities), value="All")
135
 
136
+ # Delete
137
  def delete_by_discord(discord, code):
138
  if code != ADMIN_CODE:
139
  return "❌ Invalid admin code."
140
+ conn = sqlite3.connect(DB_FILE)
141
+ c = conn.cursor()
142
+ c.execute("DELETE FROM teamup WHERE lower(discord) = ?", (discord.lower(),))
143
+ conn.commit()
144
+ conn.close()
145
  return f"πŸ—‘οΈ Deleted user with Discord: {discord}"
146
 
 
 
 
 
 
 
 
 
 
 
 
 
 
147
  with gr.Blocks(css=".gr-dropdown { max-height: 100px; overflow-y: auto; font-size: 12px; }") as demo:
148
  gr.Markdown("# 🌍 LeRobot Worldwide Hackathon - Team-Up Dashboard")
149
 
 
156
  address = gr.Text(label="Address (optional)")
157
  looking = gr.Radio(["Yes", "No"], label="πŸ” Looking for a team?")
158
  onlinecheck = gr.Radio(["Participate Online", "Join a Local Hackathon"], label="πŸš€ I will...")
159
+ languages = gr.CheckboxGroup(choices=LANGUAGES, label="Languages Spoken *")
160
  laptop = gr.Text(label="πŸ’» Laptop Setup *")
161
  robot = gr.Text(label="πŸ€– Robot Setup *")
162
  skills = gr.Text(label="🧠 Skills (comma separated)")
 
167
  status = gr.Textbox(label="", interactive=False)
168
 
169
  with gr.Column():
 
170
  country_filter = gr.Dropdown(label="Filter by Country", choices=["All"] + ALL_COUNTRIES, value="All")
171
  city_filter = gr.Dropdown(label="Filter by City", choices=["All"], value="All")
172
+ language_filter = gr.Dropdown(label="Filter by Language", choices=["All"] + LANGUAGES, value="All")
173
  table_html = gr.HTML(label="Matching Participants")
174
 
 
 
 
175
  country_filter.change(fn=update_city_filter, inputs=[country_filter], outputs=[city_filter])
176
+ for dropdown in [country_filter, city_filter, language_filter]:
177
+ dropdown.change(fn=filter_by_fields, inputs=[country_filter, city_filter, language_filter], outputs=[table_html])
 
178
 
179
+ submit_btn.click(fn=submit_profile, inputs=[name, discord, city, country, address, looking, onlinecheck, languages, laptop, robot, skills, describe3, experience, idea], outputs=[status])
180
+ submit_btn.click(fn=filter_by_fields, inputs=[country_filter, city_filter, language_filter], outputs=[table_html])
 
 
 
 
 
 
 
 
 
 
 
181
 
182
+ gr.Markdown("---\n### πŸ›‘οΈ Admin Panel")
183
  admin_discord = gr.Text(label="Discord Username")
184
  admin_code = gr.Text(label="Admin Code", type="password")
185
  del_btn = gr.Button("Delete Profile")
186
  del_status = gr.Textbox(label="Status", interactive=False)
187
  del_btn.click(delete_by_discord, inputs=[admin_discord, admin_code], outputs=[del_status])
188
 
189
+ demo.launch()