template1.py 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. # coding:utf8
  2. import re
  3. from typing import Dict, Any
  4. from BiddingKG.dl.template_extract.abstract_template import AbstractTemplate
  5. import os
  6. import json
  7. class BidResultTemplate(AbstractTemplate):
  8. """
  9. 中标结果信息提取模板
  10. 适配包含序号、候选供应商名称、中选金额的表格提取
  11. """
  12. def __init__(self):
  13. super().__init__(
  14. template_id=os.path.abspath(__file__),
  15. priority=3
  16. )
  17. def check_call_timing(self, preprocessed_data: Dict[str, Any]) -> bool:
  18. """检查是否符合模板调用条件"""
  19. if "表格列表" not in preprocessed_data:
  20. return False
  21. tables = preprocessed_data["表格列表"]
  22. if len(tables) < 1:
  23. return False
  24. try:
  25. datas = tables[0]
  26. # 至少需要表头行和一行数据
  27. if len(datas) < 2:
  28. return False
  29. header = datas[0]
  30. # 表头列数需匹配目标表格(3列)
  31. if len(header) != 3:
  32. # print(f"表头列数异常:{len(header)}列,预期3列")
  33. return False
  34. # 表头内容正则匹配(泛化类似表达)
  35. header_patterns = [
  36. r'序号|编号', # 第1列:序号
  37. r'(候选|中标)?供应商名称|(候选|中标)?单位名称|(候选|中标)?人(名称)?', # 第2列:候选供应商名称
  38. r'(中选金额|中标金额|成交金额)((万?元))?' # 第3列:中选金额
  39. ]
  40. # 逐列验证表头
  41. for i, pattern in enumerate(header_patterns):
  42. if not re.fullmatch(pattern, header[i]):
  43. # print(f'表头第{i+1}列未匹配:{pattern} vs {header[i]}')
  44. return False
  45. self.header = header
  46. self.data = datas[1:]
  47. return True
  48. except Exception as e:
  49. print(f"表格验证错误: {e}")
  50. return False
  51. def extract(self, preprocessed_data: Dict[str, Any]) -> Dict[str, Any]:
  52. """提取表格中的中标/候选人信息"""
  53. # 初始化返回结构
  54. extract_result = {
  55. "项目编号": "",
  56. "项目名称": "",
  57. "招标信息": [],
  58. "中标信息": [],
  59. "候选人信息": [],
  60. "产品信息": []
  61. }
  62. # 处理每行数据
  63. for row in self.data:
  64. # 跳过列数异常的行
  65. if len(row) != 3:
  66. continue
  67. # 解析每行数据
  68. seq, candidate, price = row
  69. # 过滤空值
  70. seq = seq.strip() if seq else ""
  71. candidate = candidate.strip() if candidate else ""
  72. price = price.strip() if price else ""
  73. # 补充金额单位(如果没有的话)
  74. if price and not re.search(r'[万亿美欧日]?元', price):
  75. # 优先从表头提取单位,没有则默认加"元"
  76. unit_match = re.search(r'[万亿美欧日]?元', self.header[2])
  77. if unit_match:
  78. price += unit_match.group(0)
  79. else:
  80. price += "元"
  81. # 若没有排名但有中标人,返回中标信息(当前数据有序号,此分支不会触发)
  82. if candidate and price:
  83. bid_info = {
  84. "标的": "",
  85. "标包": "",
  86. "包号": "",
  87. "中标人": candidate,
  88. "中标价": price,
  89. "联系人": "",
  90. "电话": "",
  91. "服务时间": "",
  92. "地址": ""
  93. }
  94. # 过滤空值字段
  95. bid_info = {k: v for k, v in bid_info.items() if v}
  96. extract_result["中标信息"].append(bid_info)
  97. # 处理招标信息(当前数据无招标人/预算,置空)
  98. extract_result["招标信息"] = []
  99. # 过滤空列表和空值字段
  100. extract_result = {k: v for k, v in extract_result.items() if v or (isinstance(v, list) and len(v) > 0)}
  101. return extract_result
  102. # 使用示例
  103. if __name__ == "__main__":
  104. # 读取数据文件
  105. with open("data.json", "r", encoding="utf8") as f:
  106. preprocessed_data = json.load(f)
  107. # 初始化模板并提取信息
  108. template = BidResultTemplate()
  109. if template.check_call_timing(preprocessed_data):
  110. result = template.extract(preprocessed_data)
  111. print("提取结果:", json.dumps(result, ensure_ascii=False, indent=2))
  112. else:
  113. print("当前数据不满足模板调用条件")