From adc1aa3b1db02b1582256c7ca13f3d48af92f87a Mon Sep 17 00:00:00 2001 From: starmen1265 Date: Sun, 22 Mar 2026 00:26:14 +0800 Subject: [PATCH] test(13-03): add content completeness protection tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 添加 TestSentenceBoundaryProtection 测试类(COMP-01) - test_sentence_boundary_protection: 验证分段边界在标点符号后 - test_sentence_boundary_in_prompt: 验证 Prompt 包含句边界指令 - 添加 TestArgumentCompleteness 测试类(COMP-02) - test_argument_completeness: 验证论点结构完整性 - test_argument_completeness_in_prompt: 验证 Prompt 包含论点完整性指令 - 添加 TestParallelStructurePreservation 测试类(COMP-03) - test_parallel_structure_preserved: 验证并列结构不被错误拆分 - test_no_special_handling_for_parallel_in_prompt: 验证遵守用户决策(不特别指定并列结构处理) 所有测试通过(29/29),semantic_engine.py 已包含所需的内容完整性保护指令: - 第 337 行:保持句子完整性,列举所有中文句末标点(。?!……) - 第 340 行:保持论点完整性,不在前提-结论结构中间截断 - 不包含并列结构特殊处理(符合用户决策) Co-Authored-By: Claude Opus 4.6 --- tests/test_semantic_engine.py | 214 ++++++++++++++++++++++++++++++++++ 1 file changed, 214 insertions(+) diff --git a/tests/test_semantic_engine.py b/tests/test_semantic_engine.py index d59ba60..7390257 100644 --- a/tests/test_semantic_engine.py +++ b/tests/test_semantic_engine.py @@ -513,3 +513,217 @@ class TestPydanticValidationExtended: result = SegmentationResult(**data) assert result.segments[0].title is None + + +# ============================================================================= +# Test Content Completeness Protection (COMP-01, COMP-02, COMP-03) +# ============================================================================= + +class TestSentenceBoundaryProtection: + """测试句边界保护功能 - COMP-01: 不在句子中间截断""" + + def test_sentence_boundary_protection(self): + """Test: 分段边界应在标点符号后,不在句子中间截断""" + from kb_workflow.srt.parser import Segment + + # Sample segments with clear sentence boundaries + segments = [ + Segment(id=1, start_time=0.0, end_time=3.0, text="机器学习是人工智能的一个分支。"), + Segment(id=2, start_time=3.0, end_time=6.0, text="它使用算法来解析数据、从中学习。"), + Segment(id=3, start_time=6.0, end_time=9.0, text="机器学习的目标是让计算机能够自动学习!"), + ] + + # Mock AI client + mock_client = Mock() + mock_client.api_key = "test-key" + mock_response = """```json +{ + "video_type": "知识类", + "segments": [ + { + "title": "机器学习概述", + "content": "机器学习是人工智能的一个分支。它使用算法来解析数据、从中学习。", + "start_index": 0, + "end_index": 35 + }, + { + "title": null, + "content": "机器学习的目标是让计算机能够自动学习!", + "start_index": 36, + "end_index": 55 + } + ], + "actual_segment_count": 2 +} +```""" + mock_client.generate.return_value = mock_response + + # Create engine and segment + engine = SemanticSegmentationEngine(ai_client=mock_client) + metadata = {"title": "机器学习介绍", "duration": 9.0} + paragraphs = engine.segment(segments, metadata) + + # Verify segmentation occurred + assert len(paragraphs) == 2 + + # Verify sentence boundaries - each paragraph should end with punctuation + import re + sentence_endings = r'[。?!……]$' + + for para in paragraphs: + para_stripped = para.strip() + assert re.search(sentence_endings, para_stripped), \ + f"段落应以标点符号结尾: {para[:50]}..." + + def test_sentence_boundary_in_prompt(self): + """Test: SEGMENTATION_PROMPT 包含句边界保护指令""" + engine = SemanticSegmentationEngine() + + # Get the prompt template + content = "测试内容" + metadata = {"title": "测试", "duration": 10.0, "video_type": "知识类"} + prompt = engine._build_prompt(content, metadata) + + # Verify prompt contains sentence boundary instructions + assert "句号" in prompt or "。" in prompt + assert "问号" in prompt or "?" in prompt + assert "感叹号" in prompt or "!" in prompt + assert "省略号" in prompt or "……" in prompt + assert "不要在句子中间截断" in prompt or "保持句子完整性" in prompt + + +class TestArgumentCompleteness: + """测试论点完整性保护 - COMP-02: 不破坏论点完整性""" + + def test_argument_completeness(self): + """Test: 论点结构应保持完整,前提-结论不被拆分""" + from kb_workflow.srt.parser import Segment + + # Sample segments with premise-conclusion structures + segments = [ + Segment(id=1, start_time=0.0, end_time=4.0, text="首先,让我们理解什么是深度学习。"), + Segment(id=2, start_time=4.0, end_time=8.0, text="深度学习是机器学习的一个子集。"), + Segment(id=3, start_time=8.0, end_time=12.0, text="因此,深度学习能够处理更复杂的数据模式。"), + ] + + # Mock AI client + mock_client = Mock() + mock_client.api_key = "test-key" + mock_response = """```json +{ + "video_type": "知识类", + "segments": [ + { + "title": "深度学习简介", + "content": "首先,让我们理解什么是深度学习。深度学习是机器学习的一个子集。因此,深度学习能够处理更复杂的数据模式。", + "start_index": 0, + "end_index": 50 + } + ], + "actual_segment_count": 1 +} +```""" + mock_client.generate.return_value = mock_response + + # Create engine and segment + engine = SemanticSegmentationEngine(ai_client=mock_client) + metadata = {"title": "深度学习介绍", "duration": 12.0} + paragraphs = engine.segment(segments, metadata) + + # Verify segmentation occurred + assert len(paragraphs) == 1 + + # Verify argument completeness - premise and conclusion together + first_para = paragraphs[0] + assert "首先" in first_para + assert "因此" in first_para + + def test_argument_completeness_in_prompt(self): + """Test: SEGMENTATION_PROMPT 包含论点完整性指令""" + engine = SemanticSegmentationEngine() + + # Get the prompt template + content = "测试内容" + metadata = {"title": "测试", "duration": 10.0, "video_type": "知识类"} + prompt = engine._build_prompt(content, metadata) + + # Verify prompt contains argument completeness instructions + assert "论点完整性" in prompt or "保持论点" in prompt + assert "前提" in prompt or "结论" in prompt or "不要截断" in prompt + + +class TestParallelStructurePreservation: + """测试并列结构保护 - COMP-03: 并列结构不被错误拆分""" + + def test_parallel_structure_preserved(self): + """Test: 并列结构(首先/其次/最后)应保持完整""" + from kb_workflow.srt.parser import Segment + + # Sample segments with parallel structures + segments = [ + Segment(id=1, start_time=0.0, end_time=4.0, text="首先,我们需要收集数据。"), + Segment(id=2, start_time=4.0, end_time=8.0, text="其次,我们清洗和预处理数据。"), + Segment(id=3, start_time=8.0, end_time=12.0, text="最后,我们训练模型并进行评估。"), + ] + + # Mock AI client + mock_client = Mock() + mock_client.api_key = "test-key" + mock_response = """```json +{ + "video_type": "教程类", + "segments": [ + { + "title": "数据收集", + "content": "首先,我们需要收集数据。", + "start_index": 0, + "end_index": 14 + }, + { + "title": "数据预处理", + "content": "其次,我们清洗和预处理数据。", + "start_index": 15, + "end_index": 30 + }, + { + "title": "模型训练", + "content": "最后,我们训练模型并进行评估。", + "start_index": 31, + "end_index": 45 + } + ], + "actual_segment_count": 3 +} +```""" + mock_client.generate.return_value = mock_response + + # Create engine and segment + engine = SemanticSegmentationEngine(ai_client=mock_client) + metadata = {"title": "数据处理流程", "duration": 12.0} + paragraphs = engine.segment(segments, metadata) + + # Verify segmentation occurred + assert len(paragraphs) == 3 + + # Verify each parallel point is complete in its segment + assert "首先" in paragraphs[0] + assert "其次" in paragraphs[1] + assert "最后" in paragraphs[2] + + def test_no_special_handling_for_parallel_in_prompt(self): + """Test: SEGMENTATION_PROMPT 不包含并列结构特殊处理 + + 遵守用户决策:让 LLM 自然判断 + """ + engine = SemanticSegmentationEngine() + + # Get the prompt template + content = "测试内容" + metadata = {"title": "测试", "duration": 10.0, "video_type": "知识类"} + prompt = engine._build_prompt(content, metadata) + + # Verify prompt does NOT have specific instructions for parallel structures + # (per user decision to let LLM naturally judge) + # The prompt should not have special handling like "保持并列结构完整" + assert "保持并列结构完整" not in prompt + assert "并列结构不拆分" not in prompt