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: