| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160 |
- # coding:utf8
- import re
- from typing import Dict, Any
- from BiddingKG.dl.template_extract.abstract_template import AbstractTemplate
- import os
- import json
- class ProductInfoTemplate(AbstractTemplate):
- """
- 产品信息提取模板(适配data.json中的第二个表格结构)
- 从第二个表格提取产品相关信息
- """
- def __init__(self):
- super().__init__(
- template_id=os.path.abspath(__file__),
- priority=3
- )
- self.target_table = None # 第二个表格,存储产品信息
- def check_call_timing(self, preprocessed_data: Dict[str, Any]) -> bool:
- """检查是否符合模板调用条件"""
- if "表格列表" not in preprocessed_data:
- return False
- tables = preprocessed_data["表格列表"]
- if len(tables) < 1:
- print("表格数量不足,至少需要2个表格")
- return False
- try:
- self.target_table = tables[0] # 只处理第二个表格
- # 验证表格关键表头(按data.json第二个表格实际结构泛化匹配)
- header_patterns = [
- (0, 0, r'序号|编号'), # 第1行第1列
- (0, 1, r'品目|采购品目'), # 第1行第2列
- (0, 2, r'商品名称|产品名称|名称'), # 第1行第3列
- (0, 3, r'品牌|品牌名称'), # 第1行第4列
- (0, 4, r'型号|规格型号|规格'), # 第1行第5列
- (0, 5, r'产地及生产商|产地|生产商'), # 第1行第6列(用于结构验证)
- (0, 6, r'数量|采购数量'), # 第1行第7列
- (0, 7, r'计量单位|单位|数量单位'), # 第1行第8列
- (0, 8, r'预算单价|单价|单价金额'), # 第1行第9列
- ]
- # 验证表头行存在
- if len(self.target_table) < 1:
- return False
- header_row = self.target_table[0]
- # 匹配所有关键表头
- for row, col, pattern in header_patterns:
- if col >= len(header_row):
- print(f"表头列索引超出范围: 第{row+1}行第{col+1}列")
- return False
- header_text = header_row[col].strip()
- if not re.search(pattern, header_text, re.IGNORECASE):
- print(f"表头不匹配: {header_text} 不符合 {pattern}")
- return False
- return True
- except Exception as e:
- print(f"表格验证错误: {e}")
- return False
- def extract(self, preprocessed_data: Dict[str, Any]) -> Dict[str, Any]:
- """提取表格中的产品信息"""
- result = {"产品信息": []}
- # 提取产品信息(只处理数据行,跳过表头行)
- for row_idx in range(1, len(self.target_table)):
- # 过滤技术参数行(根据data.json内容判断)
- if self._get_value(self.target_table, row_idx, 1) == "技术参数":
- continue
- product_info = self._extract_product_info(row_idx)
- if product_info:
- result["产品信息"].append(product_info)
- return result
- def _get_value(self, table: list, row: int, col: int) -> str:
- """获取表格指定位置的值"""
- if row < len(table) and col < len(table[row]):
- return table[row][col].strip()
- return ""
- def _format_amount(self, value: str, header_text: str) -> str:
- """格式化金额,补充单位"""
- if not value:
- return ""
- # 检查值中是否已包含单位
- if re.search(r'[万亿]?元|¥|人民币', value):
- return value
- # 从表头获取单位补充
- if re.search(r'[万亿]?元|¥|人民币', header_text):
- unit = re.search(r'[万亿]?元|¥|人民币', header_text).group(0)
- return f"{value}{unit}"
- return value
- def _extract_product_info(self, data_row: int) -> Dict[str, Any]:
- """提取指定数据行的产品详细信息"""
- product = {}
- header_row = 0 # 表头行固定为第1行(索引0)
- # 提取产品名称(商品名称)
- product_name = self._get_value(self.target_table, data_row, 2)
- if product_name:
- product["产品"] = product_name
- # 提取品目
- paimu = self._get_value(self.target_table, data_row, 1)
- if paimu:
- product["品目"] = paimu
- # 提取品牌
- brand = self._get_value(self.target_table, data_row, 3)
- if brand and brand != "见附件": # 过滤无效值
- product["品牌"] = brand
- # 提取规格(型号)
- spec = self._get_value(self.target_table, data_row, 4)
- if spec and spec != "见附件": # 过滤无效值
- product["规格"] = spec
- # 提取数量
- quantity = self._get_value(self.target_table, data_row, 6)
- if quantity and quantity != "见附件": # 过滤无效值
- product["数量"] = quantity
- # 提取单位
- unit = self._get_value(self.target_table, data_row, 7)
- if unit and unit != "见附件": # 过滤无效值
- product["单位"] = unit
- # 提取单价(带单位格式化)
- price_value = self._get_value(self.target_table, data_row, 8)
- price_header = self._get_value(self.target_table, header_row, 8)
- if price_value and price_value != "见附件": # 过滤无效值
- product["单价"] = self._format_amount(price_value, price_header)
- # 过滤空值字段
- return {k: v for k, v in product.items() if v}
- # 使用示例
- if __name__ == "__main__":
- with open("data.json", "r", encoding="utf8") as f:
- preprocessed_data = json.load(f)
- template = ProductInfoTemplate()
- if template.check_call_timing(preprocessed_data):
- result = template.extract(preprocessed_data)
- print("提取结果:", json.dumps(result, ensure_ascii=False, indent=2))
- else:
- print("当前数据不满足模板调用条件")
|