verify_title_fix.py 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. """
  4. 验证脚本:直接测试title_matcher的位置计算是否正确
  5. 不依赖embedding服务,只验证文档提取模块的bug修复
  6. """
  7. import sys
  8. import os
  9. from pathlib import Path
  10. project_root = Path(__file__).parent.parent.parent
  11. os.chdir(project_root)
  12. import fitz
  13. from core.construction_review.component.doc_worker.utils.title_matcher import TitleMatcher
  14. # 测试文件
  15. test_file = 'D:/wx_work/sichuan_luqiao/lu_sgsc_testfile/测试模版-四川路桥专项施工方案框架以及编制说明(2025修订第三版)- v0.2.pdf'
  16. def test_chapter_10_positions():
  17. """测试第十章标题位置是否正确"""
  18. print("=" * 70)
  19. print("测试:第十章 其他资料 - 标题位置查找")
  20. print("=" * 70)
  21. doc = fitz.open(test_file)
  22. full_text = ""
  23. for page in doc:
  24. full_text += page.get_text()
  25. print(f"全文长度: {len(full_text)} 字符")
  26. print()
  27. matcher = TitleMatcher()
  28. title = "第十章 其他资料"
  29. # 调用_find_full_title_positions
  30. positions = matcher._find_full_title_positions(title, full_text)
  31. print(f"找到的标题位置: {positions}")
  32. print()
  33. # 验证每个位置的内容
  34. print("验证每个位置的上下文:")
  35. print("-" * 70)
  36. for pos in positions:
  37. # 找到位置所在的行
  38. line_start = full_text.rfind('\n', 0, pos) + 1
  39. line_end = full_text.find('\n', pos)
  40. if line_end == -1:
  41. line_end = len(full_text)
  42. line_text = full_text[line_start:line_end]
  43. # 找到页码
  44. text_before = full_text[:pos]
  45. page_num = text_before.count('\f') + 1 # \f是分页符
  46. print(f" 位置 {pos} (约第{page_num}页):")
  47. print(f" 行内容: {repr(line_text[:100])}")
  48. # 判断是否为引用(包含"放置于"等前缀)
  49. if '放置于' in line_text or '置于' in line_text or '详见' in line_text:
  50. print(f" ⚠️ 警告: 这是引用位置,不是真实标题!")
  51. else:
  52. print(f" ✓ 正确: 这是真实标题位置")
  53. print()
  54. # 判断结果
  55. expected_count = 2 # 应该只找到2个真实标题位置
  56. false_positives = [p for p in positions if p in [14328, 39690]] # 已知的问题位置
  57. print("-" * 70)
  58. print("测试结果:")
  59. if len(positions) == expected_count and not false_positives:
  60. print(f" ✓ 通过: 找到 {len(positions)} 个位置,没有假阳性")
  61. return True
  62. else:
  63. print(f" ✗ 失败: 找到 {len(positions)} 个位置,期望 {expected_count} 个")
  64. if false_positives:
  65. print(f" 存在假阳性位置: {false_positives}")
  66. return False
  67. def test_all_chapter_positions():
  68. """测试所有章节的标题位置"""
  69. print("\n" + "=" * 70)
  70. print("测试:所有章节的标题位置查找")
  71. print("=" * 70)
  72. doc = fitz.open(test_file)
  73. full_text = ""
  74. for page in doc:
  75. full_text += page.get_text()
  76. matcher = TitleMatcher()
  77. # 常见章节标题
  78. test_titles = [
  79. "第一章 编制依据",
  80. "第二章 工程概况",
  81. "第三章 施工计划",
  82. "第四章 施工工艺技术",
  83. "第五章 施工保证措施",
  84. "第六章 施工管理及作业人员配备和分工",
  85. "第七章 验收要求",
  86. "第八章 应急处置措施",
  87. "第九章 计算书",
  88. "第十章 其他资料",
  89. ]
  90. results = {}
  91. for title in test_titles:
  92. positions = matcher._find_full_title_positions(title, full_text)
  93. results[title] = positions
  94. print(f" {title}: {positions}")
  95. # 检查结果:每个标题应该只找到1-2个位置(目录页和正文页)
  96. print("\n结果分析:")
  97. all_passed = True
  98. for title, positions in results.items():
  99. if len(positions) > 2:
  100. print(f" ⚠️ {title}: 找到 {len(positions)} 个位置,可能包含假阳性")
  101. all_passed = False
  102. elif len(positions) == 0:
  103. print(f" ✗ {title}: 未找到位置")
  104. all_passed = False
  105. else:
  106. print(f" ✓ {title}: 找到 {len(positions)} 个位置")
  107. return all_passed
  108. def test_false_positive_filtering():
  109. """测试假阳性过滤是否有效"""
  110. print("\n" + "=" * 70)
  111. print("测试:假阳性过滤")
  112. print("=" * 70)
  113. # 包含引用的测试行
  114. test_lines = [
  115. "横道图,应将页面横向布置,放置于第十章其他资料中。",
  116. "型、证书编号、有效期、岗位职责等内容,并将人员证件扫描件放置于第十章其他",
  117. "详见第十章其他资料",
  118. "第十章 其他资料", # 真实标题
  119. " 第十章 其他资料 ", # 带空格的真实标题
  120. ]
  121. matcher = TitleMatcher()
  122. title = "第十章 其他资料"
  123. print(f"测试标题: '{title}'")
  124. print()
  125. for line in test_lines:
  126. line_normalized = matcher._normalize_title(line)
  127. # 模拟_find_full_title_positions中的判断逻辑
  128. is_match = title in line_normalized or title.replace(' ', '') in line_normalized.replace(' ', '')
  129. if is_match:
  130. # 检查位置
  131. pos = line_normalized.find(title)
  132. if pos < 0:
  133. pos = line_normalized.replace(' ', '').find(title.replace(' ', ''))
  134. if pos >= 0:
  135. # 需要映射回normalized的位置
  136. pass
  137. # 调用_is_likely_title_position
  138. if pos >= 0:
  139. is_likely = matcher._is_likely_title_position(line_normalized, pos, title)
  140. else:
  141. is_likely = False
  142. status = "✓ 接受" if is_likely else "✗ 过滤"
  143. print(f" {status}: {repr(line[:50])}")
  144. else:
  145. print(f" - 不匹配: {repr(line[:50])}")
  146. return True
  147. if __name__ == "__main__":
  148. print("开始验证标题位置计算修复...")
  149. print(f"项目根目录: {project_root}")
  150. print(f"测试文件: {test_file}")
  151. print()
  152. # 运行测试
  153. test1_passed = test_chapter_10_positions()
  154. test2_passed = test_all_chapter_positions()
  155. test3_passed = test_false_positive_filtering()
  156. print("\n" + "=" * 70)
  157. print("最终测试结果:")
  158. print("=" * 70)
  159. print(f" 测试1 (第十章位置): {'通过' if test1_passed else '失败'}")
  160. print(f" 测试2 (所有章节): {'通过' if test2_passed else '失败'}")
  161. print(f" 测试3 (假阳性过滤): {'通过' if test3_passed else '失败'}")
  162. if test1_passed and test2_passed and test3_passed:
  163. print("\n ✓ 所有测试通过!标题位置计算bug已修复。")
  164. else:
  165. print("\n ✗ 部分测试失败,需要进一步修复。")