Dannyar608 commited on
Commit
3e64737
·
verified ·
1 Parent(s): b57ed91

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +265 -289
app.py CHANGED
@@ -1,293 +1,154 @@
1
- # ========== DEPENDENCY MANAGEMENT ==========
2
- import sys
3
- import subprocess
4
- import importlib
5
- from datetime import datetime
6
- import re
7
- import os
8
- import json
9
- import pdfplumber
10
- from collections import defaultdict
11
- from typing import List, Dict, Union
12
  import gradio as gr
 
 
 
 
13
  from PyPDF2 import PdfReader
 
14
  from transformers import pipeline
15
 
16
- required_packages = {
17
- 'gradio': 'gradio>=3.0',
18
- 'pandas': 'pandas',
19
- 'PyPDF2': 'PyPDF2',
20
- 'transformers': 'transformers',
21
- 'pdfplumber': 'pdfplumber'
22
- }
23
 
24
- def check_and_install_packages():
25
- missing_packages = []
26
- for import_name, pkg_name in required_packages.items():
27
- try:
28
- importlib.import_module(import_name)
29
- except ImportError:
30
- missing_packages.append(pkg_name)
31
 
32
- if missing_packages:
33
- print(f"Missing packages: {', '.join(missing_packages)}")
34
- subprocess.check_call([sys.executable, "-m", "pip", "install", *missing_packages])
35
-
36
- check_and_install_packages()
37
-
38
- # ========== TRANSCRIPT PARSING ==========
39
- class UniversalTranscriptParser:
40
- def __init__(self):
41
- self.patterns = {
42
- 'miami_dade': self._compile_miami_dade_patterns(),
43
- 'homeschool': self._compile_homeschool_patterns(),
44
- 'doral_academy': self._compile_doral_academy_patterns()
45
- }
46
-
47
- self.grade_level_map = {
48
- '09': '9th Grade', '10': '10th Grade', '11': '11th Grade', '12': '12th Grade',
49
- '07': '7th Grade', '08': '8th Grade', 'MA': 'Middle School'
50
- }
51
-
52
- def parse_transcript(self, text: str) -> Dict[str, Union[Dict, List[Dict]]]:
53
- transcript_type = self._identify_transcript_type(text)
54
-
55
- if transcript_type == 'homeschool':
56
- return self._parse_homeschool(text)
57
- elif transcript_type == 'doral_academy':
58
- return self._parse_doral_academy(text)
59
- else:
60
- return self._parse_miami_dade(text)
61
 
62
- def _identify_transcript_type(self, text: str) -> str:
63
- if re.search(r'Sample OFFICIAL HIGH SCHOOL TRANSCRIPT', text):
64
- return 'homeschool'
65
- elif re.search(r'DORAL ACADEMY HIGH SCHOOL', text):
66
- return 'doral_academy'
67
- return 'miami_dade'
68
 
69
- def _parse_homeschool(self, text: str) -> Dict[str, Union[Dict, List[Dict]]]:
70
- courses = []
71
- current_grade = None
72
- current_year = None
73
 
74
- student_info = {}
75
- name_match = re.search(r'Student Name:\s*(.+)\s*SSN:', text)
76
- if name_match:
77
- student_info['name'] = name_match.group(1).strip()
 
 
78
 
79
- for line in text.split('\n'):
80
- grade_match = re.match(r'^\|?\s*(\d+th Grade)\s*\|.*(\d{4}-\d{4})', line)
81
- if grade_match:
82
- current_grade = grade_match.group(1)
83
- current_year = grade_match.group(2)
84
- continue
85
-
86
- course_match = re.match(
87
- r'^\|?\s*([^\|]+?)\s*\|\s*([A-Z][+*]?)\s*\|\s*([^\|]+)\s*\|\s*(\d+\.?\d*)\s*\|\s*(\d+)',
88
- line
89
- )
90
-
91
- if course_match and current_grade:
92
- course_name = course_match.group(1).strip()
93
- course_name = re.sub(r'^\|?\s*', '', course_name)
94
-
95
- courses.append({
96
- 'name': course_name,
97
- 'grade_level': current_grade,
98
- 'school_year': current_year,
99
- 'grade': course_match.group(2),
100
- 'credit_type': course_match.group(3).strip(),
101
- 'credits': float(course_match.group(4)),
102
- 'quality_points': int(course_match.group(5)),
103
- 'transcript_type': 'homeschool'
104
- })
105
-
106
- gpa_data = self._extract_gpa_data(text)
107
- return {
108
- 'student_info': student_info,
109
- 'courses': {'All': courses},
110
- 'gpa': gpa_data,
111
- 'grade_level': current_grade.replace('th Grade', '') if current_grade else "Unknown"
112
  }
