Spaces:
Sleeping
Sleeping
Meet Patel
commited on
Commit
·
bc987d8
1
Parent(s):
250bf8c
Implement AI tutoring and content generation tools for TutorX
Browse files- Added ai_tutor_tools.py for contextualized AI tutoring features, including session management, interaction logging, and personalized responses.
- Introduced content_generation_tools.py for automated content creation, including interactive exercises, scenario-based learning, and gamified content.
- Developed test_ai_integration.py to validate the functionality of AI tutoring and content generation features through comprehensive test cases.
- README.md +35 -1
- app.py +393 -5
- docs/AI_INTEGRATION_FEATURES.md +237 -0
- mcp_server/server.py +150 -0
- mcp_server/tools/ai_tutor_tools.py +650 -0
- mcp_server/tools/content_generation_tools.py +499 -0
- tests/test_ai_integration.py +141 -0
README.md
CHANGED
|
@@ -18,6 +18,20 @@ A comprehensive Model Context Protocol (MCP) server for educational AI tutoring
|
|
| 18 |
|
| 19 |
TutorX-MCP is an adaptive, multi-modal, and collaborative AI tutoring platform that leverages the Model Context Protocol (MCP) for tool integration and Gradio for user-friendly interfaces. It provides a range of educational features accessible via both MCP clients and a dedicated web interface.
|
| 20 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 21 |

|
| 22 |
|
| 23 |
For a comprehensive analysis of the project from architectural, development, and product perspectives, please see our [Project Analysis Document](PROJECT_ANALYSIS.md).
|
|
@@ -167,6 +181,23 @@ The server exposes the following MCP tools and resources:
|
|
| 167 |
- **Learning Path Tools** (learning_path_tools.py)
|
| 168 |
- `get_learning_path`: Generate personalized learning paths based on student level and target concepts
|
| 169 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 170 |
- **Memory Tools** (v0.2.0)
|
| 171 |
- `read_memory_tool`: Retrieve stored context from the Memory Bank
|
| 172 |
- `write_memory_tool`: Store new contextual information in the Memory Bank
|
|
@@ -201,7 +232,9 @@ tutorx-mcp/
|
|
| 201 |
│ │ ├── lesson_tools.py # Lesson generation tools
|
| 202 |
│ │ ├── ocr_tools.py # Document OCR tools
|
| 203 |
│ │ ├── interaction_tools.py # Student interaction tools
|
| 204 |
-
│ │
|
|
|
|
|
|
|
| 205 |
│ └── prompts/ # LLM prompt templates
|
| 206 |
├── tests/ # Test suite
|
| 207 |
│ ├── test_mcp_server.py # MCP server tests
|
|
@@ -275,6 +308,7 @@ python run_tests.py
|
|
| 275 |
## Documentation
|
| 276 |
|
| 277 |
- [Project Analysis](PROJECT_ANALYSIS.md): Comprehensive analysis of architecture, implementation, and product features
|
|
|
|
| 278 |
- [MCP Protocol](docs/mcp.md): Details about the Model Context Protocol
|
| 279 |
- [Product Requirements](docs/prd.md): Original requirements document
|
| 280 |
- [SDK Documentation](docs/sdk.md): Client SDK usage
|
|
|
|
| 18 |
|
| 19 |
TutorX-MCP is an adaptive, multi-modal, and collaborative AI tutoring platform that leverages the Model Context Protocol (MCP) for tool integration and Gradio for user-friendly interfaces. It provides a range of educational features accessible via both MCP clients and a dedicated web interface.
|
| 20 |
|
| 21 |
+
## ✨ New: Enhanced AI Integration & Capabilities
|
| 22 |
+
|
| 23 |
+
**🤖 Contextualized AI Tutoring:**
|
| 24 |
+
- **Session-based tutoring** with persistent context and memory
|
| 25 |
+
- **Step-by-step guidance** that breaks complex concepts into manageable steps
|
| 26 |
+
- **Alternative explanations** using multiple approaches (visual, analogy, real-world)
|
| 27 |
+
- **Adaptive responses** that adjust to student understanding levels
|
| 28 |
+
|
| 29 |
+
**🎨 Advanced Automated Content Generation:**
|
| 30 |
+
- **Interactive exercises** with multiple components and adaptive features
|
| 31 |
+
- **Scenario-based learning** with realistic contexts and decision points
|
| 32 |
+
- **Gamified content** with game mechanics and progressive difficulty
|
| 33 |
+
- **Multi-modal content** supporting different learning styles
|
| 34 |
+
|
| 35 |

