模特库标签分页与全能创作收口:藏长视频、选择器分页
角色库导入打标签并支持筛选;模特库与全能创作角色/商品选择改为每页 20 条分页。临时限制成片 ≤60 秒,过滤对话里的超长时长选项,并收拢本地全能创作与后台用户相关修复。
This commit is contained in:
@@ -44,6 +44,23 @@ FREE_VIDEO_MODELS = {
|
||||
"doubao-seedance-2-0-mini-260615",
|
||||
}
|
||||
HIGH_RES_MODEL = "doubao-seedance-2-0-260128" # 1080p/4k 仅标准档(火山限制)
|
||||
# 火山对 seed 的硬上限是 int32 正数上限;超一点整条请求直接 InvalidParameter 被拒。
|
||||
VIDEO_SEED_MAX = 2147483647
|
||||
|
||||
|
||||
def normalize_video_seed(value) -> int:
|
||||
"""把任何来源的 seed 收进火山认的区间。-1 = 不指定(随机)。
|
||||
|
||||
越界不报错而是折回区间内:长视频各段共用同一个确定性 seed 保一致性,
|
||||
折算规则固定,同一个会话每次算出来仍是同一个值。
|
||||
"""
|
||||
try:
|
||||
seed = int(value)
|
||||
except (TypeError, ValueError):
|
||||
return -1
|
||||
if seed < 0:
|
||||
return -1
|
||||
return seed & VIDEO_SEED_MAX
|
||||
# 视频复刻固定 Seedance 2.5(单次最长 30 秒)。原片只用来提炼分镜,不传给火山。
|
||||
REPLACE_MODEL = "doubao-seedance-2-5-260628"
|
||||
# 出片时长的兜底上限。真实上限按 ModelConfig.metadata.durations 取(见 model_duration_range),
|
||||
@@ -129,6 +146,29 @@ def _refresh_processing_free_asset(free_asset: FreeAsset) -> bool:
|
||||
return False
|
||||
|
||||
|
||||
def _reference_asset(team, asset_id) -> Asset | None:
|
||||
"""出片参考图允许两种来源:团队自有资产,以及官方模特库的人像/三视图。
|
||||
|
||||
官方模特挂在平台团队名下,按 team 过滤会直接查不到 —— 这是模特库里明明存在、
|
||||
生成时却报「不存在或已被删除」的根因。放行范围与视频复刻(video_replace)保持一致。
|
||||
"""
|
||||
from django.db.models import Q
|
||||
|
||||
from apps.assets.models import Model as AssetModel
|
||||
|
||||
asset = Asset.objects.filter(id=asset_id, is_deleted=False).first()
|
||||
if asset is None:
|
||||
return None
|
||||
if asset.team_id == team.id:
|
||||
return asset
|
||||
is_official_model_asset = (
|
||||
AssetModel.objects.filter(is_official=True, is_deleted=False, purged_at__isnull=True)
|
||||
.filter(Q(portrait_asset=asset) | Q(triview_asset=asset))
|
||||
.exists()
|
||||
)
|
||||
return asset if is_official_model_asset else None
|
||||
|
||||
|
||||
def _guard_asset_reference(asset: Asset, label: str, ref_type: str = "") -> None:
|
||||
"""三库引用前的审核闸(模块4 · 4.2)。
|
||||
|
||||
@@ -317,7 +357,7 @@ def build_content_items(
|
||||
# 全能创作 resolve_refs / 前端常带 type=character|product 且 source 缺省为 upload,
|
||||
# 只要有 asset_id 就按 Asset 解析(含审核态 → asset://),避免直链分支把语义 type skipped。
|
||||
if ref.get("asset_id") and source in {"asset", "upload", ""}:
|
||||
asset = Asset.objects.filter(id=ref["asset_id"], team=team, is_deleted=False).first()
|
||||
asset = _reference_asset(team, ref["asset_id"])
|
||||
if asset is None:
|
||||
raise ValueError(f"素材「{label or '未命名'}」不存在或已被删除")
|
||||
_guard_asset_reference(asset, label, ref_type)
|
||||
@@ -480,10 +520,7 @@ def submit_free_video(*, team, user, params: dict) -> AITask:
|
||||
duration = int(params.get("duration") or 5)
|
||||
except (TypeError, ValueError):
|
||||
raise ValueError("时长参数无效")
|
||||
try:
|
||||
seed = int(params.get("seed") if params.get("seed") is not None else -1)
|
||||
except (TypeError, ValueError):
|
||||
seed = -1
|
||||
seed = normalize_video_seed(params.get("seed"))
|
||||
|
||||
if not prompt:
|
||||
raise ValueError("提示词不能为空")
|
||||
@@ -637,10 +674,7 @@ def start_pending_free_video(task: AITask) -> AITask:
|
||||
duration = int(payload.get("duration") or 5)
|
||||
except (TypeError, ValueError):
|
||||
duration = 5
|
||||
try:
|
||||
seed = int(payload.get("seed") if payload.get("seed") is not None else -1)
|
||||
except (TypeError, ValueError):
|
||||
seed = -1
|
||||
seed = normalize_video_seed(payload.get("seed"))
|
||||
references = list(payload.get("references") or [])
|
||||
if feature == "video_replace" and payload.get("replace_mode") == "product":
|
||||
# 商品复刻:原片只用来提炼,绝不能进 Seedance,否则真人素材直接被火山拒。
|
||||
|
||||
Reference in New Issue
Block a user