Spaces:
Sleeping
Sleeping
""" | |
Contextualized AI Tutoring tools for TutorX. | |
Provides step-by-step guidance, alternative explanations, and conversational AI tutoring. | |
""" | |
import json | |
import uuid | |
from datetime import datetime, timedelta | |
from typing import Dict, Any, List, Optional | |
from mcp_server.mcp_instance import mcp | |
from mcp_server.model.gemini_flash import GeminiFlash | |
MODEL = GeminiFlash() | |
# Tutoring session storage | |
tutoring_sessions = {} | |
def extract_json_from_text(text: str): | |
"""Extract JSON from text response""" | |
import re | |
if not text or not isinstance(text, str): | |
return None | |
# Remove code fences | |
text = re.sub(r'^\s*```(?:json)?\s*', '', text, flags=re.IGNORECASE) | |
text = re.sub(r'\s*```\s*$', '', text, flags=re.IGNORECASE) | |
text = text.strip() | |
# Remove trailing commas | |
text = re.sub(r',([ \t\r\n]*[}}\]])', r'\1', text) | |
return json.loads(text) | |
class TutoringSession: | |
"""Manages a tutoring session with context and memory""" | |
def __init__(self, session_id: str, student_id: str, subject: str = "general"): | |
self.session_id = session_id | |
self.student_id = student_id | |
self.subject = subject | |
self.created_at = datetime.utcnow() | |
self.last_activity = datetime.utcnow() | |
self.conversation_history = [] | |
self.current_topic = None | |
self.learning_objectives = [] | |
self.student_understanding_level = 0.5 # 0.0 to 1.0 | |
self.preferred_explanation_style = "detailed" # detailed, simple, visual, step-by-step | |
self.difficulty_preference = 0.5 # 0.0 to 1.0 | |
def add_interaction(self, query: str, response: str, interaction_type: str = "question"): | |
"""Add an interaction to the session history""" | |
self.conversation_history.append({ | |
"timestamp": datetime.utcnow().isoformat(), | |
"query": query, | |
"response": response, | |
"type": interaction_type, | |
"understanding_level": self.student_understanding_level | |
}) | |
self.last_activity = datetime.utcnow() | |
def get_context_summary(self) -> str: | |
"""Generate a context summary for the AI tutor""" | |
recent_interactions = self.conversation_history[-5:] # Last 5 interactions | |
context = f""" | |
Session Context: | |
- Student ID: {self.student_id} | |
- Subject: {self.subject} | |
- Current Topic: {self.current_topic or 'Not specified'} | |
- Understanding Level: {self.student_understanding_level:.2f}/1.0 | |
- Preferred Style: {self.preferred_explanation_style} | |
- Session Duration: {(datetime.utcnow() - self.created_at).total_seconds() / 60:.1f} minutes | |
Recent Conversation: | |
""" | |
for interaction in recent_interactions: | |
context += f"\nStudent: {interaction['query']}\nTutor: {interaction['response'][:100]}...\n" | |
return context | |
async def start_tutoring_session(student_id: str, subject: str = "general", | |
learning_objectives: List[str] = None) -> dict: | |
""" | |
Start a new AI tutoring session with context management. | |
Args: | |
student_id: Student identifier | |
subject: Subject area for tutoring | |
learning_objectives: List of learning objectives for the session | |
Returns: | |
Dictionary with session information | |
""" | |
try: | |
session_id = str(uuid.uuid4()) | |
session = TutoringSession(session_id, student_id, subject) | |
if learning_objectives: | |
session.learning_objectives = learning_objectives | |
tutoring_sessions[session_id] = session | |
# Generate welcome message | |
prompt = f""" | |
You are an expert AI tutor starting a new tutoring session. | |
Student ID: {student_id} | |
Subject: {subject} | |
Learning Objectives: {learning_objectives or 'To be determined based on student needs'} | |
Generate a welcoming introduction that: | |
1. Welcomes the student warmly | |
2. Explains your role as their AI tutor | |
3. Asks about their current understanding or what they'd like to learn | |
4. Sets expectations for the tutoring session | |
Return a JSON object with: | |
- "welcome_message": friendly welcome text | |
- "suggested_topics": list of 3-5 topics they might want to explore | |
- "session_guidelines": brief explanation of how the tutoring works | |
""" | |
response = await MODEL.generate_text(prompt, temperature=0.7) | |
welcome_data = extract_json_from_text(response) | |
return { | |
"success": True, | |
"session_id": session_id, | |
"student_id": student_id, | |
"subject": subject, | |
"created_at": session.created_at.isoformat(), | |
**welcome_data | |
} | |
except Exception as e: | |
return { | |
"success": False, | |
"error": f"Failed to start tutoring session: {str(e)}" | |
} | |
async def ai_tutor_chat(session_id: str, student_query: str, | |
request_type: str = "explanation") -> dict: | |
""" | |
Process student query with contextualized AI tutoring. | |
Args: | |
session_id: Active tutoring session ID | |
student_query: Student's question or request | |
request_type: Type of request ('explanation', 'step_by_step', 'alternative', 'practice', 'clarification') | |
Returns: | |
Dictionary with tutor response and guidance | |
""" | |
try: | |
if session_id not in tutoring_sessions: | |
return { | |
"success": False, | |
"error": "Invalid session ID. Please start a new tutoring session." | |
} | |
session = tutoring_sessions[session_id] | |
context = session.get_context_summary() | |
# Analyze student query to understand their needs | |
analysis_prompt = f""" | |
Analyze this student query in the context of their tutoring session: | |
{context} | |
Student Query: "{student_query}" | |
Request Type: {request_type} | |
Analyze and return JSON with: | |
- "topic_identified": main topic/concept the student is asking about | |
- "difficulty_level": estimated difficulty (0.0 to 1.0) | |
- "understanding_gaps": potential areas where student might be confused | |
- "prerequisite_concepts": concepts student should know first | |
- "confidence_level": how confident the student seems (0.0 to 1.0) | |
""" | |
analysis_response = await MODEL.generate_text(analysis_prompt, temperature=0.3) | |
analysis = extract_json_from_text(analysis_response) | |
# Update session context based on analysis | |
if analysis and "topic_identified" in analysis: | |
session.current_topic = analysis["topic_identified"] | |
if "difficulty_level" in analysis: | |
session.difficulty_preference = analysis["difficulty_level"] | |
# Generate appropriate response based on request type | |
if request_type == "step_by_step": | |
response_prompt = f""" | |
{context} | |
The student asked: "{student_query}" | |
Provide a detailed step-by-step explanation that: | |
1. Breaks down the concept into manageable steps | |
2. Uses simple, clear language appropriate for their level | |
3. Includes examples for each step | |
4. Checks understanding at key points | |
5. Provides encouragement and support | |
Return JSON with: | |
- "step_by_step_explanation": detailed step-by-step guide | |
- "key_steps": list of main steps with brief descriptions | |
- "examples": relevant examples for each step | |
- "check_points": questions to verify understanding | |
- "encouragement": supportive message | |
""" | |
elif request_type == "alternative": | |
response_prompt = f""" | |
{context} | |
The student asked: "{student_query}" | |
Provide alternative explanations using different approaches: | |
1. Visual/spatial explanation | |
2. Analogy-based explanation | |
3. Real-world application | |
4. Simplified version | |
Return JSON with: | |
- "visual_explanation": explanation using visual/spatial concepts | |
- "analogy_explanation": explanation using familiar analogies | |
- "real_world_application": how this applies in real life | |
- "simplified_version": very simple explanation | |
- "which_works_best": question asking which explanation resonates | |
""" | |
else: # Default explanation | |
response_prompt = f""" | |
{context} | |
The student asked: "{student_query}" | |
Provide a comprehensive, personalized explanation that: | |
1. Addresses their specific question directly | |
2. Builds on their current understanding level | |
3. Uses their preferred explanation style | |
4. Includes relevant examples | |
5. Suggests next steps for learning | |
Return JSON with: | |
- "main_explanation": comprehensive answer to their question | |
- "key_concepts": important concepts to remember | |
- "examples": relevant examples | |
- "next_steps": suggested follow-up activities | |
- "related_topics": topics they might want to explore next | |
""" | |
tutor_response = await MODEL.generate_text(response_prompt, temperature=0.7) | |
response_data = extract_json_from_text(tutor_response) | |
# Add interaction to session history | |
session.add_interaction( | |
student_query, | |
response_data.get("main_explanation", str(response_data)), | |
request_type | |
) | |
return { | |
"success": True, | |
"session_id": session_id, | |
"request_type": request_type, | |
"analysis": analysis, | |
"response": response_data, | |
"session_stats": { | |
"interactions_count": len(session.conversation_history), | |
"current_topic": session.current_topic, | |
"understanding_level": session.student_understanding_level | |
} | |
} | |
except Exception as e: | |
return { | |
"success": False, | |
"error": f"Failed to process tutoring request: {str(e)}" | |
} | |
async def get_step_by_step_guidance(session_id: str, concept: str, | |
current_step: int = 1) -> dict: | |
""" | |
Provide detailed step-by-step guidance for learning a specific concept. | |
Args: | |
session_id: Active tutoring session ID | |
concept: The concept to provide guidance for | |
current_step: Current step the student is on (1-based) | |
Returns: | |
Dictionary with step-by-step guidance | |
""" | |
try: | |
if session_id not in tutoring_sessions: | |
return { | |
"success": False, | |
"error": "Invalid session ID. Please start a new tutoring session." | |
} | |
session = tutoring_sessions[session_id] | |
context = session.get_context_summary() | |
prompt = f""" | |
{context} | |
Provide comprehensive step-by-step guidance for learning: "{concept}" | |
Current step: {current_step} | |
Create a structured learning path that: | |
1. Breaks the concept into logical, sequential steps | |
2. Provides clear explanations for each step | |
3. Includes practice exercises for each step | |
4. Offers multiple ways to understand each step | |
5. Includes checkpoints to verify understanding | |
Return JSON with: | |
- "total_steps": total number of steps needed | |
- "current_step_details": detailed information about the current step | |
- "step_explanation": clear explanation of the current step | |
- "practice_exercises": 2-3 practice problems for this step | |
- "key_points": important points to remember | |
- "common_mistakes": common mistakes students make at this step | |
- "next_step_preview": brief preview of what comes next | |
- "prerequisite_check": what student should know before this step | |
- "mastery_indicators": how to know if student has mastered this step | |
""" | |
response = await MODEL.generate_text(prompt, temperature=0.6) | |
guidance_data = extract_json_from_text(response) | |
return { | |
"success": True, | |
"session_id": session_id, | |
"concept": concept, | |
"current_step": current_step, | |
"guidance": guidance_data | |
} | |
except Exception as e: | |
return { | |
"success": False, | |
"error": f"Failed to generate step-by-step guidance: {str(e)}" | |
} | |
async def get_alternative_explanations(session_id: str, concept: str, | |
explanation_types: List[str] = None) -> dict: | |
""" | |
Generate alternative explanations for a concept using different approaches. | |
Args: | |
session_id: Active tutoring session ID | |
concept: The concept to explain | |
explanation_types: Types of explanations to generate | |
Returns: | |
Dictionary with alternative explanations | |
""" | |
try: | |
if session_id not in tutoring_sessions: | |
return { | |
"success": False, | |
"error": "Invalid session ID. Please start a new tutoring session." | |
} | |
session = tutoring_sessions[session_id] | |
context = session.get_context_summary() | |
if not explanation_types: | |
explanation_types = ["visual", "analogy", "real_world", "simplified", "technical"] | |
prompt = f""" | |
{context} | |
Generate multiple alternative explanations for: "{concept}" | |
Create explanations using these approaches: {explanation_types} | |
For each explanation type, provide: | |
1. A complete explanation using that approach | |
2. Key benefits of this explanation style | |
3. When this explanation works best | |
4. Supporting examples or analogies | |
Return JSON with: | |
- "visual_explanation": explanation using visual/spatial concepts and imagery | |
- "analogy_explanation": explanation using familiar analogies and metaphors | |
- "real_world_explanation": explanation showing real-world applications | |
- "simplified_explanation": very simple, basic explanation | |
- "technical_explanation": detailed, technical explanation | |
- "story_explanation": explanation told as a story or narrative | |
- "comparison_explanation": explanation comparing to similar concepts | |
- "recommendation": which explanation might work best for this student | |
""" | |
response = await MODEL.generate_text(prompt, temperature=0.7) | |
explanations_data = extract_json_from_text(response) | |
return { | |
"success": True, | |
"session_id": session_id, | |
"concept": concept, | |
"explanation_types": explanation_types, | |
"explanations": explanations_data | |
} | |
except Exception as e: | |
return { | |
"success": False, | |
"error": f"Failed to generate alternative explanations: {str(e)}" | |
} | |
async def update_student_understanding(session_id: str, concept: str, | |
understanding_level: float, | |
feedback: str = "") -> dict: | |
""" | |
Update student's understanding level and adapt tutoring accordingly. | |
Args: | |
session_id: Active tutoring session ID | |
concept: The concept being learned | |
understanding_level: Student's understanding level (0.0 to 1.0) | |
feedback: Optional feedback from student | |
Returns: | |
Dictionary with updated session information and recommendations | |
""" | |
try: | |
if session_id not in tutoring_sessions: | |
return { | |
"success": False, | |
"error": "Invalid session ID. Please start a new tutoring session." | |
} | |
session = tutoring_sessions[session_id] | |
# Update session understanding level | |
session.student_understanding_level = understanding_level | |
session.current_topic = concept | |
# Generate adaptive recommendations based on understanding level | |
prompt = f""" | |
Student understanding update: | |
- Concept: {concept} | |
- Understanding Level: {understanding_level:.2f}/1.0 | |
- Student Feedback: {feedback or 'No feedback provided'} | |
- Session Context: {session.get_context_summary()} | |
Based on this understanding level, provide adaptive recommendations: | |
Return JSON with: | |
- "understanding_assessment": assessment of student's current understanding | |
- "next_actions": recommended next steps based on understanding level | |
- "difficulty_adjustment": how to adjust difficulty (easier/harder/same) | |
- "focus_areas": specific areas that need more attention | |
- "encouragement": encouraging message appropriate for their level | |
- "study_strategies": personalized study strategies | |
- "time_estimate": estimated time to reach mastery | |
""" | |
response = await MODEL.generate_text(prompt, temperature=0.6) | |
recommendations_data = extract_json_from_text(response) | |
# Add this update to conversation history | |
session.add_interaction( | |
f"Understanding update for {concept}: {understanding_level:.2f}", | |
f"Updated understanding and provided recommendations", | |
"understanding_update" | |
) | |
return { | |
"success": True, | |
"session_id": session_id, | |
"concept": concept, | |
"updated_understanding_level": understanding_level, | |
"recommendations": recommendations_data, | |
"session_stats": { | |
"interactions_count": len(session.conversation_history), | |
"current_topic": session.current_topic, | |
"understanding_level": session.student_understanding_level | |
} | |
} | |
except Exception as e: | |
return { | |
"success": False, | |
"error": f"Failed to update understanding: {str(e)}" | |
} | |
async def get_tutoring_session_status(session_id: str) -> dict: | |
""" | |
Get the current status and context of a tutoring session. | |
Args: | |
session_id: Tutoring session ID | |
Returns: | |
Dictionary with session status and statistics | |
""" | |
try: | |
if session_id not in tutoring_sessions: | |
return { | |
"success": False, | |
"error": "Session not found" | |
} | |
session = tutoring_sessions[session_id] | |
return { | |
"success": True, | |
"session_id": session_id, | |
"student_id": session.student_id, | |
"subject": session.subject, | |
"current_topic": session.current_topic, | |
"created_at": session.created_at.isoformat(), | |
"last_activity": session.last_activity.isoformat(), | |
"duration_minutes": (datetime.utcnow() - session.created_at).total_seconds() / 60, | |
"understanding_level": session.student_understanding_level, | |
"preferred_style": session.preferred_explanation_style, | |
"learning_objectives": session.learning_objectives, | |
"interaction_count": len(session.conversation_history), | |
"recent_topics": list(set([ | |
interaction.get("query", "")[:50] | |
for interaction in session.conversation_history[-5:] | |
])) | |
} | |
except Exception as e: | |
return { | |
"success": False, | |
"error": f"Failed to get session status: {str(e)}" | |
} | |
async def end_tutoring_session(session_id: str, session_summary: str = "") -> dict: | |
""" | |
End a tutoring session and generate a summary. | |
Args: | |
session_id: Tutoring session ID | |
session_summary: Optional summary from student | |
Returns: | |
Dictionary with session summary and recommendations | |
""" | |
try: | |
if session_id not in tutoring_sessions: | |
return { | |
"success": False, | |
"error": "Session not found" | |
} | |
session = tutoring_sessions[session_id] | |
# Generate session summary | |
prompt = f""" | |
Generate a comprehensive summary for this tutoring session: | |
{session.get_context_summary()} | |
Session Details: | |
- Duration: {(datetime.utcnow() - session.created_at).total_seconds() / 60:.1f} minutes | |
- Interactions: {len(session.conversation_history)} | |
- Final Understanding Level: {session.student_understanding_level:.2f}/1.0 | |
- Student Summary: {session_summary or 'No summary provided'} | |
Return JSON with: | |
- "session_summary": comprehensive summary of what was covered | |
- "learning_achievements": what the student accomplished | |
- "areas_covered": topics and concepts discussed | |
- "understanding_progress": how understanding evolved during session | |
- "recommendations": recommendations for future study | |
- "next_session_suggestions": suggestions for next tutoring session | |
- "study_plan": personalized study plan based on session | |
- "strengths_identified": student strengths observed | |
- "areas_for_improvement": areas that need more work | |
""" | |
response = await MODEL.generate_text(prompt, temperature=0.6) | |
summary_data = extract_json_from_text(response) | |
# Store session summary before removing | |
session_data = { | |
"session_id": session_id, | |
"student_id": session.student_id, | |
"subject": session.subject, | |
"duration_minutes": (datetime.utcnow() - session.created_at).total_seconds() / 60, | |
"interaction_count": len(session.conversation_history), | |
"final_understanding": session.student_understanding_level, | |
"summary": summary_data | |
} | |
# Remove session from active sessions | |
del tutoring_sessions[session_id] | |
return { | |
"success": True, | |
"session_ended": True, | |
**session_data | |
} | |
except Exception as e: | |
return { | |
"success": False, | |
"error": f"Failed to end session: {str(e)}" | |
} | |
async def list_active_tutoring_sessions(student_id: str = None) -> dict: | |
""" | |
List all active tutoring sessions, optionally filtered by student. | |
Args: | |
student_id: Optional student ID to filter sessions | |
Returns: | |
Dictionary with list of active sessions | |
""" | |
try: | |
active_sessions = [] | |
for session_id, session in tutoring_sessions.items(): | |
if student_id is None or session.student_id == student_id: | |
active_sessions.append({ | |
"session_id": session_id, | |
"student_id": session.student_id, | |
"subject": session.subject, | |
"current_topic": session.current_topic, | |
"created_at": session.created_at.isoformat(), | |
"last_activity": session.last_activity.isoformat(), | |
"duration_minutes": (datetime.utcnow() - session.created_at).total_seconds() / 60, | |
"understanding_level": session.student_understanding_level, | |
"interaction_count": len(session.conversation_history) | |
}) | |
return { | |
"success": True, | |
"active_sessions": active_sessions, | |
"total_sessions": len(active_sessions), | |
"filtered_by_student": student_id is not None | |
} | |
except Exception as e: | |
return { | |
"success": False, | |
"error": f"Failed to list sessions: {str(e)}" | |
} | |