Dannyar608 commited on
Commit
431b892
Β·
verified Β·
1 Parent(s): 3e64737

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +650 -214
app.py CHANGED
@@ -3,9 +3,12 @@ import pandas as pd
3
  import json
4
  import os
5
  import re
 
 
6
  from PyPDF2 import PdfReader
7
  from collections import defaultdict
8
  from transformers import pipeline
 
9
 
10
  # Initialize NER model (will load only if transformers is available)
11
  try:
@@ -15,12 +18,12 @@ except Exception as e:
15
  ner_pipeline = None
16
 
17
  # ========== IMPROVED TRANSCRIPT PARSING ==========
18
- def extract_gpa(text, gpa_type):
19
  pattern = rf'{gpa_type}\s*([\d\.]+)'
20
  match = re.search(pattern, text)
21
  return match.group(1) if match else "N/A"
22
 
23
- def extract_courses_from_table(text):
24
  # This pattern matches the course table rows in the transcript
25
  course_pattern = re.compile(
26
  r'(\d{4}-\d{4})\s*' # School year
@@ -58,53 +61,56 @@ def extract_courses_from_table(text):
58
 
59
  return courses_by_grade
60
 
61
- def parse_transcript(file):
62
- if file.name.endswith('.pdf'):
63
- text = ''
64
- reader = PdfReader(file)
65
- for page in reader.pages:
66
- text += page.extract_text() + '\n'
67
-
68
- # Extract GPA information
69
- gpa_data = {
70
- 'weighted': extract_gpa(text, 'Weighted GPA'),
71
- 'unweighted': extract_gpa(text, 'Un-weighted GPA')
72
- }
73
-
74
- # Extract current grade level
75
- grade_match = re.search(r'Current Grade:\s*(\d+)', text)
76
- grade_level = grade_match.group(1) if grade_match else "Unknown"
77
-
78
- # Extract all courses with grades and year taken
79
- courses_by_grade = extract_courses_from_table(text)
80
-
81
- # Prepare detailed output
82
- output_text = f"Student Transcript Summary\n{'='*40}\n"
83
- output_text += f"Current Grade Level: {grade_level}\n"
84
- output_text += f"Weighted GPA: {gpa_data['weighted']}\n"
85
- output_text += f"Unweighted GPA: {gpa_data['unweighted']}\n\n"
86
- output_text += "Course History:\n{'='*40}\n"
87
-
88
- # Sort grades numerically (09, 10, 11, 12)
89
- for grade in sorted(courses_by_grade.keys(), key=int):
90
- output_text += f"\nGrade {grade}:\n{'-'*30}\n"
91
- for course in courses_by_grade[grade]:
92
- output_text += f"- {course['name']}"
93
- if 'grade' in course and course['grade']:
94
- output_text += f" (Grade: {course['grade']})"
95
- if 'credits' in course:
96
- output_text += f" | Credits: {course['credits']}"
97
- output_text += f" | Year: {course['year']}\n"
98
-
99
- return output_text, {
100
- "gpa": gpa_data,
101
- "grade_level": grade_level,
102
- "courses": dict(courses_by_grade)
103
- }
104
- else:
105
- return "Unsupported file format (PDF only for transcript parsing)", None
 
 
 
106
 
107
- # ========== LEARNING STYLE QUIZ ==========
108
  learning_style_questions = [
109
  "When you study for a test, you prefer to:",
110
  "When you need directions to a new place, you prefer:",
@@ -151,7 +157,7 @@ learning_style_options = [
151
  ["Write out possible solutions (Reading/Writing)", "Talk through it with someone (Auditory)", "Draw diagrams (Visual)", "Build a model or prototype (Kinesthetic)"]
152
  ]
153
 
154
- def learning_style_quiz(*answers):
155
  scores = {
156
  "Visual": 0,
157
  "Auditory": 0,
@@ -197,80 +203,132 @@ def learning_style_quiz(*answers):
197
  result += "- Create mind maps and diagrams\n"
198
  result += "- Watch educational videos\n"
199
  result += "- Use flashcards with images\n"
 
200
  elif primary_styles[0] == "Auditory":
201
  result += "Tips for Auditory Learners:\n"
202
  result += "- Record lectures and listen to them\n"
203
  result += "- Participate in study groups\n"
204
  result += "- Explain concepts out loud to yourself\n"
205
  result += "- Use rhymes or songs to remember information\n"
 
206
  elif primary_styles[0] == "Reading/Writing":
207
  result += "Tips for Reading/Writing Learners:\n"
208
  result += "- Write detailed notes\n"
209
  result += "- Create summaries in your own words\n"
210
  result += "- Read textbooks and articles\n"
211
  result += "- Make lists to organize information\n"
 
212
  else: # Kinesthetic
213
  result += "Tips for Kinesthetic Learners:\n"
214
  result += "- Use hands-on activities\n"
215
  result += "- Take frequent movement breaks\n"
216
  result += "- Create physical models\n"
217
  result += "- Associate information with physical actions\n"
 
218
  else:
219
  result += f"You have multiple strong learning styles: {', '.join(primary_styles)}\n\n"
220
- result += "You may benefit from combining different learning approaches.\n"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
221
 
222
  return result
223
 
224
- # ========== SAVE STUDENT PROFILE ==========
225
- def save_profile(name, age, interests, transcript, learning_style,
226
- movie, movie_reason, show, show_reason,
227
- book, book_reason, character, character_reason, blog):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
228
  # Convert age to int if it's a numpy number (from gradio Number input)
229
  age = int(age) if age else 0
230
 
231
- favorites = {
232
- "movie": movie,
233
- "movie_reason": movie_reason,
234
- "show": show,
235
- "show_reason": show_reason,
236
- "book": book,
237
- "book_reason": book_reason,
238
- "character": character,
239
- "character_reason": character_reason
240
- }
241
-
242
- data = {
243
  "name": name,
244
  "age": age,
245
  "interests": interests,
246
  "transcript": transcript,
247
  "learning_style": learning_style,
248
- "favorites": favorites,
249
- "blog": blog
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
250
  }
251
 
 
252
  os.makedirs("student_profiles", exist_ok=True)
253
- json_path = os.path.join("student_profiles", f"{name.replace(' ', '_')}_profile.json")
254
- with open(json_path, "w") as f:
255
- json.dump(data, f, indent=2)
 
 
 
 
256
 
257
- markdown_summary = f"""### Student Profile: {name}
258
- **Age:** {age}
259
- **Interests:** {interests}
260
- **Learning Style:** {learning_style}
261
- #### Transcript:
262
- {transcript_display(transcript)}
263
- #### Favorites:
264
- - Movie: {favorites['movie']} ({favorites['movie_reason']})
265
- - Show: {favorites['show']} ({favorites['show_reason']})
266
- - Book: {favorites['book']} ({favorites['book_reason']})
267
- - Character: {favorites['character']} ({favorites['character_reason']})
268
- #### Blog:
269
- {blog if blog else "_No blog provided_"}
270
- """
271
- return markdown_summary
 
 
 
 
 
 
 
272
 
273
- def transcript_display(transcript_dict):
 
274
  if not transcript_dict or "courses" not in transcript_dict:
275
  return "No course information available"
276
 
@@ -297,169 +355,547 @@ def transcript_display(transcript_dict):
297
 
298
  return display
299
 
300
- # ========== AI TEACHING ASSISTANT ==========
301
- def load_profile():
302
- if not os.path.exists("student_profiles"):
303
- return {}
304
- files = [f for f in os.listdir("student_profiles") if f.endswith('.json')]
305
- if files:
306
- with open(os.path.join("student_profiles", files[0]), "r") as f:
307
- return json.load(f)
308
- return {}
309
-
310
- def generate_response(message, history):
311
- profile = load_profile()
312
  if not profile:
313
- return "Please complete and save your profile first using the previous tabs."
314
-
315
- # Get profile data
316
- learning_style = profile.get("learning_style", "")
317
- grade_level = profile.get("transcript", {}).get("grade_level", "unknown")
318
- gpa = profile.get("transcript", {}).get("gpa", {})
319
- interests = profile.get("interests", "")
320
- courses = profile.get("transcript", {}).get("courses", {})
321
-
322
- # Common responses
323
- greetings = ["hi", "hello", "hey"]
324
- study_help = ["study", "learn", "prepare", "exam"]
325
- grade_help = ["grade", "gpa", "score"]
326
- interest_help = ["interest", "hobby", "passion"]
327
- course_help = ["courses", "classes", "transcript", "schedule"]
328
-
329
- if any(greet in message.lower() for greet in greetings):
330
- return f"Hello {profile.get('name', 'there')}! How can I help you today?"
331
-
332
- elif any(word in message.lower() for word in study_help):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
333
  if "Visual" in learning_style:
334
- response = ("Based on your visual learning style, I recommend:\n"
335
- "- Creating mind maps or diagrams\n"
336
- "- Using color-coded notes\n"
337
- "- Watching educational videos")
338
- elif "Auditory" in learning_style:
339
- response = ("Based on your auditory learning style, I recommend:\n"
340
- "- Recording lectures and listening to them\n"
341
- "- Participating in study groups\n"
342
- "- Explaining concepts out loud")
343
- elif "Reading/Writing" in learning_style:
344
- response = ("Based on your reading/writing learning style, I recommend:\n"
345
- "- Writing detailed notes\n"
346
- "- Creating summaries in your own words\n"
347
- "- Reading textbooks and articles")
348
- elif "Kinesthetic" in learning_style:
349
- response = ("Based on your kinesthetic learning style, I recommend:\n"
350
- "- Hands-on practice\n"
351
- "- Creating physical models\n"
352
- "- Taking frequent movement breaks")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
353
  else:
354
- response = ("Here are some general study tips:\n"
355
- "- Break study sessions into 25-minute chunks\n"
356
- "- Review material regularly\n"
357
- "- Teach concepts to someone else")
358
 
359
  return response
360
 
361
- elif any(word in message.lower() for word in grade_help):
362
- return (f"Your GPA information:\n"
363
- f"- Unweighted: {gpa.get('unweighted', 'N/A')}\n"
364
- f"- Weighted: {gpa.get('weighted', 'N/A')}\n\n"
365
- "To improve your grades, try:\n"
366
- "- Setting specific goals\n"
367
- "- Meeting with teachers\n"
368
- "- Developing a study schedule")
369
-
370
- elif any(word in message.lower() for word in interest_help):
371
- return (f"I see you're interested in: {interests}\n\n"
372
- "You might want to:\n"
373
- "- Find clubs or activities related to these interests\n"
374
- "- Explore career paths that align with them")
375
-
376
- elif any(word in message.lower() for word in course_help):
377
- response = "Here's a summary of your courses:\n"
378
  for grade in sorted(courses.keys(), key=int):
379
- response += f"\nGrade {grade}:\n"
380
  for course in courses[grade]:
381
- response += f"- {course['name']}"
382
  if 'grade' in course:
383
- response += f" (Grade: {course['grade']})"
384
  response += "\n"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
385
  return response
386
 
387
- elif "help" in message.lower():
388
- return ("I can help with:\n"
389
- "- Study tips based on your learning style\n"
390
- "- GPA and grade information\n"
391
- "- Course history and schedules\n"
392
- "- General academic advice\n\n"
393
- "Try asking about study strategies or your grades!")
 
 
 
 
 
 
394
 
395
- else:
396
- return ("I'm your personalized teaching assistant. "
397
- "I can help with study tips, grade information, and academic advice. "
398
- "Try asking about how to study for your classes!")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
399
 
400
  # ========== GRADIO INTERFACE ==========
401
- with gr.Blocks() as app:
402
- with gr.Tab("Step 1: Upload Transcript"):
403
- gr.Markdown("### Upload your transcript (PDF recommended for best results)")
404
- transcript_file = gr.File(label="Transcript file", file_types=[".pdf"])
405
- transcript_output = gr.Textbox(label="Transcript Results", lines=20)
406
- transcript_data = gr.State()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
407
  transcript_file.change(
408
  fn=parse_transcript,
409
  inputs=transcript_file,
410
  outputs=[transcript_output, transcript_data]
411
  )
412
-
413
- with gr.Tab("Step 2: Learning Style Quiz"):
414
- gr.Markdown("### Learning Style Quiz (20 Questions)")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
415
  quiz_components = []
416
- for i, (question, options) in enumerate(zip(learning_style_questions, learning_style_options)):
417
- quiz_components.append(gr.Radio(options, label=f"{i+1}. {question}"))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
418
 
419
- learning_output = gr.Textbox(label="Your Learning Style", lines=15)
420
- gr.Button("Submit Quiz").click(
421
  fn=learning_style_quiz,
422
  inputs=quiz_components,
423
  outputs=learning_output
424
  )
425
-
426
- with gr.Tab("Step 3: Personal Questions"):
427
- name = gr.Textbox(label="What's your name?")
428
- age = gr.Number(label="How old are you?", precision=0)
429
- interests = gr.Textbox(label="What are your interests?")
430
- movie = gr.Textbox(label="Favorite movie?")
431
- movie_reason = gr.Textbox(label="Why do you like that movie?")
432
- show = gr.Textbox(label="Favorite TV show?")
433
- show_reason = gr.Textbox(label="Why do you like that show?")
434
- book = gr.Textbox(label="Favorite book?")
435
- book_reason = gr.Textbox(label="Why do you like that book?")
436
- character = gr.Textbox(label="Favorite character?")
437
- character_reason = gr.Textbox(label="Why do you like that character?")
438
- blog_checkbox = gr.Checkbox(label="Do you want to write a blog?", value=False)
439
- blog_text = gr.Textbox(label="Write your blog here", visible=False, lines=5)
440
- blog_checkbox.change(lambda x: gr.update(visible=x), inputs=blog_checkbox, outputs=blog_text)
441
-
442
- with gr.Tab("Step 4: Save & Review"):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
443
  output_summary = gr.Markdown()
444
- save_btn = gr.Button("Save Profile")
 
 
 
 
 
 
445
  save_btn.click(
446
  fn=save_profile,
447
- inputs=[name, age, interests, transcript_data, learning_output,
448
- movie, movie_reason, show, show_reason,
449
- book, book_reason, character, character_reason, blog_text],
 
 
 
450
  outputs=output_summary
 
 
 
451
  )
452
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
453
  with gr.Tab("πŸ€– AI Teaching Assistant"):
454
  gr.Markdown("## Your Personalized Learning Assistant")
 
 
 
 
 
 
 
 
 
 
 
 
 
455
  chatbot = gr.ChatInterface(
456
- fn=generate_response,
457
  examples=[
458
- "How should I study for my next test?",
459
- "What's my GPA information?",
460
  "Show me my course history",
461
- "How can I improve my grades?"
462
- ]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
463
  )
464
 
465
  if __name__ == "__main__":
 
3
  import json
4
  import os
5
  import re
6
+ import hashlib
7
+ from datetime import datetime
8
  from PyPDF2 import PdfReader
9
  from collections import defaultdict
10
  from transformers import pipeline
11
+ from typing import Dict, List, Optional
12
 
13
  # Initialize NER model (will load only if transformers is available)
14
  try:
 
18
  ner_pipeline = None
19
 
20
  # ========== IMPROVED TRANSCRIPT PARSING ==========
21
+ def extract_gpa(text: str, gpa_type: str) -> str:
22
  pattern = rf'{gpa_type}\s*([\d\.]+)'
23
  match = re.search(pattern, text)
24
  return match.group(1) if match else "N/A"
25
 
26
+ def extract_courses_from_table(text: str) -> Dict[str, List[Dict]]:
27
  # This pattern matches the course table rows in the transcript
28
  course_pattern = re.compile(
29
  r'(\d{4}-\d{4})\s*' # School year
 
61
 
62
  return courses_by_grade
63
 
64
+ def parse_transcript(file) -> tuple:
65
+ try:
66
+ if file.name.endswith('.pdf'):
67
+ text = ''
68
+ reader = PdfReader(file)
69
+ for page in reader.pages:
70
+ text += page.extract_text() + '\n'
71
+
72
+ # Extract GPA information
73
+ gpa_data = {
74
+ 'weighted': extract_gpa(text, 'Weighted GPA'),
75
+ 'unweighted': extract_gpa(text, 'Un-weighted GPA')
76
+ }
77
+
78
+ # Extract current grade level
79
+ grade_match = re.search(r'Current Grade:\s*(\d+)', text)
80
+ grade_level = grade_match.group(1) if grade_match else "Unknown"
81
+
82
+ # Extract all courses with grades and year taken
83
+ courses_by_grade = extract_courses_from_table(text)
84
+
85
+ # Prepare detailed output
86
+ output_text = f"Student Transcript Summary\n{'='*40}\n"
87
+ output_text += f"Current Grade Level: {grade_level}\n"
88
+ output_text += f"Weighted GPA: {gpa_data['weighted']}\n"
89
+ output_text += f"Unweighted GPA: {gpa_data['unweighted']}\n\n"
90
+ output_text += "Course History:\n{'='*40}\n"
91
+
92
+ # Sort grades numerically (09, 10, 11, 12)
93
+ for grade in sorted(courses_by_grade.keys(), key=int):
94
+ output_text += f"\nGrade {grade}:\n{'-'*30}\n"
95
+ for course in courses_by_grade[grade]:
96
+ output_text += f"- {course['name']}"
97
+ if 'grade' in course and course['grade']:
98
+ output_text += f" (Grade: {course['grade']})"
99
+ if 'credits' in course:
100
+ output_text += f" | Credits: {course['credits']}"
101
+ output_text += f" | Year: {course['year']}\n"
102
+
103
+ return output_text, {
104
+ "gpa": gpa_data,
105
+ "grade_level": grade_level,
106
+ "courses": dict(courses_by_grade)
107
+ }
108
+ else:
109
+ return "Unsupported file format (PDF only for transcript parsing)", None
110
+ except Exception as e:
111
+ return f"Error processing transcript: {str(e)}", None
112
 
113
+ # ========== ENHANCED LEARNING STYLE QUIZ ==========
114
  learning_style_questions = [
115
  "When you study for a test, you prefer to:",
116
  "When you need directions to a new place, you prefer:",
 
157
  ["Write out possible solutions (Reading/Writing)", "Talk through it with someone (Auditory)", "Draw diagrams (Visual)", "Build a model or prototype (Kinesthetic)"]
158
  ]
159
 
160
+ def learning_style_quiz(*answers) -> str:
161
  scores = {
162
  "Visual": 0,
163
  "Auditory": 0,
 
203
  result += "- Create mind maps and diagrams\n"
204
  result += "- Watch educational videos\n"
205
  result += "- Use flashcards with images\n"
206
+ result += "- Highlight key information in different colors\n"
207
  elif primary_styles[0] == "Auditory":
208
  result += "Tips for Auditory Learners:\n"
209
  result += "- Record lectures and listen to them\n"
210
  result += "- Participate in study groups\n"
211
  result += "- Explain concepts out loud to yourself\n"
212
  result += "- Use rhymes or songs to remember information\n"
213
+ result += "- Listen to educational podcasts\n"
214
  elif primary_styles[0] == "Reading/Writing":
215
  result += "Tips for Reading/Writing Learners:\n"
216
  result += "- Write detailed notes\n"
217
  result += "- Create summaries in your own words\n"
218
  result += "- Read textbooks and articles\n"
219
  result += "- Make lists to organize information\n"
220
+ result += "- Rewrite your notes to reinforce learning\n"
221
  else: # Kinesthetic
222
  result += "Tips for Kinesthetic Learners:\n"
223
  result += "- Use hands-on activities\n"
224
  result += "- Take frequent movement breaks\n"
225
  result += "- Create physical models\n"
226
  result += "- Associate information with physical actions\n"
227
+ result += "- Study while walking or using a standing desk\n"
228
  else:
229
  result += f"You have multiple strong learning styles: {', '.join(primary_styles)}\n\n"
230
+ result += "You may benefit from combining different learning approaches:\n"
231
+ if "Visual" in primary_styles:
232
+ result += "- Create visual representations of what you're learning\n"
233
+ if "Auditory" in primary_styles:
234
+ result += "- Discuss concepts with others or record yourself explaining them\n"
235
+ if "Reading/Writing" in primary_styles:
236
+ result += "- Write summaries and read additional materials\n"
237
+ if "Kinesthetic" in primary_styles:
238
+ result += "- Incorporate physical movement into your study sessions\n"
239
+
240
+ # Add general study tips
241
+ result += "\nAdditional Study Tips for All Learners:\n"
242
+ result += "- Use the Pomodoro technique (25 min study, 5 min break)\n"
243
+ result += "- Teach concepts to someone else to reinforce your understanding\n"
244
+ result += "- Connect new information to what you already know\n"
245
+ result += "- Get adequate sleep to consolidate memories\n"
246
 
247
  return result
248
 
249
+ # ========== ENHANCED STUDENT PROFILE SYSTEM ==========
250
+ def hash_sensitive_data(data: str) -> str:
251
+ """Hash sensitive data for privacy protection"""
252
+ return hashlib.sha256(data.encode()).hexdigest()
253
+
254
+ def get_profile_list() -> List[str]:
255
+ """Get list of available profiles"""
256
+ if not os.path.exists("student_profiles"):
257
+ return []
258
+ return [f.replace("_profile.json", "").replace("_", " ")
259
+ for f in os.listdir("student_profiles")
260
+ if f.endswith('_profile.json')]
261
+
262
+ def save_profile(name: str, age: int, interests: str, transcript: dict, learning_style: str,
263
+ movie: str, movie_reason: str, show: str, show_reason: str,
264
+ book: str, book_reason: str, character: str, character_reason: str,
265
+ blog: str, goals: str, study_preferences: str) -> str:
266
+ """Save student profile with enhanced features"""
267
  # Convert age to int if it's a numpy number (from gradio Number input)
268
  age = int(age) if age else 0
269
 
270
+ # Create profile dictionary
271
+ profile_data = {
 
 
 
 
 
 
 
 
 
 
272
  "name": name,
273
  "age": age,
274
  "interests": interests,
275
  "transcript": transcript,
276
  "learning_style": learning_style,
277
+ "favorites": {
278
+ "movie": movie,
279
+ "movie_reason": movie_reason,
280
+ "show": show,
281
+ "show_reason": show_reason,
282
+ "book": book,
283
+ "book_reason": book_reason,
284
+ "character": character,
285
+ "character_reason": character_reason
286
+ },
287
+ "blog": blog,
288
+ "goals": goals,
289
+ "study_preferences": study_preferences,
290
+ "last_updated": datetime.now().isoformat(),
291
+ "security": {
292
+ "name_hash": hash_sensitive_data(name),
293
+ "interests_hash": hash_sensitive_data(interests)
294
+ }
295
  }
296
 
297
+ # Save to file
298
  os.makedirs("student_profiles", exist_ok=True)
299
+ filename = f"{name.replace(' ', '_')}_profile.json"
300
+ filepath = os.path.join("student_profiles", filename)
301
+
302
+ with open(filepath, "w") as f:
303
+ json.dump(profile_data, f, indent=2)
304
+
305
+ return f"Profile saved successfully as {filename}"
306
 
307
+ def load_profile(profile_name: str = None) -> Optional[Dict]:
308
+ """Load student profile with error handling"""
309
+ if not os.path.exists("student_profiles"):
310
+ return None
311
+
312
+ if profile_name is None:
313
+ # Load the first profile if none specified
314
+ files = [f for f in os.listdir("student_profiles") if f.endswith('.json')]
315
+ if not files:
316
+ return None
317
+ filepath = os.path.join("student_profiles", files[0])
318
+ else:
319
+ # Load specific profile
320
+ filename = f"{profile_name.replace(' ', '_')}_profile.json"
321
+ filepath = os.path.join("student_profiles", filename)
322
+
323
+ try:
324
+ with open(filepath, "r") as f:
325
+ return json.load(f)
326
+ except (FileNotFoundError, json.JSONDecodeError) as e:
327
+ print(f"Error loading profile: {e}")
328
+ return None
329
 
330
+ def transcript_display(transcript_dict: dict) -> str:
331
+ """Format transcript data for display"""
332
  if not transcript_dict or "courses" not in transcript_dict:
333
  return "No course information available"
334
 
 
355
 
356
  return display
357
 
358
+ def generate_profile_summary(profile: dict) -> str:
359
+ """Generate markdown summary of profile"""
 
 
 
 
 
 
 
 
 
 
360
  if not profile:
361
+ return "No profile data available"
362
+
363
+ name = profile.get("name", "Unknown")
364
+ age = profile.get("age", "Unknown")
365
+ interests = profile.get("interests", "Not specified")
366
+ learning_style = profile.get("learning_style", "Not determined")
367
+ favorites = profile.get("favorites", {})
368
+ blog = profile.get("blog", "")
369
+ goals = profile.get("goals", "")
370
+ study_preferences = profile.get("study_preferences", "")
371
+
372
+ markdown = f"""## Student Profile: {name}
373
+ **Age:** {age}
374
+ **Interests:** {interests}
375
+ **Learning Style:** {learning_style}
376
+
377
+ ### Academic Information
378
+ {transcript_display(profile.get("transcript", {}))}
379
+
380
+ ### Goals
381
+ {goals if goals else "_No goals specified_"}
382
+
383
+ ### Study Preferences
384
+ {study_preferences if study_preferences else "_No study preferences specified_"}
385
+
386
+ ### Favorites
387
+ - **Movie:** {favorites.get('movie', 'Not specified')} ({favorites.get('movie_reason', 'No reason given')})
388
+ - **TV Show:** {favorites.get('show', 'Not specified')} ({favorites.get('show_reason', 'No reason given')})
389
+ - **Book:** {favorites.get('book', 'Not specified')} ({favorites.get('book_reason', 'No reason given')})
390
+ - **Character:** {favorites.get('character', 'Not specified')} ({favorites.get('character_reason', 'No reason given')})
391
+
392
+ ### Personal Blog
393
+ {blog if blog else "_No blog provided_"}
394
+ """
395
+ return markdown
396
+
397
+ # ========== ENHANCED AI TEACHING ASSISTANT ==========
398
+ class TeachingAssistant:
399
+ def __init__(self):
400
+ self.conversation_history = []
401
+ self.current_profile = None
402
+
403
+ def load_profile(self, profile_name: str = None) -> bool:
404
+ """Load a student profile"""
405
+ self.current_profile = load_profile(profile_name)
406
+ if self.current_profile:
407
+ self.conversation_history.append(
408
+ (f"System: Loaded profile for {self.current_profile.get('name', 'unknown student')}", None)
409
+ )
410
+ return True
411
+ return False
412
+
413
+ def generate_response(self, message: str, history: List[tuple]) -> str:
414
+ """Generate response based on message and history"""
415
+ # Add to conversation history
416
+ self.conversation_history.append((f"Student: {message}", None))
417
+
418
+ if not self.current_profile:
419
+ return "Please complete and save your profile first using the previous tabs."
420
+
421
+ # Get profile data
422
+ name = self.current_profile.get("name", "")
423
+ learning_style = self.current_profile.get("learning_style", "")
424
+ grade_level = self.current_profile.get("transcript", {}).get("grade_level", "unknown")
425
+ gpa = self.current_profile.get("transcript", {}).get("gpa", {})
426
+ interests = self.current_profile.get("interests", "")
427
+ courses = self.current_profile.get("transcript", {}).get("courses", {})
428
+ goals = self.current_profile.get("goals", "")
429
+ study_preferences = self.current_profile.get("study_preferences", "")
430
+
431
+ # Contextual understanding
432
+ message_lower = message.lower()
433
+
434
+ # Greetings
435
+ if any(greet in message_lower for greet in ["hi", "hello", "hey"]):
436
+ return f"Hello {name}! How can I help you with your learning today?"
437
+
438
+ # Study help
439
+ elif any(word in message_lower for word in ["study", "learn", "prepare", "exam"]):
440
+ return self._generate_study_tips(learning_style, courses, study_preferences)
441
+
442
+ # Grade help
443
+ elif any(word in message_lower for word in ["grade", "gpa", "score"]):
444
+ return self._generate_grade_info(gpa, grade_level)
445
+
446
+ # Course help
447
+ elif any(word in message_lower for word in ["course", "class", "schedule", "transcript"]):
448
+ return self._generate_course_info(courses)
449
+
450
+ # Goal tracking
451
+ elif any(word in message_lower for word in ["goal", "target", "objective"]):
452
+ return self._handle_goals(message, goals)
453
+
454
+ # Resource recommendations
455
+ elif any(word in message_lower for word in ["resource", "material", "book", "video"]):
456
+ return self._recommend_resources(interests, learning_style)
457
+
458
+ # General help
459
+ elif "help" in message_lower:
460
+ return self._generate_help_message()
461
+
462
+ # Unknown query
463
+ else:
464
+ return ("I'm your personalized teaching assistant. I can help with:\n"
465
+ "- Study strategies based on your learning style\n"
466
+ "- Academic performance analysis\n"
467
+ "- Course planning and recommendations\n"
468
+ "- Goal setting and tracking\n\n"
469
+ "Try asking about how to study for your classes or about your academic progress!")
470
+
471
+ def _generate_study_tips(self, learning_style: str, courses: dict, study_preferences: str) -> str:
472
+ """Generate personalized study tips"""
473
+ response = "Here are personalized study recommendations:\n\n"
474
+
475
+ # Learning style based tips
476
  if "Visual" in learning_style:
477
+ response += ("**Visual Learner Tips:**\n"
478
+ "- Create colorful mind maps\n"
479
+ "- Use diagrams and charts\n"
480
+ "- Watch educational videos\n"
481
+ "- Highlight key information\n\n")
482
+ if "Auditory" in learning_style:
483
+ response += ("**Auditory Learner Tips:**\n"
484
+ "- Record and listen to lectures\n"
485
+ "- Participate in study groups\n"
486
+ "- Explain concepts out loud\n"
487
+ "- Use mnemonic devices\n\n")
488
+ if "Reading/Writing" in learning_style:
489
+ response += ("**Reading/Writing Learner Tips:**\n"
490
+ "- Write detailed notes\n"
491
+ "- Create summaries\n"
492
+ "- Read additional materials\n"
493
+ "- Make lists and outlines\n\n")
494
+ if "Kinesthetic" in learning_style:
495
+ response += ("**Kinesthetic Learner Tips:**\n"
496
+ "- Use hands-on activities\n"
497
+ "- Take movement breaks\n"
498
+ "- Create physical models\n"
499
+ "- Study while walking\n\n")
500
+
501
+ # Course-specific tips
502
+ if courses:
503
+ response += "\n**Course-Specific Suggestions:**\n"
504
+ for grade, course_list in courses.items():
505
+ for course in course_list:
506
+ course_name = course.get('name', '')
507
+ if 'math' in course_name.lower():
508
+ response += f"- For {course_name}: Practice problems daily\n"
509
+ elif 'science' in course_name.lower():
510
+ response += f"- For {course_name}: Focus on concepts and applications\n"
511
+ elif 'history' in course_name.lower():
512
+ response += f"- For {course_name}: Create timelines and context maps\n"
513
+ elif 'english' in course_name.lower():
514
+ response += f"- For {course_name}: Read actively and annotate texts\n"
515
+
516
+ # Study preferences
517
+ if study_preferences:
518
+ response += f"\n**Your Study Preferences:**\n{study_preferences}\n"
519
+
520
+ # General tips
521
+ response += ("\n**General Study Strategies:**\n"
522
+ "- Use the Pomodoro technique (25 min study, 5 min break)\n"
523
+ "- Space out your study sessions\n"
524
+ "- Test yourself regularly\n"
525
+ "- Teach concepts to someone else\n")
526
+
527
+ return response
528
+
529
+ def _generate_grade_info(self, gpa: dict, grade_level: str) -> str:
530
+ """Generate grade information response"""
531
+ response = (f"Your Academic Performance Summary:\n"
532
+ f"- Current Grade Level: {grade_level}\n"
533
+ f"- Unweighted GPA: {gpa.get('unweighted', 'N/A')}\n"
534
+ f"- Weighted GPA: {gpa.get('weighted', 'N/A')}\n\n")
535
+
536
+ # Add improvement suggestions
537
+ unweighted = float(gpa.get('unweighted', 0)) if gpa.get('unweighted', 'N/A') != 'N/A' else 0
538
+ if unweighted < 2.0:
539
+ response += ("**Recommendations for Improvement:**\n"
540
+ "- Meet with teachers to identify weak areas\n"
541
+ "- Establish a regular study schedule\n"
542
+ "- Focus on foundational concepts\n")
543
+ elif unweighted < 3.0:
544
+ response += ("**Recommendations for Enhancement:**\n"
545
+ "- Identify your strongest subjects to build confidence\n"
546
+ "- Set specific grade improvement goals\n"
547
+ "- Develop better study habits\n")
548
+ elif unweighted < 3.5:
549
+ response += ("**Recommendations for Advancement:**\n"
550
+ "- Challenge yourself with honors/AP courses\n"
551
+ "- Develop deeper understanding in your strongest areas\n"
552
+ "- Focus on consistent performance\n")
553
  else:
554
+ response += ("**Recommendations for Excellence:**\n"
555
+ "- Pursue advanced coursework\n"
556
+ "- Develop independent research projects\n"
557
+ "- Mentor other students to reinforce your knowledge\n")
558
 
559
  return response
560
 
561
+ def _generate_course_info(self, courses: dict) -> str:
562
+ """Generate course information response"""
563
+ if not courses:
564
+ return "No course information available in your profile."
565
+
566
+ response = "Your Course History:\n"
 
 
 
 
 
 
 
 
 
 
 
567
  for grade in sorted(courses.keys(), key=int):
568
+ response += f"\n**Grade {grade}:**\n"
569
  for course in courses[grade]:
570
+ response += f"- {course.get('name', 'Unknown')}"
571
  if 'grade' in course:
572
+ response += f" (Grade: {course.get('grade', '')})"
573
  response += "\n"
574
+
575
+ # Add recommendations
576
+ response += "\n**Course Recommendations:**\n"
577
+ highest_grade = max(courses.keys(), key=int) if courses else "0"
578
+
579
+ if highest_grade == "09":
580
+ response += "- Consider exploring different subjects to find your interests\n"
581
+ response += "- Build strong foundational skills in math and language arts\n"
582
+ elif highest_grade == "10":
583
+ response += "- Start focusing on your academic strengths\n"
584
+ response += "- Consider honors or AP courses in your strong subjects\n"
585
+ elif highest_grade == "11":
586
+ response += "- Focus on college preparatory courses\n"
587
+ response += "- Consider AP or dual enrollment courses\n"
588
+ elif highest_grade == "12":
589
+ response += "- Complete any remaining graduation requirements\n"
590
+ response += "- Consider advanced courses in your intended major\n"
591
+
592
  return response
593
 
594
+ def _handle_goals(self, message: str, current_goals: str) -> str:
595
+ """Handle goal-related queries"""
596
+ if "set" in message.lower() or "new" in message.lower():
597
+ return ("To set new goals, please update your profile with your academic goals. "
598
+ "You can include:\n"
599
+ "- Short-term goals (weekly/monthly)\n"
600
+ "- Long-term goals (semester/yearly)\n"
601
+ "- Career or college preparation goals\n")
602
+ elif current_goals:
603
+ return f"Your current goals:\n{current_goals}\n\nWould you like to update them?"
604
+ else:
605
+ return ("You haven't set any goals yet. Setting clear academic goals can help you "
606
+ "stay focused and motivated. Would you like to set some goals now?")
607
 
608
+ def _recommend_resources(self, interests: str, learning_style: str) -> str:
609
+ """Recommend learning resources"""
610
+ response = "Based on your profile, here are some resource recommendations:\n\n"
611
+
612
+ # Interest-based recommendations
613
+ if "science" in interests.lower():
614
+ response += ("**Science Resources:**\n"
615
+ "- Khan Academy Science courses\n"
616
+ "- Crash Course YouTube channel\n"
617
+ "- Science Journal app for experiments\n\n")
618
+ if "math" in interests.lower():
619
+ response += ("**Math Resources:**\n"
620
+ "- Brilliant.org interactive math\n"
621
+ "- 3Blue1Brown YouTube channel\n"
622
+ "- Wolfram Alpha for problem solving\n\n")
623
+ if "history" in interests.lower():
624
+ response += ("**History Resources:**\n"
625
+ "- Hardcore History podcast\n"
626
+ "- Timeline apps for historical events\n"
627
+ "- Historical fiction books\n\n")
628
+ if "art" in interests.lower() or "music" in interests.lower():
629
+ response += ("**Arts Resources:**\n"
630
+ "- Skillshare art classes\n"
631
+ "- Google Arts & Culture app\n"
632
+ "- Local museum virtual tours\n\n")
633
+
634
+ # Learning style based recommendations
635
+ if "Visual" in learning_style:
636
+ response += ("**Visual Learning Resources:**\n"
637
+ "- MindMeister for mind mapping\n"
638
+ "- Canva for creating visual notes\n"
639
+ "- YouTube educational channels\n\n")
640
+ if "Auditory" in learning_style:
641
+ response += ("**Auditory Learning Resources:**\n"
642
+ "- Audible for audiobooks\n"
643
+ "- Podcasts like TED Talks Education\n"
644
+ "- Text-to-speech tools\n\n")
645
+ if "Reading/Writing" in learning_style:
646
+ response += ("**Reading/Writing Resources:**\n"
647
+ "- Evernote for note-taking\n"
648
+ "- Project Gutenberg for free books\n"
649
+ "- Grammarly for writing help\n\n")
650
+ if "Kinesthetic" in learning_style:
651
+ response += ("**Kinesthetic Learning Resources:**\n"
652
+ "- Labster virtual labs\n"
653
+ "- DIY science experiment kits\n"
654
+ "- Standing desk or exercise ball chair\n\n")
655
+
656
+ return response
657
+
658
+ def _generate_help_message(self) -> str:
659
+ """Generate help message with capabilities"""
660
+ return ("""I can help you with:
661
+ 1. **Study Strategies** - Get personalized study tips based on your learning style
662
+ 2. **Academic Performance** - Check your GPA and get improvement suggestions
663
+ 3. **Course Planning** - View your course history and get recommendations
664
+ 4. **Goal Setting** - Set and track your academic goals
665
+ 5. **Resource Recommendations** - Get suggested learning materials
666
+
667
+ Try asking:
668
+ - "How should I study for my math class?"
669
+ - "What's my current GPA?"
670
+ - "What courses should I take next year?"
671
+ - "Can you recommend some science resources?"
672
+ - "Help me set some academic goals"
673
+ """)
674
+
675
+ # Initialize teaching assistant
676
+ assistant = TeachingAssistant()
677
 
678
  # ========== GRADIO INTERFACE ==========
679
+ with gr.Blocks(title="Personalized Learning Assistant", theme=gr.themes.Soft()) as app:
680
+ gr.Markdown("# πŸŽ“ Personalized Learning Assistant")
681
+ gr.Markdown("This tool helps students understand their learning style, track academic progress, and get personalized study recommendations.")
682
+
683
+ with gr.Tab("πŸ“„ Step 1: Upload Transcript"):
684
+ gr.Markdown("### Upload your academic transcript")
685
+ gr.Markdown("For best results, upload a PDF of your official transcript.")
686
+ with gr.Row():
687
+ with gr.Column():
688
+ transcript_file = gr.File(
689
+ label="Transcript file",
690
+ file_types=[".pdf"],
691
+ info="PDF format recommended"
692
+ )
693
+ clear_btn = gr.Button("Clear")
694
+ with gr.Column():
695
+ transcript_output = gr.Textbox(
696
+ label="Transcript Results",
697
+ lines=20,
698
+ interactive=False
699
+ )
700
+ transcript_data = gr.State()
701
+
702
  transcript_file.change(
703
  fn=parse_transcript,
704
  inputs=transcript_file,
705
  outputs=[transcript_output, transcript_data]
706
  )
707
+ clear_btn.click(
708
+ lambda: [None, "", None],
709
+ outputs=[transcript_file, transcript_output, transcript_data]
710
+ )
711
+
712
+ with gr.Tab("πŸ“ Step 2: Learning Style Quiz"):
713
+ gr.Markdown("### Discover Your Learning Style")
714
+ gr.Markdown("Complete this 20-question quiz to understand how you learn best.")
715
+
716
+ with gr.Accordion("About Learning Styles", open=False):
717
+ gr.Markdown("""
718
+ **Visual Learners** prefer using images, diagrams, and spatial understanding.
719
+ **Auditory Learners** learn best through listening and speaking.
720
+ **Reading/Writing Learners** prefer information displayed as words.
721
+ **Kinesthetic Learners** learn through movement and hands-on activities.
722
+ """)
723
+
724
  quiz_components = []
725
+ with gr.Column():
726
+ for i, (question, options) in enumerate(zip(learning_style_questions, learning_style_options)):
727
+ quiz_components.append(
728
+ gr.Radio(
729
+ options,
730
+ label=f"{i+1}. {question}",
731
+ interactive=True
732
+ )
733
+ )
734
+
735
+ with gr.Row():
736
+ submit_quiz = gr.Button("Submit Quiz", variant="primary")
737
+ reset_quiz = gr.Button("Reset Quiz")
738
+
739
+ learning_output = gr.Textbox(
740
+ label="Your Learning Style Results",
741
+ lines=15,
742
+ interactive=False
743
+ )
744
 
745
+ submit_quiz.click(
 
746
  fn=learning_style_quiz,
747
  inputs=quiz_components,
748
  outputs=learning_output
749
  )
750
+ reset_quiz.click(
751
+ lambda: [None]*len(quiz_components),
752
+ outputs=quiz_components
753
+ )
754
+
755
+ with gr.Tab("πŸ‘€ Step 3: Personal Profile"):
756
+ gr.Markdown("### Create Your Personal Profile")
757
+ gr.Markdown("This information helps personalize your learning experience.")
758
+
759
+ with gr.Row():
760
+ with gr.Column():
761
+ name = gr.Textbox(label="Full Name", placeholder="Enter your name")
762
+ age = gr.Number(label="Age", precision=0, minimum=10, maximum=25)
763
+ interests = gr.Textbox(
764
+ label="Interests/Hobbies",
765
+ placeholder="e.g., Science, Music, Sports"
766
+ )
767
+ goals = gr.Textbox(
768
+ label="Academic Goals",
769
+ placeholder="What do you want to achieve?",
770
+ lines=3
771
+ )
772
+ study_preferences = gr.Textbox(
773
+ label="Study Preferences",
774
+ placeholder="When/where/how do you prefer to study?",
775
+ lines=3
776
+ )
777
+
778
+ with gr.Column():
779
+ gr.Markdown("#### Favorites")
780
+ movie = gr.Textbox(label="Favorite Movie")
781
+ movie_reason = gr.Textbox(label="Why do you like it?")
782
+ show = gr.Textbox(label="Favorite TV Show")
783
+ show_reason = gr.Textbox(label="Why do you like it?")
784
+ book = gr.Textbox(label="Favorite Book")
785
+ book_reason = gr.Textbox(label="Why do you like it?")
786
+ character = gr.Textbox(label="Favorite Character (book/movie/show)")
787
+ character_reason = gr.Textbox(label="Why do you like them?")
788
+
789
+ with gr.Row():
790
+ blog_checkbox = gr.Checkbox(label="Include a personal blog/journal entry?", value=False)
791
+ blog_text = gr.Textbox(
792
+ label="Your Blog/Journal",
793
+ visible=False,
794
+ lines=5,
795
+ placeholder="Write about your learning experiences, challenges, or thoughts..."
796
+ )
797
+
798
+ blog_checkbox.change(
799
+ lambda x: gr.update(visible=x),
800
+ inputs=blog_checkbox,
801
+ outputs=blog_text
802
+ )
803
+
804
+ with gr.Tab("πŸ’Ύ Step 4: Save & Review"):
805
+ gr.Markdown("### Review and Save Your Profile")
806
+
807
+ with gr.Row():
808
+ profile_selector = gr.Dropdown(
809
+ label="Select Profile to Load",
810
+ choices=get_profile_list(),
811
+ interactive=True,
812
+ allow_custom_value=False
813
+ )
814
+ refresh_profiles = gr.Button("πŸ”„ Refresh List")
815
+
816
+ with gr.Row():
817
+ save_btn = gr.Button("πŸ’Ύ Save Profile", variant="primary")
818
+ load_btn = gr.Button("πŸ“‚ Load Profile")
819
+ clear_btn = gr.Button("🧹 Clear Form")
820
+
821
  output_summary = gr.Markdown()
822
+
823
+ # Profile management functions
824
+ refresh_profiles.click(
825
+ lambda: gr.update(choices=get_profile_list()),
826
+ outputs=profile_selector
827
+ )
828
+
829
  save_btn.click(
830
  fn=save_profile,
831
+ inputs=[
832
+ name, age, interests, transcript_data, learning_output,
833
+ movie, movie_reason, show, show_reason,
834
+ book, book_reason, character, character_reason,
835
+ blog_text, goals, study_preferences
836
+ ],
837
  outputs=output_summary
838
+ ).then(
839
+ lambda: gr.update(choices=get_profile_list()),
840
+ outputs=profile_selector
841
  )
842
+
843
+ load_btn.click(
844
+ fn=lambda name: generate_profile_summary(load_profile(name)),
845
+ inputs=profile_selector,
846
+ outputs=output_summary
847
+ )
848
+
849
+ clear_btn.click(
850
+ lambda: [""]*15 + [None, False, ""],
851
+ outputs=[
852
+ name, age, interests, goals, study_preferences,
853
+ movie, movie_reason, show, show_reason,
854
+ book, book_reason, character, character_reason,
855
+ blog_text, blog_checkbox, output_summary
856
+ ]
857
+ )
858
+
859
  with gr.Tab("πŸ€– AI Teaching Assistant"):
860
  gr.Markdown("## Your Personalized Learning Assistant")
861
+ gr.Markdown("Chat with your AI assistant to get personalized learning advice based on your profile.")
862
+
863
+ # Profile selection for assistant
864
+ with gr.Row():
865
+ assistant_profile_selector = gr.Dropdown(
866
+ label="Select Your Profile",
867
+ choices=get_profile_list(),
868
+ interactive=True
869
+ )
870
+ load_assistant_profile = gr.Button("Load Profile")
871
+ refresh_assistant_profiles = gr.Button("πŸ”„ Refresh")
872
+
873
+ # Chat interface
874
  chatbot = gr.ChatInterface(
875
+ fn=assistant.generate_response,
876
  examples=[
877
+ "How should I study for my next math test?",
878
+ "What's my current GPA?",
879
  "Show me my course history",
880
+ "Recommend some science resources",
881
+ "Help me set academic goals"
882
+ ],
883
+ title="Chat with Your Teaching Assistant",
884
+ retry_btn=None,
885
+ undo_btn=None,
886
+ clear_btn="Clear Chat"
887
+ )
888
+
889
+ # Profile management for assistant
890
+ load_assistant_profile.click(
891
+ fn=lambda name: assistant.load_profile(name) or f"Loaded profile for {name}",
892
+ inputs=assistant_profile_selector,
893
+ outputs=chatbot.chatbot
894
+ )
895
+
896
+ refresh_assistant_profiles.click(
897
+ lambda: gr.update(choices=get_profile_list()),
898
+ outputs=assistant_profile_selector
899
  )
900
 
901
  if __name__ == "__main__":