This commit is contained in:
2026-01-27 17:40:37 +01:00
parent 82947a7bd6
commit adc2cd572a
55 changed files with 4145 additions and 101 deletions

View File

@@ -0,0 +1,96 @@
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}