Spaces:
Sleeping
Sleeping
| 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" | |
| ) | |
| 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" | |
| )] | |