from fastapi import APIRouter, Depends, HTTPException from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy import select from sqlalchemy.orm import selectinload from typing import List from uuid import UUID from app.db.session import get_db from app.models.project import Project as ProjectModel from app.models.scene import Scene as SceneModel from app.models.shot import Shot as ShotModel from app.schemas.project import Project, ProjectCreate from app.schemas.script import ScriptAnalysisResponse router = APIRouter() @router.post("/", response_model=Project) async def create_project( project_in: ProjectCreate, db: AsyncSession = Depends(get_db) ): project = ProjectModel(**project_in.model_dump()) db.add(project) await db.commit() await db.refresh(project) return project @router.get("/", response_model=List[Project]) async def list_projects( skip: int = 0, limit: int = 100, db: AsyncSession = Depends(get_db) ): result = await db.execute(select(ProjectModel).offset(skip).limit(limit)) return result.scalars().all() @router.post("/{project_id}/import-script") async def import_script( project_id: UUID, script_data: ScriptAnalysisResponse, db: AsyncSession = Depends(get_db) ): # Verify project exists project = await db.get(ProjectModel, project_id) if not project: raise HTTPException(status_code=404, detail="Project not found") # Clear existing scenes/shots for simplicity in this MVP existing_scenes = await db.execute(select(SceneModel).where(SceneModel.project_id == project_id)) for scene in existing_scenes.scalars(): await db.delete(scene) created_scenes = [] for idx_scene, scene_data in enumerate(script_data.scenes): scene_db = SceneModel( project_id=project_id, slugline=scene_data.heading, raw_content=scene_data.description, sequence_number=idx_scene + 1, ) db.add(scene_db) await db.flush() # get ID for idx_shot, shot_data in enumerate(scene_data.shots): shot_db = ShotModel( scene_id=scene_db.id, description=shot_data.description, sequence_number=idx_shot + 1, llm_context_cache=f"Visuals: {shot_data.visual_notes or 'None'}\nDialogue: {shot_data.dialogue or 'None'}", status="draft" ) db.add(shot_db) created_scenes.append(scene_db) await db.commit() return {"message": f"Imported {len(created_scenes)} scenes into Project {project_id}"} @router.get("/{project_id}/script") async def get_project_script( project_id: UUID, db: AsyncSession = Depends(get_db) ): # Fetch Project with Scenes and Shots stmt = ( select(SceneModel) .options(selectinload(SceneModel.shots)) .where(SceneModel.project_id == project_id) .order_by(SceneModel.sequence_number) ) result = await db.execute(stmt) scenes = result.scalars().all() return {"scenes": scenes}