# -*- 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))}