From 3066082ceb19bb01d4e819edd38319d0a9894331 Mon Sep 17 00:00:00 2001 From: saas-backend <466829453@qq.com> Date: Sat, 3 Oct 2026 22:39:09 +0800 Subject: [PATCH] =?UTF-8?q?fix(viral-video):=20=E8=82=96=E5=83=8F/?= =?UTF-8?q?=E7=9C=9F=E4=BA=BA=E5=AE=A1=E6=A0=B8=E6=8B=A6=E6=88=AA=E6=97=B6?= =?UTF-8?q?=E8=87=AA=E5=8A=A8=E9=99=8D=E7=BA=A7=E4=B8=BA=E7=BA=AF=E6=96=87?= =?UTF-8?q?=E5=AD=97t2v=E9=87=8D=E8=AF=95=E4=B8=80=E6=AC=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - _step_render 捕获portrait_intercept/真人/肖像/隐私/SensitiveContent等关键词错误 - 第一次带参考图/首帧/参考视频被审核拦截时,自动移除所有参考素材走纯t2v重试 - 保留reference_audios(TTS口型)不影响肖像审核 - 仍失败则抛具体错误信息(#2166已增强的错误透传) - 解决用户上传真人产品图直接失败无法出片的问题 --- apps/worker/worker_app/tasks/viral_video.py | 36 +++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/apps/worker/worker_app/tasks/viral_video.py b/apps/worker/worker_app/tasks/viral_video.py index fb9892ae5..b02a6d4a7 100644 --- a/apps/worker/worker_app/tasks/viral_video.py +++ b/apps/worker/worker_app/tasks/viral_video.py @@ -1162,6 +1162,7 @@ def _step_render(job: ViralVideoJob, copy_result: dict, tts_audio_url: str | Non ) logger.info("[爆款视频] Seedance prompt (前300字): %s", prompt[:300]) + # 第一次调用:带参考图/首帧/音频/参考视频 result = call_video_generation( prompt=prompt, image_url=first_image, @@ -1175,8 +1176,12 @@ def _step_render(job: ViralVideoJob, copy_result: dict, tts_audio_url: str | Non reference_audios=ref_audios, reference_videos=ref_videos, ) - if not result or not isinstance(result, dict): - # 读取详细错误信息(HTTP 状态码、响应 body、分类后的用户提示),不再笼统显示"返回为空" + + # 肖像/内容审核拦截降级重试:去掉参考图/参考视频走纯文字 t2v 再试一次 + # (不影响音频——去掉首帧和多参考图通常就能绕过真人照片审核,纯文字描述真人是允许的) + def _check_and_reraise(result): + if result and isinstance(result, dict): + return result from packages.shared.ai_service import get_last_video_error err = get_last_video_error() or {} @@ -1196,6 +1201,33 @@ def _step_render(job: ViralVideoJob, copy_result: dict, tts_audio_url: str | Non (detail or "")[:500], ) raise RuntimeError(err_msg) + + if not result or not isinstance(result, dict): + from packages.shared.ai_service import get_last_video_error + + err = get_last_video_error() or {} + err_code = err.get("error_code") or "unknown" + is_portrait = err_code == "portrait_intercept" or any( + k in (err.get("detail", "") or "").lower() + for k in ("real person", "privacy", "portrait", "sensitivecontent", "face", "人脸", "肖像", "真人") + ) + if is_portrait and (first_image or rest_images or ref_videos): + logger.warning("[爆款视频] 参考素材触发真人/肖像审核拦截(error_code=%s),降级为纯文字t2v重试一次", err_code) + # 去掉所有参考图/参考视频,纯 t2v 泛化生成;音频仍保留(不影响肖像审核) + result = call_video_generation( + prompt=prompt, + image_url=None, + duration=dur, + ratio=ratio, + resolution=resolution, + output_dir=str(tmpdir), + model=model, + generate_audio=gen_audio, + reference_images=[], + reference_audios=ref_audios, + reference_videos=[], + ) + _check_and_reraise(result) video_path = result.get("video_path") or "" usage = result.get("usage") if not video_path or not Path(video_path).exists() or Path(video_path).stat().st_size == 0: