# modules/nlp/api.py from fastapi import APIRouter, Depends, HTTPException from sqlalchemy.orm import Session from typing import List from core.database import get_db from modules.auth.dependencies import get_current_user from modules.auth.models import User from modules.nlp.service import process_request, ask_ai # Import the response schema from modules.nlp.schemas import ProcessCommandRequest, ProcessCommandResponse from modules.calendar.service import create_calendar_event, get_calendar_events, update_calendar_event, delete_calendar_event # Import the CalendarEvent *model* for type hinting from modules.calendar.models import CalendarEvent # Import the CalendarEvent Pydantic schemas for data validation from modules.calendar.schemas import CalendarEventCreate, CalendarEventUpdate router = APIRouter(prefix="/nlp", tags=["nlp"]) # Helper to format calendar events (expects list of CalendarEvent models) def format_calendar_events(events: List[CalendarEvent]) -> List[str]: if not events: return ["You have no events matching that criteria."] formatted = ["Here are the events:"] for event in events: # Access attributes directly from the model instance start_str = event.start.strftime("%Y-%m-%d %H:%M") if event.start else "No start time" end_str = event.end.strftime("%H:%M") if event.end else "" title = event.title or "Untitled Event" formatted.append(f"- {title} ({start_str}{' - ' + end_str if end_str else ''})") return formatted # Update the response model for the endpoint @router.post("/process-command", response_model=ProcessCommandResponse) def process_command(request_data: ProcessCommandRequest, current_user: User = Depends(get_current_user), db: Session = Depends(get_db)): """ Process the user command, execute the action, and return user-friendly responses. """ user_input = request_data.user_input command_data = process_request(user_input) intent = command_data["intent"] params = command_data["params"] response_text = command_data["response_text"] responses = [response_text] # Start with the initial response if intent == "error": raise HTTPException(status_code=400, detail=response_text) if intent == "clarification_needed" or intent == "unknown": return ProcessCommandResponse(responses=responses) try: match intent: case "ask_ai": ai_answer = ask_ai(**params) responses.append(ai_answer) return ProcessCommandResponse(responses=responses) case "get_calendar_events": # get_calendar_events returns List[CalendarEvent models] events: List[CalendarEvent] = get_calendar_events(db, current_user.id, **params) responses.extend(format_calendar_events(events)) return ProcessCommandResponse(responses=responses) case "add_calendar_event": # Validate input with Pydantic schema event_data = CalendarEventCreate(**params) created_event = create_calendar_event(db, current_user.id, event_data) start_str = created_event.start.strftime("%Y-%m-%d %H:%M") if created_event.start else "No start time" title = created_event.title or "Untitled Event" responses.append(f"Added: {title} starting at {start_str}.") return ProcessCommandResponse(responses=responses) case "update_calendar_event": event_id = params.pop('event_id', None) if event_id is None: raise HTTPException(status_code=400, detail="Event ID is required for update.") # Validate input with Pydantic schema event_data = CalendarEventUpdate(**params) updated_event = update_calendar_event(db, current_user.id, event_id, event_data=event_data) title = updated_event.title or "Untitled Event" responses.append(f"Updated event ID {updated_event.id}: {title}.") return ProcessCommandResponse(responses=responses) case "delete_calendar_event": event_id = params.get('event_id') if event_id is None: raise HTTPException(status_code=400, detail="Event ID is required for delete.") delete_calendar_event(db, current_user.id, event_id) responses.append(f"Deleted event ID {event_id}.") return ProcessCommandResponse(responses=responses) case _: print(f"Warning: Unhandled intent '{intent}' reached api.py match statement.") return ProcessCommandResponse(responses=responses) except HTTPException as http_exc: raise http_exc except Exception as e: print(f"Error executing intent '{intent}': {e}") return ProcessCommandResponse(responses=["Sorry, I encountered an error while trying to perform that action."])