extract.py 51 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801
  1. #coding:utf8
  2. '''
  3. Created on 2019年1月4日
  4. @author: User
  5. '''
  6. import os
  7. from bs4 import BeautifulSoup, Comment
  8. import copy
  9. import re
  10. import sys
  11. import os
  12. import codecs
  13. import requests
  14. import time
  15. from unicodedata import normalize
  16. _time1 = time.time()
  17. sys.path.append(os.path.abspath("../.."))
  18. from BiddingKG.dl.common.Utils import *
  19. import BiddingKG.dl.entityLink.entityLink as entityLink
  20. import BiddingKG.dl.interface.predictor as predictor
  21. import BiddingKG.dl.interface.Preprocessing as Preprocessing
  22. import BiddingKG.dl.interface.getAttributes as getAttributes
  23. import BiddingKG.dl.complaint.punish_predictor as punish_rule
  24. import json
  25. from BiddingKG.dl.money.re_money_total_unit import extract_total_money, extract_unit_money
  26. from BiddingKG.dl.ratio.re_ratio import extract_ratio
  27. from BiddingKG.dl.interface.outline_extractor import ParseDocument, extract_parameters, extract_sentence_list, extract_addr
  28. from BiddingKG.dl.interface.get_label_dic import get_all_label
  29. from BiddingKG.dl.channel.channel_bert import merge_channel
  30. from BiddingKG.dl.interface.kvtree_search import get_kvtree_value
  31. from BiddingKG.dl.interface.special_debt_extract import get_debt_info
  32. # 自定义jsonEncoder
  33. class MyEncoder(json.JSONEncoder):
  34. def default(self, obj):
  35. if isinstance(obj, np.ndarray):
  36. return obj.tolist()
  37. elif isinstance(obj, bytes):
  38. return str(obj, encoding='utf-8')
  39. elif isinstance(obj, (np.float_, np.float16, np.float32,
  40. np.float64)):
  41. return float(obj)
  42. elif isinstance(obj,str):
  43. return obj
  44. return json.JSONEncoder.default(self, obj)
  45. def get_login_web_set():
  46. file = os.path.join(os.path.dirname(__file__),"login_weblist.txt")
  47. list_web = []
  48. try:
  49. if os.path.exists(file):
  50. with open(file,"r",encoding="utf8") as f:
  51. while 1:
  52. line = f.readline()
  53. if not line:
  54. break
  55. line = line.strip()
  56. if line:
  57. list_web.append(line)
  58. except Exception as e:
  59. traceback.print_exc()
  60. _set = set(list_web)
  61. log("get_login_web_set length %d"%(len(_set)))
  62. return _set
  63. set_login_web = get_login_web_set()
  64. def extractCount(extract_dict,page_attachments,web_source_name,page_time):
  65. # time_pattern = "\d{4}\-\d{2}\-\d{2}.*"
  66. if len(extract_dict):
  67. _extract = extract_dict
  68. else:
  69. _extract = {}
  70. # print(_extract)
  71. dict_pack = _extract.get("prem",{})
  72. extract_count = 0
  73. list_code = _extract.get("code",[])
  74. word_count = _extract.get("word_count",{})
  75. if word_count.get("正文",0)>500:
  76. extract_count += 3
  77. if len(list_code)>0:
  78. project_code = list_code[0]
  79. else:
  80. project_code = ""
  81. project_name = _extract.get("name","")
  82. bidding_budget = ""
  83. win_tenderer = ""
  84. win_bid_price = ""
  85. linklist_count = 0
  86. time_getFileEnd = _extract.get("time_getFileEnd","")
  87. time_bidopen = _extract.get("time_bidopen","")
  88. time_bidclose = _extract.get("time_bidclose","")
  89. time_publicityEnd = _extract.get("time_publicityEnd","")
  90. if page_time!="":
  91. if time_getFileEnd!="" and time_getFileEnd<page_time:
  92. extract_count -= 5
  93. if time_bidopen!="" and time_bidopen<page_time:
  94. extract_count -= 5
  95. if time_bidclose!="" and time_bidclose<page_time:
  96. extract_count -= 5
  97. if time_publicityEnd!="" and time_publicityEnd<page_time:
  98. extract_count -= 5
  99. for _key in dict_pack.keys():
  100. if "tendereeMoney" in dict_pack[_key] and dict_pack[_key]["tendereeMoney"]!='' and float(dict_pack[_key]["tendereeMoney"])>0:
  101. extract_count += 1
  102. if bidding_budget=="":
  103. bidding_budget = str(float(dict_pack[_key]["tendereeMoney"]))
  104. for _role in dict_pack[_key]["roleList"]:
  105. if isinstance(_role,list):
  106. extract_count += 1
  107. if _role[2]!='' and float(_role[2])>0:
  108. extract_count += 1
  109. if _role[0]=="tenderee":
  110. tenderee = _role[1]
  111. if _role[0]=="win_tenderer":
  112. if _role[1] is not None and _role[1]!="":
  113. extract_count += 2
  114. if win_tenderer=="":
  115. win_tenderer = _role[1]
  116. if _role[2]!='' and float(_role[2])>0:
  117. extract_count += 2
  118. if win_bid_price=="":
  119. win_bid_price = str(float(_role[2]))
  120. if _role[0]=="agency":
  121. agency = _role[1]
  122. if isinstance(_role,dict):
  123. extract_count += 1
  124. if "role_money" in _role:
  125. if str(_role["role_money"].get("money",""))!='' and float(_role["role_money"].get("money",""))>0:
  126. extract_count += 1
  127. if _role.get("role_name")=="tenderee":
  128. tenderee = _role["role_text"]
  129. if _role.get("role_name")=="win_tenderer":
  130. if _role["role_text"] is not None and _role["role_text"]!="":
  131. extract_count += 2
  132. if win_tenderer=="":
  133. win_tenderer = _role["role_text"]
  134. if "role_money" in _role:
  135. if str(_role["role_money"]["money"])!='' and float(_role["role_money"]["money"])>0:
  136. extract_count += 2
  137. if win_bid_price=="":
  138. win_bid_price = str(float(_role["role_money"]["money"]))
  139. if _role["role_name"]=="agency":
  140. agency = _role["role_text"]
  141. linklist = _role.get("linklist",[])
  142. for link in linklist:
  143. for l in link:
  144. if l!="":
  145. linklist_count += 1
  146. extract_count += linklist_count//2
  147. if project_code!="":
  148. extract_count += 1
  149. if project_name!="":
  150. extract_count += 1
  151. if page_attachments is not None and page_attachments!='':
  152. try:
  153. _attachments = json.loads(page_attachments)
  154. set_md5 = set()
  155. has_zhaobiao = False
  156. has_qingdan = False
  157. if len(_attachments)>0:
  158. for _atta in _attachments:
  159. classification = _atta.get("classification","")
  160. set_md5.add(_atta.get("fileMd5"))
  161. if str(classification)=='招标文件':
  162. has_zhaobiao = True
  163. if str(classification)=='采购清单':
  164. has_qingdan = True
  165. extract_count += len(set_md5)//2+1
  166. if has_zhaobiao:
  167. extract_count += 2
  168. if has_qingdan:
  169. extract_count += 1
  170. except Exception as e:
  171. traceback.print_exc()
  172. pass
  173. list_approval_dict = _extract.get("approval",[])
  174. for _dict in list_approval_dict:
  175. for k,v in _dict.items():
  176. if v is not None and v!='' and v!="未知":
  177. extract_count += 1
  178. punish_dict = _extract.get("punish",{})
  179. for k,v in punish_dict.items():
  180. if v is not None and v!='' and v!="未知":
  181. extract_count += 1
  182. if web_source_name in set_login_web:
  183. extract_count -= 3
  184. product = _extract.get("product","")
  185. extract_count += len(str(product).split(","))//5
  186. return extract_count
  187. # 字符编码标准化
  188. def str_normalize(text):
  189. # time1 = time.time()
  190. cn_punctuation = "¥,。:;{}!?()<"
  191. text_split = re.split("([{}])+".format(cn_punctuation),text)
  192. # print(text_split)
  193. new_text = ""
  194. for s in text_split:
  195. if re.search("^[{}]+$".format(cn_punctuation),s):
  196. new_text += s
  197. else:
  198. new_text += normalize('NFKD', s)
  199. # print("str_normalize cost time %s"%str(time.time()-time1))
  200. # print(new_text)
  201. return new_text
  202. # 修复prem中地区前缀不完整实体
  203. def repair_entity(prem,district_dict,list_articles):
  204. district_dict = district_dict['district']
  205. province = district_dict['province'] if district_dict['province'] and district_dict['province'] not in ['未知','全国'] else ""
  206. city = district_dict['city'] if district_dict['city'] and district_dict['city']!='未知' else ""
  207. district = district_dict['district'] if district_dict['district'] and district_dict['district']!='未知' else ""
  208. content_text = list_articles[0].content
  209. autonomous_region_dict = {
  210. "新疆":"新疆维吾尔",
  211. "西藏":"西藏",
  212. "内蒙古":"内蒙古",
  213. "广西":"广西壮族",
  214. "宁夏":"宁夏回族"
  215. }
  216. for package,_prem in prem[0]['prem'].items():
  217. for role in _prem['roleList']:
  218. if role['role_name'] in ['tenderee','agency']:
  219. role_text = role['role_text']
  220. if re.search("^[省市县区]",role_text):
  221. if role_text[0]=='省' and role_text[:2] not in ['省道']:
  222. role['role_text'] = province + role_text
  223. elif role_text[0]=='市' and role_text[:2] not in ['市政','市场']:
  224. if district+'市' in content_text:
  225. # 县级市
  226. role['role_text'] = district + role_text
  227. else:
  228. role['role_text'] = city + role_text
  229. elif role_text[0] in ['县','区']:
  230. role['role_text'] = district + role_text
  231. elif re.search("^自治[区州县]",role_text):
  232. if role_text[:3]=='自治区':
  233. role['role_text'] = autonomous_region_dict.get(province,"") + role_text
  234. elif role_text[:3] in ['自治县',"自治州"]:
  235. if re.search("自治[县州]?$",district):
  236. role['role_text'] = re.sub("自治[县州]?","",district) + role_text
  237. elif re.search("族$",district):
  238. role['role_text'] = district + role_text
  239. elif re.search("自治[县州]?$",city):
  240. role['role_text'] = re.sub("自治[县州]?","",city) + role_text
  241. elif re.search("族$",city):
  242. role['role_text'] = city + role_text
  243. def fix_table_structure_preserve_order(html):
  244. """
  245. 修复table结构中tr与tbody平级的问题
  246. 保持原有行顺序不变
  247. """
  248. soup = BeautifulSoup(html, 'html.parser')
  249. for table in soup.find_all('table'):
  250. if table.find_all('tr', recursive=False) != []:
  251. # 获取table下所有直接子节点
  252. children = list(table.children)
  253. tbody_new = soup.new_tag('tbody')
  254. table.append(tbody_new)
  255. for child in children:
  256. if child.name:
  257. if child.name == 'tbody':
  258. for tag in list(child.children):
  259. tbody_new.append(tag.extract())
  260. child.extract()
  261. else:
  262. tbody_new.append(child.extract())
  263. return str(soup)
  264. def predict(doc_id,text,title="",page_time="",web_source_no='',web_source_name="",original_docchannel='',page_attachments='[]',**kwargs):
  265. cost_time = dict()
  266. if web_source_no == None:
  267. web_source_no = ''
  268. if web_source_name == None:
  269. web_source_name = ''
  270. start_time = time.time()
  271. log("start process doc %s"%(str(doc_id)))
  272. # 字符编码标准化
  273. text = str_normalize(text)
  274. text = fix_table_structure_preserve_order(text) # 20250331 修复表格tr tbody平级问题
  275. list_articles,list_sentences,list_entitys,list_outlines,_cost_time = Preprocessing.get_preprocessed([[doc_id,text,"","",title,page_time, web_source_no]],useselffool=True)
  276. log("get preprocessed done of doc_id%s"%(doc_id))
  277. cost_time["preprocess"] = round(time.time()-start_time,2)
  278. cost_time.update(_cost_time)
  279. '''大纲提取及大纲内容相关提取'''
  280. start_time = time.time()
  281. sentence2_list, sentence2_list_attach = extract_sentence_list(list_sentences[0])
  282. parse_document = ParseDocument(text, True,list_obj=sentence2_list)
  283. requirement_text, aptitude_text, addr_bidopen_text, addr_bidsend_text, out_lines, requirement_scope, pinmu_name, list_policy = extract_parameters(parse_document)
  284. if sentence2_list_attach!=[] and requirement_text == '' and aptitude_text == '' and addr_bidopen_text=="":
  285. parse_document = ParseDocument(text, True, list_obj=sentence2_list_attach)
  286. requirement_text, aptitude_text, addr_bidopen_text, addr_bidsend_text, out_lines, requirement_scope, pinmu_name, list_policy = extract_parameters(parse_document)
  287. # print('out_lines',out_lines)
  288. # if addr_bidopen_text == '':
  289. # addr_bidopen_text = extract_addr(list_articles[0].content)
  290. addr_dic, time_dic, code_investment = predictor.getPredictor('entity_type_rule').predict(list_entitys, list_sentences, list_articles)
  291. if addr_bidopen_text != '' and 'addr_bidopen' not in addr_dic:
  292. addr_dic['addr_bidopen'] = addr_bidopen_text
  293. if addr_bidsend_text != '' and 'addr_bidsend' not in addr_dic:
  294. addr_dic['addr_bidsend'] = addr_bidsend_text
  295. log("get outline done of doc_id%s"%(doc_id))
  296. cost_time["outline"] = round(time.time()-start_time,2)
  297. '''从 kvtree 正则匹配要素'''
  298. start_time = time.time()
  299. kv_single_dic, kv_addr_dic = get_kvtree_value(text)
  300. log("get kvtree done of doc_id%s"%(doc_id))
  301. cost_time["kvtree"] = round(time.time()-start_time,2)
  302. # 过滤掉Redis里值为0的错误实体
  303. # list_entitys[0] = entityLink.enterprise_filter(list_entitys[0])
  304. # #依赖句子顺序
  305. # start_time = time.time() # 公告类型/生命周期提取 此处作废 换到后面预测 2022/4/29
  306. # channel_dic = predictor.getPredictor("channel").predict(title=title, list_sentence=list_sentences[0],
  307. # web_source_no=web_source_no,original_docchannel=original_docchannel)
  308. # cost_time["channel"] = round(time.time()-start_time,2)
  309. start_time = time.time() # 项目编号、名称提取
  310. codeName = predictor.getPredictor("codeName").predict(list_sentences,MAX_AREA=5000,list_entitys=list_entitys)
  311. if re.search('破产清算案', title):
  312. end = re.search('破产清算案', title).end()
  313. codeName[0]['name'] = title[:end]
  314. log("get codename done of doc_id%s"%(doc_id))
  315. cost_time["codename"] = round(time.time()-start_time,2)
  316. start_time = time.time() # 公告类别预测
  317. channel_dic, msc = predictor.getPredictor("channel").predict_merge(title, list_sentences[0], text,original_docchannel, web_source_no)
  318. cost_time["rule_channel"] = round(time.time() - start_time, 2)
  319. start_time = time.time() # 角色金额模型提取
  320. predictor.getPredictor("prem").predict(list_sentences,list_entitys)
  321. log("get prem done of doc_id%s"%(doc_id))
  322. cost_time["prem"] = round(time.time()-start_time,2)
  323. # start_time = time.time() # 产品名称及废标原因提取 此处作废 换到后面预测 2022/4/29
  324. # fail = channel_dic['docchannel']['docchannel'] == "废标公告"
  325. # fail_reason = predictor.getPredictor("product").predict(list_sentences,list_entitys,list_articles, fail) #只返回失败原因,产品已加入到Entity类
  326. # # predictor.getPredictor("product").predict(list_sentences, list_entitys)
  327. # log("get product done of doc_id%s"%(doc_id))
  328. # cost_time["product"] = round(time.time()-start_time,2)
  329. start_time = time.time() # 产品相关要素正则提取 单价、数量、品牌规格 ; 项目、需求、预算、时间
  330. product_attrs, total_product_money = predictor.getPredictor("product_attrs").predict(doc_id, text, page_time)
  331. log("get product attributes done of doc_id%s"%(doc_id))
  332. cost_time["product_attrs"] = round(time.time()-start_time,2)
  333. # 是否为存款类项目
  334. deposit_project = is_deposit_project(title, codeName[0]['name'], requirement_text)
  335. start_time = time.time() #正则角色提取
  336. predictor.getPredictor("roleRule").predict(list_articles,list_sentences, list_entitys,codeName, channel_dic, all_winner=is_all_winner(title), req_scope=requirement_scope, deposit_project=deposit_project)
  337. cost_time["rule"] = round(time.time()-start_time,2)
  338. '''正则补充最后一句实体日期格式为招标或代理 2021/12/30;正则最后补充角色及去掉包含 公共资源交易中心 的招标人'''
  339. start_time = time.time() #正则角色提取
  340. predictor.getPredictor("roleRuleFinal").predict(list_articles,list_sentences,list_entitys, codeName)
  341. cost_time["roleRuleFinal"] = round(time.time()-start_time,2)
  342. start_time = time.time() #正则招标人召回
  343. predictor.getPredictor("tendereeRuleRecall").predict(list_articles,list_sentences,list_entitys, codeName)
  344. cost_time["tendereeRuleRecall"] = round(time.time()-start_time,2)
  345. '''规则调整角色概率'''
  346. start_time = time.time() #
  347. predictor.getPredictor("rolegrade").predict(list_sentences,list_entitys,original_docchannel)
  348. cost_time["rolegrade"] = round(time.time()-start_time,2)
  349. '''规则调整金额概率'''
  350. start_time = time.time() #
  351. predictor.getPredictor("moneygrade").predict(list_sentences,list_entitys)
  352. cost_time["moneygrade"] = round(time.time()-start_time,2)
  353. start_time = time.time() #联系人模型提取
  354. predictor.getPredictor("epc").predict(list_sentences,list_entitys)
  355. log("get epc done of doc_id%s"%(doc_id))
  356. cost_time["person"] = round(time.time()-start_time,2)
  357. start_time = time.time() # 时间类别提取
  358. predictor.getPredictor("time").predict(list_sentences, list_entitys)
  359. log("get time done of doc_id%s"%(doc_id))
  360. cost_time["time"] = round(time.time()-start_time,2)
  361. start_time = time.time() # 保证金支付方式
  362. payment_way_dic = predictor.getPredictor("deposit_payment_way").predict(content=list_articles[0].content)
  363. cost_time["deposit"] = round(time.time()-start_time,2)
  364. # 需在getPredictor("prem").predict后 getAttributes.getPREMs 前 规则调整 监理|施工|设计|勘察类别公告的费用 为招标或中标金额
  365. predictor.getPredictor("prem").correct_money_by_rule(title, list_entitys, list_articles)
  366. # 2021-12-29新增:提取:总价,单价
  367. start_time = time.time() # 总价单价提取
  368. predictor.getPredictor("total_unit_money").predict(list_sentences, list_entitys)
  369. cost_time["total_unit_money"] = round(time.time()-start_time, 2)
  370. # 依赖句子顺序
  371. start_time = time.time() # 实体链接
  372. entityLink.link_entitys(list_entitys)
  373. doctitle_refine = entityLink.doctitle_refine(title)
  374. nlp_enterprise,nlp_enterprise_attachment, dict_enterprise = entityLink.get_nlp_enterprise(list_entitys[0])
  375. prem = getAttributes.getPREMs(list_sentences,list_entitys,list_articles,list_outlines,page_time)
  376. log("get attributes done of doc_id%s"%(doc_id))
  377. cost_time["attrs"] = round(time.time()-start_time,2)
  378. if original_docchannel != 302: # 审批项目不做下面提取
  379. '''表格要素提取'''
  380. table_prem, in_attachment = predictor.getPredictor("tableprem").predict(text, nlp_enterprise+nlp_enterprise_attachment, web_source_name, is_all_winner(title))
  381. # print('表格提取中标人:', table_prem)
  382. # print('原提取角色:', prem[0]['prem'])
  383. if table_prem:
  384. getAttributes.update_prem(old_prem=prem[0]['prem'], new_prem=table_prem, in_attachment=in_attachment)
  385. '''候选人提取'''
  386. candidate_top3_prem, candidate_dic, in_attachment = predictor.getPredictor("candidate").predict(text, list_sentences, list_entitys, nlp_enterprise+nlp_enterprise_attachment)
  387. # print('表格提取候选人:', candidate_top3_prem)
  388. getAttributes.update_prem(old_prem=prem[0]['prem'], new_prem=candidate_top3_prem, in_attachment=in_attachment)
  389. '''获取联合体信息'''
  390. getAttributes.get_win_joint(prem, list_entitys, list_sentences, list_articles)
  391. '''修正采购公告表格形式多种采购产品中标价格;中标金额小于所有产品总金额则改为总金额'''
  392. getAttributes.correct_rolemoney(prem, total_product_money, list_articles)
  393. '''修正channel预测类别为招标公告却有中标人及预测为中标信息却无中标关键词的类别''' # 依赖 prem
  394. start_time = time.time()
  395. # content = list_articles[0].content
  396. # channel_dic = predictor.getPredictor("channel").predict_rule(title, content, channel_dic, prem_dic=prem[0]['prem'])
  397. if original_docchannel == 302:
  398. channel_dic = {"docchannel":
  399. { "docchannel": "审批项目", "doctype": "审批项目", "life_docchannel": "审批项目" }
  400. }
  401. else:
  402. channel_dic, msc = predictor.getPredictor("channel").final_change(channel_dic, prem[0], original_docchannel, msc)
  403. # print('msc', msc)
  404. channel_dic = merge_channel(list_articles,channel_dic,original_docchannel) # channel_dic 根据新模型预测结合判断,整合结果
  405. cost_time["rule_channel2"] = round(time.time()-start_time,2)
  406. '''一包多中标人提取及所有金额提取'''
  407. all_moneys = getAttributes.get_multi_winner_and_money(channel_dic, prem, list_entitys,list_sentences, is_all_winner(title))
  408. start_time = time.time() # 产品名称及废标原因提取 #依赖 docchannel结果
  409. fail = channel_dic['docchannel']['docchannel'] == "废标公告"
  410. fail_reason, product_list = predictor.getPredictor("product").predict(list_sentences,list_entitys,list_articles, fail,out_lines=out_lines) #只返回失败原因,产品已加入到Entity类 #2022/7/29补充返回产品,方便行业分类调用
  411. # predictor.getPredictor("product").predict(list_sentences, list_entitys)
  412. log("get product done of doc_id%s"%(doc_id))
  413. cost_time["product"] = round(time.time()-start_time,2)
  414. prem[0].update(getAttributes.getOtherAttributes(list_entitys[0],page_time,prem,channel_dic))
  415. '''更新单一来源招标公告中标角色为预中标'''
  416. getAttributes.fix_single_source(prem[0], channel_dic, original_docchannel)
  417. '''公告无表格格式时,采购意向预测''' #依赖 docchannel结果 依赖产品及prem
  418. '''把产品要素提取结果在项目名称的添加到 采购需求,预算时间,采购时间 要素中'''
  419. predictor.getPredictor("product_attrs").add_product_attrs(channel_dic, product_attrs, list_sentences,list_entitys,list_outlines,product_list,codeName,prem,text,page_time)
  420. '''行业分类提取,需要用标题、项目名称、产品、及prem 里面的角色'''
  421. industry = predictor.getPredictor('industry').predict(title, project=codeName[0]['name'], product=','.join(product_list), prem=prem, product_attrs=product_attrs)
  422. '''地区获取'''
  423. start_time = time.time()
  424. # district = predictor.getPredictor('district').predict(project_name=codeName[0]['name'], prem=prem,title=title, list_articles=list_articles, web_source_name=web_source_name, list_entitys=list_entitys)
  425. district = predictor.getPredictor('district').predict_area(title, list_articles[0].content, web_source_name, prem=prem[0]['prem'], addr_dic=addr_dic, list_entity=list_entitys[0])
  426. cost_time["district"] = round(time.time() - start_time, 2)
  427. '''根据district提取结果修复实体'''
  428. repair_entity(prem,district,list_articles)
  429. '''根据数据源最后召回招标人角色'''
  430. prem = predictor.getPredictor('websource_tenderee').get_websource_tenderee(web_source_no, web_source_name, prem)
  431. '''根据关键词表生成项目标签'''
  432. project_label = predictor.getPredictor('project_label').predict(title,product=','.join(product_list),project_name=codeName[0]['name'],prem=prem)
  433. # 额外需求的标签
  434. project_label = predictor.getPredictor('project_label').predict_other(project_label,industry,title,codeName[0]['name'],','.join(product_list),list_articles)
  435. # print(project_label)
  436. '''产权分类二级标签'''
  437. property_label = predictor.getPredictor('property_label').predict(title, product=','.join(product_list),project_name=codeName[0]['name'], prem=prem,channel_dic=channel_dic)
  438. '''最终验证prem'''
  439. getAttributes.confirm_prem(prem[0]['prem'], channel_dic, deposit_project, prem[0]['total_tendereeMoney'])
  440. '''通过产品补充标段包名20241203'''
  441. getAttributes.add_package_name(prem[0]['prem'], list_entitys[0], product_list, name=codeName[0]['name'])
  442. # 提取拟在建所需字段
  443. start_time = time.time()
  444. pb_json = predictor.getPredictor('pb_extract').predict(prem, list_articles, list_sentences, list_entitys, title, codeName[0], text, web_source_name, industry)
  445. log("pb_extract done of doc_id%s"%(doc_id))
  446. cost_time["pb_extract"] = round(time.time() - start_time, 2)
  447. '''打标签'''
  448. label_dic = get_all_label(title, list_articles[0].content, prem[0]['prem'])
  449. '''评标评分提取'''
  450. bid_score = predictor.getPredictor('bid_score').predict(text, nlp_enterprise+nlp_enterprise_attachment)
  451. # data_res = Preprocessing.union_result(Preprocessing.union_result(codeName, prem),list_punish_dic)[0]
  452. # data_res = Preprocessing.union_result(Preprocessing.union_result(Preprocessing.union_result(codeName, prem),list_punish_dic), list_channel_dic)[0]
  453. version_date = {'version_date': '2025-05-15'}
  454. data_res = dict(codeName[0], **prem[0], **channel_dic, **product_attrs[0], **product_attrs[1], **payment_way_dic, **fail_reason, **industry, **district, **candidate_dic, **version_date, **all_moneys, **pb_json)
  455. if original_docchannel == 302:
  456. approval = predictor.getPredictor("approval").predict(list_sentences, list_entitys, text, nlp_enterprise=nlp_enterprise+nlp_enterprise_attachment)
  457. approval = predictor.getPredictor("approval").add_ree2approval(approval , prem[0]['prem'])
  458. approval = predictor.getPredictor("approval").add_codename2approval(approval , codeName)
  459. data_res['prem'] = {} # 审批项目不要这项
  460. data_res['approval'] = approval[:100] # 20250217 限制获取最多100个项目
  461. if web_source_no == 'XM6486':
  462. debt_dic = get_debt_info(text) # 专项债信息提取
  463. if debt_dic.get('district', '') != '':
  464. district = predictor.getPredictor('district').predict_area(debt_dic['district'], '', web_source_name)
  465. debt_dic['district'] = district['district']
  466. data_res['district'] = district['district']
  467. # 提取专项债信息
  468. data_res['debt_dic'] = debt_dic
  469. data_res['docchannel'] = { "docchannel": "审批项目", "doctype": "审批项目", "life_docchannel": "审批项目" }
  470. if channel_dic['docchannel']['doctype'] == '处罚公告': # 20240627 处罚公告进行失信要素提取
  471. start_time = time.time() #失信数据要素提取
  472. punish_dic = predictor.getPredictor("punish").get_punish_extracts(list_articles,list_sentences, list_entitys)
  473. cost_time["punish"] = round(time.time()-start_time,2)
  474. data_res['punish'] = punish_dic
  475. if "Project" in data_res['prem']:
  476. for d in data_res['prem']['Project']['roleList']:
  477. if d['role_name'] == 'tenderee' and d.get('role_prob', 0.6) < 0.6: # 处罚公告 去掉低概率招标人
  478. data_res['prem']['Project']['roleList'] = [d for d in data_res['prem']['Project']['roleList'] if d['role_name'] != 'tenderee']
  479. break
  480. if len(data_res['prem']['Project']['roleList']) == 0 and data_res['prem']['Project'].get('tendereeMoney', 0) in [0, '0']: # 删除空包
  481. data_res['prem'].pop('Project')
  482. # 把产品属性里面的产品补充到产品列表
  483. if len(data_res['product_attrs']['data']) > 0: # 20241108 如果产品单价数量提取到产品的,原来提取的产品只保留标题中的
  484. data_res['product'] = [it for it in data_res['product'] if it in title]
  485. for d in data_res['product_attrs']['data']:
  486. if isinstance(d['product'], str) and d['product'] not in data_res['product']:
  487. data_res['product'].append(d['product'])
  488. '''最终检查修正招标、中标金额'''
  489. getAttributes.limit_maximum_amount(data_res, list_entitys[0])
  490. '''利用采购意向需求信息补充项目'''
  491. if channel_dic['docchannel']['docchannel'] == '采购意向':
  492. getAttributes.demand_to_prem(data_res.get('demand_info', {}), prem[0]['prem'])
  493. data_res["project_label"] = project_label
  494. data_res["property_label"] = property_label
  495. data_res["doctitle_refine"] = doctitle_refine
  496. data_res["nlp_enterprise"] = nlp_enterprise
  497. data_res["nlp_enterprise_attachment"] = nlp_enterprise_attachment
  498. data_res["dict_enterprise"] = dict_enterprise
  499. # 要素的个数
  500. data_res['extract_count'] = extractCount(data_res,page_attachments,web_source_name,page_time)
  501. # 是否有表格
  502. data_res['exist_table'] = 1 if re.search("<td",text) else 0
  503. data_res["cost_time"] = cost_time
  504. data_res["success"] = True
  505. # 拟在建需建索引字段
  506. data_res["proportion"] = pb_json.get('pb').get('proportion', '')
  507. data_res["pb_project_name"] = pb_json.get('pb').get('project_name_refind', '')
  508. # 资质要求
  509. data_res['aptitude'] = aptitude_text[:1500]
  510. # 采购内容
  511. data_res['requirement'] = requirement_text[:1500]
  512. # 打标签
  513. data_res['label_dic'] = label_dic
  514. # 开标、投标、项目、收货等地址
  515. data_res['addr_dic'] = addr_dic
  516. # 字数
  517. text_main, text_attn = 0, 0
  518. for sentence in list_sentences[0]:
  519. if sentence.in_attachment:
  520. text_attn += len(sentence.sentence_text)
  521. else:
  522. text_main += len(sentence.sentence_text)
  523. data_res['word_count'] = {'正文': text_main, '附件': text_attn}
  524. # 限制产品数量
  525. data_res['product'] = data_res['product'][:500]
  526. data_res['product_attrs']['data'] = data_res['product_attrs']['data'][:500]
  527. # 是否为存款项目
  528. data_res['is_deposit_project'] = deposit_project
  529. data_res['pinmu_name'] = pinmu_name # 品目名称
  530. data_res['policies'] = list_policy # 政策法规
  531. data_res['bid_score'] = bid_score # 评标得分
  532. data_res['time_planned'] = time_dic.get('time_planned', '') # 预计招标时间
  533. data_res['code_investment'] = code_investment # 投资项目编号
  534. for k, v in kv_single_dic.items(): # 没获取到的用kv_tree补充
  535. if data_res.get(k, '') == '':
  536. data_res[k] = v
  537. for k, v in kv_addr_dic.items(): # 没获取到地址的用kv_tree补充
  538. if data_res['addr_dic'].get(k, '') == '' or re.search('时间:', data_res['addr_dic'][k]):
  539. data_res['addr_dic'][k] = v
  540. # for _article in list_articles:
  541. # log(_article.content)
  542. #
  543. # for list_entity in list_entitys:
  544. # for _entity in list_entity:
  545. # log("type:%s,text:%s,label:%s,values:%s,sentence:%s,begin_index:%s,end_index:%s"%
  546. # (str(_entity.entity_type),str(_entity.entity_text),str(_entity.label),str(_entity.values),str(_entity.sentence_index),
  547. # str(_entity.begin_index),str(_entity.end_index)))
  548. _extract_json = json.dumps(data_res,cls=MyEncoder,sort_keys=True,indent=4,ensure_ascii=False)
  549. _extract_json = _extract_json.replace("\x06", "").replace("\x05", "").replace("\x07", "")
  550. return _extract_json#, list_articles[0].content, get_ent_context(list_sentences, list_entitys)
  551. def test1(name,content):
  552. user = {
  553. "content": content,
  554. "id":name
  555. }
  556. myheaders = {'Content-Type': 'application/json'}
  557. _resp = requests.post("http://192.168.2.102:15030" + '/article_extract', json=user, headers=myheaders, verify=True)
  558. resp_json = _resp.content.decode("utf-8")
  559. # print(resp_json)
  560. return resp_json
  561. def get_ent_context(list_sentences, list_entitys):
  562. rs_list = []
  563. sentences = sorted(list_sentences[0], key=lambda x:x.sentence_index)
  564. for list_entity in list_entitys:
  565. for _entity in list_entity:
  566. if _entity.entity_type in ['org', 'company', 'money']:
  567. s = sentences[_entity.sentence_index].sentence_text
  568. b = _entity.wordOffset_begin
  569. e = _entity.wordOffset_end
  570. # print("%s %d %.4f; %s %s %s"%(_entity.entity_type, _entity.label, _entity.values[_entity.label], s[max(0, b-10):b], _entity.entity_text, s[e:e+10]))
  571. rs_list.append("%s %d %.4f; %s ## %s ## %s"%(_entity.entity_type, _entity.label, _entity.values[_entity.label], s[max(0, b-10):b], _entity.entity_text, s[e:e+10]))
  572. return '\n'.join(rs_list)
  573. def get_role_context(docid, list_sentences, list_entitys):
  574. rs_list = []
  575. sentences = sorted(list_sentences[0], key=lambda x:x.sentence_index)
  576. for list_entity in list_entitys:
  577. for _entity in list_entity:
  578. if _entity.entity_type in ['org', 'company']:
  579. idx = _entity.entity_id
  580. sentence = sentences[_entity.sentence_index]
  581. # _span = spanWindow(tokens=sentence.tokens, begin_index=_entity.begin_index, end_index=_entity.end_index, size=20,
  582. # center_include=False, word_flag=True, text=_entity.entity_text)
  583. _span = get_context(sentence.sentence_text, _entity.wordOffset_begin, _entity.wordOffset_end, size=40, center_include=False)
  584. rs_list.append((docid,idx, _entity.entity_type, _entity.label, '%.4f'%_entity.values[_entity.label], _span[0],
  585. _entity.entity_text, _span[1]))
  586. return rs_list
  587. if __name__=="__main__":
  588. import pandas as pd
  589. t1 = time.time()
  590. # text = '中标人:广州中医药有限公司,招标人:广州市第一人民医院, 代理机构:希达招标代理有限公司。招标金额:100万元, 手续费:100元,总投资:1亿元。中标金额:50000元。合同金额:50000万元。'
  591. title = '打印机'
  592. # df = pd.read_excel('E:/公告金额/产品名称采购需求预算金额采购时间等要素公告.xlsx')
  593. # # df = pd.read_excel('E:/公告金额/产品数量单价.xlsx')
  594. # for i in range(30,50,1):
  595. # text = df.loc[i, 'dochtmlcon']
  596. # rs = json.loads(predict('', text, ''))
  597. # print(rs['demand_info'])
  598. # print(rs['product'])
  599. # print(rs['product_attrs'])
  600. # print(rs)
  601. # df2 = pd.read_csv('E:/导出数据/存款入围框架采购等公告_输入要素.csv')
  602. # df = pd.read_csv('E:\导出数据/存款入围框架采购等公告_预测结果0830.csv')
  603. # df1 = pd.read_csv('E:\导出数据/存款入围框架采购等公告_html.csv')
  604. # df = df.merge(df1, on='docid', how='left')
  605. # print(len(df), df.columns)
  606. # df['rs'] = df['extract_json1'].apply(lambda x: json.loads(x))
  607. # docids = []
  608. # n1 = n2 = 0
  609. # for docid, d, html in zip(df['docid'], df['rs'], df['dochtmlcon']):
  610. # if d['docchannel']['docchannel'] == '招标公告' and '元' in html and 'Project' in d['prem'] and float(
  611. # d['prem']['Project']['tendereeMoney']) == 0:
  612. # docids.append(docid)
  613. # n1 += 1
  614. # else:
  615. # n2 += 1
  616. # print(n1, n2)
  617. # df = df[df['docid'].isin(docids)]
  618. #
  619. # df = df.merge(df2, on='docid', how='left')
  620. # df.fillna('', inplace=True)
  621. # df = df[['docid', 'doctitle', 'page_time', 'web_source_no', 'web_source_name', 'original_docchannel', 'dochtmlcon']]
  622. # print(df.columns)
  623. # # df = df[:10]
  624. # print(len(df))
  625. #
  626. # l = []
  627. # for docid, text, title, page_time,web_no, web_name, channel in zip(df['docid'], df['dochtmlcon'], df['doctitle'], df['page_time'],
  628. # df['web_source_no'], df['web_source_name'], df['original_docchannel']):
  629. # rs, content, roles = predict('', text, title, page_time, web_no, web_name, channel)
  630. # l.append((docid, rs, content, roles))
  631. # df = pd.DataFrame(l, columns=['docid', 'rs', 'content', 'roles'])
  632. # df.to_csv('E:\导出数据/存款入围框架采购等公告_招标公告无招标金额预测结果.csv')
  633. # df = pd.read_csv('E:\角色金额数据/银行类招标金额缺失公告_输入要素.csv')
  634. # # df2 = pd.read_csv('E:/角色金额数据/银行缺招标金额公告_3_html.csv')
  635. # df2 = pd.read_csv('E:/角色金额数据/银行缺招标金额公告_012_html.csv')
  636. # print(len(df), len(df2))
  637. # df = df[df['docid'].isin(df2['docid'])]
  638. # print(len(df))
  639. # df = df.merge(df2, how='left', on='docid')
  640. # print(len(df))
  641. #
  642. # # df1 = pd.read_excel('E:\角色金额数据/银行缺招标金额公告_检查汇总2.xlsx')
  643. # # # df1 = pd.read_excel('E:\角色金额数据/银行缺招标金额公告_检查汇总2_补充招标内容金额后1105.xlsx')
  644. # # df1.fillna('', inplace=True)
  645. # # df1 = df1[df1['tendereeMoney']==0]
  646. # # df = df.merge(df1, on='docid', how='right')
  647. #
  648. # df = df[['docid', 'doctitle', 'page_time', 'web_source_no', 'web_source_name', 'original_docchannel', 'dochtmlcon']]
  649. # print(df.columns)
  650. # # df = df[:10]
  651. # print(len(df))
  652. #
  653. # l = []
  654. # for docid, text, title, page_time,web_no, web_name, channel in zip(df['docid'], df['dochtmlcon'], df['doctitle'], df['page_time'],
  655. # df['web_source_no'], df['web_source_name'], df['original_docchannel']):
  656. # rs, content, roles = predict('', text, title, page_time, web_no, web_name, channel)
  657. # l.append((docid, rs, content, roles))
  658. # df = pd.DataFrame(l, columns=['docid', 'rs', 'content', 'roles'])
  659. # # df.to_csv('E:\角色金额数据/银行缺招标金额公告_3预测结果.csv')
  660. # # df.to_csv('E:\角色金额数据/银行缺招标金额公告_012预测结果.csv')
  661. # # df.to_csv('E:\角色金额数据/银行缺招标金额公告_检查汇总2_修复后预测结果.csv')
  662. # df.to_csv('E:\角色金额数据/银行缺招标金额公告_检查汇总2_修复后预测结果1106.csv')
  663. #
  664. # with open('2.html', 'r', encoding='utf-8') as f:
  665. # text = f.read()
  666. # t1 = time.time()
  667. # print(predict('', text, title))
  668. # t2 = time.time()
  669. # print(predict('', text, title))
  670. # t3 = time.time()
  671. # print('第一次耗时:%.4f, 第二次耗时:%.4f'%(t2-t1, t3-t2))
  672. # print(predict('',text,title))
  673. # df = pd.read_excel('E:/大网站规则识别/大网站要素提取结果2.xlsx')[:]
  674. # df = pd.read_excel('/data/python/lsm/datas_biddingkg/大网站要素提取结果20211115_2.xlsx')[:]
  675. # new_prem = []
  676. # for i in range(len(df)):
  677. # i = 530
  678. # doc_id = df.loc[i, 'docid']
  679. # text = df.loc[i, 'html']
  680. # # title = df.loc[i, 'doctitle']
  681. # rs = predict(doc_id,text)
  682. # rs = json.loads(rs)
  683. # prem = json.dumps(rs['prem'], ensure_ascii=False)
  684. # # print(rs)
  685. # new_prem.append(prem)
  686. # print(prem)
  687. # break
  688. # df['new_prem'] = pd.Series(new_prem)
  689. # print('耗时:', time.time()-t1)
  690. # # df.to_excel('E:/大网站规则识别/大网站要素提取结果20211115.xlsx')
  691. # df.to_excel('/data/python/lsm/datas_biddingkg/大网站要素提取结果20211115.xlsx')
  692. # # pass
  693. import json
  694. a = json.loads('''
  695. { "addr_dic": { "addr_bidopen": "七、开标时间和地点 1.时间:2025年04月14日 09:00(北京时间) 2.地点(网址:浙商银行数智采购一体化管理平台(https://ccgp.szcgpt.czbank.com,现场开标地点为https://www.zcygov.cn", "addr_bidsend": "六、投标截止时间和地点1.时间:2025年05月14日 09:30(北京时间)2.地点(网址:浙商银行数智采购一体化管理平台(https://ccgp.szcgpt.czbank.com)" }, "aptitude": "四、投标人的资格条件,(1)投标人须为具有独立承担民事责任能力的法人或具备国家认可经营资,格的其他组织。(提供合法有效的营业执照复印件,并加盖公章),(2)投标人在最近三年内(2022年04月01日起至今,以法院判决书落款,日期为准)的经营活动中没有行贿犯罪、串通投标犯罪等重大违法记录;在“信,用中国(www.creditchina.gov.cn)”无失信惩戒等情况。(提供承诺书及信用,中国网站相关截图,并加盖公章),第2页(3)投标人须承诺:在最近三年内(2022年04月01日起至今)与浙商银行,的项目(如有)合作过程中,没有出现重大合同违约、泄露商业秘密或技术秘密,等事件。(提供承诺书,并加盖公章),(4)投标人须承诺:如在本次公开招标中入围,在入围期间不得拒绝接受,招标人后续采购合同,不得接受合同后采取各种方式拒绝履约;否则,招标人有,权取消入围资格,并作出相应处理。(提供承诺书,并加盖公章),(5)单位负责人为同一人或者存在控股、管理关系的不同单位,不得同时,参加本次采购活动。(提供承诺书,并加盖公章),(6)除单一来源采购项目外,为采购项目提供整体设计、规范编制或者项,目管理、监理、检测等服务的供应商,不得再参加该采购项目的其他采购活动。(提供承诺书,并加盖公章),(7)投标人若为经营型企业须提供具有行业主管部门颁发的《食品经营许,可证》;若为生产型企业须提供《食品生产许可证》(提供有效的证书复印件加,盖公章)。(8)投标人没有出现在市场监督管理局“经营异常名录”中。(提供国家,企业信用信息公示系统“www.gsxt.gov.cn”列入经营异常名录信息截图,并加,盖公章),(9)本项目不接受联合体(提供承诺书,并加盖公章),本项目(/)接收联合体投标,", "attachmentTypes": "pdf", "bid_score": [], "bidway": "公开招标", "candidate": "", "code": [ "NJJC2024MYGKb024", "HG-241224-YH01" ], "code_investment": "", "cost_time": { "attrs": 0.74, "codename": 1.23, "deposit": 0.0, "district": 0.14, "kvtree": 0.04, "moneygrade": 0.0, "nerToken": 2.7, "outline": 0.08, "pb_extract": 0.55, "person": 0.01, "prem": 0.07, "preprocess": 4.22, "product": 1.25, "product_attrs": 0.12, "roleRuleFinal": 0.02, "rolegrade": 0.01, "rule": 0.07, "rule_channel": 0.04, "rule_channel2": 0.25, "tableToText": 0.5400543594360352, "tendereeRuleRecall": 0.0, "time": 0.05, "total_unit_money": 0.0 }, "demand_info": { "data": [], "header": [], "header_col": [] }, "deposit_patment_way": "", "dict_enterprise": { "中华人民共和国": { "in_text": 0 }, "京东": { "in_text": 0 }, "京东自营店": { "in_text": 0 }, "人民法院": { "in_text": 0 }, "南京恒广工程管理有限公司": { "credit_code": "913201136749013829", "in_text": 0 }, "南京银行和燕路支行": { "in_text": 0 }, "天猫旗舰店": { "in_text": 0 }, "浙商银行": { "in_text": 2 }, "浙商银行南京分行": { "in_text": 2 }, "浙商银行股份有限公司": { "credit_code": "91330000761336668H", "in_text": 1 }, "浙商银行股份有限公司南京分行": { "credit_code": "91320000682167245K", "in_text": 2 }, "高新技术企业": { "credit_code": "91620100MA71X5MY2B", "in_text": 0 } }, "district": { "area": "华东", "city": "南京", "district": "未知", "is_in_text": false, "province": "江苏" }, "docchannel": { "docchannel": "招标公告", "doctype": "采招数据", "life_docchannel": "招标公告", "use_original_docchannel": 0 }, "docid": "", "doctitle_refine": "关于浙商银行股份有限公司南京分行南京地区2025年宣传物品集中项目", "exist_table": 1, "extract_count": 11, "fail_reason": "", "fingerprint": "md5=ebde4b7a154fc5a996093bad41a37b5a", "industry": { "class": "租赁和商务服务业", "class_name": "广告业", "subclass": "商务服务业" }, "is_deposit_project": false, "label_dic": { "mode_of_partipation": 1, "need_ca": 1, "need_performance": 1, "need_qualification": 1 }, "match_enterprise": [ { "from": "南京恒广工程管理有限公司", "to": "南京恒广工程管理有限公司", "type": "update" }, { "from": "", "to": "高新技术企业", "type": "add" } ], "match_enterprise_type": 3, "moneys": [], "moneys_attachment": [ 4750000.0, 600.0, 40000.0, 100000.0 ], "moneysource": "", "name": "浙商银行南京分行南京地区2025年度宣传物品集中采购入围项目", "nlp_enterprise": [ "浙商银行股份有限公司南京分行", "浙商银行股份有限公司", "浙商银行", "浙商银行南京分行" ], "nlp_enterprise_attachment": [ "浙商银行南京分行", "浙商银行股份有限公司南京分行", "南京恒广工程管理有限公司", "浙商银行", "南京银行和燕路支行", "中华人民共和国", "人民法院", "京东自营店", "天猫旗舰店", "京东", "高新技术企业" ], "pb": { "industry": "司法", "location": "南京地区", "projectDigest": "项目内容:三、采购方式:公开招标,四、投标人的资格条件,(1)投标人须为具有独立承担民事责任能力的法人或具备国家认可经营资,格的其他组织。(提供合法有效的营业执照复印件,并加盖公章),(2)投标人在最近三年内(2022年04月01日起至今,以法院判决书落款,日期为准)的经营活动中没有行贿犯罪、串通投标犯罪等重大违法记录;在“信,用中国(www.creditchina.gov.cn)”无失信惩戒等情况。(提供承诺书及信用,中国网站相关截图,并加盖公章),第2页(3)投标人须承诺:在最近三年内(2022年04月01日起至今)与浙商银行,的项目(如有)合作过程中,没有出现重大合同违约、泄露商业秘密或技术秘密", "project_name_refind": "浙商银行南京分行南京地区2025年宣传物品集中采购入围", "project_property": "新建" }, "pb_project_name": "浙商银行南京分行南京地区2025年宣传物品集中采购入围", "person_review": [], "pinmu_name": "", "policies": [], "prem": { "Project": { "code": "", "name": "浙商银行南京分行南京地区2025年度宣传物品集中采购入围项目", "roleList": [ { "address": "南京市鼓楼区中山北路9号", "linklist": [ [ "杜老师", "025-86823959" ], [ "杜宇烽", "025-86823959" ] ], "role_money": { "discount_ratio": "", "downward_floating_ratio": "", "floating_ratio": "", "money": 0, "money_unit": "" }, "role_name": "tenderee", "role_prob": 0.9499998331069947, "role_text": "浙商银行股份有限公司南京分行", "serviceTime": "" }, { "address": "南京市栖霞区马群街道紫东路2号紫东国际创意园C14栋601", "linklist": [ [ "朱工", "19951754271" ] ], "role_money": { "discount_ratio": "", "downward_floating_ratio": "", "floating_ratio": "", "money": 0, "money_unit": "" }, "role_name": "agency", "role_text": "南京恒广工程管理有限公司", "serviceTime": "" } ], "tendereeMoney": "4750000", "tendereeMoneyUnit": "万元", "uuid": "663f7f3b-f7b6-48fe-a91c-c98df446214b" } }, "process_time": "2025-04-23 11:13:53", "product": [ "宣传物品", "本招标项目采购期限一年。本招标项目采购的物品为浙商银行南京地区机构在客户宣传、营销活动中的实物礼品,包括食品粮油类、日用品类、数码电器类、文创用品类、家纺服饰类等品类。" ], "product_attrs": { "data": [ { "product": "本招标项目采购期限一年。本招标项目采购的物品为浙商银行南京地区机构在客户宣传、营销活动中的实物礼品,包括食品粮油类、日用品类、数码电器类、文创用品类、家纺服饰类等品类。", "quantity": "1", "quantity_unit": "项" } ], "header": [ "_数量______项目内容___" ], "header_col": [ "项目内容_数量" ] }, "project_contacts": [ [ "朱工", "19951754271" ] ], "project_label": { "标题": {}, "核心字段": { "营销物料": [ [ "宣传品", 1 ] ], "食品": [ [ "食品", 1 ] ] } }, "property_label": "", "proportion": "", "requirement": "二、项目内容:,十一、电子招投标的说明,1.1电子招投标:本项目以数据电文形式,依托“浙商银行数智采购一体化管理平台(https://ccgp.szcgpt.czbank.com)”进行招投标活动,不接受纸质投标文件;2投标准备:注册账号--点击“供应商注册”,进行采购供应商资料填写;申领CA数字证书---浙商银行数智采购一体化管理平台CA申领使用操作手册”;安装“浙商银行数智采购一体化管理投标客户端”--前往“浙商银行数智采购一体化管理平台-帮助中心-资料下载-浙商银行数智采购一体化管理投标客户端下载”进行下载并安装;3招标文件的获取:使用账号登录或者使用CA登录浙商银行数智采购一体化管理平台;进入“项目采购”应用,在获取采购文件菜单中选择项目,获取招标文件;4投标文件的制作:在“浙商银行数智采购一体化管理投标客户端”中完成“填写基本信息”、“导入投标文件”、“标书关联”、“标书检查”、“电子签名”、“生成电子标书”等操作;5采购人、采购代理机构将依托浙商银行数智采购一体化管理平台完成本项目的电子交易活动,平台不接受未按上述方式获取招标文件的供应商进行投标活动;6对未按上述方式获取招标文件的供应商对该文件提出的质疑,采购人或采购代理机构将不予处理;7不提供招标文件纸质版;8投标文件的传输递交:投标人在投标截止时间前将加密的投标文件上传至浙商银行数智采购一体化管理平台,还可以在投标截止时间前直接提交或者以邮政快递方式递交备份投标文件1份。备份投标文件的制作、存储、密封详见招标文件第三章投标人须知投标人须知前附表;9投标文件的解密:投标人按照平台提示和招标文件的规定在半小时内完成在线解密。通过“浙商银行数智采购一体化管理平台”上传递交的投标文件无法按时解密,投标供应商递交了备份投标文件的,以备份投标文件为依据,否则视为投标文件撤回。通过“浙商银行数智采购一体化管理平台”上传递交的投标文件已按时解密的,备份投标文件自动失效。投标人仅提交备份投标文件,未在电子交易平台传输递交投标文件的,投标无效;10具体操作指南:详见浙商银行数智采购一体化管理平台“帮助中心-资料下载-浙商银行数智采购一体化管理平台供应商操作手册”。2.若对项目采购电子交易系统操作有疑问,可平台服务热线95763获取热线服务帮助。CA问题联系电话(人工:汇信CA400-888-4636;天谷CA400-087-8198。附件信息:浙商银行南京分行南京地区2025年度宣传物品集中采购入围项目.pdf,1.4M。", "serviceTime": { "service_days": 365, "service_end": "", "service_start": "" }, "success": true, "time_bidclose": "2025-05-14 09:30:00", "time_bidopen": "2025-04-14 09:00:00", "time_bidstart": "", "time_commencement": "", "time_completion": "", "time_contractEnd": "", "time_contractStart": "", "time_earnestMoneyEnd": "", "time_earnestMoneyStart": "", "time_getFileEnd": "2025-04-21", "time_getFileStart": "2025-04-14 09:00:00", "time_listingEnd": "", "time_listingStart": "", "time_planned": "", "time_publicityEnd": "", "time_publicityStart": "", "time_registrationEnd": "", "time_registrationStart": "", "time_release": "", "time_signContract": "", "total_tendereeMoney": "4750000", "total_tendereeMoneyUnit": "万元", "version_date": "2025-04-22", "word_count": { "正文": 3019, "附件": 28802 } }
  696. ''')
  697. b = '''
  698. [{"fileTitle":"浙商银行南京分行南京地区2025年度宣传物品集中采购入围项目.pdf","fileMd5":"cc435162fb36014f339844ec91fec1e0","classification":"招标文件"}]
  699. '''
  700. c = "浙商银行数智采购平台"
  701. d = '2025-04-23'
  702. print(extractCount(a,b,c,d))