Spaces:
Sleeping
Sleeping
| from fastapi import APIRouter, status, Depends, BackgroundTasks, HTTPException | |
| from fastapi.responses import JSONResponse | |
| from src.utils.logger import logger | |
| from pydantic import BaseModel, Field | |
| from typing import List, Dict, Any, Optional | |
| from src.agents.lesson_practice.flow import lesson_practice_agent | |
| from src.apis.models.lesson_models import Lesson, LessonResponse, LessonDetailResponse | |
| import json | |
| import os | |
| import uuid | |
| from datetime import datetime | |
| router = APIRouter(prefix="/lesson", tags=["AI"]) | |
| class LessonPracticeRequest(BaseModel): | |
| unit: str = Field(..., description="Unit of the lesson") | |
| vocabulary: list = Field(..., description="Vocabulary for the lesson") | |
| key_structures: list = Field(..., description="Key structures for the lesson") | |
| practice_questions: list = Field( | |
| ..., description="Practice questions for the lesson" | |
| ) | |
| student_level: str = Field("beginner", description="Student's level of English") | |
| query: str = Field(..., description="User query for the lesson") | |
| session_id: str = Field(..., description="Session ID for the lesson") | |
| # Helper function to load lessons from JSON file | |
| def load_lessons_from_file() -> List[Lesson]: | |
| """Load lessons from the JSON file""" | |
| try: | |
| lessons_file_path = os.path.join(os.path.dirname(__file__), "..", "..", "data", "lessons.json") | |
| if not os.path.exists(lessons_file_path): | |
| logger.warning(f"Lessons file not found at {lessons_file_path}") | |
| return [] | |
| with open(lessons_file_path, 'r', encoding='utf-8') as file: | |
| lessons_data = json.load(file) | |
| # Convert to Lesson objects | |
| lessons = [] | |
| for lesson_data in lessons_data: | |
| try: | |
| lesson = Lesson(**lesson_data) | |
| lessons.append(lesson) | |
| except Exception as e: | |
| logger.error(f"Error parsing lesson {lesson_data.get('id', 'unknown')}: {str(e)}") | |
| continue | |
| return lessons | |
| except Exception as e: | |
| logger.error(f"Error loading lessons: {str(e)}") | |
| return [] | |
| async def get_all_lessons(): | |
| """ | |
| Get all available lessons | |
| Returns: | |
| LessonResponse: Contains list of all lessons and total count | |
| """ | |
| try: | |
| lessons = load_lessons_from_file() | |
| return LessonResponse( | |
| lessons=lessons, | |
| total=len(lessons) | |
| ) | |
| except Exception as e: | |
| logger.error(f"Error retrieving lessons: {str(e)}") | |
| raise HTTPException( | |
| status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, | |
| detail="Failed to retrieve lessons" | |
| ) | |
| async def get_lesson_by_id(lesson_id: str): | |
| """ | |
| Get a specific lesson by ID | |
| Args: | |
| lesson_id (str): The unique identifier of the lesson | |
| Returns: | |
| LessonDetailResponse: Contains the lesson details | |
| """ | |
| try: | |
| lessons = load_lessons_from_file() | |
| # Find the lesson with the specified ID | |
| lesson = next((l for l in lessons if l.id == lesson_id), None) | |
| if not lesson: | |
| raise HTTPException( | |
| status_code=status.HTTP_404_NOT_FOUND, | |
| detail=f"Lesson with ID '{lesson_id}' not found" | |
| ) | |
| return LessonDetailResponse(lesson=lesson) | |
| except HTTPException: | |
| raise | |
| except Exception as e: | |
| logger.error(f"Error retrieving lesson {lesson_id}: {str(e)}") | |
| raise HTTPException( | |
| status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, | |
| detail="Failed to retrieve lesson" | |
| ) | |
| async def search_lessons_by_unit(unit_name: str): | |
| """ | |
| Search lessons by unit name (case-insensitive partial match) | |
| Args: | |
| unit_name (str): Part of the unit name to search for | |
| Returns: | |
| LessonResponse: Contains list of matching lessons | |
| """ | |
| try: | |
| lessons = load_lessons_from_file() | |
| # Filter lessons by unit name (case-insensitive partial match) | |
| matching_lessons = [ | |
| lesson for lesson in lessons | |
| if unit_name.lower() in lesson.unit.lower() | |
| ] | |
| return LessonResponse( | |
| lessons=matching_lessons, | |
| total=len(matching_lessons) | |
| ) | |
| except Exception as e: | |
| logger.error(f"Error searching lessons by unit '{unit_name}': {str(e)}") | |
| raise HTTPException( | |
| status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, | |
| detail="Failed to search lessons" | |
| ) | |
| async def chat(request: LessonPracticeRequest): | |
| response = await lesson_practice_agent().ainvoke( | |
| { | |
| "unit": request.unit, | |
| "vocabulary": request.vocabulary, | |
| "key_structures": request.key_structures, | |
| "practice_questions": request.practice_questions, | |
| "student_level": request.student_level, | |
| "messages": [request.query], | |
| }, | |
| {"configurable": {"thread_id": request.session_id}}, | |
| ) | |
| return JSONResponse( | |
| content=response["messages"][-1].content, status_code=status.HTTP_200_OK | |
| ) | |