| from pydantic import BaseModel, Field |
| from typing import List, Optional, Dict, Any |
| from enum import Enum |
| from datetime import datetime |
|
|
| |
|
|
| class LayoutType(str, Enum): |
| CINEMATIC_BLUR = "cinematic_blur" |
| SPLIT_SCREEN = "split_screen" |
| CROP_CENTER = "crop_center" |
| FIT_CENTER = "fit_center" |
|
|
| class AspectRatio(str, Enum): |
| RATIO_9_16 = "9:16" |
| RATIO_1_1 = "1:1" |
| RATIO_16_9 = "16:9" |
| RATIO_4_5 = "4:5" |
| ORIGINAL = "original" |
|
|
| class ShortsStyle(str, Enum): |
| ORIGINAL = "original" |
| CINEMATIC = "cinematic" |
| CROP_FILL = "crop_fill" |
| SPLIT_SCREEN = "split" |
| FIT_BARS = "fit_bars" |
|
|
| class ProcessingType(str, Enum): |
| TRANSCRIPT = "transcript" |
| CROP = "crop" |
| EFFECTS = "effects" |
| AUDIO = "audio" |
| COMBINED = "combined" |
|
|
| class VersionStatus(str, Enum): |
| PENDING = "pending" |
| PROCESSING = "processing" |
| COMPLETED = "completed" |
| FAILED = "failed" |
|
|
| |
|
|
| class Timestamp(BaseModel): |
| start_time: float |
| end_time: float |
|
|
| class Dimensions(BaseModel): |
| width: Optional[int] = 0 |
| height: Optional[int] = 0 |
| target_ratio: AspectRatio = AspectRatio.RATIO_9_16 |
| style: ShortsStyle = ShortsStyle.ORIGINAL |
| video_scale: float = 1.0 |
| vertical_shift: float = 0.0 |
| blur_intensity: int = 20 |
| background_image_url: Optional[str] = None |
| audio_path: Optional[str] = None |
| video_volume: float = 1.0 |
| music_volume: float = 0.2 |
| loop_music: bool = True |
| background_video_url: Optional[str] = None |
|
|
| class WordTiming(BaseModel): |
| word: str |
| start: float |
| end: float |
| confidence: Optional[float] = 1.0 |
|
|
| class SentenceTiming(BaseModel): |
| text: str |
| start: float |
| end: float |
| words: List[WordTiming] |
|
|
| class SubtitleStyle(str, Enum): |
| YOUTUBE_CASUAL = "youtube_casual" |
| GAMING = "gaming" |
| PROFESSIONAL = "professional" |
| MUSIC = "music" |
| EDUCATIONAL = "educational" |
| VLOG = "vlog" |
|
|
| class SubtitlePreset(BaseModel): |
| name: str |
| font_name: str = "Arial" |
| font_size: int = 48 |
| primary_color: str = "#FFFFFF" |
| secondary_color: str = "#FFFF00" |
| outline_color: str = "#000000" |
| back_color: str = "#000000" |
| outline_width: float = 2.0 |
| shadow_depth: float = 1.0 |
| alignment: int = 2 |
| margin_v: int = 100 |
| pop_up_scale: float = 1.2 |
| highlight_mode: str = "karaoke" |
| glow_effect: bool = True |
| elastic_bounce: bool = True |
| rotation_enabled: bool = False |
| back_box_enabled: bool = True |
| display_mode: str = "word" |
| max_words_per_line: int = 3 |
| uppercase: bool = False |
| letter_spacing: float = 0.0 |
| line_spacing: int = 0 |
| background_opacity: float = 1.0 |
| glow_intensity: int = 0 |
| rotation_angle: float = 0.0 |
| margin_h: int = 20 |
|
|
| class ClipRequest(BaseModel): |
| video_url: Optional[str] = None |
| aspect_ratio: AspectRatio = AspectRatio.RATIO_9_16 |
| style: ShortsStyle = ShortsStyle.ORIGINAL |
| video_volume: float = 1.0 |
| music_volume: float = 0.2 |
| loop_music: bool = True |
| add_subtitles: bool = False |
| subtitle_style: Optional[SubtitleStyle] = SubtitleStyle.YOUTUBE_CASUAL |
| subtitle_preset: Optional[SubtitlePreset] = None |
| transcription: Optional[List[WordTiming]] = None |
| custom_dimensions: Optional[Dimensions] = None |
| timestamps: Optional[List[Timestamp]] = None |
|
|
| |
|
|
| class TranscriptSegment(BaseModel): |
| start: float = Field(..., description="Start time in seconds") |
| end: float = Field(..., description="End time in seconds") |
| text: str = Field(..., description="Transcript text") |
| position: Optional[str] = Field("bottom", description="Text position: top, bottom, center") |
| font_size: Optional[int] = Field(None, description="Override font size for this segment") |
| font_color: Optional[str] = Field(None, description="Override font color for this segment") |
|
|
| class TranscriptConfig(BaseModel): |
| segments: List[TranscriptSegment] = Field(..., description="List of transcript segments") |
| font_size: int = Field(default=24, ge=12, le=72, description="Default font size") |
| font_color: str = Field(default="#FFFFFF", pattern=r"^#[0-9A-Fa-f]{6}$", description="Default font color") |
| font_family: str = Field(default="Arial", description="Font family") |
| position: str = Field(default="bottom", pattern="^(top|bottom|center)$", description="Default text position") |
| background_color: Optional[str] = Field(default=None, pattern=r"^#[0-9A-Fa-f]{6}$", description="Text background color") |
| background_alpha: float = Field(default=0.8, ge=0.0, le=1.0, description="Background transparency") |
| margin: int = Field(default=20, ge=0, le=100, description="Margin from edges") |
| opacity: float = Field(default=1.0, ge=0.0, le=1.0, description="Text opacity") |
| animation: Optional[str] = Field(None, description="Text animation type") |
| shadow: bool = Field(default=False, description="Add text shadow") |
| outline: bool = Field(default=False, description="Add text outline") |
|
|
| |
|
|
| class CropConfig(BaseModel): |
| x1: int = Field(default=0, ge=0, description="Top-left X coordinate") |
| y1: int = Field(default=0, ge=0, description="Top-left Y coordinate") |
| x2: Optional[int] = Field(None, ge=0, description="Bottom-right X coordinate") |
| y2: Optional[int] = Field(None, ge=0, description="Bottom-right Y coordinate") |
| width: Optional[int] = Field(None, ge=1, description="Crop width") |
| height: Optional[int] = Field(None, ge=1, description="Crop height") |
| aspect_ratio: Optional[str] = Field(None, description="Force aspect ratio (e.g., '16:9', '9:16')") |
| center_crop: bool = Field(default=False, description="Crop from center") |
| |
| def get_crop_coordinates(self, video_width: int, video_height: int) -> tuple: |
| """Calculate crop coordinates based on configuration""" |
| if self.center_crop and self.width and self.height: |
| center_x = video_width // 2 |
| center_y = video_height // 2 |
| half_width = self.width // 2 |
| half_height = self.height // 2 |
| |
| x1 = max(0, center_x - half_width) |
| y1 = max(0, center_y - half_height) |
| x2 = min(video_width, center_x + half_width) |
| y2 = min(video_height, center_y + half_height) |
| |
| return (x1, y1, x2, y2) |
| |
| |
| x2 = self.x2 or (self.x1 + self.width) if self.width else video_width |
| y2 = self.y2 or (self.y1 + self.height) if self.height else video_height |
| |
| return (self.x1, self.y1, x2, y2) |
|
|
| |
|
|
| class EffectsConfig(BaseModel): |
| brightness: Optional[float] = Field(None, ge=0.1, le=3.0, description="Brightness multiplier") |
| contrast: Optional[float] = Field(None, ge=0.1, le=3.0, description="Contrast multiplier") |
| saturation: Optional[float] = Field(None, ge=0.0, le=3.0, description="Saturation multiplier") |
| speed: Optional[float] = Field(None, gt=0.1, le=10.0, description="Playback speed multiplier") |
| fade_in: Optional[float] = Field(None, ge=0.0, description="Fade in duration in seconds") |
| fade_out: Optional[float] = Field(None, ge=0.0, description="Fade out duration in seconds") |
| blur: Optional[float] = Field(None, ge=0.0, le=10.0, description="Blur radius") |
| sharpen: Optional[float] = Field(None, ge=0.0, le=5.0, description="Sharpen intensity") |
| vignette: Optional[float] = Field(None, ge=0.0, le=1.0, description="Vignette intensity") |
| noise: Optional[float] = Field(None, ge=0.0, le=1.0, description="Noise amount") |
| sepia: bool = Field(default=False, description="Apply sepia tone") |
| black_white: bool = Field(default=False, description="Convert to black and white") |
| vintage: bool = Field(default=False, description="Apply vintage filter") |
|
|
| |
|
|
| class AudioConfig(BaseModel): |
| volume: Optional[float] = Field(None, ge=0.0, le=2.0, description="Volume multiplier") |
| normalize: bool = Field(default=False, description="Normalize audio") |
| remove_noise: bool = Field(default=False, description="Remove background noise") |
| bass_boost: Optional[float] = Field(None, ge=0.0, le=2.0, description="Bass boost intensity") |
| treble_boost: Optional[float] = Field(None, ge=0.0, le=2.0, description="Treble boost intensity") |
| fade_in: Optional[float] = Field(None, ge=0.0, description="Audio fade in duration") |
| fade_out: Optional[float] = Field(None, ge=0.0, description="Audio fade out duration") |
| speed: Optional[float] = Field(None, gt=0.1, le=2.0, description="Audio speed multiplier") |
| pitch_shift: Optional[float] = Field(None, ge=-12, le=12, description="Pitch shift in semitones") |
|
|
| |
|
|
| class VideoVersionResponse(BaseModel): |
| version_id: str |
| version_name: str |
| processing_type: ProcessingType |
| status: VersionStatus |
| file_path: str |
| file_size: int |
| duration: float |
| resolution: str |
| created_at: datetime |
| parent_version: Optional[str] |
| processing_config: Dict[str, Any] |
| metadata: Dict[str, Any] |
|
|
| class OriginalVideoResponse(BaseModel): |
| original_id: str |
| file_name: str |
| file_path: str |
| file_size: int |
| upload_date: datetime |
| duration: float |
| resolution: str |
| format: str |
| metadata: Dict[str, Any] |
| versions_count: int |
| versions: List[str] |
|
|
| class ProcessingRequest(BaseModel): |
| original_id: str |
| processing_type: ProcessingType |
| version_name: Optional[str] = None |
| transcript_config: Optional[TranscriptConfig] = None |
| crop_config: Optional[CropConfig] = None |
| effects_config: Optional[EffectsConfig] = None |
| audio_config: Optional[AudioConfig] = None |
| priority: str = Field(default="normal", pattern="^(low|normal|high)$") |
| metadata: Dict[str, Any] = Field(default_factory=dict) |
|
|
| class ProcessingResponse(BaseModel): |
| version_id: str |
| original_id: str |
| processing_type: ProcessingType |
| status: VersionStatus |
| message: str |
| estimated_time: Optional[int] = None |
| created_at: datetime |
|
|
| |
|
|
| class StorageStats(BaseModel): |
| original_videos: int |
| total_versions: int |
| originals_size: int |
| versions_size: int |
| total_size: int |
|
|
| class SystemStats(BaseModel): |
| storage: StorageStats |
| system_status: str |
| active_processes: int |
| queue_size: int |
| timestamp: datetime |
|
|
| |
|
|
| class UploadResponse(BaseModel): |
| original_id: str |
| file_name: str |
| file_size: int |
| upload_date: datetime |
| message: str |
| status: str |
|
|
| class VersionListResponse(BaseModel): |
| original_id: str |
| versions: List[VideoVersionResponse] |
| total_count: int |
|
|
| class VersionTreeResponse(BaseModel): |
| original_id: str |
| version_tree: Dict[str, List[str]] |
| versions_info: Dict[str, VideoVersionResponse] |