113
-
114
- def _parse_doral_academy(self, text: str) -> Dict[str, Union[Dict, List[Dict]]]:
115
- courses = []
116
- student_info = {}
117
- name_match = re.search(r'LEGAL NAME:\s*([^\n]+)', text)
118
- if name_match:
119
- student_info['name'] = name_match.group(1).strip()
120
-
121
- year_pattern = re.compile(r'YEAR:\s*(\d{4}-\d{4})\s*GRADE LEVEL:\s*(\d{2})', re.MULTILINE)
122
- year_matches = year_pattern.finditer(text)
123
-
124
- grade_year_map = {}
125
- for match in year_matches:
126
- grade_year_map[match.group(2)] = match.group(1)
127
 
128
- course_pattern = re.compile(
129
- r'(\d)\s+(\d{7})\s+([^\n]+?)\s+([A-Z]{2})\s+([A-Z])\s+([A-Z])\s+([A-Z])\s+(\d\.\d{2})\s+(\d\.\d{2})',
130
- re.MULTILINE
131
- )
132
-
133
- courses_by_grade = defaultdict(list)
134
- for match in course_pattern.finditer(text):
135
- grade_level_num = match.group(1)
136
- grade_level = self.grade_level_map.get(grade_level_num, f"Grade {grade_level_num}")
137
- school_year = grade_year_map.get(grade_level_num, "Unknown")
138
-
139
- course_info = {
140
- 'course_code': match.group(2),
141
- 'name': match.group(3).strip(),
142
- 'subject_area': match.group(4),
143
- 'grade': match.group(5),
144
- 'inclusion_status': match.group(6),
145
- 'credit_status': match.group(7),
146
- 'credits_attempted': float(match.group(8)),
147
- 'credits': float(match.group(9)),
148
- 'grade_level': grade_level,
149
- 'school_year': school_year,
150
- 'transcript_type': 'doral_academy'
151
- }
152
-
153
- courses_by_grade[grade_level_num].append(course_info)
154
 
155
- gpa_data = self._extract_gpa_data(text)
156
- grade_level = "12" if re.search(r'GRADE LEVEL:\s*12', text) else "Unknown"
157
-
158
- return {
159
- 'student_info': student_info,
160
- 'courses': dict(courses_by_grade),
161
- 'gpa': gpa_data,
162
- 'grade_level': grade_level
163
- }
164
 
165
- def _parse_miami_dade(self, text: str) -> Dict[str, Union[Dict, List[Dict]]]:
166
- courses = []
167
- courses_by_grade = defaultdict(list)
168
-
169
- student_info = {}
170
- name_match = re.search(r'0783977 - ([^,]+),\s*([^\n]+)', text)
171
- if name_match:
172
- student_info['name'] = f"{name_match.group(2)} {name_match.group(1)}"
173
-
174
- course_pattern = re.compile(
175
- r'([A-Z]-[A-Za-z\s&]+)\s*\|\s*(\d{4}-\d{4})\s*\|\s*(\d{2})\s*\|\s*([A-Z0-9]+)\s*\|\s*([^\|]+)\s*\|\s*([^\|]+)\s*\|\s*([^\|]+)\s*\|\s*([A-Z]?)\s*\|\s*([A-Z]?)\s*\|\s*([^\|]+)',
176
- re.MULTILINE
177
- )
178
-
179
- for match in course_pattern.finditer(text):
180
- grade_level = self.grade_level_map.get(match.group(3), match.group(3))
181
- credits = match.group(10).strip()
182
-
183
- course_info = {
184
- 'requirement_category': match.group(1).strip(),
185
- 'school_year': match.group(2),
186
- 'grade_level': grade_level if isinstance(grade_level, str) else f"Grade {match.group(3)}",
187
- 'course_code': match.group(4).strip(),
188
- 'name': match.group(5).strip(),
189
- 'term': match.group(6).strip(),
190
- 'district_number': match.group(7).strip(),
191
- 'grade': match.group(8),
192
- 'inclusion_status': match.group(9),
193
- 'credits': 0.0 if 'inProgress' in credits else float(credits.replace(' ', '')),
194
- 'transcript_type': 'miami_dade'
195
- }
196
-
197
- courses_by_grade[match.group(3)].append(course_info)
198
-
199
- gpa_data = self._extract_gpa_data(text)
200
- grade_level = re.search(r'Current Grade:\s*(\d+)', text).group(1) if re.search(r'Current Grade:\s*(\d+)', text) else "Unknown"
201
-
202
- return {
203
- 'student_info': student_info,
204
- 'courses': dict(courses_by_grade),
205
- 'gpa': gpa_data,
206
- 'grade_level': grade_level
207
- }
208
 
