from __future__ import annotations from datetime import datetime from pydantic import BaseModel, ConfigDict, Field class VpV3AssetCreate(BaseModel): """在项目下创建虚拟素材请求(一步到位:接收远程 URL 先下载到本地,再同步火山)。""" source_url: str = Field( ..., min_length=8, max_length=2000, description=( "素材源 URL(必须 http/https 公网可访问的图片/视频直链," "系统先将其下载保存到本地存储并占用存储配额,再同步到火山)" ), ) name: str | None = Field( None, max_length=100, description="素材名称(可选;不传则自动从 URL 文件名 / Content-Disposition 推断)", ) asset_type: str = Field( ..., pattern=r"^(Image|Video)$", description="素材类型:Image=图片 / Video=视频", ) video_duration: float | None = Field( None, description="视频时长,秒(Video 可选;不传时系统自动用 ffprobe 探测;最大 60 秒)", ) video_cover_url: str | None = Field( None, description="视频封面图 URL(可选,仅 Video 用,建议 16:9)", ) class VpV3AssetOut(BaseModel): """虚拟素材详情响应。""" model_config = ConfigDict(extra="ignore") asset_id: str = Field(description="素材 ID") project_id: str = Field(description="所属项目 ID") name: str | None = Field(None, description="素材名称") asset_type: str = Field(description="素材类型:Image/Video") status: str = Field(description="素材状态") # 显示 URL source_url: str = Field(description="原始上传 URL") preview_url: str | None = Field(None, description="显示用预览 URL(可能带签名过期)") remote_url: str | None = Field(None, description="火山返回的资源访问 URL(可能带签名过期)") remote_url_expired_at: datetime | None = Field(None, description="remote_url 过期时间") video_duration: float | None = Field(None, description="视频时长秒") video_cover_url: str | None = Field(None, description="视频封面") file_size_bytes: int | None = Field(None, description="文件大小字节") mime_type: str | None = Field(None, description="MIME 类型") moderation_json: dict | None = Field(None, description="火山审核 JSON(失败时可查看原因)") error_message: str | None = Field(None, description="失败原因") remote_delete_status: str = Field("none", description="远端删除状态") created_at: datetime = Field(description="创建时间") updated_at: datetime = Field(description="最后更新时间") class VpV3AssetListOut(BaseModel): """虚拟素材列表响应。""" items: list[VpV3AssetOut] = Field(default_factory=list) total: int = Field(0, description="总数") page: int = Field(1, description="当前页码") page_size: int = Field(20, description="每页数量") class VpV3AssetDeleteOut(BaseModel): """删除响应。""" success: bool = Field(True) remote_delete_status: str = Field(description="远端删除状态") class VpV3SelectableAssetOut(BaseModel): """AI 创作选择器使用的素材条目。""" model_config = ConfigDict(extra="ignore") asset_id: str = Field(description="素材 ID(带入生成用 source=vp_v3_asset + asset_id)") project_id: str = Field(description="项目 ID") name: str | None = Field(None) asset_type: str = Field(description="Image/Video") status: str = Field(description="状态=Active") source_url: str = Field(description="原始上传 URL") preview_url: str | None = Field(None, description="预览 URL(直接显示用)") video_duration: float | None = Field(None) video_cover_url: str | None = Field(None) file_size_bytes: int | None = Field(None) created_at: datetime = Field(description="创建时间") class VpV3SelectableAssetListOut(BaseModel): """AI 创作选择器素材列表。""" items: list[VpV3SelectableAssetOut] = Field(default_factory=list) total: int = Field(0) page: int = Field(1) page_size: int = Field(20)