Spaces:
Runtime error
Runtime error
| import gradio as gr | |
| import pandas as pd | |
| import json | |
| import os | |
| import re | |
| from PyPDF2 import PdfReader | |
| from collections import defaultdict | |
| # ========== TRANSCRIPT PARSING FUNCTIONS ========== | |
| def extract_courses_with_grade_levels(text): | |
| grade_level_pattern = r"(Grade|Year)\s*[:]?\s*(\d+|Freshman|Sophomore|Junior|Senior)" | |
| grade_match = re.search(grade_level_pattern, text, re.IGNORECASE) | |
| current_grade_level = grade_match.group(2) if grade_match else "Unknown" | |
| course_pattern = r""" | |
| (?:^|\n) | |
| (?: (Grade|Year)\s*[:]?\s*(\d+|Freshman|Sophomore|Junior|Senior)\s*[\n-]* )? | |
| ( | |
| (?:[A-Z]{2,}\s?\d{3}) | |
| | | |
| [A-Z][a-z]+(?:\s[A-Z][a-z]+)* | |
| ) | |
| \s* | |
| (?: [:\-]?\s* ([A-F][+-]?|\d{2,3}%)? )? | |
| """ | |
| courses_by_grade = defaultdict(list) | |
| current_grade = current_grade_level | |
| for match in re.finditer(course_pattern, text, re.VERBOSE | re.MULTILINE): | |
| grade_context, grade_level, course, grade = match.groups() | |
| if grade_context: | |
| current_grade = grade_level | |
| if course: | |
| course_info = {"course": course.strip()} | |
| if grade: | |
| course_info["grade"] = grade.strip() | |
| courses_by_grade[current_grade].append(course_info) | |
| return dict(courses_by_grade) | |
| def parse_transcript(file): | |
| if file.name.endswith('.csv'): | |
| df = pd.read_csv(file) | |
| elif file.name.endswith('.xlsx'): | |
| df = pd.read_excel(file) | |
| elif file.name.endswith('.pdf'): | |
| text = '' | |
| reader = PdfReader(file) | |
| for page in reader.pages: | |
| page_text = page.extract_text() | |
| if page_text: | |
| text += page_text + '\n' | |
| # Grade level extraction | |
| grade_match = re.search(r'(Grade|Year)[\s:]*(\d+|Freshman|Sophomore|Junior|Senior)', text, re.IGNORECASE) | |
| grade_level = grade_match.group(2) if grade_match else "Unknown" | |
| # Enhanced GPA extraction | |
| gpa_data = {'weighted': "N/A", 'unweighted': "N/A"} | |
| gpa_patterns = [ | |
| r'Weighted GPA[\s:]*(\d\.\d{1,2})', | |
| r'GPA \(Weighted\)[\s:]*(\d\.\d{1,2})', | |
| r'Cumulative GPA \(Weighted\)[\s:]*(\d\.\d{1,2})', | |
| r'Unweighted GPA[\s:]*(\d\.\d{1,2})', | |
| r'GPA \(Unweighted\)[\s:]*(\d\.\d{1,2})', | |
| r'Cumulative GPA \(Unweighted\)[\s:]*(\d\.\d{1,2})', | |
| r'GPA[\s:]*(\d\.\d{1,2})' | |
| ] | |
| for pattern in gpa_patterns: | |
| for match in re.finditer(pattern, text, re.IGNORECASE): | |
| gpa_value = match.group(1) | |
| if 'weighted' in pattern.lower(): | |
| gpa_data['weighted'] = gpa_value | |
| elif 'unweighted' in pattern.lower(): | |
| gpa_data['unweighted'] = gpa_value | |
| else: | |
| if gpa_data['unweighted'] == "N/A": | |
| gpa_data['unweighted'] = gpa_value | |
| if gpa_data['weighted'] == "N/A": | |
| gpa_data['weighted'] = gpa_value | |
| courses_by_grade = extract_courses_with_grade_levels(text) | |
| output_text = f"Grade Level: {grade_level}\n\n" | |
| if gpa_data['weighted'] != "N/A" or gpa_data['unweighted'] != "N/A": | |
| output_text += "GPA Information:\n" | |
| if gpa_data['unweighted'] != "N/A": | |
| output_text += f"- Unweighted GPA: {gpa_data['unweighted']}\n" | |
| if gpa_data['weighted'] != "N/A": | |
| output_text += f"- Weighted GPA: {gpa_data['weighted']}\n" | |
| else: | |
| output_text += "No GPA information found\n" | |
| output_text += "\n(Courses not shown here)" | |
| return output_text, { | |
| "gpa": gpa_data, | |
| "grade_level": grade_level, | |
| "courses": courses_by_grade | |
| } | |
| else: | |
| return "Unsupported file format", None | |
| # For CSV/XLSX fallback | |
| gpa = "N/A" | |
| for col in ['GPA', 'Grade Point Average', 'Cumulative GPA']: | |
| if col in df.columns: | |
| gpa = df[col].iloc[0] if isinstance(df[col].iloc[0], (float, int)) else "N/A" | |
| break | |
| grade_level = "N/A" | |
| for col in ['Grade Level', 'Grade', 'Class', 'Year']: | |
| if col in df.columns: | |
| grade_level = df[col].iloc[0] | |
| break | |
| courses = [] | |
| for col in ['Course', 'Subject', 'Course Name', 'Class']: | |
| if col in df.columns: | |
| courses = df[col].tolist() | |
| break | |
| output_text = f"Grade Level: {grade_level}\nGPA: {gpa}\n\nCourses:\n" | |
| output_text += "\n".join(f"- {course}" for course in courses) | |
| return output_text, { | |
| "gpa": {"unweighted": gpa, "weighted": "N/A"}, | |
| "grade_level": grade_level, | |
| "courses": courses | |
| } | |
| # ========== LEARNING STYLE QUIZ ========== | |
| learning_style_questions = [ | |
| "When you study for a test, you prefer to:", | |
| "When you need directions to a new place, you prefer:", | |
| "When you learn a new skill, you prefer to:", | |
| "When you're trying to concentrate, you:", | |
| "When you meet new people, you remember them by:" | |
| ] | |
| learning_style_options = [ | |
| ["Read the textbook (Reading/Writing)", "Listen to lectures (Auditory)", "Use diagrams/charts (Visual)", "Practice problems (Kinesthetic)"], | |
| ["Look at a map (Visual)", "Have someone tell you (Auditory)", "Write down directions (Reading/Writing)", "Try walking/driving there (Kinesthetic)"], | |
| ["Read instructions (Reading/Writing)", "Have someone show you (Visual)", "Listen to explanations (Auditory)", "Try it yourself (Kinesthetic)"], | |
| ["Need quiet (Reading/Writing)", "Need background noise (Auditory)", "Need to move around (Kinesthetic)", "Need visual stimulation (Visual)"], | |
| ["Their face (Visual)", "Their name (Auditory)", "What you talked about (Reading/Writing)", "What you did together (Kinesthetic)"] | |
| ] | |
| def learning_style_quiz(*answers): | |
| scores = { | |
| "Visual": 0, | |
| "Auditory": 0, | |
| "Reading/Writing": 0, | |
| "Kinesthetic": 0 | |
| } | |
| for i, answer in enumerate(answers): | |
| if answer == learning_style_options[i][0]: | |
| scores["Reading/Writing"] += 1 | |
| elif answer == learning_style_options[i][1]: | |
| scores["Auditory"] += 1 | |
| elif answer == learning_style_options[i][2]: | |
| scores["Visual"] += 1 | |
| elif answer == learning_style_options[i][3]: | |
| scores["Kinesthetic"] += 1 | |
| max_score = max(scores.values()) | |
| dominant_styles = [style for style, score in scores.items() if score == max_score] | |
| if len(dominant_styles) == 1: | |
| return f"Your primary learning style is: {dominant_styles[0]}" | |
| else: | |
| return f"You have multiple strong learning styles: {', '.join(dominant_styles)}" | |
| # ========== SAVE STUDENT PROFILE FUNCTION ========== | |
| def save_profile(name, age, interests, transcript, learning_style, movie, movie_reason, show, show_reason, book, book_reason, character, character_reason, blog): | |
| # Convert age to int if it's a numpy number (from gradio Number input) | |
| age = int(age) if age else 0 | |
| favorites = { | |
| "movie": movie, | |
| "movie_reason": movie_reason, | |
| "show": show, | |
| "show_reason": show_reason, | |
| "book": book, | |
| "book_reason": book_reason, | |
| "character": character, | |
| "character_reason": character_reason | |
| } | |
| data = { | |
| "name": name, | |
| "age": age, | |
| "interests": interests, | |
| "transcript": transcript, | |
| "learning_style": learning_style, | |
| "favorites": favorites, | |
| "blog": blog | |
| } | |
| os.makedirs("student_profiles", exist_ok=True) | |
| json_path = os.path.join("student_profiles", f"{name.replace(' ', '_')}_profile.json") | |
| with open(json_path, "w") as f: | |
| json.dump(data, f, indent=2) | |
| markdown_summary = f"""### Student Profile: {name} | |
| **Age:** {age} | |
| **Interests:** {interests} | |
| **Learning Style:** {learning_style} | |
| #### Transcript: | |
| {transcript_display(transcript)} | |
| #### Favorites: | |
| - Movie: {favorites['movie']} ({favorites['movie_reason']}) | |
| - Show: {favorites['show']} ({favorites['show_reason']}) | |
| - Book: {favorites['book']} ({favorites['book_reason']}) | |
| - Character: {favorites['character']} ({favorites['character_reason']}) | |
| #### Blog: | |
| {blog if blog else "_No blog provided_"} | |
| """ | |
| return markdown_summary | |
| def transcript_display(transcript_dict): | |
| if not transcript_dict: | |
| return "No transcript uploaded." | |
| if isinstance(transcript_dict, dict) and "courses" in transcript_dict: | |
| if isinstance(transcript_dict["courses"], dict): | |
| display = "" | |
| for grade_level, courses in transcript_dict["courses"].items(): | |
| display += f"\n**Grade {grade_level}**\n" | |
| for course in courses: | |
| display += f"- {course['course']}" | |
| if 'grade' in course: | |
| display += f" (Grade: {course['grade']})" | |
| display += "\n" | |
| return display | |
| elif isinstance(transcript_dict["courses"], list): | |
| return "\n".join([f"- {course}" for course in transcript_dict["courses"]]) | |
| return "No course information available" | |
| # ========== AI TEACHING ASSISTANT ========== | |
| def load_profile(): | |
| if not os.path.exists("student_profiles"): | |
| return {} | |
| files = [f for f in os.listdir("student_profiles") if f.endswith('.json')] | |
| if files: | |
| with open(os.path.join("student_profiles", files[0]), "r") as f: | |
| return json.load(f) | |
| return {} | |
| def generate_response(message, history): | |
| profile = load_profile() | |
| if not profile: | |
| return "Please complete and save your profile first using the previous tabs." | |
| # Get profile data | |
| learning_style = profile.get("learning_style", "") | |
| grade_level = profile.get("transcript", {}).get("grade_level", "unknown") | |
| gpa = profile.get("transcript", {}).get("gpa", {}) | |
| interests = profile.get("interests", "") | |
| # Common responses | |
| greetings = ["hi", "hello", "hey"] | |
| study_help = ["study", "learn", "prepare", "exam"] | |
| grade_help = ["grade", "gpa", "score"] | |
| interest_help = ["interest", "hobby", "passion"] | |
| if any(greet in message.lower() for greet in greetings): | |
| return f"Hello {profile.get('name', 'there')}! How can I help you today?" | |
| elif any(word in message.lower() for word in study_help): | |
| if "Visual" in learning_style: | |
| response = ("Based on your visual learning style, I recommend:\n" | |
| "- Creating mind maps or diagrams\n" | |
| "- Using color-coded notes\n" | |
| "- Watching educational videos") | |
| elif "Auditory" in learning_style: | |
| response = ("Based on your auditory learning style, I recommend:\n" | |
| "- Recording lectures and listening to them\n" | |
| "- Participating in study groups\n" | |
| "- Explaining concepts out loud") | |
| elif "Reading/Writing" in learning_style: | |
| response = ("Based on your reading/writing learning style, I recommend:\n" | |
| "- Writing detailed notes\n" | |
| "- Creating summaries in your own words\n" | |
| "- Reading textbooks and articles") | |
| elif "Kinesthetic" in learning_style: | |
| response = ("Based on your kinesthetic learning style, I recommend:\n" | |
| "- Hands-on practice\n" | |
| "- Creating physical models\n" | |
| "- Taking frequent movement breaks") | |
| else: | |
| response = ("Here are some general study tips:\n" | |
| "- Break study sessions into 25-minute chunks\n" | |
| "- Review material regularly\n" | |
| "- Teach concepts to someone else") | |
| return response | |
| elif any(word in message.lower() for word in grade_help): | |
| return (f"Your GPA information:\n" | |
| f"- Unweighted: {gpa.get('unweighted', 'N/A')}\n" | |
| f"- Weighted: {gpa.get('weighted', 'N/A')}\n\n" | |
| "To improve your grades, try:\n" | |
| "- Setting specific goals\n" | |
| "- Meeting with teachers\n" | |
| "- Developing a study schedule") | |
| elif any(word in message.lower() for word in interest_help): | |
| return (f"I see you're interested in: {interests}\n\n" | |
| "You might want to:\n" | |
| "- Find clubs or activities related to these interests\n" | |
| "- Explore career paths that align with them") | |
| elif "help" in message.lower(): | |
| return ("I can help with:\n" | |
| "- Study tips based on your learning style\n" | |
| "- GPA and grade information\n" | |
| "- General academic advice\n\n" | |
| "Try asking about study strategies or your grades!") | |
| else: | |
| return ("I'm your personalized teaching assistant. " | |
| "I can help with study tips, grade information, and academic advice. " | |
| "Try asking about how to study for your classes!") | |
| # ========== GRADIO INTERFACE ========== | |
| with gr.Blocks() as app: | |
| with gr.Tab("Step 1: Upload Transcript"): | |
| transcript_file = gr.File(label="Upload your transcript (CSV, Excel, or PDF)") | |
| transcript_output = gr.Textbox(label="Transcript Output") | |
| transcript_data = gr.State() | |
| transcript_file.change(fn=parse_transcript, inputs=transcript_file, outputs=[transcript_output, transcript_data]) | |
| with gr.Tab("Step 2: Learning Style Quiz"): | |
| gr.Markdown("### Learning Style Quiz") | |
| quiz_components = [] | |
| for i, (question, options) in enumerate(zip(learning_style_questions, learning_style_options)): | |
| quiz_components.append( | |
| gr.Radio(options, label=f"{i+1}. {question}") | |
| ) | |
| learning_output = gr.Textbox(label="Learning Style Result") | |
| gr.Button("Submit Quiz").click( | |
| learning_style_quiz, | |
| inputs=quiz_components, | |
| outputs=learning_output | |
| ) | |
| with gr.Tab("Step 3: Personal Questions"): | |
| name = gr.Textbox(label="What's your name?") | |
| age = gr.Number(label="How old are you?", precision=0) | |
| interests = gr.Textbox(label="What are your interests?") | |
| movie = gr.Textbox(label="Favorite movie?") | |
| movie_reason = gr.Textbox(label="Why do you like that movie?") | |
| show = gr.Textbox(label="Favorite TV show?") | |
| show_reason = gr.Textbox(label="Why do you like that show?") | |
| book = gr.Textbox(label="Favorite book?") | |
| book_reason = gr.Textbox(label="Why do you like that book?") | |
| character = gr.Textbox(label="Favorite character?") | |
| character_reason = gr.Textbox(label="Why do you like that character?") | |
| blog_checkbox = gr.Checkbox(label="Do you want to write a blog?", value=False) | |
| blog_text = gr.Textbox(label="Write your blog here", visible=False, lines=5) | |
| blog_checkbox.change(lambda x: gr.update(visible=x), inputs=blog_checkbox, outputs=blog_text) | |
| with gr.Tab("Step 4: Save & Review"): | |
| output_summary = gr.Markdown() | |
| save_btn = gr.Button("Save Profile") | |
| save_btn.click( | |
| fn=save_profile, | |
| inputs=[name, age, interests, transcript_data, learning_output, | |
| movie, movie_reason, show, show_reason, | |
| book, book_reason, character, character_reason, blog_text], | |
| outputs=output_summary | |
| ) | |
| # AI Teaching Assistant Tab | |
| with gr.Tab("🤖 AI Teaching Assistant"): | |
| gr.Markdown("## Your Personalized Learning Assistant") | |
| chatbot = gr.ChatInterface( | |
| fn=generate_response, | |
| examples=[ | |
| "How should I study for my next test?", | |
| "What's my GPA information?", | |
| "Help me with study strategies", | |
| "How can I improve my grades?" | |
| ] | |
| ) | |
| if __name__ == "__main__": | |
| app.launch() | |