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())
|