添加seedance2.5
This commit is contained in:
@@ -23,15 +23,16 @@ from apps.products.models import Product
|
||||
from .free_video import (
|
||||
FREE_VIDEO_MODELS,
|
||||
HIGH_RES_MODEL,
|
||||
REPLACE_MODEL,
|
||||
IN_FLIGHT_STATUSES,
|
||||
RATIOS,
|
||||
RESOLUTIONS,
|
||||
_reap_stale_free_video_tasks,
|
||||
model_duration_range,
|
||||
serialize_free_video_task,
|
||||
start_pending_free_video,
|
||||
submit_free_video,
|
||||
)
|
||||
from .media_probe import REF_DURATION_MAX
|
||||
from .models import AITask, ModelConfig
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -43,9 +44,10 @@ LEGACY_PROMPT_PREFIX = "[视频复刻]"
|
||||
# 商品三视图在商品库是 standalone Asset(metadata.view=three_view + product_id),
|
||||
# 和项目内的 BaseAssetGroup 是两套存储,这里直接取商品库那份。
|
||||
TRIVIEW_LABEL = "目标商品三视图"
|
||||
# 商品复刻的参考视频不进火山、只喂提炼模型,所以不受火山 15 秒参考视频限制。
|
||||
# 半秒容差同 media_probe 的老规矩(60 秒成片常被探成 60.02)。角色复刻仍是 15 秒。
|
||||
PRODUCT_REF_DURATION_MAX = 60.5
|
||||
# 复刻统一走 Seedance 2.5,单次能出 30 秒,所以参考视频也按 30 秒收口:
|
||||
# 商品模式的参考视频只喂提炼模型,角色模式直传火山,两边都不需要超过成片上限的素材。
|
||||
# 半秒容差同 media_probe 的老规矩(30 秒成片常被探成 30.02)。
|
||||
REPLACE_REF_DURATION_MAX = 30.5
|
||||
REVIEW_UNAVAILABLE = "素材审核服务暂不可用,请稍后重试"
|
||||
REVIEW_FAILED = "参考素材未通过真人合规审核,请更换视频或图片后重试"
|
||||
REVIEW_SUBMIT_FAILED = "素材提交审核失败,请稍后重试"
|
||||
@@ -257,12 +259,8 @@ def submit_video_replace(*, team, user, params: dict):
|
||||
|
||||
video = _team_asset(team, params.get("video_asset_id"), kind=Asset.Type.VIDEO, label="参考视频")
|
||||
video_seconds = _asset_duration_seconds(video)
|
||||
if replace_mode == "product":
|
||||
if video_seconds > PRODUCT_REF_DURATION_MAX:
|
||||
raise ValueError("参考视频不能超过 60 秒,请剪短后重试")
|
||||
elif video_seconds > REF_DURATION_MAX:
|
||||
# 角色复刻把参考视频直传火山,15 秒是火山那边的硬限制,不能跟着放宽。
|
||||
raise ValueError("参考视频不能超过 15 秒,请剪短后重试")
|
||||
if video_seconds > REPLACE_REF_DURATION_MAX:
|
||||
raise ValueError("参考视频不能超过 30 秒,请剪短后重试")
|
||||
|
||||
if has_product:
|
||||
subject_name, image_refs, subject_source = _product_library_refs(team, product_id)
|
||||
@@ -282,7 +280,8 @@ def submit_video_replace(*, team, user, params: dict):
|
||||
}
|
||||
base_params = {
|
||||
"mode": "universal",
|
||||
"model": str(params.get("model") or HIGH_RES_MODEL),
|
||||
# 商品和角色都固定走 Seedance 2.5:只有它支持 30 秒单次出片,不接受前端指定别的档
|
||||
"model": REPLACE_MODEL,
|
||||
"aspect_ratio": str(params.get("aspect_ratio") or "9:16"),
|
||||
"resolution": str(params.get("resolution") or "720p"),
|
||||
"duration": duration,
|
||||
@@ -494,7 +493,7 @@ def _create_reviewing_task(*, team, user, params: dict, digest_pending: bool = F
|
||||
|
||||
两种情况共用:①角色复刻的素材还在审核 ②商品复刻的参考视频还没拆解。
|
||||
"""
|
||||
model_name = str(params.get("model") or HIGH_RES_MODEL)
|
||||
model_name = str(params.get("model") or REPLACE_MODEL)
|
||||
aspect_ratio = str(params.get("aspect_ratio") or "9:16")
|
||||
resolution = str(params.get("resolution") or "720p")
|
||||
try:
|
||||
@@ -507,8 +506,9 @@ def _create_reviewing_task(*, team, user, params: dict, digest_pending: bool = F
|
||||
raise ValueError("画面比例无效")
|
||||
if resolution not in RESOLUTIONS:
|
||||
raise ValueError("分辨率无效")
|
||||
if not 4 <= duration <= 15:
|
||||
raise ValueError("视频时长需在 4-15 秒之间")
|
||||
low, high = replace_duration_range()
|
||||
if not low <= duration <= high:
|
||||
raise ValueError(f"视频时长需在 {low}-{high} 秒之间")
|
||||
|
||||
model_config = (
|
||||
ModelConfig.objects.select_related("provider")
|
||||
@@ -754,16 +754,27 @@ def _asset_duration_seconds(asset: Asset) -> float:
|
||||
return primary.duration_ms / 1000.0
|
||||
|
||||
|
||||
def replace_duration_range() -> tuple[int, int]:
|
||||
"""复刻模型(Seedance 2.5)支持的出片时长区间。模型没配好时回落 4–15,不至于炸。"""
|
||||
model = (
|
||||
ModelConfig.objects.filter(
|
||||
name=REPLACE_MODEL, capability=ModelConfig.Capability.VIDEO, status=ModelConfig.Status.ACTIVE
|
||||
).first()
|
||||
)
|
||||
return model_duration_range(model)
|
||||
|
||||
|
||||
def _output_duration(requested, video_seconds: float) -> int:
|
||||
low, high = replace_duration_range()
|
||||
try:
|
||||
value = int(requested) if requested not in (None, "") else 0
|
||||
except (TypeError, ValueError):
|
||||
value = 0
|
||||
if value:
|
||||
return min(15, max(4, value))
|
||||
return min(high, max(low, value))
|
||||
if video_seconds:
|
||||
return min(15, max(4, int(round(video_seconds))))
|
||||
return 15
|
||||
return min(high, max(low, int(round(video_seconds))))
|
||||
return high
|
||||
|
||||
|
||||
def _owned_ref(asset: Asset, *, kind: str, role: str, label: str) -> dict:
|
||||
|
||||
Reference in New Issue
Block a user