template8.py 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  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 ProductInfoTemplate(AbstractTemplate):
  8. """
  9. 产品信息提取模板(适配data.json中的第二个表格结构)
  10. 从第二个表格提取产品相关信息
  11. """
  12. def __init__(self):
  13. super().__init__(
  14. template_id=os.path.abspath(__file__),
  15. priority=3
  16. )
  17. self.target_table = None # 第二个表格,存储产品信息
  18. def check_call_timing(self, preprocessed_data: Dict[str, Any]) -> bool:
  19. """检查是否符合模板调用条件"""
  20. if "表格列表" not in preprocessed_data:
  21. return False
  22. tables = preprocessed_data["表格列表"]
  23. if len(tables) < 1:
  24. print("表格数量不足,至少需要2个表格")
  25. return False
  26. try:
  27. self.target_table = tables[0] # 只处理第二个表格
  28. # 验证表格关键表头(按data.json第二个表格实际结构泛化匹配)
  29. header_patterns = [
  30. (0, 0, r'序号|编号'), # 第1行第1列
  31. (0, 1, r'品目|采购品目'), # 第1行第2列
  32. (0, 2, r'商品名称|产品名称|名称'), # 第1行第3列
  33. (0, 3, r'品牌|品牌名称'), # 第1行第4列
  34. (0, 4, r'型号|规格型号|规格'), # 第1行第5列
  35. (0, 5, r'产地及生产商|产地|生产商'), # 第1行第6列(用于结构验证)
  36. (0, 6, r'数量|采购数量'), # 第1行第7列
  37. (0, 7, r'计量单位|单位|数量单位'), # 第1行第8列
  38. (0, 8, r'预算单价|单价|单价金额'), # 第1行第9列
  39. ]
  40. # 验证表头行存在
  41. if len(self.target_table) < 1:
  42. return False
  43. header_row = self.target_table[0]
  44. # 匹配所有关键表头
  45. for row, col, pattern in header_patterns:
  46. if col >= len(header_row):
  47. print(f"表头列索引超出范围: 第{row+1}行第{col+1}列")
  48. return False
  49. header_text = header_row[col].strip()
  50. if not re.search(pattern, header_text, re.IGNORECASE):
  51. print(f"表头不匹配: {header_text} 不符合 {pattern}")
  52. return False
  53. return True
  54. except Exception as e:
  55. print(f"表格验证错误: {e}")
  56. return False
  57. def extract(self, preprocessed_data: Dict[str, Any]) -> Dict[str, Any]:
  58. """提取表格中的产品信息"""
  59. result = {"产品信息": []}
  60. # 提取产品信息(只处理数据行,跳过表头行)
  61. for row_idx in range(1, len(self.target_table)):
  62. # 过滤技术参数行(根据data.json内容判断)
  63. if self._get_value(self.target_table, row_idx, 1) == "技术参数":
  64. continue
  65. product_info = self._extract_product_info(row_idx)
  66. if product_info:
  67. result["产品信息"].append(product_info)
  68. return result
  69. def _get_value(self, table: list, row: int, col: int) -> str:
  70. """获取表格指定位置的值"""
  71. if row < len(table) and col < len(table[row]):
  72. return table[row][col].strip()
  73. return ""
  74. def _format_amount(self, value: str, header_text: str) -> str:
  75. """格式化金额,补充单位"""
  76. if not value:
  77. return ""
  78. # 检查值中是否已包含单位
  79. if re.search(r'[万亿]?元|¥|人民币', value):
  80. return value
  81. # 从表头获取单位补充
  82. if re.search(r'[万亿]?元|¥|人民币', header_text):
  83. unit = re.search(r'[万亿]?元|¥|人民币', header_text).group(0)
  84. return f"{value}{unit}"
  85. return value
  86. def _extract_product_info(self, data_row: int) -> Dict[str, Any]:
  87. """提取指定数据行的产品详细信息"""
  88. product = {}
  89. header_row = 0 # 表头行固定为第1行(索引0)
  90. # 提取产品名称(商品名称)
  91. product_name = self._get_value(self.target_table, data_row, 2)
  92. if product_name:
  93. product["产品"] = product_name
  94. # 提取品目
  95. paimu = self._get_value(self.target_table, data_row, 1)
  96. if paimu:
  97. product["品目"] = paimu
  98. # 提取品牌
  99. brand = self._get_value(self.target_table, data_row, 3)
  100. if brand and brand != "见附件": # 过滤无效值
  101. product["品牌"] = brand
  102. # 提取规格(型号)
  103. spec = self._get_value(self.target_table, data_row, 4)
  104. if spec and spec != "见附件": # 过滤无效值
  105. product["规格"] = spec
  106. # 提取数量
  107. quantity = self._get_value(self.target_table, data_row, 6)
  108. if quantity and quantity != "见附件": # 过滤无效值
  109. product["数量"] = quantity
  110. # 提取单位
  111. unit = self._get_value(self.target_table, data_row, 7)
  112. if unit and unit != "见附件": # 过滤无效值
  113. product["单位"] = unit
  114. # 提取单价(带单位格式化)
  115. price_value = self._get_value(self.target_table, data_row, 8)
  116. price_header = self._get_value(self.target_table, header_row, 8)
  117. if price_value and price_value != "见附件": # 过滤无效值
  118. product["单价"] = self._format_amount(price_value, price_header)
  119. # 过滤空值字段
  120. return {k: v for k, v in product.items() if v}
  121. # 使用示例
  122. if __name__ == "__main__":
  123. with open("data.json", "r", encoding="utf8") as f:
  124. preprocessed_data = json.load(f)
  125. template = ProductInfoTemplate()
  126. if template.check_call_timing(preprocessed_data):
  127. result = template.extract(preprocessed_data)
  128. print("提取结果:", json.dumps(result, ensure_ascii=False, indent=2))
  129. else:
  130. print("当前数据不满足模板调用条件")