|
| 36 |
|
| 37 |
For a comprehensive analysis of the project from architectural, development, and product perspectives, please see our [Project Analysis Document](PROJECT_ANALYSIS.md).
|
|
|
|
| 181 |
- **Learning Path Tools** (learning_path_tools.py)
|
| 182 |
- `get_learning_path`: Generate personalized learning paths based on student level and target concepts
|
| 183 |
|
| 184 |
+
- **AI Tutoring Tools** (ai_tutor_tools.py) ✨ **NEW**
|
| 185 |
+
- `start_tutoring_session`: Start contextualized AI tutoring sessions with memory
|
| 186 |
+
- `ai_tutor_chat`: Interactive chat with AI tutor providing personalized responses
|
| 187 |
+
- `get_step_by_step_guidance`: Break down complex concepts into manageable steps
|
| 188 |
+
- `get_alternative_explanations`: Multiple explanation approaches for different learning styles
|
| 189 |
+
- `update_student_understanding`: Track and adapt to student understanding levels
|
| 190 |
+
- `end_tutoring_session`: Generate comprehensive session summaries
|
| 191 |
+
|
| 192 |
+
- **Content Generation Tools** (content_generation_tools.py) ✨ **NEW**
|
| 193 |
+
- `generate_interactive_exercise`: Create engaging interactive exercises with multiple components
|
| 194 |
+
- `generate_adaptive_content_sequence`: Build adaptive content that adjusts to student performance
|
| 195 |
+
- `generate_scenario_based_learning`: Create realistic scenario-based learning experiences
|
| 196 |
+
- `generate_multimodal_content`: Generate content for different learning modalities
|
| 197 |
+
- `generate_adaptive_assessment`: Create assessments that adapt based on student responses
|
| 198 |
+
- `generate_gamified_content`: Generate game-based learning content with mechanics
|
| 199 |
+
- `validate_generated_content`: Quality-check and validate educational content
|
| 200 |
+
|
| 201 |
- **Memory Tools** (v0.2.0)
|
| 202 |
- `read_memory_tool`: Retrieve stored context from the Memory Bank
|
| 203 |
- `write_memory_tool`: Store new contextual information in the Memory Bank
|
|
|
|
| 232 |
│ │ ├── lesson_tools.py # Lesson generation tools
|
| 233 |
│ │ ├── ocr_tools.py # Document OCR tools
|
| 234 |
│ │ ├── interaction_tools.py # Student interaction tools
|
| 235 |
+
│ │ ├── learning_path_tools.py # Learning path tools
|
| 236 |
+
│ │ ├── ai_tutor_tools.py # ✨ Contextualized AI tutoring
|
| 237 |
+
│ │ └── content_generation_tools.py # ✨ Advanced content generation
|
| 238 |
│ └── prompts/ # LLM prompt templates
|
| 239 |
├── tests/ # Test suite
|
| 240 |
│ ├── test_mcp_server.py # MCP server tests
|
|
|
|
| 308 |
## Documentation
|
| 309 |
|
| 310 |
- [Project Analysis](PROJECT_ANALYSIS.md): Comprehensive analysis of architecture, implementation, and product features
|
| 311 |
+
- [AI Integration Features](docs/AI_INTEGRATION_FEATURES.md): ✨ **NEW** - Detailed guide to contextualized AI tutoring and content generation
|
| 312 |
- [MCP Protocol](docs/mcp.md): Details about the Model Context Protocol
|
| 313 |
- [Product Requirements](docs/prd.md): Original requirements document
|
| 314 |
- [SDK Documentation](docs/sdk.md): Client SDK usage
|
app.py
CHANGED
|
@@ -493,6 +493,64 @@ def sync_get_progress_summary(student_id, days=7):
|
|
| 493 |
except Exception as e:
|
| 494 |
return {"error": str(e)}
|
| 495 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 496 |
# Define async functions outside the interface
|
| 497 |
async def on_generate_quiz(concept, difficulty):
|
| 498 |
try:
|
|
@@ -728,6 +786,120 @@ async def document_ocr_async(file):
|
|
| 728 |
except Exception as e:
|
| 729 |
return {"error": f"Error processing document: {str(e)}", "success": False}
|
| 730 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 731 |
# Create Gradio interface
|
| 732 |
def create_gradio_interface():
|
| 733 |
# Set a default student ID for the demo
|
|
@@ -1093,9 +1265,225 @@ def create_gradio_interface():
|
|
| 1093 |
inputs=[doc_input],
|
| 1094 |
outputs=[doc_output]
|
| 1095 |
)
|
| 1096 |
-
|
| 1097 |
-
# Tab 4:
|
| 1098 |
-
with gr.Tab("4
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1099 |
gr.Markdown("## Adaptive Learning System")
|
| 1100 |
gr.Markdown("Experience personalized learning with real-time adaptation based on your performance.")
|
| 1101 |
|
|
@@ -1264,8 +1652,8 @@ def create_gradio_interface():
|
|
| 1264 |
- **Engagement Metrics**: Measures learning engagement
|
| 1265 |
""")
|
| 1266 |
|
| 1267 |
-
# Tab
|
| 1268 |
-
with gr.Tab("
|
| 1269 |
gr.Markdown("## Plagiarism Detection")
|
| 1270 |
|
| 1271 |
with gr.Row():
|
|
|
|
| 493 |
except Exception as e:
|
| 494 |
return {"error": str(e)}
|
| 495 |
|
| 496 |
+
# AI Tutoring synchronous wrappers
|
| 497 |
+
def sync_start_tutoring_session(student_id, subject, learning_objectives):
|
| 498 |
+
"""Synchronous wrapper for start_tutoring_session_async"""
|
| 499 |
+
try:
|
| 500 |
+
return asyncio.run(start_tutoring_session_async(student_id, subject, learning_objectives))
|
| 501 |
+
except Exception as e:
|
| 502 |
+
return {"error": str(e)}
|
| 503 |
+
|
| 504 |
+
def sync_ai_tutor_chat(session_id, student_query, request_type):
|
| 505 |
+
"""Synchronous wrapper for ai_tutor_chat_async"""
|
| 506 |
+
try:
|
| 507 |
+
return asyncio.run(ai_tutor_chat_async(session_id, student_query, request_type))
|
| 508 |
+
except Exception as e:
|
| 509 |
+
return {"error": str(e)}
|
| 510 |
+
|
| 511 |
+
def sync_get_step_by_step_guidance(session_id, concept, current_step):
|
| 512 |
+
"""Synchronous wrapper for get_step_by_step_guidance_async"""
|
| 513 |
+
try:
|
| 514 |
+
return asyncio.run(get_step_by_step_guidance_async(session_id, concept, current_step))
|
| 515 |
+
except Exception as e:
|
| 516 |
+
return {"error": str(e)}
|
| 517 |
+
|
| 518 |
+
def sync_get_alternative_explanations(session_id, concept, explanation_types):
|
| 519 |
+
"""Synchronous wrapper for get_alternative_explanations_async"""
|
| 520 |
+
try:
|
| 521 |
+
return asyncio.run(get_alternative_explanations_async(session_id, concept, explanation_types))
|
| 522 |
+
except Exception as e:
|
| 523 |
+
return {"error": str(e)}
|
| 524 |
+
|
| 525 |
+
def sync_end_tutoring_session(session_id, session_summary):
|
| 526 |
+
"""Synchronous wrapper for end_tutoring_session_async"""
|
| 527 |
+
try:
|
| 528 |
+
return asyncio.run(end_tutoring_session_async(session_id, session_summary))
|
| 529 |
+
except Exception as e:
|
| 530 |
+
return {"error": str(e)}
|
| 531 |
+
|
| 532 |
+
# Content Generation synchronous wrappers
|
| 533 |
+
def sync_generate_interactive_exercise(concept, exercise_type, difficulty_level, student_level):
|
| 534 |
+
"""Synchronous wrapper for generate_interactive_exercise_async"""
|
| 535 |
+
try:
|
| 536 |
+
return asyncio.run(generate_interactive_exercise_async(concept, exercise_type, difficulty_level, student_level))
|
| 537 |
+
except Exception as e:
|
| 538 |
+
return {"error": str(e)}
|
| 539 |
+
|
| 540 |
+
def sync_generate_scenario_based_learning(concept, scenario_type, complexity_level):
|
| 541 |
+
"""Synchronous wrapper for generate_scenario_based_learning_async"""
|
| 542 |
+
try:
|
| 543 |
+
return asyncio.run(generate_scenario_based_learning_async(concept, scenario_type, complexity_level))
|
| 544 |
+
except Exception as e:
|
| 545 |
+
return {"error": str(e)}
|
| 546 |
+
|
| 547 |
+
def sync_generate_gamified_content(concept, game_type, target_age_group):
|
| 548 |
+
"""Synchronous wrapper for generate_gamified_content_async"""
|
| 549 |
+
try:
|
| 550 |
+
return asyncio.run(generate_gamified_content_async(concept, game_type, target_age_group))
|
| 551 |
+
except Exception as e:
|
| 552 |
+
return {"error": str(e)}
|
| 553 |
+
|
| 554 |
# Define async functions outside the interface
|
| 555 |
async def on_generate_quiz(concept, difficulty):
|
| 556 |
try:
|
|
|
|
| 786 |
except Exception as e:
|
| 787 |
return {"error": f"Error processing document: {str(e)}", "success": False}
|
| 788 |
|
| 789 |
+
# AI Tutoring async functions
|
| 790 |
+
async def start_tutoring_session_async(student_id, subject, learning_objectives):
|
| 791 |
+
try:
|
| 792 |
+
async with sse_client(SERVER_URL) as (sse, write):
|
| 793 |
+
async with ClientSession(sse, write) as session:
|
| 794 |
+
await session.initialize()
|
| 795 |
+
response = await session.call_tool("start_tutoring_session", {
|
| 796 |
+
"student_id": student_id,
|
| 797 |
+
"subject": subject,
|
| 798 |
+
"learning_objectives": learning_objectives
|
| 799 |
+
})
|
| 800 |
+
return await extract_response_content(response)
|
| 801 |
+
except Exception as e:
|
| 802 |
+
return {"error": str(e)}
|
| 803 |
+
|
| 804 |
+
async def ai_tutor_chat_async(session_id, student_query, request_type):
|
| 805 |
+
try:
|
| 806 |
+
async with sse_client(SERVER_URL) as (sse, write):
|
| 807 |
+
async with ClientSession(sse, write) as session:
|
| 808 |
+
await session.initialize()
|
| 809 |
+
response = await session.call_tool("ai_tutor_chat", {
|
| 810 |
+
"session_id": session_id,
|
| 811 |
+
"student_query": student_query,
|
| 812 |
+
"request_type": request_type
|
| 813 |
+
})
|
| 814 |
+
return await extract_response_content(response)
|
| 815 |
+
except Exception as e:
|
| 816 |
+
return {"error": str(e)}
|
| 817 |
+
|
| 818 |
+
async def get_step_by_step_guidance_async(session_id, concept, current_step):
|
| 819 |
+
try:
|
| 820 |
+
async with sse_client(SERVER_URL) as (sse, write):
|
| 821 |
+
async with ClientSession(sse, write) as session:
|
| 822 |
+
await session.initialize()
|
| 823 |
+
response = await session.call_tool("get_step_by_step_guidance", {
|
| 824 |
+
"session_id": session_id,
|
| 825 |
+
"concept": concept,
|
| 826 |
+
"current_step": current_step
|
| 827 |
+
})
|
| 828 |
+
return await extract_response_content(response)
|
| 829 |
+
except Exception as e:
|
| 830 |
+
return {"error": str(e)}
|
| 831 |
+
|
| 832 |
+
async def get_alternative_explanations_async(session_id, concept, explanation_types):
|
| 833 |
+
try:
|
| 834 |
+
async with sse_client(SERVER_URL) as (sse, write):
|
| 835 |
+
async with ClientSession(sse, write) as session:
|
| 836 |
+
await session.initialize()
|
| 837 |
+
response = await session.call_tool("get_alternative_explanations", {
|
| 838 |
+
"session_id": session_id,
|
| 839 |
+
"concept": concept,
|
| 840 |
+
"explanation_types": explanation_types
|
| 841 |
+
})
|
| 842 |
+
return await extract_response_content(response)
|
| 843 |
+
except Exception as e:
|
| 844 |
+
return {"error": str(e)}
|
| 845 |
+
|
| 846 |
+
async def end_tutoring_session_async(session_id, session_summary):
|
| 847 |
+
try:
|
| 848 |
+
async with sse_client(SERVER_URL) as (sse, write):
|
| 849 |
+
async with ClientSession(sse, write) as session:
|
| 850 |
+
await session.initialize()
|
| 851 |
+
response = await session.call_tool("end_tutoring_session", {
|
| 852 |
+
"session_id": session_id,
|
| 853 |
+
"session_summary": session_summary
|
| 854 |
+
})
|
| 855 |
+
return await extract_response_content(response)
|
| 856 |
+
except Exception as e:
|
| 857 |
+
return {"error": str(e)}
|
| 858 |
+
|
| 859 |
+
# Content Generation async functions
|
| 860 |
+
async def generate_interactive_exercise_async(concept, exercise_type, difficulty_level, student_level):
|
| 861 |
+
try:
|
| 862 |
+
async with sse_client(SERVER_URL) as (sse, write):
|
| 863 |
+
async with ClientSession(sse, write) as session:
|
| 864 |
+
await session.initialize()
|
| 865 |
+
response = await session.call_tool("generate_interactive_exercise", {
|
| 866 |
+
"concept": concept,
|
| 867 |
+
"exercise_type": exercise_type,
|
| 868 |
+
"difficulty_level": difficulty_level,
|
| 869 |
+
"student_level": student_level
|
| 870 |
+
})
|
| 871 |
+
return await extract_response_content(response)
|
| 872 |
+
except Exception as e:
|
| 873 |
+
return {"error": str(e)}
|
| 874 |
+
|
| 875 |
+
async def generate_scenario_based_learning_async(concept, scenario_type, complexity_level):
|
| 876 |
+
try:
|
| 877 |
+
async with sse_client(SERVER_URL) as (sse, write):
|
| 878 |
+
async with ClientSession(sse, write) as session:
|
| 879 |
+
await session.initialize()
|
| 880 |
+
response = await session.call_tool("generate_scenario_based_learning", {
|
| 881 |
+
"concept": concept,
|
| 882 |
+
"scenario_type": scenario_type,
|
| 883 |
+
"complexity_level": complexity_level
|
| 884 |
+
})
|
| 885 |
+
return await extract_response_content(response)
|
| 886 |
+
except Exception as e:
|
| 887 |
+
return {"error": str(e)}
|
| 888 |
+
|
| 889 |
+
async def generate_gamified_content_async(concept, game_type, target_age_group):
|
| 890 |
+
try:
|
| 891 |
+
async with sse_client(SERVER_URL) as (sse, write):
|
| 892 |
+
async with ClientSession(sse, write) as session:
|
| 893 |
+
await session.initialize()
|
| 894 |
+
response = await session.call_tool("generate_gamified_content", {
|
| 895 |
+
"concept": concept,
|
| 896 |
+
"game_type": game_type,
|
| 897 |
+
"target_age_group": target_age_group
|
| 898 |
+
})
|
| 899 |
+
return await extract_response_content(response)
|
| 900 |
+
except Exception as e:
|
| 901 |
+
return {"error": str(e)}
|
| 902 |
+
|
| 903 |
# Create Gradio interface
|
| 904 |
def create_gradio_interface():
|
| 905 |
# Set a default student ID for the demo
|
|
|
|
| 1265 |
inputs=[doc_input],
|
| 1266 |
outputs=[doc_output]
|
| 1267 |
)
|
| 1268 |
+
|
| 1269 |
+
# Tab 4: AI Tutoring
|
| 1270 |
+
with gr.Tab("4 🤖 AI Tutoring", elem_id="ai_tutoring_tab"):
|
| 1271 |
+
gr.Markdown("## Contextualized AI Tutoring")
|
| 1272 |
+
gr.Markdown("Experience personalized AI tutoring with step-by-step guidance and alternative explanations.")
|
| 1273 |
+
|
| 1274 |
+
with gr.Accordion("ℹ️ How AI Tutoring Works", open=False):
|
| 1275 |
+
gr.Markdown("""
|
| 1276 |
+
### 🎯 Contextualized Learning
|
| 1277 |
+
- **Session Memory**: AI remembers your conversation and adapts responses
|
| 1278 |
+
- **Step-by-Step Guidance**: Break down complex concepts into manageable steps
|
| 1279 |
+
- **Alternative Explanations**: Multiple ways to understand the same concept
|
| 1280 |
+
- **Personalized Feedback**: Responses tailored to your understanding level
|
| 1281 |
+
|
| 1282 |
+
### 🚀 Getting Started
|
| 1283 |
+
1. Start a tutoring session with your preferred subject
|
| 1284 |
+
2. Ask questions or request explanations
|
| 1285 |
+
3. Get step-by-step guidance for complex topics
|
| 1286 |
+
4. Request alternative explanations if needed
|
| 1287 |
+
5. End session to get a comprehensive summary
|
| 1288 |
+
""")
|
| 1289 |
+
|
| 1290 |
+
# Tutoring Session Management
|
| 1291 |
+
with gr.Accordion("📚 Start Tutoring Session", open=True):
|
| 1292 |
+
with gr.Row():
|
| 1293 |
+
with gr.Column():
|
| 1294 |
+
tutor_student_id = gr.Textbox(label="Student ID", value=student_id)
|
| 1295 |
+
tutor_subject = gr.Textbox(label="Subject", value="Mathematics", placeholder="e.g., Mathematics, Physics, Chemistry")
|
| 1296 |
+
tutor_objectives = gr.Textbox(
|
| 1297 |
+
label="Learning Objectives (optional)",
|
| 1298 |
+
placeholder="e.g., Understand quadratic equations, Learn calculus basics",
|
| 1299 |
+
lines=2
|
| 1300 |
+
)
|
| 1301 |
+
start_tutor_btn = gr.Button("Start Tutoring Session", variant="primary")
|
| 1302 |
+
|
| 1303 |
+
with gr.Column():
|
| 1304 |
+
tutor_session_output = gr.JSON(label="Session Information")
|
| 1305 |
+
|
| 1306 |
+
# AI Chat Interface
|
| 1307 |
+
with gr.Accordion("💬 Chat with AI Tutor", open=True):
|
| 1308 |
+
with gr.Row():
|
| 1309 |
+
with gr.Column():
|
| 1310 |
+
chat_session_id = gr.Textbox(label="Session ID", placeholder="Enter session ID from above")
|
| 1311 |
+
chat_query = gr.Textbox(
|
| 1312 |
+
label="Ask Your Question",
|
| 1313 |
+
placeholder="e.g., How do I solve quadratic equations?",
|
| 1314 |
+
lines=3
|
| 1315 |
+
)
|
| 1316 |
+
chat_request_type = gr.Dropdown(
|
| 1317 |
+
choices=["explanation", "step_by_step", "alternative", "practice", "clarification"],
|
| 1318 |
+
value="explanation",
|
| 1319 |
+
label="Request Type"
|
| 1320 |
+
)
|
| 1321 |
+
chat_btn = gr.Button("Ask AI Tutor", variant="primary")
|
| 1322 |
+
|
| 1323 |
+
with gr.Column():
|
| 1324 |
+
chat_response = gr.JSON(label="AI Tutor Response")
|
| 1325 |
+
|
| 1326 |
+
# Step-by-Step Guidance
|
| 1327 |
+
with gr.Accordion("📋 Step-by-Step Guidance", open=True):
|
| 1328 |
+
with gr.Row():
|
| 1329 |
+
with gr.Column():
|
| 1330 |
+
step_session_id = gr.Textbox(label="Session ID")
|
| 1331 |
+
step_concept = gr.Textbox(label="Concept", placeholder="e.g., Solving quadratic equations")
|
| 1332 |
+
step_current = gr.Number(label="Current Step", value=1, minimum=1)
|
| 1333 |
+
get_steps_btn = gr.Button("Get Step-by-Step Guidance")
|
| 1334 |
+
|
| 1335 |
+
with gr.Column():
|
| 1336 |
+
steps_output = gr.JSON(label="Step-by-Step Guidance")
|
| 1337 |
+
|
| 1338 |
+
# Alternative Explanations
|
| 1339 |
+
with gr.Accordion("🔄 Alternative Explanations", open=True):
|
| 1340 |
+
with gr.Row():
|
| 1341 |
+
with gr.Column():
|
| 1342 |
+
alt_session_id = gr.Textbox(label="Session ID")
|
| 1343 |
+
alt_concept = gr.Textbox(label="Concept", placeholder="e.g., Photosynthesis")
|
| 1344 |
+
alt_types = gr.CheckboxGroup(
|
| 1345 |
+
choices=["visual", "analogy", "real_world", "simplified", "technical"],
|
| 1346 |
+
value=["visual", "analogy", "real_world"],
|
| 1347 |
+
label="Explanation Types"
|
| 1348 |
+
)
|
| 1349 |
+
get_alt_btn = gr.Button("Get Alternative Explanations")
|
| 1350 |
+
|
| 1351 |
+
with gr.Column():
|
| 1352 |
+
alt_output = gr.JSON(label="Alternative Explanations")
|
| 1353 |
+
|
| 1354 |
+
# Session Management
|
| 1355 |
+
with gr.Accordion("🔚 End Session & Summary", open=True):
|
| 1356 |
+
with gr.Row():
|
| 1357 |
+
with gr.Column():
|
| 1358 |
+
end_session_id = gr.Textbox(label="Session ID")
|
| 1359 |
+
session_summary = gr.Textbox(
|
| 1360 |
+
label="Session Summary (optional)",
|
| 1361 |
+
placeholder="What did you learn? Any feedback?",
|
| 1362 |
+
lines=3
|
| 1363 |
+
)
|
| 1364 |
+
end_session_btn = gr.Button("End Session & Get Summary", variant="secondary")
|
| 1365 |
+
|
| 1366 |
+
with gr.Column():
|
| 1367 |
+
session_end_output = gr.JSON(label="Session Summary")
|
| 1368 |
+
|
| 1369 |
+
# Connect all AI tutoring buttons
|
| 1370 |
+
start_tutor_btn.click(
|
| 1371 |
+
fn=lambda sid, subj, obj: sync_start_tutoring_session(sid, subj, obj.split(',') if obj else []),
|
| 1372 |
+
inputs=[tutor_student_id, tutor_subject, tutor_objectives],
|
| 1373 |
+
outputs=[tutor_session_output]
|
| 1374 |
+
)
|
| 1375 |
+
|
| 1376 |
+
chat_btn.click(
|
| 1377 |
+
fn=sync_ai_tutor_chat,
|
| 1378 |
+
inputs=[chat_session_id, chat_query, chat_request_type],
|
| 1379 |
+
outputs=[chat_response]
|
| 1380 |
+
)
|
| 1381 |
+
|
| 1382 |
+
get_steps_btn.click(
|
| 1383 |
+
fn=sync_get_step_by_step_guidance,
|
| 1384 |
+
inputs=[step_session_id, step_concept, step_current],
|
| 1385 |
+
outputs=[steps_output]
|
| 1386 |
+
)
|
| 1387 |
+
|
| 1388 |
+
get_alt_btn.click(
|
| 1389 |
+
fn=sync_get_alternative_explanations,
|
| 1390 |
+
inputs=[alt_session_id, alt_concept, alt_types],
|
| 1391 |
+
outputs=[alt_output]
|
| 1392 |
+
)
|
| 1393 |
+
|
| 1394 |
+
end_session_btn.click(
|
| 1395 |
+
fn=sync_end_tutoring_session,
|
| 1396 |
+
inputs=[end_session_id, session_summary],
|
| 1397 |
+
outputs=[session_end_output]
|
| 1398 |
+
)
|
| 1399 |
+
|
| 1400 |
+
# Tab 5: Content Generation
|
| 1401 |
+
with gr.Tab("5 🎨 Content Generation", elem_id="content_generation_tab"):
|
| 1402 |
+
gr.Markdown("## Advanced Content Generation")
|
| 1403 |
+
gr.Markdown("Generate interactive exercises, scenarios, and gamified content automatically.")
|
| 1404 |
+
|
| 1405 |
+
# Interactive Exercise Generation
|
| 1406 |
+
with gr.Accordion("🎯 Interactive Exercise Generation", open=True):
|
| 1407 |
+
with gr.Row():
|
| 1408 |
+
with gr.Column():
|
| 1409 |
+
ex_concept = gr.Textbox(label="Concept", placeholder="e.g., Photosynthesis, Linear Algebra")
|
| 1410 |
+
ex_type = gr.Dropdown(
|
| 1411 |
+
choices=["problem_solving", "simulation", "case_study", "lab", "project"],
|
| 1412 |
+
value="problem_solving",
|
| 1413 |
+
label="Exercise Type"
|
| 1414 |
+
)
|
| 1415 |
+
ex_difficulty = gr.Slider(minimum=0.1, maximum=1.0, value=0.5, step=0.1, label="Difficulty Level")
|
| 1416 |
+
ex_level = gr.Dropdown(
|
| 1417 |
+
choices=["beginner", "intermediate", "advanced"],
|
| 1418 |
+
value="intermediate",
|
| 1419 |
+
label="Student Level"
|
| 1420 |
+
)
|
| 1421 |
+
gen_exercise_btn = gr.Button("Generate Interactive Exercise", variant="primary")
|
| 1422 |
+
|
| 1423 |
+
with gr.Column():
|
| 1424 |
+
exercise_output = gr.JSON(label="Generated Exercise")
|
| 1425 |
+
|
| 1426 |
+
# Scenario-Based Learning
|
| 1427 |
+
with gr.Accordion("🎭 Scenario-Based Learning", open=True):
|
| 1428 |
+
with gr.Row():
|
| 1429 |
+
with gr.Column():
|
| 1430 |
+
scenario_concept = gr.Textbox(label="Concept", placeholder="e.g., Climate Change, Economics")
|
| 1431 |
+
scenario_type = gr.Dropdown(
|
| 1432 |
+
choices=["real_world", "historical", "futuristic", "problem_solving"],
|
| 1433 |
+
value="real_world",
|
| 1434 |
+
label="Scenario Type"
|
| 1435 |
+
)
|
| 1436 |
+
scenario_complexity = gr.Dropdown(
|
| 1437 |
+
choices=["simple", "moderate", "complex"],
|
| 1438 |
+
value="moderate",
|
| 1439 |
+
label="Complexity Level"
|
| 1440 |
+
)
|
| 1441 |
+
gen_scenario_btn = gr.Button("Generate Scenario", variant="primary")
|
| 1442 |
+
|
| 1443 |
+
with gr.Column():
|
| 1444 |
+
scenario_output = gr.JSON(label="Generated Scenario")
|
| 1445 |
+
|
| 1446 |
+
# Gamified Content
|
| 1447 |
+
with gr.Accordion("🎮 Gamified Content Generation", open=True):
|
| 1448 |
+
with gr.Row():
|
| 1449 |
+
with gr.Column():
|
| 1450 |
+
game_concept = gr.Textbox(label="Concept", placeholder="e.g., Fractions, Chemical Reactions")
|
| 1451 |
+
game_type = gr.Dropdown(
|
| 1452 |
+
choices=["quest", "puzzle", "simulation", "competition", "story"],
|
| 1453 |
+
value="quest",
|
| 1454 |
+
label="Game Type"
|
| 1455 |
+
)
|
| 1456 |
+
game_age = gr.Dropdown(
|
| 1457 |
+
choices=["child", "teen", "adult"],
|
| 1458 |
+
value="teen",
|
| 1459 |
+
label="Target Age Group"
|
| 1460 |
+
)
|
| 1461 |
+
gen_game_btn = gr.Button("Generate Gamified Content", variant="primary")
|
| 1462 |
+
|
| 1463 |
+
with gr.Column():
|
| 1464 |
+
game_output = gr.JSON(label="Generated Game Content")
|
| 1465 |
+
|
| 1466 |
+
# Connect content generation buttons
|
| 1467 |
+
gen_exercise_btn.click(
|
| 1468 |
+
fn=sync_generate_interactive_exercise,
|
| 1469 |
+
inputs=[ex_concept, ex_type, ex_difficulty, ex_level],
|
| 1470 |
+
outputs=[exercise_output]
|
| 1471 |
+
)
|
| 1472 |
+
|
| 1473 |
+
gen_scenario_btn.click(
|
| 1474 |
+
fn=sync_generate_scenario_based_learning,
|
| 1475 |
+
inputs=[scenario_concept, scenario_type, scenario_complexity],
|
| 1476 |
+
outputs=[scenario_output]
|
| 1477 |
+
)
|
| 1478 |
+
|
| 1479 |
+
gen_game_btn.click(
|
| 1480 |
+
fn=sync_generate_gamified_content,
|
| 1481 |
+
inputs=[game_concept, game_type, game_age],
|
| 1482 |
+
outputs=[game_output]
|
| 1483 |
+
)
|
| 1484 |
+
|
| 1485 |
+
# Tab 6: Adaptive Learning
|
| 1486 |
+
with gr.Tab("6 🧠 Adaptive Learning", elem_id="adaptive_learning_tab"):
|
| 1487 |
gr.Markdown("## Adaptive Learning System")
|
| 1488 |
gr.Markdown("Experience personalized learning with real-time adaptation based on your performance.")
|
| 1489 |
|
|
|
|
| 1652 |
- **Engagement Metrics**: Measures learning engagement
|
| 1653 |
""")
|
| 1654 |
|
| 1655 |
+
# Tab 7: Data Analytics
|
| 1656 |
+
with gr.Tab("7 Data Analytics", elem_id="data_analytics_tab"):
|
| 1657 |
gr.Markdown("## Plagiarism Detection")
|
| 1658 |
|
| 1659 |
with gr.Row():
|
docs/AI_INTEGRATION_FEATURES.md
ADDED
|
@@ -0,0 +1,237 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# AI Integration and Capabilities - TutorX-MCP
|
| 2 |
+
|
| 3 |
+
## Overview
|
| 4 |
+
|
| 5 |
+
This document describes the enhanced AI integration and capabilities implemented in TutorX-MCP, focusing on contextualized AI tutoring and advanced automated content generation.
|
| 6 |
+
|
| 7 |
+
## 🤖 Contextualized AI Tutoring
|
| 8 |
+
|
| 9 |
+
### Features
|
| 10 |
+
|
| 11 |
+
#### 1. **Session-Based Tutoring**
|
| 12 |
+
- **Persistent Context**: AI maintains conversation history and adapts responses
|
| 13 |
+
- **Student Profiling**: Tracks understanding levels and learning preferences
|
| 14 |
+
- **Subject Specialization**: Tailored tutoring for specific subjects
|
| 15 |
+
|
| 16 |
+
#### 2. **Step-by-Step Guidance**
|
| 17 |
+
- **Progressive Learning**: Breaks complex concepts into manageable steps
|
| 18 |
+
- **Adaptive Pacing**: Adjusts based on student understanding
|
| 19 |
+
- **Checkpoint Validation**: Verifies understanding at key points
|
| 20 |
+
|
| 21 |
+
#### 3. **Alternative Explanations**
|
| 22 |
+
- **Multiple Approaches**: Visual, analogy-based, real-world applications
|
| 23 |
+
- **Learning Style Adaptation**: Matches student's preferred learning style
|
| 24 |
+
- **Difficulty Scaling**: Provides simplified or technical explanations as needed
|
| 25 |
+
|
| 26 |
+
### API Endpoints
|
| 27 |
+
|
| 28 |
+
#### Start Tutoring Session
|
| 29 |
+
```http
|
| 30 |
+
POST /api/start-tutoring-session
|
| 31 |
+
Content-Type: application/json
|
| 32 |
+
|
| 33 |
+
{
|
| 34 |
+
"student_id": "student_001",
|
| 35 |
+
"subject": "Mathematics",
|
| 36 |
+
"learning_objectives": ["Understand quadratic equations", "Learn factoring"]
|
| 37 |
+
}
|
| 38 |
+
```
|
| 39 |
+
|
| 40 |
+
#### Chat with AI Tutor
|
| 41 |
+
```http
|
| 42 |
+
POST /api/ai-tutor-chat
|
| 43 |
+
Content-Type: application/json
|
| 44 |
+
|
| 45 |
+
{
|
| 46 |
+
"session_id": "session_uuid",
|
| 47 |
+
"student_query": "How do I solve quadratic equations?",
|
| 48 |
+
"request_type": "step_by_step"
|
| 49 |
+
}
|
| 50 |
+
```
|
| 51 |
+
|
| 52 |
+
#### Get Step-by-Step Guidance
|
| 53 |
+
```http
|
| 54 |
+
POST /api/step-by-step-guidance
|
| 55 |
+
Content-Type: application/json
|
| 56 |
+
|
| 57 |
+
{
|
| 58 |
+
"session_id": "session_uuid",
|
| 59 |
+
"concept": "Solving quadratic equations",
|
| 60 |
+
"current_step": 1
|
| 61 |
+
}
|
| 62 |
+
```
|
| 63 |
+
|
| 64 |
+
#### Get Alternative Explanations
|
| 65 |
+
```http
|
| 66 |
+
POST /api/alternative-explanations
|
| 67 |
+
Content-Type: application/json
|
| 68 |
+
|
| 69 |
+
{
|
| 70 |
+
"session_id": "session_uuid",
|
| 71 |
+
"concept": "Quadratic formula",
|
| 72 |
+
"explanation_types": ["visual", "analogy", "real_world"]
|
| 73 |
+
}
|
| 74 |
+
```
|
| 75 |
+
|
| 76 |
+
## 🎨 Advanced Automated Content Generation
|
| 77 |
+
|
| 78 |
+
### Features
|
| 79 |
+
|
| 80 |
+
#### 1. **Interactive Exercise Generation**
|
| 81 |
+
- **Multiple Exercise Types**: Problem-solving, simulations, case studies, labs, projects
|
| 82 |
+
- **Adaptive Difficulty**: Automatically calibrated based on student level
|
| 83 |
+
- **Assessment Integration**: Built-in evaluation criteria and rubrics
|
| 84 |
+
|
| 85 |
+
#### 2. **Scenario-Based Learning**
|
| 86 |
+
- **Realistic Contexts**: Real-world, historical, and futuristic scenarios
|
| 87 |
+
- **Decision Points**: Interactive choices with consequences
|
| 88 |
+
- **Multi-Path Solutions**: Multiple valid approaches to problems
|
| 89 |
+
|
| 90 |
+
#### 3. **Gamified Content**
|
| 91 |
+
- **Game Mechanics**: Quests, puzzles, simulations, competitions
|
| 92 |
+
- **Progressive Difficulty**: Leveled content with achievements
|
| 93 |
+
- **Social Features**: Collaborative and competitive elements
|
| 94 |
+
|
| 95 |
+
#### 4. **Multi-Modal Content**
|
| 96 |
+
- **Learning Style Support**: Visual, auditory, kinesthetic, reading/writing
|
| 97 |
+
- **Accessibility Features**: Content adapted for different abilities
|
| 98 |
+
- **Technology Integration**: Enhanced with digital tools
|
| 99 |
+
|
| 100 |
+
### API Endpoints
|
| 101 |
+
|
| 102 |
+
#### Generate Interactive Exercise
|
| 103 |
+
```http
|
| 104 |
+
POST /api/generate-interactive-exercise
|
| 105 |
+
Content-Type: application/json
|
| 106 |
+
|
| 107 |
+
{
|
| 108 |
+
"concept": "Photosynthesis",
|
| 109 |
+
"exercise_type": "simulation",
|
| 110 |
+
"difficulty_level": 0.6,
|
| 111 |
+
"student_level": "intermediate"
|
| 112 |
+
}
|
| 113 |
+
```
|
| 114 |
+
|
| 115 |
+
#### Generate Scenario-Based Learning
|
| 116 |
+
```http
|
| 117 |
+
POST /api/generate-scenario-based-learning
|
| 118 |
+
Content-Type: application/json
|
| 119 |
+
|
| 120 |
+
{
|
| 121 |
+
"concept": "Climate Change",
|
| 122 |
+
"scenario_type": "real_world",
|
| 123 |
+
"complexity_level": "moderate"
|
| 124 |
+
}
|
| 125 |
+
```
|
| 126 |
+
|
| 127 |
+
#### Generate Gamified Content
|
| 128 |
+
```http
|
| 129 |
+
POST /api/generate-gamified-content
|
| 130 |
+
Content-Type: application/json
|
| 131 |
+
|
| 132 |
+
{
|
| 133 |
+
"concept": "Fractions",
|
| 134 |
+
"game_type": "quest",
|
| 135 |
+
"target_age_group": "teen"
|
| 136 |
+
}
|
| 137 |
+
```
|
| 138 |
+
|
| 139 |
+
## 🚀 Usage Examples
|
| 140 |
+
|
| 141 |
+
### Example 1: Complete Tutoring Session
|
| 142 |
+
|
| 143 |
+
```python
|
| 144 |
+
# Start session
|
| 145 |
+
session = await start_tutoring_session(
|
| 146 |
+
student_id="student_001",
|
| 147 |
+
subject="Physics",
|
| 148 |
+
learning_objectives=["Understand Newton's laws"]
|
| 149 |
+
)
|
| 150 |
+
|
| 151 |
+
# Chat with tutor
|
| 152 |
+
response = await ai_tutor_chat(
|
| 153 |
+
session_id=session["session_id"],
|
| 154 |
+
student_query="What is Newton's first law?",
|
| 155 |
+
request_type="explanation"
|
| 156 |
+
)
|
| 157 |
+
|
| 158 |
+
# Get step-by-step guidance
|
| 159 |
+
steps = await get_step_by_step_guidance(
|
| 160 |
+
session_id=session["session_id"],
|
| 161 |
+
concept="Newton's first law",
|
| 162 |
+
current_step=1
|
| 163 |
+
)
|
| 164 |
+
|
| 165 |
+
# End session
|
| 166 |
+
summary = await end_tutoring_session(
|
| 167 |
+
session_id=session["session_id"],
|
| 168 |
+
session_summary="Learned about Newton's laws"
|
| 169 |
+
)
|
| 170 |
+
```
|
| 171 |
+
|
| 172 |
+
### Example 2: Content Generation Workflow
|
| 173 |
+
|
| 174 |
+
```python
|
| 175 |
+
# Generate interactive exercise
|
| 176 |
+
exercise = await generate_interactive_exercise(
|
| 177 |
+
concept="Chemical Reactions",
|
| 178 |
+
exercise_type="lab",
|
| 179 |
+
difficulty_level=0.7,
|
| 180 |
+
student_level="advanced"
|
| 181 |
+
)
|
| 182 |
+
|
| 183 |
+
# Generate scenario
|
| 184 |
+
scenario = await generate_scenario_based_learning(
|
| 185 |
+
concept="Environmental Science",
|
| 186 |
+
scenario_type="real_world",
|
| 187 |
+
complexity_level="complex"
|
| 188 |
+
)
|
| 189 |
+
|
| 190 |
+
# Generate game
|
| 191 |
+
game = await generate_gamified_content(
|
| 192 |
+
concept="Algebra",
|
| 193 |
+
game_type="puzzle",
|
| 194 |
+
target_age_group="teen"
|
| 195 |
+
)
|
| 196 |
+
```
|
| 197 |
+
|
| 198 |
+
## 🔧 Technical Implementation
|
| 199 |
+
|
| 200 |
+
### Architecture
|
| 201 |
+
- **Modular Design**: Separate modules for tutoring and content generation
|
| 202 |
+
- **Session Management**: In-memory session storage with context preservation
|
| 203 |
+
- **AI Integration**: Powered by Google Gemini Flash models
|
| 204 |
+
- **API Layer**: RESTful endpoints with comprehensive error handling
|
| 205 |
+
|
| 206 |
+
### Key Components
|
| 207 |
+
- `ai_tutor_tools.py`: Contextualized tutoring functionality
|
| 208 |
+
- `content_generation_tools.py`: Advanced content generation
|
| 209 |
+
- `TutoringSession` class: Session state management
|
| 210 |
+
- Gradio interface: User-friendly web interface
|
| 211 |
+
|
| 212 |
+
### Quality Assurance
|
| 213 |
+
- **Content Validation**: Automated quality checking
|
| 214 |
+
- **Error Handling**: Comprehensive error management
|
| 215 |
+
- **Testing**: Automated test suite for all features
|
| 216 |
+
|
| 217 |
+
## 📊 Benefits
|
| 218 |
+
|
| 219 |
+
### For Students
|
| 220 |
+
- **Personalized Learning**: Adapted to individual needs and pace
|
| 221 |
+
- **Multiple Learning Paths**: Various approaches to understand concepts
|
| 222 |
+
- **Engaging Content**: Interactive and gamified learning experiences
|
| 223 |
+
- **Immediate Feedback**: Real-time guidance and support
|
| 224 |
+
|
| 225 |
+
### For Educators
|
| 226 |
+
- **Content Creation**: Automated generation of high-quality materials
|
| 227 |
+
- **Assessment Tools**: Built-in evaluation and rubrics
|
| 228 |
+
- **Analytics**: Detailed insights into student progress
|
| 229 |
+
- **Scalability**: Support for multiple students simultaneously
|
| 230 |
+
|
| 231 |
+
## 🔮 Future Enhancements
|
| 232 |
+
|
| 233 |
+
- **Voice Integration**: Speech-to-text and text-to-speech capabilities
|
| 234 |
+
- **Visual Content**: Automatic diagram and chart generation
|
| 235 |
+
- **Collaborative Learning**: Multi-student tutoring sessions
|
| 236 |
+
- **Advanced Analytics**: Predictive learning analytics
|
| 237 |
+
- **Mobile Optimization**: Enhanced mobile experience
|
mcp_server/server.py
CHANGED
|
@@ -57,6 +57,8 @@ from mcp_server.tools import interaction_tools
|
|
| 57 |
from mcp_server.tools import ocr_tools
|
| 58 |
from mcp_server.tools import learning_path_tools
|
| 59 |
from mcp_server.tools import concept_graph_tools
|
|
|
|
|
|
|
| 60 |
|
| 61 |
|
| 62 |
# Mount the SSE transport for MCP at '/sse/' (with trailing slash)
|
|
@@ -242,6 +244,154 @@ async def get_quiz_session_status_endpoint(request: dict):
|
|
| 242 |
raise HTTPException(status_code=400, detail="session_id is required")
|
| 243 |
return await get_quiz_session_status_tool(session_id)
|
| 244 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 245 |
# Entrypoint for running with MCP SSE transport
|
| 246 |
if __name__ == "__main__":
|
| 247 |
mcp.run(transport="sse")
|
|
|
|
| 57 |
from mcp_server.tools import ocr_tools
|
| 58 |
from mcp_server.tools import learning_path_tools
|
| 59 |
from mcp_server.tools import concept_graph_tools
|
| 60 |
+
from mcp_server.tools import ai_tutor_tools
|
| 61 |
+
from mcp_server.tools import content_generation_tools
|
| 62 |
|
| 63 |
|
| 64 |
# Mount the SSE transport for MCP at '/sse/' (with trailing slash)
|
|
|
|
| 244 |
raise HTTPException(status_code=400, detail="session_id is required")
|
| 245 |
return await get_quiz_session_status_tool(session_id)
|
| 246 |
|
| 247 |
+
# API endpoints - AI Tutoring
|
| 248 |
+
from mcp_server.tools.ai_tutor_tools import (
|
| 249 |
+
start_tutoring_session,
|
| 250 |
+
ai_tutor_chat,
|
| 251 |
+
get_step_by_step_guidance,
|
| 252 |
+
get_alternative_explanations,
|
| 253 |
+
update_student_understanding,
|
| 254 |
+
get_tutoring_session_status,
|
| 255 |
+
end_tutoring_session,
|
| 256 |
+
list_active_tutoring_sessions
|
| 257 |
+
)
|
| 258 |
+
|
| 259 |
+
@api_app.post("/api/start-tutoring-session")
|
| 260 |
+
async def start_tutoring_session_endpoint(request: dict):
|
| 261 |
+
student_id = request.get("student_id")
|
| 262 |
+
subject = request.get("subject", "general")
|
| 263 |
+
learning_objectives = request.get("learning_objectives", [])
|
| 264 |
+
if not student_id:
|
| 265 |
+
raise HTTPException(status_code=400, detail="student_id is required")
|
| 266 |
+
return await start_tutoring_session(student_id, subject, learning_objectives)
|
| 267 |
+
|
| 268 |
+
@api_app.post("/api/ai-tutor-chat")
|
| 269 |
+
async def ai_tutor_chat_endpoint(request: dict):
|
| 270 |
+
session_id = request.get("session_id")
|
| 271 |
+
student_query = request.get("student_query")
|
| 272 |
+
request_type = request.get("request_type", "explanation")
|
| 273 |
+
if not session_id or not student_query:
|
| 274 |
+
raise HTTPException(status_code=400, detail="session_id and student_query are required")
|
| 275 |
+
return await ai_tutor_chat(session_id, student_query, request_type)
|
| 276 |
+
|
| 277 |
+
@api_app.post("/api/step-by-step-guidance")
|
| 278 |
+
async def step_by_step_guidance_endpoint(request: dict):
|
| 279 |
+
session_id = request.get("session_id")
|
| 280 |
+
concept = request.get("concept")
|
| 281 |
+
current_step = request.get("current_step", 1)
|
| 282 |
+
if not session_id or not concept:
|
| 283 |
+
raise HTTPException(status_code=400, detail="session_id and concept are required")
|
| 284 |
+
return await get_step_by_step_guidance(session_id, concept, current_step)
|
| 285 |
+
|
| 286 |
+
@api_app.post("/api/alternative-explanations")
|
| 287 |
+
async def alternative_explanations_endpoint(request: dict):
|
| 288 |
+
session_id = request.get("session_id")
|
| 289 |
+
concept = request.get("concept")
|
| 290 |
+
explanation_types = request.get("explanation_types", [])
|
| 291 |
+
if not session_id or not concept:
|
| 292 |
+
raise HTTPException(status_code=400, detail="session_id and concept are required")
|
| 293 |
+
return await get_alternative_explanations(session_id, concept, explanation_types)
|
| 294 |
+
|
| 295 |
+
@api_app.post("/api/update-student-understanding")
|
| 296 |
+
async def update_student_understanding_endpoint(request: dict):
|
| 297 |
+
session_id = request.get("session_id")
|
| 298 |
+
concept = request.get("concept")
|
| 299 |
+
understanding_level = request.get("understanding_level")
|
| 300 |
+
feedback = request.get("feedback", "")
|
| 301 |
+
if not session_id or not concept or understanding_level is None:
|
| 302 |
+
raise HTTPException(status_code=400, detail="session_id, concept, and understanding_level are required")
|
| 303 |
+
return await update_student_understanding(session_id, concept, understanding_level, feedback)
|
| 304 |
+
|
| 305 |
+
@api_app.get("/api/tutoring-session-status/{session_id}")
|
| 306 |
+
async def tutoring_session_status_endpoint(session_id: str):
|
| 307 |
+
return await get_tutoring_session_status(session_id)
|
| 308 |
+
|
| 309 |
+
@api_app.post("/api/end-tutoring-session")
|
| 310 |
+
async def end_tutoring_session_endpoint(request: dict):
|
| 311 |
+
session_id = request.get("session_id")
|
| 312 |
+
session_summary = request.get("session_summary", "")
|
| 313 |
+
if not session_id:
|
| 314 |
+
raise HTTPException(status_code=400, detail="session_id is required")
|
| 315 |
+
return await end_tutoring_session(session_id, session_summary)
|
| 316 |
+
|
| 317 |
+
@api_app.get("/api/active-tutoring-sessions")
|
| 318 |
+
async def active_tutoring_sessions_endpoint(student_id: str = None):
|
| 319 |
+
return await list_active_tutoring_sessions(student_id)
|
| 320 |
+
|
| 321 |
+
# API endpoints - Content Generation
|
| 322 |
+
from mcp_server.tools.content_generation_tools import (
|
| 323 |
+
generate_interactive_exercise,
|
| 324 |
+
generate_adaptive_content_sequence,
|
| 325 |
+
generate_scenario_based_learning,
|
| 326 |
+
generate_multimodal_content,
|
| 327 |
+
generate_adaptive_assessment,
|
| 328 |
+
generate_gamified_content,
|
| 329 |
+
validate_generated_content
|
| 330 |
+
)
|
| 331 |
+
|
| 332 |
+
@api_app.post("/api/generate-interactive-exercise")
|
| 333 |
+
async def generate_interactive_exercise_endpoint(request: dict):
|
| 334 |
+
concept = request.get("concept")
|
| 335 |
+
exercise_type = request.get("exercise_type", "problem_solving")
|
| 336 |
+
difficulty_level = request.get("difficulty_level", 0.5)
|
| 337 |
+
student_level = request.get("student_level", "intermediate")
|
| 338 |
+
if not concept:
|
| 339 |
+
raise HTTPException(status_code=400, detail="concept is required")
|
| 340 |
+
return await generate_interactive_exercise(concept, exercise_type, difficulty_level, student_level)
|
| 341 |
+
|
| 342 |
+
@api_app.post("/api/generate-adaptive-content-sequence")
|
| 343 |
+
async def generate_adaptive_content_sequence_endpoint(request: dict):
|
| 344 |
+
topic = request.get("topic")
|
| 345 |
+
student_profile = request.get("student_profile", {})
|
| 346 |
+
sequence_length = request.get("sequence_length", 5)
|
| 347 |
+
if not topic:
|
| 348 |
+
raise HTTPException(status_code=400, detail="topic is required")
|
| 349 |
+
return await generate_adaptive_content_sequence(topic, student_profile, sequence_length)
|
| 350 |
+
|
| 351 |
+
@api_app.post("/api/generate-scenario-based-learning")
|
| 352 |
+
async def generate_scenario_based_learning_endpoint(request: dict):
|
| 353 |
+
concept = request.get("concept")
|
| 354 |
+
scenario_type = request.get("scenario_type", "real_world")
|
| 355 |
+
complexity_level = request.get("complexity_level", "moderate")
|
| 356 |
+
if not concept:
|
| 357 |
+
raise HTTPException(status_code=400, detail="concept is required")
|
| 358 |
+
return await generate_scenario_based_learning(concept, scenario_type, complexity_level)
|
| 359 |
+
|
| 360 |
+
@api_app.post("/api/generate-multimodal-content")
|
| 361 |
+
async def generate_multimodal_content_endpoint(request: dict):
|
| 362 |
+
concept = request.get("concept")
|
| 363 |
+
modalities = request.get("modalities", ["visual", "auditory", "kinesthetic", "reading"])
|
| 364 |
+
target_audience = request.get("target_audience", "general")
|
| 365 |
+
if not concept:
|
| 366 |
+
raise HTTPException(status_code=400, detail="concept is required")
|
| 367 |
+
return await generate_multimodal_content(concept, modalities, target_audience)
|
| 368 |
+
|
| 369 |
+
@api_app.post("/api/generate-adaptive-assessment")
|
| 370 |
+
async def generate_adaptive_assessment_endpoint(request: dict):
|
| 371 |
+
concept = request.get("concept")
|
| 372 |
+
assessment_type = request.get("assessment_type", "formative")
|
| 373 |
+
student_data = request.get("student_data", {})
|
| 374 |
+
if not concept:
|
| 375 |
+
raise HTTPException(status_code=400, detail="concept is required")
|
| 376 |
+
return await generate_adaptive_assessment(concept, assessment_type, student_data)
|
| 377 |
+
|
| 378 |
+
@api_app.post("/api/generate-gamified-content")
|
| 379 |
+
async def generate_gamified_content_endpoint(request: dict):
|
| 380 |
+
concept = request.get("concept")
|
| 381 |
+
game_type = request.get("game_type", "quest")
|
| 382 |
+
target_age_group = request.get("target_age_group", "teen")
|
| 383 |
+
if not concept:
|
| 384 |
+
raise HTTPException(status_code=400, detail="concept is required")
|
| 385 |
+
return await generate_gamified_content(concept, game_type, target_age_group)
|
| 386 |
+
|
| 387 |
+
@api_app.post("/api/validate-content")
|
| 388 |
+
async def validate_content_endpoint(request: dict):
|
| 389 |
+
content_data = request.get("content_data")
|
| 390 |
+
validation_criteria = request.get("validation_criteria", {})
|
| 391 |
+
if not content_data:
|
| 392 |
+
raise HTTPException(status_code=400, detail="content_data is required")
|
| 393 |
+
return await validate_generated_content(content_data, validation_criteria)
|
| 394 |
+
|
| 395 |
# Entrypoint for running with MCP SSE transport
|
| 396 |
if __name__ == "__main__":
|
| 397 |
mcp.run(transport="sse")
|
mcp_server/tools/ai_tutor_tools.py
ADDED
|
@@ -0,0 +1,650 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Contextualized AI Tutoring tools for TutorX.
|
| 3 |
+
Provides step-by-step guidance, alternative explanations, and conversational AI tutoring.
|
| 4 |
+
"""
|
| 5 |
+
|
| 6 |
+
import json
|
| 7 |
+
import uuid
|
| 8 |
+
from datetime import datetime, timedelta
|
| 9 |
+
from typing import Dict, Any, List, Optional
|
| 10 |
+
from mcp_server.mcp_instance import mcp
|
| 11 |
+
from mcp_server.model.gemini_flash import GeminiFlash
|
| 12 |
+
|
| 13 |
+
MODEL = GeminiFlash()
|
| 14 |
+
|
| 15 |
+
# Tutoring session storage
|
| 16 |
+
tutoring_sessions = {}
|
| 17 |
+
|
| 18 |
+
def extract_json_from_text(text: str):
|
| 19 |
+
"""Extract JSON from text response"""
|
| 20 |
+
import re
|
| 21 |
+
if not text or not isinstance(text, str):
|
| 22 |
+
return None
|
| 23 |
+
# Remove code fences
|
| 24 |
+
text = re.sub(r'^\s*```(?:json)?\s*', '', text, flags=re.IGNORECASE)
|
| 25 |
+
text = re.sub(r'\s*```\s*$', '', text, flags=re.IGNORECASE)
|
| 26 |
+
text = text.strip()
|
| 27 |
+
# Remove trailing commas
|
| 28 |
+
text = re.sub(r',([ \t\r\n]*[}}\]])', r'\1', text)
|
| 29 |
+
return json.loads(text)
|
| 30 |
+
|
| 31 |
+
class TutoringSession:
|
| 32 |
+
"""Manages a tutoring session with context and memory"""
|
| 33 |
+
|
| 34 |
+
def __init__(self, session_id: str, student_id: str, subject: str = "general"):
|
| 35 |
+
self.session_id = session_id
|
| 36 |
+
self.student_id = student_id
|
| 37 |
+
self.subject = subject
|
| 38 |
+
self.created_at = datetime.utcnow()
|
| 39 |
+
self.last_activity = datetime.utcnow()
|
| 40 |
+
self.conversation_history = []
|
| 41 |
+
self.current_topic = None
|
| 42 |
+
self.learning_objectives = []
|
| 43 |
+
self.student_understanding_level = 0.5 # 0.0 to 1.0
|
| 44 |
+
self.preferred_explanation_style = "detailed" # detailed, simple, visual, step-by-step
|
| 45 |
+
self.difficulty_preference = 0.5 # 0.0 to 1.0
|
| 46 |
+
|
| 47 |
+
def add_interaction(self, query: str, response: str, interaction_type: str = "question"):
|
| 48 |
+
"""Add an interaction to the session history"""
|
| 49 |
+
self.conversation_history.append({
|
| 50 |
+
"timestamp": datetime.utcnow().isoformat(),
|
| 51 |
+
"query": query,
|
| 52 |
+
"response": response,
|
| 53 |
+
"type": interaction_type,
|
| 54 |
+
"understanding_level": self.student_understanding_level
|
| 55 |
+
})
|
| 56 |
+
self.last_activity = datetime.utcnow()
|
| 57 |
+
|
| 58 |
+
def get_context_summary(self) -> str:
|
| 59 |
+
"""Generate a context summary for the AI tutor"""
|
| 60 |
+
recent_interactions = self.conversation_history[-5:] # Last 5 interactions
|
| 61 |
+
|
| 62 |
+
context = f"""
|
| 63 |
+
Session Context:
|
| 64 |
+
- Student ID: {self.student_id}
|
| 65 |
+
- Subject: {self.subject}
|
| 66 |
+
- Current Topic: {self.current_topic or 'Not specified'}
|
| 67 |
+
- Understanding Level: {self.student_understanding_level:.2f}/1.0
|
| 68 |
+
- Preferred Style: {self.preferred_explanation_style}
|
| 69 |
+
- Session Duration: {(datetime.utcnow() - self.created_at).total_seconds() / 60:.1f} minutes
|
| 70 |
+
|
| 71 |
+
Recent Conversation:
|
| 72 |
+
"""
|
| 73 |
+
|
| 74 |
+
for interaction in recent_interactions:
|
| 75 |
+
context += f"\nStudent: {interaction['query']}\nTutor: {interaction['response'][:100]}...\n"
|
| 76 |
+
|
| 77 |
+
return context
|
| 78 |
+
|
| 79 |
+
@mcp.tool()
|
| 80 |
+
async def start_tutoring_session(student_id: str, subject: str = "general",
|
| 81 |
+
learning_objectives: List[str] = None) -> dict:
|
| 82 |
+
"""
|
| 83 |
+
Start a new AI tutoring session with context management.
|
| 84 |
+
|
| 85 |
+
Args:
|
| 86 |
+
student_id: Student identifier
|
| 87 |
+
subject: Subject area for tutoring
|
| 88 |
+
learning_objectives: List of learning objectives for the session
|
| 89 |
+
|
| 90 |
+
Returns:
|
| 91 |
+
Dictionary with session information
|
| 92 |
+
"""
|
| 93 |
+
try:
|
| 94 |
+
session_id = str(uuid.uuid4())
|
| 95 |
+
session = TutoringSession(session_id, student_id, subject)
|
| 96 |
+
|
| 97 |
+
if learning_objectives:
|
| 98 |
+
session.learning_objectives = learning_objectives
|
| 99 |
+
|
| 100 |
+
tutoring_sessions[session_id] = session
|
| 101 |
+
|
| 102 |
+
# Generate welcome message
|
| 103 |
+
prompt = f"""
|
| 104 |
+
You are an expert AI tutor starting a new tutoring session.
|
| 105 |
+
|
| 106 |
+
Student ID: {student_id}
|
| 107 |
+
Subject: {subject}
|
| 108 |
+
Learning Objectives: {learning_objectives or 'To be determined based on student needs'}
|
| 109 |
+
|
| 110 |
+
Generate a welcoming introduction that:
|
| 111 |
+
1. Welcomes the student warmly
|
| 112 |
+
2. Explains your role as their AI tutor
|
| 113 |
+
3. Asks about their current understanding or what they'd like to learn
|
| 114 |
+
4. Sets expectations for the tutoring session
|
| 115 |
+
|
| 116 |
+
Return a JSON object with:
|
| 117 |
+
- "welcome_message": friendly welcome text
|
| 118 |
+
- "suggested_topics": list of 3-5 topics they might want to explore
|
| 119 |
+
- "session_guidelines": brief explanation of how the tutoring works
|
| 120 |
+
"""
|
| 121 |
+
|
| 122 |
+
response = await MODEL.generate_text(prompt, temperature=0.7)
|
| 123 |
+
welcome_data = extract_json_from_text(response)
|
| 124 |
+
|
| 125 |
+
return {
|
| 126 |
+
"success": True,
|
| 127 |
+
"session_id": session_id,
|
| 128 |
+
"student_id": student_id,
|
| 129 |
+
"subject": subject,
|
| 130 |
+
"created_at": session.created_at.isoformat(),
|
| 131 |
+
**welcome_data
|
| 132 |
+
}
|
| 133 |
+
|
| 134 |
+
except Exception as e:
|
| 135 |
+
return {
|
| 136 |
+
"success": False,
|
| 137 |
+
"error": f"Failed to start tutoring session: {str(e)}"
|
| 138 |
+
}
|
| 139 |
+
|
| 140 |
+
@mcp.tool()
|
| 141 |
+
async def ai_tutor_chat(session_id: str, student_query: str,
|
| 142 |
+
request_type: str = "explanation") -> dict:
|
| 143 |
+
"""
|
| 144 |
+
Process student query with contextualized AI tutoring.
|
| 145 |
+
|
| 146 |
+
Args:
|
| 147 |
+
session_id: Active tutoring session ID
|
| 148 |
+
student_query: Student's question or request
|
| 149 |
+
request_type: Type of request ('explanation', 'step_by_step', 'alternative', 'practice', 'clarification')
|
| 150 |
+
|
| 151 |
+
Returns:
|
| 152 |
+
Dictionary with tutor response and guidance
|
| 153 |
+
"""
|
| 154 |
+
try:
|
| 155 |
+
if session_id not in tutoring_sessions:
|
| 156 |
+
return {
|
| 157 |
+
"success": False,
|
| 158 |
+
"error": "Invalid session ID. Please start a new tutoring session."
|
| 159 |
+
}
|
| 160 |
+
|
| 161 |
+
session = tutoring_sessions[session_id]
|
| 162 |
+
context = session.get_context_summary()
|
| 163 |
+
|
| 164 |
+
# Analyze student query to understand their needs
|
| 165 |
+
analysis_prompt = f"""
|
| 166 |
+
Analyze this student query in the context of their tutoring session:
|
| 167 |
+
|
| 168 |
+
{context}
|
| 169 |
+
|
| 170 |
+
Student Query: "{student_query}"
|
| 171 |
+
Request Type: {request_type}
|
| 172 |
+
|
| 173 |
+
Analyze and return JSON with:
|
| 174 |
+
- "topic_identified": main topic/concept the student is asking about
|
| 175 |
+
- "difficulty_level": estimated difficulty (0.0 to 1.0)
|
| 176 |
+
- "understanding_gaps": potential areas where student might be confused
|
| 177 |
+
- "prerequisite_concepts": concepts student should know first
|
| 178 |
+
- "confidence_level": how confident the student seems (0.0 to 1.0)
|
| 179 |
+
"""
|
| 180 |
+
|
| 181 |
+
analysis_response = await MODEL.generate_text(analysis_prompt, temperature=0.3)
|
| 182 |
+
analysis = extract_json_from_text(analysis_response)
|
| 183 |
+
|
| 184 |
+
# Update session context based on analysis
|
| 185 |
+
if analysis and "topic_identified" in analysis:
|
| 186 |
+
session.current_topic = analysis["topic_identified"]
|
| 187 |
+
if "difficulty_level" in analysis:
|
| 188 |
+
session.difficulty_preference = analysis["difficulty_level"]
|
| 189 |
+
|
| 190 |
+
# Generate appropriate response based on request type
|
| 191 |
+
if request_type == "step_by_step":
|
| 192 |
+
response_prompt = f"""
|
| 193 |
+
{context}
|
| 194 |
+
|
| 195 |
+
The student asked: "{student_query}"
|
| 196 |
+
|
| 197 |
+
Provide a detailed step-by-step explanation that:
|
| 198 |
+
1. Breaks down the concept into manageable steps
|
| 199 |
+
2. Uses simple, clear language appropriate for their level
|
| 200 |
+
3. Includes examples for each step
|
| 201 |
+
4. Checks understanding at key points
|
| 202 |
+
5. Provides encouragement and support
|
| 203 |
+
|
| 204 |
+
Return JSON with:
|
| 205 |
+
- "step_by_step_explanation": detailed step-by-step guide
|
| 206 |
+
- "key_steps": list of main steps with brief descriptions
|
| 207 |
+
- "examples": relevant examples for each step
|
| 208 |
+
- "check_points": questions to verify understanding
|
| 209 |
+
- "encouragement": supportive message
|
| 210 |
+
"""
|
| 211 |
+
elif request_type == "alternative":
|
| 212 |
+
response_prompt = f"""
|
| 213 |
+
{context}
|
| 214 |
+
|
| 215 |
+
The student asked: "{student_query}"
|
| 216 |
+
|
| 217 |
+
Provide alternative explanations using different approaches:
|
| 218 |
+
1. Visual/spatial explanation
|
| 219 |
+
2. Analogy-based explanation
|
| 220 |
+
3. Real-world application
|
| 221 |
+
4. Simplified version
|
| 222 |
+
|
| 223 |
+
Return JSON with:
|
| 224 |
+
- "visual_explanation": explanation using visual/spatial concepts
|
| 225 |
+
- "analogy_explanation": explanation using familiar analogies
|
| 226 |
+
- "real_world_application": how this applies in real life
|
| 227 |
+
- "simplified_version": very simple explanation
|
| 228 |
+
- "which_works_best": question asking which explanation resonates
|
| 229 |
+
"""
|
| 230 |
+
else: # Default explanation
|
| 231 |
+
response_prompt = f"""
|
| 232 |
+
{context}
|
| 233 |
+
|
| 234 |
+
The student asked: "{student_query}"
|
| 235 |
+
|
| 236 |
+
Provide a comprehensive, personalized explanation that:
|
| 237 |
+
1. Addresses their specific question directly
|
| 238 |
+
2. Builds on their current understanding level
|
| 239 |
+
3. Uses their preferred explanation style
|
| 240 |
+
4. Includes relevant examples
|
| 241 |
+
5. Suggests next steps for learning
|
| 242 |
+
|
| 243 |
+
Return JSON with:
|
| 244 |
+
- "main_explanation": comprehensive answer to their question
|
| 245 |
+
- "key_concepts": important concepts to remember
|
| 246 |
+
- "examples": relevant examples
|
| 247 |
+
- "next_steps": suggested follow-up activities
|
| 248 |
+
- "related_topics": topics they might want to explore next
|
| 249 |
+
"""
|
| 250 |
+
|
| 251 |
+
tutor_response = await MODEL.generate_text(response_prompt, temperature=0.7)
|
| 252 |
+
response_data = extract_json_from_text(tutor_response)
|
| 253 |
+
|
| 254 |
+
# Add interaction to session history
|
| 255 |
+
session.add_interaction(
|
| 256 |
+
student_query,
|
| 257 |
+
response_data.get("main_explanation", str(response_data)),
|
| 258 |
+
request_type
|
| 259 |
+
)
|
| 260 |
+
|
| 261 |
+
return {
|
| 262 |
+
"success": True,
|
| 263 |
+
"session_id": session_id,
|
| 264 |
+
"request_type": request_type,
|
| 265 |
+
"analysis": analysis,
|
| 266 |
+
"response": response_data,
|
| 267 |
+
"session_stats": {
|
| 268 |
+
"interactions_count": len(session.conversation_history),
|
| 269 |
+
"current_topic": session.current_topic,
|
| 270 |
+
"understanding_level": session.student_understanding_level
|
| 271 |
+
}
|
| 272 |
+
}
|
| 273 |
+
|
| 274 |
+
except Exception as e:
|
| 275 |
+
return {
|
| 276 |
+
"success": False,
|
| 277 |
+
"error": f"Failed to process tutoring request: {str(e)}"
|
| 278 |
+
}
|
| 279 |
+
|
| 280 |
+
@mcp.tool()
|
| 281 |
+
async def get_step_by_step_guidance(session_id: str, concept: str,
|
| 282 |
+
current_step: int = 1) -> dict:
|
| 283 |
+
"""
|
| 284 |
+
Provide detailed step-by-step guidance for learning a specific concept.
|
| 285 |
+
|
| 286 |
+
Args:
|
| 287 |
+
session_id: Active tutoring session ID
|
| 288 |
+
concept: The concept to provide guidance for
|
| 289 |
+
current_step: Current step the student is on (1-based)
|
| 290 |
+
|
| 291 |
+
Returns:
|
| 292 |
+
Dictionary with step-by-step guidance
|
| 293 |
+
"""
|
| 294 |
+
try:
|
| 295 |
+
if session_id not in tutoring_sessions:
|
| 296 |
+
return {
|
| 297 |
+
"success": False,
|
| 298 |
+
"error": "Invalid session ID. Please start a new tutoring session."
|
| 299 |
+
}
|
| 300 |
+
|
| 301 |
+
session = tutoring_sessions[session_id]
|
| 302 |
+
context = session.get_context_summary()
|
| 303 |
+
|
| 304 |
+
prompt = f"""
|
| 305 |
+
{context}
|
| 306 |
+
|
| 307 |
+
Provide comprehensive step-by-step guidance for learning: "{concept}"
|
| 308 |
+
Current step: {current_step}
|
| 309 |
+
|
| 310 |
+
Create a structured learning path that:
|
| 311 |
+
1. Breaks the concept into logical, sequential steps
|
| 312 |
+
2. Provides clear explanations for each step
|
| 313 |
+
3. Includes practice exercises for each step
|
| 314 |
+
4. Offers multiple ways to understand each step
|
| 315 |
+
5. Includes checkpoints to verify understanding
|
| 316 |
+
|
| 317 |
+
Return JSON with:
|
| 318 |
+
- "total_steps": total number of steps needed
|
| 319 |
+
- "current_step_details": detailed information about the current step
|
| 320 |
+
- "step_explanation": clear explanation of the current step
|
| 321 |
+
- "practice_exercises": 2-3 practice problems for this step
|
| 322 |
+
- "key_points": important points to remember
|
| 323 |
+
- "common_mistakes": common mistakes students make at this step
|
| 324 |
+
- "next_step_preview": brief preview of what comes next
|
| 325 |
+
- "prerequisite_check": what student should know before this step
|
| 326 |
+
- "mastery_indicators": how to know if student has mastered this step
|
| 327 |
+
"""
|
| 328 |
+
|
| 329 |
+
response = await MODEL.generate_text(prompt, temperature=0.6)
|
| 330 |
+
guidance_data = extract_json_from_text(response)
|
| 331 |
+
|
| 332 |
+
return {
|
| 333 |
+
"success": True,
|
| 334 |
+
"session_id": session_id,
|
| 335 |
+
"concept": concept,
|
| 336 |
+
"current_step": current_step,
|
| 337 |
+
"guidance": guidance_data
|
| 338 |
+
}
|
| 339 |
+
|
| 340 |
+
except Exception as e:
|
| 341 |
+
return {
|
| 342 |
+
"success": False,
|
| 343 |
+
"error": f"Failed to generate step-by-step guidance: {str(e)}"
|
| 344 |
+
}
|
| 345 |
+
|
| 346 |
+
@mcp.tool()
|
| 347 |
+
async def get_alternative_explanations(session_id: str, concept: str,
|
| 348 |
+
explanation_types: List[str] = None) -> dict:
|
| 349 |
+
"""
|
| 350 |
+
Generate alternative explanations for a concept using different approaches.
|
| 351 |
+
|
| 352 |
+
Args:
|
| 353 |
+
session_id: Active tutoring session ID
|
| 354 |
+
concept: The concept to explain
|
| 355 |
+
explanation_types: Types of explanations to generate
|
| 356 |
+
|
| 357 |
+
Returns:
|
| 358 |
+
Dictionary with alternative explanations
|
| 359 |
+
"""
|
| 360 |
+
try:
|
| 361 |
+
if session_id not in tutoring_sessions:
|
| 362 |
+
return {
|
| 363 |
+
"success": False,
|
| 364 |
+
"error": "Invalid session ID. Please start a new tutoring session."
|
| 365 |
+
}
|
| 366 |
+
|
| 367 |
+
session = tutoring_sessions[session_id]
|
| 368 |
+
context = session.get_context_summary()
|
| 369 |
+
|
| 370 |
+
if not explanation_types:
|
| 371 |
+
explanation_types = ["visual", "analogy", "real_world", "simplified", "technical"]
|
| 372 |
+
|
| 373 |
+
prompt = f"""
|
| 374 |
+
{context}
|
| 375 |
+
|
| 376 |
+
Generate multiple alternative explanations for: "{concept}"
|
| 377 |
+
|
| 378 |
+
Create explanations using these approaches: {explanation_types}
|
| 379 |
+
|
| 380 |
+
For each explanation type, provide:
|
| 381 |
+
1. A complete explanation using that approach
|
| 382 |
+
2. Key benefits of this explanation style
|
| 383 |
+
3. When this explanation works best
|
| 384 |
+
4. Supporting examples or analogies
|
| 385 |
+
|
| 386 |
+
Return JSON with:
|
| 387 |
+
- "visual_explanation": explanation using visual/spatial concepts and imagery
|
| 388 |
+
- "analogy_explanation": explanation using familiar analogies and metaphors
|
| 389 |
+
- "real_world_explanation": explanation showing real-world applications
|
| 390 |
+
- "simplified_explanation": very simple, basic explanation
|
| 391 |
+
- "technical_explanation": detailed, technical explanation
|
| 392 |
+
- "story_explanation": explanation told as a story or narrative
|
| 393 |
+
- "comparison_explanation": explanation comparing to similar concepts
|
| 394 |
+
- "recommendation": which explanation might work best for this student
|
| 395 |
+
"""
|
| 396 |
+
|
| 397 |
+
response = await MODEL.generate_text(prompt, temperature=0.7)
|
| 398 |
+
explanations_data = extract_json_from_text(response)
|
| 399 |
+
|
| 400 |
+
return {
|
| 401 |
+
"success": True,
|
| 402 |
+
"session_id": session_id,
|
| 403 |
+
"concept": concept,
|
| 404 |
+
"explanation_types": explanation_types,
|
| 405 |
+
"explanations": explanations_data
|
| 406 |
+
}
|
| 407 |
+
|
| 408 |
+
except Exception as e:
|
| 409 |
+
return {
|
| 410 |
+
"success": False,
|
| 411 |
+
"error": f"Failed to generate alternative explanations: {str(e)}"
|
| 412 |
+
}
|
| 413 |
+
|
| 414 |
+
@mcp.tool()
|
| 415 |
+
async def update_student_understanding(session_id: str, concept: str,
|
| 416 |
+
understanding_level: float,
|
| 417 |
+
feedback: str = "") -> dict:
|
| 418 |
+
"""
|
| 419 |
+
Update student's understanding level and adapt tutoring accordingly.
|
| 420 |
+
|
| 421 |
+
Args:
|
| 422 |
+
session_id: Active tutoring session ID
|
| 423 |
+
concept: The concept being learned
|
| 424 |
+
understanding_level: Student's understanding level (0.0 to 1.0)
|
| 425 |
+
feedback: Optional feedback from student
|
| 426 |
+
|
| 427 |
+
Returns:
|
| 428 |
+
Dictionary with updated session information and recommendations
|
| 429 |
+
"""
|
| 430 |
+
try:
|
| 431 |
+
if session_id not in tutoring_sessions:
|
| 432 |
+
return {
|
| 433 |
+
"success": False,
|
| 434 |
+
"error": "Invalid session ID. Please start a new tutoring session."
|
| 435 |
+
}
|
| 436 |
+
|
| 437 |
+
session = tutoring_sessions[session_id]
|
| 438 |
+
|
| 439 |
+
# Update session understanding level
|
| 440 |
+
session.student_understanding_level = understanding_level
|
| 441 |
+
session.current_topic = concept
|
| 442 |
+
|
| 443 |
+
# Generate adaptive recommendations based on understanding level
|
| 444 |
+
prompt = f"""
|
| 445 |
+
Student understanding update:
|
| 446 |
+
- Concept: {concept}
|
| 447 |
+
- Understanding Level: {understanding_level:.2f}/1.0
|
| 448 |
+
- Student Feedback: {feedback or 'No feedback provided'}
|
| 449 |
+
- Session Context: {session.get_context_summary()}
|
| 450 |
+
|
| 451 |
+
Based on this understanding level, provide adaptive recommendations:
|
| 452 |
+
|
| 453 |
+
Return JSON with:
|
| 454 |
+
- "understanding_assessment": assessment of student's current understanding
|
| 455 |
+
- "next_actions": recommended next steps based on understanding level
|
| 456 |
+
- "difficulty_adjustment": how to adjust difficulty (easier/harder/same)
|
| 457 |
+
- "focus_areas": specific areas that need more attention
|
| 458 |
+
- "encouragement": encouraging message appropriate for their level
|
| 459 |
+
- "study_strategies": personalized study strategies
|
| 460 |
+
- "time_estimate": estimated time to reach mastery
|
| 461 |
+
"""
|
| 462 |
+
|
| 463 |
+
response = await MODEL.generate_text(prompt, temperature=0.6)
|
| 464 |
+
recommendations_data = extract_json_from_text(response)
|
| 465 |
+
|
| 466 |
+
# Add this update to conversation history
|
| 467 |
+
session.add_interaction(
|
| 468 |
+
f"Understanding update for {concept}: {understanding_level:.2f}",
|
| 469 |
+
f"Updated understanding and provided recommendations",
|
| 470 |
+
"understanding_update"
|
| 471 |
+
)
|
| 472 |
+
|
| 473 |
+
return {
|
| 474 |
+
"success": True,
|
| 475 |
+
"session_id": session_id,
|
| 476 |
+
"concept": concept,
|
| 477 |
+
"updated_understanding_level": understanding_level,
|
| 478 |
+
"recommendations": recommendations_data,
|
| 479 |
+
"session_stats": {
|
| 480 |
+
"interactions_count": len(session.conversation_history),
|
| 481 |
+
"current_topic": session.current_topic,
|
| 482 |
+
"understanding_level": session.student_understanding_level
|
| 483 |
+
}
|
| 484 |
+
}
|
| 485 |
+
|
| 486 |
+
except Exception as e:
|
| 487 |
+
return {
|
| 488 |
+
"success": False,
|
| 489 |
+
"error": f"Failed to update understanding: {str(e)}"
|
| 490 |
+
}
|
| 491 |
+
|
| 492 |
+
@mcp.tool()
|
| 493 |
+
async def get_tutoring_session_status(session_id: str) -> dict:
|
| 494 |
+
"""
|
| 495 |
+
Get the current status and context of a tutoring session.
|
| 496 |
+
|
| 497 |
+
Args:
|
| 498 |
+
session_id: Tutoring session ID
|
| 499 |
+
|
| 500 |
+
Returns:
|
| 501 |
+
Dictionary with session status and statistics
|
| 502 |
+
"""
|
| 503 |
+
try:
|
| 504 |
+
if session_id not in tutoring_sessions:
|
| 505 |
+
return {
|
| 506 |
+
"success": False,
|
| 507 |
+
"error": "Session not found"
|
| 508 |
+
}
|
| 509 |
+
|
| 510 |
+
session = tutoring_sessions[session_id]
|
| 511 |
+
|
| 512 |
+
return {
|
| 513 |
+
"success": True,
|
| 514 |
+
"session_id": session_id,
|
| 515 |
+
"student_id": session.student_id,
|
| 516 |
+
"subject": session.subject,
|
| 517 |
+
"current_topic": session.current_topic,
|
| 518 |
+
"created_at": session.created_at.isoformat(),
|
| 519 |
+
"last_activity": session.last_activity.isoformat(),
|
| 520 |
+
"duration_minutes": (datetime.utcnow() - session.created_at).total_seconds() / 60,
|
| 521 |
+
"understanding_level": session.student_understanding_level,
|
| 522 |
+
"preferred_style": session.preferred_explanation_style,
|
| 523 |
+
"learning_objectives": session.learning_objectives,
|
| 524 |
+
"interaction_count": len(session.conversation_history),
|
| 525 |
+
"recent_topics": list(set([
|
| 526 |
+
interaction.get("query", "")[:50]
|
| 527 |
+
for interaction in session.conversation_history[-5:]
|
| 528 |
+
]))
|
| 529 |
+
}
|
| 530 |
+
|
| 531 |
+
except Exception as e:
|
| 532 |
+
return {
|
| 533 |
+
"success": False,
|
| 534 |
+
"error": f"Failed to get session status: {str(e)}"
|
| 535 |
+
}
|
| 536 |
+
|
| 537 |
+
@mcp.tool()
|
| 538 |
+
async def end_tutoring_session(session_id: str, session_summary: str = "") -> dict:
|
| 539 |
+
"""
|
| 540 |
+
End a tutoring session and generate a summary.
|
| 541 |
+
|
| 542 |
+
Args:
|
| 543 |
+
session_id: Tutoring session ID
|
| 544 |
+
session_summary: Optional summary from student
|
| 545 |
+
|
| 546 |
+
Returns:
|
| 547 |
+
Dictionary with session summary and recommendations
|
| 548 |
+
"""
|
| 549 |
+
try:
|
| 550 |
+
if session_id not in tutoring_sessions:
|
| 551 |
+
return {
|
| 552 |
+
"success": False,
|
| 553 |
+
"error": "Session not found"
|
| 554 |
+
}
|
| 555 |
+
|
| 556 |
+
session = tutoring_sessions[session_id]
|
| 557 |
+
|
| 558 |
+
# Generate session summary
|
| 559 |
+
prompt = f"""
|
| 560 |
+
Generate a comprehensive summary for this tutoring session:
|
| 561 |
+
|
| 562 |
+
{session.get_context_summary()}
|
| 563 |
+
|
| 564 |
+
Session Details:
|
| 565 |
+
- Duration: {(datetime.utcnow() - session.created_at).total_seconds() / 60:.1f} minutes
|
| 566 |
+
- Interactions: {len(session.conversation_history)}
|
| 567 |
+
- Final Understanding Level: {session.student_understanding_level:.2f}/1.0
|
| 568 |
+
- Student Summary: {session_summary or 'No summary provided'}
|
| 569 |
+
|
| 570 |
+
Return JSON with:
|
| 571 |
+
- "session_summary": comprehensive summary of what was covered
|
| 572 |
+
- "learning_achievements": what the student accomplished
|
| 573 |
+
- "areas_covered": topics and concepts discussed
|
| 574 |
+
- "understanding_progress": how understanding evolved during session
|
| 575 |
+
- "recommendations": recommendations for future study
|
| 576 |
+
- "next_session_suggestions": suggestions for next tutoring session
|
| 577 |
+
- "study_plan": personalized study plan based on session
|
| 578 |
+
- "strengths_identified": student strengths observed
|
| 579 |
+
- "areas_for_improvement": areas that need more work
|
| 580 |
+
"""
|
| 581 |
+
|
| 582 |
+
response = await MODEL.generate_text(prompt, temperature=0.6)
|
| 583 |
+
summary_data = extract_json_from_text(response)
|
| 584 |
+
|
| 585 |
+
# Store session summary before removing
|
| 586 |
+
session_data = {
|
| 587 |
+
"session_id": session_id,
|
| 588 |
+
"student_id": session.student_id,
|
| 589 |
+
"subject": session.subject,
|
| 590 |
+
"duration_minutes": (datetime.utcnow() - session.created_at).total_seconds() / 60,
|
| 591 |
+
"interaction_count": len(session.conversation_history),
|
| 592 |
+
"final_understanding": session.student_understanding_level,
|
| 593 |
+
"summary": summary_data
|
| 594 |
+
}
|
| 595 |
+
|
| 596 |
+
# Remove session from active sessions
|
| 597 |
+
del tutoring_sessions[session_id]
|
| 598 |
+
|
| 599 |
+
return {
|
| 600 |
+
"success": True,
|
| 601 |
+
"session_ended": True,
|
| 602 |
+
**session_data
|
| 603 |
+
}
|
| 604 |
+
|
| 605 |
+
except Exception as e:
|
| 606 |
+
return {
|
| 607 |
+
"success": False,
|
| 608 |
+
"error": f"Failed to end session: {str(e)}"
|
| 609 |
+
}
|
| 610 |
+
|
| 611 |
+
@mcp.tool()
|
| 612 |
+
async def list_active_tutoring_sessions(student_id: str = None) -> dict:
|
| 613 |
+
"""
|
| 614 |
+
List all active tutoring sessions, optionally filtered by student.
|
| 615 |
+
|
| 616 |
+
Args:
|
| 617 |
+
student_id: Optional student ID to filter sessions
|
| 618 |
+
|
| 619 |
+
Returns:
|
| 620 |
+
Dictionary with list of active sessions
|
| 621 |
+
"""
|
| 622 |
+
try:
|
| 623 |
+
active_sessions = []
|
| 624 |
+
|
| 625 |
+
for session_id, session in tutoring_sessions.items():
|
| 626 |
+
if student_id is None or session.student_id == student_id:
|
| 627 |
+
active_sessions.append({
|
| 628 |
+
"session_id": session_id,
|
| 629 |
+
"student_id": session.student_id,
|
| 630 |
+
"subject": session.subject,
|
| 631 |
+
"current_topic": session.current_topic,
|
| 632 |
+
"created_at": session.created_at.isoformat(),
|
| 633 |
+
"last_activity": session.last_activity.isoformat(),
|
| 634 |
+
"duration_minutes": (datetime.utcnow() - session.created_at).total_seconds() / 60,
|
| 635 |
+
"understanding_level": session.student_understanding_level,
|
| 636 |
+
"interaction_count": len(session.conversation_history)
|
| 637 |
+
})
|
| 638 |
+
|
| 639 |
+
return {
|
| 640 |
+
"success": True,
|
| 641 |
+
"active_sessions": active_sessions,
|
| 642 |
+
"total_sessions": len(active_sessions),
|
| 643 |
+
"filtered_by_student": student_id is not None
|
| 644 |
+
}
|
| 645 |
+
|
| 646 |
+
except Exception as e:
|
| 647 |
+
return {
|
| 648 |
+
"success": False,
|
| 649 |
+
"error": f"Failed to list sessions: {str(e)}"
|
| 650 |
+
}
|
mcp_server/tools/content_generation_tools.py
ADDED
|
@@ -0,0 +1,499 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Advanced Automated Content Generation tools for TutorX.
|
| 3 |
+
Generates interactive content, exercises, and adaptive learning materials.
|
| 4 |
+
"""
|
| 5 |
+
|
| 6 |
+
import json
|
| 7 |
+
import uuid
|
| 8 |
+
from datetime import datetime
|
| 9 |
+
from typing import Dict, Any, List, Optional
|
| 10 |
+
from mcp_server.mcp_instance import mcp
|
| 11 |
+
from mcp_server.model.gemini_flash import GeminiFlash
|
| 12 |
+
|
| 13 |
+
MODEL = GeminiFlash()
|
| 14 |
+
|
| 15 |
+
def extract_json_from_text(text: str):
|
| 16 |
+
"""Extract JSON from text response"""
|
| 17 |
+
import re
|
| 18 |
+
if not text or not isinstance(text, str):
|
| 19 |
+
return None
|
| 20 |
+
# Remove code fences
|
| 21 |
+
text = re.sub(r'^\s*```(?:json)?\s*', '', text, flags=re.IGNORECASE)
|
| 22 |
+
text = re.sub(r'\s*```\s*$', '', text, flags=re.IGNORECASE)
|
| 23 |
+
text = text.strip()
|
| 24 |
+
# Remove trailing commas
|
| 25 |
+
text = re.sub(r',([ \t\r\n]*[}}\]])', r'\1', text)
|
| 26 |
+
return json.loads(text)
|
| 27 |
+
|
| 28 |
+
@mcp.tool()
|
| 29 |
+
async def generate_interactive_exercise(concept: str, exercise_type: str = "problem_solving",
|
| 30 |
+
difficulty_level: float = 0.5,
|
| 31 |
+
student_level: str = "intermediate") -> dict:
|
| 32 |
+
"""
|
| 33 |
+
Generate interactive exercises with multiple components and adaptive features.
|
| 34 |
+
|
| 35 |
+
Args:
|
| 36 |
+
concept: The concept to create exercises for
|
| 37 |
+
exercise_type: Type of exercise ('problem_solving', 'simulation', 'case_study', 'lab', 'project')
|
| 38 |
+
difficulty_level: Difficulty level (0.0 to 1.0)
|
| 39 |
+
student_level: Student's academic level
|
| 40 |
+
|
| 41 |
+
Returns:
|
| 42 |
+
Dictionary with interactive exercise content
|
| 43 |
+
"""
|
| 44 |
+
try:
|
| 45 |
+
prompt = f"""
|
| 46 |
+
Create an interactive {exercise_type} exercise for the concept: "{concept}"
|
| 47 |
+
|
| 48 |
+
Exercise Parameters:
|
| 49 |
+
- Difficulty Level: {difficulty_level:.2f}/1.0
|
| 50 |
+
- Student Level: {student_level}
|
| 51 |
+
- Exercise Type: {exercise_type}
|
| 52 |
+
|
| 53 |
+
Generate a comprehensive interactive exercise that includes:
|
| 54 |
+
1. Clear learning objectives
|
| 55 |
+
2. Step-by-step instructions
|
| 56 |
+
3. Interactive components that engage the student
|
| 57 |
+
4. Multiple difficulty levels within the exercise
|
| 58 |
+
5. Real-time feedback mechanisms
|
| 59 |
+
6. Assessment criteria
|
| 60 |
+
7. Extension activities for advanced students
|
| 61 |
+
|
| 62 |
+
Return JSON with:
|
| 63 |
+
- "exercise_id": unique identifier
|
| 64 |
+
- "title": engaging title for the exercise
|
| 65 |
+
- "learning_objectives": list of specific learning goals
|
| 66 |
+
- "introduction": engaging introduction to the exercise
|
| 67 |
+
- "instructions": detailed step-by-step instructions
|
| 68 |
+
- "interactive_components": list of interactive elements
|
| 69 |
+
- "materials_needed": required materials or resources
|
| 70 |
+
- "estimated_time": estimated completion time in minutes
|
| 71 |
+
- "difficulty_variations": easier and harder versions
|
| 72 |
+
- "assessment_rubric": criteria for evaluating student work
|
| 73 |
+
- "feedback_prompts": questions for self-reflection
|
| 74 |
+
- "extension_activities": additional challenges for advanced students
|
| 75 |
+
- "real_world_connections": how this relates to real-world applications
|
| 76 |
+
"""
|
| 77 |
+
|
| 78 |
+
response = await MODEL.generate_text(prompt, temperature=0.7)
|
| 79 |
+
exercise_data = extract_json_from_text(response)
|
| 80 |
+
|
| 81 |
+
# Add metadata
|
| 82 |
+
exercise_data.update({
|
| 83 |
+
"success": True,
|
| 84 |
+
"concept": concept,
|
| 85 |
+
"exercise_type": exercise_type,
|
| 86 |
+
"difficulty_level": difficulty_level,
|
| 87 |
+
"student_level": student_level,
|
| 88 |
+
"generated_at": datetime.utcnow().isoformat(),
|
| 89 |
+
"ai_generated": True
|
| 90 |
+
})
|
| 91 |
+
|
| 92 |
+
return exercise_data
|
| 93 |
+
|
| 94 |
+
except Exception as e:
|
| 95 |
+
return {
|
| 96 |
+
"success": False,
|
| 97 |
+
"error": f"Failed to generate interactive exercise: {str(e)}"
|
| 98 |
+
}
|
| 99 |
+
|
| 100 |
+
@mcp.tool()
|
| 101 |
+
async def generate_adaptive_content_sequence(topic: str, student_profile: dict,
|
| 102 |
+
sequence_length: int = 5) -> dict:
|
| 103 |
+
"""
|
| 104 |
+
Generate a sequence of adaptive content that adjusts based on student profile.
|
| 105 |
+
|
| 106 |
+
Args:
|
| 107 |
+
topic: Main topic for the content sequence
|
| 108 |
+
student_profile: Student's learning profile and preferences
|
| 109 |
+
sequence_length: Number of content pieces in the sequence
|
| 110 |
+
|
| 111 |
+
Returns:
|
| 112 |
+
Dictionary with adaptive content sequence
|
| 113 |
+
"""
|
| 114 |
+
try:
|
| 115 |
+
prompt = f"""
|
| 116 |
+
Create an adaptive content sequence for the topic: "{topic}"
|
| 117 |
+
|
| 118 |
+
Student Profile:
|
| 119 |
+
{json.dumps(student_profile, indent=2)}
|
| 120 |
+
|
| 121 |
+
Generate a sequence of {sequence_length} interconnected content pieces that:
|
| 122 |
+
1. Build upon each other progressively
|
| 123 |
+
2. Adapt to the student's learning style and preferences
|
| 124 |
+
3. Include multiple content types (text, visual descriptions, interactive elements)
|
| 125 |
+
4. Provide branching paths based on understanding
|
| 126 |
+
5. Include assessment checkpoints
|
| 127 |
+
6. Offer remediation and enrichment options
|
| 128 |
+
|
| 129 |
+
Return JSON with:
|
| 130 |
+
- "sequence_id": unique identifier for the sequence
|
| 131 |
+
- "topic": main topic
|
| 132 |
+
- "total_pieces": number of content pieces
|
| 133 |
+
- "estimated_total_time": total estimated time in minutes
|
| 134 |
+
- "content_sequence": array of content pieces, each with:
|
| 135 |
+
- "piece_id": unique identifier
|
| 136 |
+
- "title": content title
|
| 137 |
+
- "content_type": type of content (explanation, example, practice, assessment)
|
| 138 |
+
- "content": main content text
|
| 139 |
+
- "visual_elements": descriptions of visual components
|
| 140 |
+
- "interactive_elements": interactive components
|
| 141 |
+
- "difficulty_level": difficulty rating
|
| 142 |
+
- "prerequisites": what student should know
|
| 143 |
+
- "learning_objectives": specific objectives for this piece
|
| 144 |
+
- "assessment_questions": questions to check understanding
|
| 145 |
+
- "branching_options": different paths based on performance
|
| 146 |
+
- "estimated_time": time for this piece
|
| 147 |
+
- "adaptation_rules": rules for how content adapts to student responses
|
| 148 |
+
- "success_criteria": criteria for successful completion
|
| 149 |
+
"""
|
| 150 |
+
|
| 151 |
+
response = await MODEL.generate_text(prompt, temperature=0.6)
|
| 152 |
+
sequence_data = extract_json_from_text(response)
|
| 153 |
+
|
| 154 |
+
# Add metadata
|
| 155 |
+
sequence_data.update({
|
| 156 |
+
"success": True,
|
| 157 |
+
"topic": topic,
|
| 158 |
+
"student_profile": student_profile,
|
| 159 |
+
"generated_at": datetime.utcnow().isoformat(),
|
| 160 |
+
"ai_generated": True
|
| 161 |
+
})
|
| 162 |
+
|
| 163 |
+
return sequence_data
|
| 164 |
+
|
| 165 |
+
except Exception as e:
|
| 166 |
+
return {
|
| 167 |
+
"success": False,
|
| 168 |
+
"error": f"Failed to generate adaptive content sequence: {str(e)}"
|
| 169 |
+
}
|
| 170 |
+
|
| 171 |
+
@mcp.tool()
|
| 172 |
+
async def generate_scenario_based_learning(concept: str, scenario_type: str = "real_world",
|
| 173 |
+
complexity_level: str = "moderate") -> dict:
|
| 174 |
+
"""
|
| 175 |
+
Generate scenario-based learning content with realistic situations.
|
| 176 |
+
|
| 177 |
+
Args:
|
| 178 |
+
concept: The concept to teach through scenarios
|
| 179 |
+
scenario_type: Type of scenario ('real_world', 'historical', 'futuristic', 'problem_solving')
|
| 180 |
+
complexity_level: Complexity of the scenario ('simple', 'moderate', 'complex')
|
| 181 |
+
|
| 182 |
+
Returns:
|
| 183 |
+
Dictionary with scenario-based learning content
|
| 184 |
+
"""
|
| 185 |
+
try:
|
| 186 |
+
prompt = f"""
|
| 187 |
+
Create a {scenario_type} scenario-based learning experience for: "{concept}"
|
| 188 |
+
|
| 189 |
+
Scenario Parameters:
|
| 190 |
+
- Type: {scenario_type}
|
| 191 |
+
- Complexity: {complexity_level}
|
| 192 |
+
|
| 193 |
+
Design a realistic scenario that:
|
| 194 |
+
1. Presents the concept in a meaningful context
|
| 195 |
+
2. Requires students to apply their knowledge
|
| 196 |
+
3. Includes decision points and consequences
|
| 197 |
+
4. Provides multiple solution paths
|
| 198 |
+
5. Connects to real-world applications
|
| 199 |
+
6. Engages students emotionally and intellectually
|
| 200 |
+
|
| 201 |
+
Return JSON with:
|
| 202 |
+
- "scenario_id": unique identifier
|
| 203 |
+
- "title": compelling scenario title
|
| 204 |
+
- "setting": detailed description of the scenario setting
|
| 205 |
+
- "background_story": engaging background narrative
|
| 206 |
+
- "main_challenge": primary challenge students must solve
|
| 207 |
+
- "characters": key characters in the scenario (if applicable)
|
| 208 |
+
- "decision_points": critical decisions students must make
|
| 209 |
+
- "possible_outcomes": different outcomes based on decisions
|
| 210 |
+
- "learning_integration": how the concept is woven into the scenario
|
| 211 |
+
- "assessment_criteria": how to evaluate student responses
|
| 212 |
+
- "discussion_questions": questions for reflection and discussion
|
| 213 |
+
- "extension_scenarios": related scenarios for further exploration
|
| 214 |
+
- "real_world_connections": connections to actual situations
|
| 215 |
+
- "resources": additional resources students might need
|
| 216 |
+
"""
|
| 217 |
+
|
| 218 |
+
response = await MODEL.generate_text(prompt, temperature=0.8)
|
| 219 |
+
scenario_data = extract_json_from_text(response)
|
| 220 |
+
|
| 221 |
+
# Add metadata
|
| 222 |
+
scenario_data.update({
|
| 223 |
+
"success": True,
|
| 224 |
+
"concept": concept,
|
| 225 |
+
"scenario_type": scenario_type,
|
| 226 |
+
"complexity_level": complexity_level,
|
| 227 |
+
"generated_at": datetime.utcnow().isoformat(),
|
| 228 |
+
"ai_generated": True
|
| 229 |
+
})
|
| 230 |
+
|
| 231 |
+
return scenario_data
|
| 232 |
+
|
| 233 |
+
except Exception as e:
|
| 234 |
+
return {
|
| 235 |
+
"success": False,
|
| 236 |
+
"error": f"Failed to generate scenario-based learning: {str(e)}"
|
| 237 |
+
}
|
| 238 |
+
|
| 239 |
+
@mcp.tool()
|
| 240 |
+
async def generate_multimodal_content(concept: str, modalities: List[str] = None,
|
| 241 |
+
target_audience: str = "general") -> dict:
|
| 242 |
+
"""
|
| 243 |
+
Generate multi-modal content that appeals to different learning styles.
|
| 244 |
+
|
| 245 |
+
Args:
|
| 246 |
+
concept: The concept to create content for
|
| 247 |
+
modalities: List of modalities to include ('visual', 'auditory', 'kinesthetic', 'reading')
|
| 248 |
+
target_audience: Target audience description
|
| 249 |
+
|
| 250 |
+
Returns:
|
| 251 |
+
Dictionary with multi-modal content
|
| 252 |
+
"""
|
| 253 |
+
try:
|
| 254 |
+
if not modalities:
|
| 255 |
+
modalities = ["visual", "auditory", "kinesthetic", "reading"]
|
| 256 |
+
|
| 257 |
+
prompt = f"""
|
| 258 |
+
Create multi-modal content for the concept: "{concept}"
|
| 259 |
+
|
| 260 |
+
Target Audience: {target_audience}
|
| 261 |
+
Modalities to include: {modalities}
|
| 262 |
+
|
| 263 |
+
Generate content that appeals to different learning styles:
|
| 264 |
+
|
| 265 |
+
Return JSON with:
|
| 266 |
+
- "content_id": unique identifier
|
| 267 |
+
- "concept": the main concept
|
| 268 |
+
- "visual_content": content for visual learners (descriptions of diagrams, charts, images)
|
| 269 |
+
- "auditory_content": content for auditory learners (descriptions of sounds, music, verbal explanations)
|
| 270 |
+
- "kinesthetic_content": content for kinesthetic learners (hands-on activities, movement, manipulation)
|
| 271 |
+
- "reading_content": content for reading/writing learners (text-based materials, written exercises)
|
| 272 |
+
- "integrated_activities": activities that combine multiple modalities
|
| 273 |
+
- "accessibility_features": features for students with different abilities
|
| 274 |
+
- "technology_integration": how technology can enhance each modality
|
| 275 |
+
- "assessment_variations": different ways to assess understanding for each modality
|
| 276 |
+
- "adaptation_guidelines": how to adapt content for different needs
|
| 277 |
+
"""
|
| 278 |
+
|
| 279 |
+
response = await MODEL.generate_text(prompt, temperature=0.7)
|
| 280 |
+
content_data = extract_json_from_text(response)
|
| 281 |
+
|
| 282 |
+
# Add metadata
|
| 283 |
+
content_data.update({
|
| 284 |
+
"success": True,
|
| 285 |
+
"concept": concept,
|
| 286 |
+
"modalities": modalities,
|
| 287 |
+
"target_audience": target_audience,
|
| 288 |
+
"generated_at": datetime.utcnow().isoformat(),
|
| 289 |
+
"ai_generated": True
|
| 290 |
+
})
|
| 291 |
+
|
| 292 |
+
return content_data
|
| 293 |
+
|
| 294 |
+
except Exception as e:
|
| 295 |
+
return {
|
| 296 |
+
"success": False,
|
| 297 |
+
"error": f"Failed to generate multimodal content: {str(e)}"
|
| 298 |
+
}
|
| 299 |
+
|
| 300 |
+
@mcp.tool()
|
| 301 |
+
async def generate_adaptive_assessment(concept: str, assessment_type: str = "formative",
|
| 302 |
+
student_data: dict = None) -> dict:
|
| 303 |
+
"""
|
| 304 |
+
Generate adaptive assessments that adjust based on student responses.
|
| 305 |
+
|
| 306 |
+
Args:
|
| 307 |
+
concept: The concept to assess
|
| 308 |
+
assessment_type: Type of assessment ('formative', 'summative', 'diagnostic', 'peer')
|
| 309 |
+
student_data: Optional student performance data
|
| 310 |
+
|
| 311 |
+
Returns:
|
| 312 |
+
Dictionary with adaptive assessment content
|
| 313 |
+
"""
|
| 314 |
+
try:
|
| 315 |
+
prompt = f"""
|
| 316 |
+
Create an adaptive {assessment_type} assessment for: "{concept}"
|
| 317 |
+
|
| 318 |
+
Student Data: {json.dumps(student_data or {}, indent=2)}
|
| 319 |
+
|
| 320 |
+
Design an assessment that:
|
| 321 |
+
1. Adapts difficulty based on student responses
|
| 322 |
+
2. Provides immediate feedback
|
| 323 |
+
3. Identifies learning gaps
|
| 324 |
+
4. Offers multiple question types
|
| 325 |
+
5. Includes branching logic
|
| 326 |
+
6. Provides detailed analytics
|
| 327 |
+
|
| 328 |
+
Return JSON with:
|
| 329 |
+
- "assessment_id": unique identifier
|
| 330 |
+
- "title": assessment title
|
| 331 |
+
- "instructions": clear instructions for students
|
| 332 |
+
- "question_pool": large pool of questions with metadata:
|
| 333 |
+
- "question_id": unique identifier
|
| 334 |
+
- "question_text": the question
|
| 335 |
+
- "question_type": type (multiple_choice, short_answer, essay, etc.)
|
| 336 |
+
- "difficulty_level": difficulty rating (0.0 to 1.0)
|
| 337 |
+
- "cognitive_level": Bloom's taxonomy level
|
| 338 |
+
- "options": answer options (if applicable)
|
| 339 |
+
- "correct_answer": correct answer
|
| 340 |
+
- "explanation": detailed explanation
|
| 341 |
+
- "hints": progressive hints
|
| 342 |
+
- "common_misconceptions": common wrong answers and why
|
| 343 |
+
- "adaptive_rules": rules for question selection and difficulty adjustment
|
| 344 |
+
- "feedback_templates": templates for different types of feedback
|
| 345 |
+
- "scoring_rubric": detailed scoring criteria
|
| 346 |
+
- "analytics_tracking": what data to track for analysis
|
| 347 |
+
- "remediation_suggestions": suggestions based on performance
|
| 348 |
+
"""
|
| 349 |
+
|
| 350 |
+
response = await MODEL.generate_text(prompt, temperature=0.6)
|
| 351 |
+
assessment_data = extract_json_from_text(response)
|
| 352 |
+
|
| 353 |
+
# Add metadata
|
| 354 |
+
assessment_data.update({
|
| 355 |
+
"success": True,
|
| 356 |
+
"concept": concept,
|
| 357 |
+
"assessment_type": assessment_type,
|
| 358 |
+
"generated_at": datetime.utcnow().isoformat(),
|
| 359 |
+
"ai_generated": True
|
| 360 |
+
})
|
| 361 |
+
|
| 362 |
+
return assessment_data
|
| 363 |
+
|
| 364 |
+
except Exception as e:
|
| 365 |
+
return {
|
| 366 |
+
"success": False,
|
| 367 |
+
"error": f"Failed to generate adaptive assessment: {str(e)}"
|
| 368 |
+
}
|
| 369 |
+
|
| 370 |
+
@mcp.tool()
|
| 371 |
+
async def generate_gamified_content(concept: str, game_type: str = "quest",
|
| 372 |
+
target_age_group: str = "teen") -> dict:
|
| 373 |
+
"""
|
| 374 |
+
Generate gamified learning content with game mechanics and engagement features.
|
| 375 |
+
|
| 376 |
+
Args:
|
| 377 |
+
concept: The concept to gamify
|
| 378 |
+
game_type: Type of game ('quest', 'puzzle', 'simulation', 'competition', 'story')
|
| 379 |
+
target_age_group: Target age group ('child', 'teen', 'adult')
|
| 380 |
+
|
| 381 |
+
Returns:
|
| 382 |
+
Dictionary with gamified content
|
| 383 |
+
"""
|
| 384 |
+
try:
|
| 385 |
+
prompt = f"""
|
| 386 |
+
Create gamified learning content for: "{concept}"
|
| 387 |
+
|
| 388 |
+
Game Parameters:
|
| 389 |
+
- Game Type: {game_type}
|
| 390 |
+
- Target Age Group: {target_age_group}
|
| 391 |
+
|
| 392 |
+
Design engaging game-based learning that includes:
|
| 393 |
+
1. Clear game objectives aligned with learning goals
|
| 394 |
+
2. Progressive difficulty levels
|
| 395 |
+
3. Reward systems and achievements
|
| 396 |
+
4. Interactive challenges
|
| 397 |
+
5. Narrative elements (if applicable)
|
| 398 |
+
6. Social features for collaboration/competition
|
| 399 |
+
|
| 400 |
+
Return JSON with:
|
| 401 |
+
- "game_id": unique identifier
|
| 402 |
+
- "title": engaging game title
|
| 403 |
+
- "theme": game theme and setting
|
| 404 |
+
- "storyline": narrative framework (if applicable)
|
| 405 |
+
- "learning_objectives": educational goals
|
| 406 |
+
- "game_mechanics": core game mechanics and rules
|
| 407 |
+
- "levels": progressive levels with increasing difficulty
|
| 408 |
+
- "challenges": specific challenges and tasks
|
| 409 |
+
- "reward_system": points, badges, achievements
|
| 410 |
+
- "character_progression": how players advance
|
| 411 |
+
- "social_features": multiplayer or collaborative elements
|
| 412 |
+
- "assessment_integration": how learning is assessed within the game
|
| 413 |
+
- "feedback_mechanisms": how players receive feedback
|
| 414 |
+
- "customization_options": ways to personalize the experience
|
| 415 |
+
- "accessibility_features": features for different abilities
|
| 416 |
+
"""
|
| 417 |
+
|
| 418 |
+
response = await MODEL.generate_text(prompt, temperature=0.8)
|
| 419 |
+
game_data = extract_json_from_text(response)
|
| 420 |
+
|
| 421 |
+
# Add metadata
|
| 422 |
+
game_data.update({
|
| 423 |
+
"success": True,
|
| 424 |
+
"concept": concept,
|
| 425 |
+
"game_type": game_type,
|
| 426 |
+
"target_age_group": target_age_group,
|
| 427 |
+
"generated_at": datetime.utcnow().isoformat(),
|
| 428 |
+
"ai_generated": True
|
| 429 |
+
})
|
| 430 |
+
|
| 431 |
+
return game_data
|
| 432 |
+
|
| 433 |
+
except Exception as e:
|
| 434 |
+
return {
|
| 435 |
+
"success": False,
|
| 436 |
+
"error": f"Failed to generate gamified content: {str(e)}"
|
| 437 |
+
}
|
| 438 |
+
|
| 439 |
+
@mcp.tool()
|
| 440 |
+
async def validate_generated_content(content_data: dict, validation_criteria: dict = None) -> dict:
|
| 441 |
+
"""
|
| 442 |
+
Validate and quality-check generated educational content.
|
| 443 |
+
|
| 444 |
+
Args:
|
| 445 |
+
content_data: The content to validate
|
| 446 |
+
validation_criteria: Specific criteria for validation
|
| 447 |
+
|
| 448 |
+
Returns:
|
| 449 |
+
Dictionary with validation results and suggestions
|
| 450 |
+
"""
|
| 451 |
+
try:
|
| 452 |
+
default_criteria = {
|
| 453 |
+
"educational_alignment": True,
|
| 454 |
+
"age_appropriateness": True,
|
| 455 |
+
"clarity": True,
|
| 456 |
+
"engagement": True,
|
| 457 |
+
"accessibility": True,
|
| 458 |
+
"accuracy": True
|
| 459 |
+
}
|
| 460 |
+
|
| 461 |
+
criteria = {**default_criteria, **(validation_criteria or {})}
|
| 462 |
+
|
| 463 |
+
prompt = f"""
|
| 464 |
+
Validate this educational content against quality criteria:
|
| 465 |
+
|
| 466 |
+
Content to Validate:
|
| 467 |
+
{json.dumps(content_data, indent=2)}
|
| 468 |
+
|
| 469 |
+
Validation Criteria:
|
| 470 |
+
{json.dumps(criteria, indent=2)}
|
| 471 |
+
|
| 472 |
+
Perform comprehensive validation and return JSON with:
|
| 473 |
+
- "overall_quality_score": score from 0.0 to 1.0
|
| 474 |
+
- "validation_results": detailed results for each criterion
|
| 475 |
+
- "strengths": identified strengths in the content
|
| 476 |
+
- "areas_for_improvement": specific areas that need work
|
| 477 |
+
- "suggestions": concrete suggestions for improvement
|
| 478 |
+
- "compliance_check": compliance with educational standards
|
| 479 |
+
- "accessibility_assessment": accessibility for different learners
|
| 480 |
+
- "engagement_analysis": analysis of engagement potential
|
| 481 |
+
- "accuracy_verification": verification of factual accuracy
|
| 482 |
+
- "recommended_modifications": specific modifications to make
|
| 483 |
+
"""
|
| 484 |
+
|
| 485 |
+
response = await MODEL.generate_text(prompt, temperature=0.3)
|
| 486 |
+
validation_data = extract_json_from_text(response)
|
| 487 |
+
|
| 488 |
+
return {
|
| 489 |
+
"success": True,
|
| 490 |
+
"content_validated": True,
|
| 491 |
+
"validation_timestamp": datetime.utcnow().isoformat(),
|
| 492 |
+
**validation_data
|
| 493 |
+
}
|
| 494 |
+
|
| 495 |
+
except Exception as e:
|
| 496 |
+
return {
|
| 497 |
+
"success": False,
|
| 498 |
+
"error": f"Failed to validate content: {str(e)}"
|
| 499 |
+
}
|
tests/test_ai_integration.py
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""
|
| 3 |
+
Test script for the new AI integration features in TutorX-MCP.
|
| 4 |
+
Tests the contextualized AI tutoring and automated content generation.
|
| 5 |
+
"""
|
| 6 |
+
|
| 7 |
+
import asyncio
|
| 8 |
+
import json
|
| 9 |
+
import sys
|
| 10 |
+
import os
|
| 11 |
+
|
| 12 |
+
# Add the current directory to the Python path
|
| 13 |
+
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
| 14 |
+
|
| 15 |
+
from mcp_server.tools.ai_tutor_tools import (
|
| 16 |
+
start_tutoring_session,
|
| 17 |
+
ai_tutor_chat,
|
| 18 |
+
get_step_by_step_guidance,
|
| 19 |
+
get_alternative_explanations,
|
| 20 |
+
end_tutoring_session
|
| 21 |
+
)
|
| 22 |
+
|
| 23 |
+
from mcp_server.tools.content_generation_tools import (
|
| 24 |
+
generate_interactive_exercise,
|
| 25 |
+
generate_scenario_based_learning,
|
| 26 |
+
generate_gamified_content
|
| 27 |
+
)
|
| 28 |
+
|
| 29 |
+
async def test_ai_tutoring():
|
| 30 |
+
"""Test the AI tutoring functionality"""
|
| 31 |
+
print("🤖 Testing AI Tutoring Features...")
|
| 32 |
+
|
| 33 |
+
# Test 1: Start a tutoring session
|
| 34 |
+
print("\n1. Starting tutoring session...")
|
| 35 |
+
session_result = await start_tutoring_session(
|
| 36 |
+
student_id="test_student_001",
|
| 37 |
+
subject="Mathematics",
|
| 38 |
+
learning_objectives=["Understand quadratic equations", "Learn factoring methods"]
|
| 39 |
+
)
|
| 40 |
+
print(f"Session started: {session_result.get('success', False)}")
|
| 41 |
+
|
| 42 |
+
if not session_result.get('success'):
|
| 43 |
+
print(f"❌ Failed to start session: {session_result.get('error')}")
|
| 44 |
+
return
|
| 45 |
+
|
| 46 |
+
session_id = session_result.get('session_id')
|
| 47 |
+
print(f"Session ID: {session_id}")
|
| 48 |
+
|
| 49 |
+
# Test 2: Chat with AI tutor
|
| 50 |
+
print("\n2. Chatting with AI tutor...")
|
| 51 |
+
chat_result = await ai_tutor_chat(
|
| 52 |
+
session_id=session_id,
|
| 53 |
+
student_query="How do I solve quadratic equations?",
|
| 54 |
+
request_type="explanation"
|
| 55 |
+
)
|
| 56 |
+
print(f"Chat response received: {chat_result.get('success', False)}")
|
| 57 |
+
|
| 58 |
+
# Test 3: Get step-by-step guidance
|
| 59 |
+
print("\n3. Getting step-by-step guidance...")
|
| 60 |
+
steps_result = await get_step_by_step_guidance(
|
| 61 |
+
session_id=session_id,
|
| 62 |
+
concept="Solving quadratic equations",
|
| 63 |
+
current_step=1
|
| 64 |
+
)
|
| 65 |
+
print(f"Step-by-step guidance received: {steps_result.get('success', False)}")
|
| 66 |
+
|
| 67 |
+
# Test 4: Get alternative explanations
|
| 68 |
+
print("\n4. Getting alternative explanations...")
|
| 69 |
+
alt_result = await get_alternative_explanations(
|
| 70 |
+
session_id=session_id,
|
| 71 |
+
concept="Quadratic formula",
|
| 72 |
+
explanation_types=["visual", "analogy", "real_world"]
|
| 73 |
+
)
|
| 74 |
+
print(f"Alternative explanations received: {alt_result.get('success', False)}")
|
| 75 |
+
|
| 76 |
+
# Test 5: End session
|
| 77 |
+
print("\n5. Ending tutoring session...")
|
| 78 |
+
end_result = await end_tutoring_session(
|
| 79 |
+
session_id=session_id,
|
| 80 |
+
session_summary="Learned about quadratic equations and different solving methods"
|
| 81 |
+
)
|
| 82 |
+
print(f"Session ended: {end_result.get('success', False)}")
|
| 83 |
+
|
| 84 |
+
print("✅ AI Tutoring tests completed!")
|
| 85 |
+
|
| 86 |
+
async def test_content_generation():
|
| 87 |
+
"""Test the content generation functionality"""
|
| 88 |
+
print("\n🎨 Testing Content Generation Features...")
|
| 89 |
+
|
| 90 |
+
# Test 1: Generate interactive exercise
|
| 91 |
+
print("\n1. Generating interactive exercise...")
|
| 92 |
+
exercise_result = await generate_interactive_exercise(
|
| 93 |
+
concept="Photosynthesis",
|
| 94 |
+
exercise_type="simulation",
|
| 95 |
+
difficulty_level=0.6,
|
| 96 |
+
student_level="intermediate"
|
| 97 |
+
)
|
| 98 |
+
print(f"Interactive exercise generated: {exercise_result.get('success', False)}")
|
| 99 |
+
|
| 100 |
+
# Test 2: Generate scenario-based learning
|
| 101 |
+
print("\n2. Generating scenario-based learning...")
|
| 102 |
+
scenario_result = await generate_scenario_based_learning(
|
| 103 |
+
concept="Climate Change",
|
| 104 |
+
scenario_type="real_world",
|
| 105 |
+
complexity_level="moderate"
|
| 106 |
+
)
|
| 107 |
+
print(f"Scenario-based learning generated: {scenario_result.get('success', False)}")
|
| 108 |
+
|
| 109 |
+
# Test 3: Generate gamified content
|
| 110 |
+
print("\n3. Generating gamified content...")
|
| 111 |
+
game_result = await generate_gamified_content(
|
| 112 |
+
concept="Fractions",
|
| 113 |
+
game_type="quest",
|
| 114 |
+
target_age_group="teen"
|
| 115 |
+
)
|
| 116 |
+
print(f"Gamified content generated: {game_result.get('success', False)}")
|
| 117 |
+
|
| 118 |
+
print("✅ Content Generation tests completed!")
|
| 119 |
+
|
| 120 |
+
async def main():
|
| 121 |
+
"""Run all tests"""
|
| 122 |
+
print("🚀 Starting TutorX AI Integration Tests...")
|
| 123 |
+
print("=" * 50)
|
| 124 |
+
|
| 125 |
+
try:
|
| 126 |
+
# Test AI Tutoring
|
| 127 |
+
await test_ai_tutoring()
|
| 128 |
+
|
| 129 |
+
# Test Content Generation
|
| 130 |
+
await test_content_generation()
|
| 131 |
+
|
| 132 |
+
print("\n" + "=" * 50)
|
| 133 |
+
print("🎉 All tests completed successfully!")
|
| 134 |
+
|
| 135 |
+
except Exception as e:
|
| 136 |
+
print(f"\n❌ Test failed with error: {str(e)}")
|
| 137 |
+
import traceback
|
| 138 |
+
traceback.print_exc()
|
| 139 |
+
|
| 140 |
+
if __name__ == "__main__":
|
| 141 |
+
asyncio.run(main())
|