209
- def _extract_gpa_data(self, text: str) -> Dict[str, str]:
210
- """Improved GPA extraction with multiple pattern matching"""
211
- gpa_data = {}
212
-
213
- # Weighted GPA patterns
214
- weighted_patterns = [
215
- r'Weighted GPA\s*:\s*([\d\.]+)',
216
- r'Weighted GPA\s*([\d\.]+)',
217
- r'GPA WTD\s*:\s*([\d\.]+)',
218
- r'Weighted\s*:\s*([\d\.]+)'
219
- ]
220
-
221
- # Unweighted GPA patterns
222
- unweighted_patterns = [
223
- r'Un-weighted GPA\s*:\s*([\d\.]+)',
224
- r'Unweighted GPA\s*([\d\.]+)',
225
- r'GPA UNWTD\s*:\s*([\d\.]+)',
226
- r'Unweighted\s*:\s*([\d\.]+)'
227
- ]
228
-
229
- # Try all weighted patterns
230
- for pattern in weighted_patterns:
231
- match = re.search(pattern, text, re.IGNORECASE)
232
- if match:
233
- gpa_data['weighted'] = match.group(1)
234
- break
235
-
236
- # Try all unweighted patterns
237
- for pattern in unweighted_patterns:
238
- match = re.search(pattern, text, re.IGNORECASE)
239
- if match:
240
- gpa_data['unweighted'] = match.group(1)
241
- break
242
-
243
- # Fallback to cumulative GPA if not found
244
- if not gpa_data:
245
- cumulative_match = re.search(r'Cumulative GPA\s*:\s*([\d\.]+)', text, re.IGNORECASE)
246
- if cumulative_match:
247
- gpa_data['weighted'] = cumulative_match.group(1)
248
- gpa_data['unweighted'] = cumulative_match.group(1)
249
-
250
- return gpa_data
251
-
252
- # ========== TRANSCRIPT PROCESSING ==========
253
  def parse_transcript(file):
254
- parser = UniversalTranscriptParser()
255
-
256
  if file.name.endswith('.pdf'):
257
  text = ''
258
- with pdfplumber.open(file.name) as pdf:
259
- for page in pdf.pages:
260
- text += page.extract_text() or '' + '\n'
261
 
262
- parsed_data = parser.parse_transcript(text)
 
 
 
 
 
 
 
 
263
 
264
- # Enhanced GPA display
265
- gpa_data = parsed_data.get('gpa', {})
266
- weighted_gpa = gpa_data.get('weighted', 'Not Found (Please check transcript)')
267
- unweighted_gpa = gpa_data.get('unweighted', 'Not Found (Please check transcript)')
268
 
269
- output_text = "=== TRANSCRIPT ANALYSIS RESULTS ===\n\n"
270
- output_text += "GPA INFORMATION:\n"
271
- output_text += f"🔹 Weighted GPA: {weighted_gpa}\n"
272
- output_text += f"🔹 Unweighted GPA: {unweighted_gpa}\n\n"
 
 
273
 
274
- if 'Not Found' in weighted_gpa or 'Not Found' in unweighted_gpa:
275
- output_text += "NOTE: Could not automatically locate GPA information.\n"
276
- output_text += "Please check your transcript for GPA details and enter them manually if needed.\n"
 
 
 
 
 
 
 
277
 
278
- return output_text, parsed_data
 
 
 
 
279
  else:
280
  return "Unsupported file format (PDF only for transcript parsing)", None
281
 
282
  # ========== LEARNING STYLE QUIZ ==========
283
  learning_style_questions = [
284
  "When you study for a test, you prefer to:",
285
- # ... [rest of your questions] ...
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
286
  ]
287
 
288
  learning_style_options = [
289
  ["Read the textbook (Reading/Writing)", "Listen to lectures (Auditory)", "Use diagrams/charts (Visual)", "Practice problems (Kinesthetic)"],
290
- # ... [rest of your options] ...
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
291
  ]
