模特库标签分页与全能创作收口:藏长视频、选择器分页
角色库导入打标签并支持筛选;模特库与全能创作角色/商品选择改为每页 20 条分页。临时限制成片 ≤60 秒,过滤对话里的超长时长选项,并收拢本地全能创作与后台用户相关修复。
This commit is contained in:
@@ -33,6 +33,7 @@ from .free_video import (
|
||||
IN_FLIGHT_STATUSES,
|
||||
RATIOS,
|
||||
RESOLUTIONS,
|
||||
normalize_video_seed,
|
||||
_reap_stale_free_video_tasks,
|
||||
model_duration_range,
|
||||
serialize_free_video_task,
|
||||
@@ -654,6 +655,21 @@ def video_replace_q() -> Q:
|
||||
return Q(request_payload__feature=FEATURE) | Q(request_payload__prompt__startswith=LEGACY_PROMPT_PREFIX)
|
||||
|
||||
|
||||
def not_video_replace_q() -> Q:
|
||||
"""「不是视频复刻」。不能写成 exclude(video_replace_q())。
|
||||
|
||||
JSON 键不存在时取值是 SQL NULL,NOT(NULL = 'x') 仍是 NULL,整行会被 exclude 一起筛掉 ——
|
||||
于是 request_payload 里没有 feature 的历史任务在列表和回收站里凭空消失。必须把「键缺失」
|
||||
显式算作不匹配。
|
||||
"""
|
||||
return (
|
||||
Q(request_payload__feature__isnull=True) | ~Q(request_payload__feature=FEATURE)
|
||||
) & (
|
||||
Q(request_payload__prompt__isnull=True)
|
||||
| ~Q(request_payload__prompt__startswith=LEGACY_PROMPT_PREFIX)
|
||||
)
|
||||
|
||||
|
||||
def _fresh_digest_source(payload: dict) -> dict | None:
|
||||
"""历史卡「原视频」用的原片快照。快照 URL 会过期,统一走 rehydrate_ref_urls 重新取长期直链。"""
|
||||
from .free_video import rehydrate_ref_urls
|
||||
@@ -1028,10 +1044,7 @@ def _legacy_start_pending_replace_shots(task):
|
||||
generate_audio = bool(payload.get("generate_audio", True))
|
||||
search_mode = str(payload.get("search_mode") or "off")
|
||||
feature = str(payload.get("feature") or FEATURE)
|
||||
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"))
|
||||
billed_duration = sum(int(item.get("seconds") or 0) for item in plan) or int(payload.get("duration") or 5)
|
||||
references = _seedance_references(payload)
|
||||
try:
|
||||
@@ -1238,10 +1251,7 @@ def _dispatch_next_replace_shot(task, shot: dict):
|
||||
locked.request_payload = next_payload
|
||||
locked.save(update_fields=["request_payload", "updated_at"])
|
||||
|
||||
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"))
|
||||
dispatched = _dispatch_free_video_provider(
|
||||
task=locked,
|
||||
built=built,
|
||||
@@ -1403,7 +1413,9 @@ def _concat_shot_media(urls: list[str]) -> bytes:
|
||||
"-c:v", "libx264", "-pix_fmt", "yuv420p", "-preset", "veryfast", "-threads", "2",
|
||||
"-c:a", "aac", "-b:a", "192k", "-movflags", "+faststart", str(output),
|
||||
]
|
||||
proc = subprocess.run(cmd, capture_output=True, timeout=180)
|
||||
# 180 秒成片最多 6 段,1080p 重编码明显可能超过旧的 180 秒固定超时。
|
||||
# 按片段数放宽,但仍保留上限式超时,避免异常 ffmpeg 永久占住 worker。
|
||||
proc = subprocess.run(cmd, capture_output=True, timeout=max(180, len(paths) * 120))
|
||||
if proc.returncode != 0 or not output.exists() or not output.stat().st_size:
|
||||
err = (proc.stderr or b"").decode("utf-8", errors="replace")[-500:]
|
||||
raise RuntimeError(f"镜头拼接失败:{err or 'ffmpeg 未产出文件'}")
|
||||
@@ -1605,10 +1617,7 @@ def _create_reviewing_task(*, team, user, params: dict, digest_pending: bool = F
|
||||
if available < reserve_amount:
|
||||
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"))
|
||||
request_payload = {
|
||||
"feature": FEATURE,
|
||||
"mode": "universal",
|
||||
|
||||
Reference in New Issue
Block a user