# -*- coding: utf-8 -*- """角色规则预测器。 按 ARCHITECTURE.md Phase 5 拆分建议,从 ``interface/predictor.py`` 迁出以下 角色/规则相关类与函数: - ``RoleRulePredictor`` — 角色规则预测(原 predictor.py 第 1613-2176 行) - ``RoleRuleFinalAdd`` — 正则补充最后一句实体角色(原 2178-2277 行) - ``TendereeRuleRecall`` — 招标人角色召回规则(原 2279-2557 行) - ``RoleGrade`` — 角色概率分级(原 2559-2952 行) - ``role_special_predictor`` — 站源特殊角色召回(原 9185-9198 行) 角色分类流程优化 Phase E 起,前三个召回类改为薄委托 ``predictors/role_recall_engine.py::RoleRecallEngine``(规则外置 YAML + RoleContext 复用),类名与 ``predict`` 签名保持兼容。 ``interface/predictor.py`` 仍 re-export 以上全部名称,老 import 不受影响。 """ from __future__ import absolute_import import re import json import threading from BiddingKG.dl.common.logging import log from BiddingKG.dl.common.context_utils import spanWindow, get_context from BiddingKG.dl.predictors._common import is_agency __all__ = [ "RoleRulePredictor", "RoleRuleFinalAdd", "TendereeRuleRecall", "RoleGrade", "role_special_predictor", ] # ---------------------------------------------------------------------------- # Phase E:三个召回类统一委托 RoleRecallEngine # ---------------------------------------------------------------------------- # 原三个类各自内联正则、重复构建上下文的实现已合并到 # ``predictors/role_recall_engine.py``: # - 规则外置:dl/rules/patterns/role_context.yaml(三组角色模式 + 金额召回) # 与 role_fallback.yaml(final_* 文末兜底、recall_* 招标人 7 级上下文链); # - 上下文复用:Phase A RoleContext(extract.py 入口构建一次, # prem / roleRule / tendereeRuleRecall 共享,contexts=None 时引擎自建)。 # 此处保留旧类名与 predict 签名作为薄委托,保证 ``getPredictor`` 旧 key # (roleRule / roleRuleFinal / tendereeRuleRecall)与老 import 不变。 # ---------------------------------------------------------------------------- _ENGINE_LOCK = threading.Lock() _ENGINE = None def _get_recall_engine(): """模块级引擎单例(惰性创建,线程安全;模式经 RuleLoader 编译缓存)。""" global _ENGINE if _ENGINE is None: with _ENGINE_LOCK: if _ENGINE is None: from BiddingKG.dl.predictors.role_recall_engine import RoleRecallEngine _ENGINE = RoleRecallEngine() return _ENGINE class RoleRulePredictor(object): """角色/金额上下文召回(原实现已合并至 RoleRecallEngine.predict_role_rule)。 兼容保留的旧属性/方法:``SET_NOT_TENDERER``、``_check_input``、 ``ser_role``、``rule_predict``(ser_role/rule_predict 的 pattern_list 参数需传编译后的 Pattern,规则以 YAML 为准)。 """ def __init__(self): self._engine = _get_recall_engine() @property def SET_NOT_TENDERER(self): return self._engine.SET_NOT_TENDERER def _check_input(self, text, ignore=False): return self._engine._check_input(text, ignore) def ser_role(self, pattern_list, text, entity_text): return self._engine.ser_role(pattern_list, text, entity_text) def rule_predict(self, before, center, after, entity_text): return self._engine.rule_predict(before, center, after, entity_text) def predict(self, list_articles, list_sentences, list_entitys, list_codenames, channel_dic, title, on_value=0.5, all_winner=False, req_scope=[], deposit_project=False, contexts=None): """角色/金额上下文召回。 :param contexts: build_role_contexts 预计算上下文(extract.py 入口已构建, 与 prem 共享);缺省时引擎内部自建(老调用方行为不变)。 :return: all_tenderer 集合(所有召回的投标人实体文本) """ return self._engine.predict_role_rule( list_articles, list_sentences, list_entitys, list_codenames, channel_dic, title, on_value=on_value, all_winner=all_winner, req_scope=req_scope, deposit_project=deposit_project, contexts=contexts) '''正则补充最后一句实体日期格式为招标或代理 2021/12/30''' class RoleRuleFinalAdd(object): """文末/全文格式兜底召回(原实现已合并至 RoleRecallEngine.predict_final_add, 规则外置到 role_fallback.yaml final_*)。""" def __init__(self): self._engine = _get_recall_engine() def predict(self, list_articles, list_sentences, list_entitys, list_codenames): return self._engine.predict_final_add( list_articles, list_sentences, list_entitys, list_codenames) # 招标人角色召回规则 class TendereeRuleRecall(object): """招标人兜底召回(原实现已合并至 RoleRecallEngine.predict_recall, 规则外置到 role_fallback.yaml recall_*;原 entity_context_rule / subject_rule 对应引擎 _recall_entity_context / _recall_subject)。 兼容保留实例属性 ``get_tenderee``(最近一次 predict 是否召回招标人)。 """ def __init__(self): self._engine = _get_recall_engine() self.get_tenderee = False def predict(self, list_articles, list_sentences, list_entitys, list_codenames, contexts=None): """招标人兜底召回:7 级上下文链 + 公告主语规则。 :param contexts: build_role_contexts 预计算上下文(可选,缺省自建)。 """ self.get_tenderee = self._engine.predict_recall( list_articles, list_sentences, list_entitys, list_codenames, contexts=contexts) return self.get_tenderee class RoleGrade(): def __init__(self): self.tenderee_left_9 = "(?P(招标|采购|遴选|寻源|竞价|议价|比选|询比?价|比价|评选|谈判|邀标|邀请|洽谈|约谈|选取|抽取|抽选)(人|方|单位))" self.tenderee_center_8 = "(?P受.{5,20}委托)" self.tenderee_left_8 = "(?P(尊敬的供应商|项目法人|(需求|最终|发包|征集|甲|转让|出租|处置)(人|方|单位|组织|用户|业主|主体|部门|公司)))" self.tenderee_left_6 = "(?P(业主|建设|委托)(人|方|单位|组织|用户|业主|主体|部门|公司|企业)|业主|买方)" self.tenderee_left_5 = "(?P(发布)(人|方|单位|组织|用户|业主|主体|部门|公司|企业)|买方|发布机构|申报单位名称|委托人)" self.agency_left_9 = "(?P代理)" self.winTenderer_left_9 = "(?P(中标|中选|中价|成交|竞得)|第[1一](名|候选)|排[名序]:1|名次:1)" self.winTenderer_left_8 = "(?P(入选供应商|供货商|乙方|最[终后]选[择取]))" # 229435497 最后选择西平,县中原彩印有限公司,作为此项目中标供应商, self.winTenderer_left_6 = "(?P(入围|承[接建包修做制担租销]))" self.winTenderer_right_9 = "(?P^(为(中标|成交|中选)(人|单位|供应商|公司)|以\d+[\d.,]+万?元中标))" self.secondTenderer_left_9 = "(?P(第[二2](中标|中选|中价|成交)?候选(人|单位|供应商|公司)|第[二2](名|候选)|排[名序]:2|名次:2))" self.thirdTenderer_left_9 = "(?P(第[三3](中标|中选|中价|成交)?候选(人|单位|供应商|公司)|第[三3](名|候选)|排[名序]:3|名次:3))" self.pattern_list = [self.tenderee_left_9,self.tenderee_center_8, self.tenderee_left_8,self.tenderee_left_6,self.tenderee_left_5,self.agency_left_9, self.winTenderer_left_9,self.winTenderer_left_8, self.winTenderer_right_9, self.winTenderer_left_6, self.secondTenderer_left_9, self.thirdTenderer_left_9] # 概率要由高到低 274941849 self.ree_pattern = re.compile('^([((][一二三四五六七八九十\d]+[))]|[一二三四五六七八九十]+\s*[..、])凡?对本次(招标|采购|公告内容)提出询问,') self.win_pattern = re.compile( "^([((][一二三四五六七八九十\d]+[))]|[一二三四五六七八九十]+\s*[..、])[预拟]?((中标|中选|成交|(采购|招标|比选|比价|定标)结果)((成交))?(人|单位|供应商)?的?(基本|主要)?(信息|情况|概况|结果)(如下)?|[预拟]?(中标|中选|成交)((成交))?(人|供应商|单位)(名称)?(、地址)?([及和]\w{,2}(中标|投标)(价格|报价|金额))?(如下)?|中标公示单位|(采购|招标|比选|比价|定标)结果)[,:]?$") def _extract_outline_scope(self, outlines): """提取中标/招标大纲的范围""" bid_info = [] # 中标大纲范围 ree_info = [] # 招标大纲范围 for outline in outlines: text_, title_type, title_index, next_index, scope = outline if re.search(self.win_pattern, text_) and re.search('(未|没|是否)(中标|成交)|中标单位合同签订主体|业绩|提供', text_) == None: bid_info.append(scope) # log("提取的中标大纲:%s, docid:%s"%(text_, docid)) elif re.search(self.ree_pattern, text_): ree_info.append(scope) # log("提取的招标大纲:%s, docid:%s"%(text_, docid)) return bid_info, ree_info def _correct_low_prob_entities(self, agency_like_tenderee, org_tenderee, low_prob_agency, low_prob_tenderee, agency_l, low_prob_winner, all_tenderee_agency): """修正低概率实体的角色标签""" # 代理伪装招标人修正 for entity in agency_like_tenderee: if not is_agency(entity.entity_text) or entity.entity_text in org_tenderee: entity.label = 0 entity.values[entity.label] = 0.6 else: entity.values[entity.label] = 0.5 # 低概率代理→招标人(若在招标人列表) for entity in low_prob_agency: if entity.entity_text in org_tenderee: entity.label = 0 entity.values[entity.label] = 0.6 # 低概率招标人→代理(若在代理列表) for entity in low_prob_tenderee: if entity.entity_text in agency_l: entity.label = 1 entity.values[entity.label] = 0.6 # 低概率中标人→非角色(若在招标/代理列表) for entity in low_prob_winner: if entity.entity_text in all_tenderee_agency: entity.label = 5 def _correct_winner_tenderee_conflict(self, org_winner, org_tenderee): if org_winner != []: flag = 0 if org_tenderee != []: for ent in org_winner: if ent.entity_text in org_tenderee: # log('如果org中标人同时为招标人角色,降低中标概率:%s, %s' % (ent.entity_text, ent.label)) ent.values[2] = 0.6 flag = 1 # if flag == 0 and company_winner != []: # 2024/04/18 注释掉 避免提取不到 273351465 供应商(乙方:湖南省第二测绘院 # for ent in org_winner: # if ent.label == 2 and ent.values[2] > 0.6: # # log('如果同时包含org和company中标人,降低org中标人概率为0.6:%s, %s' % (ent.entity_text, ent.values[2])) # ent.values[2] = 0.6 def _supplement_outline_entities(self, bid_info_company, ree_info_company, have_winner, have_ree, span, docid, sentences ): if have_winner == False and bid_info_company: # 优化 638075055 二、推荐中标候选人信息,邯郸市婷元紧固件制造有限公司第一名, for entity in bid_info_company: text = sentences[entity.sentence_index].sentence_text b = entity.wordOffset_begin e = entity.wordOffset_end if re.search('(单位(名称)?|投标(单位|人)(名称)?|公司名称):$', text[max(0, b-span-2):b]) and entity.label == 5: entity.label = 2 entity.values[entity.label] = 0.55 log('大纲规则补充中标人:%s, docid:%s'%(entity.entity_text, docid)) elif entity.label == 0 and entity.values[entity.label]>0.5 and re.search('(采购|招标)(单位|人)', text[max(0, b-span-2):b])==None: entity.values[entity.label] = 0.5 log('中标大纲下招标人概率降低:%s, docid:%s'%(entity.entity_text, docid)) # elif len(bid_info_company) == 1 and entity.label != 2: # entity.label = 2 # entity.values[entity.label] = 0.55 # log('大纲规则补充中标人:%s, docid:%s' % (entity.entity_text, docid)) if have_ree == False and ree_info_company: # 优化 638075055 二、推荐中标候选人信息,邯郸市婷元紧固件制造有限公司第一名, for entity in ree_info_company: text = sentences[entity.sentence_index].sentence_text b = entity.wordOffset_begin e = entity.wordOffset_end if re.search('(单位名称|([^\w]|^)名称):$', text[max(0, b-span-2):b]) and entity.label == 5: entity.label = 0 entity.values[entity.label] = 0.55 log('大纲规则补充招标人:%s, docid:%s'%(entity.entity_text, docid)) break def _resolve_role_conflict(self, role_text_ent_dic,role_text_type_dic, docid): role_text_type_dic = {k: ' '.join(v) for k, v in role_text_type_dic.items() if len(v)>1 and '0' in v} if role_text_type_dic: log("同一个公司名称包含多个角色:%s, docid:%s"%(json.dumps(role_text_type_dic, ensure_ascii=False), docid)) for k in role_text_type_dic: # 冲突角色取概率最大的类别 if k in role_text_ent_dic: if max(role_text_ent_dic[k]['招标概率']) >= max(role_text_ent_dic[k]['中标概率']): log("角色冲突公司招标概率比中标概率大,去掉中标角色,公司名:%s, docid:%s" % (k, docid)) for entity in role_text_ent_dic[k]['实体列表']: if entity.label in [2,3,4] and entity.values[entity.label] >= 0.5: entity.values[entity.label] = 0.4 else: for entity in role_text_ent_dic[k]['实体列表']: if entity.label in [0] and entity.values[entity.label] >= 0.5: entity.values[entity.label] = 0.4 log("角色冲突公司中标概率比招标概率大,去掉招标角色,公司名:%s, docid:%s" % (k, docid)) def predict(self, list_sentences, list_entitys, docid, original_docchannel, title, span=15, min_prob=0.7, outlines=[]): ''' 根据规则给角色分配不同等级概率;分三级:0.9-1,0.8-0.9,0.7-0.8;附件0.7-0.8,0.6-0.7,0.5-0.6 修改概率小于0.6的且在大数据代理集合里面的招标人为代理人 :param list_articles: :param list_sentences: :param list_entitys: :param codeName: :return: ''' role_text_type_dic = {} role_text_ent_dic = {} # 提取大纲范围 bid_info, ree_info = self._extract_outline_scope(outlines) have_winner = False have_ree = False bid_info_company = [] ree_info_company = [] sentences = sorted(list_sentences[0], key=lambda x:x.sentence_index) role2id = {"tenderee": 0, "agency": 1, "winTenderer": 2, "secondTenderer": 3, "thirdTenderer": 4} org_winner = [] company_winner = [] org_tenderee = [] agency_l = [] agency_like_tenderee = [] # 类似招标人的代理人实体列表 low_prob_agency = [] low_prob_tenderee = [] low_prob_winner = [] all_tenderee_agency = [] is_bid_record = True if re.search('开标记录', title[-8:]) else False is_result_change = True if re.search('(结果|中标|成交)[^\w]?(变更|更正)', title[-8:]) else False # 第一步:遍历实体,基础概率调整与分类 for entity in list_entitys[0]: if entity.entity_type in ['org', 'company'] and entity.label == 1 and re.search('银行', entity.entity_text): # 20260528 银行不可能做代理 779393255 entity.values[entity.label] = 0.49 continue if entity.entity_type in ['org', 'company'] and entity.label in [0, 1, 2, 3, 4] and entity.values[entity.label]> min_prob: text = sentences[entity.sentence_index].sentence_text in_att = sentences[entity.sentence_index].in_attachment pre_prob = entity.values[entity.label] # 模型预测角色概率 b = entity.wordOffset_begin e = entity.wordOffset_end not_found = 1 if re.search('(乙方:甲方:|甲方((买方)?,|:)乙方((卖方)?)?:)$', text[max(0, b-span):b]): entity.label = 0 if entity.entity_type == 'org' else 5 # 修复 290777022 乙方:甲方: 重庆机场集团有限公司 错分为中标 entity.values[entity.label] = 0.55 continue elif re.search('(采购|招标)人(?或其?(采购|招标)?代理机构)?', text[max(0, b-span-2):b]): # 修复 275206588 招标人或其招标代理机构:(盖章) entity.label = 1 if is_agency(entity.entity_text) else 0 entity.values[entity.label] = 0.7 if entity.values[entity.label] > 0.7 else 0.6 if in_att: entity.values[entity.label] -= 0.05 continue elif re.search('(采购|招标|询比?价|遴选|寻源|比选)机构(名称)?[是为:]+$', text[max(0, b-span):b]) and entity.label == 1: agency_like_tenderee.append(entity) for pattern in self.pattern_list: if 'left' in pattern: context = text[max(0, b-span):b] elif 'right' in pattern: context = text[e:e+span] elif 'center' in pattern: context = text[max(0, b-span):e+span] else: print('规则错误', pattern) ser = re.search(pattern, context) if ser: groupdict = pattern.split('>')[0].replace('(?P<', '') _role, _direct, _prob = groupdict.split('_') _label = role2id.get(_role) if _label != entity.label: continue _prob = int(_prob)*0.1 # print('规则修改角色概率前:', entity.entity_text, entity.label, entity.values) if in_att: _prob = _prob - 0.1 # 0.2 if pre_prob < _prob: # 如果模型预测概率小于关键词概率 _prob = 0.65 if len(entity.entity_text) < 6 and re.search('大学|医院', entity.entity_text)==None: # 如果实体名称小于6个字,概率再降0.05 _prob -= 0.05 if re.search('(地址|联系方式):$', context): # 地址结尾的概率 概率降低 _prob -= 0.05 if _label == 0 and is_agency(entity.entity_text): # 20250116 修复 584333688 同时有招标单位 : 安徽省招标集团股份有限公司,.采购人信息 名 称:安徽开放大学 _prob -= 0.1 if re.search('成交电商:$', text[:b]): # 609280615 万银政采平台 罗山县政采平台等成交电商都不是中标人 _prob = 0.55 entity.values[_label] = _prob + entity.values[_label] / 20 not_found = 0 if is_result_change and _label == 2 and (re.search('原(公告)?(中标|中选|中价|成交|竞得)(人|单位|供应商)|原?第[一1](中标|中选|中价|成交)?候选人', context) or re.search('更正前', text[max(0, b-20):b])): entity.values[_label] = 0.5 log('结果变更公告去除原中标人:%s, docid:%s'%(entity.entity_text, docid)) if is_result_change and _label == 3 and re.search('原(排名)?第二', text[max(0, b-20):b]): entity.label = 2 entity.values[2] = 0.6 log('结果变更公告第二名变中标人:%s, docid:%s'%(entity.entity_text, docid)) # print('规则修改角色概率后:', entity.entity_text, entity.label, entity.values) break if original_docchannel == 117 and re.search('卖方(名称)?:$', text[max(0, b-span):b]): entity.label = 0 if not_found and entity.values[entity.label]> 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 entity.label == 2 and entity.values[entity.label]> min_prob: if entity.entity_type == 'org': org_winner.append(entity) elif entity.entity_type == 'company': company_winner.append(entity) # 保存中标人实体 if entity.label == 0 and entity.values[entity.label]> min_prob: org_tenderee.append(entity.entity_text) # 保存所有招标人名称 elif entity.label == 1 and entity.values[entity.label]> min_prob: agency_l.append(entity.entity_text) if entity.entity_text not in role_text_type_dic: role_text_type_dic[entity.entity_text] = set() # if entity.entity_text not in role_text_ent_dic: # role_text_ent_dic[entity.entity_text] = { # "招标概率": [], # "中标概率": [], # "实体列表": [] # } if entity.label in [0, 2, 3, 4]: role_text_type_dic[entity.entity_text].add(str(entity.label)) # role_text_ent_dic[entity.entity_text]["实体列表"].append(entity) # if entity.label == 0: # role_text_ent_dic[entity.entity_text]["招标概率"].append(entity.values[entity.label]) # else: # role_text_ent_dic[entity.entity_text]["中标概率"].append(entity.values[entity.label]) # if entity.entity_type in ['org', 'company'] and entity.label == 0 and entity.entity_text in agency_set and entity.values[entity.label]<0.6: # 修改概率小于0.6的且在大数据代理集合里面的招标人为代理人 # # log('修改概率小于0.6的且在大数据代理集合里面的招标人为代理人%s:'%entity.entity_text) # entity.label = 1 # entity.values[entity.label] = 0.5 elif entity.entity_type in ['org', 'company'] and entity.label in [1, 0] and 0.5<=entity.values[entity.label]<0.6: if entity.label == 1: low_prob_agency.append(entity) else: low_prob_tenderee.append(entity) elif entity.entity_type in ['org', 'company'] and entity.label == 2 and 0.5<=entity.values[entity.label]<0.6: low_prob_winner.append(entity) if entity.entity_type in ['org', 'company'] and entity.label in [1, 0] and 0.6 scope[0][1]: bid_info_company.append(entity) elif scope[0][0] < entity.sentence_index < scope[1][0]: bid_info_company.append(entity) elif entity.sentence_index == scope[1][0] and entity.wordOffset_end 0.5: have_winner = True if ree_info and entity.entity_type in ['org', 'company']: # 招标大纲下实体 for scope in ree_info: if scope[0][0] == scope[1][0]: if entity.sentence_index == scope[0][0] and scope[0][1] < entity.wordOffset_begin and entity.wordOffset_end <= scope[1][1]: ree_info_company.append(entity) else: if entity.sentence_index == scope[0][0] and entity.wordOffset_begin > scope[0][1]: ree_info_company.append(entity) elif scope[0][0] < entity.sentence_index < scope[1][0]: ree_info_company.append(entity) elif entity.sentence_index == scope[1][0] and entity.wordOffset_end 0.5: have_ree = True if is_bid_record and entity.entity_type in ['org', 'company'] and entity.label == 2 and 0.5<=entity.values[entity.label]<0.8: entity.values[entity.label] = 0.4 log('开标记录去掉不确定中标人:%s,docid:%s'%(entity.entity_text, docid)) # 第二步:低概率实体修正 self._correct_low_prob_entities( agency_like_tenderee, org_tenderee, low_prob_agency, low_prob_tenderee, agency_l, low_prob_winner, all_tenderee_agency ) # 第三步:中标人/招标人冲突修正 self._correct_winner_tenderee_conflict(org_winner, org_tenderee) # 第四步:大纲范围内实体补充 self._supplement_outline_entities( bid_info_company, ree_info_company, have_winner, have_ree, span, docid, sentences ) # # 第五步:角色冲突最终修正 # self._resolve_role_conflict(role_text_ent_dic, role_text_type_dic, docid) # for entity in agency_like_tenderee: # if not is_agency(entity.entity_text) or entity.entity_text in org_tenderee: # entity.label = 0 # entity.values[entity.label] = 0.6 # else: # entity.values[entity.label] = 0.5 # for entity in low_prob_agency: # 如果低概率代理在招标人列表,改为招标人 # if entity.entity_text in org_tenderee: # entity.label = 0 # entity.values[entity.label] = 0.6 # for entity in low_prob_tenderee: # if entity.entity_text in agency_l: # entity.label = 1 # entity.values[entity.label] = 0.6 # for entity in low_prob_winner: # 如果低概率中标人在招标或代理列表,改为非角色 # if entity.entity_text in all_tenderee_agency: # entity.label = 5 # # elif entity.in_attachment: # 附件低概率中标角色不要 避免:516109391 桂林银行崇左宁明支行,宁明县城中镇兴宁大道中70号,预测为中标 20241126 注释掉,558294326 附件单个候选人漏提取 # # entity.label = 5 # if org_winner != []: # flag = 0 # if org_tenderee != []: # for ent in org_winner: # if ent.entity_text in org_tenderee: # # log('如果org中标人同时为招标人角色,降低中标概率:%s, %s' % (ent.entity_text, ent.label)) # ent.values[2] = 0.6 # flag = 1 # # if flag == 0 and company_winner != []: # 2024/04/18 注释掉 避免提取不到 273351465 供应商(乙方:湖南省第二测绘院 # # for ent in org_winner: # # if ent.label == 2 and ent.values[2] > 0.6: # # # log('如果同时包含org和company中标人,降低org中标人概率为0.6:%s, %s' % (ent.entity_text, ent.values[2])) # # ent.values[2] = 0.6 # if have_winner == False and bid_info_company: # 优化 638075055 二、推荐中标候选人信息,邯郸市婷元紧固件制造有限公司第一名, # for entity in bid_info_company: # text = sentences[entity.sentence_index].sentence_text # b = entity.wordOffset_begin # e = entity.wordOffset_end # if re.search('(单位(名称)?|投标(单位|人)(名称)?|公司名称):$', text[max(0, b-span-2):b]) and entity.label == 5: # entity.label = 2 # entity.values[entity.label] = 0.55 # log('大纲规则补充中标人:%s, docid:%s'%(entity.entity_text, docid)) # elif entity.label == 0 and entity.values[entity.label]>0.5 and re.search('(采购|招标)(单位|人)', text[max(0, b-span-2):b])==None: # entity.values[entity.label] = 0.5 # log('中标大纲下招标人概率降低:%s, docid:%s'%(entity.entity_text, docid)) # # elif len(bid_info_company) == 1 and entity.label != 2: # # entity.label = 2 # # entity.values[entity.label] = 0.55 # # log('大纲规则补充中标人:%s, docid:%s' % (entity.entity_text, docid)) # if have_ree == False and ree_info_company: # 优化 638075055 二、推荐中标候选人信息,邯郸市婷元紧固件制造有限公司第一名, # for entity in ree_info_company: # text = sentences[entity.sentence_index].sentence_text # b = entity.wordOffset_begin # e = entity.wordOffset_end # if re.search('(单位名称|([^\w]|^)名称):$', text[max(0, b-span-2):b]) and entity.label == 5: # entity.label = 0 # entity.values[entity.label] = 0.55 # log('大纲规则补充招标人:%s, docid:%s'%(entity.entity_text, docid)) # break # role_text_type_dic = {k: ' '.join(v) for k, v in role_text_type_dic.items() if len(v)>1 and '0' in v} # if role_text_type_dic: # log("同一个公司名称包含多个角色:%s, docid:%s"%(json.dumps(role_text_type_dic, ensure_ascii=False), docid)) def role_special_predictor(web_source_name, content, nlp_enterprise): if web_source_name == '中国电子科技集团有限公司电子采购平台': ser = re.search(',(\w{5,30}),发布时间:\d+', content) if ser and ser.group(1) in nlp_enterprise: return ser.group(1) elif web_source_name == '高校仪器设备竞价网': ser = re.search('--(\w{5,30}),申购单主题', content) if ser and ser.group(1) in nlp_enterprise: return ser.group(1) elif web_source_name == '台泥阳光采购平台': ser = re.search(',(\w{5,30})招标公告,', content) if ser and ser.group(1) in nlp_enterprise: return ser.group(1)