Spaces:
Sleeping
Sleeping
| """ | |
| Integrate personalized learning pathway functionality into Gradio interface | |
| """ | |
| import gradio as gr | |
| import json | |
| from datetime import datetime | |
| from personalized_learning import ( | |
| UserProfilingSystem, | |
| LearningPathGenerator, | |
| AdaptiveLearningEngine | |
| ) | |
| # Initialize system components | |
| def initialize_personalized_learning(available_topics: list, client): | |
| """Initialize personalized learning system""" | |
| user_profiling = UserProfilingSystem() | |
| learning_path_generator = LearningPathGenerator(user_profiling, available_topics) | |
| adaptive_engine = AdaptiveLearningEngine(user_profiling, learning_path_generator) | |
| return user_profiling, learning_path_generator, adaptive_engine | |
| # Create personalized learning path tab | |
| def create_personalized_learning_tab(adaptive_engine, user_profiling, query_rag_model, | |
| generate_multiple_choice_questions, client): | |
| """Create personalized learning path tab""" | |
| with gr.TabItem("Personalized Learning Path"): | |
| gr.Markdown("## π― Your Personalized Learning Journey") | |
| gr.Markdown("Get a customized learning path based on your knowledge profile and performance.") | |
| # User ID input | |
| with gr.Row(): | |
| user_id_input = gr.Textbox( | |
| label="User ID", | |
| placeholder="Enter your user ID (e.g., user_001)", | |
| value="default_user" | |
| ) | |
| load_profile_btn = gr.Button("Load My Profile") | |
| # User profile display | |
| with gr.Column(visible=False) as profile_container: | |
| profile_summary = gr.Markdown() | |
| with gr.Row(): | |
| with gr.Column(): | |
| gr.Markdown("### π Knowledge Profile") | |
| knowledge_level_display = gr.JSON() | |
| with gr.Column(): | |
| gr.Markdown("### π Learning Statistics") | |
| learning_stats = gr.JSON() | |
| # Learning path section | |
| with gr.Row(): | |
| focus_areas_input = gr.CheckboxGroup( | |
| label="Focus Areas (Optional)", | |
| choices=[], | |
| value=[], | |
| interactive=True | |
| ) | |
| generate_path_btn = gr.Button("Generate Learning Path", variant="primary") | |
| # Learning path visualization | |
| with gr.Column(visible=False) as path_container: | |
| gr.Markdown("### πΊοΈ Your Learning Path") | |
| path_progress = gr.HTML() | |
| path_visualization = gr.HTML() | |
| # Current node information | |
| with gr.Row(): | |
| with gr.Column(): | |
| current_node_info = gr.Markdown() | |
| with gr.Column(): | |
| next_action_btn = gr.Button("Start This Node", variant="primary") | |
| skip_node_btn = gr.Button("Skip This Node") | |
| # Recommendations section | |
| with gr.Row(): | |
| with gr.Column(): | |
| gr.Markdown("### π‘ Recommendations") | |
| recommendations_display = gr.JSON() | |
| # Learning activity history | |
| with gr.Column(visible=False) as history_container: | |
| gr.Markdown("### π Learning History") | |
| learning_history = gr.Dataframe( | |
| headers=["Date", "Topic", "Activity", "Score"], | |
| interactive=False | |
| ) | |
| # Handler functions | |
| def load_user_profile(user_id): | |
| """Load user profile""" | |
| if not user_id: | |
| return ( | |
| gr.update(visible=False), # profile_container | |
| "", # profile_summary | |
| {}, # knowledge_level_display | |
| {}, # learning_stats | |
| [], # focus_areas_input choices | |
| gr.update(visible=False) # path_container | |
| ) | |
| profile = user_profiling.get_or_create_profile(user_id) | |
| summary = user_profiling.get_profile_summary(user_id) | |
| # Generate summary text | |
| summary_text = f""" | |
| ### π€ User Profile: {user_id} | |
| **Learning Style:** {summary['learning_style'].title()} | |
| **Learning Pace:** {summary['learning_pace'].title()} | |
| **Overall Progress:** {summary['overall_progress']:.1%} | |
| **Total Questions Asked:** {summary['total_questions']} | |
| **Total Tests Completed:** {summary['total_tests']} | |
| **Strong Areas:** {', '.join(summary['strong_areas']) if summary['strong_areas'] else 'None yet'} | |
| **Areas Needing Improvement:** {', '.join(summary['weak_areas']) if summary['weak_areas'] else 'None yet'} | |
| """ | |
| # Prepare knowledge level data | |
| knowledge_data = summary['knowledge_level'] | |
| if not knowledge_data: | |
| knowledge_data = {"No topics learned yet": 0.0} | |
| # Prepare statistics data | |
| stats_data = { | |
| "Total Questions": summary['total_questions'], | |
| "Total Tests": summary['total_tests'], | |
| "Preferred Topics": summary['preferred_topics'][:5] if summary['preferred_topics'] else [], | |
| "Overall Progress": f"{summary['overall_progress']:.1%}" | |
| } | |
| # Update focus areas options | |
| all_topics = list(set(list(knowledge_data.keys()) + | |
| summary['preferred_topics'] + | |
| summary['weak_areas'])) | |
| return ( | |
| gr.update(visible=True), | |
| summary_text, | |
| knowledge_data, | |
| stats_data, | |
| all_topics, | |
| gr.update(visible=False) | |
| ) | |
| def generate_learning_path(user_id, focus_areas): | |
| """Generate learning path""" | |
| if not user_id: | |
| return ( | |
| gr.update(visible=False), | |
| "", | |
| "", | |
| "", | |
| {}, | |
| gr.update(visible=False) | |
| ) | |
| path = adaptive_engine.create_or_update_path(user_id, focus_areas if focus_areas else None) | |
| # Generate path visualization HTML | |
| vis_data = adaptive_engine.get_path_visualization_data(user_id) | |
| # Create progress bar | |
| progress_html = f""" | |
| <div style="width:100%; background-color:#f0f0f0; border-radius:5px; overflow:hidden; margin:20px 0;"> | |
| <div style="width:{path.completion_percentage*100}%; background-color:#4CAF50; height:30px; border-radius:5px; display:flex; align-items:center; justify-content:center; color:white; font-weight:bold;"> | |
| {path.completion_percentage*100:.1f}% Complete | |
| </div> | |
| </div> | |
| <p><strong>Total Nodes:</strong> {len(path.nodes)} | <strong>Completed:</strong> {sum(1 for n in path.nodes if n.status == 'completed')} | <strong>Estimated Time:</strong> {path.estimated_total_time} minutes</p> | |
| """ | |
| # Create path visualization | |
| path_html = "<div style='margin:20px 0;'>" | |
| path_html += "<h4>Learning Path Structure:</h4>" | |
| path_html += "<div style='display:flex; flex-direction:column; gap:10px;'>" | |
| for i, node in enumerate(path.nodes): | |
| status_color = { | |
| "completed": "#4CAF50", | |
| "in_progress": "#2196F3", | |
| "pending": "#9E9E9E", | |
| "skipped": "#FF9800" | |
| }.get(node.status, "#9E9E9E") | |
| is_current = i == path.current_node_index | |
| highlight = "border: 3px solid #FF5722; padding: 10px;" if is_current else "padding: 10px;" | |
| path_html += f""" | |
| <div style='{highlight} background-color:white; border-left: 5px solid {status_color}; border-radius:5px; margin:5px 0;'> | |
| <div style='display:flex; justify-content:space-between; align-items:center;'> | |
| <div> | |
| <strong>{node.topic}</strong> - {node.bloom_level.title()} ({node.content_type}) | |
| <br> | |
| <small>Difficulty: {node.difficulty:.2f} | Time: {node.estimated_time} min</small> | |
| </div> | |
| <div style='color:{status_color}; font-weight:bold;'> | |
| {node.status.title()} | |
| </div> | |
| </div> | |
| </div> | |
| """ | |
| path_html += "</div></div>" | |
| # Current node information | |
| if path.current_node_index < len(path.nodes): | |
| current_node = path.nodes[path.current_node_index] | |
| current_node_info = f""" | |
| ### Current Learning Node | |
| **Topic:** {current_node.topic} | |
| **Bloom Level:** {current_node.bloom_level.title()} | |
| **Content Type:** {current_node.content_type.title()} | |
| **Difficulty:** {current_node.difficulty:.2f} | |
| **Estimated Time:** {current_node.estimated_time} minutes | |
| **Status:** {current_node.status.title()} | |
| """ | |
| else: | |
| current_node_info = "### Learning Path Complete! π" | |
| # Get recommendations | |
| recommendations = adaptive_engine.get_recommendations(user_id) | |
| return ( | |
| gr.update(visible=True), | |
| progress_html, | |
| path_html, | |
| current_node_info, | |
| recommendations, | |
| gr.update(visible=True) | |
| ) | |
| def start_current_node(user_id): | |
| """Start current node""" | |
| path = adaptive_engine.get_active_path(user_id) | |
| if not path or path.current_node_index >= len(path.nodes): | |
| return "No active node to start." | |
| current_node = path.nodes[path.current_node_index] | |
| return f"Starting learning node: {current_node.topic} - {current_node.bloom_level}" | |
| # Bind events | |
| load_profile_btn.click( | |
| load_user_profile, | |
| inputs=[user_id_input], | |
| outputs=[profile_container, profile_summary, knowledge_level_display, | |
| learning_stats, focus_areas_input, path_container] | |
| ) | |
| generate_path_btn.click( | |
| generate_learning_path, | |
| inputs=[user_id_input, focus_areas_input], | |
| outputs=[path_container, path_progress, path_visualization, | |
| current_node_info, recommendations_display, history_container] | |
| ) | |
| next_action_btn.click( | |
| start_current_node, | |
| inputs=[user_id_input], | |
| outputs=[] | |
| ) | |
| # Auto-load default user | |
| user_id_input.change( | |
| load_user_profile, | |
| inputs=[user_id_input], | |
| outputs=[profile_container, profile_summary, knowledge_level_display, | |
| learning_stats, focus_areas_input, path_container] | |
| ) | |
| return { | |
| "adaptive_engine": adaptive_engine, | |
| "user_profiling": user_profiling | |
| } | |
| # Integrate with existing testing functionality | |
| def integrate_with_testing(adaptive_engine, user_profiling, test_results, user_id): | |
| """Integrate test results into personalized learning system""" | |
| if not user_id or not test_results: | |
| return | |
| # Extract topic from test results (assuming test results contain topic information) | |
| topic = test_results[0].get('topic', 'unknown') if test_results else 'unknown' | |
| # Update user profile | |
| profile = user_profiling.update_from_test_results(user_id, topic, test_results) | |
| # Update learning path | |
| path = adaptive_engine.get_active_path(user_id) | |
| if path: | |
| # Calculate average score | |
| scores = [1.0 if r.get('is_correct', False) else 0.0 for r in test_results] | |
| avg_score = sum(scores) / len(scores) if scores else 0.5 | |
| # Find corresponding node and mark as completed | |
| for node in path.nodes: | |
| if node.topic == topic and node.status == "in_progress": | |
| adaptive_engine.complete_node(user_id, node.node_id, avg_score) | |
| break | |
| # Integrate with Q&A functionality | |
| def integrate_with_qa(user_profiling, user_id, question): | |
| """Integrate Q&A history into personalized learning system""" | |
| if not user_id or not question: | |
| return | |
| # Simple topic extraction (can be improved based on actual needs) | |
| topic = None | |
| if "distronic" in question.lower() or "distance" in question.lower(): | |
| topic = "DISTRONIC" | |
| elif "lane" in question.lower(): | |
| topic = "Lane Change Assist" | |
| elif "steering" in question.lower(): | |
| topic = "Steering Assist" | |
| elif "stop" in question.lower() or "go" in question.lower(): | |
| topic = "Stop-and-Go Assist" | |
| # Update user profile | |
| user_profiling.update_from_question(user_id, question, topic) | |