From 7e46afc64cddacf4f99f562723f2a8dd83bae5d0 Mon Sep 17 00:00:00 2001 From: CI Bot Date: Wed, 22 Jul 2026 19:28:34 +0800 Subject: [PATCH] =?UTF-8?q?fix(#633):=20=E4=BF=AE=E5=A4=8D=E4=B8=80?= =?UTF-8?q?=E9=94=AE=E7=94=9F=E6=88=90=E8=BD=AC=E5=9C=BA=E6=97=B6=E9=95=BF?= =?UTF-8?q?=E4=B8=8D=E7=94=9F=E6=95=88=20-=20=5FVirtualClip=E7=BC=BAtransi?= =?UTF-8?q?tion=5Fduration=E5=AD=97=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 根因:_VirtualClip 数据类缺少 transition_duration 字段,导致模板配置的自定义转场时长 在一键生成路径中被静默丢弃,永远使用引擎默认值 0.5s。 修复内容: 1. _VirtualClip 添加 transition_duration 字段(默认0.0,表示用全局默认值) 2. _apply_template_clip_effects 增加 transition_duration 从模板 config 映射 3. UnifiedRenderService 多段裁剪分支 ResolvedClip 构建补上 transition_duration (顺便补上同分支遗漏的 playback_speed) 4. 补充 3 个单测用例:正常映射/cut转场忽略/无效值安全跳过 --- .../unified_render_service.py | 2 + apps/worker/worker_app/tasks/generation.py | 13 ++++- tests/unit/test_oneclick_gen_p0_fixes.py | 50 +++++++++++++++++++ 3 files changed, 64 insertions(+), 1 deletion(-) mode change 100644 => 100755 apps/worker/worker_app/tasks/generation.py diff --git a/apps/worker/video_processing/unified_render_service.py b/apps/worker/video_processing/unified_render_service.py index d29d5a314..58b6af808 100755 --- a/apps/worker/video_processing/unified_render_service.py +++ b/apps/worker/video_processing/unified_render_service.py @@ -1304,6 +1304,8 @@ class UnifiedRenderService: start_time=seg_start, duration=seg_duration, transition_effect=clip.transition_effect or "cut", + transition_duration=getattr(clip, "transition_duration", 0.0) or 0.0, + playback_speed=getattr(clip, "playback_speed", 1.0) or 1.0, config={**clip_config, "_segment_id": seg.segment_id}, actual_duration=actual_duration, trim_config=seg.trim, diff --git a/apps/worker/worker_app/tasks/generation.py b/apps/worker/worker_app/tasks/generation.py old mode 100644 new mode 100755 index 9f096779d..0612dfa5b --- a/apps/worker/worker_app/tasks/generation.py +++ b/apps/worker/worker_app/tasks/generation.py @@ -171,6 +171,7 @@ class _VirtualClip: start_time: float = 0.0 duration: float = 0.0 transition_effect: str = "cut" + transition_duration: float = 0.0 # 0 表示使用全局默认值 playback_speed: float = 1.0 status: str = "ready" config: dict[str, Any] = field(default_factory=dict) @@ -279,7 +280,7 @@ def _apply_template_clip_effects( cfg_idx = min(i, len(main_configs) - 1) template_cfg = main_configs[cfg_idx] - # 1. 转场效果 + # 1. 转场效果 + 时长 transition = ( template_cfg.transition_effect.value if hasattr(template_cfg.transition_effect, "value") @@ -287,6 +288,16 @@ def _apply_template_clip_effects( ) if transition and transition != "cut": clip.transition_effect = transition + # 同步转场时长(模板 clip_config 里的 transition_duration) + tpl_cfg = template_cfg.config or {} + tpl_duration = tpl_cfg.get("transition_duration") + if tpl_duration: + try: + dur_val = float(tpl_duration) + if dur_val > 0: + clip.transition_duration = dur_val + except (ValueError, TypeError): + pass # 2. clip 级效果配置(滤镜、调速等) template_clip_config = template_cfg.config or {} diff --git a/tests/unit/test_oneclick_gen_p0_fixes.py b/tests/unit/test_oneclick_gen_p0_fixes.py index 283f0250d..73cf4f1fe 100755 --- a/tests/unit/test_oneclick_gen_p0_fixes.py +++ b/tests/unit/test_oneclick_gen_p0_fixes.py @@ -309,6 +309,8 @@ class TestTemplateClipEffectMapping: asset_id: str = f"asset_{idx}" duration: float = 5.0 transition_effect: str = "cut" + transition_duration: float = 0.0 + playback_speed: float = 1.0 config: dict = field(default_factory=dict) return FakeClip(config=config or {}) @@ -396,6 +398,54 @@ class TestTemplateClipEffectMapping: # 模板是 cut 时,保留原有值(避免无意义覆盖) assert clips[0].transition_effect == "fade" + def test_transition_duration_mapped(self): + """转场时长(transition_duration)从模板 config 正确映射到 clip.""" + from worker_app.tasks.generation import _apply_template_clip_effects + + clips = [self._make_virtual_clip(i) for i in range(3)] + clip_configs = [ + self._make_template_clip_config("main", transition="fade", config={"transition_duration": 0.8}), + self._make_template_clip_config("main", transition="dissolve", config={"transition_duration": 1.2}), + ] + + _apply_template_clip_effects(clips, clip_configs, "one_take") + + # 前两个按顺序映射,第三个复用最后一个 + assert clips[0].transition_effect == "fade" + assert clips[0].transition_duration == 0.8 + assert clips[1].transition_effect == "dissolve" + assert clips[1].transition_duration == 1.2 + assert clips[2].transition_effect == "dissolve" + assert clips[2].transition_duration == 1.2 + + def test_transition_duration_ignored_for_cut(self): + """模板转场为 cut 时,transition_duration 不生效(保持默认0).""" + from worker_app.tasks.generation import _apply_template_clip_effects + + clips = [self._make_virtual_clip(0)] + clip_configs = [ + self._make_template_clip_config("main", transition="cut", config={"transition_duration": 0.5}), + ] + + _apply_template_clip_effects(clips, clip_configs, "one_take") + + # cut 转场不映射,transition_duration 也不应用 + assert clips[0].transition_duration == 0.0 + + def test_transition_duration_invalid_value_skipped(self): + """transition_duration 为无效值时安全跳过.""" + from worker_app.tasks.generation import _apply_template_clip_effects + + clips = [self._make_virtual_clip(0)] + clip_configs = [ + self._make_template_clip_config("main", transition="fade", config={"transition_duration": "abc"}), + ] + + _apply_template_clip_effects(clips, clip_configs, "one_take") + + assert clips[0].transition_effect == "fade" + assert clips[0].transition_duration == 0.0 # 无效值保持默认 + def test_intro_outro_extracted(self): """intro/outro 类型 clip_config 正确提取为 plan 级 intro_outro 配置.""" from worker_app.tasks.generation import _extract_intro_outro_from_clip_configs -- 2.54.0