292
 
293
  def learning_style_quiz(*answers):
@@ -311,19 +172,49 @@ def learning_style_quiz(*answers):
311
  max_score = max(scores.values())
312
  total_questions = len(learning_style_questions)
313
 
 
314
  percentages = {style: (score/total_questions)*100 for style, score in scores.items()}
 
 
315
  sorted_styles = sorted(scores.items(), key=lambda x: x[1], reverse=True)
316
 
 
317
  result = "Your Learning Style Results:\n\n"
318
  for style, score in sorted_styles:
319
  result += f"{style}: {score}/{total_questions} ({percentages[style]:.1f}%)\n"
320
 
321
  result += "\n"
 
 
322
  primary_styles = [style for style, score in scores.items() if score == max_score]
323
 
324
  if len(primary_styles) == 1:
325
  result += f"Your primary learning style is: {primary_styles[0]}\n\n"
326
- # ... [rest of your learning style tips] ...
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
327
  else:
328
  result += f"You have multiple strong learning styles: {', '.join(primary_styles)}\n\n"
329
  result += "You may benefit from combining different learning approaches.\n"
@@ -334,6 +225,7 @@ def learning_style_quiz(*answers):
334
  def save_profile(name, age, interests, transcript, learning_style,
335
  movie, movie_reason, show, show_reason,
336
  book, book_reason, character, character_reason, blog):
 
337
  age = int(age) if age else 0
338
 
