diff --git a/webui/tools/generate_script_short.py b/webui/tools/generate_script_short.py index e01b921..79b87b5 100644 --- a/webui/tools/generate_script_short.py +++ b/webui/tools/generate_script_short.py @@ -14,9 +14,25 @@ from webui.tools.generate_short_summary import ( _build_combined_subtitle_content, _normalize_paths, analyze_short_drama_plot, + parse_and_fix_json, ) +def _parse_generated_script_payload(script): + if isinstance(script, list): + return script + + if isinstance(script, str): + parsed = parse_and_fix_json(script) + if isinstance(parsed, list): + return parsed + if isinstance(parsed, dict) and isinstance(parsed.get("items"), list): + return parsed["items"] + raise ValueError("Generated script JSON must be a list or contain an items list") + + raise ValueError("Generated script payload must be a list or JSON string") + + def generate_script_short( tr, params, @@ -175,10 +191,7 @@ def generate_script_short( script = result.get("script") logger.info(f"脚本生成完成 {json.dumps(script, ensure_ascii=False, indent=4)}") - if isinstance(script, list): - st.session_state['video_clip_json'] = script - elif isinstance(script, str): - st.session_state['video_clip_json'] = json.loads(script) + st.session_state['video_clip_json'] = _parse_generated_script_payload(script) update_progress(80, tr("Script generation completed")) diff --git a/webui/tools/generate_short_summary.py b/webui/tools/generate_short_summary.py index 468206d..df1bf54 100644 --- a/webui/tools/generate_short_summary.py +++ b/webui/tools/generate_short_summary.py @@ -176,8 +176,8 @@ def parse_and_fix_json(json_string): # 5. 修复单引号 fixed_json = re.sub(r"'([^']*)':", r'"\1":', fixed_json) - # 6. 修复没有引号的属性名 - fixed_json = re.sub(r'(\w+)(\s*):', r'"\1"\2:', fixed_json) + # 6. 修复没有引号的属性名,仅匹配对象边界后的 key,避免误伤时间戳等字符串值 + fixed_json = re.sub(r'([{\[,]\s*)([A-Za-z_][A-Za-z0-9_]*)(\s*:)', r'\1"\2"\3', fixed_json) # 7. 修复重复的引号 fixed_json = re.sub(r'""([^"]*?)""', r'"\1"', fixed_json) diff --git a/webui/tools/test_generate_script_short_unittest.py b/webui/tools/test_generate_script_short_unittest.py new file mode 100644 index 0000000..0362aed --- /dev/null +++ b/webui/tools/test_generate_script_short_unittest.py @@ -0,0 +1,38 @@ +import unittest + +from webui.tools.generate_script_short import _parse_generated_script_payload + + +class GenerateScriptShortPayloadTests(unittest.TestCase): + def test_parse_generated_script_payload_keeps_list_payload(self): + payload = [{"_id": 1, "timestamp": "00:00:01,000-00:00:02,000"}] + + self.assertEqual(payload, _parse_generated_script_payload(payload)) + + def test_parse_generated_script_payload_accepts_items_wrapper(self): + payload = '{"items": [{"_id": 1, "timestamp": "00:00:01,000-00:00:02,000"}]}' + + parsed = _parse_generated_script_payload(payload) + + self.assertEqual(1, parsed[0]["_id"]) + + def test_parse_generated_script_payload_repairs_common_llm_json_formatting(self): + payload = """```json +{ + "items": [ + {"_id": 1, "timestamp": "00:00:01,000-00:00:02,000",}, + ], +} +```""" + + parsed = _parse_generated_script_payload(payload) + + self.assertEqual(1, parsed[0]["_id"]) + + def test_parse_generated_script_payload_rejects_invalid_shape(self): + with self.assertRaises(ValueError): + _parse_generated_script_payload('{"unexpected": []}') + + +if __name__ == "__main__": + unittest.main() diff --git a/webui/tools/test_generate_short_summary_unittest.py b/webui/tools/test_generate_short_summary_unittest.py index 30122d6..e468bb7 100644 --- a/webui/tools/test_generate_short_summary_unittest.py +++ b/webui/tools/test_generate_short_summary_unittest.py @@ -22,6 +22,19 @@ class GenerateShortSummaryJsonTests(unittest.TestCase): self.assertEqual(1, parsed["items"][0]["_id"]) + def test_repair_does_not_corrupt_timestamp_values(self): + parsed = parse_and_fix_json( + """```json +{ + items: [ + {_id: 1, timestamp: "00:00:01,000-00:00:02,000",}, + ], +} +```""" + ) + + self.assertEqual("00:00:01,000-00:00:02,000", parsed["items"][0]["timestamp"]) + if __name__ == "__main__": unittest.main()