from typing import Dict, List, Literal, Any, Annotated, Optional, Union, ClassVar, Type, Tuple from pydantic import BaseModel, Field, model_validator, constr, conlist class VideoMetadata(BaseModel): """Video metadata""" width: int = Field(description="Width") height: int = Field(description="Height") duration: float = Field(description="Duration (milliseconds)") fps: float = Field(description="Video frame rate per second") has_audio: bool = Field(default=False, description="Whether audio track is present") audio_sample_rate_hz: Optional[int] = Field( None, gt=0, description="Audio sample rate (Hz), common values: 44100, 48000" ) @model_validator(mode='after') def validate_audio_sample_rate(self): """Audio sample rate is required if audio is present""" if self.has_audio and self.audio_sample_rate_hz is None: raise ValueError('audio_sample_rate_hz must be provided when video contains audio') return self class ImageMetadata(BaseModel): """Image metadata""" width: int = Field(description="Width") height: int = Field(description="Height") class Media(BaseModel): """Single media""" media_id: str path: str media_type: Literal["video", "image", "audio", "unknown"] metadata: Union[VideoMetadata, ImageMetadata] extra_info: Optional[Dict[str, Any]] = None class SourceRef(BaseModel): """ Original media reference information """ media_id: str start: float end: float duration: float height: Optional[int] = None width: Optional[int] = None class Clip(BaseModel): clip_id: str language: Optional[str] = None caption: str = Field(default="", description="Caption describing the media") media_type: str path: str fps: Optional[float] = None extra_info: Optional[Dict[str, Any]] = Field(default=None, description="Extra metadata") class SubtitleUnit(BaseModel): """Subtitle segmentation unit""" unit_id: str = Field( ..., description="Unique identifier for subtitle unit", example="subtitle_0001" ) index_in_group: int = Field( ..., ge=0, description="Sequential index within current group (starting from 0)", example=0 ) text: str = Field( ..., description="Text content of this subtitle unit", example="The cat doesn't understand what KPI means" ) class GroupClips(BaseModel): """Video group - Visual material organization""" group_id: str = Field( ..., description="Unique identifier for the group", example="group_0001" ) summary: str = Field( ..., description="Description of the group's visual style, emotional tone, or editing intent", example="Start with the calmest, most healing shots to establish the mood." ) clip_ids: List[str] = Field( ..., description="List of video clip IDs used in this group, arranged in playback order", example=["clip_0003", "clip_0002"] ) class GroupScript(BaseModel): """Group script content""" group_id: str = Field( ..., description="Unique identifier for the group", example="group_0001" ) raw_text: str = Field( ..., description="original script content for this group", example="The cat doesn't understand what KPI means, the cat only knows the sun is shining today" ) subtitle_units: List = Field( ..., description="List of subtitle segmentation units for precise control of subtitle display rhythm" ) class Voiceover(BaseModel): """Single voiceover/narration item""" group_id: str = Field(..., description="Group ID, e.g., group_0001") voiceover_id: str = Field(..., description="Voiceover ID, e.g., voiceover_0001") path: str = Field(..., description="Voiceover file path") duration: int = Field(..., description="Voiceover duration (milliseconds)", gt=0) class BGM(BaseModel): """Background music""" bgm_id: str = Field(..., description="BGM ID, e.g., bgm_0003") path: str = Field(..., description="BGM file path") duration: int = Field(..., description="BGM duration (milliseconds)", gt=0) bpm: float = Field(..., description="Beats per minute", gt=0) beats: List[int] = Field(default_factory=list, description="List of beat timestamps (milliseconds)") class TimeWindow(BaseModel): start: int = Field(..., description="Start time (milliseconds)") end: int = Field(..., description="End time (milliseconds)") class AudioMix(BaseModel): gain_db: float = Field(default=0.0, description="Gain in decibels") ducking: Optional[Any] = Field(default=None, description="Ducking effect configuration") class ClipTrack(BaseModel): clip_id: str source_window: TimeWindow timeline_window: TimeWindow class BgmTrack(BaseModel): bgm_id: str timeline_window: TimeWindow mix: AudioMix class SubtitleTrack(BaseModel): text: str timeline_window: TimeWindow class VoiceoverTrack(BaseModel): media_id: str timeline_window: TimeWindow class TimelineTracks(BaseModel): video: List[ClipTrack] = Field(default_factory=list) subtitles: List[SubtitleTrack] = Field(default_factory=list) voiceover: List[VoiceoverTrack] = Field(default_factory=list) bgm: List[BgmTrack] = Field(default_factory=list) class BaseInput(BaseModel): mode: Literal["auto", "skip", "default"] = Field( default="auto", description="auto: Automatic mode; skip: Skip mode; default: Default mode" ) class LoadMediaInput(BaseInput): ... class SearchMediaInput(BaseInput): mode: Literal["auto", "skip", "default"] = Field( default="auto", description="auto: Automatically search media from pexels; skip: skip search; default: skip search" ) photo_number: Annotated[int, Field(default=0, description="The number of images the user wants to obtain")] video_number: Annotated[int, Field(default=5, description="The number of videos the user wants to obtain")] search_keyword: Annotated[str, Field(default="scenery", description="Keyword of the media the user wants to obtain. Only one keyword is allowed; multiple keywords are not permitted.")] orientation: Literal["landscape", "portrait"] = Field( default="landscape", description="landscape: The screen is wider horizontally and narrower vertically, making it suitable for computer screens, landscape images, etc;portrait: The screen is higher vertically and narrower horizontally, making it suitable for mobile browsing and close-up shots of people." ) min_video_duration: Annotated[int, Field(default=1, description="The shortest duration of footage requested by the user in seconds.")] max_video_duration: Annotated[int, Field(default=30, description="The longest duration of footage requested by the user in seconds.")] class LoadMediaOutput(BaseModel): media: List[Media] = Field( default_factory=list, description="List of media" ) class SplitShotsInput(BaseInput): mode: Literal["auto", "skip", "default"] = Field( default="auto", description="auto: Automatically segment shots based on scene changes, treat images as single shots; skip: Do not segment shots; default: Use default segmentation method" ) min_shot_duration: Annotated[int, Field(default=1000, description="Segmented shots must not be shorter than this duration (unit: milliseconds)")] max_shot_duration: Annotated[int, Field(default=10000, description="If a single shot exceeds this duration, force segmentation (unit: milliseconds)")] class SplitShotsOutput(BaseModel): clip_captions: List[Clip] = Field(default_factory=list, description="List of clips after splitting shots") overall: Dict[str, str] class UnderstandClipsInput(BaseModel): mode: Literal["auto", "skip", "default"] = Field( default="auto", description="auto: Generate descriptions based on media content; skip: Do not generate descriptions; default: Use default description generation method" ) class UnderstandClipsOutput(BaseModel): clip_captions: List[Clip] = Field(default_factory=list, description="List of clips after understanding clips") overall: Dict[str, str] class FilterClipsInput(BaseModel): mode: Literal["auto", "skip", "default"] = Field( default="auto", description="auto: Filter clips based on user requirements; skip: Skip filtering; default: Use default filtering method" ) user_request: Annotated[str, Field(default="", description="User's requirements for clip filtering; if none provided, formulate one based on media materials and other editing requirements.")] = "" class FilterClipsOutput(BaseModel): clip_captions: List[Clip] = Field(default_factory=list, description="List of clips") overall: Dict[str, str] overall: Dict[str, str] class GroupClipsInput(BaseModel): mode: Literal["auto", "skip", "default"] = Field( default="auto", description="auto: Organize clips in a logical order based on narrative flow of media content and user's sequencing requirements; skip: Skip sorting; default: Use default ordering method" ) user_request: Annotated[str, Field(default="", description="User's requirements for media organization order; if none provided, arrange in a logical narrative sequence following standard conventions.")] class GroupClipsOutput(BaseModel): groups: List[GroupClips] = Field(default_factory=list, description="List of clips") class GenerateScriptInput(BaseModel): mode: Literal["auto", "skip", "default"] = Field( default="auto", description="auto: Generate appropriate script based on media content and user's script requirements; skip: Skip, do not add subtitles; default: Use default script" ) user_request: Annotated[str, Field(default="", description="User's requirements for the script.")] custom_script: Dict[str, Any] = Field( default={}, description="If user has specific character-level editing requirements for script/title, pass the edited custom script and title through this parameter. Format should be based on the original script generation output format but with the subtitle_units field removed. In this case, mode must use `auto`, other modes are prohibited" ) class GenerateScriptOutput(BaseModel): group_scripts: List[GroupScript] title: Optional[str] class GenerateVoiceoverInput(BaseInput): mode: Literal["auto", "skip", "default"] = Field( default="auto", description="auto: Generate appropriate voiceover based on media content and user's voice requirements; skip: Skip voiceover; default: Use default voiceover" ) user_request: Annotated[str, Field(default="", description="User's requirements for voiceover.")] class RecommendScriptTemplateInput(BaseInput): mode: Literal["auto", "skip", "default"] = Field( default="auto", description="auto: Select an appropriate copywriting template based on the material content and user's requirements for voiceover style; skip: Skip;" ) user_request: Annotated[str, Field(default="", description="User's specific requirements for the script style.")] filter_include: Annotated[ Dict[str, List[str]], Field( description=( "Positive filter conditions. Multiple dimensions are combined with AND, " "multiple values within the same dimension are combined with OR.\n" "Supported dimensions:\n" "- tags: category, one or more of " "[Life, Food, Beauty, Entertainment, Travel, Tech, Business, Vehicle, Health, Family, Pets, Knowledge]" ) ) ] = {} filter_exclude: Annotated[ Dict[str, List[Union[str]]], Field( description=( "Negative filter conditions. Items matching these conditions will be excluded. " "The semantics are the same as filter_include. " "Supported dimensions: tags, id." ) ) ] = {} class GenerateVoiceoverOutput(BaseModel): voiceover: List[Voiceover] = Field(default_factory=list, description="Voiceover list") class SelectBGMInput(BaseInput): mode: Literal["auto", "skip", "default"] = Field( default="auto", description="auto: Select appropriate music based on media content and user's music requirements; skip: Do not use music; default: Use default music" ) user_request: Annotated[str, Field(default="", description="User's requirements for background music.")] filter_include: Annotated[ Dict[str, List[Union[str, int]]], Field( description=( "Positive filter conditions. Multiple dimensions are combined with AND, " "multiple values within the same dimension are combined with OR.\n" "Supported dimensions:\n" "- mood: music emotion, one or more of " "[Dynamic, Chill, Happy, Sorrow, Romantic, Calm, Excited, Healing, Inspirational]\n" "- scene: usage scene, one or more of " "[Vlog, Travel, Relaxing, Emotion, Transition, Outdoor, Cafe, Evening, Scenery, Food, Date, Club]\n" "- genre: music genre, one or more of " "[Pop, BGM, Electronic, R&B/Soul, Hip Hop/Rap, Rock, Jazz, Folk, Classical, Chinese Style]\n" "- lang: lyric language, one or more of [bgm, en, zh, ko, ja]\n" "- id: specific music ids (int)" ) ) ] = {} filter_exclude: Annotated[ Dict[str, List[Union[str, int]]], Field( description=( "Negative filter conditions. Items matching these conditions will be excluded. " "The semantics are the same as filter_include. " "Supported dimensions: mood, scene, genre, lang, id." ) ) ] = {} class SelectBGMOutput(BaseModel): bgm: List[BGM] = Field(default_factory=list, description="BGM list") class RecommendTransitionInput(BaseInput): mode: Literal["auto", "skip", "default"] = Field( default="auto", description="auto: add fade in and fade out transitions at beginning and end; skip: Do not use transitions; default: Use default transitions", ) duration: Annotated[int, Field(default=1000, description="Duration of the transition in milliseconds")] class RecommendTransitionOutput(BaseInput): ... class RecommendTextInput(BaseInput): mode: Literal["auto", "skip", "default"] = Field( default="auto", description="auto: Select appropriate font style and color based on user's subtitle font style requirements; default: Use default font", ) user_request: Annotated[str, Field(default="", description="User's requirements for font style")] filter_include: Annotated[ Dict[str, List[Union[str, int]]], Field( description=( "Positive filter conditions. Multiple dimensions are combined with AND, " "multiple values within the same dimension are combined with OR.\n" "Supported dimensions:\n" "- class: Font type, one or more" "[Creative, Handwriting, Calligraphy, Basic]\n" ) ) ] = {} class RecommendTextOutput(BaseInput): ... class PlanTimelineInput(BaseInput): use_beats: Annotated[bool, Field(default=True, description="Whether clip transitions should sync with BGM beats")] class PlanTimelineOutput(BaseModel): tracks: List[TimelineTracks] = Field(default_factory=list, description="Timeline track collection") class RenderVideoInput(BaseInput): aspect_ratio: Annotated[str | None, Field( default=None, description="When explicitly specified, forces the canvas to one of 16:9, 4:3, 1:1, 3:4, 9:16. If unset, the system automatically infers the most suitable aspect ratio." )] output_max_dimension_px: Annotated[int | None, Field( default=None, description="Maximum output size in pixels (longest side); defaults to 1080 and works with the aspect ratio." )] clip_compose_mode: Annotated[str, Field( default="padding", description="" \ "How to fit media into the canvas: " \ "'padding' keeps aspect ratio and fills empty areas with a solid color; " \ "'crop' center-crops media to match the canvas aspect ratio." )] bg_color: Annotated[Tuple[int] | List[int] | None, Field( default=(0, 0, 0), description="Background color for canvas padding, specified as an (R, G, B) tuple (no alpha channel)." )] crf: Annotated[int, Field( default=23, description="CRF value (10–30), lower = better quality, larger file" )] # font parameters font_color: Annotated[Tuple[int, int, int, int], Field( default=(255, 255, 255, 255), description="Font color, RGBA format (R, G, B, A), values range 0-255") ] font_size: Annotated[int, Field( default=40, description="Font size in pixels. Recommended range: 28–120." )] margin_bottom: Annotated[int, Field( default=270, description="Bottom margin for subtitles in pixels. Defaults to 80; valid range: 40–1040." )] stroke_width: Annotated[int, Field( default=2, description="Text stroke width (px), typically 0–8" )] stroke_color: Annotated[Tuple[int, int, int, int], Field( default=(0, 0, 0, 255), description="Text stroke color in RGBA format", )] # audio bgm_volume_scale: Annotated[float, Field( default=0.25, description="Background music volume multiplier, range 0.0–3.0 (1.0 = default volume)" )] tts_volume_scale: Annotated[float, Field( default=2.0, description="TTS volume multiplier, range 0.0–3.0 (1.0 = default volume)" )] include_video_audio: Annotated[bool, Field( default=False, description="Whether to include the original video audio track" )]