| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160 |
- # -*- coding: utf-8 -*-
- """金额规则预测器。
- 按 ARCHITECTURE.md Phase 5 拆分建议,从 ``interface/predictor.py`` 迁出以下
- 金额相关类:
- - ``MoneyGrade`` — 金额概率分级(原 predictor.py 第 2954-3024 行)
- - ``DepositPaymentWay`` — 保证金支付方式提取(原 5551-5581 行)
- - ``TotalUnitMoney`` — 总价单价提取(原 6203-6231 行)
- ``interface/predictor.py`` 仍 re-export 以上全部名称,老 import 不受影响。
- """
- from __future__ import absolute_import
- import re
- from BiddingKG.dl.money.re_money_total_unit import extract_total_money, extract_unit_money
- __all__ = [
- "MoneyGrade",
- "DepositPaymentWay",
- "TotalUnitMoney",
- ]
- class MoneyGrade():
- def __init__(self):
- self.tenderee_money_left_9 = "(?P<tenderee_left_9>最高(投标)?限价)|控制(价|金额)|拦标价"
- self.tenderee_money_left_8 = "(?P<tenderee_left_8>预算|限价|起始|起拍|底价|标底)"
- self.tenderer_money_left_9 = "(?P<tenderer_left_9>(中标|成交|合同|总报价))"
- self.tenderer_money_left_8 = "(?P<tenderer_left_8>(投标|总价))"
- self.pattern_list = [self.tenderee_money_left_8, self.tenderer_money_left_8, self.tenderee_money_left_9, self.tenderer_money_left_9]
- def predict(self, list_sentences, list_entitys, span=10, min_prob=0.7):
- sentences = sorted(list_sentences[0], key=lambda x:x.sentence_index)
- role2id = {"tenderee": 0, "tenderer": 1}
- for entity in list_entitys[0]:
- if entity.entity_type in ['money'] and entity.label in [0, 1] and entity.values[entity.label]> 0.6:
- text = sentences[entity.sentence_index].sentence_text
- in_att = sentences[entity.sentence_index].in_attachment
- b = entity.wordOffset_begin
- e = entity.wordOffset_end
- context = text[max(0, b - span):b]
- front_long = text[max(0, b - span*3):b]
- behind = text[e:e+span]
- not_found = 1
- if entity.label == 0 and re.search('招标(控制价|金额|预算)小于$', context): # 修复预算提错。 784107197 招标控制价小于200万的标段招标文件不收取费用
- entity.values[entity.label] = 0.49
- continue
- for pattern in self.pattern_list:
- ser = re.search(pattern, context)
- if ser:
- groupdict = pattern.split('>')[0].replace('(?P<', '')
- _role, _direct, _prob = groupdict.split('_')
- if re.search('单价|不含税', context[-8:]) or re.search('(最低|风险)控制价', context) or entity.notes == '总投资' or re.match('[至到]($|¥)?\d+', behind):# or float(entity.entity_text)<100: # 753504698 最高限价单价 概率降低
- _prob = 6
- _label = role2id.get(_role)
- if _label != entity.label:
- continue
- _prob = int(_prob) * 0.1
- if in_att:
- _prob = max(0.5, _prob - 0.2)
- entity.values[_label] = _prob + entity.values[_label] / 20
- not_found = 0
- if _label == 0 and float(entity.entity_text)<100 and entity.values[_label] > 0.6: # 20250624 小金额预算概率降低 634252534 包合计才是真正的预算
- entity.values[_label] = 0.6
- break
- if not_found and entity.values[entity.label] > min_prob:
- if re.search('单价', context[-8:]) or re.search('(最低|风险)控制价', context) or float(entity.entity_text)<100:
- _prob = 0.6
- elif in_att:
- _prob = max(0.5, min_prob - 0.1)
- else:
- _prob = min_prob
- # _prob = min_prob - 0.1 if in_att else min_prob
- entity.values[entity.label] = _prob + entity.values[entity.label] / 20
- # print('找不到规则修改金额概率:', entity.entity_text, entity.label, entity.values)
- if not_found and re.search('[\d,.万]+元?至¥?$', front_long) and entity.values[entity.label] > 0.5:
- entity.values[entity.label] = 0.8
- # if entity.entity_type in ['money'] and entity.label in [0, 1] and 0.5<=entity.values[entity.label]<0.75 and float(entity.entity_text)<100: # 20241011 低概率小金额改为其他金额 # 20241128 小金额可能为单价,放单价存放
- # entity.label = 2
- elif entity.entity_type in ['money']:
- text = sentences[entity.sentence_index].sentence_text
- in_att = sentences[entity.sentence_index].in_attachment
- b = entity.wordOffset_begin
- e = entity.wordOffset_end
- context = text[max(0, b - span*4):b]
- if re.search('(?<!不)含税总价:$', context) and entity.label in [1, 2] and re.search('(中标|成交|合同|响应|投标)价|报价', context): # 783902219 响应报价:不含税总价:136800元,增值税税率:6%、含税总价:145008元
- entity.label = 1
- entity.values[1] = 0.8
- elif re.search('(预算|服务)金额:¥[\d,.万]+元?至¥?$', context): # 718392079 服务金额:¥10000.0元至¥20000.0元
- entity.label = 0
- entity.values[0] = 0.8
- # 保证金支付方式提取
- class DepositPaymentWay():
- def __init__(self,):
- self.pt = '(保证金的?(交纳|缴纳|应按下列|入账|支付)方式)[::]*([^,。]{,60})'
- self.pt2 = '保证金(必?须以|必?须?通过|以)(.{,8})方式'
- kws = ['银行转账', '公?对公方?式?转账', '对公转账', '柜台转账', '(线上|网上)自?行?(缴纳|交纳|缴退|收退)',
- '网上银行支付', '现金存入', '直接缴纳', '支票', '汇票', '本票', '电汇', '转账', '汇款', '随机码',
- '入账', '基本账户转出', '基本账户汇入', '诚信库中登记的账户转出',
- '银行保函', '电子保函', '担保函', '保证保险', '合法担保机构出具的担保', '金融机构、担保机构出具的保函']
- self.kws = sorted(kws, key=lambda x: len(x), reverse=True)
- def predict(self,content):
- pay_way = {'deposit_patment_way':''}
- result = []
- pay = re.search(self.pt, content)
- if pay:
- # print(pay.group(0))
- pay = pay.group(3)
- for it in re.finditer('|'.join(self.kws), pay):
- result.append(it.group(0))
- pay_way['deposit_patment_way'] = ';'.join(result)
- return pay_way
- pay = re.search(self.pt2, content)
- if pay:
- # print(pay.group(0))
- pay = pay.group(2)
- for it in re.finditer('|'.join(self.kws), pay):
- result.append(it.group(0))
- pay_way['deposit_patment_way'] = ';'.join(result)
- return pay_way
- else:
- return pay_way
- # 总价单价提取
- class TotalUnitMoney:
- def __init__(self):
- pass
- def predict(self, list_sentences, list_entitys):
- for i in range(len(list_entitys)):
- list_entity = list_entitys[i]
- # 总价单价
- for _entity in list_entity:
- if _entity.entity_type == 'money':
- word_of_sentence = list_sentences[i][_entity.sentence_index].sentence_text
- # 总价在中投标金额中
- if _entity.label == 1:
- result = extract_total_money(word_of_sentence,
- _entity.entity_text,
- [_entity.wordOffset_begin, _entity.wordOffset_end])
- if result:
- _entity.is_total_money = 1
- # 单价在普通金额中
- else:
- result = extract_unit_money(word_of_sentence,
- _entity.entity_text,
- [_entity.wordOffset_begin, _entity.wordOffset_end])
- if result:
- _entity.is_unit_money = 1
- # print("total_unit_money", _entity.entity_text,
- # _entity.is_total_money, _entity.is_unit_money)
|