Spaces:
Sleeping
Sleeping
Meet Patel
commited on
Commit
·
71c0fd0
1
Parent(s):
3d56f3d
Fix some major issue with api and integrations
Browse files- .coverage +0 -0
- README.md +1 -16
- client.py +2 -49
- docs/api.md +0 -368
- docs/prd.md +2 -16
- main.py +2 -122
- utils/integrations.py +0 -251
.coverage
ADDED
|
Binary file (53.2 kB). View file
|
|
|
README.md
CHANGED
|
@@ -166,25 +166,10 @@ uv install -e ".[test]"
|
|
| 166 |
python run_tests.py
|
| 167 |
```
|
| 168 |
|
| 169 |
-
|
| 170 |
-
|
| 171 |
-
TutorX-MCP can integrate with various external educational systems:
|
| 172 |
-
|
| 173 |
-
1. **Learning Management Systems (LMS)**
|
| 174 |
-
- Canvas, Moodle, Blackboard
|
| 175 |
-
- Grade syncing and assignment management
|
| 176 |
-
|
| 177 |
-
2. **Open Educational Resources (OER)**
|
| 178 |
-
- Search and integration with OER repositories
|
| 179 |
-
- Access to diverse educational content
|
| 180 |
-
|
| 181 |
-
3. **Real-time Personalized Tutoring Platforms**
|
| 182 |
-
- Schedule and manage tutoring sessions
|
| 183 |
-
- Connect students with expert tutors
|
| 184 |
|
| 185 |
## Documentation
|
| 186 |
|
| 187 |
-
- [API Documentation](docs/api.md): Complete API reference for developers
|
| 188 |
- [MCP Protocol](docs/mcp.md): Details about the Model Context Protocol
|
| 189 |
- [Product Requirements](docs/prd.md): Original requirements document
|
| 190 |
- [SDK Documentation](docs/sdk.md): Client SDK usage
|
|
|
|
| 166 |
python run_tests.py
|
| 167 |
```
|
| 168 |
|
| 169 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 170 |
|
| 171 |
## Documentation
|
| 172 |
|
|
|
|
| 173 |
- [MCP Protocol](docs/mcp.md): Details about the Model Context Protocol
|
| 174 |
- [Product Requirements](docs/prd.md): Original requirements document
|
| 175 |
- [SDK Documentation](docs/sdk.md): Client SDK usage
|
client.py
CHANGED
|
@@ -190,60 +190,13 @@ class TutorXClient:
|
|
| 190 |
return self._call_tool("get_student_analytics", {
|
| 191 |
"student_id": student_id,
|
| 192 |
"timeframe_days": timeframe_days
|
| 193 |
-
})
|
| 194 |
-
|
| 195 |
"""Check student submission for potential plagiarism"""
|
| 196 |
return self._call_tool("check_submission_originality", {
|
| 197 |
"submission": submission,
|
| 198 |
"reference_sources": reference_sources
|
| 199 |
})
|
| 200 |
-
|
| 201 |
-
# ------------ External Integrations ------------
|
| 202 |
-
|
| 203 |
-
def lms_sync_grades(self, lms_type: str, api_url: str, api_key: str,
|
| 204 |
-
course_id: str, assignment_id: str,
|
| 205 |
-
grades: List[Dict[str, Any]]) -> Dict[str, Any]:
|
| 206 |
-
"""Sync grades with a Learning Management System"""
|
| 207 |
-
return self._call_tool("lms_sync_grades", {
|
| 208 |
-
"lms_type": lms_type,
|
| 209 |
-
"api_url": api_url,
|
| 210 |
-
"api_key": api_key,
|
| 211 |
-
"course_id": course_id,
|
| 212 |
-
"assignment_id": assignment_id,
|
| 213 |
-
"grades": grades
|
| 214 |
-
})
|
| 215 |
-
|
| 216 |
-
def oer_search(self, repository_url: str, query: str,
|
| 217 |
-
subject: Optional[str] = None, grade_level: Optional[str] = None,
|
| 218 |
-
api_key: Optional[str] = None) -> Dict[str, Any]:
|
| 219 |
-
"""Search for educational resources in OER repositories"""
|
| 220 |
-
params = {
|
| 221 |
-
"repository_url": repository_url,
|
| 222 |
-
"query": query
|
| 223 |
-
}
|
| 224 |
-
|
| 225 |
-
if subject:
|
| 226 |
-
params["subject"] = subject
|
| 227 |
-
|
| 228 |
-
if grade_level:
|
| 229 |
-
params["grade_level"] = grade_level
|
| 230 |
-
|
| 231 |
-
if api_key:
|
| 232 |
-
params["api_key"] = api_key
|
| 233 |
-
|
| 234 |
-
return self._call_tool("oer_search", params)
|
| 235 |
-
|
| 236 |
-
def schedule_tutoring_session(self, platform_url: str, client_id: str, client_secret: str,
|
| 237 |
-
student_id: str, subject: str, datetime_str: str) -> Dict[str, Any]:
|
| 238 |
-
"""Schedule a session with a real-time personalized tutoring platform"""
|
| 239 |
-
return self._call_tool("schedule_tutoring_session", {
|
| 240 |
-
"platform_url": platform_url,
|
| 241 |
-
"client_id": client_id,
|
| 242 |
-
"client_secret": client_secret,
|
| 243 |
-
"student_id": student_id,
|
| 244 |
-
"subject": subject,
|
| 245 |
-
"datetime_str": datetime_str
|
| 246 |
-
})
|
| 247 |
|
| 248 |
# Create a default client instance for easy import
|
| 249 |
client = TutorXClient()
|
|
|
|
| 190 |
return self._call_tool("get_student_analytics", {
|
| 191 |
"student_id": student_id,
|
| 192 |
"timeframe_days": timeframe_days
|
| 193 |
+
})
|
| 194 |
+
def check_submission_originality(self, submission: str, reference_sources: List[str]) -> Dict[str, Any]:
|
| 195 |
"""Check student submission for potential plagiarism"""
|
| 196 |
return self._call_tool("check_submission_originality", {
|
| 197 |
"submission": submission,
|
| 198 |
"reference_sources": reference_sources
|
| 199 |
})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 200 |
|
| 201 |
# Create a default client instance for easy import
|
| 202 |
client = TutorXClient()
|
docs/api.md
DELETED
|
@@ -1,368 +0,0 @@
|
|
| 1 |
-
# TutorX-MCP API Documentation
|
| 2 |
-
|
| 3 |
-
This document provides comprehensive documentation for the TutorX-MCP API for developers who want to integrate with the system.
|
| 4 |
-
|
| 5 |
-
## API Overview
|
| 6 |
-
|
| 7 |
-
The TutorX-MCP server exposes a Model Context Protocol (MCP) API that allows clients to interact with various educational tools and resources. This API follows the standard MCP protocol as defined in [MCP Specification](https://github.com/anthropics/anthropic-tools/blob/main/mcp/README.md).
|
| 8 |
-
|
| 9 |
-
## Authentication
|
| 10 |
-
|
| 11 |
-
For production deployments, all API requests should include an API key in the `Authorization` header:
|
| 12 |
-
|
| 13 |
-
```
|
| 14 |
-
Authorization: Bearer your-api-key-here
|
| 15 |
-
```
|
| 16 |
-
|
| 17 |
-
## Base URL
|
| 18 |
-
|
| 19 |
-
Default: `http://localhost:8000`
|
| 20 |
-
|
| 21 |
-
For production: See your deployment configuration
|
| 22 |
-
|
| 23 |
-
## Tools API
|
| 24 |
-
|
| 25 |
-
Tools represent functionality that can be invoked by MCP clients. Each tool is accessed via:
|
| 26 |
-
|
| 27 |
-
```
|
| 28 |
-
POST /tools/{tool_name}
|
| 29 |
-
Content-Type: application/json
|
| 30 |
-
|
| 31 |
-
{
|
| 32 |
-
"param1": "value1",
|
| 33 |
-
"param2": "value2"
|
| 34 |
-
}
|
| 35 |
-
```
|
| 36 |
-
|
| 37 |
-
### Core Features
|
| 38 |
-
|
| 39 |
-
#### Adaptive Learning Engine
|
| 40 |
-
|
| 41 |
-
##### `assess_skill`
|
| 42 |
-
|
| 43 |
-
Assess a student's skill level on a specific concept.
|
| 44 |
-
|
| 45 |
-
**Request:**
|
| 46 |
-
```json
|
| 47 |
-
{
|
| 48 |
-
"student_id": "student123",
|
| 49 |
-
"concept_id": "math_algebra_basics"
|
| 50 |
-
}
|
| 51 |
-
```
|
| 52 |
-
|
| 53 |
-
**Response:**
|
| 54 |
-
```json
|
| 55 |
-
{
|
| 56 |
-
"student_id": "student123",
|
| 57 |
-
"concept_id": "math_algebra_basics",
|
| 58 |
-
"skill_level": 0.75,
|
| 59 |
-
"confidence": 0.85,
|
| 60 |
-
"recommendations": [
|
| 61 |
-
"Practice more complex problems",
|
| 62 |
-
"Review related concept: algebra_linear_equations"
|
| 63 |
-
],
|
| 64 |
-
"timestamp": "2025-06-07T10:30:45.123456"
|
| 65 |
-
}
|
| 66 |
-
```
|
| 67 |
-
|
| 68 |
-
##### `generate_quiz`
|
| 69 |
-
|
| 70 |
-
Generate a quiz based on specified concepts and difficulty.
|
| 71 |
-
|
| 72 |
-
**Request:**
|
| 73 |
-
```json
|
| 74 |
-
{
|
| 75 |
-
"concept_ids": ["math_algebra_basics", "math_algebra_linear_equations"],
|
| 76 |
-
"difficulty": 2
|
| 77 |
-
}
|
| 78 |
-
```
|
| 79 |
-
|
| 80 |
-
**Response:**
|
| 81 |
-
```json
|
| 82 |
-
{
|
| 83 |
-
"quiz_id": "q12345",
|
| 84 |
-
"concept_ids": ["math_algebra_basics", "math_algebra_linear_equations"],
|
| 85 |
-
"difficulty": 2,
|
| 86 |
-
"questions": [
|
| 87 |
-
{
|
| 88 |
-
"id": "q1",
|
| 89 |
-
"text": "Solve for x: 2x + 3 = 7",
|
| 90 |
-
"type": "algebraic_equation",
|
| 91 |
-
"answer": "x = 2",
|
| 92 |
-
"solution_steps": [
|
| 93 |
-
"2x + 3 = 7",
|
| 94 |
-
"2x = 7 - 3",
|
| 95 |
-
"2x = 4",
|
| 96 |
-
"x = 4/2 = 2"
|
| 97 |
-
]
|
| 98 |
-
}
|
| 99 |
-
]
|
| 100 |
-
}
|
| 101 |
-
```
|
| 102 |
-
|
| 103 |
-
#### Feedback System
|
| 104 |
-
|
| 105 |
-
##### `analyze_error_patterns`
|
| 106 |
-
|
| 107 |
-
Analyze common error patterns for a student on a specific concept.
|
| 108 |
-
|
| 109 |
-
**Request:**
|
| 110 |
-
```json
|
| 111 |
-
{
|
| 112 |
-
"student_id": "student123",
|
| 113 |
-
"concept_id": "math_algebra_basics"
|
| 114 |
-
}
|
| 115 |
-
```
|
| 116 |
-
|
| 117 |
-
**Response:**
|
| 118 |
-
```json
|
| 119 |
-
{
|
| 120 |
-
"student_id": "student123",
|
| 121 |
-
"concept_id": "math_algebra_basics",
|
| 122 |
-
"common_errors": [
|
| 123 |
-
{
|
| 124 |
-
"type": "sign_error",
|
| 125 |
-
"frequency": 0.65,
|
| 126 |
-
"example": "2x - 3 = 5 → 2x = 5 - 3 → 2x = 2 → x = 1 (should be x = 4)"
|
| 127 |
-
}
|
| 128 |
-
],
|
| 129 |
-
"recommendations": [
|
| 130 |
-
"Practice more sign manipulation problems"
|
| 131 |
-
]
|
| 132 |
-
}
|
| 133 |
-
```
|
| 134 |
-
|
| 135 |
-
### Advanced Features
|
| 136 |
-
|
| 137 |
-
#### Neurological Engagement Monitor
|
| 138 |
-
|
| 139 |
-
##### `analyze_cognitive_state`
|
| 140 |
-
|
| 141 |
-
Analyze EEG data to determine cognitive state.
|
| 142 |
-
|
| 143 |
-
**Request:**
|
| 144 |
-
```json
|
| 145 |
-
{
|
| 146 |
-
"eeg_data": {
|
| 147 |
-
"channels": [...],
|
| 148 |
-
"sampling_rate": 256,
|
| 149 |
-
"duration": 10.0
|
| 150 |
-
}
|
| 151 |
-
}
|
| 152 |
-
```
|
| 153 |
-
|
| 154 |
-
**Response:**
|
| 155 |
-
```json
|
| 156 |
-
{
|
| 157 |
-
"attention_level": 0.82,
|
| 158 |
-
"cognitive_load": 0.65,
|
| 159 |
-
"stress_level": 0.25,
|
| 160 |
-
"recommendations": [
|
| 161 |
-
"Student is engaged but approaching cognitive overload",
|
| 162 |
-
"Consider simplifying next problems slightly"
|
| 163 |
-
],
|
| 164 |
-
"timestamp": "2025-06-07T10:32:15.123456"
|
| 165 |
-
}
|
| 166 |
-
```
|
| 167 |
-
|
| 168 |
-
### External Integrations
|
| 169 |
-
|
| 170 |
-
#### Learning Management Systems
|
| 171 |
-
|
| 172 |
-
##### `lms_sync_grades`
|
| 173 |
-
|
| 174 |
-
Sync grades with a Learning Management System.
|
| 175 |
-
|
| 176 |
-
**Request:**
|
| 177 |
-
```json
|
| 178 |
-
{
|
| 179 |
-
"lms_type": "canvas",
|
| 180 |
-
"api_url": "https://canvas.example.com/api/v1",
|
| 181 |
-
"api_key": "your-api-key",
|
| 182 |
-
"course_id": "course123",
|
| 183 |
-
"assignment_id": "assign456",
|
| 184 |
-
"grades": [
|
| 185 |
-
{
|
| 186 |
-
"student_id": "student123",
|
| 187 |
-
"score": 85.5
|
| 188 |
-
}
|
| 189 |
-
]
|
| 190 |
-
}
|
| 191 |
-
```
|
| 192 |
-
|
| 193 |
-
**Response:**
|
| 194 |
-
```json
|
| 195 |
-
{
|
| 196 |
-
"success": true,
|
| 197 |
-
"timestamp": "2025-06-07T10:35:22.123456",
|
| 198 |
-
"message": "Grades successfully synced"
|
| 199 |
-
}
|
| 200 |
-
```
|
| 201 |
-
|
| 202 |
-
#### Open Educational Resources
|
| 203 |
-
|
| 204 |
-
##### `oer_search`
|
| 205 |
-
|
| 206 |
-
Search for educational resources in OER repositories.
|
| 207 |
-
|
| 208 |
-
**Request:**
|
| 209 |
-
```json
|
| 210 |
-
{
|
| 211 |
-
"repository_url": "https://oer.example.com/api",
|
| 212 |
-
"query": "linear equations",
|
| 213 |
-
"subject": "mathematics",
|
| 214 |
-
"grade_level": "8"
|
| 215 |
-
}
|
| 216 |
-
```
|
| 217 |
-
|
| 218 |
-
**Response:**
|
| 219 |
-
```json
|
| 220 |
-
{
|
| 221 |
-
"success": true,
|
| 222 |
-
"count": 2,
|
| 223 |
-
"results": [
|
| 224 |
-
{
|
| 225 |
-
"id": "resource123",
|
| 226 |
-
"title": "Introduction to Linear Equations",
|
| 227 |
-
"description": "A comprehensive guide to solving linear equations",
|
| 228 |
-
"url": "https://oer.example.com/resources/resource123",
|
| 229 |
-
"subject": "mathematics",
|
| 230 |
-
"grade_level": "8-9",
|
| 231 |
-
"license": "CC-BY"
|
| 232 |
-
}
|
| 233 |
-
],
|
| 234 |
-
"timestamp": "2025-06-07T10:36:12.123456"
|
| 235 |
-
}
|
| 236 |
-
```
|
| 237 |
-
|
| 238 |
-
#### Real-Time Personalized Tutoring
|
| 239 |
-
|
| 240 |
-
##### `schedule_tutoring_session`
|
| 241 |
-
|
| 242 |
-
Schedule a session with a real-time personalized tutoring platform.
|
| 243 |
-
|
| 244 |
-
**Request:**
|
| 245 |
-
```json
|
| 246 |
-
{
|
| 247 |
-
"platform_url": "https://tutoring.example.com/api",
|
| 248 |
-
"client_id": "your-client-id",
|
| 249 |
-
"client_secret": "your-client-secret",
|
| 250 |
-
"student_id": "student123",
|
| 251 |
-
"subject": "mathematics",
|
| 252 |
-
"datetime_str": "2025-06-10T15:00:00Z"
|
| 253 |
-
}
|
| 254 |
-
```
|
| 255 |
-
|
| 256 |
-
**Response:**
|
| 257 |
-
```json
|
| 258 |
-
{
|
| 259 |
-
"success": true,
|
| 260 |
-
"session_id": "session789",
|
| 261 |
-
"tutor": {
|
| 262 |
-
"id": "tutor456",
|
| 263 |
-
"name": "Dr. Jane Smith",
|
| 264 |
-
"rating": 4.9,
|
| 265 |
-
"specialization": "mathematics"
|
| 266 |
-
},
|
| 267 |
-
"datetime": "2025-06-10T15:00:00Z",
|
| 268 |
-
"join_url": "https://tutoring.example.com/session/session789",
|
| 269 |
-
"timestamp": "2025-06-07T10:37:45.123456"
|
| 270 |
-
}
|
| 271 |
-
```
|
| 272 |
-
|
| 273 |
-
## Resources API
|
| 274 |
-
|
| 275 |
-
Resources represent data that can be fetched by MCP clients. Each resource is accessed via:
|
| 276 |
-
|
| 277 |
-
```
|
| 278 |
-
GET /resources?uri={resource_uri}
|
| 279 |
-
Accept: application/json
|
| 280 |
-
```
|
| 281 |
-
|
| 282 |
-
### Available Resources
|
| 283 |
-
|
| 284 |
-
#### `concept-graph://`
|
| 285 |
-
|
| 286 |
-
Retrieves the full knowledge concept graph.
|
| 287 |
-
|
| 288 |
-
#### `learning-path://{student_id}`
|
| 289 |
-
|
| 290 |
-
Retrieves the personalized learning path for a student.
|
| 291 |
-
|
| 292 |
-
#### `curriculum-standards://{country_code}`
|
| 293 |
-
|
| 294 |
-
Retrieves curriculum standards for a specific country.
|
| 295 |
-
|
| 296 |
-
#### `student-dashboard://{student_id}`
|
| 297 |
-
|
| 298 |
-
Retrieves dashboard data for a specific student.
|
| 299 |
-
|
| 300 |
-
## Error Handling
|
| 301 |
-
|
| 302 |
-
API errors follow a standard format:
|
| 303 |
-
|
| 304 |
-
```json
|
| 305 |
-
{
|
| 306 |
-
"error": {
|
| 307 |
-
"code": "error_code",
|
| 308 |
-
"message": "Human-readable error message",
|
| 309 |
-
"details": {}
|
| 310 |
-
}
|
| 311 |
-
}
|
| 312 |
-
```
|
| 313 |
-
|
| 314 |
-
Common error codes:
|
| 315 |
-
- `invalid_request`: The request was malformed
|
| 316 |
-
- `authentication_error`: Authentication failed
|
| 317 |
-
- `not_found`: The requested resource does not exist
|
| 318 |
-
- `server_error`: Internal server error
|
| 319 |
-
|
| 320 |
-
## Rate Limiting
|
| 321 |
-
|
| 322 |
-
Production deployments implement rate limiting to prevent abuse. Clients should monitor the following headers:
|
| 323 |
-
|
| 324 |
-
- `X-RateLimit-Limit`: Maximum requests per hour
|
| 325 |
-
- `X-RateLimit-Remaining`: Remaining requests for the current hour
|
| 326 |
-
- `X-RateLimit-Reset`: Timestamp when the limit will reset
|
| 327 |
-
|
| 328 |
-
## SDK
|
| 329 |
-
|
| 330 |
-
For easier integration, we provide client SDKs in multiple languages:
|
| 331 |
-
|
| 332 |
-
- Python: `pip install tutorx-client`
|
| 333 |
-
- JavaScript: `npm install tutorx-client`
|
| 334 |
-
|
| 335 |
-
Example usage (Python):
|
| 336 |
-
|
| 337 |
-
```python
|
| 338 |
-
from tutorx_client import TutorXClient
|
| 339 |
-
|
| 340 |
-
client = TutorXClient("http://localhost:8000", api_key="your-api-key")
|
| 341 |
-
|
| 342 |
-
# Call a tool
|
| 343 |
-
result = client.assess_skill("student123", "math_algebra_basics")
|
| 344 |
-
print(result["skill_level"])
|
| 345 |
-
|
| 346 |
-
# Access a resource
|
| 347 |
-
concept_graph = client.get_concept_graph()
|
| 348 |
-
```
|
| 349 |
-
|
| 350 |
-
## Webhooks
|
| 351 |
-
|
| 352 |
-
For real-time updates, you can register webhook endpoints:
|
| 353 |
-
|
| 354 |
-
```
|
| 355 |
-
POST /webhooks/register
|
| 356 |
-
Content-Type: application/json
|
| 357 |
-
Authorization: Bearer your-api-key
|
| 358 |
-
|
| 359 |
-
{
|
| 360 |
-
"url": "https://your-app.example.com/webhook",
|
| 361 |
-
"events": ["assessment.completed", "badge.awarded"],
|
| 362 |
-
"secret": "your-webhook-secret"
|
| 363 |
-
}
|
| 364 |
-
```
|
| 365 |
-
|
| 366 |
-
## Support
|
| 367 |
-
|
| 368 |
-
For API support, contact us at [email protected]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
docs/prd.md
CHANGED
|
@@ -51,7 +51,6 @@ To provide an adaptive, multi-modal, and collaborative AI tutoring platform acce
|
|
| 51 |
- **Feedback System**
|
| 52 |
- Contextual error analysis and suggestions
|
| 53 |
- Multimodal feedback (text, audio, visual)
|
| 54 |
-
- Emotional state recognition (via webcam/EEG)
|
| 55 |
|
| 56 |
## 3.2 Advanced Features
|
| 57 |
|
|
@@ -74,8 +73,6 @@ To provide an adaptive, multi-modal, and collaborative AI tutoring platform acce
|
|
| 74 |
- **Accessibility**
|
| 75 |
- Screen reader compatibility
|
| 76 |
- Text-to-speech and adjustable interface
|
| 77 |
-
- **Gamification**
|
| 78 |
-
- Badges, leaderboards, token-based rewards
|
| 79 |
|
| 80 |
---
|
| 81 |
|
|
@@ -85,18 +82,7 @@ To provide an adaptive, multi-modal, and collaborative AI tutoring platform acce
|
|
| 85 |
- **Gradio Interface:** User-friendly, customizable, and accessible
|
| 86 |
- **Microservices Architecture:** Modular design for scalability
|
| 87 |
- **Real-Time Data Processing:** Asynchronous task queues and caching
|
| 88 |
-
- **
|
| 89 |
-
- **Integration:** Supports external APIs, LMS, and educational tools
|
| 90 |
-
|
| 91 |
-
---
|
| 92 |
-
|
| 93 |
-
## 5. Non-Functional Requirements
|
| 94 |
-
|
| 95 |
-
- **Performance:** Supports 100+ concurrent users with <1s response time for core features
|
| 96 |
-
- **Security:** End-to-end encryption, role-based access control
|
| 97 |
-
- **Privacy:** Compliant with GDPR, COPPA, and FERPA
|
| 98 |
-
- **Scalability:** Horizontally scalable to support large institutions
|
| 99 |
-
- **Accessibility:** WCAG 2.1 AA compliant
|
| 100 |
|
| 101 |
---
|
| 102 |
|
|
@@ -115,7 +101,7 @@ To provide an adaptive, multi-modal, and collaborative AI tutoring platform acce
|
|
| 115 |
1. **Phase 1:** Core adaptive learning engine and MCP integration
|
| 116 |
2. **Phase 2:** Multi-modal interaction and collaborative tools
|
| 117 |
3. **Phase 3:** Advanced features (engagement monitor, lesson authoring)
|
| 118 |
-
4. **Phase 4:**
|
| 119 |
|
| 120 |
---
|
| 121 |
|
|
|
|
| 51 |
- **Feedback System**
|
| 52 |
- Contextual error analysis and suggestions
|
| 53 |
- Multimodal feedback (text, audio, visual)
|
|
|
|
| 54 |
|
| 55 |
## 3.2 Advanced Features
|
| 56 |
|
|
|
|
| 73 |
- **Accessibility**
|
| 74 |
- Screen reader compatibility
|
| 75 |
- Text-to-speech and adjustable interface
|
|
|
|
|
|
|
| 76 |
|
| 77 |
---
|
| 78 |
|
|
|
|
| 82 |
- **Gradio Interface:** User-friendly, customizable, and accessible
|
| 83 |
- **Microservices Architecture:** Modular design for scalability
|
| 84 |
- **Real-Time Data Processing:** Asynchronous task queues and caching
|
| 85 |
+
- **Local Access:** Browser-based access from local machine
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 86 |
|
| 87 |
---
|
| 88 |
|
|
|
|
| 101 |
1. **Phase 1:** Core adaptive learning engine and MCP integration
|
| 102 |
2. **Phase 2:** Multi-modal interaction and collaborative tools
|
| 103 |
3. **Phase 3:** Advanced features (engagement monitor, lesson authoring)
|
| 104 |
+
4. **Phase 4:** Analytics and performance monitoring
|
| 105 |
|
| 106 |
---
|
| 107 |
|
main.py
CHANGED
|
@@ -18,11 +18,6 @@ from utils.assessment import (
|
|
| 18 |
generate_performance_analytics,
|
| 19 |
detect_plagiarism
|
| 20 |
)
|
| 21 |
-
from utils.integrations import (
|
| 22 |
-
LMSIntegration,
|
| 23 |
-
OERIntegration,
|
| 24 |
-
RTPTIntegration
|
| 25 |
-
)
|
| 26 |
|
| 27 |
# Create the TutorX MCP server
|
| 28 |
mcp = FastMCP("TutorX")
|
|
@@ -581,124 +576,9 @@ def check_submission_originality(submission: str, reference_sources: List[str])
|
|
| 581 |
reference_sources: List of reference texts to check against
|
| 582 |
|
| 583 |
Returns:
|
| 584 |
-
Originality analysis
|
| 585 |
-
return detect_plagiarism(submission, reference_sources)
|
| 586 |
-
|
| 587 |
-
# ------------------ External Integrations ------------------
|
| 588 |
-
|
| 589 |
-
@mcp.tool()
|
| 590 |
-
def lms_sync_grades(lms_type: str, api_url: str, api_key: str,
|
| 591 |
-
course_id: str, assignment_id: str,
|
| 592 |
-
grades: List[Dict[str, Any]]) -> Dict[str, Any]:
|
| 593 |
-
"""
|
| 594 |
-
Sync grades with a Learning Management System
|
| 595 |
-
|
| 596 |
-
Args:
|
| 597 |
-
lms_type: Type of LMS ('canvas', 'moodle', 'blackboard')
|
| 598 |
-
api_url: URL for the LMS API
|
| 599 |
-
api_key: API key for authentication
|
| 600 |
-
course_id: ID of the course
|
| 601 |
-
assignment_id: ID of the assignment
|
| 602 |
-
grades: List of grade data to sync
|
| 603 |
-
|
| 604 |
-
Returns:
|
| 605 |
-
Status of the sync operation
|
| 606 |
"""
|
| 607 |
-
|
| 608 |
-
lms = LMSIntegration(lms_type, api_url, api_key)
|
| 609 |
-
success = lms.sync_grades(course_id, assignment_id, grades)
|
| 610 |
-
return {
|
| 611 |
-
"success": success,
|
| 612 |
-
"timestamp": datetime.now().isoformat(),
|
| 613 |
-
"message": "Grades successfully synced" if success else "Failed to sync grades"
|
| 614 |
-
}
|
| 615 |
-
except Exception as e:
|
| 616 |
-
return {
|
| 617 |
-
"success": False,
|
| 618 |
-
"error": str(e),
|
| 619 |
-
"timestamp": datetime.now().isoformat()
|
| 620 |
-
}
|
| 621 |
-
|
| 622 |
-
@mcp.tool()
|
| 623 |
-
def oer_search(repository_url: str, query: str,
|
| 624 |
-
subject: Optional[str] = None, grade_level: Optional[str] = None,
|
| 625 |
-
api_key: Optional[str] = None) -> Dict[str, Any]:
|
| 626 |
-
"""
|
| 627 |
-
Search for educational resources in OER repositories
|
| 628 |
-
|
| 629 |
-
Args:
|
| 630 |
-
repository_url: URL of the OER repository
|
| 631 |
-
query: Search query
|
| 632 |
-
subject: Optional subject filter
|
| 633 |
-
grade_level: Optional grade level filter
|
| 634 |
-
api_key: Optional API key if required
|
| 635 |
-
|
| 636 |
-
Returns:
|
| 637 |
-
List of matching resources
|
| 638 |
-
"""
|
| 639 |
-
try:
|
| 640 |
-
oer = OERIntegration(repository_url, api_key)
|
| 641 |
-
results = oer.search_resources(query, subject, grade_level)
|
| 642 |
-
return {
|
| 643 |
-
"success": True,
|
| 644 |
-
"count": len(results),
|
| 645 |
-
"results": results,
|
| 646 |
-
"timestamp": datetime.now().isoformat()
|
| 647 |
-
}
|
| 648 |
-
except Exception as e:
|
| 649 |
-
return {
|
| 650 |
-
"success": False,
|
| 651 |
-
"error": str(e),
|
| 652 |
-
"timestamp": datetime.now().isoformat()
|
| 653 |
-
}
|
| 654 |
-
|
| 655 |
-
@mcp.tool()
|
| 656 |
-
def schedule_tutoring_session(platform_url: str, client_id: str, client_secret: str,
|
| 657 |
-
student_id: str, subject: str, datetime_str: str) -> Dict[str, Any]:
|
| 658 |
-
"""
|
| 659 |
-
Schedule a session with a real-time personalized tutoring platform
|
| 660 |
-
|
| 661 |
-
Args:
|
| 662 |
-
platform_url: URL of the tutoring platform
|
| 663 |
-
client_id: OAuth client ID
|
| 664 |
-
client_secret: OAuth client secret
|
| 665 |
-
student_id: ID of the student
|
| 666 |
-
subject: Subject for tutoring
|
| 667 |
-
datetime_str: ISO format datetime for the session
|
| 668 |
-
|
| 669 |
-
Returns:
|
| 670 |
-
Session details
|
| 671 |
-
"""
|
| 672 |
-
try:
|
| 673 |
-
# Find an available tutor
|
| 674 |
-
rtpt = RTPTIntegration(platform_url, client_id, client_secret)
|
| 675 |
-
tutors = rtpt.get_available_tutors(subject, "intermediate")
|
| 676 |
-
|
| 677 |
-
if not tutors:
|
| 678 |
-
return {
|
| 679 |
-
"success": False,
|
| 680 |
-
"message": "No tutors available for this subject",
|
| 681 |
-
"timestamp": datetime.now().isoformat()
|
| 682 |
-
}
|
| 683 |
-
|
| 684 |
-
# Schedule with first available tutor
|
| 685 |
-
tutor_id = tutors[0]["id"]
|
| 686 |
-
session = rtpt.schedule_session(student_id, tutor_id, subject, datetime_str)
|
| 687 |
-
|
| 688 |
-
return {
|
| 689 |
-
"success": True,
|
| 690 |
-
"session_id": session.get("id"),
|
| 691 |
-
"tutor": session.get("tutor"),
|
| 692 |
-
"datetime": session.get("datetime"),
|
| 693 |
-
"join_url": session.get("join_url"),
|
| 694 |
-
"timestamp": datetime.now().isoformat()
|
| 695 |
-
}
|
| 696 |
-
except Exception as e:
|
| 697 |
-
return {
|
| 698 |
-
"success": False,
|
| 699 |
-
"error": str(e),
|
| 700 |
-
"timestamp": datetime.now().isoformat()
|
| 701 |
-
}
|
| 702 |
|
| 703 |
if __name__ == "__main__":
|
| 704 |
mcp.run()
|
|
|
|
| 18 |
generate_performance_analytics,
|
| 19 |
detect_plagiarism
|
| 20 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 21 |
|
| 22 |
# Create the TutorX MCP server
|
| 23 |
mcp = FastMCP("TutorX")
|
|
|
|
| 576 |
reference_sources: List of reference texts to check against
|
| 577 |
|
| 578 |
Returns:
|
| 579 |
+
Originality analysis
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 580 |
"""
|
| 581 |
+
return detect_plagiarism(submission, reference_sources)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 582 |
|
| 583 |
if __name__ == "__main__":
|
| 584 |
mcp.run()
|
utils/integrations.py
DELETED
|
@@ -1,251 +0,0 @@
|
|
| 1 |
-
"""
|
| 2 |
-
Integration utilities for connecting TutorX-MCP with external educational systems
|
| 3 |
-
"""
|
| 4 |
-
|
| 5 |
-
import requests
|
| 6 |
-
import json
|
| 7 |
-
import os
|
| 8 |
-
from typing import Dict, Any, List, Optional
|
| 9 |
-
import logging
|
| 10 |
-
|
| 11 |
-
logger = logging.getLogger(__name__)
|
| 12 |
-
|
| 13 |
-
class LMSIntegration:
|
| 14 |
-
"""Integration with Learning Management Systems (Canvas, Moodle, etc.)"""
|
| 15 |
-
|
| 16 |
-
def __init__(self, lms_type: str, api_url: str, api_key: str):
|
| 17 |
-
"""
|
| 18 |
-
Initialize LMS integration
|
| 19 |
-
|
| 20 |
-
Args:
|
| 21 |
-
lms_type: Type of LMS ('canvas', 'moodle', 'blackboard', etc.)
|
| 22 |
-
api_url: Base URL for LMS API
|
| 23 |
-
api_key: API key or token for authentication
|
| 24 |
-
"""
|
| 25 |
-
self.lms_type = lms_type.lower()
|
| 26 |
-
self.api_url = api_url.rstrip('/')
|
| 27 |
-
self.api_key = api_key
|
| 28 |
-
|
| 29 |
-
def get_courses(self) -> List[Dict[str, Any]]:
|
| 30 |
-
"""Get list of courses from LMS"""
|
| 31 |
-
if self.lms_type == 'canvas':
|
| 32 |
-
return self._canvas_get_courses()
|
| 33 |
-
elif self.lms_type == 'moodle':
|
| 34 |
-
return self._moodle_get_courses()
|
| 35 |
-
else:
|
| 36 |
-
raise ValueError(f"Unsupported LMS type: {self.lms_type}")
|
| 37 |
-
|
| 38 |
-
def _canvas_get_courses(self) -> List[Dict[str, Any]]:
|
| 39 |
-
"""Get courses from Canvas LMS"""
|
| 40 |
-
headers = {"Authorization": f"Bearer {self.api_key}"}
|
| 41 |
-
response = requests.get(f"{self.api_url}/courses", headers=headers)
|
| 42 |
-
response.raise_for_status()
|
| 43 |
-
return response.json()
|
| 44 |
-
|
| 45 |
-
def _moodle_get_courses(self) -> List[Dict[str, Any]]:
|
| 46 |
-
"""Get courses from Moodle"""
|
| 47 |
-
params = {
|
| 48 |
-
"wstoken": self.api_key,
|
| 49 |
-
"wsfunction": "core_course_get_courses",
|
| 50 |
-
"moodlewsrestformat": "json"
|
| 51 |
-
}
|
| 52 |
-
response = requests.get(f"{self.api_url}/webservice/rest/server.php", params=params)
|
| 53 |
-
response.raise_for_status()
|
| 54 |
-
return response.json()
|
| 55 |
-
|
| 56 |
-
def sync_grades(self, course_id: str, assignment_id: str, grades: List[Dict[str, Any]]) -> bool:
|
| 57 |
-
"""
|
| 58 |
-
Sync grades to LMS
|
| 59 |
-
|
| 60 |
-
Args:
|
| 61 |
-
course_id: ID of the course
|
| 62 |
-
assignment_id: ID of the assignment
|
| 63 |
-
grades: List of grade data to sync
|
| 64 |
-
|
| 65 |
-
Returns:
|
| 66 |
-
Success status
|
| 67 |
-
"""
|
| 68 |
-
try:
|
| 69 |
-
if self.lms_type == 'canvas':
|
| 70 |
-
return self._canvas_sync_grades(course_id, assignment_id, grades)
|
| 71 |
-
elif self.lms_type == 'moodle':
|
| 72 |
-
return self._moodle_sync_grades(course_id, assignment_id, grades)
|
| 73 |
-
else:
|
| 74 |
-
raise ValueError(f"Unsupported LMS type: {self.lms_type}")
|
| 75 |
-
except Exception as e:
|
| 76 |
-
logger.error(f"Error syncing grades: {e}")
|
| 77 |
-
return False
|
| 78 |
-
|
| 79 |
-
def _canvas_sync_grades(self, course_id: str, assignment_id: str, grades: List[Dict[str, Any]]) -> bool:
|
| 80 |
-
"""Sync grades to Canvas LMS"""
|
| 81 |
-
headers = {"Authorization": f"Bearer {self.api_key}"}
|
| 82 |
-
|
| 83 |
-
for grade in grades:
|
| 84 |
-
data = {
|
| 85 |
-
"submission": {
|
| 86 |
-
"posted_grade": grade["score"]
|
| 87 |
-
}
|
| 88 |
-
}
|
| 89 |
-
|
| 90 |
-
url = f"{self.api_url}/courses/{course_id}/assignments/{assignment_id}/submissions/{grade['student_id']}"
|
| 91 |
-
response = requests.put(url, json=data, headers=headers)
|
| 92 |
-
|
| 93 |
-
if response.status_code != 200:
|
| 94 |
-
logger.error(f"Failed to sync grade for student {grade['student_id']}: {response.text}")
|
| 95 |
-
return False
|
| 96 |
-
|
| 97 |
-
return True
|
| 98 |
-
|
| 99 |
-
def _moodle_sync_grades(self, course_id: str, assignment_id: str, grades: List[Dict[str, Any]]) -> bool:
|
| 100 |
-
"""Sync grades to Moodle"""
|
| 101 |
-
# Implementation specific to Moodle's API
|
| 102 |
-
# This would use the Moodle grade update API
|
| 103 |
-
return True # Placeholder
|
| 104 |
-
|
| 105 |
-
class OERIntegration:
|
| 106 |
-
"""Integration with Open Educational Resources repositories"""
|
| 107 |
-
|
| 108 |
-
def __init__(self, repository_url: str, api_key: Optional[str] = None):
|
| 109 |
-
"""
|
| 110 |
-
Initialize OER repository integration
|
| 111 |
-
|
| 112 |
-
Args:
|
| 113 |
-
repository_url: Base URL for OER repository API
|
| 114 |
-
api_key: Optional API key if required by the repository
|
| 115 |
-
"""
|
| 116 |
-
self.repository_url = repository_url.rstrip('/')
|
| 117 |
-
self.api_key = api_key
|
| 118 |
-
|
| 119 |
-
def search_resources(self, query: str, subject: Optional[str] = None,
|
| 120 |
-
grade_level: Optional[str] = None) -> List[Dict[str, Any]]:
|
| 121 |
-
"""
|
| 122 |
-
Search for educational resources
|
| 123 |
-
|
| 124 |
-
Args:
|
| 125 |
-
query: Search query
|
| 126 |
-
subject: Optional subject filter
|
| 127 |
-
grade_level: Optional grade level filter
|
| 128 |
-
|
| 129 |
-
Returns:
|
| 130 |
-
List of matching resources
|
| 131 |
-
"""
|
| 132 |
-
params = {"q": query}
|
| 133 |
-
|
| 134 |
-
if subject:
|
| 135 |
-
params["subject"] = subject
|
| 136 |
-
|
| 137 |
-
if grade_level:
|
| 138 |
-
params["grade"] = grade_level
|
| 139 |
-
|
| 140 |
-
headers = {}
|
| 141 |
-
if self.api_key:
|
| 142 |
-
headers["Authorization"] = f"Bearer {self.api_key}"
|
| 143 |
-
|
| 144 |
-
response = requests.get(f"{self.repository_url}/search", params=params, headers=headers)
|
| 145 |
-
response.raise_for_status()
|
| 146 |
-
|
| 147 |
-
return response.json().get("results", [])
|
| 148 |
-
|
| 149 |
-
def get_resource(self, resource_id: str) -> Dict[str, Any]:
|
| 150 |
-
"""
|
| 151 |
-
Get details for a specific resource
|
| 152 |
-
|
| 153 |
-
Args:
|
| 154 |
-
resource_id: ID of the resource to fetch
|
| 155 |
-
|
| 156 |
-
Returns:
|
| 157 |
-
Resource details
|
| 158 |
-
"""
|
| 159 |
-
headers = {}
|
| 160 |
-
if self.api_key:
|
| 161 |
-
headers["Authorization"] = f"Bearer {self.api_key}"
|
| 162 |
-
|
| 163 |
-
response = requests.get(f"{self.repository_url}/resources/{resource_id}", headers=headers)
|
| 164 |
-
response.raise_for_status()
|
| 165 |
-
|
| 166 |
-
return response.json()
|
| 167 |
-
|
| 168 |
-
|
| 169 |
-
class RTPTIntegration:
|
| 170 |
-
"""Integration with real-time personalized tutoring platforms"""
|
| 171 |
-
|
| 172 |
-
def __init__(self, platform_url: str, client_id: str, client_secret: str):
|
| 173 |
-
"""
|
| 174 |
-
Initialize RTPT integration
|
| 175 |
-
|
| 176 |
-
Args:
|
| 177 |
-
platform_url: Base URL for RTPT platform API
|
| 178 |
-
client_id: OAuth client ID
|
| 179 |
-
client_secret: OAuth client secret
|
| 180 |
-
"""
|
| 181 |
-
self.platform_url = platform_url.rstrip('/')
|
| 182 |
-
self.client_id = client_id
|
| 183 |
-
self.client_secret = client_secret
|
| 184 |
-
self._access_token = None
|
| 185 |
-
|
| 186 |
-
def _get_access_token(self) -> str:
|
| 187 |
-
"""Get OAuth access token"""
|
| 188 |
-
if self._access_token:
|
| 189 |
-
return self._access_token
|
| 190 |
-
|
| 191 |
-
data = {
|
| 192 |
-
"grant_type": "client_credentials",
|
| 193 |
-
"client_id": self.client_id,
|
| 194 |
-
"client_secret": self.client_secret
|
| 195 |
-
}
|
| 196 |
-
|
| 197 |
-
response = requests.post(f"{self.platform_url}/oauth/token", data=data)
|
| 198 |
-
response.raise_for_status()
|
| 199 |
-
|
| 200 |
-
token_data = response.json()
|
| 201 |
-
self._access_token = token_data["access_token"]
|
| 202 |
-
return self._access_token
|
| 203 |
-
|
| 204 |
-
def get_available_tutors(self, subject: str, level: str) -> List[Dict[str, Any]]:
|
| 205 |
-
"""
|
| 206 |
-
Get available tutors for a subject and level
|
| 207 |
-
|
| 208 |
-
Args:
|
| 209 |
-
subject: Academic subject
|
| 210 |
-
level: Academic level
|
| 211 |
-
|
| 212 |
-
Returns:
|
| 213 |
-
List of available tutors
|
| 214 |
-
"""
|
| 215 |
-
headers = {"Authorization": f"Bearer {self._get_access_token()}"}
|
| 216 |
-
params = {
|
| 217 |
-
"subject": subject,
|
| 218 |
-
"level": level
|
| 219 |
-
}
|
| 220 |
-
|
| 221 |
-
response = requests.get(f"{self.platform_url}/tutors/available", params=params, headers=headers)
|
| 222 |
-
response.raise_for_status()
|
| 223 |
-
|
| 224 |
-
return response.json()
|
| 225 |
-
|
| 226 |
-
def schedule_session(self, student_id: str, tutor_id: str,
|
| 227 |
-
subject: str, datetime_str: str) -> Dict[str, Any]:
|
| 228 |
-
"""
|
| 229 |
-
Schedule a tutoring session
|
| 230 |
-
|
| 231 |
-
Args:
|
| 232 |
-
student_id: ID of the student
|
| 233 |
-
tutor_id: ID of the tutor
|
| 234 |
-
subject: Subject for tutoring
|
| 235 |
-
datetime_str: ISO format datetime for the session
|
| 236 |
-
|
| 237 |
-
Returns:
|
| 238 |
-
Session details
|
| 239 |
-
"""
|
| 240 |
-
headers = {"Authorization": f"Bearer {self._get_access_token()}"}
|
| 241 |
-
data = {
|
| 242 |
-
"student_id": student_id,
|
| 243 |
-
"tutor_id": tutor_id,
|
| 244 |
-
"subject": subject,
|
| 245 |
-
"datetime": datetime_str
|
| 246 |
-
}
|
| 247 |
-
|
| 248 |
-
response = requests.post(f"{self.platform_url}/sessions", json=data, headers=headers)
|
| 249 |
-
response.raise_for_status()
|
| 250 |
-
|
| 251 |
-
return response.json()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|