""" Video API Schemas 영상 생성 관련 Pydantic 스키마를 정의합니다. """ from datetime import datetime from typing import Any, Dict, List, Optional from pydantic import BaseModel, Field # ============================================================================= # Request Schemas # ============================================================================= class GenerateVideoRequest(BaseModel): """영상 생성 요청 스키마 Usage: POST /video/generate/{task_id} Request body for generating a video via Creatomate API. Example Request: { "template_id": "abc123...", "image_urls": ["https://...", "https://..."], "lyrics": "가사 내용...", "music_url": "https://..." } """ model_config = { "json_schema_extra": { "example": { "template_id": "abc123-template-id", "image_urls": [ "https://example.com/image1.jpg", "https://example.com/image2.jpg", ], "lyrics": "인스타 감성의 스테이 머뭄, 머물러봐요\n군산 신흥동 말랭이 마을의 마음 힐링", "music_url": "https://example.com/song.mp3", } } } template_id: str = Field(..., description="Creatomate 템플릿 ID") image_urls: List[str] = Field(..., description="영상에 사용할 이미지 URL 목록") lyrics: str = Field(..., description="영상에 표시할 가사") music_url: str = Field(..., description="배경 음악 URL") # ============================================================================= # Response Schemas # ============================================================================= class GenerateVideoResponse(BaseModel): """영상 생성 응답 스키마 Usage: POST /video/generate/{task_id} Returns the task IDs for tracking video generation. Example Response (Success): { "success": true, "task_id": "019123ab-cdef-7890-abcd-ef1234567890", "creatomate_render_id": "render-id-123", "message": "영상 생성 요청이 접수되었습니다.", "error_message": null } """ success: bool = Field(..., description="요청 성공 여부") task_id: Optional[str] = Field(None, description="내부 작업 ID (Project task_id)") creatomate_render_id: Optional[str] = Field(None, description="Creatomate 렌더 ID") message: str = Field(..., description="응답 메시지") error_message: Optional[str] = Field(None, description="에러 메시지 (실패 시)") class VideoRenderData(BaseModel): """Creatomate 렌더링 결과 데이터""" id: Optional[str] = Field(None, description="렌더 ID") status: Optional[str] = Field(None, description="렌더 상태") url: Optional[str] = Field(None, description="영상 URL") snapshot_url: Optional[str] = Field(None, description="스냅샷 URL") class PollingVideoResponse(BaseModel): """영상 생성 상태 조회 응답 스키마 Usage: GET /video/status/{creatomate_render_id} Creatomate API 작업 상태를 조회합니다. Note: 상태 값: - planned: 예약됨 - waiting: 대기 중 - transcribing: 트랜스크립션 중 - rendering: 렌더링 중 - succeeded: 성공 - failed: 실패 Example Response (Success): { "success": true, "status": "succeeded", "message": "영상 생성이 완료되었습니다.", "render_data": { "id": "render-id", "status": "succeeded", "url": "https://...", "snapshot_url": "https://..." }, "raw_response": {...}, "error_message": null } """ success: bool = Field(..., description="조회 성공 여부") status: Optional[str] = Field( None, description="작업 상태 (planned, waiting, rendering, succeeded, failed)" ) message: str = Field(..., description="상태 메시지") render_data: Optional[VideoRenderData] = Field(None, description="렌더링 결과 데이터") raw_response: Optional[Dict[str, Any]] = Field(None, description="Creatomate API 원본 응답") error_message: Optional[str] = Field(None, description="에러 메시지 (실패 시)") class DownloadVideoResponse(BaseModel): """영상 다운로드 응답 스키마 Usage: GET /video/download/{task_id} Polls for video completion and returns project info with video URL. Note: 상태 값: - processing: 영상 생성 진행 중 (result_movie_url은 null) - completed: 영상 생성 완료 (result_movie_url 포함) - failed: 영상 생성 실패 - not_found: task_id에 해당하는 Video 없음 - error: 조회 중 오류 발생 Example Response (Completed): { "success": true, "status": "completed", "message": "영상 다운로드가 완료되었습니다.", "store_name": "스테이 머뭄", "region": "군산", "task_id": "019123ab-cdef-7890-abcd-ef1234567890", "result_movie_url": "http://localhost:8000/media/2025-01-15/video.mp4", "created_at": "2025-01-15T12:00:00", "error_message": null } """ success: bool = Field(..., description="다운로드 성공 여부") status: str = Field(..., description="처리 상태 (processing, completed, failed, not_found, error)") message: str = Field(..., description="응답 메시지") store_name: Optional[str] = Field(None, description="업체명") region: Optional[str] = Field(None, description="지역명") task_id: Optional[str] = Field(None, description="작업 고유 식별자") result_movie_url: Optional[str] = Field(None, description="영상 결과 URL") created_at: Optional[datetime] = Field(None, description="생성 일시") error_message: Optional[str] = Field(None, description="에러 메시지 (실패 시)") class VideoListItem(BaseModel): """영상 목록 아이템 스키마 Usage: GET /videos 응답의 개별 영상 정보 Example: { "store_name": "스테이 머뭄", "region": "군산", "task_id": "019123ab-cdef-7890-abcd-ef1234567890", "result_movie_url": "http://localhost:8000/media/2025-01-15/video.mp4", "created_at": "2025-01-15T12:00:00" } """ store_name: Optional[str] = Field(None, description="업체명") region: Optional[str] = Field(None, description="지역명") task_id: str = Field(..., description="작업 고유 식별자") result_movie_url: Optional[str] = Field(None, description="영상 결과 URL") created_at: Optional[datetime] = Field(None, description="생성 일시")