verify_title_fix.py 6.7 KB

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