339
  favorites = {
@@ -362,27 +254,49 @@ def save_profile(name, age, interests, transcript, learning_style,
362
  with open(json_path, "w") as f:
363
  json.dump(data, f, indent=2)
364
 
365
- gpa = transcript.get('gpa', {})
366
  markdown_summary = f"""### Student Profile: {name}
367
  **Age:** {age}
368
  **Interests:** {interests}
369
  **Learning Style:** {learning_style}
370
-
371
- #### GPA Information:
372
- - Weighted GPA: {gpa.get('weighted', 'Not Available')}
373
- - Unweighted GPA: {gpa.get('unweighted', 'Not Available')}
374
-
375
  #### Favorites:
376
  - Movie: {favorites['movie']} ({favorites['movie_reason']})
377
  - Show: {favorites['show']} ({favorites['show_reason']})
378
  - Book: {favorites['book']} ({favorites['book_reason']})
379
  - Character: {favorites['character']} ({favorites['character_reason']})
380
-
381
  #### Blog:
382
  {blog if blog else "_No blog provided_"}
383
  """
384
  return markdown_summary
385
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
386
  # ========== AI TEACHING ASSISTANT ==========
387
  def load_profile():
388
  if not os.path.exists("student_profiles"):
@@ -398,36 +312,97 @@ def generate_response(message, history):
398
  if not profile:
399
  return "Please complete and save your profile first using the previous tabs."
400
 
401
- transcript = profile.get("transcript", {})
402
- gpa = transcript.get("gpa", {})
 
 
 
 
403
 
404
- # When user asks about GPA
405
- if any(word in message.lower() for word in ["gpa", "grade", "weighted", "unweighted"]):
406
- response = "Your GPA Information:\n"
407
- response += f"- Weighted GPA: {gpa.get('weighted', 'Not Available')}\n"
408
- response += f"- Unweighted GPA: {gpa.get('unweighted', 'Not Available')}\n"
409
-
410
- # Add interpretation if available
411
- weighted = gpa.get('weighted')
412
- if weighted and weighted.replace('.', '').isdigit():
413
- weighted_num = float(weighted)
414
- if weighted_num >= 3.5:
415
- response += "\nExcellent GPA! You're doing great!"
416
- elif weighted_num >= 3.0:
417
- response += "\nGood GPA! Keep up the good work!"
418
- else:
419
- response += "\nConsider focusing on improving your grades."
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
420
 
421
  return response
422
 
423
- # ... [rest of your AI assistant logic] ...
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
424
 
425
  # ========== GRADIO INTERFACE ==========
426
  with gr.Blocks() as app:
427
  with gr.Tab("Step 1: Upload Transcript"):
428
- gr.Markdown("### Upload your transcript (PDF recommended)")
429
  transcript_file = gr.File(label="Transcript file", file_types=[".pdf"])
430
- transcript_output = gr.Textbox(label="Transcript Results", lines=5)
431
  transcript_data = gr.State()
432
  transcript_file.change(
433
  fn=parse_transcript,
@@ -480,9 +455,10 @@ with gr.Blocks() as app:
480
  chatbot = gr.ChatInterface(
481
  fn=generate_response,
482
  examples=[
483
- "What's my GPA?",
484
- "How should I study for my classes?",
485
- "What subjects am I taking?"
 
486
  ]
487
  )
488
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  import gradio as gr
2
+ 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:
12
+ ner_pipeline = pipeline("ner", model="dslim/bert-base-NER")
13
+ except Exception as e:
14
+ print(f"Could not load NER model: {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
27
+ r'\|?\s*(\d+)\s*' # Grade level
28
+ r'\|?\s*([A-Z0-9]+)\s*' # Course code
29
+ r'\|?\s*([^\|]+?)\s*' # Course name (captures until next pipe)
30
+ r'(?:\|\s*[^\|]*){2}' # Skip Term and DstNumber
31
+ r'\|\s*([A-FW]?)\s*' # Grade (FG column)
32
+ r'(?:\|\s*[^\|]*)' # Skip Incl column
33
+ r'\|\s*([\d\.]+|inProgress)' # Credits
34
+ )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
35
 
36
+ courses_by_grade = defaultdict(list)
 
 
 
 
 
37
 
38
+ for match in re.finditer(course_pattern, text):
39
+ year_range, grade_level, course_code, course_name, grade, credits = match.groups()
 
 
40
 
41
+ # Clean up course name
42
+ course_name = course_name.strip()
43
+ if 'DE:' in course_name:
44
+ course_name = course_name.replace('DE:', 'Dual Enrollment:')
45
+ if 'AP' in course_name:
46
+ course_name = course_name.replace('AP', 'AP ')
47
 
48
+ course_info = {
49
+ 'name': f"{course_code} {course_name}",
50
+ 'year': year_range,
51
+ 'credits': credits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
52
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
53
 
54
+ if grade and grade.strip():
55
+ course_info['grade'] = grade.strip()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
56
 
57
+ courses_by_grade[grade_level].append(course_info)
 
 
 
 
 
 
 
 
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:",
111
+ "When you learn a new skill, you prefer to:",
112
+ "When you're trying to concentrate, you:",
113
+ "When you meet new people, you remember them by:",
114
+ "When you're assembling furniture or a gadget, you:",
115
+ "When choosing a restaurant, you rely most on:",
116
+ "When you're in a waiting room, you typically:",
117
+ "When giving someone instructions, you tend to:",
118
+ "When you're trying to recall information, you:",
119
+ "When you're at a museum or exhibit, you:",
120
+ "When you're learning a new language, you prefer:",
121
+ "When you're taking notes in class, you:",
122
+ "When you're explaining something complex, you:",
123
+ "When you're at a party, you enjoy:",
124
+ "When you're trying to remember a phone number, you:",
125
+ "When you're relaxing, you prefer to:",
126
+ "When you're learning to use new software, you:",
127
+ "When you're giving a presentation, you rely on:",
128
+ "When you're solving a difficult problem, you:"
129
  ]
130
 
131
  learning_style_options = [
132
  ["Read the textbook (Reading/Writing)", "Listen to lectures (Auditory)", "Use diagrams/charts (Visual)", "Practice problems (Kinesthetic)"],
133
+ ["Look at a map (Visual)", "Have someone tell you (Auditory)", "Write down directions (Reading/Writing)", "Try walking/driving there (Kinesthetic)"],
134
+ ["Read instructions (Reading/Writing)", "Have someone show you (Visual)", "Listen to explanations (Auditory)", "Try it yourself (Kinesthetic)"],
135
+ ["Need quiet (Reading/Writing)", "Need background noise (Auditory)", "Need to move around (Kinesthetic)", "Need visual stimulation (Visual)"],
136
+ ["Their face (Visual)", "Their name (Auditory)", "What you talked about (Reading/Writing)", "What you did together (Kinesthetic)"],
137
+ ["Read the instructions carefully (Reading/Writing)", "Look at the diagrams (Visual)", "Ask someone to explain (Auditory)", "Start putting pieces together (Kinesthetic)"],
138
+ ["Online photos of the food (Visual)", "Recommendations from friends (Auditory)", "Reading the menu online (Reading/Writing)", "Remembering how it felt to eat there (Kinesthetic)"],
139
+ ["Read magazines (Reading/Writing)", "Listen to music (Auditory)", "Watch TV (Visual)", "Fidget or move around (Kinesthetic)"],
140
+ ["Write them down (Reading/Writing)", "Explain verbally (Auditory)", "Demonstrate (Visual)", "Guide them physically (Kinesthetic)"],
141
+ ["See written words in your mind (Visual)", "Hear the information in your head (Auditory)", "Write it down to remember (Reading/Writing)", "Associate it with physical actions (Kinesthetic)"],
142
+ ["Read all the descriptions (Reading/Writing)", "Listen to audio guides (Auditory)", "Look at the displays (Visual)", "Touch interactive exhibits (Kinesthetic)"],
143
+ ["Study grammar rules (Reading/Writing)", "Listen to native speakers (Auditory)", "Use flashcards with images (Visual)", "Practice conversations (Kinesthetic)"],
144
+ ["Write detailed paragraphs (Reading/Writing)", "Record the lecture (Auditory)", "Draw diagrams and charts (Visual)", "Doodle while listening (Kinesthetic)"],
145
+ ["Write detailed steps (Reading/Writing)", "Explain verbally with examples (Auditory)", "Draw diagrams (Visual)", "Use physical objects to demonstrate (Kinesthetic)"],
146
+ ["Conversations with people (Auditory)", "Watching others or the environment (Visual)", "Writing notes or texting (Reading/Writing)", "Dancing or physical activities (Kinesthetic)"],
147
+ ["See the numbers in your head (Visual)", "Say them aloud (Auditory)", "Write them down (Reading/Writing)", "Dial them on a keypad (Kinesthetic)"],
148
+ ["Read a book (Reading/Writing)", "Listen to music (Auditory)", "Watch TV/movies (Visual)", "Do something physical (Kinesthetic)"],
149
+ ["Read the manual (Reading/Writing)", "Ask someone to show you (Visual)", "Call tech support (Auditory)", "Experiment with the software (Kinesthetic)"],
150
+ ["Detailed notes (Reading/Writing)", "Verbal explanations (Auditory)", "Visual slides (Visual)", "Physical demonstrations (Kinesthetic)"],
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):
 
172
  max_score = max(scores.values())
173
  total_questions = len(learning_style_questions)
174
 
175
+ # Calculate percentages
176
  percentages = {style: (score/total_questions)*100 for style, score in scores.items()}
177
+
178
+ # Sort styles by score (descending)
179
  sorted_styles = sorted(scores.items(), key=lambda x: x[1], reverse=True)
180
 
181
+ # Prepare detailed results
182
  result = "Your Learning Style Results:\n\n"
183
  for style, score in sorted_styles:
184
  result += f"{style}: {score}/{total_questions} ({percentages[style]:.1f}%)\n"
185
 
186
  result += "\n"
187
+
188
+ # Determine primary and secondary styles
189
  primary_styles = [style for style, score in scores.items() if score == max_score]
190
 
191
  if len(primary_styles) == 1:
192
  result += f"Your primary learning style is: {primary_styles[0]}\n\n"
193
+ # Add personalized tips based on primary style
194
+ if primary_styles[0] == "Visual":
195
+ result += "Tips for Visual Learners:\n"
196
+ result += "- Use color coding in your notes\n"
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"
 
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 = {
 
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
+
277
+ display = "### Detailed Course History\n"
278
+ courses_by_grade = transcript_dict["courses"]
279
+
280
+ if isinstance(courses_by_grade, dict):
281
+ # Sort grades numerically
282
+ for grade in sorted(courses_by_grade.keys(), key=int):
283
+ display += f"\n**Grade {grade}**\n"
284
+ for course in courses_by_grade[grade]:
285
+ display += f"- {course['name']}"
286
+ if 'grade' in course and course['grade']:
287
+ display += f" (Grade: {course['grade']})"
288
+ if 'credits' in course:
289
+ display += f" | Credits: {course['credits']}"
290
+ display += f" | Year: {course['year']}\n"
291
+
292
+ if 'gpa' in transcript_dict:
293
+ gpa = transcript_dict['gpa']
294
+ display += "\n**GPA Information**\n"
295
+ display += f"- Unweighted: {gpa.get('unweighted', 'N/A')}\n"
296
+ display += f"- Weighted: {gpa.get('weighted', 'N/A')}\n"
297
+
298
+ return display
299
+
300
  # ========== AI TEACHING ASSISTANT ==========
301
  def load_profile():
302
  if not os.path.exists("student_profiles"):
 
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,
 
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