Spaces:
Sleeping
Sleeping
Meet Patel
Refactor response handling in app.py and various tool modules to improve JSON parsing and error management. Introduce utility functions for cleaning and extracting JSON from text, ensuring consistent data handling across quiz, lesson, learning path, and interaction tools. Enhance robustness by accommodating multiple response formats, including strings and dictionaries, to streamline educational interactions.
2dc3c19
""" | |
Concept-related MCP tools for TutorX. | |
""" | |
import random | |
from typing import Dict, Any, Optional | |
from datetime import datetime, timezone | |
import sys | |
import os | |
from pathlib import Path | |
import json | |
import re | |
# Add the parent directory to the Python path | |
current_dir = Path(__file__).parent | |
parent_dir = current_dir.parent.parent | |
sys.path.insert(0, str(parent_dir)) | |
# Import from local resources | |
from resources.concept_graph import get_concept, get_all_concepts | |
# Import MCP | |
from mcp_server.mcp_instance import mcp | |
from mcp_server.model.gemini_flash import GeminiFlash | |
MODEL = GeminiFlash() | |
def clean_json_trailing_commas(json_text: str) -> str: | |
return re.sub(r',([ \t\r\n]*[}}\]])', r'\1', json_text) | |
def extract_json_from_text(text: str): | |
if not text or not isinstance(text, str): | |
return None | |
# Remove code fences | |
text = re.sub(r'^\s*```(?:json)?\s*', '', text, flags=re.IGNORECASE) | |
text = re.sub(r'\s*```\s*$', '', text, flags=re.IGNORECASE) | |
text = text.strip() | |
# Remove trailing commas | |
cleaned = clean_json_trailing_commas(text) | |
return json.loads(cleaned) | |
async def get_concept_tool(concept_id: str = None) -> dict: | |
""" | |
Get a specific concept or all concepts from the knowledge graph, fully LLM-driven. | |
If a concept_id is provided, use Gemini to generate a JSON object with explanation, key points, and example. | |
""" | |
if not concept_id: | |
return {"error": "concept_id is required for LLM-driven mode"} | |
prompt = ( | |
f"Explain the concept '{concept_id}' in detail. " | |
f"Return a JSON object with fields: explanation (string), key_points (list of strings), and example (string)." | |
) | |
llm_response = await MODEL.generate_text(prompt) | |
try: | |
data = extract_json_from_text(llm_response) | |
except Exception: | |
data = {"llm_raw": llm_response, "error": "Failed to parse LLM output as JSON"} | |
return data | |
async def assess_skill_tool(student_id: str, concept_id: str) -> dict: | |
""" | |
Assess a student's understanding of a specific concept, fully LLM-driven. | |
Use Gemini to generate a JSON object with a score (0-1), feedback, and recommendations. | |
""" | |
prompt = ( | |
f"A student (ID: {student_id}) is being assessed on the concept '{concept_id}'. " | |
f"Generate a JSON object with: score (float 0-1), feedback (string), and recommendations (list of strings)." | |
) | |
llm_response = await MODEL.generate_text(prompt) | |
try: | |
data = extract_json_from_text(llm_response) | |
except Exception: | |
data = {"llm_raw": llm_response, "error": "Failed to parse LLM output as JSON"} | |
return data | |