# -*- coding: utf-8 -*- """ Phase 6 migration from interface/getAttributes.py. This module groups the post-processing helpers that refine the assembled ``prem`` structure (package-role-money) after the initial extraction: correcting role money against table totals, limiting amounts by industry thresholds, merging table-extracted prem into the existing one, rule-based role supplementation, conflict confirmation, package naming, single-source fixups, demand-driven prem expansion and candidate manager enrichment. Migrated functions: getPREMs, correct_rolemoney, limit_maximum_amount, update_prem, rule_add_role, confirm_prem, add_package_name, fix_single_source, demand_to_prem, add_manager """ from __future__ import absolute_import import re import copy import json import uuid from decimal import Decimal from BiddingKG.dl.common.Utils import log, money_process, get_money_entity, getCurrent_date def getPREMs(list_sentences,list_entitys,list_articles,list_outlines,page_time,winter_scope): ''' @param: list_sentence:所有文章的句子list list_entity:所有文章的实体list @return:list of dict which include文章的包-角色-实体名称-金额-联系人-联系电话 ''' from BiddingKG.dl.assembly.role_money import getPackageRoleMoney from BiddingKG.dl.assembly.time_attrs import getTimeAttributes from BiddingKG.dl.assembly.contacts import getProjectContacts result = [] for list_sentence,list_entity,list_article,list_outline in zip(list_sentences,list_entitys,list_articles,list_outlines): RoleList = getPackageRoleMoney(list_sentence,list_entity,list_outline,winter_scope) result.append(dict({"prem": RoleList, "docid": list_article.doc_id}, **getTimeAttributes(list_entity, list_sentence,page_time), **getProjectContacts(list_entity, list_sentence), **{"fingerprint": list_article.fingerprint, "match_enterprise": list_article.match_enterprise, "match_enterprise_type": list_article.match_enterprise_type, "process_time": getCurrent_date(), "attachmentTypes": list_article.attachmentTypes, "bidway": list_article.bidway})) # result.append(dict({"prem":RoleList,"docid":list_article.doc_id},**getOtherAttributes(list_entity),**getTimeAttributes(list_entity,list_sentence), # **{"fingerprint":list_article.fingerprint,"match_enterprise":list_article.match_enterprise, # "match_enterprise_type":list_article.match_enterprise_type,"process_time":getCurrent_date(), # "attachmentTypes":list_article.attachmentTypes, "bidway": list_article.bidway})) return result def correct_rolemoney(docid, prem, total_product_money, total_budget, list_articles): # 2022/9/26修改为 中标金额小于表格单价数量合计总金额十分之一时替换 ''' 最后根据表格提取的单价数量合计对比更新中标金额,或中标金额为0全文只有一个总价或合计时,作为中标金额 :param docid: 公告编号 :param prem: 列表 :param total_product_money: 表格统计金额 :param total_budget: 表格合计预算金额 :param list_articles: 文章对象 :return: ''' if '##attachment##' in list_articles[0].content: content, attachment = list_articles[0].content.split('##attachment##') if len(content) < 200: content += attachment else: content = list_articles[0].content if len(re.findall('win_tenderer|second_tenderer|third_tenderer', str(prem[0]['prem'])))==1:# and re.search('(中标|成交|合同|投标))?(总?金额|[报总]?价)((万?元))?:', content) == None: # 只有一个中标角色且没有明确中标金额表达的 if total_product_money>0 and total_product_money<2000000: for value in prem[0]['prem'].values(): ree_money = float(value['tendereeMoney']) for l in value['roleList']: try: # if l[0] == 'win_tenderer' and float(l[2])合计((万?元))?:)(?P[\d,.]+(万?元)?)', content) if len(re.findall('合计', content)) == 1 else re.search('(?P
总价((万?元))?:)(?P[\d,.]+(万?元)?)', content) if ser: money_text = ser.group('money') header = ser.group('header') money, money_unit = money_process(money_text, header) if 100 10000000000: # 工期小于180天且金额大于百亿的,错误 l["role_money"]['money'] = str(Decimal(l["role_money"]['money']) / 10000) # print('工期纠正百亿以上金额 ') elif float(l["role_money"]['money']) > maximum_amount: flag = 1 for money in moneys: if float(l["role_money"]['money'])/money == 10000 and l['role_money']['money_unit'] == '万元': l["role_money"]['money'] = str(Decimal(l["role_money"]['money']) / 10000) # print('万倍关系纠正连接金额') flag = 0 break if flag and l["role_money"]['money_unit'] == '万元' or re.search('^\d{11,}(\.0)?$', str(l["role_money"]['money'])): l["role_money"]['money'] = str(Decimal(l["role_money"]['money']) / 10000) # print('行业限额纠正连接金额') elif industry in ['餐饮业', '物业管理'] and maximum_amount == indu_amount[industry]: l["role_money"]['money'] = str(Decimal(l["role_money"]['money']) / 10000) # elif flag and l["role_money"]['money_unit'] == '元': # l["role_money"]['money'] = 0 elif 0 maximum_amount: flag = 1 for money in moneys: if float(value['tendereeMoney'])/money == 10000 and l['role_money']['money_unit'] == '万元': value['tendereeMoney'] = str(Decimal(value['tendereeMoney'])/10000) # print('万倍关系纠正连接金额') flag = 0 break if (flag and value['tendereeMoneyUnit'] == '万元' or re.search('^\d{11,}(\.0)?$', str(value['tendereeMoney']))) and float(value['tendereeMoney']) > maximum_amount*100: #2024/5/23 改为单位万元且超过限额100倍才除一万,避免不合理纠正 比如 174255856 项目(系统)一亿变一万 value['tendereeMoney'] = str(Decimal(value['tendereeMoney']) / 10000) # print('行业限额纠正连接金额') elif industry in ['餐饮业', '物业管理'] and maximum_amount == indu_amount[industry]: value['tendereeMoney'] = str(Decimal(value['tendereeMoney']) / 10000) # elif flag and value['tendereeMoneyUnit'] == '元': # value['tendereeMoney'] = 0 elif 0= 1 : '''如果表格提取的包大于2,原来的包比表格提取的包多则删除原来多余的包,以表格的为准 20250528补充条件表格提取需有中标人避免 626464296 替换错误''' if len(new_prem) >= 2 and 'win_tenderer' in json.dumps(new_prem) and (len(new_prem) len(new_prem) and len(new_prem)>=1 and in_attachment==False: # 如果表格有提取,非表格包数比表格提取多,去掉非表格在附件里提取的包 del_k = [] for k in old_prem: if 'in_attachment' in old_prem[k] and old_prem[k]['in_attachment'] and k not in new_prem and k != 'Project': del_k.append(k) for k in del_k: old_prem.pop(k) if in_attachment and len(new_prem) < len(old_prem)*2: # 附件表格提取的,原来提取有中标人,停止替换 for v in old_prem.values(): for d in v['roleList']: if d['role_name'] in ['win_tenderer', 'pre_win_tenderer']: return 0 # if len(new_prem) > len(old_prem) and [k for k in new_prem if '自增' not in k] == []: # 如果表格提取包号都为自增编号且包数大于非表格提取,不进行更新 例 244355092 281854766 # return None if len(old_prem) >= 2 and len(new_prem) == 1 and ('Project' in new_prem or set(new_prem)&set(old_prem)==set()): # 如果表格提取包为Project,非表格提取两个包且一个包为Project,把表格提取合并到非Project包 # k = list(old_prem.keys()-set(['Project']))[0] k = sorted((old_prem.keys()-set(['Project'])), key=lambda x: x)[0] k_new = list(new_prem.keys())[0] new_prem[k] = new_prem.pop(k_new) elif len(old_prem) == 1 and len(new_prem) == 1 and 'Project' not in old_prem and set(new_prem)&set(old_prem)==set(): # 如果表格提取包与非表格提取都是一个包且不同,把表格提取包名替换为非表格包名 k = list(old_prem.keys()-set(['Project']))[0] k_new = list(new_prem.keys())[0] new_prem[k] = new_prem.pop(k_new) if len(new_prem) == len(old_prem) == 1 and 'Project' not in new_prem and 'Project' in old_prem: # 如果表格提取到包号,非表格没提取到,合并到Project k = list(new_prem.keys())[0] new_prem['Project'] = new_prem.pop(k) multi_tendereeMoney = [] # 多包招标金额 for k, v in new_prem.items(): if k == 'Project': if 'Project' in old_prem: tmp_l = [] # 保存新旧同时包含的角色 if v.get('code', "") != "": old_prem['Project']['code'] = v.get('code', "") if v.get('name', "") != "": old_prem['Project']['name'] = v.get('name', "") for d in old_prem['Project']['roleList']: for d2 in v['roleList']: if d['role_name'] == d2['role_name']: # 同时包含的角色用表格的替换 tmp_l.append(d2) if d2['role_text'] != "": d['role_text'] = d2['role_text'] if d2.get('serviceTime', '') != "": d['serviceTime'] = d2['serviceTime'] if float(d2['role_money']['money']) != 0: # 如果表格提取的金额不为0才替换 d['role_money']['money'] = d2['role_money']['money'] d['role_money']['money_unit'] = d2['role_money']['money_unit'] for k in set(d2)-set(d): # 把表格提取加的属性补充过来,比如:multi_winner other_winner_dic等 if d2[k]: d[k] = d2[k] for d2 in v['roleList']: if d2 not in tmp_l: # 把新预测有,旧没有的角色添加上去 old_prem['Project']['roleList'].append(d2) if float(old_prem['Project'].get('tendereeMoney', 0)) < float(new_prem['Project'].get('tendereeMoney', 0)) < 100000000: old_prem['Project']['tendereeMoney'] = new_prem['Project']['tendereeMoney'] # 20240508 修复 464187225 表格提取纠正招标金额错误 else: old_prem[k] = v else: if v['tendereeMoney'] != 0: multi_tendereeMoney.append(v['tendereeMoney']) if k.startswith('自增'): # 表格提取的没找到包号 按行数添加包号,前面加自增,例 自增1 k = k[2:] if k not in old_prem: # 新有旧没有的包直接添加 old_prem[k] = v else: tmp_l = [] # 保存新旧同时包含的角色 if v.get('code', "") != "": old_prem[k]['code'] = v.get('code', "") if v.get('name', "") != "": old_prem[k]['name'] = v.get('name', "") for d in old_prem[k]['roleList']: for d2 in v['roleList']: if d['role_name'] == d2['role_name']: tmp_l.append(d2) if d2['role_text'] != "": d['role_text'] = d2['role_text'] if d2.get('serviceTime', '') != "": d['serviceTime'] = d2['serviceTime'] if float(d2['role_money']['money']) != 0: # 如果表格提取的金额不为0才替换 d['role_money']['money'] = d2['role_money']['money'] d['role_money']['money_unit'] = d2['role_money']['money_unit'] for k2 in set(d2)-set(d): # 把表格提取加的属性补充过来,比如:multi_winner other_winner_dic等 if d2[k2]: d[k2] = d2[k2] for d2 in v['roleList']: if d2 not in tmp_l: # 把新预测有,旧没有的角色添加上去 old_prem[k]['roleList'].append(d2) if float(old_prem[k].get('tendereeMoney', 0)) < float(v.get('tendereeMoney', 0)) < 100000000: old_prem[k]['tendereeMoney'] = v['tendereeMoney'] # 2024/05/24 使用表格招标金额 if multi_tendereeMoney and 'Project' in old_prem and float(old_prem['Project']['tendereeMoney'])!=0: # 表格提取到多标段招标金额,去掉Project包招标金额 old_prem['Project']['tendereeMoney'] = 0 tenderee_l = [d2['role_text'] for v in old_prem.values() for d2 in v['roleList'] if d2['role_name']=='tenderee'] winner_l = [d2['role_text'] for v in old_prem.values() for d2 in v['roleList'] if d2['role_name']=='win_tenderer'] if set(tenderee_l) & set(winner_l): # 删除与中标人冲突的招标人 for k in old_prem: old_prem[k]['roleList'] = [d for d in old_prem[k]['roleList'] if not(d['role_name'] == 'tenderee' and d['role_text'] in winner_l)] # print('删除与中标人冲突的招标人') # return old_prem def rule_add_role(docid, prem, channel, content, web_source_no, nlp_enterprise): def add_role(ent_name, role_type, prem, money=0): if 'Project' in prem: prem['Project']['roleList'].append( { "address": "", "linklist": [], "role_money": { "discount_ratio": "", "downward_floating_ratio": "", "floating_ratio": "", "money": money, "money_unit": "" }, "role_name": role_type, "role_prob": 0.6, "role_text": ent_name, "rule_add_role": True, "serviceTime": "" } ) else: prem['Project'] = { "code": "", "name": "", "roleList": [ { "address": "", "linklist": [ ], "role_money": { "discount_ratio": "", "downward_floating_ratio": "", "floating_ratio": "", "money": money, "money_unit": "" }, "role_name": role_type, "role_prob": 0.6, "role_text": ent_name, "rule_add_role": True, "serviceTime": "" } ], "tendereeMoney": 0, "tendereeMoneyUnit": "", "uuid": str(uuid.uuid4()) } if channel['docchannel']['docchannel'] in ['招标公告', '中标信息'] and re.search('"role_name": "tenderee"',json.dumps(prem)) == None: match = re.search('(招标|采购|招商)(人|方|商|单位|部门)(信息[,:]?)?(名称)?((甲方))?:(?P[\w()—-]{4,35})([,。]|$)', content) match2 = re.search('(招标|采购|招商)(人|方|商|单位|部门)(信息[,:]?)?(名称)?((甲方))?:(?P[\w()—-、]{25,55}(局|人民政府|委员会|执法队))?)([,。]|$)', content) if match: ent_name = match.group('name') if re.search('测试|演示|某|\d号|\*|XX', ent_name)==None and re.search('^(\w{1,5}[省市县区]|乌鲁木齐)[\w()]{2,25}([厂店铺市场行部城室馆中心站处社会狱所园关局司署段厅院队小学村]|社区)((个体工商户)?|(普通合伙)?)?$', ent_name): # or is_enterprise_exist(ent_name) log('规则补充招标人角色:%s,docid:%s'%(ent_name, docid)) add_role(ent_name, "tenderee", prem) elif match2: ent_name = match2.group('name') log('规则补充招标人角色:%s,docid:%s' % (ent_name, docid)) add_role(ent_name, "tenderee", prem) elif web_source_no == 'DX000752' and len(nlp_enterprise)==1 and re.search('更多信息点击报价地址', content): # 修复 628311260 ent_name = nlp_enterprise[0] add_role(ent_name, "tenderee", prem) if channel['docchannel']['docchannel'] == '中标信息' and re.search('"role_name": "win_tenderer"',json.dumps(prem)) == None: match = re.search('((中标|中选|成交))?(人|方|供应商|服务商|单位|部门|企业)|(拟定|[,。])供应商)(信息[,:]?)?(名称)?((乙方))?:(?P[\w()—-]{4,35})([,。]|$)',content) if match: ent_name = match.group('name') if re.search('测试|演示|某|\d号|\*|XX', ent_name)==None and re.search('^(\w{1,5}[省市县区]|乌鲁木齐)[\w()]{2,25}[厂店铺市场行部城室馆中心站处社会狱所园关局署段厅院队小学]((个体工商户)?|(普通合伙)?)?$', ent_name): # or is_enterprise_exist(ent_name) b_idx = match.end() idx_ = content[b_idx:].find('。') e_idx = idx_ if idx_ > 0 else 200 text = content[b_idx:b_idx+e_idx] money_list, _ = get_money_entity(text) money = 0 for money_tup in money_list: entity_text, b, e, unit, notes = money_tup if re.search('(中标|成交|中选|投标|合同)总?(价格?|金额)', text[max(0, b-10):b]): money = float(entity_text) break log('规则补充中标人角色:%s, 金额:%s,docid:%s'%(ent_name, money, docid)) add_role(ent_name, "win_tenderer", prem, money) def confirm_prem(docid, prem, channel_dic, content, is_deposit_project=False, total_tendereeMoney=0, all_tenderer=set()): ''' 规则检查纠正prem,如果Project包中标人在其他包中标人,去掉project包中标角色;如果有其他包中标人,去掉roleList为空的包; :param prem: prem 字段字典 :return: ''' if len(prem) > 1: # 表格提取到中标人的,去掉project包中标人 pro_winner = set() other_winner = set() other_winner_prob = 0 pro_winner_prob = 0 empty_roleList = [] for k in prem: prem[k]['uuid'] = str(uuid.uuid4()) # 20240627 每个包都添加uuid if prem[k]['roleList'] == []: empty_roleList.append(k) for d in prem[k]['roleList']: if d['role_name'] in ['win_tenderer', 'pre_win_tenderer', 'second_tenderer','third_tenderer']: if k == 'Project': pro_winner.add(d['role_text']) if 'win_tenderer_joint' in d: pro_winner.update(set(d['win_tenderer_joint'].split(','))) if 'multi_winner' in d: pro_winner.update(set(d['multi_winner'].split(','))) if d['role_name'] == 'win_tenderer' and d.get('role_prob', 0)>0.6: pro_winner_prob = d.get('role_prob', 0) else: other_winner.add(d['role_text']) if 'win_tenderer_joint' in d: other_winner.update(set(d['win_tenderer_joint'].split(','))) if 'multi_winner' in d: other_winner.update(set(d['multi_winner'].split(','))) if d['role_name'] == 'win_tenderer' and d.get('role_prob', 0)>0.6: other_winner_prob = d.get('role_prob', 0) if pro_winner!=set() and (pro_winner & other_winner != set() or other_winner_prob>pro_winner_prob): # 如果默认包与其他包中标人重复或其他包中标人概率比默认包大,删除默认包中标人 prem['Project']['roleList'] = [d for d in prem['Project']['roleList'] if d['role_name'] not in ['win_tenderer', 'second_tenderer', 'third_tenderer']] elif other_winner_prob 10: log('prem包数量大于10,当前包数量:%d, docid:%s'%(len(prem), docid)) # 验证中标人招标人是否冲突 tenderee = "" tenderee_prob = 0.5 win_channel = True if channel_dic['docchannel']['docchannel'] in ['中标信息', '候选人公示', '合同公告'] else False win_tenderer_set = set() tenderee_or_agency = set() agency = '' for k, v in prem.items(): win_money = 0 for d in v.get('roleList', []): if d.get('role_name', '') == 'tenderee' and k == 'Project': tenderee = d['role_text'] tenderee_prob = d.get('role_prob', 0.5) elif d.get('role_name', '') == 'agency' and k == 'Project': agency = d['role_text'] elif d.get('role_name', '') in ['win_tenderer', 'pre_win_tenderer', 'second_tenderer', 'third_tenderer']: win_tenderer_set.add(d['role_text']) if d.get('role_name', '') in ['win_tenderer', 'pre_win_tenderer'] and float(d.get('role_money', {}).get('money', 0)): win_money = float(d.get('role_money', {}).get('money', 0)) if d.get('role_name') in ['tenderee', 'agency']: tenderee_or_agency.add(d['role_text']) elif d.get('role_name') in ['win_tenderer', 'pre_win_tenderer', 'second_tenderer', 'third_tenderer']: if d['role_text'] not in all_tenderer: all_tenderer.add(d['role_text']) if 'multi_winner' in d: for item in d['multi_winner'].split(','): if item not in all_tenderer: all_tenderer.add(item) if 'win_tenderer_joint' in d: for item in d['win_tenderer_joint'].split(','): if item not in all_tenderer: all_tenderer.add(item) # 招标金额小于中标金额的, 去掉招标金额 if win_money and 0 < float(v.get('tendereeMoney', 0))*1.1 < win_money: log('招标金额比中标金额小,去除招标金额:%d, %d ,docid:%s'%(float(v.get('tendereeMoney', 0)), win_money, docid)) v['tendereeMoney'] = 0 # 招标单位和代理机构在同一个公告里是一致的,就只保留招标单位 if tenderee and tenderee == agency: prem['Project']['roleList'] = [it for it in prem['Project']['roleList'] if it.get('role_name', '') != 'agency'] if tenderee != '' and len(win_tenderer_set) > 0 and (tenderee in ' '.join(win_tenderer_set) or [it for it in win_tenderer_set if it in tenderee]): conflict_short = [it for it in win_tenderer_set if it in tenderee] # 名称重叠冲突角色 conflict_long = [it for it in win_tenderer_set if tenderee in it] # 名称重叠冲突角色 解决 751037129 采购人:贵州盘江精煤股份有限公司,承办单位:贵州盘江精煤股份有限公司物资管理分公司, remove_packages = [] # 待删除空包 for k, v in prem.items(): if v.get('roleList', []): if tenderee_prob >= 0.8 or not win_channel: v['roleList'] = [it for it in v['roleList'] if it.get('role_text', '') not in conflict_short + conflict_long] log('去掉冲突角色的中标角色, 中标人:%s, 招标人:%s, docid:%s'%(' '.join(conflict_short + conflict_long), tenderee, docid)) elif conflict_short: v['roleList'] = [it for it in v['roleList'] if it.get('role_text', '') not in conflict_short] log('去掉冲突角色的中标角色, 中标人:%s, 招标人:%s, docid:%s' % (' '.join(conflict_short), tenderee, docid)) elif conflict_long: v['roleList'] = [it for it in v['roleList'] if it.get('role_name', '')!='tenderee'] log('去掉冲突角色的招标角色, 中标人:%s, 招标人:%s, docid:%s' % (' '.join(conflict_long), tenderee, docid)) else: v['roleList'] = [it for it in v['roleList'] if it.get('role_text', '') not in conflict_short + conflict_long and it.get('role_name', '')!='tenderee'] log('去掉冲突角色的招标中标角色, 中标人:%s, 招标人:%s, docid:%s' % ( ' '.join(conflict_short + conflict_long), tenderee, docid)) # if re.search('政府|医院|学院|学校|中学|小学|大学|中心|幼儿园|保健院|党校|研究院|血站|分校|银行|红十字会|防治院|研究所', tenderee): # v['roleList'] = [it for it in v['roleList'] if it.get('role_name', '')=='tenderee' and it.get('role_prob', 1) > 0.6 or ( # it.get('role_name', '')!='tenderee' and tenderee not in it.get('role_text', '') and it.get('role_text', '') not in tenderee)] # log('去掉招标中标冲突的中标角色,招标人:%s, docid:%s'%(tenderee, docid)) # else: # v['roleList'] = [it for it in v['roleList'] if it.get('role_name', '') != 'tenderee' or ( # it.get('role_name', '') == 'tenderee' and tenderee not in it.get('role_text', '') and it.get('role_text', '') not in tenderee)] # log('去掉招标中标冲突的招标角色,招标人:%s, docid:%s' % (tenderee, docid)) if not v.get('roleList', []) and not v.get("tendereeMoney", 0) and not v.get('unit_tendereeMoney', 0): remove_packages.append(k) for k in remove_packages: prem.pop(k) return {'candidate': ','.join(all_tenderer-tenderee_or_agency)} def add_package_name(prem, list_entity, product_list, name): ''' 通过产品、项目名称,补充各标段包名,如果标段无包名,标段后紧接产品,把产品作为包名;如果标段数少于等于2且包名为空,补充项目名称为包名 :param prem: :param list_entity: :param product_list: :param name: :return: ''' if len(prem)>2 and len(product_list)>2: ent_l = [] for entity in list_entity: if entity.entity_type in ['product', 'package']: ent_l.append((entity.entity_type, entity.entity_text, entity.sentence_index, entity.wordOffset_begin, entity.wordOffset_end, entity.in_attachment)) ent_l.sort(key=lambda x: [x[2],x[3]]) i = 0 pk_dic = {} while i < len(ent_l)-1: ty1, ent1, s1, b1, e1, in_att1 = ent_l[i] ty2, ent2, s2, b2, e2, in_att2 = ent_l[i+1] if in_att1 == in_att2 and ty1 == 'package' and ty2 == 'product' and s1 == s2 and 0 1: for k, v in prem.items(): if k in pk_dic and v.get('name', '') == '': v['name'] = pk_dic[k] elif name != '' and len(prem)<=2: # 20241129 小于等于两个包且无包名称,取项目名称 for k in prem: if prem[k].get('name', '') == '': prem[k]['name'] = name def fix_single_source(prem, channel_dic, original_docchannel): if prem.get('bidway', '') == '单一来源' and channel_dic['docchannel']['docchannel'] == '招标公告' and original_docchannel==52: for l in prem['prem'].values(): for d in l['roleList']: if d['role_name'] == "win_tenderer": d['role_name'] = 'pre_win_tenderer' def demand_to_prem(demand, prem): if len(demand.get('data', [])) > len(prem): i = 1 for d in demand.get('data', []): d['demand_id'] = i if d.get('project_name', '') != '' and d.get('budget', '') != '': if d.get('project_name', '') not in prem: prem[d.get('project_name', '')] = { 'demand_id': i, 'code': '', 'name': d.get('project_name', ''), 'roleList': [], 'tendereeMoney': d.get('budget', ''), 'tendereeMoneyUnit': "" } else: prem[d.get('project_name', '')+'_%d'%i] = { 'demand_id': i, 'code': '', 'name': d.get('project_name', ''), 'roleList': [], 'tendereeMoney': d.get('budget', ''), 'tendereeMoneyUnit': "" } i += 1 def add_manager(docid, prem, list_entitys, list_sentences): ''' 补充候选人的 项目负责人、经理 :param prem: :param list_entitys: :param list_sentences: :return: ''' if 'win_tenderer' in str(prem): # 有中标人才做下面操作 managers = set() # 项目经理,项目负责人 roles = set() # 候选人 ent_list = [] # 实体列表 role_person_dic = {} for entity in list_entitys[0]: if entity.entity_type == 'person': b = entity.wordOffset_begin s_index = entity.sentence_index sentance_text = list_sentences[0][s_index].sentence_text if re.search('(项目负责人|项目总工)([:,]?姓名)?:$', sentance_text[max(0, b - 12):b]): managers.add(entity.entity_text) ent_list.append(('person', s_index, b, entity.entity_text, 'leader')) elif re.search('(项目经理)([:,]?姓名)?:$', sentance_text[max(0, b - 12):b]): managers.add(entity.entity_text) ent_list.append(('person', s_index, b, entity.entity_text, 'manager')) elif entity.entity_type in ['org', 'company']: b = entity.wordOffset_begin s_index = entity.sentence_index lb = entity.label if lb in [2, 3, 4]: roles.add(entity.entity_text) ent_list.append(('org', s_index, b, entity.entity_text, lb)) ent_list.sort(key = lambda x: [x[1], x[2]]) if len(roles) > 0 and len(managers) > 0: for i in range(len(ent_list)): ent = ent_list[i] if ent[0] == 'org': for j in range(i + 1, len(ent_list)): ent2 = ent_list[j] if ent2[0] == 'person' and 0 <= ent2[1] - ent[1] < 4: if ent[3] not in role_person_dic: role_person_dic[ent[3]] = [] role_person_dic[ent[3]].append(ent2) elif ent2[0] == 'org': break if role_person_dic: for v in prem.values(): for d in v['roleList']: if d['role_name'] in ['win_tenderer', 'pre_win_tenderer', 'second_tenderer', 'third_tenderer']: ent = "" if d['role_text'] in role_person_dic: ent = d['role_text'] elif'win_tenderer_joint' in d: for name in d['win_tenderer_joint'].split(','): if name in role_person_dic: ent = name if ent != "": for per in role_person_dic[ent]: if per[4] not in d: d[per[4]] = per[3] log('规则补充候选人项目经理:%s, docid:%s'%(per[3], docid)) __all__ = ["getPREMs", "correct_rolemoney", "limit_maximum_amount", "update_prem", "rule_add_role", "confirm_prem", "add_package_name", "fix_single_source", "demand_to_prem", "add_manager"]