fix(core): 脚本 agent 用通用字段解析,根治模型 schema 漂移致旁白/画面空
模型每次生成都换字段名(scene/screenDescription/画面…;dialogue 字符串 /
lines:[{role,content}] / caption…),逐一追变体是治标。改为通用解析:
- _pick_field:优先键命中 → 否则按关键词模糊匹配,跳过 bgMusic/note/shotNo 等非内容键
- 画面来源:visual/scene/screenDescription/画面… 任意命中
- 旁白来源:结构化 dialogue/lines 优先,其次整句 dialogue,再退 narration/voiceover/caption/字幕
实测覆盖 4 种真实/契约变体,全部正确填充;新增通用解析回归用例,23 测试通过。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -51,6 +51,25 @@ class NormalizeDraftTests(SimpleTestCase):
|
||||
self.assertIn("防晒泛白太尴尬", draft["segments"][0]["narration"])
|
||||
self.assertEqual(len(draft["segments"][0]["dialogue"]), 2) # lines→结构化对白
|
||||
|
||||
def test_generic_resolver_covers_unseen_field_names(self):
|
||||
"""模型每次换字段名(scene/screenDescription/画面…、dialogue/lines/caption…)。
|
||||
通用解析应「优先键 + 关键词模糊匹配」都能填,且跳过 bgMusic/note 等非内容键。"""
|
||||
variants = {
|
||||
"canonical": {"total_duration": 15, "segments": [{"role": "钩子", "narration": "口播A", "visual": "画面A"}]},
|
||||
"scene+dialogue_str+subtitle": {"total_duration": 15, "shots": [{"scene": "画面B", "dialogue": "口播B", "subtitle": "字幕B"}]},
|
||||
"scene+lines+caption": {"total_duration": 15, "shots": [{"scene": "画面C", "lines": [{"role": "女主", "content": "口播C"}], "caption": "字幕C"}]},
|
||||
"screenDescription+dialogue+bgMusic+note": {"total_duration": 15, "shots": [{"screenDescription": "画面D", "dialogue": "口播D", "bgMusic": "音乐D", "note": "备注D"}]},
|
||||
}
|
||||
for name, raw in variants.items():
|
||||
draft = normalize_draft(json.dumps(raw, ensure_ascii=False), aspect_ratio="9:16", total_duration=15)
|
||||
seg = draft["segments"][0]
|
||||
self.assertTrue(seg["narration"], f"{name}: 旁白为空")
|
||||
self.assertTrue(seg["visual"], f"{name}: 画面为空")
|
||||
# bgMusic/note 不得被误当画面/旁白
|
||||
d = normalize_draft(json.dumps(variants["screenDescription+dialogue+bgMusic+note"], ensure_ascii=False), aspect_ratio="9:16", total_duration=15)
|
||||
self.assertEqual(d["segments"][0]["visual"], "画面D")
|
||||
self.assertEqual(d["segments"][0]["narration"], "口播D")
|
||||
|
||||
def test_string_dialogue_not_iterated_as_chars(self):
|
||||
"""dialogue 为整句字符串时,要当作旁白而不是逐字符遍历。"""
|
||||
raw = json.dumps({
|
||||
|
||||
Reference in New Issue
Block a user