Files
AICyclingCoach/backend/app/routes/plan.py
2025-09-12 09:08:10 -07:00

132 lines
4.1 KiB
Python

from fastapi import APIRouter, Depends, HTTPException, BackgroundTasks
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select
from backend.app.database import get_db
from backend.app.models.plan import Plan as PlanModel
from backend.app.models.rule import Rule
from backend.app.schemas.plan import PlanCreate, Plan as PlanSchema, PlanGenerationRequest, PlanGenerationResponse
from backend.app.dependencies import get_ai_service
from backend.app.services.ai_service import AIService
from uuid import UUID, uuid4
from datetime import datetime
from typing import List
router = APIRouter(prefix="/plans", tags=["Training Plans"])
@router.post("/", response_model=PlanSchema)
async def create_plan(
plan: PlanCreate,
db: AsyncSession = Depends(get_db)
):
# Create plan
db_plan = PlanModel(
jsonb_plan=plan.jsonb_plan,
version=plan.version,
parent_plan_id=plan.parent_plan_id
)
db.add(db_plan)
await db.commit()
await db.refresh(db_plan)
return db_plan
@router.get("/{plan_id}", response_model=PlanSchema)
async def read_plan(
plan_id: UUID,
db: AsyncSession = Depends(get_db)
):
plan = await db.get(PlanModel, plan_id)
if not plan:
raise HTTPException(status_code=404, detail="Plan not found")
return plan
@router.get("/", response_model=List[PlanSchema])
async def read_plans(
db: AsyncSession = Depends(get_db)
):
result = await db.execute(select(PlanModel))
return result.scalars().all()
@router.put("/{plan_id}", response_model=PlanSchema)
async def update_plan(
plan_id: UUID,
plan: PlanCreate,
db: AsyncSession = Depends(get_db)
):
db_plan = await db.get(PlanModel, plan_id)
if not db_plan:
raise HTTPException(status_code=404, detail="Plan not found")
# Update plan fields
db_plan.jsonb_plan = plan.jsonb_plan
db_plan.version = plan.version
db_plan.parent_plan_id = plan.parent_plan_id
await db.commit()
await db.refresh(db_plan)
return db_plan
@router.delete("/{plan_id}")
async def delete_plan(
plan_id: UUID,
db: AsyncSession = Depends(get_db)
):
plan = await db.get(PlanModel, plan_id)
if not plan:
raise HTTPException(status_code=404, detail="Plan not found")
await db.delete(plan)
await db.commit()
return {"detail": "Plan deleted"}
@router.post("/generate", response_model=PlanGenerationResponse)
async def generate_plan(
request: PlanGenerationRequest,
background_tasks: BackgroundTasks,
db: AsyncSession = Depends(get_db),
ai_service: AIService = Depends(get_ai_service)
):
"""
Generate a new training plan using AI based on provided goals and rule set.
"""
try:
# Get all rules from the provided rule IDs
rules = []
for rule_id in request.rule_ids:
rule = await db.get(Rule, rule_id)
if not rule:
raise HTTPException(status_code=404, detail=f"Rule with ID {rule_id} not found")
rules.append(rule.jsonb_rules)
# Generate plan using AI service
generated_plan = await ai_service.generate_training_plan(
rule_set=rules, # Pass all rules as a list
goals=request.goals.model_dump(),
preferred_routes=request.preferred_routes
)
# Create a Plan object for the response
plan_obj = PlanSchema(
id=uuid4(), # Generate a proper UUID
jsonb_plan=generated_plan,
version=1,
parent_plan_id=None,
created_at=datetime.utcnow()
)
# Create response with generated plan
response = PlanGenerationResponse(
plan=plan_obj,
generation_metadata={
"status": "success",
"generated_at": datetime.utcnow().isoformat(),
"rule_ids": [str(rule_id) for rule_id in request.rule_ids]
}
)
return response
except Exception as e:
raise HTTPException(
status_code=500,
detail=f"Failed to generate plan: {str(e)}"
)