fix(视频): 场景/商品也送火山审核, 避免含真人参考图被判「疑似真人」拒
场景图与商品图可能出现真人(模特出镜/上身), 此前从不送审, 视频路只能 传原始直链 → 火山报 InputImageSensitiveContentDetected.PrivacyInformation → 整批段失败。现按角色流程把 scene/product_image 也纳入送审: - REVIEW_CATEGORIES 增加 scene + product_image(送审 + 轮询自动覆盖) - 场景/商品基础资产生成后 on_commit 自动静默送审, 拿到 remote_id → 视频路 _seedance_ref_url 换成 asset:// 素材库引用即可放行 - 前端场景卡 + 商品三视图面板挂同款审核盾牌, 可查状态/手动补送审 未改动生成前硬性过审闸(避免无真人的场景/商品被误拦; asset:// 在 processing 态也能引用, 故不拦也能正常出片)。 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -1337,11 +1337,12 @@ def run_base_asset_task(*, task_id: str) -> None:
|
||||
group.candidate_assets.add(asset)
|
||||
group.adopted_asset = asset
|
||||
group.save(update_fields=["adopted_asset", "prompt", "updated_at"])
|
||||
# 真人资产:事务提交后静默送火山审核(best-effort,网络调用放 on_commit 避免占着事务)
|
||||
if kind == BaseAssetGroup.Kind.PERSON:
|
||||
from apps.assets.review import submit_asset_for_review
|
||||
# 含人脸资产(角色 / 场景 / 商品):事务提交后静默送火山审核(best-effort,网络调用放 on_commit 避免占着事务)。
|
||||
# 场景 / 商品也送审,因为它们可能出现真人(模特出镜/上身),拿到 remote_id 后视频路才能换 asset:// 引用,
|
||||
# 否则传原始直链会被火山判「疑似真人」拒。submit_asset_for_review 自身按 REVIEW_CATEGORIES 兜底,非送审类不会真送。
|
||||
from apps.assets.review import submit_asset_for_review
|
||||
|
||||
transaction.on_commit(lambda a=asset: submit_asset_for_review(a))
|
||||
transaction.on_commit(lambda a=asset: submit_asset_for_review(a))
|
||||
except Exception as exc: # noqa: BLE001 — 失败要退费并把错误记进 AITask 供前端轮询读取;不向上抛(避免 celery 重试二次扣费)
|
||||
task.status = AITask.Status.FAILED
|
||||
task.error_message = str(exc)
|
||||
|
||||
@@ -34,8 +34,10 @@ class Asset(TeamOwnedModel):
|
||||
FREE_CREATE = "free_create", "Free Create" # 自由创作(图片趴)
|
||||
STORYBOARD = "storyboard", "Storyboard" # 分镜图(视频趴·送审)
|
||||
|
||||
# 送审范围(火山人像审核):视频趴含人脸 = 角色定妆照 / 三视图 / 分镜图。图片趴(上身图/套图/创作)不送审。
|
||||
REVIEW_CATEGORIES = ("person", "tri_view", "storyboard")
|
||||
# 送审范围(火山人像审核):视频趴含人脸 = 角色定妆照 / 三视图 / 分镜图 / 场景 / 商品图。
|
||||
# 场景图与商品图也可能出现真人(模特出镜/上身),不送审则视频路只能传原始直链 → 火山判「疑似真人」拒;
|
||||
# 送审后拿到 remote_id,视频路换 asset:// 素材库引用即可放行。图片趴(上身图/套图/创作)仍不送审。
|
||||
REVIEW_CATEGORIES = ("person", "tri_view", "storyboard", "scene", "product_image")
|
||||
|
||||
name = models.CharField(max_length=255)
|
||||
asset_type = models.CharField(max_length=24, choices=Type.choices)
|
||||
|
||||
@@ -2942,6 +2942,16 @@ export function PipelinePage(props: {
|
||||
})()}
|
||||
{previewTriAsset && (
|
||||
<div className="prod-preview-foot" id="prod-preview-foot">
|
||||
{/* 商品图也挂审核盾:商品图可能出现模特,送审后视频路才能换 asset:// 引用(与角色/场景同款) */}
|
||||
{adoptedTriAsset && (
|
||||
<ReviewBadge
|
||||
compact
|
||||
status={(reviews[adoptedTriAsset] || productGroup?.adopted_asset_review || "") as ReviewStatus}
|
||||
error={productGroup?.adopted_asset_review_error || byId.get(adoptedTriAsset)?.review_error}
|
||||
busy={reviewBusyId === adoptedTriAsset}
|
||||
onSubmit={() => submitAssetReview(adoptedTriAsset)}
|
||||
/>
|
||||
)}
|
||||
<button className="btn btn-ghost btn-sm" type="button" disabled={triGenerating} onClick={runProductTri}>↻ 重跑</button>
|
||||
<button className="btn btn-sm prod-preview-adopt" type="button" disabled={previewTriAsset === adoptedTriAsset || loading} title={previewTriAsset === adoptedTriAsset ? "此版本已采用" : "将此版本设为商品采用版本"} onClick={() => { if (productGroup && previewTriAsset !== adoptedTriAsset) void onAdoptBaseAsset(productGroup.id, previewTriAsset); }}>
|
||||
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" style={{ marginRight: 4 }}><path d="M4 12l5 5L20 6" /></svg>
|
||||
@@ -3081,7 +3091,8 @@ export function PipelinePage(props: {
|
||||
const busy = isBusy(entBK) || isBusy(`${entBK}:tri`) || (!mainUrl && pendingHas(kind, entity.name));
|
||||
// 审核态:优先本地轮询的实时态(processing→终态),回退项目详情持久下发的 adopted_asset_review
|
||||
// (刷新后轮询 map 为空也能回显;不再依赖 byId,因为页面没喂全量 assets)
|
||||
const rs = kind === "person" && grp.adopted_asset ? (reviews[grp.adopted_asset] || grp.adopted_asset_review || "") : "";
|
||||
// 角色 + 场景卡都挂审核盾:场景图也可能出现真人,送审后视频路才能换 asset:// 引用
|
||||
const rs = (kind === "person" || kind === "scene") && grp.adopted_asset ? (reviews[grp.adopted_asset] || grp.adopted_asset_review || "") : "";
|
||||
return (
|
||||
<div className="asset-card-2" data-asset-kind={kind} data-asset-id={entity.key} key={entity.key}>
|
||||
{/* D:hover 删除(角色/场景卡;商品主卡不给删)·二次确认 */}
|
||||
@@ -3106,7 +3117,7 @@ export function PipelinePage(props: {
|
||||
<div className="hstack">
|
||||
<strong style={{ fontSize: "13.5px", cursor: "pointer" }} onClick={() => openAssetDetail(kind, entity)}>{entity.name}</strong>
|
||||
<span className="spacer"></span>
|
||||
{kind === "person" && grp.adopted_asset && (
|
||||
{(kind === "person" || kind === "scene") && grp.adopted_asset && (
|
||||
<ReviewBadge
|
||||
status={rs as ReviewStatus}
|
||||
error={grp.adopted_asset_review_error || byId.get(grp.adopted_asset)?.review_error}
|
||||
|
||||
Reference in New Issue
Block a user