Lujainossaily commited on
Commit
d0f00a3
·
verified ·
1 Parent(s): 8033e49
Files changed (1) hide show
  1. app.py +501 -263
app.py CHANGED
@@ -1,17 +1,23 @@
1
  import gradio as gr
 
 
2
  import json
3
  from datetime import datetime
4
- import random
5
 
6
  # ============================================
7
- # 🌟 SYNCHRONY - DEMO VERSION (NO WEBHOOKS)
8
- # Uses mock data for demonstration
9
  # ============================================
10
 
11
  REGISTRATION_FORM = "https://docs.google.com/forms/d/e/1FAIpQLSfJFGx-yd0FPIuRYLUJut3BOOiQ14x_5DYheWpgrUqcHdQaCA/viewform"
12
  GOOGLE_SHEETS = "https://docs.google.com/spreadsheets/d/1rpR-E_RSooDkNDh-Q_1BDIeGw4vfgmusNAfwPqATaW4/edit?usp=sharing"
13
 
14
- # Current student session
 
 
 
 
 
15
  current_student = {
16
  "name": None,
17
  "email": None,
@@ -21,22 +27,16 @@ current_student = {
21
  "challenges": []
22
  }
23
 
24
- # MOCK DATA - Simulates your real backend
25
- MOCK_STUDENTS = [
26
- {"name": "Omar Khalil", "topic": "Linked Lists"},
27
- {"name": "Khaled Ibrahim", "topic": "Queues"},
28
- {"name": "Layla Mahmoud", "topic": "Binary Search Trees"}
29
- ]
30
-
31
  MOCK_CHALLENGES = [
32
  {
33
  "challenge_number": 1,
34
  "description": "Layla, explain how Binary Search Trees work to the group. Focus on BST properties, insertion, and search operations. Omar and Khaled, compare this with your data structures - how is searching in a BST different from searching in a linked list or checking elements in a queue?",
35
  "topics_involved": "Binary Search Trees, Linked Lists, Queues",
36
  "hints": [
37
- "Start by drawing a simple diagram showing how nodes are organized in a BST",
38
- "Think about the left-subtree and right-subtree properties - what makes a BST special?",
39
- "Compare time complexity: BST search is O(log n) while linked list is O(n)"
40
  ]
41
  },
42
  {
@@ -44,9 +44,9 @@ MOCK_CHALLENGES = [
44
  "description": "Omar, teach us about Linked Lists. Create a real-world example showing both singly and doubly linked lists. Layla and Khaled, find connections between Linked Lists and your data structures.",
45
  "topics_involved": "Linked Lists, Binary Search Trees, Queues",
46
  "hints": [
47
- "Think about how nodes point to each other - what's the difference between singly and doubly?",
48
- "Consider real-world examples: browser history, music playlists, undo/redo functionality",
49
- "Both BST nodes and queue nodes use similar pointer concepts!"
50
  ]
51
  },
52
  {
@@ -54,156 +54,255 @@ MOCK_CHALLENGES = [
54
  "description": "Everyone: Design ONE real-world system that uses ALL three data structures (BST, Linked Lists, Queues). Explain how they work together. Be creative!",
55
  "topics_involved": "Binary Search Trees, Linked Lists, Queues",
56
  "hints": [
57
- "Think of a system with searching, ordering, and waiting - like a restaurant management system",
58
- "BST for menu items (fast lookup), Queue for order processing, Linked List for order history",
59
- "Draw a diagram showing how data flows between the three structures"
60
  ]
61
  }
62
  ]
63
 
64
  # ============================================
65
- # 🔧 SIMULATED API FUNCTIONS
66
  # ============================================
67
 
68
- def generate_session_id():
69
- """Generate realistic session ID"""
70
- timestamp = datetime.utcnow().strftime("%Y%m%d%H%M%S")
71
- return f"S{timestamp}"
 
 
 
 
72
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
73
 
74
  def lookup_student(email):
75
- """Login simulation"""
76
  try:
77
  if not email or "@" not in email:
78
- return "❌ please enter a valid email address!"
79
 
80
- # Extract name from email
81
- name_part = email.split("@")[0]
82
- name = name_part.replace(".", " ").replace("_", " ").title()
83
 
84
- # Simulate successful login
85
- session_id = generate_session_id()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
86
 
87
  current_student["name"] = name
88
  current_student["email"] = email
89
- current_student["group_id"] = "G001"
90
  current_student["session_id"] = session_id
91
- current_student["team_members"] = MOCK_STUDENTS
92
-
93
- welcome_msg = f"✅ **welcome back, {name}!** 🎉\n\n"
94
- welcome_msg += f"🆔 **session id:** `{session_id}`\n\n"
95
- welcome_msg += f"💬 **synco says:**\n"
96
- welcome_msg += f"Hey {', '.join([s['name'] for s in MOCK_STUDENTS])}! Welcome to your Synchrony study session! "
97
- welcome_msg += f"You're all studying Data Structures, and I love that each of you is focusing on different topics. "
98
- welcome_msg += f"This is perfect for peer teaching!\n\n"
99
- welcome_msg += f"Today, we'll tackle 3 collaborative challenges together. Each challenge will help you "
100
- welcome_msg += f"learn from each other's expertise. Ready? Let's go! 🚀\n\n"
101
- welcome_msg += f"👥 **your team:** {', '.join([s['name'] for s in MOCK_STUDENTS])}\n\n"
102
- welcome_msg += f"✨ head to **MY TEAM** tab to see everyone!"
103
 
104
  return welcome_msg
105
 
106
  except Exception as e:
107
- return f"❌ **error:** {str(e)}"
108
-
109
 
110
  def get_team_info():
111
- """Display team information"""
112
  if not current_student.get("team_members"):
113
- return "⚠️ please login first in the **HOME** tab!"
114
 
115
- output = f"## 👥 your study squad - {current_student.get('group_id', 'G001')} 🔥\n\n"
116
- output += f"**session id:** `{current_student.get('session_id', 'not started')}`\n\n"
117
  output += "---\n\n"
118
 
119
  for member in current_student["team_members"]:
120
  user_name = current_student.get("name", "").lower()
121
  member_name = member.get("name", "").lower()
122
- is_you = " **(YOU)** 🌟" if user_name in member_name or member_name in user_name else ""
123
  output += f"### 🎓 {member['name']}{is_you}\n"
124
- output += f"**studying:** {member.get('topic', 'N/A')}\n\n"
125
 
126
- output += "---\n\n💡 *collaborate, learn together, level up!*"
127
  return output
128
 
129
-
130
  def load_challenges():
131
- """Load challenges (simulated)"""
132
  if not current_student.get("session_id"):
133
- return "⚠️ no active session. please login first in the **HOME** tab!"
134
-
135
- current_student["challenges"] = MOCK_CHALLENGES
136
 
137
- output = f"# 🎯 your collaborative challenges\n\n"
138
- output += f"💬 **synco says:**\n"
139
- output += f"🎯 Here are your 3 collaborative challenges! Let's start with Challenge 1. "
140
- output += f"Work together, discuss your approaches, and ask for hints if you get stuck. Ready? Let's go!\n\n"
141
- output += "---\n\n"
142
-
143
- for i, challenge in enumerate(MOCK_CHALLENGES, 1):
144
- output += f"## 🎯 challenge {i}\n\n"
145
- output += f"{challenge['description']}\n\n"
146
- output += f"**📚 topics:** {challenge['topics_involved']}\n\n"
147
- output += f"💡 *stuck? request a hint in the **HINTS** tab!*\n\n"
148
  output += "---\n\n"
149
-
150
- return output
151
-
 
 
 
 
 
 
 
 
 
152
 
153
  def request_hint(challenge_num, hint_level_text):
154
- """Request hint (simulated)"""
155
  if not current_student.get("session_id"):
156
- return "⚠️ no active session. please login first!"
157
 
158
  if not current_student.get("challenges"):
159
- return "⚠️ please load challenges first in the **CHALLENGES** tab!"
160
 
161
  try:
162
  hint_level = int(hint_level_text.split(" - ")[0])
163
  challenge_idx = int(challenge_num) - 1
164
 
165
- if challenge_idx < 0 or challenge_idx >= len(MOCK_CHALLENGES):
166
- return "⚠️ invalid challenge number!"
 
 
 
167
 
168
- if hint_level < 1 or hint_level > 3:
169
- return "⚠️ invalid hint level!"
170
 
171
- challenge = MOCK_CHALLENGES[challenge_idx]
172
- hint = challenge["hints"][hint_level - 1]
173
 
174
- # Encouraging messages based on hint level
175
  if hint_level == 1:
176
- encouragement = "💡 **Think about it a bit more!**"
177
  elif hint_level == 2:
178
- encouragement = "💡 **You're getting closer!**"
179
  else:
180
- encouragement = "💡 **Almost there!**"
181
 
182
- output = f"## {encouragement} Hint {hint_level}\n\n"
183
- output += f"🎯 **challenge {challenge_num}** | **hint level {hint_level}**\n\n"
184
  output += "---\n\n"
185
  output += f"{hint}\n\n"
186
  output += "---\n\n"
187
- output += f"💪 *you got this! keep going!*"
188
 
189
  return output
190
 
191
  except Exception as e:
192
- return f"❌ **error:** {str(e)}"
193
-
194
 
195
  def send_message(message, history):
196
- """Simulated team chat"""
197
  if not message.strip():
198
  return history, ""
199
 
200
  history.append({
201
  "role": "user",
202
- "content": f"**{current_student.get('name', 'you')}:** {message}"
203
  })
204
 
205
  if not current_student.get("team_members"):
206
- response = "**synco (ai):** please login first to chat with your team! 💬"
207
  else:
208
  other_members = [m for m in current_student["team_members"]
209
  if m['name'].lower() != current_student.get('name', '').lower()]
@@ -211,133 +310,328 @@ def send_message(message, history):
211
  if other_members:
212
  member = random.choice(other_members)
213
  responses = [
214
- f"**{member['name']}:** that's a great point! let me add to that...",
215
- f"**{member['name']}:** interesting! in {member['topic']}, we do it differently...",
216
- f"**{member['name']}:** i agree! should we try that approach?",
217
- f"**{member['name']}:** wait, can you explain that part again?",
218
- f"**{member['name']}:** oh I see! that connects to {member['topic']} because...",
219
- f"**synco (ai):** great discussion everyone! 💡 keep collaborating!"
220
  ]
221
  response = random.choice(responses)
222
  else:
223
- response = "**synco (ai):** great question! your teammates will respond soon! 💬"
224
 
225
  history.append({"role": "assistant", "content": response})
226
  return history, ""
227
 
228
-
229
  # ============================================
230
- # 🎨 CUSTOM CSS
231
  # ============================================
232
 
233
  custom_css = """
 
 
234
  .gradio-container {
235
- background: #000000 !important;
236
- font-family: 'Inter', sans-serif !important;
237
- color: #ffffff !important;
238
  }
239
 
 
240
  :root {
241
- --neon-pink: #ff0080;
242
- --neon-cyan: #00ffff;
243
- --neon-purple: #a855f7;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
244
  }
245
 
246
  .tab-nav button {
247
- background: #1a1a1a !important;
248
- border: 2px solid #222222 !important;
249
- color: var(--neon-cyan) !important;
250
- font-weight: 800 !important;
251
- text-transform: uppercase !important;
252
- transition: all 0.3s ease !important;
 
 
 
253
  }
254
 
255
  .tab-nav button:hover {
256
- border-color: var(--neon-pink) !important;
257
- color: var(--neon-pink) !important;
258
- transform: translateY(-2px) !important;
259
  }
260
 
261
  .tab-nav button.selected {
262
- background: linear-gradient(135deg, var(--neon-pink), var(--neon-purple)) !important;
263
- color: #000000 !important;
264
- box-shadow: 0 0 30px rgba(255, 0, 128, 0.8) !important;
265
  }
266
 
267
- input, textarea {
268
- background: #1a1a1a !important;
269
- border: 2px solid #333333 !important;
270
- color: #ffffff !important;
 
271
  border-radius: 10px !important;
 
 
 
272
  }
273
 
274
- input:focus, textarea:focus {
275
- border-color: var(--neon-cyan) !important;
276
- box-shadow: 0 0 25px rgba(0, 255, 255, 0.5) !important;
 
277
  }
278
 
 
 
 
 
 
279
  button {
280
- background: linear-gradient(135deg, var(--neon-pink), var(--neon-purple)) !important;
281
  border: none !important;
282
- color: #000000 !important;
283
- font-weight: 900 !important;
284
- text-transform: uppercase !important;
285
  border-radius: 10px !important;
286
- padding: 16px 32px !important;
287
- transition: all 0.3s ease !important;
 
288
  }
289
 
290
  button:hover {
291
- transform: translateY(-4px) scale(1.03) !important;
292
- box-shadow: 0 10px 40px rgba(255, 0, 128, 0.7) !important;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
293
  }
294
 
295
- .output-markdown {
296
- background: #0a0a0a !important;
297
- border: 2px solid #1a1a1a !important;
 
298
  border-radius: 12px !important;
299
  padding: 24px !important;
300
- color: #e0e0e0 !important;
 
 
301
  }
302
 
 
303
  h1 {
304
- background: linear-gradient(135deg, var(--neon-pink), var(--neon-cyan));
305
- -webkit-background-clip: text;
306
- -webkit-text-fill-color: transparent;
307
- font-weight: 900 !important;
308
- font-size: 56px !important;
309
  text-align: center !important;
 
 
310
  }
311
 
312
  h2 {
313
- color: var(--neon-cyan) !important;
314
- font-weight: 800 !important;
 
 
315
  }
316
 
317
  h3 {
318
- color: var(--neon-pink) !important;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
319
  font-weight: 700 !important;
320
  }
321
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
322
  code {
323
- background: #1a1a1a !important;
324
- color: #00ff88 !important;
325
- padding: 4px 10px !important;
326
  border-radius: 6px !important;
327
- border: 1px solid var(--neon-cyan) !important;
 
 
 
 
 
 
 
 
 
328
  }
329
 
 
330
  ::-webkit-scrollbar {
331
- width: 12px;
 
332
  }
333
 
334
  ::-webkit-scrollbar-track {
335
- background: #0a0a0a;
 
336
  }
337
 
338
  ::-webkit-scrollbar-thumb {
339
- background: linear-gradient(135deg, var(--neon-pink), var(--neon-cyan));
340
  border-radius: 10px;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
341
  }
342
  """
343
 
@@ -345,36 +639,37 @@ code {
345
  # 🎭 GRADIO INTERFACE
346
  # ============================================
347
 
348
- demo = gr.Blocks(css=custom_css, title="🌟 SYNCHRONY", theme=gr.themes.Base())
349
 
350
  with demo:
351
  gr.Markdown("""
352
- # 🌟 SYNCHRONY
353
- ## *where students teach students* 💫
354
 
355
- *demo version - using simulated data*
356
 
357
  ---
358
  """)
359
 
360
- # HOME
361
- with gr.Tab("🏠 home"):
362
  gr.Markdown("""
363
- ## welcome to synchrony ✨
364
 
365
- *the ai-powered study platform where you learn by teaching each other*
366
  """)
367
 
368
  with gr.Column():
369
- gr.Markdown("### 📝 new here?")
370
- register_btn = gr.Button("🚀 REGISTER NOW", variant="primary", size="lg")
 
371
 
372
- gr.Markdown("### 🔐 already registered?")
 
373
  email_input = gr.Textbox(
374
- label="📧 university email",
375
  placeholder="your.email@university.edu"
376
  )
377
- login_btn = gr.Button("🔓 LOGIN", variant="secondary", size="lg")
378
  login_output = gr.Markdown()
379
 
380
  register_btn.click(
@@ -392,84 +687,77 @@ with demo:
392
  outputs=[login_output]
393
  )
394
 
395
- # MY TEAM
396
- with gr.Tab("👥 my team"):
397
- gr.Markdown("## your study squad 🔥")
398
- team_display = gr.Markdown(value="⚠️ please login first in the **HOME** tab!")
399
- refresh_team_btn = gr.Button("🔄 REFRESH TEAM INFO", variant="secondary")
400
- refresh_team_btn.click(fn=get_team_info, outputs=[team_display])
401
 
402
- # CHALLENGES
403
- with gr.Tab("🎯 challenges"):
404
  gr.Markdown("""
405
- ## your collaborative challenges 💪
406
 
407
- work together, learn from each other, level up!
408
  """)
409
- load_challenges_btn = gr.Button("📥 LOAD CHALLENGES", variant="primary", size="lg")
410
- challenges_display = gr.Markdown(value="⚠️ click the button above to load your challenges!")
411
- load_challenges_btn.click(fn=load_challenges, outputs=[challenges_display])
412
 
413
- # HINTS
414
- with gr.Tab("💡 hints"):
415
  gr.Markdown("""
416
- ## need help? no worries! 🤝
417
-
418
- synco's got your back with **adaptive hints**
419
 
420
- **hint 1:** gentle nudge 🤔
421
- **hint 2:** clearer guidance 💭
422
- **hint 3:** almost there! 🎯
423
  """)
424
 
425
  with gr.Row():
426
  challenge_select = gr.Dropdown(
427
- label="🎯 select challenge",
428
  choices=["1", "2", "3"],
429
  value="1"
430
  )
431
  hint_level_select = gr.Dropdown(
432
- label="💡 hint level",
433
  choices=[
434
- "1 - gentle nudge 🤔",
435
- "2 - clearer guidance 💭",
436
- "3 - almost there! 🎯"
437
  ],
438
- value="1 - gentle nudge 🤔"
439
  )
440
 
441
- get_hint_btn = gr.Button("💡 GET HINT", variant="primary", size="lg")
442
- hint_display = gr.Markdown(value="⚠️ select a challenge and hint level, then click the button!")
443
- get_hint_btn.click(
444
  fn=request_hint,
445
  inputs=[challenge_select, hint_level_select],
446
  outputs=[hint_display]
447
  )
448
 
449
- # CHAT
450
- with gr.Tab("💬 chat"):
451
  gr.Markdown("""
452
- ## team chat 💬
453
 
454
- discuss challenges, share ideas, help each other out!
455
 
456
- *demo mode - simulated responses*
457
  """)
458
 
459
  chatbot = gr.Chatbot(
460
  value=[],
461
  label="",
462
- height=400,
463
  type="messages"
464
  )
465
 
466
  with gr.Row():
467
  msg_input = gr.Textbox(
468
  label="",
469
- placeholder="type your message here...",
470
  scale=5
471
  )
472
- send_btn = gr.Button("📤 SEND", variant="primary", scale=1)
473
 
474
  send_btn.click(
475
  fn=send_message,
@@ -482,72 +770,22 @@ with demo:
482
  outputs=[chatbot, msg_input]
483
  )
484
 
485
- # ABOUT
486
- with gr.Tab("ℹ️ about"):
487
- gr.Markdown(f"""
488
- ## 🌟 about synchrony
489
-
490
- **synchrony** is an ai-powered collaborative learning platform.
491
-
492
- ---
493
-
494
- ### ✨ features
495
-
496
- ✅ **smart matching** - students matched by learning styles
497
- ✅ **ai challenges** - personalized collaborative challenges
498
- ✅ **adaptive hints** - progressive learning support
499
- ✅ **peer teaching** - students teach each other
500
-
501
- ---
502
-
503
- ### 🛠️ tech stack
504
-
505
- - **frontend:** gradio (python)
506
- - **backend:** n8n workflows
507
- - **ai:** groq api (llama 3.3 70b)
508
- - **database:** google sheets
509
-
510
- ---
511
-
512
- ### 🔗 links
513
-
514
- - 📝 [student registration]({REGISTRATION_FORM})
515
- - 📊 [view database]({GOOGLE_SHEETS})
516
-
517
- ---
518
-
519
- ### 👥 created by
520
-
521
- **maryam shanabli** | november 2025
522
-
523
- *powered by ai • built for students • designed for impact* 🚀
524
-
525
- ---
526
-
527
- ### 📊 demo note
528
-
529
- This is a **demonstration version** using simulated data. The real system connects to live n8n workflows, Groq AI API, and Google Sheets database for full functionality.
530
- """)
531
-
532
- # FOOTER
533
  gr.Markdown("""
534
  ---
535
 
536
- ### 🌟 **synchrony** | *collaborative learning, powered by ai* 💜
537
 
538
- made with 🔥 by maryam shanabli | 2025
 
 
539
  """)
540
 
541
- # ============================================
542
- # 🚀 LAUNCH
543
- # ============================================
544
-
545
  print("\n" + "="*60)
546
- print("🚀 SYNCHRONY STUDENT PORTAL (DEMO VERSION)")
547
  print("="*60)
548
- print("✅ Using simulated data for demonstration")
 
549
  print("✅ All features functional")
550
- print("✅ Ready for demo!")
551
  print("="*60 + "\n")
552
 
553
  demo.launch()
 
1
  import gradio as gr
2
+ import pandas as pd
3
+ import random
4
  import json
5
  from datetime import datetime
 
6
 
7
  # ============================================
8
+ # 🌟 SYNCHRONY - PROFESSIONAL LIGHT MODE
9
+ # Soft Academic Aesthetic
10
  # ============================================
11
 
12
  REGISTRATION_FORM = "https://docs.google.com/forms/d/e/1FAIpQLSfJFGx-yd0FPIuRYLUJut3BOOiQ14x_5DYheWpgrUqcHdQaCA/viewform"
13
  GOOGLE_SHEETS = "https://docs.google.com/spreadsheets/d/1rpR-E_RSooDkNDh-Q_1BDIeGw4vfgmusNAfwPqATaW4/edit?usp=sharing"
14
 
15
+ SHEET_ID = "1rpR-E_RSooDkNDh-Q_1BDIeGw4vfgmusNAfwPqATaW4"
16
+
17
+ STUDENTS_URL = f"https://docs.google.com/spreadsheets/d/{SHEET_ID}/gviz/tq?tqx=out:csv&sheet=Students"
18
+ GROUPS_URL = f"https://docs.google.com/spreadsheets/d/{SHEET_ID}/gviz/tq?tqx=out:csv&sheet=Groups"
19
+ CHALLENGES_URL = f"https://docs.google.com/spreadsheets/d/{SHEET_ID}/gviz/tq?tqx=out:csv&sheet=Challenges"
20
+
21
  current_student = {
22
  "name": None,
23
  "email": None,
 
27
  "challenges": []
28
  }
29
 
30
+ # Mock data fallback
 
 
 
 
 
 
31
  MOCK_CHALLENGES = [
32
  {
33
  "challenge_number": 1,
34
  "description": "Layla, explain how Binary Search Trees work to the group. Focus on BST properties, insertion, and search operations. Omar and Khaled, compare this with your data structures - how is searching in a BST different from searching in a linked list or checking elements in a queue?",
35
  "topics_involved": "Binary Search Trees, Linked Lists, Queues",
36
  "hints": [
37
+ "Start by drawing a simple diagram showing how nodes are organized in a BST with the property: left < parent < right",
38
+ "Think about the left-subtree and right-subtree properties - what makes a BST special compared to a regular tree?",
39
+ "Compare time complexity: BST search is O(log n) average case, while linked list search is O(n)"
40
  ]
41
  },
42
  {
 
44
  "description": "Omar, teach us about Linked Lists. Create a real-world example showing both singly and doubly linked lists. Layla and Khaled, find connections between Linked Lists and your data structures.",
45
  "topics_involved": "Linked Lists, Binary Search Trees, Queues",
46
  "hints": [
47
+ "Think about how nodes point to each other - singly linked has 'next' pointer, doubly linked has 'next' and 'prev'",
48
+ "Consider real-world examples: browser history (doubly linked), music playlist (singly linked), undo/redo (doubly linked)",
49
+ "Both BST nodes and queue nodes use pointers/references just like linked lists - they're all node-based structures!"
50
  ]
51
  },
52
  {
 
54
  "description": "Everyone: Design ONE real-world system that uses ALL three data structures (BST, Linked Lists, Queues). Explain how they work together. Be creative!",
55
  "topics_involved": "Binary Search Trees, Linked Lists, Queues",
56
  "hints": [
57
+ "Think of a system with searching, ordering, and waiting - like a restaurant management system or task scheduler",
58
+ "Example: Restaurant app with BST for menu items (fast lookup by price/name), Queue for order processing, Linked List for order history",
59
+ "Draw a diagram showing how data flows between the three structures in your system"
60
  ]
61
  }
62
  ]
63
 
64
  # ============================================
65
+ # 📊 GOOGLE SHEETS FUNCTIONS
66
  # ============================================
67
 
68
+ def read_sheet_safe(url, sheet_name="Unknown"):
69
+ try:
70
+ df = pd.read_csv(url)
71
+ print(f"✅ Loaded {len(df)} rows from {sheet_name}")
72
+ return df
73
+ except Exception as e:
74
+ print(f"⚠️ Could not read {sheet_name}: {e}")
75
+ return pd.DataFrame()
76
 
77
+ def get_students_in_group(group_id):
78
+ try:
79
+ groups_df = read_sheet_safe(GROUPS_URL, "Groups")
80
+
81
+ if groups_df.empty:
82
+ return [
83
+ {"name": "Omar Khalil", "topic": "Linked Lists"},
84
+ {"name": "Khaled Ibrahim", "topic": "Queues"},
85
+ {"name": "Layla Mahmoud", "topic": "Binary Search Trees"}
86
+ ]
87
+
88
+ group = groups_df[groups_df['group_id'] == group_id]
89
+
90
+ if group.empty:
91
+ return [
92
+ {"name": "Omar Khalil", "topic": "Linked Lists"},
93
+ {"name": "Khaled Ibrahim", "topic": "Queues"},
94
+ {"name": "Layla Mahmoud", "topic": "Binary Search Trees"}
95
+ ]
96
+
97
+ group_row = group.iloc[0]
98
+ member_names = str(group_row.get('member_names', '')).split(',')
99
+ topics = str(group_row.get('topics', '')).split(',')
100
+
101
+ team_members = []
102
+ for i, name in enumerate(member_names):
103
+ name = name.strip()
104
+ topic = topics[i].strip() if i < len(topics) else "Data Structures"
105
+ if name:
106
+ team_members.append({"name": name, "topic": topic})
107
+
108
+ if team_members:
109
+ return team_members
110
+ else:
111
+ return [
112
+ {"name": "Omar Khalil", "topic": "Linked Lists"},
113
+ {"name": "Khaled Ibrahim", "topic": "Queues"},
114
+ {"name": "Layla Mahmoud", "topic": "Binary Search Trees"}
115
+ ]
116
+
117
+ except Exception as e:
118
+ print(f"❌ Error: {e}")
119
+ return [
120
+ {"name": "Omar Khalil", "topic": "Linked Lists"},
121
+ {"name": "Khaled Ibrahim", "topic": "Queues"},
122
+ {"name": "Layla Mahmoud", "topic": "Binary Search Trees"}
123
+ ]
124
+
125
+ def get_challenges_for_session(session_id):
126
+ try:
127
+ challenges_df = read_sheet_safe(CHALLENGES_URL, "Challenges")
128
+
129
+ if challenges_df.empty:
130
+ return MOCK_CHALLENGES
131
+
132
+ session_challenges = challenges_df[challenges_df['session_id'] == session_id]
133
+
134
+ if session_challenges.empty:
135
+ return MOCK_CHALLENGES
136
+
137
+ challenges = []
138
+ for _, row in session_challenges.iterrows():
139
+ hints_json = row.get('hints_json', '[]')
140
+ try:
141
+ hints = json.loads(hints_json) if isinstance(hints_json, str) else []
142
+ except:
143
+ hints = []
144
+
145
+ challenges.append({
146
+ "challenge_number": row.get('challenge_number', len(challenges) + 1),
147
+ "description": row.get('description', 'No description'),
148
+ "topics_involved": row.get('topics_involved', 'N/A'),
149
+ "hints": hints
150
+ })
151
+
152
+ if challenges:
153
+ return challenges
154
+ else:
155
+ return MOCK_CHALLENGES
156
+
157
+ except Exception as e:
158
+ return MOCK_CHALLENGES
159
+
160
+ # ============================================
161
+ # 🔧 APPLICATION FUNCTIONS
162
+ # ============================================
163
 
164
  def lookup_student(email):
 
165
  try:
166
  if not email or "@" not in email:
167
+ return "❌ Please enter a valid email address"
168
 
169
+ name = email.split("@")[0].replace(".", " ").replace("_", " ").title()
 
 
170
 
171
+ try:
172
+ students_df = read_sheet_safe(STUDENTS_URL, "Students")
173
+
174
+ if not students_df.empty:
175
+ student = students_df[students_df['email'].str.lower() == email.lower()]
176
+
177
+ if not student.empty:
178
+ student_row = student.iloc[0]
179
+ name = student_row.get('name', name)
180
+ group_id = student_row.get('group_id', 'G001')
181
+ else:
182
+ group_id = "G001"
183
+ else:
184
+ group_id = "G001"
185
+ except:
186
+ group_id = "G001"
187
+
188
+ team_members = get_students_in_group(group_id)
189
+ session_id = f"S{datetime.utcnow().strftime('%Y%m%d%H%M%S')}"
190
 
191
  current_student["name"] = name
192
  current_student["email"] = email
193
+ current_student["group_id"] = group_id
194
  current_student["session_id"] = session_id
195
+ current_student["team_members"] = team_members
196
+
197
+ welcome_msg = f"### ✅ Welcome back, {name}!\n\n"
198
+ welcome_msg += f"**Session ID:** `{session_id}`\n\n"
199
+ welcome_msg += f"**Synco says:**\n"
200
+ welcome_msg += f"Hey {', '.join([m['name'] for m in team_members])}! Welcome to your Synchrony study session. "
201
+ welcome_msg += f"You're all studying Data Structures with different focus areas—perfect for peer teaching!\n\n"
202
+ welcome_msg += f"**Your Team ({group_id}):** {', '.join([m['name'] for m in team_members])}\n\n"
203
+ welcome_msg += f"👉 Head to the **My Team** tab to see everyone's topics!"
 
 
 
204
 
205
  return welcome_msg
206
 
207
  except Exception as e:
208
+ return f"❌ Error: {str(e)}"
 
209
 
210
  def get_team_info():
 
211
  if not current_student.get("team_members"):
212
+ return "⚠️ Please login first in the Home tab"
213
 
214
+ output = f"## 👥 Your Study Squad - {current_student.get('group_id', 'G001')}\n\n"
215
+ output += f"**Session ID:** `{current_student.get('session_id', 'not started')}`\n\n"
216
  output += "---\n\n"
217
 
218
  for member in current_student["team_members"]:
219
  user_name = current_student.get("name", "").lower()
220
  member_name = member.get("name", "").lower()
221
+ is_you = " **(You)**" if user_name in member_name or member_name in user_name else ""
222
  output += f"### 🎓 {member['name']}{is_you}\n"
223
+ output += f"**Focus Area:** {member.get('topic', 'N/A')}\n\n"
224
 
225
+ output += "---\n\n💡 Collaborate, learn together, and grow!"
226
  return output
227
 
 
228
  def load_challenges():
 
229
  if not current_student.get("session_id"):
230
+ return "⚠️ No active session. Please login first in the Home tab"
 
 
231
 
232
+ try:
233
+ session_id = current_student["session_id"]
234
+ challenges = get_challenges_for_session(session_id)
235
+ current_student["challenges"] = challenges
236
+
237
+ output = f"# 🎯 Your Collaborative Challenges\n\n"
238
+ output += f"**Synco says:** Here are your 3 collaborative challenges! Work together, discuss your approaches, "
239
+ output += f"and request hints when needed. Ready? Let's go!\n\n"
 
 
 
240
  output += "---\n\n"
241
+
242
+ for challenge in challenges:
243
+ output += f"## Challenge {challenge['challenge_number']}\n\n"
244
+ output += f"{challenge['description']}\n\n"
245
+ output += f"**📚 Topics:** {challenge['topics_involved']}\n\n"
246
+ output += f"💡 *Need help? Request a hint in the Hints tab!*\n\n"
247
+ output += "---\n\n"
248
+
249
+ return output
250
+
251
+ except Exception as e:
252
+ return f"❌ Error loading challenges: {str(e)}"
253
 
254
  def request_hint(challenge_num, hint_level_text):
 
255
  if not current_student.get("session_id"):
256
+ return "⚠️ No active session. Please login first"
257
 
258
  if not current_student.get("challenges"):
259
+ return "⚠️ Please load challenges first in the Challenges tab"
260
 
261
  try:
262
  hint_level = int(hint_level_text.split(" - ")[0])
263
  challenge_idx = int(challenge_num) - 1
264
 
265
+ if challenge_idx < 0 or challenge_idx >= len(current_student["challenges"]):
266
+ return "⚠️ Invalid challenge number"
267
+
268
+ challenge = current_student["challenges"][challenge_idx]
269
+ hints = challenge.get("hints", [])
270
 
271
+ if hint_level < 1 or hint_level > len(hints):
272
+ return f"⚠️ Only {len(hints)} hints available"
273
 
274
+ hint = hints[hint_level - 1]
 
275
 
 
276
  if hint_level == 1:
277
+ encouragement = "💡 **Think about it a bit more**"
278
  elif hint_level == 2:
279
+ encouragement = "💭 **You're getting closer**"
280
  else:
281
+ encouragement = "🎯 **Almost there**"
282
 
283
+ output = f"## {encouragement}\n\n"
284
+ output += f"**Challenge {challenge_num}** • Hint Level {hint_level}\n\n"
285
  output += "---\n\n"
286
  output += f"{hint}\n\n"
287
  output += "---\n\n"
288
+ output += f"💪 You got this! Keep going!"
289
 
290
  return output
291
 
292
  except Exception as e:
293
+ return f"❌ Error: {str(e)}"
 
294
 
295
  def send_message(message, history):
 
296
  if not message.strip():
297
  return history, ""
298
 
299
  history.append({
300
  "role": "user",
301
+ "content": f"**{current_student.get('name', 'You')}:** {message}"
302
  })
303
 
304
  if not current_student.get("team_members"):
305
+ response = "**Synco:** Please login first to chat with your team"
306
  else:
307
  other_members = [m for m in current_student["team_members"]
308
  if m['name'].lower() != current_student.get('name', '').lower()]
 
310
  if other_members:
311
  member = random.choice(other_members)
312
  responses = [
313
+ f"**{member['name']}:** That's a great point about {member['topic']}!",
314
+ f"**{member['name']}:** Interesting! Let me explain how {member['topic']} relates to that...",
315
+ f"**{member['name']}:** I agree! In {member['topic']}, we approach it similarly.",
316
+ f"**{member['name']}:** Good question! Let me draw a quick diagram...",
317
+ f"**Synco:** Excellent collaboration! Keep discussing!"
 
318
  ]
319
  response = random.choice(responses)
320
  else:
321
+ response = "**Synco:** Great thinking!"
322
 
323
  history.append({"role": "assistant", "content": response})
324
  return history, ""
325
 
 
326
  # ============================================
327
+ # 🎨 PROFESSIONAL LIGHT MODE CSS
328
  # ============================================
329
 
330
  custom_css = """
331
+ /* Professional Light Mode - Soft Academic Aesthetic */
332
+
333
  .gradio-container {
334
+ background: linear-gradient(135deg, #FDFBF7 0%, #F8F6F3 100%) !important;
335
+ font-family: 'Inter', 'SF Pro Display', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif !important;
336
+ color: #1F2937 !important;
337
  }
338
 
339
+ /* Color Variables */
340
  :root {
341
+ --primary: #7C3AED;
342
+ --primary-light: #A78BFA;
343
+ --accent: #F97316;
344
+ --success: #10B981;
345
+ --bg-cream: #FDFBF7;
346
+ --bg-light: #FFFFFF;
347
+ --text-dark: #1F2937;
348
+ --text-gray: #6B7280;
349
+ --border-light: #E5E7EB;
350
+ }
351
+
352
+ /* Main Container */
353
+ .contain {
354
+ background: var(--bg-cream) !important;
355
+ max-width: 1200px !important;
356
+ margin: 0 auto !important;
357
+ padding: 20px !important;
358
+ }
359
+
360
+ /* Tabs */
361
+ .tab-nav {
362
+ background: var(--bg-light) !important;
363
+ border-bottom: 2px solid var(--border-light) !important;
364
+ padding: 8px 0 !important;
365
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05) !important;
366
  }
367
 
368
  .tab-nav button {
369
+ background: transparent !important;
370
+ border: none !important;
371
+ color: var(--text-gray) !important;
372
+ font-weight: 600 !important;
373
+ font-size: 15px !important;
374
+ padding: 12px 24px !important;
375
+ margin: 0 4px !important;
376
+ border-radius: 8px !important;
377
+ transition: all 0.2s ease !important;
378
  }
379
 
380
  .tab-nav button:hover {
381
+ background: rgba(124, 58, 237, 0.08) !important;
382
+ color: var(--primary) !important;
 
383
  }
384
 
385
  .tab-nav button.selected {
386
+ background: var(--primary) !important;
387
+ color: white !important;
388
+ box-shadow: 0 2px 8px rgba(124, 58, 237, 0.25) !important;
389
  }
390
 
391
+ /* Input Fields */
392
+ input, textarea, select {
393
+ background: var(--bg-light) !important;
394
+ border: 2px solid var(--border-light) !important;
395
+ color: var(--text-dark) !important;
396
  border-radius: 10px !important;
397
+ font-size: 15px !important;
398
+ padding: 12px 16px !important;
399
+ transition: all 0.2s ease !important;
400
  }
401
 
402
+ input:focus, textarea:focus, select:focus {
403
+ border-color: var(--primary) !important;
404
+ box-shadow: 0 0 0 3px rgba(124, 58, 237, 0.1) !important;
405
+ outline: none !important;
406
  }
407
 
408
+ input::placeholder, textarea::placeholder {
409
+ color: #9CA3AF !important;
410
+ }
411
+
412
+ /* Buttons */
413
  button {
414
+ background: var(--primary) !important;
415
  border: none !important;
416
+ color: white !important;
417
+ font-weight: 600 !important;
418
+ font-size: 15px !important;
419
  border-radius: 10px !important;
420
+ padding: 12px 24px !important;
421
+ transition: all 0.2s ease !important;
422
+ box-shadow: 0 2px 8px rgba(124, 58, 237, 0.2) !important;
423
  }
424
 
425
  button:hover {
426
+ background: #6D28D9 !important;
427
+ transform: translateY(-1px) !important;
428
+ box-shadow: 0 4px 12px rgba(124, 58, 237, 0.3) !important;
429
+ }
430
+
431
+ button:active {
432
+ transform: translateY(0) !important;
433
+ }
434
+
435
+ button.secondary {
436
+ background: var(--accent) !important;
437
+ box-shadow: 0 2px 8px rgba(249, 115, 22, 0.2) !important;
438
+ }
439
+
440
+ button.secondary:hover {
441
+ background: #EA580C !important;
442
  }
443
 
444
+ /* Output/Markdown Boxes */
445
+ .output-markdown, .prose, .markdown {
446
+ background: var(--bg-light) !important;
447
+ border: 2px solid var(--border-light) !important;
448
  border-radius: 12px !important;
449
  padding: 24px !important;
450
+ color: var(--text-dark) !important;
451
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05) !important;
452
+ line-height: 1.7 !important;
453
  }
454
 
455
+ /* Headers */
456
  h1 {
457
+ color: var(--primary) !important;
458
+ font-weight: 800 !important;
459
+ font-size: 42px !important;
 
 
460
  text-align: center !important;
461
+ margin: 24px 0 !important;
462
+ letter-spacing: -0.5px !important;
463
  }
464
 
465
  h2 {
466
+ color: var(--primary) !important;
467
+ font-weight: 700 !important;
468
+ font-size: 28px !important;
469
+ margin: 20px 0 12px 0 !important;
470
  }
471
 
472
  h3 {
473
+ color: var(--accent) !important;
474
+ font-weight: 600 !important;
475
+ font-size: 20px !important;
476
+ margin: 16px 0 8px 0 !important;
477
+ }
478
+
479
+ /* Paragraphs */
480
+ p {
481
+ color: var(--text-dark) !important;
482
+ font-size: 15px !important;
483
+ line-height: 1.7 !important;
484
+ margin: 12px 0 !important;
485
+ }
486
+
487
+ /* Strong/Bold */
488
+ strong {
489
+ color: var(--primary) !important;
490
  font-weight: 700 !important;
491
  }
492
 
493
+ /* Links */
494
+ a {
495
+ color: var(--primary) !important;
496
+ text-decoration: none !important;
497
+ font-weight: 600 !important;
498
+ transition: color 0.2s ease !important;
499
+ }
500
+
501
+ a:hover {
502
+ color: var(--accent) !important;
503
+ text-decoration: underline !important;
504
+ }
505
+
506
+ /* Code blocks */
507
  code {
508
+ background: #F3F4F6 !important;
509
+ color: var(--primary) !important;
510
+ padding: 3px 8px !important;
511
  border-radius: 6px !important;
512
+ border: 1px solid var(--border-light) !important;
513
+ font-family: 'SF Mono', 'Monaco', 'Consolas', monospace !important;
514
+ font-size: 14px !important;
515
+ }
516
+
517
+ /* Horizontal Rules */
518
+ hr {
519
+ border: none !important;
520
+ border-top: 2px solid var(--border-light) !important;
521
+ margin: 24px 0 !important;
522
  }
523
 
524
+ /* Scrollbar */
525
  ::-webkit-scrollbar {
526
+ width: 10px;
527
+ height: 10px;
528
  }
529
 
530
  ::-webkit-scrollbar-track {
531
+ background: #F3F4F6;
532
+ border-radius: 10px;
533
  }
534
 
535
  ::-webkit-scrollbar-thumb {
536
+ background: var(--primary-light);
537
  border-radius: 10px;
538
+ border: 2px solid #F3F4F6;
539
+ }
540
+
541
+ ::-webkit-scrollbar-thumb:hover {
542
+ background: var(--primary);
543
+ }
544
+
545
+ /* Labels */
546
+ label {
547
+ color: var(--text-dark) !important;
548
+ font-weight: 600 !important;
549
+ font-size: 14px !important;
550
+ margin-bottom: 6px !important;
551
+ }
552
+
553
+ /* Chatbot Messages */
554
+ .message-wrap {
555
+ background: var(--bg-light) !important;
556
+ border: 1px solid var(--border-light) !important;
557
+ border-radius: 12px !important;
558
+ margin: 8px 0 !important;
559
+ padding: 12px !important;
560
+ }
561
+
562
+ .message.user {
563
+ background: var(--primary) !important;
564
+ color: white !important;
565
+ border-radius: 12px !important;
566
+ padding: 12px 16px !important;
567
+ margin-left: 20% !important;
568
+ }
569
+
570
+ .message.bot {
571
+ background: #F3F4F6 !important;
572
+ color: var(--text-dark) !important;
573
+ border-radius: 12px !important;
574
+ padding: 12px 16px !important;
575
+ margin-right: 20% !important;
576
+ }
577
+
578
+ /* Dropdown */
579
+ .dropdown-container {
580
+ background: var(--bg-light) !important;
581
+ border: 2px solid var(--border-light) !important;
582
+ border-radius: 10px !important;
583
+ }
584
+
585
+ /* Lists */
586
+ ul, ol {
587
+ color: var(--text-dark) !important;
588
+ padding-left: 24px !important;
589
+ }
590
+
591
+ li {
592
+ margin: 8px 0 !important;
593
+ line-height: 1.6 !important;
594
+ }
595
+
596
+ /* Blockquotes */
597
+ blockquote {
598
+ border-left: 4px solid var(--primary) !important;
599
+ padding-left: 16px !important;
600
+ color: var(--text-gray) !important;
601
+ font-style: italic !important;
602
+ margin: 16px 0 !important;
603
+ }
604
+
605
+ /* Success Messages */
606
+ .success {
607
+ background: rgba(16, 185, 129, 0.1) !important;
608
+ border-left: 4px solid var(--success) !important;
609
+ padding: 16px !important;
610
+ border-radius: 8px !important;
611
+ color: var(--text-dark) !important;
612
+ }
613
+
614
+ /* Warning Messages */
615
+ .warning {
616
+ background: rgba(249, 115, 22, 0.1) !important;
617
+ border-left: 4px solid var(--accent) !important;
618
+ padding: 16px !important;
619
+ border-radius: 8px !important;
620
+ color: var(--text-dark) !important;
621
+ }
622
+
623
+ /* Cards/Panels */
624
+ .panel {
625
+ background: var(--bg-light) !important;
626
+ border: 2px solid var(--border-light) !important;
627
+ border-radius: 12px !important;
628
+ padding: 20px !important;
629
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04) !important;
630
+ }
631
+
632
+ /* Emoji styling */
633
+ .emoji {
634
+ font-size: 1.2em !important;
635
  }
636
  """
637
 
 
639
  # 🎭 GRADIO INTERFACE
640
  # ============================================
641
 
642
+ demo = gr.Blocks(css=custom_css, title="Synchrony • Collaborative Learning", theme=gr.themes.Soft())
643
 
644
  with demo:
645
  gr.Markdown("""
646
+ # 🌟 Synchrony
647
+ ## Where students teach students
648
 
649
+ *AI-powered collaborative learning platform*
650
 
651
  ---
652
  """)
653
 
654
+ with gr.Tab("🏠 Home"):
 
655
  gr.Markdown("""
656
+ ## Welcome to Synchrony
657
 
658
+ Join a community of students learning together through peer teaching.
659
  """)
660
 
661
  with gr.Column():
662
+ gr.Markdown("### 📝 New Here?")
663
+ gr.Markdown("Register to get matched with your perfect study group")
664
+ register_btn = gr.Button("Register Now", variant="primary", size="lg")
665
 
666
+ gr.Markdown("### 🔐 Already Registered?")
667
+ gr.Markdown("Enter your university email to access your study session")
668
  email_input = gr.Textbox(
669
+ label="University Email",
670
  placeholder="your.email@university.edu"
671
  )
672
+ login_btn = gr.Button("Login", variant="secondary", size="lg")
673
  login_output = gr.Markdown()
674
 
675
  register_btn.click(
 
687
  outputs=[login_output]
688
  )
689
 
690
+ with gr.Tab("👥 My Team"):
691
+ gr.Markdown("## Your Study Squad")
692
+ gr.Markdown("Meet your teammates and see what everyone's focusing on")
693
+ team_display = gr.Markdown(value="⚠️ Please login first in the Home tab")
694
+ refresh_btn = gr.Button("Refresh Team Info", variant="secondary")
695
+ refresh_btn.click(fn=get_team_info, outputs=[team_display])
696
 
697
+ with gr.Tab("🎯 Challenges"):
 
698
  gr.Markdown("""
699
+ ## Collaborative Challenges
700
 
701
+ Work together on AI-generated challenges designed for your group's topics
702
  """)
703
+ load_btn = gr.Button("Load Challenges", variant="primary", size="lg")
704
+ challenges_display = gr.Markdown(value="Click the button above to load your challenges")
705
+ load_btn.click(fn=load_challenges, outputs=[challenges_display])
706
 
707
+ with gr.Tab("💡 Hints"):
 
708
  gr.Markdown("""
709
+ ## Adaptive Hints
 
 
710
 
711
+ Get progressive hints when you're stuck—from gentle nudges to detailed guidance
 
 
712
  """)
713
 
714
  with gr.Row():
715
  challenge_select = gr.Dropdown(
716
+ label="Select Challenge",
717
  choices=["1", "2", "3"],
718
  value="1"
719
  )
720
  hint_level_select = gr.Dropdown(
721
+ label="Hint Level",
722
  choices=[
723
+ "1 - Gentle nudge",
724
+ "2 - Clearer guidance",
725
+ "3 - Almost there"
726
  ],
727
+ value="1 - Gentle nudge"
728
  )
729
 
730
+ hint_btn = gr.Button("Get Hint", variant="primary", size="lg")
731
+ hint_display = gr.Markdown(value="Select a challenge and hint level, then click the button")
732
+ hint_btn.click(
733
  fn=request_hint,
734
  inputs=[challenge_select, hint_level_select],
735
  outputs=[hint_display]
736
  )
737
 
738
+ with gr.Tab("💬 Chat"):
 
739
  gr.Markdown("""
740
+ ## Team Chat
741
 
742
+ Discuss challenges, share insights, and help each other learn
743
 
744
+ *Demo mode - responses are simulated*
745
  """)
746
 
747
  chatbot = gr.Chatbot(
748
  value=[],
749
  label="",
750
+ height=450,
751
  type="messages"
752
  )
753
 
754
  with gr.Row():
755
  msg_input = gr.Textbox(
756
  label="",
757
+ placeholder="Type your message...",
758
  scale=5
759
  )
760
+ send_btn = gr.Button("Send", variant="primary", scale=1)
761
 
762
  send_btn.click(
763
  fn=send_message,
 
770
  outputs=[chatbot, msg_input]
771
  )
772
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
773
  gr.Markdown("""
774
  ---
775
 
776
+ ### Synchrony • Collaborative Learning Platform
777
 
778
+ *Powered by AI • Built for Students • Designed for Impact*
779
+
780
+ Created by Maryam Shanabli • 2025
781
  """)
782
 
 
 
 
 
783
  print("\n" + "="*60)
784
+ print("🌟 SYNCHRONY - Professional Light Mode")
785
  print("="*60)
786
+ print("✅ Soft academic aesthetic")
787
+ print("✅ Optimal readability")
788
  print("✅ All features functional")
 
789
  print("="*60 + "\n")
790
 
791
  demo.launch()