from pydantic import BaseModel, Field class SyncInputItem(BaseModel): type: str = Field(..., description="Input kind: 'video', 'image' or 'audio'.") url: str = Field(...) class SyncActiveSpeakerDetection(BaseModel): auto_detect: bool | None = Field( None, description="Detect the active speaker automatically. Video input only; rejected for images." ) frame_number: int | None = Field( None, description="Frame used for manual speaker selection. Must be 0 for image inputs." ) coordinates: list[int] | None = Field( None, description="Pixel [x, y] of the speaker's face in the frame selected by frame_number." ) class SyncGenerationOptions(BaseModel): sync_mode: str | None = Field( None, description="How to resolve an audio/video duration mismatch: " "cut_off, bounce, loop, silence or remap. Ignored for image inputs.", ) i2v_prompt: str | None = Field( None, description="Motion prompt for image-to-video generation. Image input only." ) active_speaker_detection: SyncActiveSpeakerDetection | None = Field(None) class SyncGenerationRequest(BaseModel): model: str = Field(..., description="Generation model, e.g. 'sync-3'.") input: list[SyncInputItem] = Field( ..., description="Exactly one visual input (video or image) plus one audio input." ) options: SyncGenerationOptions | None = Field(None) class SyncGeneration(BaseModel): """Subset of the Generation object returned by POST /v2/generate and GET /v2/generate/{id}.""" id: str = Field(...) status: str = Field(..., description="PENDING | PROCESSING | COMPLETED | FAILED | REJECTED") outputUrl: str | None = Field(None) outputDuration: float | None = Field(None) error: str | None = Field(None, description="Human-readable failure message.") errorCode: str | None = Field(None, description="Stable machine-readable code from the GET /v2/errors catalog.")