getAttributes.py 325 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313
  1. # from BiddingKG.dl.common.Utils import findAllIndex,debug,timeFormat,getCurrent_date,API_URL,uniform_package_name,money_process,getDigitsDic,isValidDate
  2. from BiddingKG.dl.common.Utils import *
  3. from BiddingKG.dl.interface.Entitys import PREM,Role,Entity
  4. from decimal import Decimal
  5. import re
  6. import copy
  7. import math
  8. import pandas as pd
  9. import os
  10. from scipy.optimize import linear_sum_assignment
  11. from BiddingKG.dl.interface.Entitys import Match
  12. import numpy as np
  13. import uuid
  14. import time,calendar
  15. from datetime import datetime
  16. import json
  17. from BiddingKG.dl.entityLink.entityLink import is_enterprise_exist
  18. def getTheRole(entity,role_list):
  19. '''
  20. @summary:根据实体名称拿到index
  21. @param:
  22. entity:实体名称
  23. role_list:角色list
  24. @return:该实体所在下标
  25. '''
  26. for role_index in range(len(role_list)):
  27. if entity in role_list[role_index]:
  28. return role_index
  29. return None
  30. dict_role_id = {"0":"tenderee",
  31. "1":"agency",
  32. "2":"win_tenderer",
  33. "3":"second_tenderer",
  34. "4":"third_tenderer"}
  35. role2id_dict = {"tenderee":0,
  36. "agency":1,
  37. "win_tenderer":2,
  38. "second_tenderer":3,
  39. "third_tenderer":4}
  40. def getPackage(packageList,sentence_index,begin_index,roleid,MAX_DIS=None,DIRECT=None):
  41. '''
  42. @param:
  43. packageList:文章的包的信息,包号-sent_index-词偏移-字偏移-[[前作用域句子,句内偏移],[后作用域句子,句内偏移]]-匹配集合
  44. sentence_index:实体所在的句子
  45. begin_index:实体所在句子的起始位置
  46. @return:公司实体所属的包
  47. @summary: 优化多标段,确定标段作用域之后,寻找作用域包含该实体的所有包,从前往后找到一个还没有该roleid的包返回,若找到的包都有roleid,则返回第一个,若没有找到包,返回None
  48. '''
  49. '''
  50. if len(packageList)==0:
  51. return None
  52. before_index = None
  53. after_index = None
  54. equal_index = None
  55. equal_count = 0
  56. for pack_index in range(len(packageList)):
  57. if packageList[pack_index][1]>sentence_index and after_index is None:
  58. after_index = pack_index
  59. if packageList[pack_index][1]<sentence_index:
  60. before_index = pack_index
  61. if packageList[pack_index][1]==sentence_index and equal_index is None:
  62. equal_index = pack_index
  63. #当前句子和之前句子未找到包
  64. if before_index is None and equal_index is None:
  65. return None
  66. else:
  67. if after_index is None:
  68. end_index = len(packageList)
  69. else:
  70. end_index = after_index
  71. #只在当前句子找到一个包号
  72. if end_index-max((before_index if before_index is not None else -1,equal_index if equal_index is not None else -1))==1:
  73. return packageList[end_index-1][0]
  74. else:
  75. for i in range(max((before_index if before_index is not None else -1,equal_index if equal_index is not None else -1)),end_index):
  76. if packageList[i][2]>int(begin_index):
  77. if packageList[i-1][4]:
  78. return packageList[i-1][0]
  79. else:
  80. if packageList[i][4]:
  81. return packageList[i-1][0]
  82. else:
  83. return packageList[i][0]
  84. return packageList[end_index-1][0]
  85. '''
  86. if len(packageList)==0:
  87. return None,False
  88. list_legalPack = []
  89. for pack_index in range(len(packageList)):
  90. if DIRECT=="L" and (packageList[pack_index]["sentence_index"]>sentence_index or (packageList[pack_index]["sentence_index"]==sentence_index and packageList[pack_index]["offsetWords_begin"]>begin_index)):
  91. continue
  92. if DIRECT=="R" and (packageList[pack_index]["sentence_index"]<sentence_index or (packageList[pack_index]["sentence_index"]==sentence_index and packageList[pack_index]["offsetwords_begin"]<begin_index)):
  93. continue
  94. if (packageList[pack_index]["scope"][0][0]<sentence_index or (packageList[pack_index]["scope"][0][0]==sentence_index and packageList[pack_index]["scope"][0][1]<=begin_index)) and (packageList[pack_index]["scope"][1][0]>sentence_index or (packageList[pack_index]["scope"][1][0]==sentence_index and packageList[pack_index]["scope"][1][1]>=begin_index)):
  95. if MAX_DIS is not None:
  96. if abs(sentence_index-packageList[pack_index]["sentence_index"])<=MAX_DIS:
  97. list_legalPack.append(pack_index)
  98. else:
  99. list_legalPack.append(pack_index)
  100. # if (packageList[pack_index]["scope"][0][0] < sentence_index
  101. # or (packageList[pack_index]["scope"][0][0] == sentence_index
  102. # and packageList[pack_index]["scope"][0][1] <= begin_index))
  103. # and (packageList[pack_index]["scope"][1][0] > sentence_index
  104. # or (packageList[pack_index]["scope"][1][0] == sentence_index
  105. # and packageList[pack_index]["scope"][1][1] >= begin_index)):
  106. # pass
  107. _flag = True
  108. for _index in list_legalPack:
  109. if roleid in packageList[_index]["hit"]:
  110. continue
  111. else:
  112. _flag = False
  113. packageList[_index]["hit"].add(roleid)
  114. return packageList[_index]["pointer"],_flag
  115. if len(list_legalPack)>0:
  116. return packageList[0]["pointer"],_flag
  117. return None,False
  118. #生成合法的组合
  119. def get_legal_comba(list_entity,dict_role_combination):
  120. #拿到一个包中所有合法的组合
  121. def circle_package(_dict_legal_combination):
  122. list_dict_role_first = []
  123. for _role in _dict_legal_combination:
  124. if len(list_dict_role_first)==0:
  125. for _entity in _dict_legal_combination[_role]:
  126. if _entity !="":
  127. list_dict_role_first.append({_role:_entity})
  128. else:
  129. list_dict_role_after = []
  130. _find_count = 0
  131. for _entity in _dict_legal_combination[_role]:
  132. if _entity !="":
  133. for _dict in list_dict_role_first:
  134. _flag = True
  135. for _key1 in _dict:
  136. if _entity==_dict[_key1]:
  137. #修改为招标人和代理人可以为同一个
  138. if str(_key1) in ["0","1"] and str(_role) in ["0","1"]:
  139. _flag = True
  140. else:
  141. _flag = False
  142. if _flag:
  143. _find_count += 1
  144. _new_dict = copy.copy(_dict)
  145. _new_dict[_role] = _entity
  146. if len(list_dict_role_after)>100000:
  147. break
  148. list_dict_role_after.append(_new_dict)
  149. else:
  150. # 2021/5/25 update,同一实体(entity_text)不同角色
  151. if len(list_dict_role_after) > 100000:
  152. break
  153. for _dict in list_dict_role_first:
  154. for _key1 in _dict:
  155. if _entity == _dict[_key1]:
  156. _new_dict = copy.copy(_dict)
  157. _new_dict.pop(_key1)
  158. _new_dict[_role] = _entity
  159. list_dict_role_after.append({_role:_entity})
  160. if len(list_dict_role_after)==0:
  161. pass
  162. else:
  163. list_dict_role_first.extend(list_dict_role_after)
  164. return list_dict_role_first
  165. def recursive_package(_dict_legal_combination,set_legal_entity,dict_one_selution,list_all_selution):
  166. last_layer = False
  167. #若是空组合则放回空
  168. if len(_dict_legal_combination.keys())==0:
  169. return []
  170. #递归到最后一层则修改状态
  171. if len(_dict_legal_combination.keys())==1:
  172. last_layer = True
  173. #取一个角色开始进行遍历
  174. _key_role = list(_dict_legal_combination.keys())[0]
  175. for item in _dict_legal_combination[_key_role]:
  176. copy_dict_one_selution = copy.copy(dict_one_selution)
  177. copy_dict_legal_combination = {}
  178. copy_set_legal_entity = copy.copy(set_legal_entity)
  179. #复制余下的所有角色,进行下一轮递归
  180. for _key in _dict_legal_combination.keys():
  181. if _key!=_key_role:
  182. copy_dict_legal_combination[_key] = _dict_legal_combination[_key]
  183. #修改为招标人和代理人可以为同一个
  184. if item !="":
  185. _flag = True
  186. if str(_key_role) in ["0","1"]:
  187. for _key_flag in copy_dict_one_selution:
  188. if _key_flag not in ["0","1"] and copy_dict_one_selution[_key_flag]==item:
  189. _flag = False
  190. else:
  191. for _key_flag in copy_dict_one_selution:
  192. if copy_dict_one_selution[_key_flag]==item:
  193. _flag = False
  194. if _flag:
  195. copy_dict_one_selution[_key_role] = item
  196. '''
  197. if item not in copy_set_legal_entity:
  198. if item !="":
  199. copy_dict_one_selution[_key_role] = item
  200. '''
  201. copy_set_legal_entity.add(item)
  202. if last_layer:
  203. list_all_selution.append(copy_dict_one_selution)
  204. else:
  205. recursive_package(copy_dict_legal_combination,copy_set_legal_entity,copy_dict_one_selution,list_all_selution)
  206. #递归匹配各个包的结果
  207. def recursive_packages(_dict_legal_combination,dict_one_selution,list_all_selution):
  208. last_layer = False
  209. if len(_dict_legal_combination.keys())==0:
  210. return []
  211. if len(_dict_legal_combination.keys())==1:
  212. last_layer = True
  213. _key_pack = list(_dict_legal_combination.keys())[0]
  214. for item in _dict_legal_combination[_key_pack]:
  215. copy_dict_one_selution = copy.copy(dict_one_selution)
  216. copy_dict_legal_combination = {}
  217. for _key in _dict_legal_combination.keys():
  218. if _key!=_key_pack:
  219. copy_dict_legal_combination[_key] = _dict_legal_combination[_key]
  220. for _key_role in item.keys():
  221. copy_dict_one_selution[_key_pack+"$$"+_key_role] = item[_key_role]
  222. if last_layer:
  223. list_all_selution.append(copy_dict_one_selution)
  224. else:
  225. recursive_packages(copy_dict_legal_combination,copy_dict_one_selution,list_all_selution)
  226. return list_all_selution
  227. #循环获取所有包组合
  228. def circle_pageages(_dict_legal_combination):
  229. list_all_selution = []
  230. for _key_pack in _dict_legal_combination.keys():
  231. list_key_selution = []
  232. for item in _dict_legal_combination[_key_pack]:
  233. _dict = dict()
  234. for _key_role in item.keys():
  235. _dict[_key_pack+"$$"+_key_role] = item[_key_role]
  236. list_key_selution.append(_dict)
  237. if len(list_all_selution)==0:
  238. list_all_selution = list_key_selution
  239. else:
  240. _list_all_selution = []
  241. for item_1 in list_all_selution:
  242. for item_2 in list_key_selution:
  243. _list_all_selution.append(dict(item_1,**item_2))
  244. list_all_selution = _list_all_selution
  245. return list_all_selution
  246. #拿到各个包解析之后的结果
  247. _dict_legal_combination = {}
  248. for packageName in dict_role_combination.keys():
  249. _list_all_selution = []
  250. # recursive_package(dict_role_combination[packageName], set(), {}, _list_all_selution)
  251. _list_all_selution = circle_package(dict_role_combination[packageName])
  252. '''
  253. # print("===1")
  254. # print(packageName)
  255. for item in _list_all_selution:
  256. # print(item)
  257. # print("===2")
  258. '''
  259. #去除包含子集
  260. list_all_selution_simple = []
  261. _list_set_all_selution = []
  262. for item_selution in _list_all_selution:
  263. item_set_selution = set()
  264. for _key in item_selution.keys():
  265. item_set_selution.add((_key,item_selution[_key]))
  266. _list_set_all_selution.append(item_set_selution)
  267. if len(_list_set_all_selution)>1000:
  268. _dict_legal_combination[packageName] = _list_all_selution
  269. continue
  270. for i in range(len(_list_set_all_selution)):
  271. be_included = False
  272. for j in range(len(_list_set_all_selution)):
  273. if i!=j:
  274. if len(set(_list_set_all_selution[i])&set(_list_set_all_selution[j]))==len(_list_set_all_selution[i]) and len(_list_set_all_selution[i])!=len(_list_set_all_selution[j]):
  275. be_included = True
  276. if not be_included:
  277. list_all_selution_simple.append(_list_all_selution[i])
  278. _dict_legal_combination[packageName] = list_all_selution_simple
  279. _list_final_comba = []
  280. #对各个包的结果进行排列组合
  281. _comba_count = 1
  282. for _key in _dict_legal_combination.keys():
  283. _comba_count *= len(_dict_legal_combination[_key])
  284. #如果过大,则每个包只取概率最大的那个
  285. dict_pack_entity_prob = get_dict_entity_prob(list_entity)
  286. if _comba_count>250:
  287. new_dict_legal_combination = dict()
  288. for _key_pack in _dict_legal_combination.keys():
  289. MAX_PROB = -1000
  290. _MAX_PROB_COMBA = None
  291. for item in _dict_legal_combination[_key_pack]:
  292. # print(_key_pack,item)
  293. _dict = dict()
  294. for _key in item.keys():
  295. _dict[str(_key_pack)+"$$"+str(_key)] = item[_key]
  296. _prob = getSumExpectation(dict_pack_entity_prob, _dict)
  297. if _prob>MAX_PROB:
  298. MAX_PROB = _prob
  299. _MAX_PROB_COMBA = [item]
  300. if _MAX_PROB_COMBA is not None:
  301. new_dict_legal_combination[_key_pack] = _MAX_PROB_COMBA
  302. _dict_legal_combination = new_dict_legal_combination
  303. #recursive_packages(_dict_legal_combination, {}, _list_final_comba)
  304. _list_final_comba = circle_pageages(_dict_legal_combination)
  305. #除了Project包(招标人和代理人),其他包是不会有冲突的
  306. #查看是否有一个实体出现在了Project包和其他包中,如有,要进行裁剪
  307. _list_real_comba = []
  308. for dict_item in _list_final_comba:
  309. set_project = set()
  310. set_other = set()
  311. for _key in list(dict_item.keys()):
  312. if _key.split("$$")[0]=="Project":
  313. set_project.add(dict_item[_key])
  314. else:
  315. set_other.add(dict_item[_key])
  316. set_common = set_project&set_other
  317. if len(set_common)>0:
  318. dict_project = {}
  319. dict_not_project = {}
  320. for _key in list(dict_item.keys()):
  321. if dict_item[_key] in set_common:
  322. if str(_key.split("$$")[0])=="Project":
  323. dict_project[_key] = dict_item[_key]
  324. else:
  325. dict_not_project[_key] = dict_item[_key]
  326. else:
  327. dict_project[_key] = dict_item[_key]
  328. dict_not_project[_key] = dict_item[_key]
  329. _list_real_comba.append(dict_project)
  330. _list_real_comba.append(dict_not_project)
  331. else:
  332. _list_real_comba.append(dict_item)
  333. return _list_real_comba
  334. def get_dict_entity_prob(list_entity,on_value=0.5):
  335. dict_pack_entity_prob = {}
  336. for in_attachment in [False,True]:
  337. identified_role = []
  338. if in_attachment==True:
  339. identified_role = [value[0] for value in dict_pack_entity_prob.values()]
  340. for entity in list_entity:
  341. if entity.entity_type in ['org','company'] and entity.in_attachment==in_attachment:
  342. values = entity.values
  343. role_prob = float(values[int(entity.label)])
  344. _key = entity.packageName+"$$"+str(entity.label)
  345. if role_prob>=on_value and str(entity.label)!="5":
  346. _key_prob = _key+"$text$"+entity.entity_text
  347. if in_attachment == True:
  348. role_prob = 0.8 if role_prob>0.8 else role_prob #附件的概率修改低点
  349. # if entity.entity_text in identified_role: # 2023/7/3 注释掉,选取概率最大的作为连接概率
  350. # continue
  351. if _key_prob in dict_pack_entity_prob:
  352. # new_prob = role_prob+dict_pack_entity_prob[_key_prob][1] if role_prob>0.9 else max(role_prob, dict_pack_entity_prob[_key_prob][1])
  353. # dict_pack_entity_prob[_key_prob] = [entity.entity_text, new_prob] #公司同角色多次出现概率累计
  354. if role_prob>dict_pack_entity_prob[_key_prob][1]:
  355. dict_pack_entity_prob[_key_prob] = [entity.entity_text,role_prob]
  356. else:
  357. dict_pack_entity_prob[_key_prob] = [entity.entity_text,role_prob]
  358. return dict_pack_entity_prob
  359. #计算合计期望
  360. def getSumExpectation(dict_pack_entity_prob,combination,on_value=0.5):
  361. '''
  362. expect = 0
  363. for entity in list_entity:
  364. if entity.entity_type in ['org','company']:
  365. values = entity.values
  366. role_prob = float(values[int(entity.label)])
  367. _key = entity.packageName+"$$"+str(entity.label)
  368. if role_prob>on_value and str(entity.label)!="5":
  369. if _key in combination.keys() and combination[_key]==entity.entity_text:
  370. expect += math.pow(role_prob,4)
  371. else:
  372. expect -= math.pow(role_prob,4)
  373. '''
  374. #修改为同一个实体只取对应包-角色的最大的概率值
  375. expect = 0
  376. dict_entity_prob = {}
  377. for _key_pack_entity in dict_pack_entity_prob:
  378. _key_pack = _key_pack_entity.split("$text$")[0]
  379. role_prob = dict_pack_entity_prob[_key_pack_entity][1]
  380. if _key_pack in combination.keys() and combination[_key_pack]==dict_pack_entity_prob[_key_pack_entity][0]:
  381. if _key_pack_entity in dict_entity_prob.keys():
  382. if dict_entity_prob[_key_pack_entity]<role_prob:
  383. dict_entity_prob[_key_pack_entity] = role_prob
  384. else:
  385. dict_entity_prob[_key_pack_entity] = role_prob
  386. else:
  387. if _key_pack_entity in dict_entity_prob.keys():
  388. if dict_entity_prob[_key_pack_entity]>-role_prob:
  389. dict_entity_prob[_key_pack_entity] = -role_prob
  390. else:
  391. dict_entity_prob[_key_pack_entity] = -role_prob
  392. # for entity in list_entity:
  393. # if entity.entity_type in ['org','company']:
  394. # values = entity.values
  395. # role_prob = float(values[int(entity.label)])
  396. # _key = entity.packageName+"$$"+str(entity.label)
  397. # if role_prob>=on_value and str(entity.label)!="5":
  398. # if _key in combination.keys() and combination[_key]==entity.entity_text:
  399. # _key_prob = _key+entity.entity_text
  400. # if _key_prob in dict_entity_prob.keys():
  401. # if dict_entity_prob[_key_prob]<role_prob:
  402. # dict_entity_prob[_key_prob] = role_prob
  403. # else:
  404. # dict_entity_prob[_key_prob] = role_prob
  405. # else:
  406. # _key_prob = _key+entity.entity_text
  407. # if _key_prob in dict_entity_prob.keys():
  408. # if dict_entity_prob[_key_prob]>-role_prob:
  409. # dict_entity_prob[_key_prob] = -role_prob
  410. # else:
  411. # dict_entity_prob[_key_prob] = -role_prob
  412. for _key in dict_entity_prob.keys():
  413. symbol = 1 if dict_entity_prob[_key]>0 else -1
  414. expect += symbol*math.pow(dict_entity_prob[_key],2)
  415. return expect
  416. def getRoleList(list_sentence,list_entity,on_value = 0.5):
  417. '''
  418. @summary: 搜索树,得到所有不矛盾的角色组合,取合计期望值最大的作为结果返回
  419. @param:
  420. list_sentence:文章所有的sentence
  421. list_entity:文章所有的实体
  422. on_value:概率阈值
  423. @return:文章的角色list
  424. '''
  425. pack = getPackagesFromArticle(list_sentence,list_entity)
  426. if pack is None:
  427. return None
  428. # PackageList,PackageSet,dict_PackageCode = pack
  429. PackageList,PackageSet,dict_PackageCode,main_body_pack = pack
  430. #拿到所有可能的情况
  431. dict_role_combination = {}
  432. tenderee_or_agency_set = set() # 记录所有预测为招标或代理的实体集合
  433. win_tenderer_set = set() # 记录所有预测为中标的实体集合
  434. # print(PackageList)
  435. #拿到各个实体的packageName,packageCode
  436. main_contain_winner = False # 2024/10/11 判断正文是否包含中标人
  437. for entity in list_entity:
  438. if entity.entity_type in ['org','company'] and entity.label==2 and entity.values[entity.label]>0.7 and entity.in_attachment==False:
  439. main_contain_winner = True
  440. break
  441. for entity in list_entity:
  442. if entity.entity_type in ['org','company']:
  443. #限制附件里角色values[label]最大概率prob
  444. max_prob = 0.85
  445. if str(entity.label)!="5" and entity.in_attachment:
  446. if entity.values[entity.label]>max_prob:
  447. entity.values[entity.label] = max_prob
  448. #过滤掉字数小于3个的实体
  449. if len(entity.entity_text)<=3:
  450. continue
  451. values = entity.values
  452. role_prob = float(values[int(entity.label)])
  453. if role_prob>=on_value and str(entity.label)!="5":
  454. if main_contain_winner and entity.in_attachment and entity.label in [2,3,4]: # 2024/10/11 正文包含中标人,不再提取附件中标人 避免 例:504046747 附件角色OCR错字变两个标段
  455. continue
  456. if str(entity.label) in ["0","1"]:
  457. packageName = "Project"
  458. else:
  459. if len(PackageSet)>0:
  460. packagePointer,_ = getPackage(PackageList,entity.sentence_index,entity.begin_index,"role-"+str(entity.label))
  461. if packagePointer is None:
  462. #continue
  463. packageName = "Project"
  464. # print(entity.entity_text, packageName,entity.sentence_index,entity.begin_index)
  465. else:
  466. #add pointer_pack
  467. entity.pointer_pack = packagePointer
  468. packageName = packagePointer.entity_text
  469. # print(entity.entity_text, packageName)
  470. else:
  471. packageName = "Project"
  472. find_flag = False
  473. if packageName in dict_PackageCode.keys():
  474. packageCode = dict_PackageCode[packageName]
  475. else:
  476. packageCode = ""
  477. entity.packageCode = packageCode
  478. role_name = dict_role_id.get(str(entity.label))
  479. entity.roleName = role_name
  480. entity.packageName = packageName
  481. if entity.packageName in dict_role_combination.keys():
  482. if str(entity.label) in dict_role_combination[entity.packageName].keys():
  483. dict_role_combination[entity.packageName][str(entity.label)].add(entity.entity_text)
  484. else:
  485. dict_role_combination[entity.packageName][str(entity.label)] = set([entity.entity_text])
  486. else:
  487. dict_role_combination[entity.packageName] = {}
  488. #初始化空值
  489. roleIds = [0,1,2,3,4]
  490. for _roleId in roleIds:
  491. dict_role_combination[entity.packageName][str(_roleId)] = set([""])
  492. dict_role_combination[entity.packageName][str(entity.label)].add(entity.entity_text)
  493. list_real_comba = get_legal_comba(list_entity,dict_role_combination)
  494. # print("===role_combination",dict_role_combination)
  495. # print("== real_comba",list_real_comba)
  496. #拿到最大期望值的组合
  497. max_index = 0
  498. max_expect = -100
  499. _index = 0
  500. dict_pack_entity_prob = get_dict_entity_prob(list_entity)
  501. for item_combination in list_real_comba:
  502. expect = getSumExpectation(dict_pack_entity_prob, item_combination)
  503. if expect>max_expect:
  504. max_index = _index
  505. max_expect = expect
  506. _index += 1
  507. RoleList = []
  508. RoleSet = set()
  509. if len(list_real_comba)>0:
  510. for _key in list_real_comba[max_index].keys():
  511. packageName = _key.split("$$")[0]
  512. label = _key.split("$$")[1]
  513. role_name = dict_role_id.get(str(label))
  514. entity_text = list_real_comba[max_index][_key]
  515. entity_prob = dict_pack_entity_prob.get(_key+'$text$'+entity_text, ['',0])[1]
  516. # entity_text = list_real_comba[max_index][_key][0]
  517. # entity_prob = list_real_comba[max_index][_key][1]
  518. if packageName in dict_PackageCode.keys():
  519. packagecode = dict_PackageCode.get(packageName)
  520. else:
  521. packagecode = ""
  522. RoleList.append(PREM(packageName,packagecode,role_name,entity_text,entity_prob,0,0.0,[]))
  523. if str(label) in ["0", "1"]:
  524. tenderee_or_agency_set.add(entity_text)
  525. elif str(label) in ["2"] and entity_prob > 0.8:
  526. win_tenderer_set.add(entity_text)
  527. # if len(list_real_comba) > 1 and label == '2': # 20240809 由于包号对应不上注销
  528. # multi_winner = []
  529. # for comba in list_real_comba:
  530. # tmp_ent = comba.get(_key, '')
  531. # tmp_prob = dict_pack_entity_prob.get(_key+'$text$'+tmp_ent, ['',0])[1]
  532. # if tmp_ent !='' and tmp_prob>0.8:
  533. # multi_winner.append(comba[_key])
  534. # if len(set(multi_winner)) > 1:
  535. # RoleList[-1].multi_winner = multi_winner
  536. # print('RoleList: ', RoleList)
  537. RoleSet.add(entity_text)
  538. #根据最优树来修正list_entity中角色对包的连接
  539. for _entity in list_entity:
  540. if _entity.pointer_pack is not None:
  541. _pack_name = _entity.pointer_pack.entity_text
  542. _find_flag = False
  543. for _prem in RoleList:
  544. if _prem.packageName==_pack_name and _prem.entity_text==_entity.entity_text:
  545. _find_flag = True
  546. if not _find_flag:
  547. _entity.pointer_pack = None
  548. return RoleList,RoleSet,PackageList,PackageSet,win_tenderer_set,tenderee_or_agency_set,main_body_pack
  549. def getPackageScopePattern():
  550. '''
  551. @summary: 获取包的作用域关键词
  552. '''
  553. df = pd.read_excel(os.path.dirname(__file__)+"/end.xls")
  554. pattern = "("
  555. for item in df["list_word"]:
  556. item = str(item).replace("(","\(").replace(")","\)").replace(".","\.").replace("[","\[").replace("]","\]").replace("-","\-")
  557. pattern += item+"|"
  558. pattern = pattern[:-1]+")[::是为]|业绩.{,30}标段[0-9A-Za-z一二三四五六七八九十]{0,3}|##attachment##"
  559. return pattern
  560. pattern_packageScope = getPackageScopePattern()
  561. def getPackagesFromArticle(list_sentence, list_entity):
  562. '''
  563. @param:
  564. list_sentence:文章的句子list
  565. @summary: 将包的信息插入list_entity中
  566. @return: type:list if [包号,句子index,词偏移,标段号] meaning:文章的包/标段信息
  567. '''
  568. if len(list_sentence) == 0:
  569. return None
  570. list_sentence.sort(key=lambda x: x.sentence_index)
  571. PackageList = []
  572. PackageList_scope = []
  573. PackageSet = set()
  574. dict_packageCode = dict()
  575. main_body_pack = set() # 2024/04/28 保存正文包号
  576. # package_number_pattern = re.compile(
  577. # '((施工|监理|监测|勘察|设计|劳务)(标段)?[0-9一二三四五六七八九十ⅠⅡⅢⅣⅤⅥⅦa-zA-Z]{,4}(标段?|包))|(([a-zA-Z]包[:)]?)?第?[0-9一二三四五六七八九十ⅠⅡⅢⅣⅤⅥⅦa-zA-Z]{1,4}标[段包]?)|((标[段号的包项]|([标分子]|合同|项目|采购|()包|包[组件号])[0-9一二三四五六七八九十ⅠⅡⅢⅣⅤⅥⅦA-Za-z]{1,4})|(([,;。、:(]|第)[0-9一二三四五六七八九十ⅠⅡⅢⅣⅤⅥⅦ]{1,4}分?包)|([a-zA-Z][0-9]{,3}分?[包标])|.{,1}((包组|包件|包号|分?包|标[段号的包]|子项目)编?号?[::]?[a-zA-Z0-9一二三四五六七八九十ⅠⅡⅢⅣⅤⅥⅦ-]+)|[,;。、:(]包[0-9一二三四五六七八九十ⅠⅡⅢⅣⅤⅥⅦ]{1,4}[^\w]') # 标号
  578. # package_number_pattern = re.compile(
  579. # '((施工|监理|监测|勘察|设计|劳务)(标段)?:?第?([一二三四五六七八九十]{1,3}|[ⅠⅡⅢⅣⅤⅥⅦ]{1,3}|[a-zA-Z0-9]{1,9}\-?[a-zA-Z0-9-]{,9})?[分子]?(标[段包项]?|包[组件标]?|合同[包段]))\
  580. # |(([a-zA-Z]包[:()]?)?第?([一二三四五六七八九十]{1,3}|[ⅠⅡⅢⅣⅤⅥⅦ]{1,3}|[a-zA-Z0-9]{1,9}\-?[a-zA-Z0-9-]{,9})[分子]?(标[段包项]?|合同[包段]))\
  581. # |(([,;。、:(]|第)?([一二三四五六七八九十]{1,3}|[ⅠⅡⅢⅣⅤⅥⅦ]{1,3}|[a-zA-Z0-9]{1,9}\-?[a-zA-Z0-9-]{,9})[分子]?(标[段包项]?|包[组件标]?|合同[包段]))\
  582. # |((标[段包项]|标段(包)|包[组件标]|[标分子(]包)(\[|【)?:?([一二三四五六七八九十]{1,3}|[ⅠⅡⅢⅣⅤⅥⅦ]{1,3}|[a-zA-Z0-9]{1,9}\-?[a-zA-Z0-9-]{,9}))\
  583. # |[,;。、:(](标的?|项目|子项目?)(\[|【)?:?([一二三四五六七八九十]+|[0-9]{1,9})\
  584. # |((([标分子(]|合同|项目|采购)包|[,。]标的|子项目|[分子]标|标[段包项]|包[组件标]?)编?号[::]?[a-zA-Z0-9一二三四五六七八九十ⅠⅡⅢⅣⅤⅥⅦ-]{1,9})\
  585. # |[,;。、:(]?(合同|分|子)?包:?([一二三四五六七八九十]{1,3}|[ⅠⅡⅢⅣⅤⅥⅦ]{1,3}|[a-zA-Z0-9]{1,9}\-?[a-zA-Z0-9-]{,9})')
  586. other_package_pattern = re.compile(
  587. '((项目|物资|设备|场次|标段|标的|产品)(名称)?)[::]([^,。]{2,50}?)[,。]') # # 2020/11/23 大网站规则 调整 package_N_name_pattern, package_N_name_pattern 中的项目 改为 子项目
  588. win_tenderer_pattern = re.compile('(中标候?选?人|供应商)(名称)?[::](.{2,25})[,。]') # 2020/11/23 大网站规则 调整
  589. model_pattern = re.compile('(型号|序号)[::]([^,。]{2,20})[,。]') # 2020/11/23 大网站规则 调整
  590. number_pattern = re.compile("[0-9A-Za-z一二三四五六七八九十ⅠⅡⅢⅣⅤⅥⅦ]{1,4}")
  591. package_code_pattern = re.compile("(?:编号[::]?\s*)([-\dA-Za-z\(\)]{1,20})")
  592. # 纯数字类型的包号统一,例如:'01','1'
  593. re_digital = re.compile("^\d+$")
  594. def changeIndexFromWordToWords(tokens, word_index):
  595. '''
  596. @summary:转换某个字的字偏移为词偏移
  597. '''
  598. before_index = 0
  599. after_index = 0
  600. for i in range(len(tokens)):
  601. after_index = after_index + len(tokens[i])
  602. if before_index <= word_index and after_index >= word_index:
  603. return i
  604. before_index = after_index
  605. package_names = []
  606. def extractPackageCode(tokens, word_index, size=20, pattern=package_code_pattern):
  607. '''
  608. @summary:抽取包附近的标段号
  609. @param:
  610. tokens:包所在句子的分词
  611. word_index:包所在字偏移
  612. size:左右各取多少个词
  613. pattern:提取标段号的正则
  614. @return: type:string,meaning:标段号
  615. '''
  616. index = changeIndexFromWordToWords(tokens, word_index)
  617. if index < size:
  618. begin = index
  619. else:
  620. begin = index - size
  621. if index + size > len(tokens):
  622. end = len(tokens)
  623. else:
  624. end = index + size
  625. # 拿到左右两边的词语组成短语
  626. text = "".join(tokens[begin:end])
  627. # 在短语中的字偏移
  628. new_word_index = word_index - len("".join(tokens[:begin]))
  629. min_distance = len(text)
  630. packageCode = None
  631. for the_iter in re.finditer(pattern, text):
  632. # 算出最小距离
  633. distance = min([abs(new_word_index - the_iter.span()[0]), abs(new_word_index - the_iter.span()[1])])
  634. if distance < min_distance:
  635. min_distance = distance
  636. packageCode = the_iter.group(1)
  637. return packageCode
  638. def get_package():
  639. PackageList_scope = []
  640. True_package = set()
  641. for i in range(len(list_sentence)):
  642. PackageList_item = []
  643. PackageList_item_scope = []
  644. content = list_sentence[i].sentence_text
  645. # content = content.replace('号,', '号:').replace(':', ':').replace('(', '(').replace(')', ')')
  646. # # .replace('-包',' 包').replace('包-', '包 ').replace('-标', ' 标').replace('标段-', '标段 ').replace('-合同包', ' 合同包') # 72760191 标段:№10
  647. # content = re.sub('[一二三四五六七八九十\d](标[段包项]|包[组件标])编号', ' 标段编号', content)
  648. #
  649. # for it in re.finditer('CA标|(每个?|所有|相关|个|各|不分)[分子]?(标[段包项]?|包[组件标]?|合同包)|(质量|责任)三包|包[/每]|标段(划分|范围)|(承|压缩|软|皮|书|挂)包\
  650. # |标[识注签贴配]|[商油]标号|第X包|第[一二三四五六七八九十]+至[一二三四五六七八九十]+(标[段包项]?|包[组件标]?|合同[包段])\
  651. # |\.(docx|doc|pdf|xlsx|xls|jpg)|[一二三四五]次|五金|\d+[年月]|[\d.,]+万?元|\d+\.\d+', content):
  652. # content = content.replace(it.group(0), ' ' * len(it.group(0)))
  653. # tokens = list_sentence[i].tokens
  654. # _names = []
  655. # for iter in re.finditer(package_number_pattern, content):
  656. # if re.search('(业绩|信誉要求):', content[:iter.start()]): # 前面有业绩或信誉的标段去掉
  657. # continue
  658. # # print('提取到标段:%s, 前后文:%s'%(iter.group(), content[iter.start()-5:iter.end()+5]))
  659. # if re.match('\d', iter.group(0)) and re.search('\d\.$', content[:iter.start()]): # 排除2.10标段3 5.4标段划分 这种情况
  660. # # print('过滤掉错误包:', iter.group())
  661. # continue
  662. # if re.search('[承每书/]包|XX|xx', iter.group(0)) or re.search('\d包[/每]\w|一包[0-9一二三四五六七八九十]+', content[iter.start():iter.end()+3]) or re.search('[a-zA-Z0-9一二三四五六七八九十ⅠⅡⅢⅣⅤⅥⅦ-]{6,}', iter.group(0)):
  663. # # print('过滤掉错误包:', iter.group())
  664. # continue
  665. # elif iter.end()+2 < len(content) and re.search('标准|标的物|标志|包装|划分|标书', content[iter.start():iter.end()+2]):
  666. # # print('过滤掉错误包:',iter.group())
  667. # continue
  668. # elif re.search('同一(标段?|包)', content[max(0, iter.start()-2):iter.end()]): # 不得参加同一标段
  669. # # print('过滤掉错误包:', iter.group())
  670. # continue
  671. # elif re.search('三包', content[max(0, iter.start()-2):iter.end()]) and re.search('第三包', content[max(0, iter.start()-2):iter.end()])==None: # 规规章和“三包”规定
  672. # # print('过滤掉错误包:', iter.group())
  673. # continue
  674. # elif re.search('[1-9]\d{2,}$|\d{4,}|^[1-9]\d{2,}|合同包[A-Za-z]{2,}', iter.group(0)):
  675. # # print('过滤掉错误包号5:', iter.group(0))
  676. # continue
  677. tokens = list_sentence[i].tokens
  678. _names = []
  679. for iter in find_package(content):
  680. temp_package_number = uniform_package_name(iter.group(0))
  681. True_package.add(temp_package_number)
  682. PackageList_item.append({"name": temp_package_number, "sentence_index": list_sentence[i].sentence_index,
  683. "offsetWords_begin": changeIndexFromWordToWords(tokens, iter.span()[0]),
  684. "offsetWord_begin": iter.span()[0], "offsetWord_end": iter.span()[1]})
  685. # PackageList_item.append([temp_package_number,i,changeIndexFromWordToWords(tokens,iter.span()[0]),iter.span()[0],iter.span()[1]])
  686. code = extractPackageCode(tokens, iter.span()[0])
  687. if code is not None:
  688. dict_packageCode[temp_package_number] = code
  689. PackageSet.add(temp_package_number)
  690. if not list_sentence[i].in_attachment: # 保存不在附件的包号
  691. main_body_pack.add(temp_package_number)
  692. # 识别packageScope
  693. for iter in re.finditer(pattern_packageScope, content):
  694. PackageList_item_scope.append({"name": "", "sentence_index": list_sentence[i].sentence_index,
  695. "offsetWords_begin": changeIndexFromWordToWords(tokens, iter.span()[0]),
  696. "offsetWord_begin": iter.span()[0], "offsetWord_end": iter.span()[1]})
  697. # PackageList_item_scope.append(["",i,changeIndexFromWordToWords(tokens,iter.span()[0]),iter.span()[0],iter.span()[1]])
  698. PackageList_item_scope = PackageList_item + PackageList_item_scope
  699. PackageList_item_scope.sort(key=lambda x: x["offsetWord_begin"])
  700. PackageList_scope = PackageList_scope + PackageList_item_scope
  701. PackageList_item.sort(key=lambda x: x["sentence_index"])
  702. return PackageList_scope, True_package
  703. def get_win_project():
  704. '''获取多个项目多个中标人的项目'''
  705. PackageList_scope = []
  706. True_package = set()
  707. # 2020/11/23 大网站规则 调整
  708. if len(PackageSet) == 0 and len(
  709. set([it.entity_text for it in list_entity if
  710. it.entity_type in ['org', 'company'] and it.label == 2])) > 1:
  711. for i in range(len(list_sentence)):
  712. PackageList_item = []
  713. PackageList_item_scope = []
  714. content = list_sentence[i].sentence_text
  715. tokens = list_sentence[i].tokens
  716. names = re.findall(other_package_pattern, content)
  717. N_names = re.findall(win_tenderer_pattern, content)
  718. if len(names) != 1 or len(N_names) != 1:
  719. continue
  720. for iter in re.finditer(other_package_pattern, content):
  721. temp_package_number = iter.group(4)
  722. xinghao = re.search(model_pattern, content)
  723. if xinghao:
  724. temp_package_number = temp_package_number + '+' + xinghao.group(2)
  725. # print('新正则采购包名补充',temp_package_number)
  726. if re.search(re_digital, temp_package_number):
  727. temp_package_number = str(int(temp_package_number))
  728. True_package.add(temp_package_number)
  729. PackageList_item.append(
  730. {"name": temp_package_number, "sentence_index": list_sentence[i].sentence_index,
  731. "offsetWords_begin": changeIndexFromWordToWords(tokens, iter.span()[0]),
  732. "offsetWord_begin": iter.span()[0], "offsetWord_end": iter.span()[1]})
  733. # PackageList_item.append([temp_package_number,i,changeIndexFromWordToWords(tokens,iter.span()[0]),iter.span()[0],iter.span()[1]])
  734. code = extractPackageCode(tokens, iter.span()[0])
  735. if code is not None:
  736. dict_packageCode[temp_package_number] = code
  737. PackageSet.add(temp_package_number)
  738. if not list_sentence[i].in_attachment: # 保存不在附件的包号
  739. main_body_pack.add(temp_package_number)
  740. # 识别packageScope
  741. for iter in re.finditer(pattern_packageScope, content):
  742. PackageList_item_scope.append({"name": "", "sentence_index": list_sentence[i].sentence_index,
  743. "offsetWords_begin": changeIndexFromWordToWords(tokens,
  744. iter.span()[0]),
  745. "offsetWord_begin": iter.span()[0],
  746. "offsetWord_end": iter.span()[1]})
  747. # PackageList_item_scope.append(["",i,changeIndexFromWordToWords(tokens,iter.span()[0]),iter.span()[0],iter.span()[1]])
  748. PackageList_item_scope = PackageList_item + PackageList_item_scope
  749. PackageList_item_scope.sort(key=lambda x: x["offsetWord_begin"])
  750. PackageList_scope = PackageList_scope + PackageList_item_scope
  751. PackageList_item.sort(key=lambda x: x["sentence_index"])
  752. return PackageList_scope, True_package
  753. def get_package_scope(PackageList_scope):
  754. PackageList = []
  755. pattern_punctuation = "[::()\(\),,。;;]"
  756. # print("===packageList_scope",PackageList_scope)
  757. for i in range(len(list_sentence)):
  758. for j in range(len(PackageList_scope)):
  759. if i == PackageList_scope[j]["sentence_index"] and PackageList_scope[j]["name"] != "":
  760. _flag = False
  761. left_str = list_sentence[i].sentence_text[
  762. PackageList_scope[j]["offsetWord_begin"] - 30:PackageList_scope[j][
  763. "offsetWord_begin"] + 1]
  764. right_str = list_sentence[i].sentence_text[
  765. PackageList_scope[j]["offsetWord_begin"]:PackageList_scope[j]["offsetWord_begin"] + 30]
  766. _left_find = re.findall(pattern_punctuation, left_str)
  767. _right_find = re.findall(pattern_punctuation, right_str)
  768. # print(left_str)
  769. if re.search("同", left_str[-1:]) is not None and PackageList_scope[j]["name"] == "一":
  770. continue
  771. if re.search("划分", right_str[:10]) is not None:
  772. continue
  773. if len(_left_find) > 0 and _left_find[-1] in [":", ":"]:
  774. _flag = True
  775. if len(_right_find) > 0 and _right_find[0] in [":", ":"]:
  776. _flag = True
  777. if _flag:
  778. scope_begin = [PackageList_scope[j]["sentence_index"],
  779. PackageList_scope[j]["offsetWords_begin"]]
  780. else:
  781. scope_begin = [PackageList_scope[j]["sentence_index"], 0] # 2024/10/10 改为包作用域开始位置为包号所在句子开头
  782. # if j == 0:
  783. # scope_begin = [0, 0]
  784. # else:
  785. # scope_begin = [PackageList_scope[j - 1]["sentence_index"],
  786. # PackageList_scope[j - 1]["offsetWords_begin"]]
  787. if j == len(PackageList_scope) - 1:
  788. scope_end = [list_sentence[-1].sentence_index,
  789. changeIndexFromWordToWords(list_sentence[-1].tokens,
  790. len(list_sentence[
  791. -1].sentence_text))]
  792. else:
  793. scope_end = [PackageList_scope[j + 1]["sentence_index"],
  794. PackageList_scope[j + 1]["offsetWords_begin"]]
  795. if j>0 and PackageList_scope[j - 1]["sentence_index"] == PackageList_scope[j]["sentence_index"] and \
  796. PackageList_scope[j - 1]["offsetWord_begin"] <= PackageList_scope[j]["offsetWord_begin"] and \
  797. PackageList_scope[j - 1]["offsetWord_end"] >= PackageList_scope[j]["offsetWord_end"]:
  798. continue
  799. # add package to entity
  800. _pack_entity = Entity(doc_id=list_sentence[0].doc_id, entity_id="%s_%s_%s_%s" % (
  801. list_sentence[0].doc_id, i, PackageList_scope[j]["offsetWord_begin"],
  802. PackageList_scope[j]["offsetWord_begin"]), entity_text=PackageList_scope[j]["name"],
  803. entity_type="package", sentence_index=PackageList_scope[j]["sentence_index"],
  804. begin_index=changeIndexFromWordToWords(list_sentence[i].tokens,
  805. PackageList_scope[j][
  806. "offsetWord_begin"]),
  807. end_index=changeIndexFromWordToWords(list_sentence[i].tokens,
  808. PackageList_scope[j]["offsetWord_end"]),
  809. wordOffset_begin=PackageList_scope[j]["offsetWord_begin"],
  810. wordOffset_end=PackageList_scope[j]["offsetWord_end"],
  811. in_attachment=list_sentence[i].in_attachment)
  812. list_entity.append(_pack_entity)
  813. copy_pack = copy.copy(PackageList_scope[j])
  814. copy_pack["scope"] = [scope_begin, scope_end]
  815. copy_pack["hit"] = set()
  816. copy_pack["pointer"] = _pack_entity
  817. PackageList.append(copy_pack)
  818. return PackageList
  819. PackageList_scope, True_package = get_package()
  820. # PackageList_scope2, True_package2 = get_win_project() # 20240508 与表格提取重复,去掉
  821. # if len(True_package2) > 2: # 同时包含多标段及多中标人的
  822. # PackageList_scope = PackageList_scope + PackageList_scope2
  823. PackageList = get_package_scope(PackageList_scope)
  824. # if len(PackageSet)<2: # 20230922只提取到一个包号的去掉,都放在默认包project 2024/02/02 注释掉,防止多标段每篇公告只公布一个标段的没法提取标段号
  825. # return [], set(), {}
  826. return PackageList, PackageSet, dict_packageCode, main_body_pack
  827. # km配对方法
  828. def dispatch(match_list):
  829. main_roles = list(set([match.main_role for match in match_list]))
  830. # print('main_roles',[i.entity_text for i in main_roles])
  831. attributes = list(set([match.attribute for match in match_list]))
  832. # try:
  833. # print('attributes',[i.entity_text for i in attributes])
  834. # except:
  835. # pass
  836. label = np.zeros(shape=(len(main_roles), len(attributes)))
  837. for match in match_list:
  838. main_role = match.main_role
  839. attribute = match.attribute
  840. value = match.value
  841. label[main_roles.index(main_role), attributes.index(attribute)] = value + 10000
  842. # print(label)
  843. gragh = -label
  844. # km算法
  845. row, col = linear_sum_assignment(gragh)
  846. max_dispatch = [(i, j) for i, j, value in zip(row, col, gragh[row, col]) if value]
  847. # return [Match(main_roles[row], attributes[col]) for row, col in max_dispatch]
  848. return [(main_roles[row], attributes[col]) for row, col in max_dispatch]
  849. from BiddingKG.dl.common.Utils import getUnifyMoney
  850. from BiddingKG.dl.interface.modelFactory import Model_relation_extraction
  851. relationExtraction_model = Model_relation_extraction()
  852. def findAttributeAfterEntity(PackDict,roleSet,PackageList,PackageSet,list_sentence,list_entity,list_outline,winter_scope,on_value = 0.5,on_value_person=0.5,sentence_len=4):
  853. '''
  854. @param:
  855. PackDict:文章包dict
  856. roleSet:文章所有角色的公司名称
  857. PackageList:文章的包信息
  858. PackageSet:文章所有包的名称
  859. list_entity:文章所有经过模型处理的实体
  860. on_value:金额模型的阈值
  861. on_value_person:联系人模型的阈值
  862. sentence_len:公司和属性间隔句子的最大长度
  863. @return:添加了属性信息的角色list
  864. '''
  865. #根据roleid添加金额到rolelist中
  866. def addMoneyByRoleid(packDict,packageName,roleid,money,money_prob):
  867. for i in range(len(packDict[packageName]["roleList"])):
  868. if packDict[packageName]["roleList"][i].role_name==dict_role_id.get(str(roleid)):
  869. if money_prob>packDict[packageName]["roleList"][i].money_prob:
  870. packDict[packageName]["roleList"][i].money = money
  871. packDict[packageName]["roleList"][i].money_prob = money_prob
  872. return packDict
  873. #根据实体名称添加金额到rolelist中
  874. def addMoneyByEntity(packDict,packageName,entity,money,money_prob):
  875. for i in range(len(packDict[packageName]["roleList"])):
  876. if packDict[packageName]["roleList"][i].entity_text==entity:
  877. # if money_prob>packDict[packageName]["roleList"][i].money_prob:
  878. # packDict[packageName]["roleList"][i].money = money
  879. # packDict[packageName]["roleList"][i].money_prob = money_prob
  880. if packDict[packageName]["roleList"][i].money_prob==0 : # 2021/7/20第一次更新金额
  881. if money.notes == '单价':
  882. packDict[packageName]["roleList"][i].unit_price = money.entity_text
  883. else:
  884. packDict[packageName]["roleList"][i].money = money.entity_text
  885. packDict[packageName]["roleList"][i].money_prob = money_prob
  886. packDict[packageName]["roleList"][i].money_unit = money.money_unit
  887. elif money_prob>packDict[packageName]["roleList"][i].money_prob+0.2 or (money.notes in ['大写'] and money.in_attachment==False): # 2021/7/20改为优先选择大写金额,
  888. # print('已连接金额概率:money_prob:',packDict[packageName]["roleList"][i].money_prob)
  889. # print('链接金额备注 ',money.notes, money.entity_text, money.values)
  890. if money.notes == '单价':
  891. packDict[packageName]["roleList"][i].unit_price = money.entity_text
  892. else:
  893. packDict[packageName]["roleList"][i].money = money.entity_text
  894. packDict[packageName]["roleList"][i].money_prob = money_prob
  895. packDict[packageName]["roleList"][i].money_unit = money.money_unit
  896. # print('链接中的金额:{0}, 单位:{1}'.format(money.entity_text, money.money_unit))
  897. return packDict
  898. def addRatioByEntity(packDict,packageName,entity,ratio):
  899. for i in range(len(packDict[packageName]["roleList"])):
  900. if packDict[packageName]["roleList"][i].entity_text==entity:
  901. packDict[packageName]["roleList"][i].ratio = ratio.ratio_value
  902. def addServiceTimeByEntity(packDict,packageName,entity,serviceTime):
  903. for i in range(len(packDict[packageName]["roleList"])):
  904. if packDict[packageName]["roleList"][i].entity_text==entity and not packDict[packageName]["roleList"][i].serviceTime:
  905. # packDict[packageName]["roleList"][i].serviceTime = serviceTime.entity_text
  906. packDict[packageName]["roleList"][i].serviceTime = extract_serviceTime(serviceTime.entity_text,"")
  907. #根据实体名称得到角色
  908. def getRoleWithText(packDict,entity_text):
  909. for pack in packDict.keys():
  910. for i in range(len(packDict[pack]["roleList"])):
  911. if packDict[pack]["roleList"][i].entity_text==entity_text:
  912. return packDict[pack]["roleList"][i].role_name
  913. def doesEntityOrLinkedEntity_inRoleSet(entity,RoleSet):
  914. _list_entitys = [entity]+entity.linked_entitys
  915. for _entity in _list_entitys:
  916. if _entity.entity_text in RoleSet:
  917. return True
  918. p_entity = 0
  919. # 2021/7/19 顺序比较金额,前面是后面的一万倍则把前面金额/10000
  920. # money_list = [it for it in list_entity if it.entity_type=="money"]
  921. # for i in range(len(money_list)-1):
  922. # for j in range(1, len(money_list)):
  923. # if (float(money_list[i].entity_text) > 5000000000 or money_list[j].notes=='大写') and \
  924. # Decimal(money_list[i].entity_text)/Decimal(money_list[j].entity_text)==10000:
  925. # money_list[i].entity_text = str(Decimal(money_list[i].entity_text)/10000)
  926. # # print('连接前修改大于50亿金额:前面是后面的一万倍则把前面金额/10000')
  927. '''同样金额同时有元及万元单位的,把万元的金额改为元'''
  928. wanyuan = []
  929. yuan = []
  930. for it in list_entity:
  931. if it.entity_type == "money" and float(it.entity_text)>1000000: # 20240523 修改为百万以上金额才对比万倍关系,其他又行业限额纠正避免有些万元单位提取不到从而被除一万 例:52435607 最高限价(万元):22679.32 蜀冈招标控制价22679.32工程地点南路西侧(万元)
  932. if it.money_unit == '万元' or float(it.entity_text)>5000000000:
  933. wanyuan.append(it)
  934. if it.money_unit == '元' or float(it.entity_text)<5000000:
  935. yuan.append(it)
  936. if wanyuan != [] and yuan != []:
  937. for m1 in wanyuan:
  938. for m2 in yuan:
  939. if Decimal(m1.entity_text)/Decimal(m2.entity_text) == 10000:
  940. m1.entity_text = m2.entity_text
  941. #遍历所有实体
  942. # while(p_entity<len(list_entity)):
  943. # entity = list_entity[p_entity]
  944. '''
  945. #招标金额从后往前找
  946. if entity.entity_type=="money":
  947. if entity.values[entity.label]>=on_value:
  948. if str(entity.label)=="0":
  949. packagePointer,_ = getPackage(PackageList,entity.sentence_index,entity.begin_index,"money-"+str(entity.label))
  950. if packagePointer is None:
  951. packageName = "Project"
  952. else:
  953. packageName = packagePointer.entity_text
  954. addMoneyByRoleid(PackDict, packageName, "0", entity.entity_text, entity.values[entity.label])
  955. '''
  956. ''' # 2020/11/25 与下面的联系人连接步骤重复,取消
  957. if entity.entity_type=="person":
  958. if entity.values[entity.label]>=on_value_person:
  959. if str(entity.label)=="1":
  960. for i in range(len(PackDict["Project"]["roleList"])):
  961. if PackDict["Project"]["roleList"][i].role_name=="tenderee":
  962. PackDict["Project"]["roleList"][i].linklist.append((entity.entity_text,entity.person_phone))
  963. # add pointer_person
  964. for _entity in list_entity:
  965. if dict_role_id.get(str(_entity.label))=="tenderee":
  966. for i in range(len(PackDict["Project"]["roleList"])):
  967. if PackDict["Project"]["roleList"][i].entity_text==_entity.entity_text and PackDict["Project"]["roleList"][i].role_name=="tenderee":
  968. _entity.pointer_person = entity
  969. elif str(entity.label)=="2":
  970. for i in range(len(PackDict["Project"]["roleList"])):
  971. if PackDict["Project"]["roleList"][i].role_name=="agency":
  972. PackDict["Project"]["roleList"][i].linklist.append((entity.entity_text,entity.person_phone))
  973. # add pointer_person
  974. for _entity in list_entity:
  975. if dict_role_id.get(str(_entity.label))=="agency":
  976. for i in range(len(PackDict["Project"]["roleList"])):
  977. if PackDict["Project"]["roleList"][i].entity_text==_entity.entity_text and PackDict["Project"]["roleList"][i].role_name=="agency":
  978. _entity.pointer_person = entity
  979. '''
  980. # #金额往前找实体
  981. # if entity.entity_type=="money":
  982. # if entity.values[entity.label]>=on_value:
  983. # p_entity_money= p_entity
  984. # entity_money = list_entity[p_entity_money]
  985. # if len(PackageSet)>0:
  986. # packagePointer,_ = getPackage(PackageList,entity_money.sentence_index,entity_money.begin_index,"money-"+str(entity_money.entity_text)+"-"+str(entity_money.label))
  987. # if packagePointer is None:
  988. # packageName_entity = "Project"
  989. # else:
  990. # packageName_entity = packagePointer.entity_text
  991. # else:
  992. # packageName_entity = "Project"
  993. # while(p_entity_money>0):
  994. # entity_before = list_entity[p_entity_money]
  995. # if entity_before.entity_type in ['org','company']:
  996. # if str(entity_before.label)=="1":
  997. # addMoneyByEntity(PackDict, packageName_entity, entity_before.entity_text, entity_money.entity_text, entity_money.values[entity_money.label])
  998. # #add pointer_money
  999. # entity_before.pointer_money = entity_money
  1000. # break
  1001. # p_entity_money -= 1
  1002. #如果实体属于角色集合,则往后找属性
  1003. # if doesEntityOrLinkedEntity_inRoleSet(entity, roleSet):
  1004. #
  1005. # p_entity += 1
  1006. # #循环查找符合的属性
  1007. # while(p_entity<len(list_entity)):
  1008. #
  1009. # entity_after = list_entity[p_entity]
  1010. # if entity_after.sentence_index-entity.sentence_index>=sentence_len:
  1011. # p_entity -= 1
  1012. # break
  1013. # #若是遇到公司实体,则跳出循环
  1014. # if entity_after.entity_type in ['org','company']:
  1015. # p_entity -= 1
  1016. # break
  1017. # if entity_after.values is not None:
  1018. # if entity_after.entity_type=="money":
  1019. # if entity_after.values[entity_after.label]>=on_value:
  1020. # '''
  1021. # #招标金额从后往前找
  1022. # if str(entity_after.label)=="0":
  1023. # packagePointer,_ = getPackage(PackageList,entity.sentence_index,entity.begin_index,"money-"+str(entity.label))
  1024. # if packagePointer is None:
  1025. # packageName = "Project"
  1026. # else:
  1027. # packageName = packagePointer.entity_text
  1028. # addMoneyByRoleid(PackDict, packageName, "0", entity_after.entity_text, entity_after.values[entity_after.label])
  1029. # '''
  1030. # if str(entity_after.label)=="1":
  1031. # #print(entity_after.entity_text,entity.entity_text)
  1032. # _list_entitys = [entity]+entity.linked_entitys
  1033. # if len(PackageSet)>0:
  1034. # packagePointer,_ = getPackage(PackageList,entity_after.sentence_index,entity_after.begin_index,"money-"+str(entity_after.entity_text)+"-"+str(entity_after.label))
  1035. # if packagePointer is None:
  1036. # packageName_entity = "Project"
  1037. # else:
  1038. # packageName_entity = packagePointer.entity_text
  1039. # else:
  1040. # packageName_entity = "Project"
  1041. # if str(entity.label) in ["2","3","4"]:
  1042. # # addMoneyByEntity(PackDict, packageName_entity, entity.entity_text, entity_after.entity_text, entity_after.values[entity_after.label])
  1043. # if entity_after.notes == '单价' or float(entity_after.entity_text)<5000: #2021/12/17 调整小金额阈值,避免203608823.html 两次金额一次万元没提取到的情况
  1044. # addMoneyByEntity(PackDict, packageName_entity, entity.entity_text, entity_after,
  1045. # 0.5)
  1046. # entity.pointer_money = entity_after
  1047. # # print('role zhao money', entity.entity_text, '中标金额:', entity_after.entity_text)
  1048. # else:
  1049. # addMoneyByEntity(PackDict, packageName_entity, entity.entity_text, entity_after,
  1050. # entity_after.values[entity_after.label])
  1051. # entity.pointer_money = entity_after
  1052. # # print('role zhao money', entity.entity_text, '中标金额:', entity_after.entity_text)
  1053. # if entity_after.values[entity_after.label]>0.6:
  1054. # break # 2021/7/16 新增,找到中标金额,非单价即停止,不再往后找金额
  1055. # #add pointer_money
  1056. # # entity.pointer_money = entity_after
  1057. # # print('role zhao money', entity.entity_text, '中标金额:', entity_after.entity_text)
  1058. # # if entity_after.notes!='单价':
  1059. # # break # 2021/7/16 新增,找到中标金额即停止,不再往后找金额
  1060. # '''
  1061. # if entity_after.entity_type=="person":
  1062. # if entity_after.values[entity_after.label]>=on_value_person:
  1063. # if str(entity_after.label)=="1":
  1064. # for i in range(len(roleList)):
  1065. # if roleList[i].role_name=="tenderee":
  1066. # roleList[i].linklist.append((entity_after.entity_text,entity_after.person_phone))
  1067. # elif str(entity_after.label)=="2":
  1068. # for i in range(len(roleList)):
  1069. # if roleList[i].role_name=="agency":
  1070. # roleList[i].linklist.append((entity_after.entity_text,entity_after.person_phone))
  1071. # elif str(entity_after.label)=="3":
  1072. # _list_entitys = [entity]+entity.linked_entitys
  1073. # for _entity in _list_entitys:
  1074. # for i in range(len(roleList)):
  1075. # if roleList[i].entity_text==_entity.entity_text:
  1076. # if entity_after.sentence_index-_entity.sentence_index>1 and len(roleList[i].linklist)>0:
  1077. # break
  1078. # roleList[i].linklist.append((entity_after.entity_text,entity_after.person_phone))
  1079. # '''
  1080. #
  1081. # p_entity += 1
  1082. #
  1083. # p_entity += 1
  1084. # 记录每句的分词数量
  1085. tokens_num_dict = dict()
  1086. last_tokens_num = 0
  1087. for sentence in list_sentence:
  1088. _index = sentence.sentence_index
  1089. if _index == 0:
  1090. tokens_num_dict[_index] = 0
  1091. else:
  1092. tokens_num_dict[_index] = tokens_num_dict[_index - 1] + last_tokens_num
  1093. last_tokens_num = len(sentence.tokens)
  1094. attribute_type = ['money','serviceTime','ratio']# 'money'仅指“中投标金额”
  1095. for link_attribute in attribute_type:
  1096. temp_entity_list = []
  1097. if link_attribute=="money":
  1098. temp_entity_list = [ent for ent in list_entity if (ent.entity_type in ['org','company'] and ent.label in [2,3,4]) or
  1099. (ent.entity_type=='money' and ent.label==1 and ent.values[ent.label]>=0.5)]
  1100. # 删除重复的‘中投标金额’,一般为大小写两种样式
  1101. drop_tendererMoney = []
  1102. for ent_idx in range(len(temp_entity_list)-1):
  1103. entity = temp_entity_list[ent_idx]
  1104. if entity.entity_type=='money':
  1105. next_entity = temp_entity_list[ent_idx+1]
  1106. if next_entity.entity_type=='money':
  1107. if getUnifyMoney(entity.entity_text)==getUnifyMoney(next_entity.entity_text):
  1108. if (tokens_num_dict[next_entity.sentence_index] + next_entity.begin_index) - (
  1109. tokens_num_dict[entity.sentence_index] + entity.end_index) < 10:
  1110. drop_tendererMoney.append(next_entity)
  1111. for _drop in drop_tendererMoney:
  1112. temp_entity_list.remove(_drop)
  1113. elif link_attribute=="serviceTime":
  1114. temp_entity_list = [ent for ent in list_entity if (ent.entity_type in ['org','company'] and ent.label in [2,3,4]) or
  1115. ent.entity_type=='serviceTime']
  1116. elif link_attribute=="ratio":
  1117. temp_entity_list = [ent for ent in list_entity if (ent.entity_type in ['org','company'] and ent.label in [2,3,4]) or
  1118. ent.entity_type=='ratio']
  1119. temp_entity_list = sorted(temp_entity_list,key=lambda x: (x.sentence_index, x.begin_index))
  1120. temp_match_list = []
  1121. for ent_idx in range(len(temp_entity_list)):
  1122. entity = temp_entity_list[ent_idx]
  1123. if entity.entity_type in ['org','company']:
  1124. match_nums = 0
  1125. tenderer_nums = 0 #经过其他中投标人的数量
  1126. byNotTenderer_match_nums = 0 #跟在中投标人后面的属性
  1127. for after_index in range(ent_idx + 1, min(len(temp_entity_list), ent_idx + 4)):
  1128. after_entity = temp_entity_list[after_index]
  1129. if entity.in_attachment != after_entity.in_attachment: # 正文与附件的不能相连
  1130. break
  1131. if after_entity.entity_type == link_attribute:
  1132. distance = (tokens_num_dict[after_entity.sentence_index] + after_entity.begin_index) - (
  1133. tokens_num_dict[entity.sentence_index] + entity.end_index)
  1134. sentence_distance = after_entity.sentence_index - entity.sentence_index
  1135. value = (-1 / 2 * (distance ** 2)) / 10000
  1136. if link_attribute == "money":
  1137. if after_entity.notes == '单价':
  1138. value = value * 100
  1139. if sentence_distance == 0:
  1140. if distance < 100:
  1141. # value = (-1 / 2 * (distance ** 2)) / 10000
  1142. temp_match_list.append(Match(entity, after_entity, value))
  1143. match_nums += 1
  1144. if not tenderer_nums:
  1145. byNotTenderer_match_nums += 1
  1146. else:
  1147. break
  1148. else:
  1149. if distance < 60:
  1150. # value = (-1 / 2 * (distance ** 2)) / 10000
  1151. temp_match_list.append(Match(entity, after_entity, value))
  1152. match_nums += 1
  1153. if not tenderer_nums:
  1154. byNotTenderer_match_nums += 1
  1155. else:
  1156. break
  1157. else:
  1158. tenderer_nums += 1
  1159. #前向查找属性
  1160. if ent_idx!=0 and (not match_nums or not byNotTenderer_match_nums):
  1161. previous_entity = temp_entity_list[ent_idx - 1]
  1162. if previous_entity.entity_type == link_attribute:
  1163. # if previous_entity.sentence_index == entity.sentence_index:
  1164. distance = (tokens_num_dict[entity.sentence_index] + entity.begin_index) - (
  1165. tokens_num_dict[previous_entity.sentence_index] + previous_entity.end_index)
  1166. if distance < 40:
  1167. # 前向 没有 /10000
  1168. value = (-1 / 2 * (distance ** 2))
  1169. temp_match_list.append(Match(entity, previous_entity, value))
  1170. # km算法分配求解
  1171. dispatch_result = dispatch(temp_match_list)
  1172. dispatch_result = sorted(dispatch_result, key=lambda x: (x[0].sentence_index,x[0].begin_index))
  1173. for match in dispatch_result:
  1174. _entity = match[0]
  1175. _attribute = match[1]
  1176. if link_attribute=='money':
  1177. _entity.pointer_money = _attribute
  1178. packagePointer, _ = getPackage(PackageList, _attribute.sentence_index, _attribute.begin_index,
  1179. "money-" + str(_attribute.entity_text) + "-" + str(_attribute.label))
  1180. # print(_entity.entity_text,_attribute.entity_text)
  1181. if packagePointer is None:
  1182. packageName_entity = "Project"
  1183. else:
  1184. packageName_entity = packagePointer.entity_text
  1185. if _attribute.notes == '单价' or float(_attribute.entity_text) < 5000: # 2021/12/17 调整小金额阈值,避免203608823.html 两次金额一次万元没提取到的情况
  1186. # print(packageName_entity,_attribute.entity_text, _attribute.values[_attribute.label])
  1187. addMoneyByEntity(PackDict, packageName_entity, _entity.entity_text, _attribute,0.5)
  1188. else:
  1189. # print(packageName_entity,_attribute.entity_text, _attribute.values[_attribute.label])
  1190. addMoneyByEntity(PackDict, packageName_entity, _entity.entity_text, _attribute,
  1191. _attribute.values[_attribute.label])
  1192. elif link_attribute=='serviceTime':
  1193. _entity.pointer_serviceTime = _attribute
  1194. packagePointer, _ = getPackage(PackageList, _attribute.sentence_index, _attribute.begin_index,
  1195. "serviceTime-" + str(_attribute.entity_text) + "-" + str(_attribute.label))
  1196. if packagePointer is None:
  1197. packageName_entity = "Project"
  1198. else:
  1199. packageName_entity = packagePointer.entity_text
  1200. addServiceTimeByEntity(PackDict, packageName_entity, _entity.entity_text, _attribute)
  1201. elif link_attribute=='ratio':
  1202. _entity.pointer_ratio = _attribute
  1203. packagePointer, _ = getPackage(PackageList, _attribute.sentence_index, _attribute.begin_index,
  1204. "ratio-" + str(_attribute.entity_text) + "-" + str(_attribute.label))
  1205. if packagePointer is None:
  1206. packageName_entity = "Project"
  1207. else:
  1208. packageName_entity = packagePointer.entity_text
  1209. addRatioByEntity(PackDict, packageName_entity, _entity.entity_text, _attribute)
  1210. ''''''
  1211. # 通过模型分类的招标/代理联系人
  1212. list_sentence = sorted(list_sentence, key=lambda x: x.sentence_index)
  1213. person_list = [entity for entity in list_entity if entity.entity_type == 'person' and entity.label in [1, 2]]
  1214. tenderee_contact = set()
  1215. tenderee_phone = set()
  1216. agency_contact = set()
  1217. agency_phone = set()
  1218. winter_contact = set()
  1219. rule_winter_phone = set()
  1220. tenderee_entity_set = set()
  1221. agency_entity_set = set()
  1222. for _person in person_list:
  1223. if _person.label == 1:
  1224. tenderee_contact.add(_person.entity_text)
  1225. if _person.label == 2:
  1226. agency_contact.add(_person.entity_text)
  1227. for _entity in [entity for entity in list_entity if entity.entity_type in ['company','org']]:
  1228. if _entity.label==0:
  1229. tenderee_entity_set.add(_entity.entity_text)
  1230. elif _entity.label==1:
  1231. agency_entity_set.add(_entity.entity_text)
  1232. # 正则匹配无 '主体/联系人' 的电话
  1233. # 例:"采购人联系方式:0833-5226788,"
  1234. phone_pattern = '(1[3-9][0-9][-—-―]?\d{4}[-—-―]?\d{4}|' \
  1235. '\+86.?1[3-9]\d{9}|' \
  1236. '0[1-9]\d{1,2}[-—-―][2-9]\d{6,7}/[1-9]\d{6,10}|' \
  1237. '0[1-9]\d{1,2}[-—-―][2-9]\d{6}\d?.?转\d{1,4}|' \
  1238. '0[1-9]\d{1,2}[-—-―][2-9]\d{6}\d?[-—-―]\d{1,4}|' \
  1239. '0[1-9]\d{1,2}[-—-―]?[2-9]\d{6}\d?(?=1[3-9]\d{9})|' \
  1240. '0[1-9]\d{1,2}[-—-―]?[2-9]\d{6}\d?(?=0[1-9]\d{1,2}[-—-―]?[2-9]\d{6}\d?)|' \
  1241. '0[1-9]\d{1,2}[-—-―]?[2-9]\d{6}\d?(?=[2-9]\d{6,7})|' \
  1242. '0[1-9]\d{1,2}[-—-―]?[2-9]\d{6}\d?|' \
  1243. '[\(|\(]0[1-9]\d{1,2}[\)|\)]-?[2-9]\d{6}\d?-?\d{,4}|' \
  1244. '[2-9]\d{6,7})'
  1245. re_tenderee_phone = re.compile(
  1246. # "(?:(?:(?:采购|招标|议价|议标|比选|业主|委托)(?:人|公司|单位|组织|部门)|建设(?:单位|业主)|(?:采购|招标|甲)方|询价单位|项目业主|业主)(?:单位)?[^。代理]{0,5}(?:电话|联系方式|联系人|联系电话)[::]?[^。]{0,7}?)"
  1247. "(?:(?:(?:遴选|寻源|采购|招标|竞价|议价|比选|(?:[^受被]|^)委托|询比?价|比价|评选|谈判|邀标|邀请|洽谈|约谈|选取|抽取|抽选|项目|需求?|甲方?|转让|招租|议标|合同主体|挂牌|出租|出让|出售|标卖|处置|发包|最终|建设|业主|竞卖|申购|公选)"
  1248. "(?:人|方|商|单位|组织|用户|业主|主体|部门|公司|企业))(?:单位)?[^。代理]{0,5}(?:电话|联系方式|联系人|联系电话)[::]?[^。]{0,7}?)"
  1249. # 电话号码
  1250. + phone_pattern)
  1251. # 例:"采购人地址和联系方式:峨边彝族自治县教育局,0833-5226788,"
  1252. re_tenderee_phone2 = re.compile(
  1253. # "(?:(?:(?:采购|招标|议价|议标|比选|业主)(?:人|公司|单位|组织|部门)|建设(?:单位|业主)|(?:采购|招标|甲)方|询价单位|项目业主|业主)(?:单位)?[^。代理]{0,3}(?:地址)[^。]{0,3}(?:电话|联系方式|联系人|联系电话)[::]?[^。]{0,20}?)"
  1254. "(?:(?:(?:遴选|寻源|采购|招标|竞价|议价|比选|(?:[^受被]|^)委托|询比?价|比价|评选|谈判|邀标|邀请|洽谈|约谈|选取|抽取|抽选|项目|需求?|甲方?|转让|招租|议标|合同主体|挂牌|出租|出让|出售|标卖|处置|发包|最终|建设|业主|竞卖|申购|公选)"
  1255. "(?:人|方|商|单位|组织|用户|业主|主体|部门|公司|企业))(?:单位)?[^。代理]{0,3}(?:地址)[^。]{0,3}(?:电话|联系方式|联系人|联系电话|联系人和联系方式)[::]?[^。]{0,20}?)"
  1256. # 电话号码
  1257. + phone_pattern)
  1258. re_agent_phone = re.compile(
  1259. "(?:(?:(?:代理|[受被]委托)(?:人|方|商|机构|公司|单位|组织|企业)|采购机构|集中采购机构|集采机构|招标机构)[^。]{0,5}(?:电话|联系方式|联系人|联系电话|联系人和联系方式)[::]?[^。]{0,7}?)"
  1260. # 电话号码
  1261. + phone_pattern)
  1262. re_agent_phone2 = re.compile(
  1263. "(?:(?:(?:代理|[受被]委托)(?:人|方|商|机构|公司|单位|组织|企业)|采购机构|集中采购机构|集采机构|招标机构)[^。]{0,3}(?:地址)[^。]{0,3}(?:电话|联系方式|联系人|联系电话|联系人和联系方式)[::]?[^。]{0,20}?)"
  1264. # 电话号码
  1265. + phone_pattern)
  1266. re_win_tenderer_phone = re.compile(
  1267. "(?:(?:(?:乙|竞得|受让|买受|签约|供货|供应?|合作|承做|承包|承建|承销|承保|承接|承制|承担|承修|承租(?:(包))?|入围|入选|竞买|中标|中选|中价|中签|成交|候选)"
  1268. "(?:候选|投标)?(?:人|单位|(?:中介)?(?:服务)?机构|供应商|客户|方|公司|企业|厂商|商|社会资本方?)|选定单位|中[标选]银行|成交对象)[^。审核]{0,5}(?:负责人|联系人|项目)?(?:经理|电话|联系方式|联系人|负责人|联系电话|联系人和联系方式)[::]?[^。]{0,7}?)"
  1269. + phone_pattern)
  1270. re_win_tenderer_phone2 = re.compile(
  1271. "(?:(?:(?:乙|竞得|受让|买受|签约|供货|供应?|合作|承做|承包|承建|承销|承保|承接|承制|承担|承修|承租(?:(包))?|入围|入选|竞买|中标|中选|中价|中签|成交|候选)"
  1272. "(?:候选|投标)?(?:人|单位|(?:中介)?(?:服务)?机构|供应商|客户|方|公司|企业|厂商|商|社会资本方?)|选定单位|中[标选]银行|成交对象)[^。]{0,3}(?:地址)[^。审核]{0,3}(?:负责人|联系人|项目)?(?:经理|电话|联系方式|联系人|负责人|联系电话|联系人和联系方式)[::]?[^。]{0,20}?)"
  1273. + phone_pattern)
  1274. not_win_tenderer_contact = re.compile("纪检|监察|质疑|投诉|监督|受理|请.{0,4}(联系|与)"
  1275. "|(遴选|寻源|采购|招标|竞价|议价|比选|委托|询比?价|比价|评选|谈判|邀标|邀请|洽谈|约谈|选取|抽取|抽选|项目|需求?|甲方?|转让|招租|议标|合同主体|挂牌|出租|出让|出售|标卖|处置|发包|最终|建设|业主|竞卖|申购|公选|发布|代理|拍卖|转出){1,2}"
  1276. "(人|方|商|单位|组织|用户|业主|主体|部门|公司|企业|工厂|银行|机构){0,2}"
  1277. "[\u4e00-\u9fa5]{0,4}(联系|咨询|电话)(人|电话|方式)?")
  1278. content = ""
  1279. for _sentence in list_sentence:
  1280. content += "".join(_sentence.tokens)
  1281. _content = copy.deepcopy(content)
  1282. while re.search("(.)(,)([^0-9])|([^0-9])(,)(.)", content):
  1283. content_words = list(content)
  1284. for i in re.finditer("(.)(,)([^0-9])", content):
  1285. content_words[i.span(2)[0]] = ""
  1286. for i in re.finditer("([^0-9])(,)(.)", content):
  1287. content_words[i.span(2)[0]] = ""
  1288. content = "".join(content_words)
  1289. content = re.sub("[::]|[\((]|[\))]", "", content)
  1290. _tenderee_phone = re.findall(re_tenderee_phone, content)
  1291. # 更新正则确定的角色属性
  1292. for i in range(len(PackDict["Project"]["roleList"])):
  1293. if PackDict["Project"]["roleList"][i].role_name == "tenderee":
  1294. _tenderee_phone = re.findall(re_tenderee_phone, content)
  1295. if _tenderee_phone:
  1296. for _phone in _tenderee_phone:
  1297. _phone = _phone.split("/") # 分割多个号码
  1298. for one_phone in _phone:
  1299. PackDict["Project"]["roleList"][i].linklist.append(("", one_phone))
  1300. tenderee_phone.add(one_phone)
  1301. _tenderee_phone2 = re.findall(re_tenderee_phone2, content)
  1302. if _tenderee_phone2:
  1303. for _phone in _tenderee_phone2:
  1304. _phone = _phone.split("/")
  1305. for one_phone in _phone:
  1306. PackDict["Project"]["roleList"][i].linklist.append(("", one_phone))
  1307. tenderee_phone.add(one_phone)
  1308. if PackDict["Project"]["roleList"][i].role_name == "agency":
  1309. _agent_phone = re.findall(re_agent_phone, content)
  1310. if _agent_phone:
  1311. for _phone in _agent_phone:
  1312. _phone = _phone.split("/")
  1313. for one_phone in _phone:
  1314. PackDict["Project"]["roleList"][i].linklist.append(("", one_phone))
  1315. agency_phone.add(one_phone)
  1316. _agent_phone2 = re.findall(re_agent_phone2, content)
  1317. if _agent_phone2:
  1318. for _phone in _agent_phone2:
  1319. _phone = _phone.split("/")
  1320. for one_phone in _phone:
  1321. PackDict["Project"]["roleList"][i].linklist.append(("", one_phone))
  1322. agency_phone.add(one_phone)
  1323. # 中标人联系方式规则筛选
  1324. _winter_phone = re.findall(re_win_tenderer_phone, content)
  1325. if _winter_phone:
  1326. for _phone in _winter_phone:
  1327. _phone = _phone.split("/")
  1328. for one_phone in _phone:
  1329. rule_winter_phone.add(one_phone)
  1330. _winter_phone2 = re.findall(re_win_tenderer_phone2, content)
  1331. if _winter_phone2:
  1332. for _phone in _winter_phone2:
  1333. _phone = _phone.split("/")
  1334. for one_phone in _phone:
  1335. rule_winter_phone.add(one_phone)
  1336. # 正则提取电话号码实体
  1337. # key_word = re.compile('((?:电话|联系方式|联系人).{0,4}?)([0-1]\d{6,11})')
  1338. phone = re.compile('1[3-9][0-9][-—-―]?\d{4}[-—-―]?\d{4}|'
  1339. '\+86.?1[3-9]\d{9}|'
  1340. # '0[^0]\d{1,2}[-—-―][1-9]\d{6,7}/[1-9]\d{6,10}|'
  1341. '0[1-9]\d{1,2}[-—-―][2-9]\d{6}\d?[-—-―]\d{1,4}|'
  1342. '0[1-9]\d{1,2}[-—-―]{0,2}[2-9]\d{6}\d?(?=1[3-9]\d{9})|'
  1343. '0[1-9]\d{1,2}[-—-―]{0,2}[2-9]\d{6}\d?(?=0[1-9]\d{1,2}[-—-―]?[2-9]\d{6}\d?)|'
  1344. '0[1-9]\d{1,2}[-—-―]{0,2}[2-9]\d{6}\d?(?=[2-9]\d{6,7})|'
  1345. '0[1-9]\d{1,2}[-—-―]{0,2}[2-9]\d{6}\d?|'
  1346. '[\(|\(]0[1-9]\d{1,2}[\)|\)]-?[2-9]\d{6}\d?-?\d{,4}|'
  1347. '400\d{7}转\d{1,4}|'
  1348. '[2-9]\d{6,7}')
  1349. url_pattern = re.compile("http[s]?://(?:[a-zA-Z]|[0-9]|[#$\-_@.&+=\?:/]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+")
  1350. email_pattern = re.compile("[a-zA-Z0-9][a-zA-Z0-9_-]+(?:\.[a-zA-Z0-9_-]+)*@"
  1351. "[a-zA-Z0-9_-]+(?:\.[a-zA-Z0-9_-]+)*(?:\.[a-zA-Z]{2,})")
  1352. phone_entitys = []
  1353. code_entitys = [ent for ent in list_entity if ent.entity_type=='code']
  1354. for _sentence in list_sentence:
  1355. sentence_text = _sentence.sentence_text
  1356. # 过长数字串直接过滤替换
  1357. for _re in re.findall("\d{50,}",sentence_text):
  1358. sentence_text = sentence_text.replace(_re,"#"*len(_re))
  1359. in_attachment = _sentence.in_attachment
  1360. list_tokenbegin = []
  1361. begin = 0
  1362. for i in range(0, len(_sentence.tokens)):
  1363. list_tokenbegin.append(begin)
  1364. begin += len(str(_sentence.tokens[i]))
  1365. list_tokenbegin.append(begin + 1)
  1366. # 排除网址、邮箱、项目编号实体
  1367. error_list = []
  1368. for i in re.finditer(url_pattern, sentence_text):
  1369. error_list.append((i.start(), i.end()))
  1370. for i in re.finditer(email_pattern, sentence_text):
  1371. error_list.append((i.start(), i.end()))
  1372. for code_ent in [ent for ent in code_entitys if ent.sentence_index==_sentence.sentence_index]:
  1373. error_list.append((code_ent.wordOffset_begin,code_ent.wordOffset_end))
  1374. res_set = set()
  1375. for i in re.finditer(phone, sentence_text):
  1376. is_continue = False
  1377. for error_ent in error_list:
  1378. if i.start()>=error_ent[0] and i.end()<=error_ent[1]:
  1379. is_continue = True
  1380. break
  1381. if is_continue:
  1382. continue
  1383. res_set.add((i.group(), i.start(), i.end()))
  1384. res_set = sorted(list(res_set),key=lambda x:x[1])
  1385. # 限制数量,防止异常数据处理时间过长
  1386. res_set = res_set[:200]
  1387. last_phone_mask = True
  1388. error_numStr_index = []
  1389. sentence_phone_list = []
  1390. for item_idx in range(len(res_set)):
  1391. item = res_set[item_idx]
  1392. phone_left = sentence_text[max(0, item[1] - 10):item[1]]
  1393. phone_right = sentence_text[item[2]:item[2] + 10]
  1394. phone_left_num = re.search("[\da-zA-Z\-—-―]+$",phone_left)
  1395. numStr_left = item[1]
  1396. if phone_left_num:
  1397. numStr_left -= len(phone_left_num.group())
  1398. phone_right_num = re.search("^[\da-zA-Z\-—-―]+",phone_right)
  1399. numStr_right = item[2]
  1400. if phone_right_num:
  1401. numStr_right += len(phone_right_num.group())
  1402. numStr_index = (numStr_left,numStr_right)
  1403. if re.search("电话|手机|联系[人方]|联系方式",re.sub(",","",phone_left)):
  1404. pass
  1405. else:
  1406. # 排除“传真号”和其它错误项
  1407. if re.search("传,?真|信,?箱|邮,?[编箱件]|QQ|qq", phone_left):
  1408. if not re.search("电,?话", phone_left):
  1409. error_numStr_index.append(numStr_index)
  1410. last_phone_mask = False
  1411. continue
  1412. if re.search("身份证号?码?|注册[证号]|帐号|编[号码]|报价|费率|标价|证号|资格证|资质|价格|金额|型号|附件|代码|列号|行号|税号|[\(\(]万?元[\)\)]|[a-zA-Z]+\d*$", re.sub(",","",phone_left)):
  1413. error_numStr_index.append(numStr_index)
  1414. last_phone_mask = False
  1415. continue
  1416. if re.search("^\d{0,4}[.,]\d{2,}|^[0-9a-zA-Z\.]*@|^\d*[a-zA-Z]+|元", phone_right):
  1417. error_numStr_index.append(numStr_index)
  1418. last_phone_mask = False
  1419. continue
  1420. # 号码含有0过多,不符合规则
  1421. if re.search("0{6,}",item[0]):
  1422. error_numStr_index.append(numStr_index)
  1423. last_phone_mask = False
  1424. continue
  1425. # 前后跟着字母
  1426. if re.search("[a-zA-Z/]+$", phone_left) or re.search("^[a-zA-Z/]+", phone_right):
  1427. error_numStr_index.append(numStr_index)
  1428. last_phone_mask = False
  1429. continue
  1430. # 时间日期类排除
  1431. if re.search("时间|日期", phone_left):
  1432. error_numStr_index.append(numStr_index)
  1433. last_phone_mask = False
  1434. continue
  1435. # 排除号码实体为时间格式 ,例如:20150515
  1436. if re.search("^20(1[0-9]|2[0-5])(0[1-9]|1[012])(0[1-9]|[1-2][0-9]|3[01])$",item[0]):
  1437. error_numStr_index.append(numStr_index)
  1438. last_phone_mask = False
  1439. continue
  1440. # 前后跟着长度小于一定值数字的正则排除
  1441. if re.search("\d+[-—-―]?\d*$",phone_left) or re.search("^\d+[-—-―]?\d*",phone_right):
  1442. phone_left_number = re.search("\d+[-—-―]?\d*$",phone_left)
  1443. phone_right_number = re.search("^\d+[-—-―]?\d+",phone_right)
  1444. if phone_left_number:
  1445. if len(phone_left_number.group())<7:
  1446. error_numStr_index.append(numStr_index)
  1447. last_phone_mask = False
  1448. continue
  1449. if phone_right_number:
  1450. if len(phone_right_number.group())<7:
  1451. error_numStr_index.append(numStr_index)
  1452. last_phone_mask = False
  1453. continue
  1454. left_context = re.search("[\da-zA-Z\-—-―]+$",sentence_text[:item[1]])
  1455. if left_context:
  1456. if len(left_context.group()) != len("".join(re.findall(phone, left_context.group()))):
  1457. # if not re.search("(" + phone.pattern + ")$", left_context.group()):
  1458. error_numStr_index.append(numStr_index)
  1459. last_phone_mask = False
  1460. continue
  1461. right_context = re.search("^[\da-zA-Z\-—-―]+", sentence_text[item[2]:])
  1462. if right_context:
  1463. if len(right_context.group()) != len("".join(re.findall(phone, right_context.group()))):
  1464. # if not re.search("^(" + phone.pattern + ")", right_context.group()):
  1465. error_numStr_index.append(numStr_index)
  1466. last_phone_mask = False
  1467. continue
  1468. # if:上一个phone实体不符合条件
  1469. if not last_phone_mask:
  1470. item_start = item[1]
  1471. last_item_end = res_set[item_idx-1][2]
  1472. if item_start - last_item_end<=1 or re.search("^[\da-zA-Z\-—-―、]+$",sentence_text[last_item_end:item_start]):
  1473. error_numStr_index.append(numStr_index)
  1474. last_phone_mask = False
  1475. continue
  1476. sentence_phone_list.append(item)
  1477. last_phone_mask = True
  1478. if error_numStr_index:
  1479. drop_list = []
  1480. for item in sentence_phone_list:
  1481. for err_index in error_numStr_index:
  1482. if (item[1]>=err_index[0] and item[1]<=err_index[1]) or (item[2]>=err_index[0] and item[2]<=err_index[1]) or (item[1]<=err_index[0] and item[2]>=err_index[1]):
  1483. drop_list.append(item)
  1484. break
  1485. for _drop_item in drop_list:
  1486. sentence_phone_list.remove(_drop_item)
  1487. for item in sentence_phone_list:
  1488. for j in range(len(list_tokenbegin)):
  1489. if list_tokenbegin[j] == item[1]:
  1490. begin_index = j
  1491. break
  1492. elif list_tokenbegin[j] > item[1]:
  1493. begin_index = j - 1
  1494. break
  1495. for j in range(begin_index, len(list_tokenbegin)):
  1496. if list_tokenbegin[j] >= item[2]:
  1497. end_index = j - 1
  1498. break
  1499. phone_text = re.sub("[-—-―]+","-",item[0]).replace("(","(").replace(")",")")
  1500. _entity = Entity(_sentence.doc_id, None, phone_text, "phone", _sentence.sentence_index, begin_index, end_index, item[1],
  1501. item[2],in_attachment=in_attachment)
  1502. phone_entitys.append(_entity)
  1503. # print('phone_set:',set([ent.entity_text for ent in phone_entitys]))
  1504. def is_company(entity,text):
  1505. # 判断"公司"实体是否为地址地点
  1506. if entity.label!=5 and entity.values[entity.label]>0.5:
  1507. return True
  1508. if ent.is_tail==True:
  1509. return False
  1510. entity_left = text[max(0,entity.wordOffset_begin-10):entity.wordOffset_begin]
  1511. entity_left = re.sub(",()\(\)","",entity_left)
  1512. entity_left = entity_left[-5:]
  1513. if re.search("地址|地点|银行[::]",entity_left):
  1514. return False
  1515. else:
  1516. return True
  1517. pre_entity = []
  1518. for ent in list_entity:
  1519. if (ent.entity_type in ['company','org','phone'] and is_company(ent,list_sentence[ent.sentence_index].sentence_text)) or (ent.entity_type=='person' and ent.label in [1,2,3]) \
  1520. or (ent.entity_type=='location' and len(ent.entity_text)>5):
  1521. pre_entity.append(ent)
  1522. text_data,pre_data = relationExtraction_model.encode(pre_entity + phone_entitys, list_sentence)
  1523. # print(pre_data)
  1524. maxlen = 512
  1525. relation_list = []
  1526. if 0<len(text_data)<=maxlen:
  1527. relation_list = relationExtraction_model.predict(text_data, pre_data)
  1528. else:
  1529. # 公告大于maxlen时,分段预测
  1530. start = 0
  1531. # print("len(pre_data)",len(pre_data))
  1532. temp_data = []
  1533. deal_data = 0
  1534. while start<len(pre_data):
  1535. _pre_data = pre_data[start:start+maxlen]
  1536. _text_data = text_data[start:start+maxlen]
  1537. if relationExtraction_model.check_data(_pre_data):
  1538. temp_data.append((_text_data,_pre_data))
  1539. else:
  1540. if temp_data:
  1541. deal_data += len(temp_data)
  1542. if deal_data>4:
  1543. break
  1544. for _text_data, _pre_data in temp_data:
  1545. relation_list.extend(relationExtraction_model.predict(_text_data,_pre_data))
  1546. temp_data = []
  1547. start = start + maxlen - 120
  1548. if temp_data:
  1549. deal_data += len(temp_data)
  1550. if deal_data <= 4:
  1551. for _text_data, _pre_data in temp_data:
  1552. relation_list.extend(relationExtraction_model.predict(_text_data, _pre_data))
  1553. # print("预测数据:",len(temp_data))
  1554. # 去重结果
  1555. relation_list = list(set(relation_list))
  1556. # print([(rel[0].entity_text,rel[2].entity_text) for rel in relation_list])
  1557. # relation_list = [] # 放弃原来的模型连接,结果不好控制
  1558. right_combination = [('org','person'),('company','person'),('company','location'),('org','location'),('person','phone')]
  1559. linked_company = set()
  1560. linked_person = set()
  1561. linked_connetPerson = set()
  1562. linked_phone = set()
  1563. for predicate in ["rel_address","rel_phone","rel_person"]:
  1564. _match_list = []
  1565. _match_combo = []
  1566. for relation in relation_list:
  1567. _subject = relation[0]
  1568. _object = relation[2]
  1569. if isinstance(_subject,Entity) and isinstance(_object,Entity) and (_subject.entity_type,_object.entity_type) in right_combination:
  1570. if _subject.in_attachment != _object.in_attachment:
  1571. continue
  1572. if relation[1]==predicate:
  1573. distance = (tokens_num_dict[_object.sentence_index] + _object.begin_index) - (
  1574. tokens_num_dict[_subject.sentence_index] + _subject.end_index)
  1575. if predicate=="rel_person":
  1576. # print(predicate, _subject.entity_text, _object.entity_text)
  1577. if (_subject.label==0 and _object.entity_text in agency_contact ) or (_subject.label==1 and _object.entity_text in tenderee_contact):
  1578. continue
  1579. # 角色为中标候选人,排除"质疑|投诉|监督|受理"相关的联系人
  1580. # if _subject.label in [2,3,4] and re.search("纪检|监察|质疑|投诉|监督|受理|项目(单位)?联系|^联系人|请.{0,4}联系",list_sentence[_object.sentence_index].sentence_text[max(0,_object.wordOffset_begin-10):_object.wordOffset_begin]):
  1581. if _subject.label in [2,3,4] and re.search(not_win_tenderer_contact,list_sentence[_object.sentence_index].sentence_text[max(0,_object.wordOffset_begin-15):_object.wordOffset_begin]):
  1582. # print('not_win_tenderer_contact1')
  1583. continue
  1584. # 角色为招标/代理人,排除"纪检|监察"相关的联系人
  1585. if (_subject.label in [0,1] or _subject.entity_text in tenderee_entity_set|agency_entity_set) and re.search("纪检|监察|投诉|监督|乙方|中标",list_sentence[_object.sentence_index].sentence_text[max(0,_object.wordOffset_begin - 10):_object.wordOffset_begin]):
  1586. # if _subject.label in [0,1] and re.search("纪检|监察|乙方|中标",list_sentence[_object.sentence_index].sentence_text[_subject.end_index:_object.wordOffset_begin]):
  1587. continue
  1588. if _object.sentence_index!=0 and _object.wordOffset_begin<=10:
  1589. if _subject.label in [2, 3, 4] and re.search("请.{0,4}联系",
  1590. list_sentence[_object.sentence_index-1].sentence_text[-10:]+
  1591. list_sentence[_object.sentence_index].sentence_text[0:_object.wordOffset_begin]):
  1592. continue
  1593. # 角色为中标候选人,排除距离过远的联系人
  1594. if _subject.label in [2, 3, 4] and distance>=40:
  1595. continue
  1596. if distance>0:
  1597. value = (-1 / 2 * (distance ** 2))/10000
  1598. else:
  1599. distance = abs(distance)
  1600. value = (-1 / 2 * (distance ** 2))
  1601. _match_list.append(Match(_subject,_object,value))
  1602. _match_combo.append((_subject,_object))
  1603. match_result = dispatch(_match_list)
  1604. error_list = []
  1605. for mat in list(set(_match_combo)-set(match_result)):
  1606. for temp in match_result:
  1607. if mat[1]==temp[1] and mat[0]!=temp[0]:
  1608. error_list.append(mat)
  1609. break
  1610. result = list(set(_match_combo)-set(error_list))
  1611. if predicate=='rel_person':
  1612. # 从后往前更新状态,已近后向链接的属性不在前向链接(解决错误链接)
  1613. result = sorted(result,key=lambda x:x[1].begin_index,reverse=True)
  1614. for combo in result:
  1615. is_continue = False
  1616. if not combo[0].pointer_person:
  1617. combo[0].pointer_person = []
  1618. if combo[1].begin_index<combo[0].begin_index:
  1619. if combo[0].pointer_person:
  1620. for temp in combo[0].pointer_person:
  1621. if temp.begin_index>combo[0].begin_index:
  1622. is_continue = True
  1623. break
  1624. if is_continue:
  1625. continue
  1626. combo[0].pointer_person.append(combo[1])
  1627. linked_company.add(combo[0])
  1628. linked_person.add(combo[1])
  1629. # print(1,combo[0].entity_text,combo[1].entity_text)
  1630. if predicate=='rel_address':
  1631. result = sorted(result,key=lambda x:x[1].begin_index,reverse=True)
  1632. for combo in result:
  1633. if combo[0].pointer_address:
  1634. continue
  1635. combo[0].pointer_address = combo[1]
  1636. # print(2,combo[0].entity_text,combo[1].entity_text)
  1637. if predicate=='rel_phone':
  1638. result = sorted(result,key=lambda x:x[1].begin_index,reverse=True)
  1639. for combo in result:
  1640. is_continue = False
  1641. if not combo[0].person_phone:
  1642. combo[0].person_phone = []
  1643. if combo[1].begin_index<combo[0].begin_index:
  1644. if combo[0].person_phone:
  1645. for temp in combo[0].person_phone:
  1646. if temp.begin_index>combo[0].begin_index:
  1647. is_continue = True
  1648. break
  1649. if is_continue:
  1650. continue
  1651. combo[0].person_phone.append(combo[1])
  1652. linked_connetPerson.add(combo[0])
  1653. linked_phone.add(combo[1])
  1654. if combo[0].label in [1,2]:
  1655. if PackDict.get("Project"):
  1656. for i in range(len(PackDict["Project"]["roleList"])):
  1657. if (combo[0].label==1 and PackDict["Project"]["roleList"][i].role_name=='tenderee') \
  1658. or (combo[0].label==2 and PackDict["Project"]["roleList"][i].role_name=='agency'):
  1659. PackDict["Project"]["roleList"][i].linklist.append((combo[0].entity_text,combo[1].entity_text))
  1660. break
  1661. # print(3,combo[0].entity_text,combo[1].entity_text)
  1662. # "公司——地址" 链接规则补充
  1663. company_lacation_EntityList = [ent for ent in pre_entity if ent.entity_type in ['company', 'org', 'location']]
  1664. # company_lacation_EntityList = [ent for ent in pre_entity if (ent.entity_type in ['company', 'org'] and ent.label!=5) or ent.entity_type=="location"]
  1665. company_lacation_EntityList = sorted(company_lacation_EntityList, key=lambda x: (x.sentence_index, x.begin_index))
  1666. t_match_list = []
  1667. for ent_idx in range(len(company_lacation_EntityList)):
  1668. entity = company_lacation_EntityList[ent_idx]
  1669. if entity.entity_type in ['company', 'org'] and entity.label!=5:
  1670. match_nums = 0
  1671. company_nums = 0 # 经过其他公司的数量
  1672. location_nums = 0 # 经过住址的数量
  1673. for after_index in range(ent_idx + 1, min(len(company_lacation_EntityList), ent_idx + 5)):
  1674. after_entity = company_lacation_EntityList[after_index]
  1675. if after_entity.entity_type == "location":
  1676. distance = (tokens_num_dict[after_entity.sentence_index] + after_entity.begin_index) - (
  1677. tokens_num_dict[entity.sentence_index] + entity.end_index)
  1678. location_nums += 1
  1679. if distance > 100 or location_nums >= 3:
  1680. break
  1681. sentence_distance = after_entity.sentence_index - entity.sentence_index
  1682. value = (-1 / 2 * (distance ** 2)) / 10000
  1683. if sentence_distance == 0:
  1684. if distance < 60:
  1685. t_match_list.append(Match(entity, after_entity, value))
  1686. match_nums += 1
  1687. if company_nums:
  1688. break
  1689. else:
  1690. if distance < 50:
  1691. t_match_list.append(Match(entity, after_entity, value))
  1692. match_nums += 1
  1693. if company_nums:
  1694. break
  1695. else:
  1696. # type:company/org
  1697. company_nums += 1
  1698. if entity.label in [2, 3, 4] and after_entity.label in [0, 1]:
  1699. break
  1700. if entity.label in [0, 1] and after_entity.label in [2, 3, 4]:
  1701. break
  1702. if entity.label in [0, 1] and after_entity.label not in [0, 1]:
  1703. break
  1704. # km算法分配求解
  1705. # for item in t_match_list:
  1706. # print("loc_rela",item.main_role.entity_text,item.attribute.entity_text)
  1707. relate_location_result = dispatch(t_match_list)
  1708. relate_location_result = sorted(relate_location_result, key=lambda x: (x[0].sentence_index, x[0].begin_index))
  1709. for match in relate_location_result:
  1710. _company = match[0]
  1711. _relation = match[1]
  1712. # print("loc_relation1", _company.entity_text, _relation.entity_text, )
  1713. if not _company.pointer_address:
  1714. # print('loc_relation2',_company.entity_text,_relation.entity_text)
  1715. _company.pointer_address = _relation
  1716. # "联系人——联系电话" 链接规则补充
  1717. # person_phone_EntityList = [ent for ent in pre_entity+ phone_entitys if ent.entity_type not in ['company','org','location']]
  1718. person_phone_EntityList = [ent for ent in pre_entity+ phone_entitys if ent.entity_type not in ['location']]
  1719. person_phone_EntityList = sorted(person_phone_EntityList, key=lambda x: (x.sentence_index, x.begin_index))
  1720. t_match_list = []
  1721. for ent_idx in range(len(person_phone_EntityList)):
  1722. entity = person_phone_EntityList[ent_idx]
  1723. if entity.entity_type=="person":
  1724. match_nums = 0
  1725. person_nums = 0 # 经过其他中联系人的数量
  1726. byNotPerson_match_nums = 0 # 跟在联系人后面的属性
  1727. phone_nums = 0 # 经过电话的数量
  1728. for after_index in range(ent_idx + 1, min(len(person_phone_EntityList), ent_idx + 8)):
  1729. after_entity = person_phone_EntityList[after_index]
  1730. if after_entity.entity_type == "phone":
  1731. distance = (tokens_num_dict[after_entity.sentence_index] + after_entity.begin_index) - (
  1732. tokens_num_dict[entity.sentence_index] + entity.end_index)
  1733. phone_nums += 1
  1734. if distance>100 or phone_nums>=4:
  1735. break
  1736. sentence_distance = after_entity.sentence_index - entity.sentence_index
  1737. value = (-1 / 2 * (distance ** 2)) / 10000
  1738. if sentence_distance == 0:
  1739. if distance < 70:
  1740. # value = (-1 / 2 * (distance ** 2)) / 10000
  1741. t_match_list.append(Match(entity, after_entity, value))
  1742. match_nums += 1
  1743. if not person_nums:
  1744. byNotPerson_match_nums += 1
  1745. else:
  1746. break
  1747. else:
  1748. if distance < 30:
  1749. # value = (-1 / 2 * (distance ** 2)) / 10000
  1750. t_match_list.append(Match(entity, after_entity, value))
  1751. match_nums += 1
  1752. if not person_nums:
  1753. byNotPerson_match_nums += 1
  1754. else:
  1755. break
  1756. elif after_entity.entity_type == "person":
  1757. person_nums += 1
  1758. elif after_entity.entity_type in ["company","org"]:
  1759. break
  1760. # 前向查找属性
  1761. if ent_idx != 0 and (not match_nums or not byNotPerson_match_nums):
  1762. previous_entity = person_phone_EntityList[ent_idx - 1]
  1763. if previous_entity.entity_type == 'phone':
  1764. # if previous_entity.sentence_index == entity.sentence_index:
  1765. distance = (tokens_num_dict[entity.sentence_index] + entity.begin_index) - (
  1766. tokens_num_dict[previous_entity.sentence_index] + previous_entity.end_index)
  1767. if distance < 30:
  1768. # 前向 没有 /10000
  1769. value = (-1 / 2 * (distance ** 2))
  1770. t_match_list.append(Match(entity, previous_entity, value))
  1771. # km算法分配求解(person-phone)
  1772. t_match_list = [mat for mat in t_match_list if mat.main_role not in linked_connetPerson and mat.attribute not in linked_phone]
  1773. # print([(mat.main_role.entity_text,mat.attribute.entity_text) for mat in t_match_list])
  1774. personphone_result = dispatch(t_match_list)
  1775. personphone_result = sorted(personphone_result, key=lambda x: (x[0].sentence_index, x[0].begin_index))
  1776. for match in personphone_result:
  1777. _person = match[0]
  1778. _phone = match[1]
  1779. if not _person.person_phone:
  1780. _person.person_phone = []
  1781. _person.person_phone.append(_phone)
  1782. # 多个招标人/代理人或者别称
  1783. for idx in range(1,len(pre_entity)):
  1784. _pre_entity = pre_entity[idx]
  1785. if _pre_entity in linked_company and _pre_entity.label==5:
  1786. last_ent = pre_entity[idx-1]
  1787. if last_ent.entity_type in ['company','org'] and last_ent.label in [0,1]:
  1788. if last_ent.sentence_index==_pre_entity.sentence_index:
  1789. mid_text = list_sentence[_pre_entity.sentence_index].sentence_text[last_ent.wordOffset_end:_pre_entity.wordOffset_begin]
  1790. if len(mid_text)<=20 and "," not in mid_text and re.search("[、\((]",mid_text):
  1791. _pre_entity.label = last_ent.label
  1792. _pre_entity.values[last_ent.label] = 0.6
  1793. # 2022/01/25 固定电话可连多个联系人
  1794. temp_person_entitys = [entity for entity in pre_entity if entity.entity_type == 'person']
  1795. temp_person_entitys2 = [] #和固定电话相连的联系人
  1796. for entity in temp_person_entitys:
  1797. if entity.person_phone:
  1798. for _phone in entity.person_phone:
  1799. if not re.search("^1[3-9]\d{9}$", _phone.entity_text):
  1800. temp_person_entitys2.append(entity)
  1801. break
  1802. for index in range(len(temp_person_entitys)):
  1803. entity = temp_person_entitys[index]
  1804. if entity in temp_person_entitys2:
  1805. last_person = entity
  1806. for after_index in range(index + 1, min(len(temp_person_entitys), index + 5)):
  1807. after_entity = temp_person_entitys[after_index]
  1808. if after_entity.sentence_index == last_person.sentence_index and after_entity.begin_index - last_person.end_index < 3:
  1809. for _phone in entity.person_phone:
  1810. if not re.search("^1[3-9]\d{9}$", _phone.entity_text):
  1811. if _phone not in after_entity.person_phone:
  1812. after_entity.person_phone.append(_phone)
  1813. last_person = after_entity
  1814. else:
  1815. break
  1816. if index==0:
  1817. continue
  1818. last_person = entity
  1819. for before_index in range(index-1, max(-1,index-5), -1):
  1820. before_entity = temp_person_entitys[before_index]
  1821. if before_entity.sentence_index == last_person.sentence_index and last_person.begin_index - before_entity.end_index < 3:
  1822. for _phone in entity.person_phone:
  1823. if not re.search("^1[3-9]\d{9}$", _phone.entity_text):
  1824. if _phone not in before_entity.person_phone:
  1825. before_entity.person_phone.append(_phone)
  1826. last_person = before_entity
  1827. else:
  1828. break
  1829. # 更新person为招标/代理联系人的联系方式
  1830. for k in PackDict.keys():
  1831. for i in range(len(PackDict[k]["roleList"])):
  1832. if PackDict[k]["roleList"][i].role_name == "tenderee":
  1833. for _person in person_list:
  1834. if _person.label==1:#招标联系人
  1835. person_phone = [phone for phone in _person.person_phone] if _person.person_phone else []
  1836. for _p in person_phone:
  1837. PackDict[k]["roleList"][i].linklist.append((_person.entity_text, _p.entity_text))
  1838. if not person_phone:
  1839. PackDict[k]["roleList"][i].linklist.append((_person.entity_text,""))
  1840. if PackDict[k]["roleList"][i].role_name == "agency":
  1841. for _person in person_list:
  1842. if _person.label==2:#代理联系人
  1843. person_phone = [phone for phone in _person.person_phone] if _person.person_phone else []
  1844. for _p in person_phone:
  1845. PackDict[k]["roleList"][i].linklist.append((_person.entity_text, _p.entity_text))
  1846. if not person_phone:
  1847. PackDict[k]["roleList"][i].linklist.append((_person.entity_text,""))
  1848. # 更新 PackDict
  1849. not_sure_linked = []
  1850. for link_p in list(linked_company):
  1851. for k in PackDict.keys():
  1852. for i in range(len(PackDict[k]["roleList"])):
  1853. if PackDict[k]["roleList"][i].role_name == "tenderee":
  1854. if PackDict[k]["roleList"][i].entity_text != link_p.entity_text and link_p.label == 0:
  1855. not_sure_linked.append(link_p)
  1856. continue
  1857. if PackDict[k]["roleList"][i].entity_text == link_p.entity_text:
  1858. for per in link_p.pointer_person:
  1859. person_phone = [phone for phone in per.person_phone] if per.person_phone else []
  1860. if not person_phone:
  1861. if per.entity_text not in agency_contact:
  1862. PackDict[k]["roleList"][i].linklist.append((per.entity_text, ""))
  1863. continue
  1864. for _p in person_phone:
  1865. if per.entity_text not in agency_contact and _p.entity_text not in agency_phone:
  1866. PackDict[k]["roleList"][i].linklist.append((per.entity_text, _p.entity_text))
  1867. elif PackDict[k]["roleList"][i].role_name == "agency":
  1868. if PackDict[k]["roleList"][i].entity_text != link_p.entity_text and link_p.label == 1:
  1869. not_sure_linked.append(link_p)
  1870. continue
  1871. if PackDict[k]["roleList"][i].entity_text == link_p.entity_text:
  1872. for per in link_p.pointer_person:
  1873. person_phone = [phone for phone in per.person_phone] if per.person_phone else []
  1874. if not person_phone:
  1875. if per.entity_text not in tenderee_contact:
  1876. PackDict[k]["roleList"][i].linklist.append((per.entity_text, ""))
  1877. continue
  1878. for _p in person_phone:
  1879. if per.entity_text not in tenderee_contact and _p.entity_text not in tenderee_phone:
  1880. PackDict[k]["roleList"][i].linklist.append((per.entity_text, _p.entity_text))
  1881. else:
  1882. if PackDict[k]["roleList"][i].entity_text == link_p.entity_text:
  1883. for per in link_p.pointer_person:
  1884. person_phone = [phone for phone in per.person_phone] if per.person_phone else []
  1885. if not person_phone:
  1886. if per.entity_text not in tenderee_contact and per.entity_text not in agency_contact:
  1887. # 角色为中标候选人,联系人无号码且上文没有联系关键词时排除
  1888. if re.search("联系人|联系方式|电话|负责人|经理|法人|法定代表人",list_sentence[per.sentence_index].sentence_text[max(0, per.wordOffset_begin - 10):per.wordOffset_begin]):
  1889. PackDict[k]["roleList"][i].linklist.append((per.entity_text, ""))
  1890. winter_contact.add(per.entity_text)
  1891. continue
  1892. for _p in person_phone:
  1893. if per.entity_text not in tenderee_contact and _p.entity_text not in tenderee_phone and \
  1894. per.entity_text not in agency_contact and _p.entity_text not in agency_phone:
  1895. PackDict[k]["roleList"][i].linklist.append((per.entity_text, _p.entity_text))
  1896. winter_contact.add(per.entity_text)
  1897. # 更新org/company实体label为0,1的链接
  1898. for link_p in not_sure_linked:
  1899. for k in PackDict.keys():
  1900. for i in range(len(PackDict[k]["roleList"])):
  1901. if PackDict[k]["roleList"][i].role_name == "tenderee":
  1902. if link_p.label == 0:
  1903. for per in link_p.pointer_person:
  1904. person_phone = [phone for phone in per.person_phone] if per.person_phone else []
  1905. if not person_phone:
  1906. if per.entity_text not in agency_contact and per.entity_text not in winter_contact:
  1907. PackDict[k]["roleList"][i].linklist.append((per.entity_text, ""))
  1908. continue
  1909. for _p in person_phone:
  1910. if per.entity_text not in agency_contact and _p.entity_text not in agency_phone and per.entity_text not in winter_contact:
  1911. PackDict[k]["roleList"][i].linklist.append((per.entity_text, _p.entity_text))
  1912. elif PackDict[k]["roleList"][i].role_name == "agency":
  1913. if link_p.label == 1:
  1914. for per in link_p.pointer_person:
  1915. person_phone = [phone for phone in per.person_phone] if per.person_phone else []
  1916. if not person_phone:
  1917. if per.entity_text not in tenderee_contact and per.entity_text not in winter_contact:
  1918. PackDict[k]["roleList"][i].linklist.append((per.entity_text, ""))
  1919. continue
  1920. for _p in person_phone:
  1921. if per.entity_text not in tenderee_contact and _p.entity_text not in tenderee_phone and per.entity_text not in winter_contact:
  1922. PackDict[k]["roleList"][i].linklist.append((per.entity_text, _p.entity_text))
  1923. # 使用中标信息大纲提取联系人
  1924. winter_scope_group = []
  1925. if winter_scope:
  1926. winter_scope_begin = winter_scope[0]
  1927. winter_scope_end = winter_scope[1]
  1928. # print(list_sentence[winter_scope_begin[0]].sentence_text[winter_scope_begin[1]:winter_scope_end[1]])
  1929. winter_temporary_list = []
  1930. for entity in list_entity:
  1931. if entity.entity_type in ['org', 'company', 'person']:
  1932. winter_temporary_list.append(entity)
  1933. winter_temporary_list = sorted(winter_temporary_list, key=lambda x: (x.sentence_index, x.begin_index))
  1934. winter_temporary_list2 = []
  1935. for _entity in winter_temporary_list:
  1936. if _entity.sentence_index>=winter_scope_begin[0] and _entity.sentence_index<=winter_scope_end[0]:
  1937. if (_entity.sentence_index==winter_scope_begin[0] and _entity.wordOffset_begin>=winter_scope_begin[1]) or \
  1938. _entity.sentence_index>winter_scope_begin[0]:
  1939. if (_entity.sentence_index == winter_scope_end[0] and _entity.wordOffset_end<=winter_scope_end[1]) or \
  1940. _entity.sentence_index<winter_scope_end[0]:
  1941. winter_temporary_list2.append(_entity)
  1942. # print('winter_scope_entity',[i.entity_text for i in winter_temporary_list2])
  1943. winter_scope_group = winter_temporary_list2
  1944. match_list_winter = []
  1945. for index in range(len(winter_scope_group)):
  1946. entity = winter_scope_group[index]
  1947. if entity.entity_type in ['company','org']:
  1948. match_nums = 0
  1949. for after_index in range(index + 1, min(len(winter_scope_group), index + 4)):
  1950. after_entity = winter_scope_group[after_index]
  1951. if match_nums > 2:
  1952. break
  1953. if after_entity.entity_type == 'person':
  1954. distance = (tokens_num_dict[after_entity.sentence_index] + after_entity.begin_index) - (
  1955. tokens_num_dict[entity.sentence_index] + entity.end_index)
  1956. # 实体为中标人/候选人,联系人已确定类别【1,2】
  1957. if entity.label in [2, 3, 4] and after_entity.label in [1, 2]:
  1958. break
  1959. if entity.label in [2, 3, 4] and distance >= 30:
  1960. break
  1961. # 角色为中标候选人,排除"质疑|投诉|监督|受理"相关的联系人
  1962. if entity.label in [2, 3, 4] and re.search(not_win_tenderer_contact, list_sentence[after_entity.sentence_index].sentence_text[max(0,after_entity.wordOffset_begin - 15):after_entity.wordOffset_begin]):
  1963. break
  1964. # 角色为中标候选人,联系人无号码且上文没有联系关键词时排除
  1965. if entity.label in [2, 3, 4] and not after_entity.person_phone and not re.search(
  1966. "联系人|联系方式|电话|负责人|经理|法人|法定代表人", list_sentence[after_entity.sentence_index].sentence_text[max(0,after_entity.wordOffset_begin - 10):after_entity.wordOffset_begin]):
  1967. continue
  1968. # 角色为招标/代理人,排除"纪检|监察"相关的联系人
  1969. if (entity.label in [0,1] or entity.entity_text in tenderee_entity_set|agency_entity_set) and re.search("纪检|监察|投诉|监督|乙方|中标", list_sentence[after_entity.sentence_index].sentence_text[max(0,after_entity.wordOffset_begin - 10):after_entity.wordOffset_begin]):
  1970. break
  1971. if after_entity.sentence_index != 0 and after_entity.wordOffset_begin <= 10:
  1972. if entity.label in [2, 3, 4] and re.search("请.{0,5}联系",list_sentence[after_entity.sentence_index - 1].sentence_text[-10:] +
  1973. list_sentence[after_entity.sentence_index].sentence_text[0:after_entity.wordOffset_begin]):
  1974. continue
  1975. if distance < 80:
  1976. if (entity.label == 0 and after_entity.label == 1) or (
  1977. entity.label == 1 and after_entity.label == 2):
  1978. distance = distance / 100
  1979. value = (-1 / 2 * (distance ** 2)) / 10000
  1980. match_list_winter.append(Match(entity, after_entity, value))
  1981. match_nums += 1
  1982. # 前向查找匹配
  1983. if index != 0:
  1984. previous_entity = winter_scope_group[index - 1]
  1985. if previous_entity.entity_type == 'person' and previous_entity.label in [1,2,3]:
  1986. if entity.label in [2, 3, 4] and previous_entity.label in [1, 2]:
  1987. continue
  1988. # 角色为中标候选人,排除"质疑|投诉|监督|受理"相关的联系人
  1989. if entity.label in [2, 3, 4] and re.search(not_win_tenderer_contact, list_sentence[previous_entity.sentence_index].sentence_text[
  1990. max(0,previous_entity.wordOffset_begin - 15):previous_entity.wordOffset_begin]):
  1991. break
  1992. # 角色为中标候选人,联系人无号码且上文没有联系关键词时排除
  1993. if entity.label in [2, 3, 4] and not previous_entity.person_phone and not re.search(
  1994. "联系人|联系方式|电话|负责人|经理|法人|法定代表人",list_sentence[previous_entity.sentence_index].sentence_text[
  1995. max(0, previous_entity.wordOffset_begin - 10):previous_entity.wordOffset_begin]):
  1996. continue
  1997. # 角色为招标/代理人,排除"纪检|监察"相关的联系人
  1998. if (entity.label in [0,1] or entity.entity_text in tenderee_entity_set|agency_entity_set) and re.search("纪检|监察|投诉|监督|乙方|中标", list_sentence[previous_entity.sentence_index].sentence_text[
  1999. max(0,previous_entity.wordOffset_begin - 10):previous_entity.wordOffset_begin]):
  2000. break
  2001. if previous_entity.sentence_index == entity.sentence_index:
  2002. distance = (tokens_num_dict[entity.sentence_index] + entity.begin_index) - (
  2003. tokens_num_dict[
  2004. previous_entity.sentence_index] + previous_entity.end_index)
  2005. if distance < 30:
  2006. # 距离相等时,前向添加处罚值
  2007. # distance += 1
  2008. # 前向 没有 /10000
  2009. value = (-1 / 2 * (distance ** 2))
  2010. match_list_winter.append(Match(entity, previous_entity, value))
  2011. # test
  2012. # match_list_winter = company_contact_link([winter_scope_group])
  2013. # km算法分配求解
  2014. result_winter = dispatch(match_list_winter)
  2015. for match in result_winter:
  2016. _company = match[0]
  2017. _person = match[1]
  2018. _person = _person.entity_text
  2019. # 更新中标人联系方式
  2020. if _company.label==2:
  2021. phone_ = [i.entity_text for i in match[1].person_phone] if match[1].person_phone else []
  2022. for k in PackDict.keys():
  2023. for i in range(len(PackDict[k]["roleList"])):
  2024. if PackDict[k]["roleList"][i].role_name == "win_tenderer":
  2025. if PackDict[k]["roleList"][i].entity_text == _company.entity_text:
  2026. if _person not in tenderee_contact and len(set(phone_) & set(tenderee_phone)) == 0 and \
  2027. _person not in agency_contact and len(set(phone_) & set(agency_phone)) == 0:
  2028. if not phone_:
  2029. PackDict[k]["roleList"][i].linklist.append((_person, ""))
  2030. for p in phone_:
  2031. PackDict[k]["roleList"][i].linklist.append((_person, p))
  2032. if phone_:
  2033. for p in phone_:
  2034. rule_winter_phone.add(p)
  2035. # print('rule_winter_phone',rule_winter_phone)
  2036. re_split = re.compile("[^\u4e00-\u9fa5、](十一|十二|十三|十四|十五|一|二|三|四|五|六|七|八|九|十)、")
  2037. split_list = [0] * 16
  2038. split_dict = {
  2039. "一、": 1,
  2040. "二、": 2,
  2041. "三、": 3,
  2042. "四、": 4,
  2043. "五、": 5,
  2044. "六、": 6,
  2045. "七、": 7,
  2046. "八、": 8,
  2047. "九、": 9,
  2048. "十、": 10,
  2049. "十一、": 11,
  2050. "十二、": 12,
  2051. "十三、": 13,
  2052. "十四、": 14,
  2053. "十五、": 15
  2054. }
  2055. for item in re.finditer(re_split, _content):
  2056. _index = split_dict.get(item.group()[1:])
  2057. if not split_list[_index]:
  2058. split_list[_index] = item.span()[0] + 1
  2059. split_list = [i for i in split_list if i != 0]
  2060. start = 0
  2061. new_split_list = []
  2062. for idx in split_list:
  2063. new_split_list.append((start, idx))
  2064. start = idx
  2065. new_split_list.append((start, len(_content)))
  2066. # 实体列表按照“公告分段”分组
  2067. words_num_dict = dict()
  2068. last_words_num = 0
  2069. for sentence in list_sentence:
  2070. _index = sentence.sentence_index
  2071. if _index == 0:
  2072. words_num_dict[_index] = 0
  2073. else:
  2074. words_num_dict[_index] = words_num_dict[_index - 1] + last_words_num
  2075. last_words_num = len(sentence.sentence_text)
  2076. # 公司-联系人连接(km算法)
  2077. re_phone = re.compile('1[3-9][0-9][-—-―]?\d{4}[-—-―]?\d{4}|'
  2078. '\+86.?1[3-9]\d{9}|'
  2079. # '0[1-9]\d{1,2}[-—-―][1-9]\d{6,7}/[1-9]\d{6,10}|'
  2080. '0[1-9]\d{1,2}[-—-―][2-9]\d{6,7}[^\d]?转\d{1,4}|'
  2081. '0[1-9]\d{1,2}[-—-―][2-9]\d{6}\d?[-—-―]\d{1,4}|'
  2082. '0[1-9]\d{1,2}[-—-―]{0,2}[2-9]\d{6}\d?(?=1[3-9]\d{9})|'
  2083. '0[1-9]\d{1,2}[-—-―]{0,2}[2-9]\d{6}\d?(?=0[1-9]\d{1,2}[-—-―]?[2-9]\d{6}\d?)|'
  2084. '0[1-9]\d{1,2}[-—-―]{0,2}[2-9]\d{6}\d?(?=[2-9]\d{6,7})|'
  2085. '0[1-9]\d{1,2}[-—-―]{0,2}[2-9]\d{6}\d?|'
  2086. '[\(|\(]0[1-9]\d{1,2}[\)|\)]-?[2-9]\d{6,7}-?\d{,4}|'
  2087. '400\d{7}转\d{1,4}|'
  2088. '[2-9]\d{6,7}')
  2089. key_phone = re.compile("联系方式|电话|联系人|负责人")
  2090. temporary_list2 = []
  2091. for entity in list_entity:
  2092. # if entity.entity_type in ['org', 'company', 'person'] and entity.is_tail==False:
  2093. if entity.entity_type in ['org', 'company', 'person']:
  2094. temporary_list2.append(entity)
  2095. temporary_list2 = sorted(temporary_list2, key=lambda x: (x.sentence_index, x.begin_index))
  2096. new_temporary_list2 = []
  2097. for _split in new_split_list:
  2098. temp_list = []
  2099. for _entity in temporary_list2:
  2100. if words_num_dict[_entity.sentence_index] + _entity.wordOffset_begin >= _split[0] and words_num_dict[
  2101. _entity.sentence_index] + _entity.wordOffset_end < _split[1]:
  2102. temp_list.append(_entity)
  2103. elif words_num_dict[_entity.sentence_index] + _entity.wordOffset_begin >= _split[1]:
  2104. break
  2105. new_temporary_list2.append(temp_list)
  2106. # print(new_temporary_list2)
  2107. match_list2 = []
  2108. for split_index in range(len(new_temporary_list2)):
  2109. split_entitys = new_temporary_list2[split_index]
  2110. if len(split_entitys)<=1:
  2111. continue
  2112. is_skip = False
  2113. for index in range(len(split_entitys)):
  2114. entity = split_entitys[index]
  2115. if is_skip:
  2116. is_skip = False
  2117. continue
  2118. else:
  2119. if entity.entity_type in ['org', 'company']:
  2120. if entity.label != 5 or entity.entity_text in roleSet:
  2121. match_nums = 0
  2122. for after_index in range(index + 1, min(len(split_entitys), index + 4)):
  2123. after_entity = split_entitys[after_index]
  2124. if entity.in_attachment != after_entity.in_attachment:
  2125. break
  2126. if after_entity.entity_type in ['person']:
  2127. distance = (tokens_num_dict[after_entity.sentence_index] + after_entity.begin_index) - (
  2128. tokens_num_dict[entity.sentence_index] + entity.end_index)
  2129. # 实体为中标人/候选人,联系人已确定类别【1,2】
  2130. if entity.label in [2, 3, 4] and after_entity.label in [1, 2]:
  2131. break
  2132. if entity.label in [2, 3, 4] and distance>=30:
  2133. break
  2134. # 角色为中标候选人,排除"质疑|投诉|监督|受理"相关的联系人
  2135. # if entity.label in [2, 3, 4] and re.search("纪检|监察|质疑|投诉|监督|受理|项目(单位|业主)?联系|(采购|招标)人?联系|请.{0,4}联系", list_sentence[after_entity.sentence_index].sentence_text[max(0,after_entity.wordOffset_begin - 10):after_entity.wordOffset_begin]):
  2136. if entity.label in [2, 3, 4] and re.search(not_win_tenderer_contact, list_sentence[after_entity.sentence_index].sentence_text[max(0,after_entity.wordOffset_begin - 15):after_entity.wordOffset_begin]):
  2137. # print('not_win_tenderer_contact2')
  2138. break
  2139. # 角色为中标候选人,联系人无号码且上文没有联系关键词时排除
  2140. # print('test',after_entity.entity_text,after_entity.person_phone,list_sentence[after_entity.sentence_index].sentence_text[max(0,after_entity.wordOffset_begin - 10):after_entity.wordOffset_begin])
  2141. if entity.label in [2, 3, 4] and not after_entity.person_phone and not re.search("联系人|联系方式|电话|负责人|经理|法人|法定代表人",list_sentence[after_entity.sentence_index].sentence_text[max(0,after_entity.wordOffset_begin - 10):after_entity.wordOffset_begin]):
  2142. continue
  2143. # 角色为招标/代理人,排除"纪检|监察"相关的联系人
  2144. if (entity.label in [0,1] or entity.entity_text in tenderee_entity_set|agency_entity_set) and re.search("纪检|监察|投诉|监督|乙方|中标",list_sentence[after_entity.sentence_index].sentence_text[max(0,after_entity.wordOffset_begin - 10):after_entity.wordOffset_begin]):
  2145. break
  2146. if after_entity.sentence_index != 0 and after_entity.wordOffset_begin <= 10:
  2147. if entity.label in [2, 3, 4] and re.search("请.{0,5}联系",
  2148. list_sentence[after_entity.sentence_index - 1].sentence_text[-10:] +
  2149. list_sentence[after_entity.sentence_index].sentence_text[0:after_entity.wordOffset_begin]):
  2150. continue
  2151. if after_entity.label in [1, 2, 3]:
  2152. # distance = (tokens_num_dict[
  2153. # after_entity.sentence_index] + after_entity.begin_index) - (
  2154. # tokens_num_dict[entity.sentence_index] + entity.end_index)
  2155. sentence_distance = after_entity.sentence_index - entity.sentence_index
  2156. if sentence_distance == 0:
  2157. if distance < 100:
  2158. if entity.label in [2, 3, 4] and distance>40:
  2159. break
  2160. if (entity.label == 0 and after_entity.label == 1) or (
  2161. entity.label == 1 and after_entity.label == 2):
  2162. distance = distance / 100
  2163. value = (-1 / 2 * (distance ** 2)) / 10000
  2164. match_list2.append(Match(entity, after_entity, value))
  2165. match_nums += 1
  2166. else:
  2167. if distance < 60:
  2168. if entity.label in [2, 3, 4] and distance>20:
  2169. break
  2170. if (entity.label == 0 and after_entity.label == 1) or (
  2171. entity.label == 1 and after_entity.label == 2):
  2172. distance = distance / 100
  2173. value = (-1 / 2 * (distance ** 2)) / 10000
  2174. match_list2.append(Match(entity, after_entity, value))
  2175. match_nums += 1
  2176. if after_entity.entity_type in ['org', 'company']:
  2177. if entity.label in [2, 3, 4] and after_entity.label in [0, 1]:
  2178. break
  2179. # 解决在‘地址’中识别出org/company的问题
  2180. # if entity.label in [0,1] and after_index==index+1 and after_entity.label not in [0,1]:
  2181. if entity.label != 5 and after_index == index + 1 and (
  2182. after_entity.label == entity.label or after_entity.label == 5):
  2183. distance = (tokens_num_dict[
  2184. after_entity.sentence_index] + after_entity.begin_index) - (
  2185. tokens_num_dict[entity.sentence_index] + entity.end_index)
  2186. if distance < 20:
  2187. after_entity_left = list_sentence[after_entity.sentence_index].tokens[max(0,
  2188. after_entity.begin_index - 10):after_entity.begin_index]
  2189. after_entity_right = list_sentence[after_entity.sentence_index].tokens[
  2190. after_entity.end_index + 1:after_entity.end_index + 6]
  2191. after_entity_left = "".join(after_entity_left)
  2192. if len(after_entity_left) > 20:
  2193. after_entity_left = after_entity_left[-20:]
  2194. after_entity_right = "".join(after_entity_right)[:10]
  2195. if re.search("地,?址", after_entity_left):
  2196. is_skip = True
  2197. continue
  2198. if re.search("\(|(", after_entity_left) and re.search("\)|)",after_entity_right):
  2199. is_skip = True
  2200. continue
  2201. if entity.label in [0, 1] and after_entity.label in [0, 1] and entity.label == after_entity.label:
  2202. break
  2203. if entity.label in [0, 1] and after_entity.label in [0, 1] and split_entitys[
  2204. index + 1].entity_type == "person":
  2205. break
  2206. if entity.label in [0, 1 ,5] and after_entity.label in [2, 3, 4]:
  2207. break
  2208. if entity.label in [2, 3, 4] and after_entity.label in [0, 1]:
  2209. break
  2210. # 搜索没有联系人的电话
  2211. mid_tokens = []
  2212. is_same_sentence = False
  2213. if index == len(split_entitys) - 1:
  2214. for i in range(entity.sentence_index, len(list_sentence)):
  2215. mid_tokens += list_sentence[i].tokens
  2216. mid_tokens = mid_tokens[entity.end_index + 1:]
  2217. mid_sentence = "".join(mid_tokens)
  2218. have_phone = re.findall(re_phone, mid_sentence)
  2219. if have_phone:
  2220. if re.findall(re_phone, mid_sentence.split("。")[0]):
  2221. is_same_sentence = True
  2222. _phone = have_phone[0]
  2223. if _phone in [ent.entity_text for ent in phone_entitys]:
  2224. phone_begin = mid_sentence.find(_phone)
  2225. if words_num_dict[entity.sentence_index] + entity.wordOffset_begin + phone_begin < \
  2226. new_split_list[split_index][1]:
  2227. mid_sentence = mid_sentence[max(0, phone_begin - 15):phone_begin].replace(",", "")
  2228. if re.search(key_phone, mid_sentence):
  2229. # if entity.label in [2, 3, 4] and re.search("纪检|监察|质疑|投诉|监督|受理|项目(单位|业主)?联系|(采购|招标)人?联系|请.{0,4}联系",mid_sentence[-10:]):
  2230. if entity.label in [2, 3, 4] and re.search(not_win_tenderer_contact,mid_sentence[-15:]):
  2231. # print('not_win_tenderer_contact3')
  2232. pass
  2233. else:
  2234. distance = 1
  2235. if is_same_sentence:
  2236. if phone_begin <= 200:
  2237. if entity.label in [2,3,4] and phone_begin>80:
  2238. break
  2239. value = (-1 / 2 * (distance ** 2)) / 10000
  2240. match_list2.append(Match(entity, (entity, _phone), value))
  2241. match_nums += 1
  2242. else:
  2243. if phone_begin <= 60:
  2244. if entity.label in [2,3,4] and phone_begin>40:
  2245. break
  2246. value = (-1 / 2 * (distance ** 2)) / 10000
  2247. match_list2.append(Match(entity, (entity, _phone), value))
  2248. match_nums += 1
  2249. else:
  2250. next_entity = split_entitys[index + 1]
  2251. if next_entity.entity_type in ["org","company"]:
  2252. _entity_left = list_sentence[next_entity.sentence_index].sentence_text[entity.wordOffset_end:next_entity.wordOffset_begin]
  2253. _entity_left2 = re.sub(",()\(\)::", "", _entity_left)
  2254. _entity_left2 = _entity_left2[-5:]
  2255. if re.search("(地,?址|地,?点)[::][^,。]*$", _entity_left) or re.search("地址|地点", _entity_left2):
  2256. if index + 2<= len(split_entitys) - 1:
  2257. next_entity = split_entitys[index + 2]
  2258. if len(_entity_left)<=2 and re.search("[、(\(]",_entity_left):
  2259. if index + 2 <= len(split_entitys) - 1:
  2260. next_entity = split_entitys[index + 2]
  2261. if entity.sentence_index == next_entity.sentence_index:
  2262. mid_tokens += list_sentence[entity.sentence_index].tokens[
  2263. entity.end_index + 1:next_entity.begin_index]
  2264. else:
  2265. sentence_index = entity.sentence_index
  2266. while sentence_index <= next_entity.sentence_index:
  2267. mid_tokens += list_sentence[sentence_index].tokens
  2268. sentence_index += 1
  2269. mid_tokens = mid_tokens[entity.end_index + 1:-(len(
  2270. list_sentence[next_entity.sentence_index].tokens) - next_entity.begin_index) + 1]
  2271. mid_sentence = "".join(mid_tokens)
  2272. have_phone = re.findall(re_phone, mid_sentence)
  2273. if have_phone:
  2274. if re.findall(re_phone, mid_sentence.split("。")[0]):
  2275. is_same_sentence = True
  2276. _phone = have_phone[0]
  2277. if _phone in [ent.entity_text for ent in phone_entitys]:
  2278. phone_begin = mid_sentence.find(_phone)
  2279. mid_sentence = mid_sentence[max(0, phone_begin - 15):phone_begin].replace(",", "")
  2280. if re.search(key_phone, mid_sentence):
  2281. p_phone = [p.entity_text for p in next_entity.person_phone] if next_entity.person_phone else []
  2282. if next_entity.entity_type == 'person' and _phone in p_phone:
  2283. pass
  2284. # elif entity.label in [2, 3, 4] and re.search("纪检|监察|质疑|投诉|监督|受理|项目(单位|业主)?联系|(采购|招标)人?联系|请.{0,4}联系", mid_sentence[-10:]):
  2285. elif entity.label in [2, 3, 4] and re.search(not_win_tenderer_contact, mid_sentence[-15:]):
  2286. # print('not_win_tenderer_contact4')
  2287. pass
  2288. else:
  2289. distance = (tokens_num_dict[
  2290. next_entity.sentence_index] + next_entity.begin_index) - (
  2291. tokens_num_dict[entity.sentence_index] + entity.end_index)
  2292. distance = distance / 2
  2293. if is_same_sentence:
  2294. if phone_begin <= 200:
  2295. value = (-1 / 2 * (distance ** 2)) / 10000
  2296. match_list2.append(Match(entity, (entity, _phone), value))
  2297. match_nums += 1
  2298. else:
  2299. if phone_begin <= 60:
  2300. value = (-1 / 2 * (distance ** 2)) / 10000
  2301. match_list2.append(Match(entity, (entity, _phone), value))
  2302. match_nums += 1
  2303. # 实体无匹配时,尝试前向查找匹配
  2304. if not match_nums:
  2305. if (entity.label != 5 or entity.entity_text in roleSet) and entity.values[entity.label] >= 0.5 and index != 0:
  2306. previous_entity = split_entitys[index - 1]
  2307. if previous_entity.entity_type == 'person' and previous_entity.label in [1, 2, 3]:
  2308. if entity.label in [2, 3, 4] and previous_entity.label in [1, 2]:
  2309. continue
  2310. # 角色为中标候选人,排除"质疑|投诉|监督|受理"相关的联系人
  2311. if entity.label in [2, 3, 4] and re.search(not_win_tenderer_contact,list_sentence[previous_entity.sentence_index].sentence_text[
  2312. max(0,previous_entity.wordOffset_begin - 15):previous_entity.wordOffset_begin]):
  2313. # print('not_win_tenderer_contact2')
  2314. break
  2315. # 角色为中标候选人,联系人无号码且上文没有联系关键词时排除
  2316. if entity.label in [2, 3,4] and not previous_entity.person_phone and not re.search("联系人|联系方式|电话|负责人|经理|法人|法定代表人",
  2317. list_sentence[previous_entity.sentence_index].sentence_text[max(0,previous_entity.wordOffset_begin - 10):previous_entity.wordOffset_begin]):
  2318. continue
  2319. # 角色为招标/代理人,排除"纪检|监察"相关的联系人
  2320. if (entity.label in [0,1] or entity.entity_text in tenderee_entity_set|agency_entity_set) and re.search("纪检|监察|投诉|监督|乙方|中标", list_sentence[previous_entity.sentence_index].sentence_text[
  2321. max(0,previous_entity.wordOffset_begin - 10):previous_entity.wordOffset_begin]):
  2322. break
  2323. if previous_entity.sentence_index == entity.sentence_index:
  2324. distance = (tokens_num_dict[entity.sentence_index] + entity.begin_index) - (
  2325. tokens_num_dict[
  2326. previous_entity.sentence_index] + previous_entity.end_index)
  2327. if distance < 20:
  2328. # 距离相等时,前向添加处罚值
  2329. # distance += 1
  2330. # 前向 没有 /10000
  2331. value = (-1 / 2 * (distance ** 2))
  2332. match_list2.append(Match(entity, previous_entity, value))
  2333. # print(match_list2)
  2334. # print([(mat.main_role.entity_text,mat.attribute.entity_text if not isinstance(mat.attribute, tuple) else mat.attribute[1]) for mat in match_list2])
  2335. match_list2 = [mat for mat in match_list2 if mat.main_role not in linked_company and mat.attribute not in linked_person]
  2336. # print(match_list2)
  2337. # print([(mat.main_role.entity_text,mat.attribute.entity_text if not isinstance(mat.attribute, tuple) else mat.attribute[1]) for mat in match_list2])
  2338. # km算法分配求解
  2339. result2 = dispatch(match_list2)
  2340. # print(result2)
  2341. for match in result2:
  2342. entity = match[0]
  2343. # print(entity.entity_text)
  2344. # print(entity.label)
  2345. # print(match.attribute)
  2346. entity_index = list_entity.index(entity)
  2347. is_update = False
  2348. if isinstance(match[1], tuple):
  2349. person_ = ''
  2350. phone_ = match[1][1].split("/") # 分割多个号码
  2351. # print(person_,phone_)
  2352. else:
  2353. person_ = match[1].entity_text
  2354. phone_ = [i.entity_text for i in match[1].person_phone] if match[1].person_phone else []
  2355. for k in PackDict.keys():
  2356. for i in range(len(PackDict[k]["roleList"])):
  2357. if PackDict[k]["roleList"][i].role_name == "tenderee":
  2358. # if not PackDict[k]["roleList"][i].linklist:
  2359. if PackDict[k]["roleList"][i].entity_text == entity.entity_text or entity.label == 0:
  2360. if person_ not in agency_contact and len(set(phone_)&set(agency_phone))==0 and person_ not in winter_contact:
  2361. if not phone_:
  2362. PackDict[k]["roleList"][i].linklist.append((person_, ""))
  2363. for p in phone_:
  2364. # if not person_ and len()
  2365. PackDict[k]["roleList"][i].linklist.append((person_, p))
  2366. is_update = True
  2367. elif PackDict[k]["roleList"][i].role_name == "agency":
  2368. # if not PackDict[k]["roleList"][i].linklist:
  2369. if PackDict[k]["roleList"][i].entity_text == entity.entity_text or entity.label == 1 and person_ not in winter_contact:
  2370. if person_ not in tenderee_contact and len(set(phone_)&set(tenderee_phone))==0:
  2371. if not phone_:
  2372. PackDict[k]["roleList"][i].linklist.append((person_, ""))
  2373. for p in phone_:
  2374. PackDict[k]["roleList"][i].linklist.append((person_, p))
  2375. is_update = True
  2376. else:
  2377. if PackDict[k]["roleList"][i].entity_text == entity.entity_text:
  2378. # if not PackDict[k]["roleList"][i].linklist:
  2379. if len([item for item in PackDict[k]["roleList"][i].linklist if item[1]])==0: # 有联系人但无联系方式(号码)
  2380. if person_ not in tenderee_contact and len(set(phone_)&set(tenderee_phone))==0 and \
  2381. person_ not in agency_contact and len(set(phone_)&set(agency_phone))==0:
  2382. if not phone_:
  2383. PackDict[k]["roleList"][i].linklist.append((person_, ""))
  2384. for p in phone_:
  2385. PackDict[k]["roleList"][i].linklist.append((person_, p))
  2386. is_update = True
  2387. if not person_:
  2388. is_update = False
  2389. if is_update:
  2390. # 更新 list_entity
  2391. if not list_entity[entity_index].pointer_person:
  2392. list_entity[entity_index].pointer_person = []
  2393. list_entity[entity_index].pointer_person.append(match[1])
  2394. # print('tenderee_contact',tenderee_contact)
  2395. # print('tenderee_phone',tenderee_phone)
  2396. # print('agency_contact',agency_contact)
  2397. # print('agency_phone',agency_phone)
  2398. # print('PackDict')
  2399. # for k in PackDict.keys():
  2400. # for i in range(len(PackDict[k]["roleList"])):
  2401. # print(PackDict[k]["roleList"][i].role_name)
  2402. # print(PackDict[k]["roleList"][i].entity_text)
  2403. # print(PackDict[k]["roleList"][i].linklist)
  2404. linked_person = []
  2405. linked_persons_with = []
  2406. for company_entity in [entity for entity in list_entity if entity.entity_type in ['company','org']]:
  2407. if company_entity.pointer_person:
  2408. for _person in company_entity.pointer_person:
  2409. linked_person.append(_person)
  2410. linked_persons_with.append(company_entity)
  2411. # 一个公司对应多个联系人的补充
  2412. person_entitys = [entity for entity in list_entity if entity.entity_type=='person']
  2413. person_entitys = person_entitys[::-1]
  2414. for index in range(len(person_entitys)):
  2415. entity = person_entitys[index]
  2416. prepare_link = []
  2417. if entity not in linked_person:
  2418. prepare_link.append(entity)
  2419. last_person = entity
  2420. for after_index in range(index + 1, min(len(person_entitys), index + 5)):
  2421. after_entity = person_entitys[after_index]
  2422. if after_entity.sentence_index==last_person.sentence_index and last_person.begin_index-after_entity.end_index<5:
  2423. if after_entity in linked_person:
  2424. _index = linked_person.index(after_entity)
  2425. with_company = linked_persons_with[_index]
  2426. for i in range(len(PackDict["Project"]["roleList"])):
  2427. if PackDict["Project"]["roleList"][i].role_name == "tenderee":
  2428. if PackDict["Project"]["roleList"][i].entity_text == with_company.entity_text or with_company.label == 0:
  2429. for item in prepare_link:
  2430. person_phone = [p.entity_text for p in item.person_phone] if item.person_phone else []
  2431. for _p in person_phone:
  2432. PackDict["Project"]["roleList"][i].linklist.append((item.entity_text, _p))
  2433. with_company.pointer_person.append(item)
  2434. linked_person.append(item)
  2435. elif PackDict["Project"]["roleList"][i].role_name == "agency":
  2436. if PackDict["Project"]["roleList"][i].entity_text == with_company.entity_text or with_company.label == 1:
  2437. for item in prepare_link:
  2438. person_phone = [p.entity_text for p in item.person_phone] if item.person_phone else []
  2439. for _p in person_phone:
  2440. PackDict["Project"]["roleList"][i].linklist.append((item.entity_text, _p))
  2441. with_company.pointer_person.append(item)
  2442. linked_person.append(item)
  2443. else:
  2444. if PackDict["Project"]["roleList"][i].entity_text == with_company.entity_text:
  2445. for item in prepare_link:
  2446. person_phone = [p.entity_text for p in item.person_phone] if item.person_phone else []
  2447. for _p in person_phone:
  2448. PackDict["Project"]["roleList"][i].linklist.append((item.entity_text, _p))
  2449. with_company.pointer_person.append(item)
  2450. linked_person.append(item)
  2451. break
  2452. else:
  2453. prepare_link.append(after_entity)
  2454. last_person = after_entity
  2455. continue
  2456. # 统一同类角色的属性
  2457. for k in PackDict.keys():
  2458. for i in range(len(PackDict[k]["roleList"])):
  2459. for _entity in list_entity:
  2460. if _entity.entity_type in ['org','company']:
  2461. is_same = False
  2462. is_similar = False
  2463. # entity_text相同
  2464. if _entity.entity_text==PackDict[k]["roleList"][i].entity_text:
  2465. is_same = True
  2466. # entity.label为【0,1】
  2467. if _entity.label in [0,1] and dict_role_id[str(_entity.label)]==PackDict[k]["roleList"][i].role_name:
  2468. is_similar = True
  2469. if is_same:
  2470. linked_entitys = _entity.linked_entitys
  2471. if linked_entitys:
  2472. for linked_entity in linked_entitys:
  2473. pointer_person = linked_entity.pointer_person if linked_entity.pointer_person else []
  2474. for _pointer_person in pointer_person:
  2475. _phone = [p.entity_text for p in _pointer_person.person_phone] if _pointer_person.person_phone else []
  2476. for _p in _phone:
  2477. if (_pointer_person.entity_text,_p) not in PackDict[k]["roleList"][i].linklist:
  2478. PackDict[k]["roleList"][i].linklist.append((_pointer_person.entity_text,_p))
  2479. elif is_similar:
  2480. pointer_person = _entity.pointer_person if _entity.pointer_person else []
  2481. for _pointer_person in pointer_person:
  2482. _phone = [p.entity_text for p in _pointer_person.person_phone] if _pointer_person.person_phone else []
  2483. for _p in _phone:
  2484. if (_pointer_person.entity_text, _p) not in PackDict[k]["roleList"][i].linklist:
  2485. PackDict[k]["roleList"][i].linklist.append(
  2486. (_pointer_person.entity_text, _p))
  2487. # "roleList"中联系人电话去重
  2488. tenderee_agency_phone = []
  2489. tenderee_agency_contact = []
  2490. for k in PackDict.keys():
  2491. for i in range(len(PackDict[k]["roleList"])):
  2492. if PackDict[k]["roleList"][i].role_name in ['agency','tenderee']:
  2493. tenderee_agency_phone.extend([person_phone[1] for person_phone in PackDict[k]["roleList"][i].linklist if person_phone[1]])
  2494. tenderee_agency_contact.extend([person_phone[0]+'-'+person_phone[1] for person_phone in PackDict[k]["roleList"][i].linklist])
  2495. # 带有联系人的电话
  2496. with_person = [person_phone[1] for person_phone in PackDict[k]["roleList"][i].linklist if person_phone[0]]
  2497. # 带有电话的联系人
  2498. with_phone = [person_phone[0] for person_phone in PackDict[k]["roleList"][i].linklist if person_phone[1]]
  2499. remove_list = []
  2500. for item in PackDict[k]["roleList"][i].linklist:
  2501. if not item[0]:
  2502. if item[1] in with_person:
  2503. # 删除重复的无联系人电话
  2504. remove_list.append(item)
  2505. elif not item[1]:
  2506. if item[0] in with_phone:
  2507. remove_list.append(item)
  2508. for _item in remove_list:
  2509. PackDict[k]["roleList"][i].linklist.remove(_item)
  2510. # 中标候选人联系方式异常排除
  2511. for k in PackDict.keys():
  2512. for i in range(len(PackDict[k]["roleList"])):
  2513. if PackDict[k]["roleList"][i].role_name in ['win_tenderer', 'second_tenderer','third_tenderer']:
  2514. if tenderee_agency_phone or tenderee_agency_contact:
  2515. remove_list = []
  2516. for item in PackDict[k]["roleList"][i].linklist:
  2517. if item[1] and item[1] in tenderee_agency_phone:
  2518. remove_list.append(item)
  2519. elif item[0]+'-'+item[1] in tenderee_agency_contact:
  2520. remove_list.append(item)
  2521. for _item in remove_list:
  2522. PackDict[k]["roleList"][i].linklist.remove(_item)
  2523. elif not tenderee_agency_phone:
  2524. # 公告中无招标代理联系方式时,可排除中标联系方式
  2525. remove_list = []
  2526. for _item in PackDict[k]["roleList"][i].linklist:
  2527. # 排除非正则规则识别的联系方式
  2528. if _item[1] not in rule_winter_phone:
  2529. remove_list.append(_item)
  2530. # print('remove_list',remove_list)
  2531. for _item in remove_list:
  2532. PackDict[k]["roleList"][i].linklist.remove(_item)
  2533. # PackDict更新company/org地址
  2534. last_role_prob = {}
  2535. for ent in pre_entity:
  2536. if ent.entity_type in ['company','org']:
  2537. if ent.pointer_address:
  2538. for k in PackDict.keys():
  2539. for i in range(len(PackDict[k]["roleList"])):
  2540. if PackDict[k]["roleList"][i].entity_text == ent.entity_text:
  2541. if not PackDict[k]["roleList"][i].address:
  2542. PackDict[k]["roleList"][i].address = ent.pointer_address.entity_text
  2543. last_role_prob[PackDict[k]["roleList"][i].role_name] = ent.values[role2id_dict[PackDict[k]["roleList"][i].role_name]]
  2544. else:
  2545. if PackDict[k]["roleList"][i].role_name in ['tenderee','agency']:
  2546. # 角色为招标/代理人时,取其实体概率高的链接地址作为角色address
  2547. if ent.values[role2id_dict[PackDict[k]["roleList"][i].role_name]] > last_role_prob[PackDict[k]["roleList"][i].role_name]:
  2548. PackDict[k]["roleList"][i].address = ent.pointer_address.entity_text
  2549. last_role_prob[PackDict[k]["roleList"][i].role_name] = ent.values[role2id_dict[PackDict[k]["roleList"][i].role_name]]
  2550. else:
  2551. if len(ent.pointer_address.entity_text) > len(PackDict[k]["roleList"][i].address):
  2552. PackDict[k]["roleList"][i].address = ent.pointer_address.entity_text
  2553. # 联系人——电子邮箱链接
  2554. temporary_list3 = [entity for entity in list_entity if entity.entity_type=='email' or (entity.entity_type=='person' and entity.label in [1,2,3])]
  2555. temporary_list3 = sorted(temporary_list3, key=lambda x: (x.sentence_index, x.begin_index))
  2556. new_temporary_list3 = []
  2557. for _split in new_split_list:
  2558. temp_list = []
  2559. for _entity in temporary_list3:
  2560. if words_num_dict[_entity.sentence_index] + _entity.wordOffset_begin >= _split[0] and words_num_dict[
  2561. _entity.sentence_index] + _entity.wordOffset_end < _split[1]:
  2562. temp_list.append(_entity)
  2563. elif words_num_dict[_entity.sentence_index] + _entity.wordOffset_begin >= _split[1]:
  2564. break
  2565. new_temporary_list3.append(temp_list)
  2566. # print(new_temporary_list3)
  2567. match_list3 = []
  2568. for split_index in range(len(new_temporary_list3)):
  2569. split_entitys = new_temporary_list3[split_index]
  2570. for index in range(len(split_entitys)):
  2571. entity = split_entitys[index]
  2572. if entity.entity_type == 'person':
  2573. match_nums = 0
  2574. for after_index in range(index + 1, min(len(split_entitys), index + 4)):
  2575. after_entity = split_entitys[after_index]
  2576. if match_nums > 2:
  2577. break
  2578. if after_entity.entity_type == 'email':
  2579. distance = (tokens_num_dict[after_entity.sentence_index] + after_entity.begin_index) - (
  2580. tokens_num_dict[entity.sentence_index] + entity.end_index)
  2581. sentence_distance = after_entity.sentence_index - entity.sentence_index
  2582. if sentence_distance == 0:
  2583. if distance < 100:
  2584. if (entity.label == 0 and after_entity.label == 1) or (
  2585. entity.label == 1 and after_entity.label == 2):
  2586. distance = distance / 100
  2587. value = (-1 / 2 * (distance ** 2)) / 10000
  2588. match_list3.append(Match(entity, after_entity, value))
  2589. match_nums += 1
  2590. else:
  2591. if distance < 60:
  2592. if (entity.label == 0 and after_entity.label == 1) or (
  2593. entity.label == 1 and after_entity.label == 2):
  2594. distance = distance / 100
  2595. value = (-1 / 2 * (distance ** 2)) / 10000
  2596. match_list3.append(Match(entity, after_entity, value))
  2597. match_nums += 1
  2598. # 前向查找匹配
  2599. # if not match_nums:
  2600. if index != 0:
  2601. previous_entity = split_entitys[index - 1]
  2602. if previous_entity.entity_type == 'email':
  2603. if previous_entity.sentence_index == entity.sentence_index:
  2604. distance = (tokens_num_dict[entity.sentence_index] + entity.begin_index) - (
  2605. tokens_num_dict[
  2606. previous_entity.sentence_index] + previous_entity.end_index)
  2607. if distance < 30:
  2608. # 距离相等时,前向添加处罚值
  2609. # distance += 1
  2610. # 前向 没有 /10000
  2611. value = (-1 / 2 * (distance ** 2))
  2612. match_list3.append(Match(entity, previous_entity, value))
  2613. # print(match_list3)
  2614. # km算法分配求解
  2615. result3 = dispatch(match_list3)
  2616. for match in result3:
  2617. match_person = match[0]
  2618. match_email = match[1]
  2619. match_person.pointer_email = match_email
  2620. # # 1)第一个公司实体的招标人,则看看下一个实体是否为代理人,如果是则联系人错位连接 。2)在同一句中往后找联系人。3)连接不上在整个文章找联系人。
  2621. # temp_ent_list = [] # 临时列表,记录0,1角色及3联系人
  2622. # other_person = [] # 阈值以上的联系人列表
  2623. # link_person = [] # 有电话没联系上角色的person列表
  2624. # other_ent = []
  2625. # link_ent = []
  2626. # found_person = False
  2627. # ent_list = []
  2628. # for entity in list_entity:
  2629. # if entity.entity_type in ['org','company','person']:
  2630. # ent_list.append(entity)
  2631. # # ent_list = [entity for entity in list_entity if entity.entity_type in ['org','company','person']]
  2632. # #for list_index in range(len(ent_list)):
  2633. # #if ent_list[list_index].entity_type in ['org','company'] and ent_list[list_index].label == 0 and list_index+2<len(ent_list) and \
  2634. # #ent_list[list_index+1].entity_type in ['org','company'] and ent_list[list_index+1].label == 1 and ent_list[list_index+2].entity_type in ['person']:
  2635. # #ent_list[list_index+1], ent_list[list_index+2] = ent_list[list_index+2], ent_list[list_index+1]
  2636. # # 2020/11/25增加确定角色联系人判断
  2637. # sure_person_set = set([entity.entity_text for entity in ent_list if entity.entity_type == 'person' and entity.label in [1, 2]])
  2638. # # 招标/代理在同一句中交叉情况的处理
  2639. # for index in range(len(ent_list)):
  2640. # entity = ent_list[index]
  2641. # if entity.entity_text in roleSet and entity.label in [0, 1] and index+3<len(ent_list):
  2642. # if entity.sentence_index==ent_list[index+1].sentence_index==ent_list[index+2].sentence_index==ent_list[index+3].sentence_index:
  2643. # if ent_list[index+1].begin_index - entity.end_index < 30:
  2644. # if ent_list[index+1].entity_text in roleSet and ent_list[index+1].label in [0, 1] and entity.label!=ent_list[index+1].label:
  2645. # if ent_list[index+2].entity_type=="person" and ent_list[index+3].entity_type=="person" and \
  2646. # ent_list[index+2].label==3 and ent_list[index+3].label==3:
  2647. # ent_list[index + 1], ent_list[index + 2] = ent_list[index + 2], ent_list[index + 1]
  2648. #
  2649. #
  2650. # for index in range(len(ent_list)):
  2651. # entity = ent_list[index]
  2652. # if entity.entity_type=="person":
  2653. # if str(entity.label) == "0": # 2020/11/25 非联系人直接跳过
  2654. # continue
  2655. # if entity.values[entity.label]>on_value_person:
  2656. # if str(entity.label)=="1":
  2657. # for i in range(len(PackDict["Project"]["roleList"])):
  2658. # if PackDict["Project"]["roleList"][i].role_name=="tenderee":
  2659. # PackDict["Project"]["roleList"][i].linklist.append((entity.entity_text,entity.person_phone))
  2660. # link_person.append(entity.entity_text)
  2661. # link_ent.append(PackDict["Project"]["roleList"][i].entity_text)
  2662. # # add pointer_person
  2663. # for _entity in list_entity:
  2664. # if dict_role_id.get(str(_entity.label))=="tenderee":
  2665. # for i in range(len(PackDict["Project"]["roleList"])):
  2666. # if PackDict["Project"]["roleList"][i].entity_text==_entity.entity_text and PackDict["Project"]["roleList"][i].role_name=="tenderee":
  2667. # _entity.pointer_person = entity
  2668. # elif str(entity.label)=="2":
  2669. # for i in range(len(PackDict["Project"]["roleList"])):
  2670. # if PackDict["Project"]["roleList"][i].role_name=="agency":
  2671. # PackDict["Project"]["roleList"][i].linklist.append((entity.entity_text,entity.person_phone))
  2672. # link_person.append(entity.entity_text)
  2673. # link_ent.append(PackDict["Project"]["roleList"][i].entity_text)
  2674. # # add pointer_person
  2675. # for _entity in list_entity:
  2676. # if dict_role_id.get(str(_entity.label))=="agency":
  2677. # for i in range(len(PackDict["Project"]["roleList"])):
  2678. # if PackDict["Project"]["roleList"][i].entity_text==_entity.entity_text and PackDict["Project"]["roleList"][i].role_name=="agency":
  2679. # _entity.pointer_person = entity
  2680. # elif str(entity.label)=="3":
  2681. # if entity.entity_text in sure_person_set: # 2020/11/25 排除已经确定角色的联系人
  2682. # continue
  2683. # #not_link_person.append((entity_after.entity_text,entity_after.person_phone))
  2684. # other_person.append(entity.entity_text)
  2685. # temp_ent_list.append((entity.entity_text,entity.person_phone,entity))
  2686. #
  2687. # #if entity.entity_text in roleSet:
  2688. # if entity.entity_text in roleSet:
  2689. # if entity.label in [0,1]:
  2690. # other_ent.append(entity.entity_text)
  2691. # temp_ent_list.append((entity.entity_text, entity.label,entity))
  2692. # for behind_index in range(index+1, len(ent_list)):
  2693. # entity_after = ent_list[behind_index]
  2694. # if entity_after.sentence_index-entity.sentence_index>=1 or entity_after.entity_type in ['org','company']: # 只在本句中找联系人
  2695. # break
  2696. # if entity_after.values is not None:
  2697. # if entity_after.entity_type=="person":
  2698. # if str(entity_after.label) == "0": # 2020/11/25角色后面为非联系人 停止继续往后找
  2699. # break
  2700. # if entity_after.values[entity_after.label]>on_value_person:
  2701. # if str(entity_after.label)=="1":
  2702. # for i in range(len(PackDict["Project"]["roleList"])):
  2703. # if PackDict["Project"]["roleList"][i].role_name=="tenderee":
  2704. # PackDict["Project"]["roleList"][i].linklist.append((entity_after.entity_text,entity_after.person_phone))
  2705. # link_person.append(entity_after.entity_text)
  2706. # link_ent.append(PackDict["Project"]["roleList"][i].entity_text)
  2707. # elif str(entity_after.label)=="2":
  2708. # for i in range(len(PackDict["Project"]["roleList"])):
  2709. # if PackDict["Project"]["roleList"][i].role_name=="agency":
  2710. # PackDict["Project"]["roleList"][i].linklist.append((entity_after.entity_text,entity_after.person_phone))
  2711. # link_person.append(entity_after.entity_text)
  2712. # link_ent.append(PackDict["Project"]["roleList"][i].entity_text)
  2713. # elif str(entity_after.label)=="3":
  2714. # if entity_after.entity_text in sure_person_set: # 2020/11/25 如果姓名已经出现在确定角色联系人中则停止往后找
  2715. # break
  2716. # elif entity_after.begin_index - entity.end_index > 30:#2020/10/25 如果角色实体与联系人实体间隔大于阈值停止
  2717. # break
  2718. # for pack in PackDict.keys():
  2719. # for i in range(len(PackDict[pack]["roleList"])):
  2720. # if PackDict[pack]["roleList"][i].entity_text==entity.entity_text:
  2721. # #if entity_after.sentence_index-entity.sentence_index>1 and len(roleList[i].linklist)>0:
  2722. # #break
  2723. # PackDict[pack]["roleList"][i].linklist.append((entity_after.entity_text,entity_after.person_phone))
  2724. # link_person.append(entity_after.entity_text)
  2725. # #add pointer_person
  2726. # entity.pointer_person = entity_after
  2727. #
  2728. # not_link_person = [person for person in other_person if person not in link_person]
  2729. # not_link_ent = [ent for ent in other_ent if ent not in link_ent]
  2730. # if len(not_link_person) > 0 and len(not_link_ent) > 0 :
  2731. # item = temp_ent_list
  2732. # for i in range(len(item)):
  2733. # if item[i][0] in not_link_ent and item[i][1] == 0 and i+3 < len(item):
  2734. # if item[i+1][0] in other_ent and item[i+1][1] == 1 and item[i+2][0] in other_person and item[i+3][0] in other_person:
  2735. # item[i+1], item[i+2] = item[i+2], item[i+1]
  2736. # for i in range(len(item)-1, -1, -1):
  2737. # if item[i][0] in not_link_ent:
  2738. # for pack in PackDict.keys():
  2739. # for role in PackDict[pack]["roleList"]:
  2740. # if role.entity_text == item[i][0] and len(role.linklist) < 1:
  2741. # for j in range(i+1, len(item)):
  2742. # if item[j][0] in not_link_person:
  2743. # role.linklist.append(item[j][:2])
  2744. # #add pointer_person
  2745. # item[i][2].pointer_person = item[j][2]
  2746. # break
  2747. # else:
  2748. # break
  2749. # # 电话没有联系人的处理
  2750. # role_with_no_phone = []
  2751. # for i in range(len(PackDict["Project"]["roleList"])):
  2752. # if PackDict["Project"]["roleList"][i].role_name in ["tenderee","agency"]:
  2753. # if len(PackDict["Project"]["roleList"][i].linklist)==0: # 找出没有联系人的招标/代理人
  2754. # role_with_no_phone.append(PackDict["Project"]["roleList"][i].entity_text)
  2755. # else:
  2756. # phone_nums = 0
  2757. # for link in PackDict["Project"]["roleList"][i].linklist:
  2758. # if link[1]:
  2759. # phone_nums += 1
  2760. # break
  2761. # if not phone_nums:
  2762. # role_with_no_phone.append(PackDict["Project"]["roleList"][i].entity_text)
  2763. # if role_with_no_phone:
  2764. # phone_with_person = [entity.person_phone for entity in list_entity if entity.entity_type == "person"]
  2765. # # phone_with_person = [phone for phone in phone_with_person if phone]
  2766. #
  2767. # dict_index_sentence = {}
  2768. # for _sentence in list_sentence:
  2769. # dict_index_sentence[_sentence.sentence_index] = _sentence
  2770. # new_entity_list = [entity for entity in list_entity if entity.entity_type in ['org','company','person']]
  2771. # for index in range(len(new_entity_list)):
  2772. # entity = new_entity_list[index]
  2773. # if entity.entity_text in role_with_no_phone:
  2774. # e_sentence = dict_index_sentence[entity.sentence_index]
  2775. # entity_right = e_sentence.tokens[entity.end_index:entity.end_index+40]
  2776. # entity_right = "".join(entity_right)
  2777. # if index+1<len(new_entity_list) and entity_right.find(new_entity_list[index+1].entity_text)>-1:
  2778. # entity_right = entity_right[:entity_right.find(new_entity_list[index+1].entity_text)]
  2779. # have_phone = re.findall(phone,entity_right)
  2780. # if have_phone:
  2781. # _phone = have_phone[0]
  2782. # phone_begin = entity_right.find(_phone)
  2783. # if _phone not in phone_with_person and re.search(key_phone,entity_right[:phone_begin]):
  2784. # # entity.person_phone = _phone
  2785. # for i in range(len(PackDict["Project"]["roleList"])):
  2786. # if PackDict["Project"]["roleList"][i].entity_text == entity.entity_text:
  2787. # PackDict["Project"]["roleList"][i].linklist.append(('', _phone))
  2788. #寻找多标段招标金额
  2789. p_entity = len(list_entity)-1
  2790. set_tenderer_money = set()
  2791. list_tenderer_money = [] #2021/7/16 新增列表,倒序保存所有中标金额
  2792. unit_list = [] #2021/8/17 新增,保存金额单位
  2793. #遍历所有实体
  2794. max_prob = 0 # 保存招标金额最大概率
  2795. while(p_entity>=0):
  2796. entity = list_entity[p_entity]
  2797. if entity.entity_type=="money":
  2798. # 2021/12/03 添加成本警戒线、保证金
  2799. if entity.notes in ['保证金', '成本警戒线']:
  2800. packagePointer, _flag = getPackage(PackageList, entity.sentence_index, entity.begin_index,
  2801. "money-" + str(entity.label), MAX_DIS=2, DIRECT="L")
  2802. if packagePointer is None:
  2803. packageName = "Project"
  2804. else:
  2805. packageName = packagePointer.entity_text
  2806. if packageName == "Project":
  2807. # if PackDict["Project"]["tendereeMoney"]<float(entity.entity_text):
  2808. # PackDict["Project"]["tendereeMoney"] = str(Decimal(entity.entity_text))
  2809. if entity.notes=="保证金" and "bond" not in PackDict["Project"]:
  2810. PackDict["Project"]["bond"] = str(Decimal(entity.entity_text))
  2811. elif entity.notes=="成本警戒线" and "cost_warning" not in PackDict["Project"]:
  2812. PackDict["Project"]["cost_warning"] = str(Decimal(entity.entity_text))
  2813. else:
  2814. if entity.notes == "保证金" and "bond" not in PackDict[packageName]:
  2815. PackDict[packageName]["bond"] = str(Decimal(entity.entity_text))
  2816. elif entity.notes == "成本警戒线" and "cost_warning" not in PackDict[packageName]:
  2817. PackDict[packageName]["cost_warning"] = str(Decimal(entity.entity_text))
  2818. elif entity.values[entity.label]>=on_value:
  2819. if str(entity.label)=="1" and entity.notes != '单价':
  2820. set_tenderer_money.add(float(entity.entity_text))
  2821. list_tenderer_money.append(float(entity.entity_text)) # 2021/7/16 新增列表,倒序保存所有中标金额
  2822. unit_list.append(entity.money_unit)
  2823. # if str(entity.label)=="0":
  2824. if str(entity.label)=="0" and (entity.notes!='总投资' or float(entity.entity_text)<100000000):
  2825. '''
  2826. if p_entity>0:
  2827. p_before = list_entity[p_entity-1]
  2828. if p_before.entity_type=="money" and p_before.label==entity.label and p_before.entity_text==entity.entity_text and abs(entity.begin_index-p_before.end_index)<=2:
  2829. p_entity -= 1
  2830. continue
  2831. '''
  2832. packagePointer,_flag = getPackage(PackageList,entity.sentence_index,entity.begin_index,"money-"+str(entity.label),MAX_DIS=2,DIRECT="L")
  2833. if packagePointer is None:
  2834. packageName = "Project"
  2835. else:
  2836. packageName = packagePointer.entity_text
  2837. if packageName=="Project":
  2838. # if PackDict["Project"]["tendereeMoney"]<float(entity.entity_text):
  2839. # PackDict["Project"]["tendereeMoney"] = str(Decimal(entity.entity_text))
  2840. # if entity.values[entity.label]>on_value:
  2841. if entity.values[entity.label]>max_prob-0.005: # 选择最大概率招标金额 2024/05/23 相差0.005尽量选前面的
  2842. if entity.notes == '单价':
  2843. PackDict["Project"]["unit_tendereeMoney"] = str(Decimal(entity.entity_text))
  2844. else:
  2845. PackDict["Project"]["tendereeMoney"] = str(Decimal(entity.entity_text))
  2846. PackDict["Project"]["tendereeMoneyUnit"] = entity.money_unit
  2847. max_prob = entity.values[entity.label]
  2848. else:
  2849. if entity.notes == '单价':
  2850. PackDict[packageName]["unit_tendereeMoney"] = str(Decimal(entity.entity_text))
  2851. else:
  2852. PackDict[packageName]["tendereeMoney"] = str(Decimal(entity.entity_text))
  2853. PackDict[packageName]["tendereeMoneyUnit"] = entity.money_unit
  2854. #add pointer_tendereeMoney
  2855. packagePointer.pointer_tendereeMoney = entity
  2856. p_entity -= 1
  2857. '''标段链接包名包号'''
  2858. pk_name_l = []
  2859. pk_code_l = []
  2860. count_dic = {
  2861. 'package': set(),
  2862. 'name': set(),
  2863. 'code': set()
  2864. }
  2865. def get_sort_dist(l, max_sent_dist=2):
  2866. '''
  2867. 计算标段与其他要素距离,并按距离排序返回字典
  2868. :param l: [(entity.entity_type, entity.entity_text, entity.sentence_index, entity.wordOffset_begin, entity.wordOffset_end)]
  2869. :param max_sent_dist: 最大句子距离
  2870. :return:
  2871. '''
  2872. l.sort(key=lambda x: [x[2],x[3],x[4]]) # 20241204 多个字段排序 修复 561998414 第一标段西铭矿清水泵采购 标段和包名开始位置一样的情况
  2873. link_dic = {}
  2874. i = 1
  2875. while i < len(l):
  2876. ty1, ent1, s1, b1, e1, in_att1 = l[i - 1]
  2877. ty2, ent2, s2, b2, e2, in_att2 = l[i]
  2878. if ty1 != ty2 and in_att1 == in_att2 and s2 - s1 <= max_sent_dist:
  2879. if ty1 == 'package':
  2880. if ent1 not in link_dic:
  2881. link_dic[ent1] = []
  2882. if s1 == s2:
  2883. dist = abs(b2 - e1) if b2 > e1 else 0
  2884. else:
  2885. dist = len(list_sentence[s1].sentence_text) - e1
  2886. for id in range(s1+1, s2):
  2887. dist += len(list_sentence[id].sentence_text)
  2888. dist += b2
  2889. if in_att1:
  2890. dist += 100 # 附件的距离加100
  2891. link_dic[ent1].append((s2 - s1, dist, ent2))
  2892. elif ty2 == 'package':
  2893. if ent2 not in link_dic:
  2894. link_dic[ent2] = []
  2895. if s1 == s2:
  2896. dist = abs(b2 - e1) if b2 > e1 else 0
  2897. else:
  2898. dist = len(list_sentence[s1].sentence_text) - e1
  2899. for id in range(s1+1, s2):
  2900. dist += len(list_sentence[id].sentence_text)
  2901. dist += b2
  2902. if in_att1:
  2903. dist += 100 # 附件的距离加100
  2904. if s1!=s2 or e1!=e2:
  2905. dist += 30 # 包号在实体后面距离再加30
  2906. link_dic[ent2].append((s2 - s1, dist, ent1))
  2907. i += 1
  2908. return link_dic
  2909. for entity in list_entity:
  2910. if entity.entity_type == 'package':
  2911. pk_name_l.append((entity.entity_type, entity.entity_text, entity.sentence_index, entity.wordOffset_begin, entity.wordOffset_end, entity.in_attachment))
  2912. pk_code_l.append((entity.entity_type, entity.entity_text, entity.sentence_index, entity.wordOffset_begin, entity.wordOffset_end, entity.in_attachment))
  2913. count_dic['package'].add(entity.entity_text)
  2914. elif entity.entity_type == 'name':
  2915. pk_name_l.append((entity.entity_type, entity.entity_text, entity.sentence_index, entity.wordOffset_begin, entity.wordOffset_end, entity.in_attachment))
  2916. count_dic['name'].add(entity.entity_text)
  2917. elif entity.entity_type == 'code':
  2918. pk_code_l.append((entity.entity_type, entity.entity_text, entity.sentence_index, entity.wordOffset_begin, entity.wordOffset_end, entity.in_attachment))
  2919. count_dic['code'].add(entity.entity_text)
  2920. if len(count_dic['package']) > 0:
  2921. if len(count_dic['name'])>0:
  2922. link_dic = get_sort_dist(pk_name_l)
  2923. for k, v in link_dic.items():
  2924. v.sort(key=lambda x: [x[0], x[1]])
  2925. if v[0][0] < 2 and v[0][1] < 200: # 标段号与包名句子数小于2,字距离小于200的才添加
  2926. PackDict[k]["name"] = v[0][2]
  2927. if len(count_dic['code'])>0:
  2928. link_dic = get_sort_dist(pk_code_l)
  2929. for k, v in link_dic.items():
  2930. v.sort(key=lambda x: [x[0], x[1]])
  2931. if v[0][0] < 2 and v[0][1] < 200:
  2932. PackDict[k]["code"] = v[0][2]
  2933. #删除一个机构有多个角色的数据
  2934. #删除重复人、概率不回传
  2935. final_roleList = []
  2936. list_pop = []
  2937. set_tenderer_role = set()
  2938. dict_pack_tenderer_money = dict()
  2939. for pack in PackDict.keys():
  2940. #删除无效包
  2941. if PackDict[pack]["code"]=="" and PackDict[pack]["tendereeMoney"]==0 and len(PackDict[pack]["roleList"])==0:
  2942. list_pop.append(pack)
  2943. for i in range(len(PackDict[pack]["roleList"])):
  2944. if PackDict[pack]["roleList"][i].role_name=="win_tenderer":
  2945. if PackDict[pack]["roleList"][i].money==0:
  2946. set_tenderer_role.add(PackDict[pack]["roleList"][i])
  2947. dict_pack_tenderer_money[pack] = [PackDict[pack]["roleList"][i],set()]
  2948. #找到包的中投标金额
  2949. for _index in range(len(PackageList)):
  2950. if "hit" in PackageList[_index]:
  2951. for _hit in list(PackageList[_index]["hit"]):
  2952. if len(_hit.split("-"))==3:
  2953. _money = float(_hit.split("-")[1]) if _hit.split("-")[0]=="money" else None
  2954. # 补充金额前新增负号‘-’导致错误的规则
  2955. elif len(_hit.split("-"))==4:
  2956. _money = float(_hit.split("-")[2]) if _hit.split("-")[0] == "money" else None
  2957. else:
  2958. _money = None
  2959. if PackageList[_index]["name"] in dict_pack_tenderer_money and _money is not None:
  2960. dict_pack_tenderer_money[PackageList[_index]["name"]][1].add(_money)
  2961. #只找到一个中标人和中标金额
  2962. if len(set_tenderer_money)==1 and len(set_tenderer_role)==1:
  2963. list(set_tenderer_role)[0].money = list(set_tenderer_money)[0]
  2964. list(set_tenderer_role)[0].money_unit = unit_list[0]
  2965. # print('一个中标人一个金额:', list(set_tenderer_money)[0])
  2966. #找到一个中标人和多个招标金额
  2967. if len(set_tenderer_money)>1 and len(set_tenderer_role)==1:
  2968. _maxMoney = list(set_tenderer_money)[0]
  2969. _sumMoney = 0
  2970. for _m in list(set_tenderer_money):
  2971. _sumMoney += _m
  2972. if _m>_maxMoney:
  2973. _maxMoney = _m
  2974. if _sumMoney/_maxMoney==2:
  2975. list(set_tenderer_role)[0].money = _maxMoney
  2976. # print('一人多金额分项合计 取最大金额:', _maxMoney)
  2977. else:
  2978. # list(set_tenderer_role)[0].money = _maxMoney
  2979. if min(list_tenderer_money)>200000 and list_tenderer_money[-1]/min(list_tenderer_money)>9000:
  2980. list(set_tenderer_role)[0].money = min(list_tenderer_money)
  2981. list(set_tenderer_role)[0].money_unit = unit_list[list_tenderer_money.index(min(list_tenderer_money))]
  2982. # print('一人多金额 且最小的大于20万第一个金额比最小金额大几千倍的最小中标金额:', min(list_tenderer_money))
  2983. else:
  2984. list(set_tenderer_role)[0].money = list_tenderer_money[-1] # 2021/7/16 修改 不是单价合计方式取第一个中标金额
  2985. list(set_tenderer_role)[0].money_unit = unit_list[-1] # 金额单位
  2986. # print('一人多金额 取第一个中标金额:', list_tenderer_money[-1])
  2987. #每个包都只找到一个金额
  2988. _flag_pack_money = True
  2989. for k,v in dict_pack_tenderer_money.items():
  2990. if len(v[1])!=1:
  2991. _flag_pack_money = False
  2992. if _flag_pack_money and len(PackageSet)==len(dict_pack_tenderer_money.keys()):
  2993. for k,v in dict_pack_tenderer_money.items():
  2994. if float(v[0].unit_price) < float(list(v[1])[0]): # 20241128 金额大于单价时才作链接金额
  2995. v[0].money = list(v[1])[0]
  2996. # 2021/7/16 #增加判断中标金额是否远大于招标金额逻辑
  2997. for pack in PackDict.keys():
  2998. for i in range(len(PackDict[pack]["roleList"])):
  2999. if float(PackDict[pack]["tendereeMoney"]) > 0:
  3000. # print('金额数据类型:',type(PackDict[pack]["roleList"][i].money))
  3001. if float(PackDict[pack]["roleList"][i].money) >10000000 and \
  3002. float(PackDict[pack]["roleList"][i].money)/float(PackDict[pack]["tendereeMoney"])>=1000:
  3003. PackDict[pack]["roleList"][i].money = float(PackDict[pack]["roleList"][i].money) / 10000
  3004. # print('招标金额校正中标金额')
  3005. # 2022/04/01 #增加判断中标金额是否远小于招标金额逻辑,比例相差10000倍左右(中标金额“万”单位丢失或未识别)
  3006. for pack in PackDict.keys():
  3007. for i in range(len(PackDict[pack]["roleList"])):
  3008. if float(PackDict[pack]["tendereeMoney"]) > 0 and float(PackDict[pack]["roleList"][i].money) > 0.:
  3009. if float(PackDict[pack]["roleList"][i].money) < 1000 and \
  3010. float(PackDict[pack]["tendereeMoney"])/float(PackDict[pack]["roleList"][i].money)>=9995 and \
  3011. float(PackDict[pack]["tendereeMoney"])/float(PackDict[pack]["roleList"][i].money)<11000:
  3012. PackDict[pack]["roleList"][i].money = float(PackDict[pack]["roleList"][i].money) * 10000
  3013. # 2021/7/19 #增加判断中标金额是否远大于第二三中标金额
  3014. for pack in PackDict.keys():
  3015. tmp_moneys = []
  3016. for i in range(len(PackDict[pack]["roleList"])):
  3017. if float(PackDict[pack]["roleList"][i].money) >100000:
  3018. tmp_moneys.append(float(PackDict[pack]["roleList"][i].money))
  3019. if len(tmp_moneys)>2 and max(tmp_moneys)/min(tmp_moneys)>1000:
  3020. for i in range(len(PackDict[pack]["roleList"])):
  3021. if float(PackDict[pack]["roleList"][i].money)/min(tmp_moneys)>1000:
  3022. PackDict[pack]["roleList"][i].money = float(PackDict[pack]["roleList"][i].money) / 10000
  3023. # print('通过其他中标人投标金额校正中标金额')
  3024. for item in list_pop:
  3025. PackDict.pop(item)
  3026. # 公告中只有"招标人"且无"联系人"链接时
  3027. if len(PackDict)==1:
  3028. k = list(PackDict.keys())[0]
  3029. tenderee_agency_role = [role for role in PackDict[k]["roleList"] if role.role_name in ['tenderee','agency','win_tenderer']]
  3030. if len(tenderee_agency_role)==1:
  3031. exist_person = []
  3032. exist_phone = []
  3033. for role in PackDict[k]["roleList"]:
  3034. for group in role.linklist:
  3035. if group[0]:
  3036. exist_person.append(group[0])
  3037. if group[1]:
  3038. exist_phone.append(group[1])
  3039. if tenderee_agency_role[0].role_name == "tenderee":
  3040. if not tenderee_agency_role[0].linklist:
  3041. get_contacts = False
  3042. if not get_contacts:
  3043. # 根据大纲Outline类召回联系人
  3044. for outline in list_outline:
  3045. if re.search("联系人|联系方|联系方式|联系电话|电话|负责人|与.{2,4}联系",outline.outline_summary) and \
  3046. not re.search("代理|乙方|竞得|受让|买受|签约|供货|供应|承做|承包|承建|承销|承保|承接|承制|承担|承修|承租(?:(包))?|入围|入选|竞买|中标|中选|中价|中签|成交|候选",outline.outline_summary):
  3047. for t_person in [p for p in temporary_list2 if p.entity_type=='person' and p.label==3]:
  3048. if words_num_dict[t_person.sentence_index] + t_person.wordOffset_begin >= words_num_dict[outline.sentence_begin_index] + outline.wordOffset_begin and words_num_dict[
  3049. t_person.sentence_index] + t_person.wordOffset_end < words_num_dict[outline.sentence_end_index] + outline.wordOffset_end:
  3050. if t_person.person_phone:
  3051. _phone = [p.entity_text for p in t_person.person_phone]
  3052. for _p in _phone:
  3053. if t_person.entity_text not in exist_person and _p not in ",".join(exist_phone):
  3054. tenderee_agency_role[0].linklist.append((t_person.entity_text, _p))
  3055. get_contacts = True
  3056. break
  3057. elif words_num_dict[t_person.sentence_index] + t_person.wordOffset_begin >= \
  3058. words_num_dict[outline.sentence_end_index] + outline.wordOffset_end:
  3059. break
  3060. if not get_contacts:
  3061. sentence_phone = phone.findall(outline.outline_text)
  3062. if sentence_phone:
  3063. if sentence_phone[0] not in ",".join(exist_phone):
  3064. tenderee_agency_role[0].linklist.append(("", sentence_phone[0]))
  3065. get_contacts = True
  3066. break
  3067. # if not get_contacts: # 会召回错误数据,不启用规则
  3068. # # 直接取文中倒数第一个联系人
  3069. # for _entity in temporary_list2[::-1]:
  3070. # if _entity.entity_type=='person' and _entity.label==3:
  3071. # if _entity.person_phone:
  3072. # _phone = [p.entity_text for p in _entity.person_phone]
  3073. # for _p in _phone:
  3074. # if _entity.entity_text not in exist_person and _p not in ",".join(exist_phone):
  3075. # tenderee_agency_role[0].linklist.append((_entity.entity_text, _p))
  3076. # get_contacts = True
  3077. # break
  3078. # if not get_contacts: # 会召回错误数据,不启用规则
  3079. # # 如果文中只有一个“phone”实体,则直接取为联系人电话
  3080. # if len(phone_entitys) == 1:
  3081. # if phone_entitys[0].entity_text not in ",".join(exist_phone):
  3082. # tenderee_agency_role[0].linklist.append(("", phone_entitys[0].entity_text))
  3083. # get_contacts = True
  3084. if not get_contacts:
  3085. # 通过大纲Outline类直接取电话
  3086. if len(new_split_list) > 1:
  3087. for _start, _end in new_split_list:
  3088. temp_sentence = _content[_start:_end]
  3089. sentence_outline = temp_sentence.split(",::")[0]
  3090. if re.search("联系人|联系方|联系方式|联系电话|电话|负责人|与.{2,4}联系", sentence_outline) and \
  3091. not re.search("代理|乙方|竞得|受让|买受|签约|供货|供应|承做|承包|承建|承销|承保|承接|承制|承担|承修|承租(?:(包))?|入围|入选|竞买|中标|中选|中价|中签|成交|候选",sentence_outline):
  3092. sentence_phone = phone.findall(temp_sentence)
  3093. if sentence_phone:
  3094. if sentence_phone[0] in [ent.entity_text for ent in phone_entitys] and sentence_phone[0] not in ",".join(exist_phone):
  3095. tenderee_agency_role[0].linklist.append(("", sentence_phone[0]))
  3096. get_contacts = True
  3097. break
  3098. if not get_contacts:
  3099. # 通过正则提取句子段落进行提取电话
  3100. contacts_person = "(?:联系人|联系方|联系方式|负责人|电话|联系电话)[::]?"
  3101. tenderee_pattern = "(?:(?:采购|招标|议价|议标|比选)(?:人|公司|单位|组织|部门)|建设(?:单位|业主)|(?:采购|招标|甲)方|询价单位|项目业主|业主|业主单位)[^。]{0,5}"
  3102. contact_pattern_list = [tenderee_pattern + contacts_person,
  3103. "(?:采购[^。,]{0,2}项目|采购事项|招标)[^。,]{0,4}" + contacts_person,
  3104. "(?:项目|采购)[^。,]{0,4}" + contacts_person,
  3105. "(?:报名|报价|业务咨询|业务|投标咨询)[^。,]{0,4}" + contacts_person, ]
  3106. for _pattern in contact_pattern_list:
  3107. get_tenderee_contacts = False
  3108. for regular_match in re.finditer(_pattern, _content):
  3109. match_text = _content[regular_match.end():regular_match.end() + 50]
  3110. match_text = match_text.split("。")[0]
  3111. sentence_phone = phone.findall(match_text)
  3112. if sentence_phone:
  3113. if sentence_phone[0] not in ",".join(exist_phone):
  3114. tenderee_agency_role[0].linklist.append(("", sentence_phone[0]))
  3115. get_tenderee_contacts = True
  3116. break
  3117. if get_tenderee_contacts:
  3118. break
  3119. # 如果同一个电话连到了不同的单位就直接去掉(2024-09-03 新增)
  3120. get_phone_dict = dict()
  3121. for k in PackDict.keys():
  3122. for i in range(len(PackDict[k]["roleList"])):
  3123. for item in PackDict[k]["roleList"][i].linklist:
  3124. if item[1]:
  3125. if item[1] not in get_phone_dict:
  3126. get_phone_dict[item[1]] = set()
  3127. get_phone_dict[item[1]].add(PackDict[k]["roleList"][i].entity_text)
  3128. # print(get_phone_dict)
  3129. remove_phone = []
  3130. for phone,role_list in get_phone_dict.items():
  3131. if len(role_list)>1:
  3132. remove_phone.append(phone)
  3133. for k in PackDict.keys():
  3134. for i in range(len(PackDict[k]["roleList"])):
  3135. remove_list = []
  3136. for item in PackDict[k]["roleList"][i].linklist:
  3137. if item[1] and item[1] in remove_phone:
  3138. remove_list.append(item)
  3139. for _item in remove_list:
  3140. PackDict[k]["roleList"][i].linklist.remove(_item)
  3141. for pack in PackDict.keys():
  3142. for i in range(len(PackDict[pack]["roleList"])):
  3143. PackDict[pack]["roleList"][i] = PackDict[pack]["roleList"][i].getString()
  3144. return PackDict
  3145. def initPackageAttr(RoleList,PackageSet,win_tenderer_set,tenderee_or_agency_set, main_body_pack):
  3146. '''
  3147. @summary: 根据拿到的roleList和packageSet初始化接口返回的数据
  3148. '''
  3149. packDict = dict()
  3150. packDict["Project"] = {"code":"","tendereeMoney":0,"roleList":[], 'tendereeMoneyUnit':''}
  3151. for item in list(PackageSet):
  3152. packDict[item] = {"code":"","tendereeMoney":0,"roleList":[], 'tendereeMoneyUnit':''}
  3153. packDict[item]['in_attachment'] = False if item in main_body_pack else True
  3154. for item in RoleList:
  3155. if packDict[item.packageName]["code"] =="":
  3156. packDict[item.packageName]["code"] = item.packageCode
  3157. # packDict[item.packageName]["roleList"].append(Role(item.role_name,item.entity_text,0,0,0.0,[]))
  3158. # packDict[item.packageName]["roleList"].append(Role(item.role_name,item.entity_text,0,0,0.0,[])) #Role(角色名称,实体名称,角色阈值,金额,金额阈值,连接列表,金额单位)
  3159. packDict[item.packageName]["roleList"].append(Role(item.role_name,item.entity_text,item.role_prob,0,0.0,[],set(item.multi_winner)-win_tenderer_set-tenderee_or_agency_set)) #Role(角色名称,实体名称,角色阈值,金额,金额阈值,连接列表,多中标人)
  3160. return packDict
  3161. def getPackageRoleMoney(list_sentence,list_entity,list_outline,winter_scope):
  3162. '''
  3163. @param:
  3164. list_sentence:文章的句子list
  3165. list_entity:文章的实体list
  3166. @return: 拿到文章的包-标段号-角色-实体名称-金额-联系人-联系电话
  3167. '''
  3168. # print("=1")
  3169. theRole = getRoleList(list_sentence,list_entity)
  3170. if not theRole:
  3171. return []
  3172. # RoleList,RoleSet,PackageList,PackageSet = theRole
  3173. RoleList,RoleSet,PackageList,PackageSet,win_tenderer_set,tenderee_or_agency_set,main_body_pack = theRole
  3174. '''
  3175. for item in PackageList:
  3176. # print(item)
  3177. '''
  3178. # PackDict = initPackageAttr(RoleList, PackageSet)
  3179. PackDict = initPackageAttr(RoleList, PackageSet, win_tenderer_set,tenderee_or_agency_set,main_body_pack)
  3180. PackDict = findAttributeAfterEntity(PackDict, RoleSet, PackageList, PackageSet, list_sentence, list_entity, list_outline, winter_scope)
  3181. return PackDict
  3182. def turnBidWay(bidway):
  3183. if bidway in ("邀请招标","采购方式:邀请"):
  3184. return "邀请招标"
  3185. elif bidway in ("询价","询单","询比","采购方式:询价"):
  3186. return "询价"
  3187. elif bidway in ("竞谈","竞争性谈判","公开竞谈"):
  3188. return "竞争性谈判"
  3189. elif bidway in ("竞争性磋商","磋商"):
  3190. return "竞争性磋商"
  3191. elif bidway in ("竞价","竞标","电子竞价","以电子竞价","电子书面竞投"):
  3192. return "竞价"
  3193. elif bidway in ("公开招标","网上电子投标","网上招标","采购方式:公开","招标为其他"):
  3194. return "公开招标"
  3195. elif bidway in ("单一来源"):
  3196. return "单一来源"
  3197. elif bidway in ("比选"):
  3198. return "比选"
  3199. else:
  3200. return "其他"
  3201. def turnMoneySource(moneysource):
  3202. result_list = []
  3203. if re.search("自筹|业主筹集|筹资|自有",moneysource):
  3204. result_list.append("自筹")
  3205. if re.search("财政",moneysource) and not re.search("非财政",moneysource):
  3206. result_list.append("财政资金")
  3207. if re.search("拨款|补助|划拨|拨付|国拨|上级资金",moneysource):
  3208. result_list.append("上级拨款")
  3209. if re.search("社会资本|社会资金",moneysource):
  3210. result_list.append("社会资本")
  3211. if re.search("贷款|借款|借贷",moneysource):
  3212. result_list.append("贷款资金")
  3213. if re.search("债券|债|国债",moneysource):
  3214. result_list.append("债券资金")
  3215. if re.search("专项|项目资金",moneysource):
  3216. result_list.append("项目专项资金")
  3217. if re.search("配套",moneysource):
  3218. result_list.append("配套资金")
  3219. if re.search("外资",moneysource):
  3220. result_list.append("外资")
  3221. if re.search("国有资金|国企资金|国资|国家投资",moneysource):
  3222. result_list.append("国有资金")
  3223. if re.search("投资|融资",moneysource):
  3224. result_list.append("投资资金")
  3225. if re.search("预算(?<!外)|预算内",moneysource):
  3226. result_list.append("预算内资金")
  3227. if re.search("预算外",moneysource):
  3228. result_list.append("预算外资金")
  3229. result_list = sorted(result_list,key = lambda x:x)
  3230. if len(result_list)>0 and len(result_list)<5:
  3231. return ",".join(result_list)
  3232. else:
  3233. return "其他资金"
  3234. my_time_format_pattern = re.compile("((?:(?P<year>20\d{2}|\d{2}|二[零〇0][零〇一二三四五六七八九0]{2})\s*[-/年.]\s*)?(?P<month>\d{1,2}|[一二三四五六七八九十]{1,3})\s*[-/月.]\s*(?P<day>\d{1,2}|[一二三四五六七八九十]{1,3}))(?:.?\d{1,2}:\d{2}(?::\d{2})?)?")
  3235. from BiddingKG.dl.ratio.re_ratio import getUnifyNum
  3236. def my_timeFormat(_time,page_time):
  3237. # if page_time:
  3238. # current_year = time.strftime("%Y",time.localtime(int(datetime.strptime(page_time, '%Y-%m-%d').timestamp())))
  3239. # else:
  3240. # current_year = time.strftime("%Y",time.localtime())
  3241. all_match = re.finditer(my_time_format_pattern,_time)
  3242. time_list = []
  3243. idx = 0
  3244. global_year = ""
  3245. for _match in all_match:
  3246. if len(_match.group())>0:
  3247. idx += 1
  3248. legal = True
  3249. year = ""
  3250. month = ""
  3251. day = ""
  3252. for k,v in _match.groupdict().items():
  3253. if k=="year":
  3254. year = v
  3255. if k=="month":
  3256. month = v
  3257. if k=="day":
  3258. day = v
  3259. if year!="":
  3260. if year==None: # 例:5月18日
  3261. if idx==2 and global_year: # 例:2025年5月14日-5月18日,第二个时间没年份
  3262. year = global_year
  3263. else:
  3264. legal = False
  3265. else:
  3266. if re.search("^\d+$", year):
  3267. if len(year) == 2:
  3268. year = "20" + year
  3269. # if int(year) - int(current_year) > 5 or int(year) - int(current_year) < -1:
  3270. # legal = False
  3271. # else:
  3272. # if int(year) - int(current_year)>10 or int(year) - int(current_year) < -1:
  3273. # legal = False
  3274. else:
  3275. _year = ""
  3276. for word in year:
  3277. if word == '0':
  3278. _year += word
  3279. else:
  3280. _year += str(getDigitsDic(word))
  3281. year = _year
  3282. else:
  3283. legal = False
  3284. if month!="":
  3285. if re.search("^\d+$", month):
  3286. if int(month) > 12:
  3287. legal = False
  3288. else:
  3289. month = int(getUnifyNum(month))
  3290. if month >= 1 and month <= 12:
  3291. month = str(month)
  3292. else:
  3293. legal = False
  3294. else:
  3295. legal = False
  3296. if day!="":
  3297. if re.search("^\d+$", day):
  3298. if int(day) > 31:
  3299. legal = False
  3300. else:
  3301. day = int(getUnifyNum(day))
  3302. if day >= 1 and day <= 31:
  3303. day = str(day)
  3304. else:
  3305. legal = False
  3306. else:
  3307. legal = False
  3308. if legal and not isValidDate(int(year),int(month),int(day)):
  3309. legal = False
  3310. if legal:
  3311. # 数字字符格式化
  3312. year = str(int(year))
  3313. month = str(int(month))
  3314. day = str(int(day))
  3315. time_list.append("%s-%s-%s"%(year,month.rjust(2,"0"),day.rjust(2,"0")))
  3316. # if idx==1 and not global_year:
  3317. if not global_year:
  3318. global_year = year
  3319. return time_list,global_year
  3320. def getTimeAttributes(list_entity,list_sentence,page_time):
  3321. # from BiddingKG.dl.interface.htmlparser import get_childs
  3322. # document_tree = parse_document.tree
  3323. # new_document_tree = []
  3324. # _data_i = -1
  3325. # while _data_i < len(document_tree) - 1:
  3326. # _data_i += 1
  3327. # _data = document_tree[_data_i]
  3328. # _type = _data["type"]
  3329. # if _type == "sentence":
  3330. # if _data["sentence_title"] is not None:
  3331. # new_document_tree.append(_data)
  3332. # document_tree = new_document_tree
  3333. time_entitys = [i for i in list_entity if i.entity_type=='time']
  3334. time_entitys = sorted(time_entitys,key=lambda x:(x.sentence_index, x.begin_index))
  3335. list_sentence = sorted(list_sentence,key=lambda x:x.sentence_index)
  3336. dict_time = {
  3337. "time_release": [], # 1 发布时间
  3338. "time_bidopen": [], # 2 开标时间
  3339. "time_bidclose": [], # 3 截标时间
  3340. 'time_bidstart': [], # 12 投标(开始)时间、响应文件接收(开始)时间
  3341. 'time_publicityStart': [], # 4 公示开始时间(公示时间、公示期)
  3342. 'time_publicityEnd': [], # 5 公示截止时间
  3343. 'time_getFileStart': [], # 6 文件获取开始时间(文件获取时间)
  3344. 'time_getFileEnd': [], # 7 文件获取截止时间
  3345. 'time_registrationStart': [], # 8 报名开始时间(报名时间)
  3346. 'time_registrationEnd': [], # 9 报名截止时间
  3347. 'time_earnestMoneyStart': [], #10 保证金递交开始时间(保证金递交时间)
  3348. 'time_earnestMoneyEnd': [] , # 11 保证金递交截止时间
  3349. 'time_commencement':[] , #13 开工日期
  3350. 'time_completion': [], # 14 竣工日期
  3351. 'time_listingStart': [], # 15 挂牌开始日期(挂牌时间)
  3352. 'time_listingEnd': [], # 16 挂牌结束日期、挂牌截止日期
  3353. 'time_signContract': [], # 17 合同签订时间
  3354. 'time_contractStart': [], # 18 合同开始时间
  3355. 'time_contractEnd': [] # 19 合同结束时间
  3356. }
  3357. dict_time2label = {
  3358. "time_release": 1, # 1 发布时间
  3359. "time_bidopen": 2, # 2 开标时间
  3360. "time_bidclose": 3, # 3 截标时间
  3361. 'time_bidstart': 12, # 12 投标(开始)时间、响应文件接收(开始)时间
  3362. 'time_publicityStart': 4, # 4 公示开始时间(公示时间、公示期)
  3363. 'time_publicityEnd': 5, # 5 公示截止时间
  3364. 'time_getFileStart': 6, # 6 文件获取开始时间(文件获取时间)
  3365. 'time_getFileEnd': 7, # 7 文件获取截止时间
  3366. 'time_registrationStart': 8, # 8 报名开始时间(报名时间)
  3367. 'time_registrationEnd': 9, # 9 报名截止时间
  3368. 'time_earnestMoneyStart': 10, # 10 保证金递交开始时间(保证金递交时间)
  3369. 'time_earnestMoneyEnd': 11, # 11 保证金递交截止时间
  3370. 'time_commencement': 13, # 13 开工日期
  3371. 'time_completion': 14, # 14 竣工日期
  3372. 'time_listingStart': 15, # 15 挂牌开始日期(挂牌时间)
  3373. 'time_listingEnd': 16, # 16 挂牌结束日期、挂牌截止日期
  3374. 'time_signContract': 17, # 17 合同签订时间
  3375. 'time_contractStart': 18, # 18 合同开始时间
  3376. 'time_contractEnd': 19 # 19 合同结束时间
  3377. }
  3378. last_sentence_index = 0
  3379. last_time_type = ""
  3380. last_time_index = {
  3381. 'time_bidstart':"time_bidclose",
  3382. 'time_publicityStart':"time_publicityEnd",
  3383. 'time_getFileStart':"time_getFileEnd",
  3384. 'time_registrationStart':"time_registrationEnd",
  3385. 'time_earnestMoneyStart':"time_earnestMoneyEnd",
  3386. 'time_commencement':"time_completion",
  3387. 'time_listingStart':"time_listingEnd",
  3388. 'time_contractStart':"time_contractEnd"
  3389. }
  3390. # time_entitys = [[_entity,my_timeFormat(_entity.entity_text,page_time)] for _entity in time_entitys]
  3391. new_time_entitys = []
  3392. year_list = []
  3393. for _entity in time_entitys:
  3394. _time_list,_year = my_timeFormat(_entity.entity_text,page_time)
  3395. _in_attachment = _entity.in_attachment
  3396. if _time_list:
  3397. new_time_entitys.append([_entity,_time_list,_year])
  3398. year_list.append([_year,_in_attachment])
  3399. get_all_time = False if False in [i[1] for i in year_list] else True
  3400. if page_time:
  3401. current_year = time.strftime("%Y",time.localtime(int(datetime.strptime(page_time, '%Y-%m-%d').timestamp())))
  3402. year_list.append([current_year,False])
  3403. else:
  3404. current_year = time.strftime("%Y",time.localtime())
  3405. if get_all_time:
  3406. year_list = [i[0] for i in year_list]
  3407. else:
  3408. year_list = [i[0] for i in year_list if not i[1]]
  3409. year_list = [(y,year_list.count(y)) for y in year_list if y[:2]=='20']
  3410. year_list.sort(key=lambda x:x[1],reverse=True)
  3411. most_year = year_list[0][0] if year_list else ""
  3412. if most_year:
  3413. time_entitys = [item for item in new_time_entitys if int(item[2])-int(most_year)<=10 and int(item[2])-int(most_year)>=-1]
  3414. else:
  3415. time_entitys = new_time_entitys
  3416. # print(time_entitys)
  3417. for entity_idx in range(len(time_entitys)):
  3418. entity = time_entitys[entity_idx][0]
  3419. extract_time = time_entitys[entity_idx][1]
  3420. sentence_text = list_sentence[entity.sentence_index].sentence_text
  3421. previous_entity = time_entitys[entity_idx-1][0] if entity_idx!=0 else None
  3422. previous_extract_time = time_entitys[entity_idx-1][1] if entity_idx!=0 else None
  3423. next_entity = time_entitys[entity_idx+1][0] if entity_idx!=len(time_entitys)-1 else None
  3424. next_extract_time = time_entitys[entity_idx+1][1] if entity_idx!=len(time_entitys)-1 else None
  3425. # 实体有效上下文
  3426. entity_context_begin = previous_entity.wordOffset_end if previous_entity and previous_entity.sentence_index==entity.sentence_index else 0
  3427. entity_context_end = next_entity.wordOffset_begin if next_entity and next_entity.sentence_index==entity.sentence_index else len(sentence_text)
  3428. if entity.sentence_index!=last_sentence_index:
  3429. # sentence_index 不同句子重置last_time_type
  3430. last_time_type = ""
  3431. entity_left = sentence_text[max(entity_context_begin, entity.wordOffset_begin - 2):entity.wordOffset_begin]
  3432. entity_left2 = sentence_text[max(entity_context_begin, entity.wordOffset_begin - 10):entity.wordOffset_begin]
  3433. entity_left3 = sentence_text[max(entity_context_begin, entity.wordOffset_begin - 30):entity.wordOffset_begin]
  3434. entity_right = sentence_text[entity.wordOffset_end:min(entity.wordOffset_end + 3,entity_context_end)]
  3435. entity_right2 = sentence_text[entity.wordOffset_end:entity_context_end]
  3436. entity_right2 = re.sub(r"http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\\(\\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+",'',entity_right2)[:60] # 去除网址
  3437. # print(entity.entity_text,entity_right2)
  3438. label_prob = entity.values[entity.label]
  3439. entity_text = entity.entity_text
  3440. in_attachment = entity.in_attachment
  3441. if extract_time:
  3442. definite_time_list = []
  3443. t = re.compile("(北京时间)?(?P<day>下午|上午|早上)?(?P<hour>\d{1,2})[::时点](?P<half_hour>半)?(?P<minute>\d{1,2})?[::分]?(?P<second>\d{2})?秒?")
  3444. _entity_text = re.sub(" (?=[^\d])|(?<=[^\d]) ","",entity_text)
  3445. _entity_text_len = len(_entity_text)
  3446. _entity_text = _entity_text + sentence_text[entity.wordOffset_end:entity.wordOffset_end+20]
  3447. t_in_word_num = len(re.findall(t,_entity_text))
  3448. # t_out_of_word = re.search("^[^\d]{,2}"+t.pattern,re.sub(" (?=[^\d])|(?<=[^\d]) ","",sentence_text[entity.wordOffset_end:]))
  3449. begin_index = 0
  3450. definite_time_idx_list = []
  3451. for _num in range(t_in_word_num):
  3452. if begin_index> _entity_text_len + 8:
  3453. break
  3454. t_in_word = re.search(t, _entity_text[begin_index:])
  3455. # print(_entity_text[begin_index:])
  3456. if t_in_word:
  3457. if _num==0 and t_in_word.start() > _entity_text_len + 8:
  3458. break
  3459. begin_index += t_in_word.end()
  3460. # print('t_in_word',entity_text,t_in_word.groupdict())
  3461. day = t_in_word.groupdict().get('day',"")
  3462. hour = t_in_word.groupdict().get('hour',"")
  3463. half_hour = t_in_word.groupdict().get('half_hour',"")
  3464. minute = t_in_word.groupdict().get('minute',"")
  3465. second = t_in_word.groupdict().get('second',"")
  3466. if hour:
  3467. if day=='下午' and int(hour)<12:
  3468. hour = str(int(hour)+12)
  3469. if int(hour)>24:
  3470. continue
  3471. else:
  3472. hour = "00"
  3473. if not minute:
  3474. if half_hour:
  3475. minute = "30"
  3476. else:
  3477. minute = "00"
  3478. if int(minute)>60:
  3479. continue
  3480. if not second:
  3481. second = "00"
  3482. if int(second)>60:
  3483. continue
  3484. definite_time = "%s:%s:%s"%(hour.rjust(2,"0"),minute.rjust(2,"0"),second.rjust(2,"0"))
  3485. # print(definite_time)
  3486. definite_time_list.append(definite_time)
  3487. definite_time_idx_list.append([begin_index-len(t_in_word.group()),begin_index])
  3488. if len(extract_time)==1 and len(definite_time_list)>=2: # 实体只包含一个时间,"2024-12-09 09:00~16:00" 考虑单个时间对应两个详细时间段的识别
  3489. # 前两个详细时间的间隔
  3490. distance = definite_time_idx_list[1][0] - definite_time_idx_list[0][1]
  3491. if distance<=8 and int(definite_time_list[1][:2])>=int(definite_time_list[0][:2]): # 判断详细时间都‘小时’顺序从小到大
  3492. new_extract_time = []
  3493. for d_time in definite_time_list[:2]:
  3494. if d_time == "24:00:00": # 修正不规范时间表述
  3495. d_time = "23:59:59"
  3496. new_extract_time.append(extract_time[0] + " " + d_time)
  3497. extract_time = new_extract_time
  3498. else:
  3499. if definite_time_list[0] == "24:00:00": # 修正不规范时间表述
  3500. definite_time_list[0] = "23:59:59"
  3501. if definite_time_list[0] != "00:00:00":
  3502. extract_time[0] = extract_time[0] + " " + definite_time_list[0]
  3503. else:
  3504. min_len = min(len(extract_time),len(definite_time_list))
  3505. for i in range(min_len):
  3506. if definite_time_list[i] == "24:00:00": # 修正不规范时间表述
  3507. definite_time_list[i] = "23:59:59"
  3508. if definite_time_list[i] != "00:00:00":
  3509. extract_time[i] = extract_time[i] + " " + definite_time_list[i]
  3510. if extract_time:
  3511. # 时间变更prob优化
  3512. if re.search("原",entity_left2):
  3513. last_index = 0
  3514. for item in re.finditer("原",entity_left2):
  3515. last_index = item.start() + 1
  3516. label_prob = label_prob - 0.2 * last_index / len(entity_left2)
  3517. # print('prob优化',label_prob,extract_time)
  3518. elif re.search("改正|更正|修正|修改|更改|变更|延期",entity_left3[-20:]) and not re.search("更正日期",entity_left3[-8:]):
  3519. last_time_label = dict_time2label.get(last_time_type,None)
  3520. if last_time_label and entity.label==0:
  3521. entity.label = last_time_label
  3522. label_prob = 1.5
  3523. elif last_time_label and entity.label==last_time_label:# 前后两个相同类型的时间为变更关系
  3524. label_prob = 2
  3525. # 优化多个并列的时间,如:开标时间和截标时间,截标时间和报名结束时间
  3526. if entity.label in [2,3,9]:
  3527. if entity.label==2 and re.search("截标|投标.{,2}截止|([递提]交|接收)(?:文件)?.{,2}截止|报价.{,2}截止|响应.{,2}截止|文件.{,2}([递提]交|接收)",entity_left3):
  3528. dict_time['time_bidclose'].append((extract_time[0], label_prob-0.1, in_attachment))
  3529. if entity.label==3 and re.search("开标|(评审|比选).{,2}(?:开始)?(时间|日期)|选取.{,2}(时间|日期)",entity_left3):
  3530. dict_time['time_bidopen'].append((extract_time[0], label_prob-0.1, in_attachment))
  3531. if entity.label==3 and re.search("报名",entity_left3):
  3532. dict_time['time_registrationEnd'].append((extract_time[0], 0.5, in_attachment))
  3533. if entity.label==3 and re.search("获取",entity_left3[-20:]):
  3534. dict_time['time_getFileEnd'].append((extract_time[0], 0.45, in_attachment))
  3535. if entity.label==9 and re.search("截标|投标.{,2}截止|([递提]交|接收)(?:文件)?.{,2}截止|报价.{,2}截止|响应.{,2}截止|文件.{,2}([递提]交|接收)",entity_left3):
  3536. dict_time['time_bidclose'].append((extract_time[0], label_prob-0.1, in_attachment))
  3537. if entity.label in [11, 3]:
  3538. if entity.label==11 and re.search("文件.{,2}([递提]交|接收)|截标|投标.{,2}截止|([递提]交|接收)(?:文件)?.{,2}截止|报价.{,2}截止|响应.{,2}截止",entity_left3):
  3539. dict_time['time_bidclose'].append((extract_time[0], 0.5, in_attachment))
  3540. if entity.label==3 and re.search("保证金.{,2}(接受|收取)|(接受|收取).{,2}保证金",entity_left3):
  3541. dict_time['time_earnestMoneyEnd'].append((extract_time[0], 0.5, in_attachment))
  3542. if entity.label in [6, 7]:
  3543. if re.search("文件.{,2}([递提]交|接收)|截标|投标.{,2}截止|([递提]交|接收)(?:文件)?.{,2}截止|报价.{,2}截止|响应.{,2}截止",entity_left3):
  3544. dict_time['time_bidclose'].append((extract_time[0], 0.5, in_attachment))
  3545. if entity.label==0:
  3546. if re.search("文件.{,2}([递提]交|接收)|截标|投标.{,2}截止|([递提]交|接收)(?:文件)?.{,2}截止|报价.{,2}截止|响应.{,2}截止",entity_left3):
  3547. if len(extract_time)>=2:
  3548. dict_time['time_bidstart'].append((extract_time[0], 0.45, in_attachment))
  3549. dict_time['time_bidclose'].append((extract_time[1], 0.45, in_attachment))
  3550. else:
  3551. dict_time['time_bidclose'].append((extract_time[0], 0.45, in_attachment))
  3552. if entity.label==6:
  3553. # "文件获取时间"和"报名时间"并列
  3554. if re.search("报名",entity_left3):
  3555. if len(extract_time)==1:
  3556. dict_time['time_registrationStart'].append((extract_time[0], 0.51, in_attachment))
  3557. else:
  3558. dict_time['time_registrationStart'].append((extract_time[0], 0.51, in_attachment))
  3559. dict_time['time_registrationEnd'].append((extract_time[1], 0.51, in_attachment))
  3560. # 获取文件/报名/报价 时间补充(上下文表达过长无法通过模型识别)
  3561. # if entity.label == 0:
  3562. # if re.search("(获取|领取|售卖|出售|购买|下载).{,4}(招标|投标|采购)?(文件|标书)|(文件|标书).{,4}(获取|售卖|出售|发售|购买)", entity_left3):
  3563. # if len(extract_time)==2:
  3564. # dict_time['time_getFileStart'].append((extract_time[0], 0.51, in_attachment))
  3565. # dict_time['time_getFileEnd'].append((extract_time[1], 0.51, in_attachment))
  3566. # else:
  3567. # if next_entity and next_entity.sentence_index==entity.sentence_index:
  3568. # mid_text = sentence_text[entity.wordOffset_end:next_entity.wordOffset_begin]
  3569. # if len(mid_text)<=10 and re.search("至|到|[-—]|[~~]",mid_text) and len(next_extract_time)==1:
  3570. # dict_time['time_getFileStart'].append((extract_time[0], 0.51, in_attachment))
  3571. # dict_time['time_getFileEnd'].append((next_extract_time[0], 0.51, in_attachment))
  3572. # if not dict_time['time_getFileEnd']:
  3573. # if re.search("前|止|截止", entity_right) or re.search("前",entity_text[-2:]):
  3574. # dict_time['time_getFileEnd'].append((extract_time[0], 0.51, in_attachment))
  3575. # elif re.search("起|开?始", entity_right) or re.search("起",entity_text[-2:]):
  3576. # dict_time['time_getFileStart'].append((extract_time[0], 0.51, in_attachment))
  3577. # if re.search("(进行|在线|线下|线上|网上).{,2}报名|报名.{,2}(开始)?(时间|日期)", entity_left3):
  3578. # if len(extract_time)==2:
  3579. # dict_time['time_registrationStart'].append((extract_time[0], 0.51, in_attachment))
  3580. # dict_time['time_registrationEnd'].append((extract_time[1], 0.51, in_attachment))
  3581. # else:
  3582. # if next_entity and next_entity.sentence_index==entity.sentence_index:
  3583. # mid_text = sentence_text[entity.wordOffset_end:next_entity.wordOffset_begin]
  3584. # if len(mid_text)<=10 and re.search("至|到|[-—]|[~~]",mid_text) and len(next_extract_time)==1:
  3585. # dict_time['time_registrationStart'].append((extract_time[0], 0.51, in_attachment))
  3586. # dict_time['time_registrationEnd'].append((next_extract_time[0], 0.51, in_attachment))
  3587. # if not dict_time['time_registrationEnd']:
  3588. # if re.search("前|止|截止", entity_right) or re.search("前",entity_text[-2:]):
  3589. # dict_time['time_registrationEnd'].append((extract_time[0], 0.51, in_attachment))
  3590. # elif re.search("起|开?始", entity_right) or re.search("起",entity_text[-2:]):
  3591. # dict_time['time_registrationStart'].append((extract_time[0], 0.51, in_attachment))
  3592. #
  3593. # if re.search("(获取|售卖|出售|购买).{,4}(招标|投标|采购)?(文件|标书)|(文件|标书).{,4}(获取|售卖|出售|发售|购买)", entity_right2):
  3594. # if len(extract_time)==2:
  3595. # dict_time['time_getFileStart'].append((extract_time[0], 0.51, in_attachment))
  3596. # dict_time['time_getFileEnd'].append((extract_time[1], 0.51, in_attachment))
  3597. # else:
  3598. # if previous_entity and previous_entity.sentence_index==entity.sentence_index:
  3599. # mid_text = sentence_text[previous_entity.wordOffset_end:entity.wordOffset_begin]
  3600. # if len(mid_text)<=10 and re.search("至|到|[-—]|[~~]",mid_text) and len(previous_extract_time)==1:
  3601. # dict_time['time_getFileStart'].append((previous_extract_time[0], 0.51, in_attachment))
  3602. # dict_time['time_getFileEnd'].append((extract_time[0], 0.51, in_attachment))
  3603. # if not dict_time['time_getFileEnd']:
  3604. # if re.search("前|止|截止", entity_right) or re.search("前",entity_text[-2:]):
  3605. # dict_time['time_getFileEnd'].append((extract_time[0], 0.51, in_attachment))
  3606. # elif re.search("起|开?始", entity_right) or re.search("起",entity_text[-2:]):
  3607. # dict_time['time_getFileStart'].append((extract_time[0], 0.51, in_attachment))
  3608. # if re.search("(进行|在线|线下).{,2}报名", entity_right2):
  3609. # if len(extract_time) == 2:
  3610. # dict_time['time_registrationStart'].append((extract_time[0], 0.51, in_attachment))
  3611. # dict_time['time_registrationEnd'].append((extract_time[1], 0.51, in_attachment))
  3612. # else:
  3613. # if previous_entity and previous_entity.sentence_index==entity.sentence_index:
  3614. # mid_text = sentence_text[previous_entity.wordOffset_end:entity.wordOffset_begin]
  3615. # if len(mid_text)<=10 and re.search("至|到|[-—]|[~~]",mid_text) and len(previous_extract_time)==1:
  3616. # dict_time['time_registrationStart'].append((previous_extract_time[0], 0.51, in_attachment))
  3617. # dict_time['time_registrationEnd'].append((extract_time[0], 0.51, in_attachment))
  3618. # if not dict_time['time_registrationEnd']:
  3619. # if re.search("前|止|截止", entity_right) or re.search("前",entity_text[-2:]):
  3620. # dict_time['time_registrationEnd'].append((extract_time[0], 0.51, in_attachment))
  3621. # elif re.search("起|开?始", entity_right) or re.search("起",entity_text[-2:]):
  3622. # dict_time['time_registrationStart'].append((extract_time[0], 0.51, in_attachment))
  3623. # if re.search("(进行|开始).{,4}(报价|投标|竞价)", entity_right2):
  3624. # if len(extract_time) == 2:
  3625. # dict_time['time_bidstart'].append((extract_time[0], 0.51, in_attachment))
  3626. # # dict_time['time_bidclose'].append((extract_time[1], 0.51, in_attachment))
  3627. # 补充公告末尾处的发布时间
  3628. if entity.label==0:
  3629. if entity.is_tail:
  3630. entity.label = 1
  3631. entity.values[1] = 0.5
  3632. dict_time['time_release'].append((extract_time[0], 0.5, in_attachment))
  3633. # 2022/12/12 新增挂牌时间正则
  3634. if re.search("挂牌.{,4}(?:时间|日期)",entity_left2):
  3635. if re.search("挂牌.{,4}(?:时间|日期)",entity_left2).end()>len(entity_left2)/2:
  3636. if len(extract_time) == 1:
  3637. if re.search("挂牌.?(开始|起始).?(?:时间|日期)",entity_left2):
  3638. dict_time['time_listingStart'].append((extract_time[0], 0.5, in_attachment))
  3639. last_time_type = 'time_listingStart'
  3640. elif re.search("挂牌.?(截[止至]|结束).?(?:时间|日期)",entity_left2):
  3641. dict_time['time_listingEnd'].append((extract_time[0], 0.5, in_attachment))
  3642. last_time_type = 'time_listingEnd'
  3643. elif re.search("挂牌.?(?:时间|日期)",entity_left2):
  3644. if re.search("前|止|截止",entity_right) or re.search("至|止|到",entity_left) or re.search("前",entity_text[-2:]):
  3645. dict_time['time_listingEnd'].append((extract_time[0], 0.5, in_attachment))
  3646. last_time_type = 'time_listingEnd'
  3647. else:
  3648. dict_time['time_listingStart'].append((extract_time[0], 0.5, in_attachment))
  3649. last_time_type = 'time_listingStart'
  3650. else:
  3651. dict_time['time_listingStart'].append((extract_time[0], 0.5, in_attachment))
  3652. dict_time['time_listingEnd'].append((extract_time[1], 0.5, in_attachment))
  3653. last_time_type = ''
  3654. last_sentence_index = entity.sentence_index
  3655. continue
  3656. # 2023/9/13 新增合同相关时间
  3657. if re.search("合同|服务|履[约行]", entity_left3[-15:]):
  3658. if len(extract_time) == 1:
  3659. if re.search("(合同.{,2}签[订定署].{,2}|签[订定署].{,2}合同.{,2})(?:时间|日期)|合同签[订定署].{,1}$", entity_left2):
  3660. dict_time['time_signContract'].append((extract_time[0], 0.5, in_attachment))
  3661. last_time_type = 'time_signContract'
  3662. last_sentence_index = entity.sentence_index
  3663. continue
  3664. elif re.search("(合同|服务|履约|(合同|服务)履行).{,4}(?:起始|开始)(?:时间|日期)", entity_left3[-15:]):
  3665. dict_time['time_contractStart'].append((extract_time[0], 0.55, in_attachment))
  3666. last_time_type = 'time_contractStart'
  3667. last_sentence_index = entity.sentence_index
  3668. continue
  3669. elif re.search("(合同|服务|履约).{,2}(?:完成|截止|结束)(?:时间|日期|时限)", entity_left2):
  3670. dict_time['time_contractEnd'].append((extract_time[0], 0.55, in_attachment))
  3671. last_time_type = 'time_contractEnd'
  3672. last_sentence_index = entity.sentence_index
  3673. continue
  3674. elif re.search("(?:合同|服务|履约|(合同|服务)履行)(?:期限?|有效期)|(?:服务|履约|(合同|服务)履行)(?:时间|日期|周期)|服务[时年]限|合同周期", entity_left2):
  3675. if re.search("到|至|截[至止]",entity_left) or re.search("前|止|截止",entity_right) or re.search("前",entity_text[-2:]):
  3676. dict_time['time_contractEnd'].append((extract_time[0], 0.5, in_attachment))
  3677. last_time_type = 'time_contractEnd'
  3678. else:
  3679. dict_time['time_contractStart'].append((extract_time[0], 0.5, in_attachment))
  3680. last_time_type = 'time_contractStart'
  3681. last_sentence_index = entity.sentence_index
  3682. continue
  3683. else:
  3684. if re.search("(?:合同|服务|履约|(合同|服务)履行)(?:期限?|有效期)|(?:服务|履约|(合同|服务)履行)(?:时间|日期|周期)|服务[时年]限|合同周期", entity_left2):
  3685. # 排除开始和借宿时间一样的错误模板,例:“履约期限:2023年02月15日至2023年02月15日”
  3686. if extract_time[0]!=extract_time[1]:
  3687. dict_time['time_contractStart'].append((extract_time[0], 0.6, in_attachment))
  3688. dict_time['time_contractEnd'].append((extract_time[1], 0.6, in_attachment))
  3689. last_time_type = ''
  3690. last_sentence_index = entity.sentence_index
  3691. continue
  3692. # 服务期限表达补充
  3693. if entity.label==0:
  3694. re_service = '合同期限|工期/交货期/服务期|工期\(交货期\)|合格工期|服务期限|工期' \
  3695. '|工期要求|项目周期|工期\(交货期\)|计划工期\(服务期限\)|服务时限|履行期限|服务周期|供货期限' \
  3696. '|合格工期|计划工期\(服务期\)|服务期|服务,期|交货\(完工\)(时间|日期)|交付\(服务、完工\)(时间|日期)' \
  3697. '|交货(时间|日期)|工期承诺|(服务|合同|施工|实施|工程|设计)的?(年限|期限|周期|期:)' \
  3698. '|服务期限为|计划工期|工期要求|服务期限|服务期' \
  3699. '|投标工期|设计工期|合格服务周期|总工期|服务(时间|日期)(范围)?|流转期限|维护期限|服务时限|交货期' \
  3700. '|完成(时间|日期)|服务期限|中标工期|项目周期|期限要求|供货期|合同履行日期|计划的?周期' \
  3701. '|履约期限|合同约定完成时限|合同完成日期|承诺完成日期' \
  3702. '|合同起始日起|合同履约期|履约截止日期|承包期限|合同完成日期' \
  3703. '|服务期间|服务履行期|委托(管理)?期限|履约期限、地点等简要信息'
  3704. if len(extract_time)==2:
  3705. if re.search(re_service,entity_left2) or re.search("履约期限、地点等简要信息",entity_left3[-20:]):
  3706. dict_time['time_contractStart'].append((extract_time[0], 0.5, in_attachment))
  3707. dict_time['time_contractEnd'].append((extract_time[1], 0.5, in_attachment))
  3708. last_time_type = ''
  3709. # 报价/投标时间补充(规则补充)
  3710. if entity.label == 0:
  3711. if re.search("[报竞]价.{,2}(开始|起始).{,2}(时间|日期)",entity_left2):
  3712. entity.label = 12
  3713. label_prob = 0.8
  3714. elif re.search("[报竞]价.{,2}起止.{,2}(时间|日期)",entity_left2):
  3715. entity.label = 12
  3716. label_prob = 0.6
  3717. elif re.search("响应.{,2}文件([递提]交|接收).{,2}(时间|日期)[::]|([递提]交|接收).{,2}响应.{,2}文件.{,2}(时间|日期)[::]",entity_left2):
  3718. entity.label = 3
  3719. label_prob = 0.501
  3720. elif re.search("响应.{,2}文件([递提]交|接收).{,2}(时间|日期)|([递提]交|接收).{,2}响应.{,2}文件.{,2}(时间|日期)",entity_left2) and not re.search("截[止至]",entity_left2):
  3721. entity.label = 12
  3722. label_prob = 0.51
  3723. elif re.search("[报竞]价.{,2}截[止至].{,2}(时间|日期)",entity_left2):
  3724. entity.label = 3
  3725. label_prob = 0.8
  3726. elif re.search("(竞价|报价).?(时间|日期)",entity_left2):
  3727. entity.label = 12
  3728. label_prob = 0.51
  3729. elif re.search("(竞价|报价).?(时间|日期)",entity_left3) and re.search("参与|报价|有意",entity_left2):
  3730. entity.label = 12
  3731. label_prob = 0.501
  3732. # 文档结构补充
  3733. # if entity.label == 0:
  3734. # re_registration = re.compile("报名|(文件|标书)[\u4e00-\u9fa5、]{,4}(获取|出售|售卖|购买|下载)|"
  3735. # "(获取|出售|售卖|购买|下载)[\u4e00-\u9fa5、]{,4}(文件|标书)")
  3736. # _data_i = -1
  3737. # while _data_i < len(document_tree) - 1:
  3738. # _data_i += 1
  3739. # _data = document_tree[_data_i]
  3740. # _type = _data["type"]
  3741. # _text = _data["text"].strip()
  3742. # childs = get_childs([_data])
  3743. # last_child = childs[-1]
  3744. # if entity.sentence_index>=_data.sentence_index and entity.wordOffset_begin>=_data.wordOffset_begin and
  3745. # ():
  3746. # if re.search(re_registration, re.split("[::;;,]", _text)[0][:20]) is not None:
  3747. #
  3748. # content_text = ""
  3749. # for c in childs:
  3750. # content_text += c["text"] + ""
  3751. # print('concat_text', content_text)
  3752. if re.search("[,;](完成|截止|结束)(时间|日期)", entity_left2[-8:]) and entity.label==0:
  3753. if entity.sentence_index == last_sentence_index:
  3754. time_type = last_time_index.get(last_time_type)
  3755. if time_type:
  3756. dict_time[time_type].append((extract_time[0], 0.5 + label_prob / 10,in_attachment))
  3757. last_time_type = ""
  3758. last_sentence_index = entity.sentence_index
  3759. continue
  3760. if re.search("至|到|[日\d][-—]$|[~~]", entity_left):
  3761. if entity.sentence_index == last_sentence_index:
  3762. time_type = last_time_index.get(last_time_type)
  3763. if time_type:
  3764. dict_time[time_type].append((extract_time[0], 0.5 + label_prob / 10,in_attachment))
  3765. last_time_type = ""
  3766. last_sentence_index = entity.sentence_index
  3767. continue
  3768. if entity.label!=0:
  3769. if entity.label==1 and label_prob>0.5:
  3770. dict_time['time_release'].append((extract_time[0],label_prob,in_attachment))
  3771. last_time_type = 'time_release'
  3772. elif entity.label==2 and label_prob>0.5:
  3773. dict_time['time_bidopen'].append((extract_time[0],label_prob,in_attachment))
  3774. last_time_type = 'time_bidopen'
  3775. elif entity.label==3 and label_prob>0.5:
  3776. if len(extract_time)==1:
  3777. dict_time['time_bidclose'].append((extract_time[0],label_prob,in_attachment))
  3778. last_time_type = 'time_bidclose'
  3779. elif len(extract_time)==2:
  3780. dict_time['time_bidstart'].append((extract_time[0], 0.6, in_attachment))
  3781. dict_time['time_bidclose'].append((extract_time[1], label_prob, in_attachment))
  3782. last_time_type = 'time_bidclose'
  3783. elif entity.label==12 and label_prob>0.5:
  3784. if len(extract_time)==1:
  3785. if re.search("前|止|截止",entity_right) or re.search("至|止|到",entity_left) or re.search("前",entity_text[-2:]):
  3786. dict_time['time_bidclose'].append((extract_time[0], label_prob,in_attachment))
  3787. last_time_type = 'time_bidclose'
  3788. else:
  3789. dict_time['time_bidstart'].append((extract_time[0], label_prob,in_attachment))
  3790. last_time_type = 'time_bidstart'
  3791. else:
  3792. dict_time['time_bidstart'].append((extract_time[0],label_prob,in_attachment))
  3793. dict_time['time_bidclose'].append((extract_time[1],label_prob,in_attachment))
  3794. last_time_type = ''
  3795. elif entity.label==4 and label_prob>0.5:
  3796. if len(extract_time)==1:
  3797. if re.search("前|止|截止",entity_right) or re.search("至|止|到",entity_left) or re.search("前",entity_text[-2:]):
  3798. dict_time['time_publicityEnd'].append((extract_time[0], label_prob,in_attachment))
  3799. last_time_type = 'time_publicityEnd'
  3800. else:
  3801. dict_time['time_publicityStart'].append((extract_time[0], label_prob,in_attachment))
  3802. last_time_type = 'time_publicityStart'
  3803. else:
  3804. dict_time['time_publicityStart'].append((extract_time[0],label_prob,in_attachment))
  3805. dict_time['time_publicityEnd'].append((extract_time[1],label_prob,in_attachment))
  3806. last_time_type = ''
  3807. elif entity.label==5 and label_prob>0.5:
  3808. if len(extract_time)==1:
  3809. dict_time['time_publicityEnd'].append((extract_time[0], label_prob,in_attachment))
  3810. last_time_type = 'time_publicityEnd'
  3811. else:
  3812. dict_time['time_publicityStart'].append((extract_time[0],label_prob,in_attachment))
  3813. dict_time['time_publicityEnd'].append((extract_time[1],label_prob,in_attachment))
  3814. last_time_type = ''
  3815. elif entity.label==6 and label_prob>0.5:
  3816. if len(extract_time)==1:
  3817. if (re.search("前|截?止",entity_right) and re.search("前|截?止(?!时间|日期)",entity_right2[:len(entity_right)+3])) or re.search("至|止|到",entity_left) or re.search("前",entity_text[-2:]):
  3818. dict_time['time_getFileEnd'].append((extract_time[0], label_prob,in_attachment))
  3819. last_time_type = 'time_getFileEnd'
  3820. else:
  3821. dict_time['time_getFileStart'].append((extract_time[0], label_prob,in_attachment))
  3822. last_time_type = 'time_getFileStart'
  3823. else:
  3824. dict_time['time_getFileStart'].append((extract_time[0],label_prob,in_attachment))
  3825. dict_time['time_getFileEnd'].append((extract_time[1],label_prob,in_attachment))
  3826. last_time_type = ''
  3827. elif entity.label==7 and label_prob>0.5:
  3828. if len(extract_time)==1:
  3829. dict_time['time_getFileEnd'].append((extract_time[0], label_prob,in_attachment))
  3830. last_time_type = 'time_getFileEnd'
  3831. else:
  3832. dict_time['time_getFileStart'].append((extract_time[0],label_prob,in_attachment))
  3833. dict_time['time_getFileEnd'].append((extract_time[1],label_prob,in_attachment))
  3834. last_time_type = ''
  3835. elif entity.label==8 and label_prob>0.5:
  3836. if len(extract_time)==1:
  3837. if re.search("前|止|截止",entity_right) or re.search("至|止|到",entity_left) or re.search("前",entity_text[-2:]):
  3838. dict_time['time_registrationEnd'].append((extract_time[0], label_prob,in_attachment))
  3839. last_time_type = 'time_registrationEnd'
  3840. else:
  3841. dict_time['time_registrationStart'].append((extract_time[0], label_prob,in_attachment))
  3842. last_time_type = 'time_registrationStart'
  3843. else:
  3844. dict_time['time_registrationStart'].append((extract_time[0],label_prob,in_attachment))
  3845. dict_time['time_registrationEnd'].append((extract_time[1],label_prob,in_attachment))
  3846. last_time_type = ''
  3847. elif entity.label==9 and label_prob>0.5:
  3848. if len(extract_time)==1:
  3849. dict_time['time_registrationEnd'].append((extract_time[0], label_prob,in_attachment))
  3850. last_time_type = 'time_registrationEnd'
  3851. else:
  3852. dict_time['time_registrationStart'].append((extract_time[0],label_prob,in_attachment))
  3853. dict_time['time_registrationEnd'].append((extract_time[1],label_prob,in_attachment))
  3854. last_time_type = ''
  3855. elif entity.label==10 and label_prob>0.5:
  3856. if len(extract_time)==1:
  3857. if re.search("前|止|截止",entity_right) or re.search("至|止|到",entity_left) or re.search("前",entity_text[-2:]):
  3858. dict_time['time_earnestMoneyEnd'].append((extract_time[0], label_prob,in_attachment))
  3859. last_time_type = 'time_earnestMoneyEnd'
  3860. else:
  3861. dict_time['time_earnestMoneyStart'].append((extract_time[0], label_prob,in_attachment))
  3862. last_time_type = 'time_earnestMoneyStart'
  3863. else:
  3864. dict_time['time_earnestMoneyStart'].append((extract_time[0],label_prob,in_attachment))
  3865. dict_time['time_earnestMoneyEnd'].append((extract_time[1],label_prob,in_attachment))
  3866. last_time_type = ''
  3867. elif entity.label==11 and label_prob>0.5:
  3868. if len(extract_time)==1:
  3869. dict_time['time_earnestMoneyEnd'].append((extract_time[0], label_prob,in_attachment))
  3870. last_time_type = 'time_earnestMoneyEnd'
  3871. else:
  3872. dict_time['time_earnestMoneyStart'].append((extract_time[0],label_prob,in_attachment))
  3873. dict_time['time_earnestMoneyEnd'].append((extract_time[1],label_prob,in_attachment))
  3874. last_time_type = ''
  3875. elif entity.label==13 and label_prob>0.5:
  3876. if len(extract_time)==1:
  3877. if re.search("前|止|截止",entity_right) or re.search("至|止|到",entity_left) or re.search("前",entity_text[-2:]):
  3878. dict_time['time_completion'].append((extract_time[0], label_prob,in_attachment))
  3879. last_time_type = 'time_completion'
  3880. else:
  3881. dict_time['time_commencement'].append((extract_time[0], label_prob,in_attachment))
  3882. last_time_type = 'time_commencement'
  3883. else:
  3884. dict_time['time_commencement'].append((extract_time[0],label_prob,in_attachment))
  3885. dict_time['time_completion'].append((extract_time[1],label_prob,in_attachment))
  3886. last_time_type = ''
  3887. elif entity.label==14 and label_prob>0.5:
  3888. if len(extract_time)==1:
  3889. dict_time['time_completion'].append((extract_time[0], label_prob,in_attachment))
  3890. last_time_type = 'time_completion'
  3891. else:
  3892. dict_time['time_commencement'].append((extract_time[0],label_prob,in_attachment))
  3893. dict_time['time_completion'].append((extract_time[1],label_prob,in_attachment))
  3894. last_time_type = ''
  3895. else:
  3896. last_time_type = ""
  3897. else:
  3898. last_time_type = ""
  3899. else:
  3900. last_time_type = ""
  3901. last_sentence_index = entity.sentence_index
  3902. # 通过文档分析树形结构补充部分时间实体
  3903. def add_time_by_parseDocument(dict_time,parse_document):
  3904. from BiddingKG.dl.interface.htmlparser import get_childs
  3905. document_tree = parse_document.tree
  3906. # if not dict_time['time_getFileStart'] or not dict_time['time_getFileEnd']:
  3907. # time_pattern = re.compile("")
  3908. concat_text_list = []
  3909. if not dict_time['time_registrationStart'] or not dict_time['time_registrationEnd']:
  3910. re_registration = re.compile("报名|(文件|标书)[\u4e00-\u9fa5、]{,4}(获取|出售|售卖|购买|下载)|"
  3911. "(获取|出售|售卖|购买|下载)[\u4e00-\u9fa5、]{,4}(文件|标书)")
  3912. _data_i = -1
  3913. while _data_i < len(document_tree) - 1:
  3914. _data_i += 1
  3915. _data = document_tree[_data_i]
  3916. _type = _data["type"]
  3917. _text = _data["text"].strip()
  3918. # print(_data.keys())
  3919. if _type == "sentence":
  3920. print('_text:',_text,_data["sentence_title"])
  3921. if _data["sentence_title"] is not None:
  3922. print("aptitude_pattern", _text)
  3923. print(_data['sentence_index'],_data['wordOffset_begin'],_data['wordOffset_end'])
  3924. if re.search(re_registration, re.split("[::;;。]",_text)[0][:15]) is not None:
  3925. childs = get_childs([_data])
  3926. concat_text = ""
  3927. for c in childs:
  3928. concat_text += c["text"] + ""
  3929. print('concat_text',concat_text)
  3930. concat_text_list.append(concat_text)
  3931. _data_i += len(childs)-1
  3932. # if _type == "table":
  3933. # list_table = _data["list_table"]
  3934. # parent_title = _data["parent_title"]
  3935. # if list_table is not None:
  3936. # for line in list_table[:2]:
  3937. # for cell_i in range(len(line)):
  3938. # cell = line[cell_i]
  3939. # cell_text = cell[0]
  3940. # if len(cell_text) > 120 and re.search(re_registration, cell_text) is not None:
  3941. # concat_text += cell_text + "\n"
  3942. print('_text',concat_text_list)
  3943. for text in concat_text_list:
  3944. time_list = re.finditer(my_time_format_pattern,text)
  3945. time_list = [(i,my_timeFormat(i.group(),page_time)) for i in time_list]
  3946. for time_idx in range(len(time_list)):
  3947. _time = time_list[time_idx][0]
  3948. extract_time = time_list[time_idx][1]
  3949. entity_left = text[:_time.start()]
  3950. entity_left = re.split("[。;;!??]",entity_left)[-1]
  3951. # entity_left2 = sentence_text[
  3952. # max(entity_context_begin, entity.wordOffset_begin - 10):entity.wordOffset_begin]
  3953. # entity_left3 = sentence_text[
  3954. # max(entity_context_begin, entity.wordOffset_begin - 30):entity.wordOffset_begin]
  3955. entity_right = text[_time.end():]
  3956. entity_right = re.split("[。;;!??]",entity_right)[0]
  3957. # entity_right2 = sentence_text[entity.wordOffset_end:entity_context_end]
  3958. entity_right2 = re.sub(r"(http[s]?://)?(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\\(\\),]|(?:%[0-9a-fA-F][0-9a-fA-F])){6,}",
  3959. '', entity_right)[:60] # 去除网址
  3960. print('entity_right2',entity_right2)
  3961. if re.search("(进行|在线|线下).{,2}报名", entity_right2):
  3962. print('报名text',entity_right2)
  3963. if len(extract_time) == 2:
  3964. dict_time['time_registrationStart'].append((extract_time[0], 0.51, in_attachment))
  3965. dict_time['time_registrationEnd'].append((extract_time[1], 0.51, in_attachment))
  3966. else:
  3967. if previous_entity and previous_entity.sentence_index==entity.sentence_index:
  3968. mid_text = sentence_text[previous_entity.wordOffset_end:entity.wordOffset_begin]
  3969. if len(mid_text)<=10 and re.search("至|到|[-—]|[~~]",mid_text) and len(previous_extract_time)==1:
  3970. dict_time['time_registrationStart'].append((previous_extract_time[0], 0.51, in_attachment))
  3971. dict_time['time_registrationEnd'].append((extract_time[0], 0.51, in_attachment))
  3972. if not dict_time['time_registrationEnd']:
  3973. if re.search("前|止|截止", entity_right) or re.search("前",entity_text[-2:]):
  3974. dict_time['time_registrationEnd'].append((extract_time[0], 0.51, in_attachment))
  3975. elif re.search("起|开?始", entity_right) or re.search("起",entity_text[-2:]):
  3976. dict_time['time_registrationStart'].append((extract_time[0], 0.51, in_attachment))
  3977. return dict_time
  3978. # dict_time = add_time_by_parseDocument(dict_time,parse_document)
  3979. # print(dict_time)
  3980. result_dict = dict((key,"") for key in dict_time.keys())
  3981. for time_type,value in dict_time.items():
  3982. list_time = dict_time[time_type]
  3983. if list_time:
  3984. for in_attachment in [False,True]:
  3985. _list_time = [_time for _time in list_time if _time[2]==in_attachment]
  3986. if _list_time:
  3987. _list_time.sort(key=lambda x:(x[1],len(x[0])),reverse=True) # sort_key: label_prob,时间文本长度(优先有具体时分秒的)
  3988. if in_attachment==True and len(result_dict[time_type])>0:
  3989. break
  3990. result_dict[time_type] = _list_time[0][0]
  3991. # result_dict 纠错
  3992. if not result_dict['time_bidclose']:
  3993. if result_dict['time_bidstart']: # 无截标时间,投标开始和开标时间一样
  3994. if result_dict['time_bidstart'][:10] in result_dict['time_bidopen']:
  3995. result_dict['time_bidstart'] = ""
  3996. result_dict['time_bidclose'] = result_dict['time_bidopen']
  3997. if not result_dict['time_bidclose']:
  3998. if result_dict['time_getFileEnd']: # 无截标时间,获取文件截止时间和开标时间一样
  3999. if result_dict['time_getFileEnd'][:10] in result_dict['time_bidopen']:
  4000. result_dict['time_bidclose'] = result_dict['time_bidopen']
  4001. else:
  4002. if result_dict['time_bidopen']: # 截标时间 和 开标时间 时分秒互补
  4003. if len(result_dict['time_bidclose'])<len(result_dict['time_bidopen']) and result_dict['time_bidclose'] in result_dict['time_bidopen']:
  4004. result_dict['time_bidclose'] = result_dict['time_bidopen']
  4005. elif len(result_dict['time_bidclose'])>len(result_dict['time_bidopen']) and result_dict['time_bidopen'] in result_dict['time_bidclose']:
  4006. result_dict['time_bidopen'] = result_dict['time_bidclose']
  4007. return result_dict
  4008. def get_days_between(day1,day2,get_abs=0):
  4009. '''
  4010. :param day1: 较小日期
  4011. :param day2: 较大日期
  4012. :param get_abs: 是否取绝对值
  4013. :return: 天数差
  4014. '''
  4015. # 将日期字符串转换为datetime对象
  4016. date1 = datetime.strptime(day1, '%Y-%m-%d')
  4017. date2 = datetime.strptime(day2, '%Y-%m-%d')
  4018. # 计算日期差
  4019. delta = date2 - date1
  4020. # 获取天数差
  4021. days_difference = delta.days
  4022. if get_abs:
  4023. return abs(days_difference)
  4024. else:
  4025. return days_difference
  4026. def extract_serviceTime(service_time,page_time):
  4027. pattern1 = re.compile("\d{4}[年\-./]\d{1,2}[月\-./]\d{1,2}日?")
  4028. pattern2 = re.compile("\d+(?:\.\d+)?[((]?个?[^\d]?[^\d]?(?:日|天|周年|整年|学?年|月|周|日历[天日]|工作[天日])")
  4029. pattern3 = re.compile("\d{4}[年\-./]\d{1,2}月?")
  4030. pattern4 = re.compile("(?:日|天|周年|年|月|周|日历[天日]|工作[天日]|星期)[^\d]{1,3}\d+(?:\.\d+)?")
  4031. DigitsDic = {"零":0, "壹":1, "贰":2, "叁":3, "肆":4, "伍":5, "陆":6, "柒":7, "捌":8, "玖":9,
  4032. "〇":0, "一":1, "二":2, "三":3, "四":4, "五":5, "六":6, "七":7, "八":8, "九":9,
  4033. "两":2, '貮': 2}
  4034. def get_month_days(year, month):
  4035. # calendar.monthrange(year, month)返回一个元组,其中第一个元素是月份的第一天是星期几(0-6为星期一到星期日),
  4036. # 第二个元素是该月的天数。
  4037. _, last_day = calendar.monthrange(year, month)
  4038. return last_day
  4039. def get_num(text):
  4040. CN_UNIT = {'十': 10,'拾': 10,'百': 100,
  4041. '佰': 100,'千': 1000,'仟': 1000}
  4042. regex = re.compile(r'[〇一二三四五六七八九零壹贰叁肆伍陆柒捌玖貮两十拾百佰千仟]+')
  4043. text = regex.search(text)
  4044. if text:
  4045. text = text.group()
  4046. else:
  4047. return ""
  4048. result = 0
  4049. result_list = []
  4050. unit = 0
  4051. control = 0
  4052. for i, d in enumerate(text):
  4053. if d in '零百佰千仟' and i == 0:
  4054. return ""
  4055. if d in DigitsDic:
  4056. result += DigitsDic[d]
  4057. elif d in CN_UNIT:
  4058. if unit == 0:
  4059. unit_1 = CN_UNIT[d]
  4060. # 这里的处理主要是考虑到类似于二十三亿五千万这种数
  4061. if result == 0:
  4062. result = CN_UNIT[d]
  4063. else:
  4064. result *= CN_UNIT[d]
  4065. unit = CN_UNIT[d]
  4066. result_1 = result
  4067. elif unit > CN_UNIT[d]:
  4068. result -= DigitsDic[text[i - 1]]
  4069. result += DigitsDic[text[i - 1]] * CN_UNIT[d]
  4070. unit = CN_UNIT[d]
  4071. elif unit <= CN_UNIT[d]:
  4072. if (CN_UNIT[d] < unit_1) and (len(result_list) == control):
  4073. result_list.append(result_1)
  4074. result = (result - result_1) * CN_UNIT[d]
  4075. control += 1
  4076. else:
  4077. result *= CN_UNIT[d]
  4078. unit = CN_UNIT[d]
  4079. if len(result_list) == control:
  4080. unit_1 = unit
  4081. result_1 = result
  4082. else:
  4083. return ""
  4084. return sum(result_list) + result
  4085. serviceTime_dict = {"service_start": "", "service_end": "", "service_days": 0}
  4086. re_num = re.findall(r'[〇一二三四五六七八九零壹贰叁肆伍陆柒捌玖貮两十拾百佰千仟]+',service_time)
  4087. for _num in re_num:
  4088. if not re.search("[十拾百佰千仟]",_num):
  4089. num = ""
  4090. for word in _num:
  4091. num += str(DigitsDic.get(word,word))
  4092. service_time = service_time.replace(_num,num,1)
  4093. else:
  4094. num = str(get_num(_num))
  4095. service_time = service_time.replace(_num,num,1)
  4096. end_time = ""
  4097. service_days = 0
  4098. re_page_time = re.search("20\d{2}-\d{2}-\d{2}", page_time)
  4099. page_time = re_page_time.group() if re_page_time else "2000-01-01" # page_time为空时默认值为2000-01-01
  4100. if re.search(pattern1,service_time):
  4101. # end_time = re.findall(pattern1,service_time)[-1]
  4102. time_list = []
  4103. for _time in re.findall(pattern1,service_time):
  4104. _time = re.sub("日","",_time)
  4105. _time = re.sub("[年月./]","-",_time)
  4106. _year,_month,_day = _time.split("-")
  4107. _month = int(_month)
  4108. _day = int(_day)
  4109. _year = int(_year)
  4110. if _year>2050 or _year<=2000 or _month>12 or _month<=0 or _day<=0 or _day>31:
  4111. service_days = 0
  4112. else:
  4113. if isValidDate(_year,_month,_day):
  4114. _time = str(_year)+'-'+str(_month)+'-'+str(_day)
  4115. _time = _time.split("-")[0] + '-' + _time.split("-")[1].rjust(2,"0") + '-' + _time.split("-")[2].rjust(2,"0")
  4116. time_list.append(_time)
  4117. if len(time_list)>=2:
  4118. if get_days_between(page_time,time_list[1])>1 and get_days_between(time_list[0],time_list[1])>0:
  4119. serviceTime_dict['service_end'] = time_list[1]
  4120. serviceTime_dict['service_start'] = time_list[0]
  4121. elif len(time_list)==1:
  4122. if get_days_between(page_time, time_list[0]) > 1:
  4123. serviceTime_dict['service_end'] = time_list[0]
  4124. # service_days = (time.mktime(time.strptime(end_time,"%Y-%m-%d"))-page_timestamp)/(24*60*60)
  4125. elif re.search(pattern3,service_time):
  4126. time_list = []
  4127. # end_time = re.findall(pattern3,service_time)[-1]
  4128. for _time in re.findall(pattern3,service_time):
  4129. _time = re.sub("月","",_time)
  4130. _time = re.sub("[年./]","-",_time)
  4131. _year,_month = _time.split("-")
  4132. _day = 0
  4133. _month = int(_month)
  4134. _year = int(_year)
  4135. if _year>2050 or _year<=2000 or _month>12 or _month<=0:
  4136. service_days = 0
  4137. else:
  4138. _day = get_month_days(_year,_month)
  4139. if isValidDate(_year, _month, _day):
  4140. _time = str(_year)+'-'+str(_month)+'-'+str(_day)
  4141. _time = _time.split("-")[0] + '-' + _time.split("-")[1].rjust(2,"0") + '-' + _time.split("-")[2].rjust(2,"0")
  4142. time_list.append(_time)
  4143. if len(time_list) >= 2:
  4144. if get_days_between(page_time, time_list[1]) > 1 and get_days_between(time_list[0], time_list[1]) > 0:
  4145. serviceTime_dict['service_end'] = time_list[1]
  4146. serviceTime_dict['service_start'] = time_list[0]
  4147. elif len(time_list)==1:
  4148. if get_days_between(page_time, time_list[0]) > 1:
  4149. serviceTime_dict['service_end'] = time_list[0]
  4150. # service_days = (time.mktime(time.strptime(end_time,"%Y-%m-%d"))-page_timestamp)/(24*60*60)
  4151. elif re.search(pattern2,service_time) or re.search(pattern4,service_time):
  4152. for pattern in [pattern2,pattern4]:
  4153. unit = 1
  4154. match = re.findall(pattern,service_time)
  4155. if len(set(match))==1:
  4156. match_text = match[0]
  4157. if "月" in match_text:
  4158. unit = 30
  4159. elif "年" in match_text:
  4160. unit = 365
  4161. elif "周" in match_text or "星期" in match_text:
  4162. unit = 7
  4163. match_num = float(re.search("\d+",match_text).group())
  4164. # 数字能被365整除,单位更正为天
  4165. if int(match_num)%365==0:
  4166. unit = 1
  4167. if unit==365:
  4168. if match_num>10:#单位为'年'时,排除数字过大的
  4169. match_num = 0
  4170. elif unit==30:
  4171. if match_num>60:#单位为'月'时,排除数字过大的
  4172. match_num = 0
  4173. elif unit==1:
  4174. if match_num>4000:#单位为'日'时,排除数字过大的
  4175. match_num = 0
  4176. service_days = int(match_num * unit)
  4177. if service_days % 360==0:
  4178. service_days = service_days / 360 * 365
  4179. elif service_days % 180==0 and service_days % 360!=0:
  4180. service_days = service_days // 360 * 365 + 180
  4181. service_days = int(service_days)
  4182. if service_days <= 1 and service_days > 4000:
  4183. service_days = 0
  4184. # if service_days>3:
  4185. if service_days>0:
  4186. # service_days = str(service_days) + "天"
  4187. serviceTime_dict['service_days'] = service_days
  4188. break
  4189. elif "半年" in service_time:
  4190. service_days = 180
  4191. # service_days = str(service_days) + "天"
  4192. serviceTime_dict['service_days'] = service_days
  4193. if serviceTime_dict['service_start'] and serviceTime_dict['service_end']:
  4194. service_days = get_days_between(serviceTime_dict['service_start'],serviceTime_dict['service_end'])
  4195. serviceTime_dict['service_days'] = service_days
  4196. return serviceTime_dict
  4197. def getServiceTime():
  4198. pass
  4199. def getOtherAttributes(list_entity,page_time,prem,channel_dic):
  4200. dict_other = {"moneysource":"",
  4201. "person_review":[],
  4202. "serviceTime":"",
  4203. "product":[],
  4204. "total_tendereeMoney":0,
  4205. "total_tendereeMoneyUnit":''}
  4206. list_serviceTime = []
  4207. last_moneysource_prob = 0
  4208. for entity in list_entity:
  4209. if entity.entity_type == 'bidway':
  4210. dict_other["bidway"] = turnBidWay(entity.entity_text)
  4211. elif entity.entity_type=='moneysource':
  4212. if dict_other["moneysource"] and entity.in_attachment:
  4213. continue
  4214. if not dict_other["moneysource"]:
  4215. dict_other["moneysource"] = entity.entity_text
  4216. last_moneysource_prob = entity.prob
  4217. elif entity.prob>last_moneysource_prob:
  4218. dict_other["moneysource"] = entity.entity_text
  4219. last_moneysource_prob = entity.prob
  4220. elif entity.entity_type=='serviceTime':
  4221. # print(entity.entity_text)
  4222. # if list_serviceTime and entity.in_attachment:
  4223. # continue
  4224. if re.search("[^之]日|天|年|月|周|星期", entity.entity_text) or re.search("\d{4}[-./]\d{1,2}", entity.entity_text):
  4225. list_serviceTime.append(entity)
  4226. elif entity.entity_type=="person" and entity.label ==4 and entity.entity_text not in dict_other["person_review"]: # 20240624评审专家去重
  4227. dict_other["person_review"].append(entity.entity_text)
  4228. elif entity.entity_type=='product' and entity.entity_text not in dict_other["product"]: #顺序去重保留
  4229. dict_other["product"].append(entity.entity_text)
  4230. elif entity.entity_type=='money' and entity.notes=='总投资' and float(entity.entity_text)>5000000 and float(dict_other["total_tendereeMoney"])<float(entity.entity_text): # 20250702 限制总投资为500万的以上
  4231. dict_other["total_tendereeMoney"] = str(Decimal(entity.entity_text))
  4232. dict_other["total_tendereeMoneyUnit"] = entity.money_unit
  4233. time_contractEnd = prem[0].get("time_contractEnd","")[:10]
  4234. time_contractStart = prem[0].get("time_contractStart","")[:10]
  4235. serviceTime_dict = {"service_start":"", "service_end":"", "service_days": 0}
  4236. if time_contractEnd:
  4237. serviceTime_dict['service_end'] = time_contractEnd
  4238. if time_contractStart:
  4239. if get_days_between(time_contractStart,time_contractEnd)>0:
  4240. serviceTime_dict['service_start'] = time_contractStart
  4241. # print([i.entity_text for i in list_serviceTime])
  4242. if list_serviceTime and not serviceTime_dict['service_end']:
  4243. list_serviceTime_inAtt = [serviceTime for serviceTime in list_serviceTime if serviceTime.in_attachment==1]
  4244. list_serviceTime = [serviceTime for serviceTime in list_serviceTime if serviceTime.in_attachment==0]
  4245. error_serviceTime = []
  4246. for list_time in [list_serviceTime,list_serviceTime_inAtt]:
  4247. if not serviceTime_dict['service_end'] and not serviceTime_dict['service_days']:
  4248. list_time.sort(key=lambda x: (x.prob,-x.sentence_index,-x.begin_index), reverse=True)
  4249. for _serviceTime in list_time:
  4250. # 优先取具体时间(20XX年x月x日-20XX年x月x日)
  4251. if re.search("20\d{2}[年/.\-]\d{1,2}[月/.\-]\d{1,2}日?[^。\d半一二三四五六七八九十壹两叁贰肆伍陆柒捌玖拾;;]{,4}20\d{2}[年/.\-]\d{1,2}[月/.\-]\d{1,2}日?",_serviceTime.entity_text):
  4252. _extract_time,_ = my_timeFormat(_serviceTime.entity_text,page_time)
  4253. if _extract_time and len(_extract_time)==2:
  4254. # 排除开始和结束时间一样的错误模板,例:“履约期限:2023年02月15日至2023年02月15日”
  4255. if _extract_time[0]!=_extract_time[1]:
  4256. # dict_other["serviceTime"] = _serviceTime.entity_text
  4257. # extract_time = extract_serviceTime(_serviceTime.entity_text)
  4258. # if extract_time['service_end']:
  4259. serviceTime_dict['service_start'] = _extract_time[0]
  4260. serviceTime_dict['service_end'] = _extract_time[1]
  4261. break
  4262. else:
  4263. error_serviceTime.append(_serviceTime.entity_text)
  4264. if not serviceTime_dict['service_end']:
  4265. for _serviceTime in list_time:
  4266. # 优先取具体时间(20XX年x月-20XX年x月)
  4267. if re.search("20\d{2}[年/.\-]\d{1,2}月?[^。\d半一二三四五六七八九十壹两叁贰肆伍陆柒捌玖拾;;]{,3}20\d{2}[年/.\-]\d{1,2}月?", _serviceTime.entity_text):
  4268. # dict_other["serviceTime"] = _serviceTime.entity_text
  4269. extract_time = extract_serviceTime(_serviceTime.entity_text,page_time)
  4270. if extract_time['service_end']:
  4271. serviceTime_dict = extract_time
  4272. break
  4273. if not serviceTime_dict['service_end']:
  4274. for _serviceTime in list_time:
  4275. # 优先取具体时间(20XX年x月x日)
  4276. if re.search("20\d{2}[年/.\-]\d{1,2}[月/.\-]\d{1,2}日?",_serviceTime.entity_text):
  4277. if _serviceTime.entity_text not in error_serviceTime:
  4278. # dict_other["serviceTime"] = _serviceTime.entity_text
  4279. extract_time = extract_serviceTime(_serviceTime.entity_text,page_time)
  4280. if extract_time['service_end']:
  4281. serviceTime_dict = extract_time
  4282. break
  4283. if not serviceTime_dict['service_end'] and not serviceTime_dict['service_days']:
  4284. for _serviceTime in list_time:
  4285. if _serviceTime.entity_text not in error_serviceTime:
  4286. # dict_other["serviceTime"] = _serviceTime.entity_text
  4287. extract_time = extract_serviceTime(_serviceTime.entity_text,page_time)
  4288. # service_days > 3
  4289. if extract_time['service_end'] or extract_time['service_days']>3:
  4290. serviceTime_dict = extract_time
  4291. break
  4292. # 若上一步仍无结果,取消service_days > 3 的条件
  4293. if not serviceTime_dict['service_end'] and not serviceTime_dict['service_days']:
  4294. for _serviceTime in list_time:
  4295. if _serviceTime.entity_text not in error_serviceTime:
  4296. # dict_other["serviceTime"] = _serviceTime.entity_text
  4297. extract_time = extract_serviceTime(_serviceTime.entity_text,page_time)
  4298. if extract_time['service_end'] or extract_time['service_days']:
  4299. serviceTime_dict = extract_time
  4300. break
  4301. if serviceTime_dict['service_start'] and serviceTime_dict['service_end']:
  4302. service_days = get_days_between(serviceTime_dict['service_start'],serviceTime_dict['service_end'])
  4303. serviceTime_dict['service_days'] = service_days
  4304. dict_other["serviceTime"] = serviceTime_dict
  4305. if not time_contractEnd and channel_dic['docchannel']['docchannel']=='合同公告': # 用serviceTime补充合同开始结束时间,公告类型为合同公告
  4306. if serviceTime_dict['service_start'] and serviceTime_dict['service_end']:
  4307. prem[0]["time_contractStart"] = serviceTime_dict['service_start']
  4308. prem[0]["time_contractEnd"] = serviceTime_dict['service_end']
  4309. if dict_other['moneysource']:
  4310. dict_other['moneysource'] = turnMoneySource(dict_other['moneysource'])
  4311. # dict_other["product"] = list(set(dict_other["product"])) # 已在添加时 顺序去重保留
  4312. return dict_other
  4313. def getMoneyRange(RoleList):
  4314. pass
  4315. def getProjectContacts(list_entity, list_sentence):
  4316. # project_contacts "项目联系人"提取
  4317. temp_person_entitys = [ent for ent in list_entity if ent.entity_type=='person' and ent.label in [1,2,3]]
  4318. temp_person_entitys = sorted(temp_person_entitys,key=lambda x:(x.sentence_index,x.wordOffset_begin))
  4319. project_contacts_patterns = ['项目.?联系[人方]','项目.?联系.?方式', '项目.?负责人']
  4320. project_contacts_patterns_prob = [0.9, 0.85, 0.8]
  4321. project_contacts_patterns_res = []
  4322. for ent in temp_person_entitys:
  4323. sent_idx = ent.sentence_index
  4324. word_begin = ent.wordOffset_begin
  4325. # word_end = ent.wordOffset_end
  4326. in_att = ent.in_attachment
  4327. if word_begin >= 5: # > len('项目联系人')
  4328. left_text = list_sentence[sent_idx].sentence_text[max(0, word_begin - 15):word_begin]
  4329. # print('left_text', left_text)
  4330. for pattern, prob in zip(project_contacts_patterns, project_contacts_patterns_prob):
  4331. if re.search(pattern, left_text):
  4332. project_contacts_patterns_res.append([ent, sent_idx, word_begin, prob if not in_att else prob / 2])
  4333. project_contacts_patterns_res = sorted(project_contacts_patterns_res, key=lambda x: (x[3], -x[1], -x[2]),
  4334. reverse=True)
  4335. # print('project_contacts_patterns_res', project_contacts_patterns_res)
  4336. project_contacts_list = []
  4337. phone_set = set()
  4338. have_in_text = False
  4339. if project_contacts_patterns_res:
  4340. for item in project_contacts_patterns_res:
  4341. in_att = item[0].in_attachment
  4342. contacts_person = item[0].entity_text
  4343. contacts_phone = item[0].person_phone[0].entity_text if item[0].person_phone else ""
  4344. if contacts_phone:
  4345. if not in_att:
  4346. have_in_text = True
  4347. if in_att and have_in_text: # 正文已提取,则排除附件的
  4348. break
  4349. if contacts_phone not in phone_set:
  4350. phone_set.add(contacts_phone)
  4351. project_contacts_list.append([contacts_person,contacts_phone])
  4352. return {'project_contacts':project_contacts_list}
  4353. def getPREMs(list_sentences,list_entitys,list_articles,list_outlines,page_time,winter_scope):
  4354. '''
  4355. @param:
  4356. list_sentence:所有文章的句子list
  4357. list_entity:所有文章的实体list
  4358. @return:list of dict which include文章的包-角色-实体名称-金额-联系人-联系电话
  4359. '''
  4360. result = []
  4361. for list_sentence,list_entity,list_article,list_outline in zip(list_sentences,list_entitys,list_articles,list_outlines):
  4362. RoleList = getPackageRoleMoney(list_sentence,list_entity,list_outline,winter_scope)
  4363. result.append(dict({"prem": RoleList, "docid": list_article.doc_id},
  4364. **getTimeAttributes(list_entity, list_sentence,page_time),
  4365. **getProjectContacts(list_entity, list_sentence),
  4366. **{"fingerprint": list_article.fingerprint,
  4367. "match_enterprise": list_article.match_enterprise,
  4368. "match_enterprise_type": list_article.match_enterprise_type,
  4369. "process_time": getCurrent_date(),
  4370. "attachmentTypes": list_article.attachmentTypes, "bidway": list_article.bidway}))
  4371. # result.append(dict({"prem":RoleList,"docid":list_article.doc_id},**getOtherAttributes(list_entity),**getTimeAttributes(list_entity,list_sentence),
  4372. # **{"fingerprint":list_article.fingerprint,"match_enterprise":list_article.match_enterprise,
  4373. # "match_enterprise_type":list_article.match_enterprise_type,"process_time":getCurrent_date(),
  4374. # "attachmentTypes":list_article.attachmentTypes, "bidway": list_article.bidway}))
  4375. return result
  4376. def correct_rolemoney(docid, prem, total_product_money, total_budget, list_articles): # 2022/9/26修改为 中标金额小于表格单价数量合计总金额十分之一时替换
  4377. '''
  4378. 最后根据表格提取的单价数量合计对比更新中标金额,或中标金额为0全文只有一个总价或合计时,作为中标金额
  4379. :param docid: 公告编号
  4380. :param prem: 列表
  4381. :param total_product_money: 表格统计金额
  4382. :param total_budget: 表格合计预算金额
  4383. :param list_articles: 文章对象
  4384. :return:
  4385. '''
  4386. if '##attachment##' in list_articles[0].content:
  4387. content, attachment = list_articles[0].content.split('##attachment##')
  4388. if len(content) < 200:
  4389. content += attachment
  4390. else:
  4391. content = list_articles[0].content
  4392. if len(re.findall('win_tenderer|second_tenderer|third_tenderer', str(prem[0]['prem'])))==1:# and re.search('(中标|成交|合同|投标))?(总?金额|[报总]?价)((万?元))?:', content) == None: # 只有一个中标角色且没有明确中标金额表达的
  4393. if total_product_money>0 and total_product_money<2000000:
  4394. for value in prem[0]['prem'].values():
  4395. ree_money = float(value['tendereeMoney'])
  4396. for l in value['roleList']:
  4397. try:
  4398. # if l[0] == 'win_tenderer' and float(l[2])<total_product_money:
  4399. # l[2] = total_product_money
  4400. # log('修改中标金额为所有产品总金额')
  4401. # if l["role_name"] == 'win_tenderer' and float(l["role_money"]['money']) == 0 and float(l["role_money"]['money'])<total_product_money/10:
  4402. if l["role_name"] == 'win_tenderer' and (float(l["role_money"]['money']) == 0 or(float(l["role_money"]['money'])*2<total_product_money<500000) or (float(l["role_money"]['money'])<ree_money/2 and float(l["role_money"]['money'])<total_product_money<ree_money)): # 改为小于一半招标金额或为0时替换为合计金额
  4403. l["role_money"]['money'] = total_product_money
  4404. log('修改中标金额为产品总金额: %s, docid:%s' % (total_product_money, docid))
  4405. except Exception as e:
  4406. print('表格产品价格修正中标价格报错:%s'%e)
  4407. elif (len(re.findall('合计', content)) == 1 or len(re.findall('总价', content)) == 1):
  4408. ser = re.search('(?P<header>合计((万?元))?:)(?P<money>[\d,.]+(万?元)?)', content) if len(re.findall('合计', content)) == 1 else re.search('(?P<header>总价((万?元))?:)(?P<money>[\d,.]+(万?元)?)', content)
  4409. if ser:
  4410. money_text = ser.group('money')
  4411. header = ser.group('header')
  4412. money, money_unit = money_process(money_text, header)
  4413. if 100<money<8000000:
  4414. for value in prem[0]['prem'].values():
  4415. for l in value['roleList']:
  4416. try: # 如果原中标金额为0 或 金额小于合计金额0.1倍且正文没中标金额关键词 替换为 合计金额
  4417. if l["role_name"] == 'win_tenderer' and (float(l["role_money"]['money'])==0 or (float(l["role_money"]['money']) < money / 10 and re.search('(中标|成交|合同)(总?金额|[单报总]?价)', content) == None)):
  4418. l["role_money"]['money'] = str(money)
  4419. l["role_money"]['money_unit'] = money_unit
  4420. log('修改中标金额为总价或合计金额: %s, docid:%s'%(money, docid))
  4421. except Exception as e:
  4422. print('修正中标价格报错:%s' % e)
  4423. if 0 < total_budget < 2000000 and len(prem[0]['prem']) == 1 and 'Project' in prem[0]['prem'] and float(prem[0]['prem']['Project']["tendereeMoney"])*2 < total_budget:
  4424. prem[0]['prem']['Project']["tendereeMoney"] = total_budget
  4425. log('修改招标金额为表格合计预算: %s, docid:%s' % (total_budget, docid))
  4426. def limit_maximum_amount(dic, list_entity):
  4427. '''
  4428. 通过关键词、行业、公告类别等设置最高最低角色金额
  4429. :param dic: 最终返回所有字段结果字典
  4430. :param list_entity: 实体列表
  4431. :return:
  4432. '''
  4433. indu_amount = {
  4434. '计算机设备': 200000000,
  4435. '办公设备': 100000000,
  4436. '家具用具': 500000000,
  4437. '办公消耗用品及类似物品': 100000000,
  4438. '日杂用品': 100000000,
  4439. '餐饮业': 1000000000,
  4440. '物业管理': 1000000000,
  4441. '工程技术与设计服务': 1000000000,
  4442. '工程评价服务': 100000000,
  4443. '其他工程服务': 100000000,
  4444. '工程监理服务': 100000000,
  4445. '工程造价服务': 100000000,
  4446. '会计、审计及税务服务': 100000000,
  4447. '其他专业咨询与调查': 100000000
  4448. }
  4449. title = dic.get('doctitle_refine', '')
  4450. name = dic.get('name', '')
  4451. product = ','.join(dic.get('product', []))
  4452. text = "%s;%s;%s"%(title, name, product)
  4453. doctype = dic.get('docchannel', {}).get('doctype', '') # 公告类型
  4454. industry = dic['industry'].get('class_name', '')
  4455. category = dic['industry'].get('class', '') # 行业门类
  4456. moneys = [float(it.entity_text) for it in list_entity if it.entity_type=='money' and re.search('^\d+(\.\d+)?', it.entity_text) and 5000<float(it.entity_text)<5000000]
  4457. maximum_amount = 10000000000
  4458. minximum_amount = 100
  4459. if re.search('监理|造价咨询|设计|勘察|招标代理中介服务|工程审计', text) and re.search('施工|总承包|ppp|PPP', text.replace('施工监理', '监理'))==None:
  4460. # print('监理设计等限额')
  4461. maximum_amount = 1000000000
  4462. minximum_amount = 200
  4463. elif re.search('施工|总承包|ppp|PPP|公路|道路|桥梁|铁路|土地使用权|地块|棚改|征地拆迁|棚户区改造|土地征收|建设用地|社会保险', text) or category in ['金融业', '建筑业'] or doctype == '土地矿产':
  4464. # print('施工、铁路等限额')
  4465. if industry in ['科研、医疗、教育用房', '住宅、商业用房', '场馆、站港用房','工业、生产用房','专业施工']:
  4466. maximum_amount = 20000000000
  4467. minximum_amount = 200
  4468. elif industry in ['修缮工程', '电气安装', '管道和设备安装', '建筑装饰和装修业', '建筑物拆除和场地准备活动']:
  4469. maximum_amount = 10000000000
  4470. minximum_amount = 100
  4471. else:
  4472. maximum_amount = 50000000000
  4473. minximum_amount = 500
  4474. elif re.search('(办公|体育)(用品|设备|器材)|耗材|打印机|复印机|打印纸|粉盒|墨粉|复印纸|网上超市|电子卖场|家电|配电箱采购|配件|备件', text):
  4475. # print('商品采购限额')
  4476. maximum_amount = 80000000
  4477. minximum_amount = 10
  4478. elif re.search('修理|维修|(安保|保安|安全|保洁|物业|后勤|管理|代理|中介|印刷)服务', text):
  4479. # print('维修限额')
  4480. maximum_amount = 50000000
  4481. elif re.search('(速递|快递|邮政|邮寄)(物流)?服务', text):
  4482. # print('快递限额')
  4483. maximum_amount = 80000000
  4484. minximum_amount = 10
  4485. elif industry in indu_amount:
  4486. maximum_amount = indu_amount[industry]
  4487. # print('maximum_amount:', maximum_amount)
  4488. for value in dic['prem'].values():
  4489. for l in value['roleList']:
  4490. if l["role_name"] in ['win_tenderer', 'second_tenderer', 'third_tenderer']:
  4491. # date = float(re.search('(\d+)天', l.get('serviceTime', '')).group(1)) if re.search('(\d+)天', l.get('serviceTime', '')) else 0
  4492. serviceTime_dict = l.get('serviceTime', dict())
  4493. serviceTime_dict = serviceTime_dict if serviceTime_dict else dict()
  4494. date = serviceTime_dict.get("service_days",0)
  4495. if 0 < date < 180 and float(l["role_money"]['money']) > 10000000000: # 工期小于180天且金额大于百亿的,错误
  4496. l["role_money"]['money'] = str(Decimal(l["role_money"]['money']) / 10000)
  4497. # print('工期纠正百亿以上金额 ')
  4498. elif float(l["role_money"]['money']) > maximum_amount:
  4499. flag = 1
  4500. for money in moneys:
  4501. if float(l["role_money"]['money'])/money == 10000 and l['role_money']['money_unit'] == '万元':
  4502. l["role_money"]['money'] = str(Decimal(l["role_money"]['money']) / 10000)
  4503. # print('万倍关系纠正连接金额')
  4504. flag = 0
  4505. break
  4506. if flag and l["role_money"]['money_unit'] == '万元' or re.search('^\d{11,}(\.0)?$', str(l["role_money"]['money'])):
  4507. l["role_money"]['money'] = str(Decimal(l["role_money"]['money']) / 10000)
  4508. # print('行业限额纠正连接金额')
  4509. elif industry in ['餐饮业', '物业管理'] and maximum_amount == indu_amount[industry]:
  4510. l["role_money"]['money'] = str(Decimal(l["role_money"]['money']) / 10000)
  4511. # elif flag and l["role_money"]['money_unit'] == '元':
  4512. # l["role_money"]['money'] = 0
  4513. elif 0<float(l["role_money"]['money']) < minximum_amount:
  4514. if l["role_money"]['money_unit'] == '元' and re.search('^\d{1,2}\.\d{4,6}$', str(l["role_money"]['money'])):
  4515. # print('单位元小金额且格式类似万元的乘以万倍')
  4516. l["role_money"]['money'] = str(Decimal(l["role_money"]['money']) * 10000)
  4517. # else: # 20241011 取消小于最低金额改为0 避免小金额不提取 例:520248605
  4518. # # print('中标金额小于限额:%d元 去除' % minximum_amount)
  4519. # l["role_money"]['money'] = 0
  4520. if float(value['tendereeMoney']) > maximum_amount:
  4521. flag = 1
  4522. for money in moneys:
  4523. if float(value['tendereeMoney'])/money == 10000 and l['role_money']['money_unit'] == '万元':
  4524. value['tendereeMoney'] = str(Decimal(value['tendereeMoney'])/10000)
  4525. # print('万倍关系纠正连接金额')
  4526. flag = 0
  4527. break
  4528. 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 项目(系统)一亿变一万
  4529. value['tendereeMoney'] = str(Decimal(value['tendereeMoney']) / 10000)
  4530. # print('行业限额纠正连接金额')
  4531. elif industry in ['餐饮业', '物业管理'] and maximum_amount == indu_amount[industry]:
  4532. value['tendereeMoney'] = str(Decimal(value['tendereeMoney']) / 10000)
  4533. # elif flag and value['tendereeMoneyUnit'] == '元':
  4534. # value['tendereeMoney'] = 0
  4535. elif 0<float(value['tendereeMoney']) < minximum_amount:
  4536. if value['tendereeMoneyUnit'] == '元' and re.search('^\d{1,2}\.\d{4,6}$', str(value['tendereeMoney'])):
  4537. # print('单位元小金额且格式类似万元的乘以万倍')
  4538. value['tendereeMoney'] = str(Decimal(value['tendereeMoney']) * 10000)
  4539. # else: # 20241011 取消小于最低金额改为0 避免小金额不提取 例:520248605
  4540. # # print('招标金额小于限额:%d元 去除' % minximum_amount)
  4541. # value['tendereeMoney'] = 0
  4542. def limit_maximum_amount_backup(prem, industry):
  4543. indu = industry['industry'].get('class_name', '')
  4544. indu_amount = {
  4545. '计算机设备': 200000000,
  4546. '办公设备': 100000000,
  4547. '家具用具': 500000000,
  4548. '办公消耗用品及类似物品': 100000000,
  4549. '日杂用品': 100000000,
  4550. '餐饮业': 1000000000,
  4551. '物业管理': 1000000000,
  4552. '工程技术与设计服务': 1000000000,
  4553. '工程评价服务': 100000000,
  4554. '其他工程服务': 100000000,
  4555. '工程监理服务': 100000000,
  4556. '工程造价服务': 100000000,
  4557. '会计、审计及税务服务': 100000000,
  4558. }
  4559. if indu in indu_amount:
  4560. maximum_amount = indu_amount[indu]
  4561. try:
  4562. for value in prem[0]['prem'].values():
  4563. for l in value['roleList']:
  4564. if l["role_name"] == 'win_tenderer' and float(l["role_money"]['money']) > maximum_amount:
  4565. if indu in ['餐饮业', '物业管理']:
  4566. l["role_money"]['money'] = str(float(l["role_money"]['money'])/10000)
  4567. elif l["role_money"]['money_unit'] == '万元':
  4568. l["role_money"]['money'] = str(float(l["role_money"]['money'])/10000)
  4569. if float(value['tendereeMoney']) > maximum_amount:
  4570. if indu in ['餐饮业', '物业管理']:
  4571. value['tendereeMoney'] = float(value['tendereeMoney'])/10000
  4572. elif value['tendereeMoneyUnit'] == '万元':
  4573. value['tendereeMoney'] = float(value['tendereeMoney']) / 10000
  4574. except Exception as e:
  4575. print('行业分类限制最高金额抛出异常:%s' % e)
  4576. def get_win_joint(prem, list_entitys, list_sentences, list_articles):
  4577. '''
  4578. 获取联合体信息, 添加到prem
  4579. :param prem:
  4580. :param list_entitys:
  4581. :param list_sentences:
  4582. :param list_articles:
  4583. :return:
  4584. '''
  4585. try:
  4586. if 'win_tenderer' in str(prem[0]['prem']) and re.search('联合(体|方|投标人):|联合体(成员|单位)[12345一二三四五]?:|(联合体)?成员单位[12345一二三四五]?:|特殊普通合伙:|(联合(体|投标人))|(联合体(成员|单位)方?[12345一二三四五]?)|((联合体)?成员单位[12345一二三四五]?)|(特殊普通合伙|成员?)|[,;]成:|(成[),]|与[^,。]{6,100}联合体', list_articles[0].content):
  4587. sentences = sorted(list_sentences[0], key=lambda x:x.sentence_index)
  4588. for v in prem[0]['prem'].values():
  4589. for d in v['roleList']:
  4590. if d.get('role_name', '') == 'win_tenderer':
  4591. winner = d.get('role_text')
  4592. join_l = [winner]
  4593. for list_entity in list_entitys:
  4594. for i in range(len(list_entity)-1):
  4595. _entity = list_entity[i]
  4596. b = _entity.wordOffset_begin
  4597. e = _entity.wordOffset_end
  4598. if _entity.entity_type in ['org', 'company'] and _entity.label==2\
  4599. and _entity.entity_text==winner:
  4600. s = sentences[_entity.sentence_index].sentence_text
  4601. find_joint = 0 # 是否包含联合体
  4602. for j in range(i+1, len(list_entity)):
  4603. behind_entity = list_entity[j]
  4604. b2 = behind_entity.wordOffset_begin
  4605. e2 = behind_entity.wordOffset_end
  4606. if _entity.sentence_index == behind_entity.sentence_index and behind_entity.entity_type in ['org', 'company'] \
  4607. and b2-e<13 and re.search('联合(体|方|投标人):|联合体(成员|单位)[12345一二三四五]?:|(联合体)?成员单位[12345一二三四五]?:|特殊普通合伙:|[,;]成:|(成)$', s[e:b2]) or \
  4608. re.search('(联合(体|方|投标人))|(联合体(成员|单位)方?[12345一二三四五]?)|((联合体)?成员单位[12345一二三四五]?)|(特殊普通合伙|成员?)|^(成[),]$', s[e2:e2+10]) and behind_entity.label in [2, 5]:
  4609. join_l.append(behind_entity.entity_text)
  4610. b = b2
  4611. e = e2
  4612. find_joint = 1
  4613. 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]=='联合体'):
  4614. join_l.append(behind_entity.entity_text)
  4615. b = b2
  4616. e = e2
  4617. elif e == e2: # 修复重复实体导致中断情况
  4618. continue
  4619. else:
  4620. break
  4621. if len(join_l)>1:
  4622. d['win_tenderer_joint'] = ','.join(set(join_l))
  4623. # behind_entity = list_entity[i + 1]
  4624. # if _entity.sentence_index== behind_entity.sentence_index and _entity.entity_type in ['org', 'company'] and _entity.label==2\
  4625. # and _entity.entity_text==winner and behind_entity.entity_type in ['org', 'company'] and behind_entity.label==5:
  4626. # s = sentences[_entity.sentence_index].sentence_text
  4627. # b = _entity.wordOffset_begin
  4628. # e = _entity.wordOffset_end
  4629. # b2 = behind_entity.wordOffset_begin
  4630. # e2 = behind_entity.wordOffset_end
  4631. # if re.search('(联合体)', s[e2:e2+6]) and b2-e<3:
  4632. # print('联合体:', s[max(0, b-10):e2+10])
  4633. # d['win_tenderer_joint'] = '%s,%s'%(_entity.entity_text, behind_entity.entity_text)
  4634. # break
  4635. # elif re.search('(联合体((牵头|主办)(人|方|单位)|主体)|牵头(人|方|单位))|(联合体)?成员:|特殊普通合伙:', s[e:b2]) and b2-e<10:
  4636. # d['win_tenderer_joint'] = '%s,%s' % (_entity.entity_text, behind_entity.entity_text)
  4637. # print('联合体:', s[max(0, b - 10):e2 + 10])
  4638. # break
  4639. except Exception as e:
  4640. print('获取联合体抛出异常', e)
  4641. def get_multi_winner_and_money(channel_dic, prem, list_entitys,list_sentences, all_winner=False):
  4642. '''
  4643. 获取多中标人及正文、附件所有金额,多中标人multi_winner写入prem,返回金额列表
  4644. :param channel_dic:
  4645. :param prem:
  4646. :param list_entitys:
  4647. :param list_sentences:
  4648. :return:
  4649. '''
  4650. def add_multi_winner(pack_l, winner_l):
  4651. if len(prem[0]['prem']) > 1 and len(set([it[0] for it in pack_l])) > 1: # 多标段多中标人处理
  4652. pk_dic = {}
  4653. for ent in winner_l:
  4654. for i in range(len(pack_l)):
  4655. pk, s1, b1, _ = pack_l[i]
  4656. if ent[1] < s1 or ent[1] == s1 and ent[2] < b1:
  4657. break
  4658. elif (ent[1] > s1 or ent[1] == s1 and ent[2] > b1):
  4659. if i < len(pack_l) - 1:
  4660. pk2, s2, b2, _ = pack_l[i + 1]
  4661. if (ent[1] < s2 or ent[1] == s2 and ent[2] < b2):
  4662. if pk not in pk_dic:
  4663. pk_dic[pk] = set()
  4664. pk_dic[pk].add(ent[0])
  4665. else:
  4666. continue
  4667. else:
  4668. if pk not in pk_dic:
  4669. pk_dic[pk] = set()
  4670. pk_dic[pk].add(ent[0])
  4671. else:
  4672. continue
  4673. for pk, multi_winner in pk_dic.items():
  4674. multi_winner = multi_winner - tenderee_or_agency
  4675. if len(multi_winner) < 2:
  4676. continue
  4677. for k, v in prem[0]['prem'].items():
  4678. if pk == k:
  4679. for d in v['roleList']:
  4680. if d.get('role_name', '') == 'win_tenderer':
  4681. if d.get('role_text', '') in multi_winner and 'multi_winner' not in d:
  4682. d['multi_winner'] = ','.join(set(multi_winner))
  4683. elif 0 < len(prem[0]['prem']) < 3: # 修复 单包多中标人 例:285780273
  4684. multi_winner = set([it[0] for it in winner_l]) - tenderee_or_agency
  4685. if len(multi_winner) > 1:
  4686. for v in prem[0]['prem'].values():
  4687. for d in v['roleList']:
  4688. if d.get('role_name', '') == 'win_tenderer':
  4689. if d.get('role_text', '') in multi_winner and 'multi_winner' not in d:
  4690. d['multi_winner'] = ','.join(set(multi_winner))
  4691. break
  4692. moneys = []
  4693. moneys_attachment = []
  4694. if channel_dic['docchannel']['life_docchannel'] in ['中标信息','候选人公示','合同公告'] and 'win_tenderer' in str(prem):
  4695. sentences = sorted(list_sentences[0], key=lambda x: x.sentence_index)
  4696. finalists = [] # 入围供应商
  4697. multi_winner_l = [] # 保存中标人名称列表
  4698. tenderee_or_agency = set()
  4699. package_l = []
  4700. i = 0
  4701. while i < len(list_entitys[0])-1:
  4702. ent = list_entitys[0][i]
  4703. b_idx_fr = ent.wordOffset_begin
  4704. e_idx_fr = ent.wordOffset_end
  4705. i += 1
  4706. if ent.entity_type in ['money']:
  4707. money = float(ent.entity_text)
  4708. if ent.in_attachment:
  4709. moneys_attachment.append(money)
  4710. else:
  4711. moneys.append(money)
  4712. elif ent.entity_type in ['package']:
  4713. package_l.append((ent.entity_text, ent.sentence_index, ent.wordOffset_begin, ent.in_attachment))
  4714. elif ent.entity_type in ['org', 'company']:
  4715. sentence_text = sentences[ent.sentence_index].sentence_text
  4716. pre_text = sentence_text[max(0, b_idx_fr - 10):b_idx_fr]
  4717. if ent.label in [0,1] and ent.values[ent.label] > 0.8:
  4718. tenderee_or_agency.add(ent.entity_text)
  4719. elif ent.label == 2 and (ent.values[ent.label] > 0.8 or all_winner):
  4720. multi_winner_l.append((ent.entity_text, ent.sentence_index, ent.wordOffset_begin, ent.in_attachment))
  4721. for j in range(i, len(list_entitys[0])):
  4722. ent_bh = list_entitys[0][j]
  4723. b_idx_bh = ent_bh.wordOffset_begin
  4724. e_idx_bh = ent_bh.wordOffset_end
  4725. 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]:
  4726. if sentence_text[e_idx_fr:b_idx_bh] in [';', '、', '&', ',', '/', '//'] and (
  4727. len(sentence_text) == e_idx_bh or sentence_text[e_idx_bh] in [';', '、', '&', ',','/', '//','。']): # 修复多中标人刚好在文末index超出报错,例子 407126558
  4728. multi_winner_l.append((ent_bh.entity_text, ent_bh.sentence_index, ent_bh.wordOffset_begin, ent_bh.in_attachment))
  4729. e_idx_fr = e_idx_bh
  4730. i = j + 1
  4731. else:
  4732. break
  4733. 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: # 两实体间没符号分割情况
  4734. multi_winner_l.append((ent_bh.entity_text, ent_bh.sentence_index, ent_bh.wordOffset_begin, ent_bh.in_attachment))
  4735. e_idx_fr = e_idx_bh
  4736. i = j + 1
  4737. elif ent_bh.entity_type in ['org', 'company'] and ent_bh.label == 5 and e_idx_fr == e_idx_bh: # 处理 514603520 中国邮政储蓄银行股份有限公司淄博市临淄区支行 实体由于字典匹配重复两次情况
  4738. i = j + 1
  4739. else:
  4740. break
  4741. if re.search('入围', pre_text) and re.search('未入围', pre_text)==None:
  4742. finalists.append((ent.entity_text, ent.sentence_index, ent.wordOffset_begin, ent.in_attachment))
  4743. elif all_winner==1 and ent.label in [3,4,5] and re.search('第[一二三四五六七八九十0-9]+名|候选(人|单位)|入围(单位|供应商)|投标银行', pre_text) and re.search('未', pre_text)==None:
  4744. multi_winner_l.append((ent.entity_text, ent.sentence_index, ent.wordOffset_begin, ent.in_attachment))
  4745. if len(multi_winner_l)>=2:
  4746. winner_main = [it for it in multi_winner_l if not it[3]]
  4747. winner_attn = [it for it in multi_winner_l if it[3]]
  4748. pack_main = [it for it in package_l if not it[3]]
  4749. pack_attn = [it for it in package_l if it[3]]
  4750. if len(set([it[0] for it in winner_main]))>=2: # 有两个及以上多中标人及多标段 例:441612746
  4751. add_multi_winner(pack_main, winner_main)
  4752. elif len(set([it[0] for it in winner_attn]))>=2:
  4753. add_multi_winner(pack_attn, winner_attn)
  4754. if len(finalists)>=2: # 多入围候选人
  4755. winner_main = [it for it in finalists if not it[3]]
  4756. winner_attn = [it for it in finalists if it[3]]
  4757. pack_main = [it for it in package_l if not it[3]]
  4758. pack_attn = [it for it in package_l if it[3]]
  4759. if len(set([it[0] for it in winner_main]))>=2: # 有两个及以上多中标人及多标段 例:276326152
  4760. add_multi_winner(pack_main, winner_main)
  4761. elif len(set([it[0] for it in winner_attn]))>=2:
  4762. add_multi_winner(pack_attn, winner_attn)
  4763. else:
  4764. for i in range(len(list_entitys[0])):
  4765. ent = list_entitys[0][i]
  4766. if ent.entity_type in ['money']:
  4767. money = float(ent.entity_text)
  4768. if ent.in_attachment:
  4769. moneys_attachment.append(money)
  4770. else:
  4771. moneys.append(money)
  4772. return {'moneys': list(set(moneys)), 'moneys_attachment': list(set(moneys_attachment))}
  4773. def update_prem(old_prem, new_prem, in_attachment=False):
  4774. '''
  4775. 根据新旧对比,更新数据
  4776. :param old_prem:
  4777. :param new_prem: 表格提取的要素
  4778. :return:
  4779. '''
  4780. if len(new_prem) >= 1 :
  4781. '''如果表格提取的包大于2,原来的包比表格提取的包多则删除原来多余的包,以表格的为准 20250528补充条件表格提取需有中标人避免 626464296 替换错误'''
  4782. if len(new_prem) >= 2 and 'win_tenderer' in json.dumps(new_prem) and (len(new_prem)<len(old_prem) <= len(new_prem)*2 or set(old_prem)&set(new_prem)==set()): # 修复类似443925411 标的+标包才算标段号
  4783. del_k = []
  4784. for k in old_prem:
  4785. if k not in new_prem and k != 'Project':
  4786. del_k.append(k)
  4787. for k in del_k:
  4788. old_prem.pop(k)
  4789. if len(old_prem) > len(new_prem) and len(new_prem)>1 and in_attachment==False: # 如果表格有提取,非表格包数比表格提取多,去掉非表格在附件里提取的包
  4790. del_k = []
  4791. for k in old_prem:
  4792. if 'in_attachment' in old_prem[k] and old_prem[k]['in_attachment'] and k not in new_prem and k != 'Project':
  4793. del_k.append(k)
  4794. for k in del_k:
  4795. old_prem.pop(k)
  4796. if in_attachment: # 附件表格提取的,原来提取有中标人,停止替换
  4797. for v in old_prem.values():
  4798. for d in v['roleList']:
  4799. if d['role_name'] in ['win_tenderer', 'pre_win_tenderer']:
  4800. return 0
  4801. # if len(new_prem) > len(old_prem) and [k for k in new_prem if '自增' not in k] == []: # 如果表格提取包号都为自增编号且包数大于非表格提取,不进行更新 例 244355092 281854766
  4802. # return None
  4803. 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包
  4804. k = list(old_prem.keys()-set(['Project']))[0]
  4805. k_new = list(new_prem.keys())[0]
  4806. new_prem[k] = new_prem.pop(k_new)
  4807. elif len(old_prem) == 1 and len(new_prem) == 1 and 'Project' not in old_prem and set(new_prem)&set(old_prem)==set(): # 如果表格提取包与非表格提取都是一个包且不同,把表格提取包名替换为非表格包名
  4808. k = list(old_prem.keys()-set(['Project']))[0]
  4809. k_new = list(new_prem.keys())[0]
  4810. new_prem[k] = new_prem.pop(k_new)
  4811. if len(new_prem) == len(old_prem) == 1 and 'Project' not in new_prem and 'Project' in old_prem: # 如果表格提取到包号,非表格没提取到,合并到Project
  4812. k = list(new_prem.keys())[0]
  4813. new_prem['Project'] = new_prem[k]
  4814. multi_tendereeMoney = [] # 多包招标金额
  4815. for k, v in new_prem.items():
  4816. if k == 'Project':
  4817. if 'Project' in old_prem:
  4818. tmp_l = [] # 保存新旧同时包含的角色
  4819. if v.get('code', "") != "":
  4820. old_prem['Project']['code'] = v.get('code', "")
  4821. if v.get('name', "") != "":
  4822. old_prem['Project']['name'] = v.get('name', "")
  4823. for d in old_prem['Project']['roleList']:
  4824. for d2 in v['roleList']:
  4825. if d['role_name'] == d2['role_name']: # 同时包含的角色用表格的替换
  4826. tmp_l.append(d2)
  4827. if d2['role_text'] != "":
  4828. d['role_text'] = d2['role_text']
  4829. if d2['serviceTime'] != "":
  4830. d['serviceTime'] = d2['serviceTime']
  4831. if float(d2['role_money']['money']) != 0: # 如果表格提取的金额不为0才替换
  4832. d['role_money']['money'] = d2['role_money']['money']
  4833. d['role_money']['money_unit'] = d2['role_money']['money_unit']
  4834. for k in set(d2)-set(d): # 把表格提取加的属性补充过来,比如:multi_winner other_winner_dic等
  4835. if d2[k]:
  4836. d[k] = d2[k]
  4837. for d2 in v['roleList']:
  4838. if d2 not in tmp_l: # 把新预测有,旧没有的角色添加上去
  4839. old_prem['Project']['roleList'].append(d2)
  4840. if float(new_prem['Project']['tendereeMoney'])!=0:
  4841. old_prem['Project']['tendereeMoney'] = new_prem['Project']['tendereeMoney'] # 20240508 修复 464187225 表格提取纠正招标金额错误
  4842. else:
  4843. old_prem[k] = v
  4844. else:
  4845. if v['tendereeMoney'] != 0:
  4846. multi_tendereeMoney.append(v['tendereeMoney'])
  4847. if k.startswith('自增'): # 表格提取的没找到包号 按行数添加包号,前面加自增,例 自增1
  4848. k = k[2:]
  4849. if k not in old_prem: # 新有旧没有的包直接添加
  4850. old_prem[k] = v
  4851. else:
  4852. tmp_l = [] # 保存新旧同时包含的角色
  4853. if v.get('code', "") != "":
  4854. old_prem[k]['code'] = v.get('code', "")
  4855. if v.get('name', "") != "":
  4856. old_prem[k]['name'] = v.get('name', "")
  4857. for d in old_prem[k]['roleList']:
  4858. for d2 in v['roleList']:
  4859. if d['role_name'] == d2['role_name']:
  4860. tmp_l.append(d2)
  4861. if d2['role_text'] != "":
  4862. d['role_text'] = d2['role_text']
  4863. if d2['serviceTime'] != "":
  4864. d['serviceTime'] = d2['serviceTime']
  4865. if float(d2['role_money']['money']) != 0: # 如果表格提取的金额不为0才替换
  4866. d['role_money']['money'] = d2['role_money']['money']
  4867. d['role_money']['money_unit'] = d2['role_money']['money_unit']
  4868. for k2 in set(d2)-set(d): # 把表格提取加的属性补充过来,比如:multi_winner other_winner_dic等
  4869. if d2[k2]:
  4870. d[k2] = d2[k2]
  4871. for d2 in v['roleList']:
  4872. if d2 not in tmp_l: # 把新预测有,旧没有的角色添加上去
  4873. old_prem[k]['roleList'].append(d2)
  4874. if v['tendereeMoney'] != 0:
  4875. old_prem[k]['tendereeMoney'] = v['tendereeMoney'] # 2024/05/24 使用表格招标金额
  4876. if multi_tendereeMoney and 'Project' in old_prem and float(old_prem['Project']['tendereeMoney'])!=0: # 表格提取到多标段招标金额,去掉Project包招标金额
  4877. old_prem['Project']['tendereeMoney'] = 0
  4878. tenderee_l = [d2['role_text'] for v in old_prem.values() for d2 in v['roleList'] if d2['role_name']=='tenderee']
  4879. winner_l = [d2['role_text'] for v in old_prem.values() for d2 in v['roleList'] if d2['role_name']=='win_tenderer']
  4880. if set(tenderee_l) & set(winner_l): # 删除与中标人冲突的招标人
  4881. for k in old_prem:
  4882. old_prem[k]['roleList'] = [d for d in old_prem[k]['roleList'] if
  4883. not(d['role_name'] == 'tenderee' and d['role_text'] in winner_l)]
  4884. # print('删除与中标人冲突的招标人')
  4885. # return old_prem
  4886. def rule_add_role(docid, prem, channel, content, web_source_no, nlp_enterprise):
  4887. def add_role(ent_name, role_type, prem, money=0):
  4888. if 'Project' in prem:
  4889. prem['Project']['roleList'].append(
  4890. {
  4891. "address": "",
  4892. "linklist": [],
  4893. "role_money": {
  4894. "discount_ratio": "",
  4895. "downward_floating_ratio": "",
  4896. "floating_ratio": "",
  4897. "money": money,
  4898. "money_unit": ""
  4899. },
  4900. "role_name": role_type,
  4901. "role_prob": 0.6,
  4902. "role_text": ent_name,
  4903. "rule_add_role": True,
  4904. "serviceTime": ""
  4905. }
  4906. )
  4907. else:
  4908. prem['Project'] = {
  4909. "code": "",
  4910. "name": "",
  4911. "roleList": [
  4912. {
  4913. "address": "",
  4914. "linklist": [
  4915. ],
  4916. "role_money": {
  4917. "discount_ratio": "",
  4918. "downward_floating_ratio": "",
  4919. "floating_ratio": "",
  4920. "money": money,
  4921. "money_unit": ""
  4922. },
  4923. "role_name": role_type,
  4924. "role_prob": 0.6,
  4925. "role_text": ent_name,
  4926. "rule_add_role": True,
  4927. "serviceTime": ""
  4928. }
  4929. ],
  4930. "tendereeMoney": 0,
  4931. "tendereeMoneyUnit": "",
  4932. "uuid": str(uuid.uuid4())
  4933. }
  4934. if channel['docchannel']['docchannel'] == '招标公告' and re.search('"role_name": "tenderee"',json.dumps(prem)) == None:
  4935. match = re.search('(招标|采购|招商)(人|方|商|单位|部门)(信息[,:]?)?(名称)?((甲方))?:(?P<name>[\w()—-]{4,35})([,。]|$)', content)
  4936. if match:
  4937. ent_name = match.group('name')
  4938. if re.search('测试|演示|某|\d号|\*|XX', ent_name)==None and re.search('^\w{1,5}[省市县区][\w()]{2,25}[厂店铺市场行部城室馆中心站处社会狱所园关局司署段厅院队小学村]((个体工商户)?|(普通合伙)?)?$',
  4939. ent_name): # or is_enterprise_exist(ent_name)
  4940. log('规则补充招标人角色:%s,docid:%s'%(ent_name, docid))
  4941. add_role(ent_name, "tenderee", prem)
  4942. elif web_source_no == 'DX000752' and len(nlp_enterprise)==1 and re.search('更多信息点击报价地址', content): # 修复 628311260
  4943. ent_name = nlp_enterprise[0]
  4944. add_role(ent_name, "tenderee", prem)
  4945. elif channel['docchannel']['docchannel'] == '中标信息' and re.search('"role_name": "win_tenderer"',json.dumps(prem)) == None:
  4946. match = re.search('((中标|中选|成交))?(人|方|供应商|服务商|单位|部门)|(拟定|[,。])供应商)(信息[,:]?)?(名称)?((乙方))?:(?P<name>[\w()—-]{4,35})([,。]|$)',content)
  4947. if match:
  4948. ent_name = match.group('name')
  4949. if re.search('测试|演示|某|\d号|\*|XX', ent_name)==None and re.search('^\w{1,5}[省市县区][\w()]{2,25}[厂店铺市场行部城室馆中心站处社会狱所园关局署段厅院队小学]((个体工商户)?|(普通合伙)?)?$',
  4950. ent_name): # or is_enterprise_exist(ent_name)
  4951. b_idx = match.end()
  4952. idx_ = content[b_idx:].find('。')
  4953. e_idx = idx_ if idx_ > 0 else 200
  4954. text = content[b_idx:b_idx+e_idx]
  4955. money_list, _ = get_money_entity(text)
  4956. money = 0
  4957. for money_tup in money_list:
  4958. entity_text, b, e, unit, notes = money_tup
  4959. if re.search('(中标|成交|中选|投标|合同)总?(价格?|金额)', text[max(0, b-10):b]):
  4960. money = float(entity_text)
  4961. break
  4962. log('规则补充中标人角色:%s, 金额:%s,docid:%s'%(ent_name, money, docid))
  4963. add_role(ent_name, "win_tenderer", prem, money)
  4964. def confirm_prem(docid, prem, channel_dic, content, is_deposit_project=False, total_tendereeMoney=0):
  4965. '''
  4966. 规则检查纠正prem,如果Project包中标人在其他包中标人,去掉project包中标角色;如果有其他包中标人,去掉roleList为空的包;
  4967. :param prem: prem 字段字典
  4968. :return:
  4969. '''
  4970. if len(prem) > 1: # 表格提取到中标人的,去掉project包中标人
  4971. pro_winner = set()
  4972. other_winner = set()
  4973. other_winner_prob = 0
  4974. pro_winner_prob = 0
  4975. empty_roleList = []
  4976. for k in prem:
  4977. prem[k]['uuid'] = str(uuid.uuid4()) # 20240627 每个包都添加uuid
  4978. if prem[k]['roleList'] == []:
  4979. empty_roleList.append(k)
  4980. for d in prem[k]['roleList']:
  4981. if d['role_name'] in ['win_tenderer', 'pre_win_tenderer', 'second_tenderer','third_tenderer']:
  4982. if k == 'Project':
  4983. pro_winner.add(d['role_text'])
  4984. if 'win_tenderer_joint' in d:
  4985. pro_winner.update(set(d['win_tenderer_joint'].split(',')))
  4986. if 'multi_winner' in d:
  4987. pro_winner.update(set(d['multi_winner'].split(',')))
  4988. if d['role_name'] == 'win_tenderer' and d.get('role_prob', 0)>0.6:
  4989. pro_winner_prob = d.get('role_prob', 0)
  4990. else:
  4991. other_winner.add(d['role_text'])
  4992. if 'win_tenderer_joint' in d:
  4993. other_winner.update(set(d['win_tenderer_joint'].split(',')))
  4994. if 'multi_winner' in d:
  4995. other_winner.update(set(d['multi_winner'].split(',')))
  4996. if d['role_name'] == 'win_tenderer' and d.get('role_prob', 0)>0.6:
  4997. other_winner_prob = d.get('role_prob', 0)
  4998. if pro_winner!=set() and (pro_winner & other_winner != set() or other_winner_prob>pro_winner_prob): # 如果默认包与其他包中标人重复或其他包中标人概率比默认包大,删除默认包中标人
  4999. prem['Project']['roleList'] = [d for d in prem['Project']['roleList'] if
  5000. d['role_name'] not in ['win_tenderer', 'second_tenderer',
  5001. 'third_tenderer']]
  5002. elif other_winner_prob<pro_winner_prob and len(prem)==2: # 两个包情况,如果默认包中标人概率比其他包大,删除其他包
  5003. rm_k = [k for k in prem if k != 'Project']
  5004. for k in rm_k:
  5005. prem.pop(k)
  5006. if other_winner and channel_dic['docchannel']['docchannel'] in ['中标信息', '候选人公示', '合同公告']:
  5007. for k in empty_roleList:
  5008. prem.pop(k)
  5009. elif "Project" in prem:
  5010. prem['Project']['uuid'] = str(uuid.uuid4())
  5011. if len(prem) == 2:
  5012. del_k = [k for k,v in prem.items() if v.get('roleList', [])==[] and v.get('tendereeMoney', 0)==0 and v.get('unit_tendereeMoney', 0)==0] # 20250310 删除掉没有角色且招标金额为0 的包
  5013. for k in del_k:
  5014. prem.pop(k)
  5015. # print('删除掉没有角色且招标金额为0 的包', k)
  5016. if is_deposit_project and float(total_tendereeMoney)!=0 and len(prem)==1: #20241107 存款类项目有总投资没招标金额且只有一个标段,把总投资作招标金额
  5017. for k in prem:
  5018. if float(prem[k]['tendereeMoney'])==0:
  5019. prem[k]['tendereeMoney'] = total_tendereeMoney
  5020. # 采购人:某单位 等去掉tenderee
  5021. if "Project" in prem and re.search('(招标|采购|招商)(人|商|单位|部门)(信息[,:]?)?(名称)?((甲方))?:[\u4e00-\u9fa5]{,3}某+(单位|部)', content):
  5022. for d in prem['Project']['roleList']:
  5023. if d['role_name'] == 'tenderee' and d.get('role_prob', 0)<0.7: # 581195772 小于0.7才删除,附件明确表达可能0.7多
  5024. log('规则去除文中包含“采购人:某单位”等概率小于0.7的招标人:%s,docid:%s'%(d.get('role_text', ''), docid))
  5025. prem['Project']['roleList'].remove(d)
  5026. def add_package_name(prem, list_entity, product_list, name):
  5027. '''
  5028. 通过产品、项目名称,补充各标段包名,如果标段无包名,标段后紧接产品,把产品作为包名;如果标段数少于等于2且包名为空,补充项目名称为包名
  5029. :param prem:
  5030. :param list_entity:
  5031. :param product_list:
  5032. :param name:
  5033. :return:
  5034. '''
  5035. if len(prem)>2 and len(product_list)>2:
  5036. ent_l = []
  5037. for entity in list_entity:
  5038. if entity.entity_type in ['product', 'package']:
  5039. ent_l.append((entity.entity_type, entity.entity_text, entity.sentence_index, entity.wordOffset_begin, entity.wordOffset_end, entity.in_attachment))
  5040. ent_l.sort(key=lambda x: [x[2],x[3]])
  5041. i = 0
  5042. pk_dic = {}
  5043. while i < len(ent_l)-1:
  5044. ty1, ent1, s1, b1, e1, in_att1 = ent_l[i]
  5045. ty2, ent2, s2, b2, e2, in_att2 = ent_l[i+1]
  5046. if in_att1 == in_att2 and ty1 == 'package' and ty2 == 'product' and s1 == s2 and 0<b2-e1<3:
  5047. pk_dic[ent1] = ent2
  5048. i += 1
  5049. if len(pk_dic) > 1:
  5050. for k, v in prem.items():
  5051. if k in pk_dic and v.get('name', '') == '':
  5052. v['name'] = pk_dic[k]
  5053. elif name != '' and len(prem)<=2: # 20241129 小于等于两个包且无包名称,取项目名称
  5054. for k in prem:
  5055. if prem[k].get('name', '') == '':
  5056. prem[k]['name'] = name
  5057. def fix_single_source(prem, channel_dic, original_docchannel):
  5058. if prem.get('bidway', '') == '单一来源' and channel_dic['docchannel']['docchannel'] == '招标公告' and original_docchannel==52:
  5059. for l in prem['prem'].values():
  5060. for d in l['roleList']:
  5061. if d['role_name'] == "win_tenderer":
  5062. d['role_name'] = 'pre_win_tenderer'
  5063. def demand_to_prem(demand, prem):
  5064. if len(demand.get('data', [])) > len(prem):
  5065. i = 1
  5066. for d in demand.get('data', []):
  5067. d['demand_id'] = i
  5068. if d.get('project_name', '') != '' and d.get('budget', '') != '':
  5069. if d.get('project_name', '') not in prem:
  5070. prem[d.get('project_name', '')] = {
  5071. 'demand_id': i,
  5072. 'code': '',
  5073. 'name': d.get('project_name', ''),
  5074. 'roleList': [],
  5075. 'tendereeMoney': d.get('budget', ''),
  5076. 'tendereeMoneyUnit': ""
  5077. }
  5078. else:
  5079. prem[d.get('project_name', '')+'_%d'%i] = {
  5080. 'demand_id': i,
  5081. 'code': '',
  5082. 'name': d.get('project_name', ''),
  5083. 'roleList': [],
  5084. 'tendereeMoney': d.get('budget', ''),
  5085. 'tendereeMoneyUnit': ""
  5086. }
  5087. i += 1
  5088. if __name__=="__main__":
  5089. '''
  5090. conn = getConnection()
  5091. cursor = conn.cursor()
  5092. #sql = " select distinct A.doc_id from entity_mention A,test_predict_role B where A.entity_id=B.entity_id limit 200"
  5093. sql = " select B.doc_id,B.prem from articles_processed A, articles_validation B where A.id=B.doc_id "
  5094. result = []
  5095. cursor.execute(sql)
  5096. rows = cursor.fetchall()
  5097. count = 0
  5098. for row in rows:
  5099. count += 1
  5100. # print(count)
  5101. doc_id = row[0]
  5102. roleList = getPackageRoleMoney(doc_id)
  5103. result.append([doc_id,str(roleList),row[1]])
  5104. ''''''
  5105. with codecs.open("getAttribute.html","w",encoding="utf8") as f:
  5106. f.write('<html><head>\
  5107. <meta http-equiv="Content-Type"\
  5108. content="text/html; charset=UTF-8">\
  5109. </head>\
  5110. <body bgcolor="#FFFFFF">\
  5111. <table border="1">\
  5112. <tr>\
  5113. <td>doc_id</td>\
  5114. <td>角色</td>\
  5115. </tr>')
  5116. for item in result:
  5117. f.write("<tr>"+"<td>"+item[0]+"</td>"+"<td>"+item[1]+"</td>"+"<td>"+item[2]+"</td>"+"</tr>")
  5118. f.write("</table></body>")
  5119. '''