CSRC-Car-Manual-RAG / modules /integrate_personalized_learning.py
Bryceeee's picture
Upload 34 files
6a11527 verified
"""
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)