| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220 |
- # -*- coding: utf-8 -*-
- """联合体与多中标人金额装配(Phase 6 迁移)。
- 本模块由 ``interface/getAttributes.py`` 第 4804-5006 行迁移而来,负责:
- - ``get_win_joint``:从正文与实体列表中识别联合体信息并写入 prem
- - ``get_multi_winner_and_money``:装配多中标人(multi_winner)并收集正文/附件金额
- 迁移说明:原文件使用 ``from BiddingKG.dl.common.Utils import *``,本模块改为显式导入。
- 经核查,两个函数仅依赖标准库 ``re``,不依赖 common.Utils 中的任何名称。
- """
- from __future__ import absolute_import
- import re
- __all__ = ["get_win_joint", "get_multi_winner_and_money"]
- def get_win_joint(prem, list_entitys, list_sentences, list_articles):
- '''
- 获取联合体信息, 添加到prem
- :param prem:
- :param list_entitys:
- :param list_sentences:
- :param list_articles:
- :return:
- '''
- try:
- if 'win_tenderer' in str(prem[0]['prem']) and re.search('联合(体|方|投标人):|联合体?(成员|单位)[12345一二三四五]?:|(联合体?)?成员单位[12345一二三四五]?:|特殊普通合伙:|(联合(体|投标人))|(联合体(成员|单位)方?[12345一二三四五]?)|((联合体)?成员单位[12345一二三四五]?)|(特殊普通合伙|成员?)|[,;]成:|(成[),]|[与和][^,。]{6,100}联合体', list_articles[0].content):
- sentences = sorted(list_sentences[0], key=lambda x:x.sentence_index)
- for v in prem[0]['prem'].values():
- for d in v['roleList']:
- if d.get('role_name', '') == 'win_tenderer':
- winner = d.get('role_text')
- join_l = [winner]
- for list_entity in list_entitys:
- for i in range(len(list_entity)-1):
- _entity = list_entity[i]
- b = _entity.wordOffset_begin
- e = _entity.wordOffset_end
- if _entity.entity_type in ['org', 'company'] and _entity.label==2 and _entity.values[2] > 0.7 and _entity.entity_text==winner: # 补充概率,修复多中标错误 746420740 ,推荐理由:中国移动通信集团辽宁有限公司大连分公司、大连天途有线电视网络股份有限公司、中国联合网络通信有限公司大连市分公司,参与了本项目投标,
- s = sentences[_entity.sentence_index].sentence_text
- find_joint = 0 # 是否包含联合体
- for j in range(i+1, len(list_entity)):
- behind_entity = list_entity[j]
- b2 = behind_entity.wordOffset_begin
- e2 = behind_entity.wordOffset_end
- if _entity.sentence_index == behind_entity.sentence_index and behind_entity.entity_type in ['org', 'company'] \
- and b2-e<13 and re.search('联合(体|方|投标人):|联合体?(成员|单位)[12345一二三四五]?:|(联合体?)?成员单位[12345一二三四五]?:|特殊普通合伙:|[,;]成:|(成)$', s[e:b2]) or \
- re.search('(联合(体|方|投标人))|(联合体?(成员|单位)方?[12345一二三四五]?)|((联合体?)?成员单位[12345一二三四五]?)|(特殊普通合伙|成员?)|^(成[),]$', s[e2:e2+10]) and behind_entity.label in [2, 5]:
- join_l.append(behind_entity.entity_text)
- b = b2
- e = e2
- find_joint = 1
- elif (find_joint or re.search('[与和][^,。]{6,100}联合体', list_articles[0].content)) and behind_entity.entity_type in ['org', 'company'] and s[e:b2] in ['与', '和',';','、','&',',','/','//'] and (len(s)==e2 or s[e2] in [';','、','&',',','/','//', '。', ')', '】'] or s[e2:e2+3]=='联合体'):
- join_l.append(behind_entity.entity_text)
- b = b2
- e = e2
- elif e == e2: # 修复重复实体导致中断情况
- continue
- else:
- break
- if len(join_l)>1:
- d['win_tenderer_joint'] = ','.join(set(join_l))
- # behind_entity = list_entity[i + 1]
- # if _entity.sentence_index== behind_entity.sentence_index and _entity.entity_type in ['org', 'company'] and _entity.label==2\
- # and _entity.entity_text==winner and behind_entity.entity_type in ['org', 'company'] and behind_entity.label==5:
- # s = sentences[_entity.sentence_index].sentence_text
- # b = _entity.wordOffset_begin
- # e = _entity.wordOffset_end
- # b2 = behind_entity.wordOffset_begin
- # e2 = behind_entity.wordOffset_end
- # if re.search('(联合体)', s[e2:e2+6]) and b2-e<3:
- # print('联合体:', s[max(0, b-10):e2+10])
- # d['win_tenderer_joint'] = '%s,%s'%(_entity.entity_text, behind_entity.entity_text)
- # break
- # elif re.search('(联合体((牵头|主办)(人|方|单位)|主体)|牵头(人|方|单位))|(联合体)?成员:|特殊普通合伙:', s[e:b2]) and b2-e<10:
- # d['win_tenderer_joint'] = '%s,%s' % (_entity.entity_text, behind_entity.entity_text)
- # print('联合体:', s[max(0, b - 10):e2 + 10])
- # break
- except Exception as e:
- print('获取联合体抛出异常', e)
- def get_multi_winner_and_money(channel_dic, prem, list_entitys,list_sentences, all_winner=False):
- '''
- 获取多中标人及正文、附件所有金额,多中标人multi_winner写入prem,返回金额列表
- :param channel_dic:
- :param prem:
- :param list_entitys:
- :param list_sentences:
- :return:
- '''
- def add_multi_winner(pack_l, winner_l):
- if len(prem[0]['prem']) > 1 and len(set([it[0] for it in pack_l])) > 1: # 多标段多中标人处理
- pk_dic = {}
- for ent in winner_l:
- for i in range(len(pack_l)):
- pk, s1, b1, _ = pack_l[i]
- if ent[1] < s1 or ent[1] == s1 and ent[2] < b1:
- break
- elif (ent[1] > s1 or ent[1] == s1 and ent[2] > b1):
- if i < len(pack_l) - 1:
- pk2, s2, b2, _ = pack_l[i + 1]
- if (ent[1] < s2 or ent[1] == s2 and ent[2] < b2):
- if pk not in pk_dic:
- pk_dic[pk] = set()
- pk_dic[pk].add(ent[0])
- else:
- continue
- else:
- if pk not in pk_dic:
- pk_dic[pk] = set()
- pk_dic[pk].add(ent[0])
- else:
- continue
- for pk, multi_winner in pk_dic.items():
- multi_winner = multi_winner - tenderee_or_agency
- if len(multi_winner) < 2:
- continue
- for k, v in prem[0]['prem'].items():
- if pk == k:
- for d in v['roleList']:
- if d.get('role_name', '') == 'win_tenderer':
- if d.get('role_text', '') in multi_winner and 'multi_winner' not in d:
- d['multi_winner'] = ','.join(set(multi_winner))
- elif 0 < len(prem[0]['prem']) < 3: # 修复 单包多中标人 例:285780273
- multi_winner = set([it[0] for it in winner_l]) - tenderee_or_agency
- if len(multi_winner) > 1:
- for v in prem[0]['prem'].values():
- for d in v['roleList']:
- if d.get('role_name', '') == 'win_tenderer':
- if d.get('role_text', '') in multi_winner and 'multi_winner' not in d:
- d['multi_winner'] = ','.join(set(multi_winner))
- break
- moneys = []
- moneys_attachment = []
- if channel_dic['docchannel']['life_docchannel'] in ['中标信息','候选人公示','合同公告'] and 'win_tenderer' in str(prem):
- sentences = sorted(list_sentences[0], key=lambda x: x.sentence_index)
- finalists = [] # 入围供应商
- multi_winner_l = [] # 保存中标人名称列表
- tenderee_or_agency = set()
- package_l = []
- i = 0
- while i < len(list_entitys[0])-1:
- ent = list_entitys[0][i]
- b_idx_fr = ent.wordOffset_begin
- e_idx_fr = ent.wordOffset_end
- i += 1
- if ent.entity_type in ['money']:
- money = float(ent.entity_text)
- if ent.in_attachment:
- moneys_attachment.append(money)
- else:
- moneys.append(money)
- elif ent.entity_type in ['package']:
- package_l.append((ent.entity_text, ent.sentence_index, ent.wordOffset_begin, ent.in_attachment))
- elif ent.entity_type in ['org', 'company']:
- sentence_text = sentences[ent.sentence_index].sentence_text
- pre_text = sentence_text[max(0, b_idx_fr - 10):b_idx_fr]
- if ent.label in [0,1] and ent.values[ent.label] > 0.8:
- tenderee_or_agency.add(ent.entity_text)
- elif ent.label == 2 and (ent.values[ent.label] > 0.8 or all_winner):
- multi_winner_l.append((ent.entity_text, ent.sentence_index, ent.wordOffset_begin, ent.in_attachment))
- for j in range(i, len(list_entitys[0])):
- ent_bh = list_entitys[0][j]
- b_idx_bh = ent_bh.wordOffset_begin
- e_idx_bh = ent_bh.wordOffset_end
- if ent_bh.entity_type in ['org','company'] and ent_bh.label in [2,5] and ent_bh.sentence_index == ent.sentence_index and b_idx_bh - e_idx_fr in [1, 2]:
- if sentence_text[e_idx_fr:b_idx_bh] in [';', '、', '&', ',', '/', '//'] and (
- len(sentence_text) == e_idx_bh or sentence_text[e_idx_bh] in [';', '、', '&', ',','/', '//','。']): # 修复多中标人刚好在文末index超出报错,例子 407126558
- multi_winner_l.append((ent_bh.entity_text, ent_bh.sentence_index, ent_bh.wordOffset_begin, ent_bh.in_attachment))
- e_idx_fr = e_idx_bh
- i = j + 1
- else:
- break
- elif ent_bh.entity_type in ['org', 'company'] and ent_bh.label == 5 and ent_bh.sentence_index == ent.sentence_index and b_idx_bh == e_idx_fr: # 两实体间没符号分割情况
- multi_winner_l.append((ent_bh.entity_text, ent_bh.sentence_index, ent_bh.wordOffset_begin, ent_bh.in_attachment))
- e_idx_fr = e_idx_bh
- i = j + 1
- elif ent_bh.entity_type in ['org', 'company'] and ent_bh.label == 5 and e_idx_fr == e_idx_bh: # 处理 514603520 中国邮政储蓄银行股份有限公司淄博市临淄区支行 实体由于字典匹配重复两次情况
- i = j + 1
- else:
- break
- if re.search('入围', pre_text) and re.search('未入围', pre_text)==None:
- finalists.append((ent.entity_text, ent.sentence_index, ent.wordOffset_begin, ent.in_attachment))
- elif all_winner==1 and ent.label in [3,4,5] and re.search('第[一二三四五六七八九十0-9]+名|候选(人|单位)|入围(单位|供应商)|投标银行', pre_text) and re.search('未', pre_text)==None:
- multi_winner_l.append((ent.entity_text, ent.sentence_index, ent.wordOffset_begin, ent.in_attachment))
- if len(multi_winner_l)>=2:
- winner_main = [it for it in multi_winner_l if not it[3]]
- winner_attn = [it for it in multi_winner_l if it[3]]
- pack_main = [it for it in package_l if not it[3]]
- pack_attn = [it for it in package_l if it[3]]
- if len(set([it[0] for it in winner_main]))>=2: # 有两个及以上多中标人及多标段 例:441612746
- add_multi_winner(pack_main, winner_main)
- elif len(set([it[0] for it in winner_attn]))>=2:
- add_multi_winner(pack_attn, winner_attn)
- if len(finalists)>=2: # 多入围候选人
- winner_main = [it for it in finalists if not it[3]]
- winner_attn = [it for it in finalists if it[3]]
- pack_main = [it for it in package_l if not it[3]]
- pack_attn = [it for it in package_l if it[3]]
- if len(set([it[0] for it in winner_main]))>=2: # 有两个及以上多中标人及多标段 例:276326152
- add_multi_winner(pack_main, winner_main)
- elif len(set([it[0] for it in winner_attn]))>=2:
- add_multi_winner(pack_attn, winner_attn)
- else:
- for i in range(len(list_entitys[0])):
- ent = list_entitys[0][i]
- if ent.entity_type in ['money']:
- money = float(ent.entity_text)
- if ent.in_attachment:
- moneys_attachment.append(money)
- else:
- moneys.append(money)
- return {'moneys': list(set(moneys)), 'moneys_attachment': list(set(moneys_attachment))}
|