from dataclasses import dataclass from typing import Literal from PIL import Image from pydantic import BaseModel SceneKind = Literal["clip", "stills", "scroll", "poster"] class Scene(BaseModel): """나레이션 큐 하나에 대응하는 화면.""" cue: int kind: SceneKind section: str | None = None # scroll 시작점이 된 섹션 이름 tag: str | None = None # 그 섹션의 태그. 왜 골랐는지 남긴다 # scroll은 조각이 아니라 롱이미지 위에서 일어난다. 아래 셋이 그 좌표다 source: str | None = None # 훑을 롱이미지 (detail_01 …) y0: float | None = None # 시작 위치. 롱이미지 높이 대비 0~1 y1: float | None = None # 끝 위치 class LongcutPlan(BaseModel): scenes: list[Scene] class EndBandInfo(BaseModel): """엔드밴드 두 줄. 위가 공연명, 아래가 일시·장소.""" title: str detail: str @dataclass class LongcutResult: video: bytes thumbnail: bytes # 첫 프레임. 0초가 포스터 원본이라 그대로 정지컷이 된다 duration: float frames: int plan: LongcutPlan proof: Image.Image | None = None