fix(P0): 一键生成接入BGM/ASR字幕/标题 - 修复模板plan config读取 #565
@@ -921,8 +921,10 @@ def _validate_template_exists(template_id: str) -> None:
|
||||
|
||||
|
||||
def _load_template_plan_config(template_id: str) -> dict:
|
||||
"""从模板加载 plan 级配置(BGM、字幕、滤镜等效果层)。
|
||||
"""从模板加载 plan 级配置(BGM、字幕、标题等效果层)。
|
||||
|
||||
TemplateModel 里 bgm_config / subtitle_config / title_config 是独立字段,
|
||||
需要组装成 plan.config 的格式({bgm, subtitle, title})后再注入。
|
||||
模板不存在时返回空 dict,不阻塞主流程。
|
||||
"""
|
||||
if not template_id:
|
||||
@@ -943,17 +945,26 @@ def _load_template_plan_config(template_id: str) -> dict:
|
||||
if template is None:
|
||||
logger.warning("模板不存在,跳过配置加载: template_id=%s", template_id)
|
||||
return {}
|
||||
config = template.config or {}
|
||||
if isinstance(config, str):
|
||||
import json
|
||||
|
||||
config = json.loads(config)
|
||||
# 从独立字段组装成 plan.config 格式
|
||||
plan_config: dict[str, Any] = {}
|
||||
title_cfg = template.title_config or {}
|
||||
subtitle_cfg = template.subtitle_config or {}
|
||||
bgm_cfg = template.bgm_config or {}
|
||||
|
||||
if title_cfg:
|
||||
plan_config["title"] = title_cfg
|
||||
if subtitle_cfg:
|
||||
plan_config["subtitle"] = subtitle_cfg
|
||||
if bgm_cfg:
|
||||
plan_config["bgm"] = bgm_cfg
|
||||
|
||||
logger.info(
|
||||
"模板配置加载成功: template_id=%s keys=%s",
|
||||
template_id,
|
||||
list(config.keys()),
|
||||
list(plan_config.keys()),
|
||||
)
|
||||
return config
|
||||
return plan_config
|
||||
finally:
|
||||
session.close()
|
||||
except Exception as e:
|
||||
|
||||
@@ -408,3 +408,108 @@ class TestTemplateClipEffectMapping:
|
||||
|
||||
result = _extract_intro_outro_from_clip_configs(clip_configs)
|
||||
assert result == {}
|
||||
|
||||
|
||||
class TestTemplatePlanConfigLoading:
|
||||
"""验证从模板加载 plan 级配置(BGM、字幕、标题)的逻辑。"""
|
||||
|
||||
def _mock_template(
|
||||
self,
|
||||
title_config=None,
|
||||
subtitle_config=None,
|
||||
bgm_config=None,
|
||||
is_active=True,
|
||||
):
|
||||
template = MagicMock()
|
||||
template.id = "tmpl_001"
|
||||
template.name = "Test Template"
|
||||
template.is_active = is_active
|
||||
template.title_config = title_config or {}
|
||||
template.subtitle_config = subtitle_config or {}
|
||||
template.bgm_config = bgm_config or {}
|
||||
return template
|
||||
|
||||
def _mock_session(self, template):
|
||||
session = MagicMock()
|
||||
mock_query = MagicMock()
|
||||
session.query.return_value = mock_query
|
||||
filter_result = MagicMock()
|
||||
mock_query.filter.return_value = filter_result
|
||||
filter_result.first.return_value = template
|
||||
return session
|
||||
|
||||
def test_load_template_config_assembles_three_fields(self):
|
||||
"""模板的三个独立字段正确组装成 plan.config 格式。"""
|
||||
from worker_app.tasks.generation import _load_template_plan_config
|
||||
|
||||
title_cfg = {"enabled": True, "text": "我的标题", "font_size": 36}
|
||||
subtitle_cfg = {"enabled": True, "auto_generated": True, "language": "zh"}
|
||||
bgm_cfg = {"enabled": True, "preset_id": "bgm-001", "volume": 0.5}
|
||||
|
||||
template = self._mock_template(
|
||||
title_config=title_cfg,
|
||||
subtitle_config=subtitle_cfg,
|
||||
bgm_config=bgm_cfg,
|
||||
)
|
||||
session = self._mock_session(template)
|
||||
|
||||
with patch("worker_app.tasks.generation.SessionLocal", return_value=session):
|
||||
result = _load_template_plan_config("tmpl_001")
|
||||
|
||||
assert result["title"] == title_cfg
|
||||
assert result["subtitle"] == subtitle_cfg
|
||||
assert result["bgm"] == bgm_cfg
|
||||
|
||||
def test_load_template_config_empty_template_returns_empty(self):
|
||||
"""模板三个字段都为空时返回空 dict。"""
|
||||
from worker_app.tasks.generation import _load_template_plan_config
|
||||
|
||||
template = self._mock_template()
|
||||
session = self._mock_session(template)
|
||||
|
||||
with patch("worker_app.tasks.generation.SessionLocal", return_value=session):
|
||||
result = _load_template_plan_config("tmpl_001")
|
||||
|
||||
assert result == {}
|
||||
|
||||
def test_load_template_config_only_bgm(self):
|
||||
"""只有 BGM 配置时只返回 bgm 字段。"""
|
||||
from worker_app.tasks.generation import _load_template_plan_config
|
||||
|
||||
bgm_cfg = {"enabled": True, "audio_url": "https://example.com/bgm.mp3"}
|
||||
template = self._mock_template(bgm_config=bgm_cfg)
|
||||
session = self._mock_session(template)
|
||||
|
||||
with patch("worker_app.tasks.generation.SessionLocal", return_value=session):
|
||||
result = _load_template_plan_config("tmpl_001")
|
||||
|
||||
assert "bgm" in result
|
||||
assert result["bgm"] == bgm_cfg
|
||||
assert "title" not in result
|
||||
assert "subtitle" not in result
|
||||
|
||||
def test_load_template_config_empty_template_id(self):
|
||||
"""空 template_id 直接返回空 dict。"""
|
||||
from worker_app.tasks.generation import _load_template_plan_config
|
||||
|
||||
result = _load_template_plan_config("")
|
||||
assert result == {}
|
||||
|
||||
result = _load_template_plan_config(None)
|
||||
assert result == {}
|
||||
|
||||
def test_load_template_config_not_found_returns_empty(self):
|
||||
"""模板不存在时返回空 dict,不抛异常。"""
|
||||
from worker_app.tasks.generation import _load_template_plan_config
|
||||
|
||||
session = MagicMock()
|
||||
mock_query = MagicMock()
|
||||
session.query.return_value = mock_query
|
||||
filter_result = MagicMock()
|
||||
mock_query.filter.return_value = filter_result
|
||||
filter_result.first.return_value = None
|
||||
|
||||
with patch("worker_app.tasks.generation.SessionLocal", return_value=session):
|
||||
result = _load_template_plan_config("tmpl_nonexist")
|
||||
|
||||
assert result == {}
|
||||
|
||||
Reference in New Issue
Block a user