From 7eea236417d747fe644e143e9be9e86b475a2924 Mon Sep 17 00:00:00 2001 From: manoraga Date: Tue, 4 Aug 2026 17:43:00 +0300 Subject: [PATCH] =?UTF-8?q?=D0=BF=D0=B5=D1=80=D0=B5=D0=B4=20=D0=B2=D0=BD?= =?UTF-8?q?=D0=B5=D0=B4=D1=80=D0=B5=D0=BD=D0=B8=D0=B5=D0=BC=20API=20=D0=B8?= =?UTF-8?q?=20=D0=B2=D0=B5=D0=B1=20=D0=B8=D0=BD=D1=82=D0=B5=D1=80=D1=84?= =?UTF-8?q?=D0=B5=D0=B9=D1=81=D0=B0.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...alysis_and_Recommendations_04.08.2026.docx | Bin 0 -> 40310 bytes config.py | 12 +++ data/scud_orion_ai.db | Bin 516096 -> 610304 bytes modules/data_loader.py | 63 ++++++----- modules/database.py | 31 ++++-- modules/zup_extractor.py | 102 +++++++++--------- scripts/db_cli.py | 12 ++- test_zup_conn.py | 56 ++++++++++ update_kb.py | 45 ++++++++ zup_detective.py | 63 +++++++++++ zup_scanner.py | 60 +++++++++++ 11 files changed, 357 insertions(+), 87 deletions(-) create mode 100644 Project_Analysis_and_Recommendations_04.08.2026.docx create mode 100644 test_zup_conn.py create mode 100644 update_kb.py create mode 100644 zup_detective.py create mode 100644 zup_scanner.py diff --git a/Project_Analysis_and_Recommendations_04.08.2026.docx b/Project_Analysis_and_Recommendations_04.08.2026.docx new file mode 100644 index 0000000000000000000000000000000000000000..c3e1e4f1951388bf9c22a979044c5463dce5cb32 GIT binary patch literal 40310 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

R3 zZ@wSP8#;Bod^Y%f2gQSHw>~NOT)1oRb$oa{_}m1%AI`5ln-zcB+pD+eToB3^t4H6+ zD!VI?MFb|6+84bYOj}nj%-R=;J(;=jWTpjvVlewY)vTGpLzWLOzO`rGZ|IGF?Pkc{ z+Txj-EPblF+rKq@d-8H@sQZ(~b;rc?^zKvp_RxR+tMAVh^M>6s$+FT9e|5F3 zPV{G+KW%Orcs9n@7TvN-O~#KZ<swn2#l?XH$qeNLYB4e6 z_b)FyPks0Er}j@D*~w?VSIIHUdmlIihaaVbp_6MKzFxU9kbGD81p@fV)hGFx-|BP= z`(GWO%a86T+9PX4aBR!Z=HnJ7N$~5vY?fCR0drhGD1m|>#bW%2%n#(T|{jq-!G(YQU-cQJ-)g@_GHb=xRIP9HhV&5f<*@?kB{g7~+} zp+1J`h|q)i!zcUJ&KKvWVcoL091d54XxtK?9%zq);>DxlH=Vvv0(aVHGSFU={o+L% zJ=?tfycSwJxGFu64eT!;8vIq8x>J0Ey>VVCebFkm!z#52@G#T;k%>`uyg#Z9N%6e0 zDX?g8cHH8B)FCx*hOJYh(KqQm9`0(`G);3%XIvCFn_Yf2q2)MYaCyWRxA~S z)XJ5k9du=ifbc_P4Af+CQKKjEw2oFk+|(PLQLo2lS12cqBvSkC&#^p+%JUA28=MAxePgaY2wd$4=OY4xM*Bo4Q|Re6|0smk!u`cW^UCk$d;By5I4k!!@a zWuY}l)LWTP1{Q9wX(0dG`?7nRO9xH7Ef>%)moS^yz zI6-&;I1vjtQ6t_0Zuf5p+$E@Hptp3KZnE9aME|<_Gm+b*H85^b$tOy~C;VS1|C!)F zQU1>?Fxi^H?Nal9fpE&s+5qE1STqB{2L=Ja*#3*_Ka_rfoYEoL0+K-kl3D$etjE^o z%QmA}<0sAr2q)~^C(eH+_z%rB;tk*n+QgfHWXOPIpVHv19LlAh;U8{qqF;g!hz_*L zU#q1OI)Hq<7JTUh=$gmxL5I)iP}QcVsr8e0;qLV7pB#q&Ncm|8;4*oZ$4r+`?))qf zu!W7Z+S30xdc6!iILI37`-2jRBPHNA?z8E_>GFKZ-RkvmWHonc^}tp+yvOmS*mWEM zW87gE~my-BOr z8&_+$Yp{_(C17o%hwc0R(U@_C4C^`X&3(VAdDp}gwoAMFL+czL(Wm*V=@g#Ub>T~r zvGwK3trYLIwnv4*=E{@NIa_VV?hc=|bo?pbwe)DC%NX~|Yl6AA?N{0=f$(BTFoIt^ z=V(_~7@=~z9-JGP^ITX*k;eQvS*Y^H{MlK?o@WapF#0ZKz31j&^(0`2ug_*cBMLc? zjsadPM6sUN#+X4Sgbe--dhixG=yNt~g*s8OE-zpf#kR3U{>AEW3JN5=d_-=#QWj=} zXTRW9zg{A+Z1a|d+)9#UN_dCXoAGBl);RHU@Q2Uip1a}BgDh4Klt&axYUMeCH5u)QZ*>T43FlYrV?E`Ui=UWt1|JV z7#~#z(;;I2TTNh=U#?g6nl%(v?!LCDz2AB9R^DazLV*7$H{H zb_CAZVb$yD^)*I}KjXmXR_kqkZ>;XMK|q%sSGJ7)wPp2+g8`S$2Eq1Wfi*4q>vfmH zu-kU4kLOd%dbVNQPy2omo8j>67#3^-`dnIDw-&bKSp_g~H9-WI!#y-Rl%w(lipcO^PvP8oIIPA$8-d(!%B!@FViL8G26 z)Vgc)=D0;&+kAr`>bI}s+jRQ&EGoaT1XvxRgV@I*t{H=N^E@*phx6x`!;#r0eO+K( z{@P=;v0dKEH0h;^1UzsgPrR=EC{yA?2ep1nFPnBBp`zPVWZMQsDZ~2-x2v<2q_l`h zoojPF7JXn>PHO++y`;YR>xN2ut`*gQWSgHxvVnm4UiB-^5PHJXMd^Ca*W}QaIf+> zKyxB+oS%L2iSpRC5S+8*5Nfb@WCi-9buqj78%AjMDk%2d=sGIF!-epw+D~e}<>QwLNf>!?*HO2r5GmFd5V@!70HmhVc|v|`@9+)RGvizr}dEM^rXx7S;a z5mcM|jPa;!WhJ9zrQ_dgU(S|M`JT=W6?bUGL~EbTy3gHNzNsODb2*(HAlJ7wj5!<6 z-G{i%x3-rZzCB^@nRY1_vlmX8@-$kW>TxeNj4~{gLXK?-R=*ov*K8z4Y%-jjAVcro zsNe-C$?08U5V*EFvvS$J+yC-EVd=7Q8Eq1n`mU0s4j;N|=Xn2f@B2vGjq)&_TStm~ zortb`=~L+z52X|FwA@7zT zP9Xa%iFl87xNSLn*at0#ireAyn?0)c`_vb*aFPDTFR=yj7SsZW>({%zI|2`(%xyis z7g0A#x&2=DidN5^JR6zgihbuNw}8>tPoAy1_aF&eC4RghwqHU^ z(x`A?PE?OGc#;?t8H@?9-U2yq&Zw)tRyZdVjJgV>D(OwsQS~>t`sRtML+Sj@Z0`R68x~P{jg@>M!+8_L5_170?TFr!b=)vn>2*bpM3m)C3_V94s z-x(^sw5(lUz{LNg!H>ws_px$C7(AV?dN~#`T7};h2}0XS?X>T*^6+ZIXCee2J|J-D zFTyNmRJwM0ba7R~&470#ZVDPu&~@)O$IHO?P`g}QZ!@@`XU(XA_Z)%$hJ0-d?d}Ij z<(=UJrX5h+YMG6J2E}}DTED!KQv3$lknCsojX9g1_Vk4|S*UeG!;;qoO)Q3(i z9s&H}s;0*|B~iP*!EjQ~ngOEE%J+{x!ec<2($>M+s#I^)AA`&26t$$i%McclwCc{= zOIWj9O^**WDC7R0{xTvkn%0HN=kT-zNp@C#y-iF|%SFo-+)n+R;V>0#Ba7SX8oaPz zmvR<9C?TFIafgLCmy-*Q-pe$eYX#kxa7WsVbM1^*+U$0=+nb6aYB-Ik?V#f&Wa~Kk zHP*0wohNM7(SRjt^)xk;)sJHOI%}OUq1H3zWCLOU6cO*}bF6373OKKGd2-l!o^Q$q z5@O1YKZ|X2?tCY>gj>gP7_lr!Hgwg;Y7FuOg>8xwYTmtr-zv1D*Xy^Q+VFSxxK3AUc`oqb-ujpNd8R}S>S#?D#sAh15Tx@tmgVw&FXec%pLIv+HED@y z>c2QPA^d^3gyS-9RFbLXsfpC;>jZ{a8zNlK(7iq7jO?gMttkiO#3mpolrJY0$~U^k zin%h?{}|O-EJaE^+BB#1=ESt})_3%_X4@9CB1`>QWNS;p-|hDuRC;f5d%SUPcb93( z@?;O)UJqzVxdr)EXTg}%Je|!07n9K(vwU({UP#4anS~y6NO;lQDLV?e0&`)7CM?teqm(z)&tBInU z=9O%Y$CZmS#Vpr(+{aTt$J39?=mg(z@e>%64pd}OyIi&>>wbx{&Nju<>Q*1{zKe?V zd+FHGC_+I%gxPjno{#h)q?;o?>QF++H&sj-sgX@os_nPbL^SnnrUi=&~Jc+ zrLw)aT3a+qN^#+=zRWa1N$BAc;eJn^zb3$DP(7NNf3?L<50$aVmT8URID4bF_WV<$ z^_C95`SOx7=*zxFUmHn6?tG>sCPPf160L+*pNGf69T86 zp~gZLA|N0U7RCY8`5Cx9%C?oU<;qF?3wcH$s0Cq1>;pzMzmCZsAVC{}5$8}SYMF3T z5inFTF(l#<-H`bFkVI6Ir;|2VD0+O#@O14*MB*A9l$zo)9gDD@%sLk>@FABndScO; zT~zT!-3k35C`4i)yc&DD6V))Fo*7tJrhC?K5e{Pvr%{3n`LO>Ci3t3!kY_7qfRN7T ze}&|J2wA8#`zK^31R}9uSP#5hPqy;dPa+UUODZcg%r&a}C`6$Ml~e{%{b|%8SQ`Tf z5>fqYl0f*C_GBk&Q6PPDh>%>5Qwb$bfZDQRn@e+7VKBj5^z?bk&{~jv>kud)hZmtL z9?|XV5U9FmK4Gw-AgITP&hZJmxFwUrX2}=idhJ5@Qbhk2;NHQ&c_3jhD5RA(hH`UfqNKVEux4}^7X?>}^be|s3`WVjudoIVz2SWkDPWB+G zDD-n?iY7!`(g<#vh5->a6YRH%fRSt>_CgVXpooC!GGpv=o9o`H1=a^4TAz50B^U-o1j54#e2G=yIasDsKW2pl zl{VA*-2x5sX_-9;ikmr@%L++@C73BtJGB=IN#k`S7xbZuEDHt+2s7QEs3eCBKi-;z;f$f zY0Z@)0{i7*VH%!V;EL;VwtQxo&;L2Y^se_W%nzIiqBh1GPr%OL2MYr7)}BV+*n4!50o+OgqH`wG5kKD z!(d=)-m8B9e!rYvB!YJu_?O|q{*>vpN$tMS+vGLRdIbk=){X|&t`^qL4#~05U>T^A z+wI?a{@estdTAs$XvmCT6Ne+uUn3W&Mw*F#%;O}f(zT|vJ`uhRe>Il6PmPy)te+(>F3}K|9C#M}^U>hB;c`;(UeXrh9GPC^s%+=vDF}XP*=k`|V`KFZV zRv|wckirL3z15)`w4C!$Lvwg<#^>VpHsto^&y%AdeJazEgp;^XRBbG8I~CSqTV2an zfG3z*^LL%Z&V9x*fayH`!$8M-g$#W47G||Cwt}h9588{bHj2s_UGZFLbb6z?10mJM z3S(y}jZoDDy1pd3-LHw}UU3!%X%;?tOd(xp)YwNd7X4?oegBTqwoEXzLz$Y0( z`+4$A%kF7733`rB**%_(U@%^pIb%Eq&%Kh%n{ui#N{yI1+1$9eTzZ9x-|Qwlj#SA0rJd%vg_6gg8N%y4w2c z45XYDYj+pTD$3$GKo(|t4+NSPVh(|dNtSNkr6sOOh@P+cz#L|ZI7yg(?--0>8@)!c>36~N~+J_IXKxCTp3MrGbyl83hoND0Las9?9 z)5__|p|Q#W?VQxo#`?we>}SMG)d;UsC7VJ+zp>_4zj-ysRqLry=_A*E_x3ivE0A%4 zP;YE6Wowbf__1o!IFcPHKRkD`)t0%YheK zVP=QD8Hnb&TBf9ms&}&{B67(kCR|}A@-k$=m^Hf zY&97q%k9X#2)qfnVFzJV)DBvr84%7Hp6lzeZrDUI=PH|4;#uQBoyICa9mQCsbeIFHqbm>|b_);+4ly zoiN`g(%?-FWuaIQO(p99>(1heI0THvTNdI53-T4+c;{TT?K7joTJ!M5tfL$}z#2#aXNNw^TN(SLgbYcgdP#)fDmc_SC$ zh$m8~IUa9CIv%3&iCQa8OIMB7PW@ek@Cc2eQ#U#PVqalLctymwjXR$7=4 zVQjdFmQocvC2HG>YBYWtptT`|$^o3qOoi})w5{T4kYQ|@P;_Wk1IT0ALNx94OJQ(W z1K43~T7HW$N*vl1N>q>mrMle5h*p@?{%mNfZFEbl0{`Z!WHy{vQ4d-RVF)J`MPOfL zBneKW=@11X1`va!MZFZ3BwQPy=Au)9gv0!)r~#;)puna{qd<8CMy1nfhG>bgtGl-7 zLA`h|9X$lt5Dqd(3)za3dVnhtZI^IKu!5*mp5l768LRQic$7{0OsHZ<)ZBdvJC9gb zZDy=0g3V9_0uVe3UH{%_VG`X+RhrSTECrr>06RolUv6>CCW37e0dxQx9;%Ua$!>w& znbIml7+{)+vijG|Gfd^iugTvEC}{_<<%5#L*$fXTDsz)`FsuebU=860u<3eEhf6Z( zmP$|&hEy5woWj^5b(@Pe9sW02Y*efFE*(BKb${t_WF-!8}RGA{p_R^;LdcWs}f0kd= zYRe*{Dq`Utl)2%n=m8JF~V0~3hHOdVaR~~f745{b(16J=(4JZkm%QUj0_!Q8n>S_b2O&JQPI59qJ zYTf5w83L5Szo|}0B^9bLQL3m&4*oZ4A@qNv62ga&5iHb@r^2cJW5Kr?fCX`1&_6Ah zY!6R(BD`CP*e>xvO7u`y8q8d152uDO+5DQiR-Z8IPO?MI1^)d7?NZNU># zCT;-A3HcKLgEBG5e^cg6oi_chJD9G|t|%52L#lwr#c!7P7;ZAh%_16YXv9S?L6Dh_ zPSNmcJzk^!zC>0+?YpPkq1xasggmy$i)jYwa3M)&=@6;34?eq3U}g(fe7Y|b#mBJ{ zyj!@Yq%CNJZbPc1){~YWVSqk^ExEp~SNOXn7y}WNW5}xNeV59w*!%Yc!pF4(usWX1 zh_f2pxHQNm%6U!_>bF@SU_u-M0U2d#nq%hIv=iL12`5BL!i7YNg(!;tTvpG-GF6hf zHdO}`{|A#gsxPbzDg2r%e&$`q{Gf=|+;MMHlB?vAS*dTe5J5Ol9M8PeP#nU7XSG*w zI}qD()u?!)1@Rmc)=4(!qXN>@n|2BI?oS~(SLLAf!Aj>*LH)Pka3(_O21I=*dc8GzkVRE`}9}LxY3Qg ziG6rzNMw2Uxe>sN1{u}eI*3v12o3d2n<}=_r_vA@fKpObfKquye$ZGu?l`(lNoX@v z1?f#K!+Q);TuIK9JdSmy&>+x403|NBIocQ^9?{-?P;^PohlMl3B)gW;mX4tQ=|9k2 zXI4I_o+LYVsv7o`G!=q<{y{3IdkPR;DN^7`+NvEOMu;hPqFO0&cA~#hV(moJQ{wFg z;Gm>AGa(3fobtmX;*g_J2AOy;2TmD2ouU`9Z7~ASm-G*scl<3{z!<%f&76RsLAbM` zA`zk5w?n>ngA6aQr4DKOrCO+@nv78#y2^TwF!vmtjiVyvVGlhk1cs)0V~ zi$tz>+BZ&+$?=0eBzD5|FQL;wq?z)n>MTlqKl)Z;ir3%30cK5^9K*Rz5bXd_#oBqm zXWO9zwrrY)q>Z&ZFSV7*_!62DIWEKb>Xk!?A%FXKSmII<%{bJ*!g8nWm0l&$Qv3Kb zNhT_znd_7}lnK5t2P=c8r<6xfe-~_krOpAC z1XY$_-#^GmVZ%ZhIyB>-xIn3sF@{HExY4+rsHL_=Y4aD9>>Kl3H^*F)yyRZSjqpNW zls!Uo;jkt}W`fq0X-q_&Y7aO--U?{gTGUOxxerPefGZVj98jbc%h6giMx^h>rOkF$ zNqJy!t7$kBYuLfovn+v?RywjIBOX~RXmZn})`m=Iz|77qQLPO)l>u?@^yvrO{Pfg2 zp^^kQ{%ZaEG>p9*B`==%d(4yX(I^<7A4T9DL29+8P&LCdctYgswj5x@IA2EuWQy#ilD&NGES0;0UHuUrELy{B9mw{C<900Ig89fW z+EAVWf;Md5-vyKt>N=bZ3r}-IVFG?RMDO}wt?3X#jD}{xWRgG;kD$8@ejn zLN4krBHV#qMqE39Xa6CE#Q(7$>TkycU-QbZAt}-apAy}Ug1JAwg8l6nrchOfK6_5R z06pIIZ3%T0lq32z}0NKjN)gO#75=cBjL;tPC%l|Pj=HE(Y zA4LF-UQ)T7)4u_N1w>wZp&Za+K40Owy?yY%{zNkP%ndH9=}$S=kT`aL+}K4ZG6Kj^ zgn2`RKdg^eaMQ5i*hT1J+eI*)U;qHNtoS@xG_KVL!k?_R_gfrr_PfP$ZOCU5DJ1Wk zt4BLwp||_FWoDQJ_WK5FHtD_BPQw+MCbf{oPjTxtropmZkQc?@d3-NvjRWs7Cu9yH zA&0=V!mAHwn#Oy|HJ+HYc|8IQFfc0SFXb_ z{$GLnOY~}b7%efyHM<}0ls9XJ1o*pSU7hK+Df^Y029zFlM;Z0iD?-X))v>DTXzeOC zLh+`fydOMM?2@teRxHd`?VbKwx=C*Q`STOz|g7 z@!v2y^2JZe<9MIfX=ffKZEhf7jvD>_F06?e-ECYP*KGAhtBGcjTOA;l`AjziY!cd$Iz@prE|Gq79YkQ zi_5C{bqMrrR#ywc9o99L*l>AAsk~d9;+3OQ-Yzh`|=O zGVokG0p^dH(12tf`fyFgolQfYYe1mD+NHOju{QgIb581DOL9&=z!sLwduc!lbmGa9 zeW6-2Iv@|#Uq`;VQ=Y};W~Sz4CN5yos>oAH z!wGXyeKXH=P^M&wC4tkmaZgc_he`TysB8~jGD$>W)IBv8Bhm~}sKmq>Ol zU|2S*C`-#Vi!v1xmxCOXTV^;93Kg|TB(PuCZ|IX|N%St5m!C@j)kSdxKy{JX1Bw;l zpipm23U$b5VsrVnF*i38iiTo6BA#yneN0L{5yk9$dgvSqs~!qBF=5<7B`M(_PV6im z4Srmd6b`Xg6a^ArfM&C2`w{xXvRI-9YrZSWn-s8gOu@q+8W{sFj4G`Mzj6VLOS6y@9UGr`_R z2x_4D>X8Zmn+1AO0>GIA(SJMRfDD<3QRA3bhnWmFCWSj;#?s`_=RrzIVNFFLQ0el5 z-MVl0qfInkE)(WQkQ%Z7xTRF7iqVQ_QaiU3?6qJ~9FOB_1|N&}vX@P^tEO8B?m?GS zzPcCCMVIM`;_XsglMv&!J+-?SxpH&BW(n!n;Ay2N`A0w(No!V%DjAKl51Y?p%pd=6 z?~uv{d6~hm^D;rseusG6?LT)q=R+5YvbxC@&_?tcj8TLvV@`Wz=E^%VGbH+!1GlYNRw?DOLq< ze<3E{ZlE)7MNqy#lNWXs1pf9f0`A-O`-#NRy#Ej&KY-vu!y2_`&GG~hQ;;Ps4mKN! zo6ndNAuJ{=mKGP1cMiJWvr~?j3T@2O5R#WL_!ckf_ar$PKi{U>uIV5hXNIxgU`I4! zL2#QLkQv^JW#r0e6is?NZuS?cvReed%z#X4EO4$xA^9v-^ZiZ5?}WuWwBd#+e;cw2 z`^hH>fbf?gMaiH5K2pmWK`bu3QE4+Pq7GVseB$bqqJejSaVRqexFm5i%6KC!omI<@ ziZfzyBRL-*;4~p&>6iKL-R@CA^fOdup|#`-eR_9nY(yP-`sMl*1uXG}!&^tn#Oy2( zOL891D**!@psf8KE*rK$tIV60bFX8rHK%)-O&$4FQz47eSFi^icAU-1PT@qpjT@`* zgVPLJ%tv`cRA~*gbVhWlQ2yj+qEuE7&KHaTj)!0lX^NSeEG~$ICtgFdSqN9w7L-bp zn9q^Iyex39wMkublZ1b@kkm7*_7Ji0BLhcNjCUoP#G$UH^bi9u#2$jhq|MrDvc$v- z^pPW532#pL;xT~{MB(kjcRY3rf@IK=&K?Af*5_$HHRI2wgR62$s(&KB`? zwDH7p$Qs5w!ZjmZHIgTZs7>`FGcoIaZ-z8yy}iV6fYrw}_g8Yb=@s<+#hT{S+cfui zVf(Q@zSa7R0h&QT&^1%0DaVPaZm|5t0C#i5Ib1~IB%T3JMCSBSV7z*_CIURVg(QX6 zII#qv8N6NvmNB9JAx*4l7Jy`o2-zP$ZKmNk2!URD9S5ahth1X(8&N393x=-Qf=FA( zK >8hAm={JXz~Gz0hFgbH~w-BcdhNhZDld7H*r-z7c#A(q&oG)!^R{||Lo0iWtb z5dXKj@2~)MoKT&9Z>MPg1~cA&c8qf>{u{^!9SibyHBzqiU!<66Z*F`OvR*&_$G+eN z0^)kzpg=%J(EqWEuA_;QlZB1hU-PUQ)ixY{aiVr@73;U`m_j$%%kEK~kk)Lo>&k_(q)$PdF1FbgC~MMKSg zJG)%`{ndb#F*z)pkxHMR+YigT?fqhppG}|6G7Z=Rk^JDmtEExxXTlGv=AIv|u`pl( zR;66EkEI+a@^_AvLqGS!HMA7PFAR{ug_zIRN1keyh%dfHa?v%iI#_2(Q7>C*3IExn zyW_IgPWVY{1>eVxM1hTYNEp1TY|_E;uGdM_axd?4g;u*aady$a9qI5#S-l$lsPG6j zF_{cA5Mv-sAvT=f?lrJrc?AQrou<}4_|RY`^LYY}hawK$BR81**)9{DVZJ>oHXRlA zP-Mc?Eh_SvoQ&Xn9#7~995X|SCzBH>BJOM*`3n>dcqEqxybJ_b*2R1jId0kk8DOCT zD`l1!(eQQYgN>>D+~9G#*}{fgM=|NUrr18q(GFd*k7O5r+QpTDrM_4^Udt7w6@j_A zC2TDTxTK9z_Sm;;LHN2R3CYc9Xm0c%qgvaN?s&8o5KFn~?wC9UxTzHgs29&FUf9tN5rP}9p3=0{ch z$>I$vb5#8KsWAix$IeZ^R7Q?jXA4|BDSxnW#J**^bLR2I=NLMz^vvF5yJI&uH z*=-6-Albhmjxq3Pbr}XZu!18p>h*|#wI$%d&n6ILjkWeti2q)ROkY_h5Gu&`#ld3(D|(bdXOM zp%fS)yCY-#^8rw`L?6;{at|#CEf&Wg6ha1zEmsA=Gwr&lijdu0l7AhA5$U zprX*z&tVcT)(UmYz@OoT!=eU=4NIBpq>d234RVcQMdsq-t!UuR;vgBGQrH9uWNpaj z+Y^`QTA)?ER#D>5MO`;jaz;z{v5eIN<1D#f3P~W*O^(gRG_B{;9YY=|fhcthAKOkt znfRvNyb~BF-br$X@Z#57Hz?b8&@PP}Ct_)K%A5fMj${yFED^jqyFWXsjZEZs)6Bmlg~Y) zHj;a7elg+>U3rI7resQgPiRC%q8CF41VX{BL0^lz5Nw@$nd12#!+236)qZCk z>v2IdK?)oIh296)!g<|E2Q3o1zl_|lFA5W8w1z#!VV{{+ zfc)BoP$QBJZzk+CEdr>e&Jo8wECNadJ64@o5_5;Ub1R9IIXa-6DQa=d+9PaDb;N*H zOfZpI+f?arnDM|0=lBAX30pExw8YAkUyFhQ3rvIqh+HbYyx7@JdDR6!lE=jtlt3M5(QMz(R4Yj(;%MNuajPP!X(34s(7* zv$16-3heD$N9>cXKern&@2!aG{@33i#oPD4&Y_$=I^n9TO22XNw)CGBg{yl&v*Z}L zJ2T;=imBOa-HdY5x#!*5fs~AlYO8fPAM|`P$+XEHJUQ7}o9{)kiGuzBL*#2_YUj)+xA-b__A@GMZX}Ds zyoT01%SLJj-h8AR=9l5SBhyD?OSj%ccMiXeEbNch=^JunsUH<%IE?N*u^SdQ$pTHf z+p79@`@PAx{K+cA6*arI;2;c>wO0q;Kc<{tQ@Y5{iaq42#LK*|asK<3OcWw+8G--; zYNrMQLi^V(>11wVZNl)^k?F6U%(Uce*Vr+;{-`6i?Jqp9Ifu82ov&Oh6~Q4li^MdD zYJaCxB0M4Og1fNq@iW+{>4!OQ>aVF3{Bl0`mTrUB1b?iDNwpeIspN1tDEEsDa+vsu z*Q;Ak`S;>kC_eB@n7!=VgVuqvI~?Iw5&XmOMWbin``{AxHpnwP>4L;XBh{|eatuK^I#MV?E?XGAfouC#`Rh+%_Jd35{D{En=dvfF-c!q@-d&23f)5oyMaaHY5|0ijo!TH&2|f z&&boYLW;5#=BYW(aK56*@rle+*2tL^tXZdePc+}ezT9BK63wZ1FLPl#m z5u7JPX3XC=Ws;GpYfzr8E?AJvbg?InE@417&W9vWUP?J@*nmb|fi%R_sZn0@FJXzmPe3dz7f*w+0KDZ|#jMsA(9z)aCuOx0W*9TQ0$%%lCY+xHnvl|Mm^6 z8~V*2`Tg*P;oaw%>hbK!)i&F!5ojc#XUq5byjidNn;)Xoz*%+9+x711nJxdvZ779U z3minK)H;x7SRl_a(7B=lwO#`mb{$zBD8??SQ$K;@u?RSQz- zRR~v#@-_I&j%qxTql4df!`fovH0p#m`i+)xBP~t)U>wnuIzwbfq4Eb@%7{!oGEQAr z1k}23joW3`z9+rOH^nV)@xS$OZ-g`$7}OQNtO*OYl{-^8{tlg8VBZ3iG0G3z|7{lD6}&ZwrAE*j}gIto%mfgruNsDP+|QWfdF z8A|9u=|pNMkzS<>A|OGOfb?dR-lPaf5DZ0ndw?SFUH#sBKC;Y@+?82(@5!0FX3p8? ztUCjrWVcp%fKASuG;>3kWxo5`J^pmi;R-%Rtl*JQv(rR!tWgw)6e}%}Dwf~qO}!{h zp(cwEraj&H)!V1sd1km=kw8Jq=R0+ahs>#|v}a{@_S7KfnN5eIMn}5l!}ANa1NCN8 zlN)LUhlfY`i&R&)982y*vFfPD-Tsp9hu>ed{K|kTY}3sCj?d6ZRTt2Dea?~pH6tVb zxwsbTw<}rwp0S3WSzHWt1J~Xgr@ag+dQkoJxp+z1z+P2BdBdfNwh*`HQ_-VxXW+A; zq171Nb6H`l_BML8FQVG>hUE;2mDAO*)}cYC71H;639bj;UIoR(}=iMwc z(-2u~j8?}KQr;}3T6FXDvr^fmF1|91zT=3=uu00Ee#~Mg{fvXOO0~GEuZFFa)MEFjq+e2BY-64%HE7-Kxz~(}I?>raDs7== z+zt46EOJiAzcp`b(7j8w?3MW{=Y(kStE|bj9T&MW&JHyhep?Dt3vE`CQu!*8t}qSz zdTKM+UPi-*^n1w$pjYVv#2}T!4W;V`CGQl{_-FfJ8hCxpmCq7ZMzYp3l3~@@9^A3( z*zFOYJPPWMuq4g!o(UD>OXBHJg5L|Mt=4i)ED%iH&qgG(V6YZ)h+bXtkGvDy}8!RHBWrWEKd>dOC|M$Tj*&M zq=IhoanEIXOMS!(@LAK>LtJ#UMJN;F@?o4)%-;G%C*6081+TxQUSx1q*qesE$PT+G zgv3N#7^e9a*r2Xw`z(mTLc8&8x4KOHH~VzRsnh3gQ_2leXsgdI*j$Of9+mSp)WzWT z6}l3s5jBc9KV#2WD6Qk$>1#ZQ?CaMr78Y3VekfU)vs+Mq^>IML*+pTLEpkSgP0BFM z_OUTMW3EK-KJ7HGm=!-+2G3)=OT08(**9&(BC0KGb<(N^iE>j7=Rfe-ZiEF0(xz=V zu3$HQ@7EpqrhEozEah<_~x2`5E%5(6_!%kR>)G7TO%+kjQcTqH% zy!C3iNX`^rc*Ps4Cw87;BjW^iDR#|`Gy?YU19owpuY2<{CI|@cFaS z6vU$Yj)&|L^kcAV3U{?fm5{3V(y7AlYfrDXI@Q`aY)0LlOh`t?+^ z<11Z5#hGtDY--z@?UcwPabQNOg9MyMZku!ZAoyTBlQ&SMNB&w68Qb>{(eSmA%N$B` zVXjs$1_b#B!Mqgr$}ZTQ8f$D9$I5@k%b^Y(IVKLfl~>iI)o z&Lh+Qj>@vv(17Il+M-6ffwar4xpA(}9gIk`2LpGN_V?9*a2y&RRgS|Vk7*mCmw9)r z_OIY1{H0$NcaiUJr(WDAP-*c4kx|Y-P9_S7?*7#ruHG&-_MSji=4W)*Yc%CLE6>_E zU96m-YKDnQk|vR^Do{2sN2&5)wn1RlmrJ=F65^lMG*)eUgatkFht1>U8nq}Nc0gU7!gJM@6_vz=ko zXNlW-SgCLrxn5b`(;t$uRA07+yt8ztYz;gbDvw=#N`J-1b2@^2tDqI)h#ak&ZDNDB3zK|T*r z(2$c?SQ<^%B9-I2wHl!#Td#wd?%T;g_{(rmiU|Z~gkI_ts(_O8kv?{art-K&={6=T zq!75j+gqproXD*`sYE&rR+Ihocr~igz^s(%2d&}E;MdWi2iPlaRt2>5C^a4Dccfr3GOc*u<{96>jhjYOF5ITe zM{d5?GIBO2$G66P3Kqn$WZ+6D3Y&AFEe|(4z8+6u1@ztwlL;$2NX?YV9Un& zau2fkJJQRG%9#OIr`hT^G5XLS6lhvabOg#gTOp|>u;<_-i=~fYz%*wdWTEu&gX1P@ zEmazJ_8D68Q@R#rdp_oyaLm?>62x3sDk=NO)$a?ew&G=;Ez}Clc4oNciqs04Y8%A ztmDM9WZ6QI3Xh0eNm@*qVC#n;Qnj-azJvaXyb^F+$$Sr<<)J$m0=aurS&f{Ynwj<8 zMW;=fE6kR}o1dl%DRsjVEc;fb#t)mawx_)M75o=m3*Hx4whwGE`csP25Zn7)+o@{m zcEzCG<;!lbu*kwei#4@vGazRo2b!*e*TXg@b+Fo7)6~MTA<`WY(rKntXB9YD5TQ;p zbsk?S#F^=I&VM?t;OPZcK@gbKw}YpaJ)s7)aq6K_@+mlUz+yl+GGTfBM$QGBkdEHu zv9gBrEl7%(zO;#CP;e9eVigEYGeomnT^u8vDAAt8$opE!td*mNw@QQZ29 zdm9+@RDwRLLXK=5UXt&3%7(Ulia%AswxNCXl|D}{G9cKfTKB*XuXOXAQ%t-Lsa2#e zHqk`CA2+#FW*l;bsrJ3tq_fTLsFk^W3M6e6Mj_(*Mu!e?@Y(lSe3Hs#9|or}&zG8xu&adx~;s9?I@Cny6&>ro^_M)p79UalbL zTK*y@PGNDO>Yw6(A~W_uUZ|=0Cmyy8sM9_ zJtB_}p?`tG;??}juvIlu@%^FLSZWfAYn+Nx^kLmrMEuDiq!Kh2{Te<;f=ozus2nz> z9x4-0kc}xYqq>-){p=qoWuwYy(02^w**}D-pOHukXjq7+l1yWcR}oM6hF6q~V}6Q> z?_o<{RyWB-dq3dr6GU3wD>bD_{cAiS>#g7FELHPCOVR>5le10~dLc*0lU%ut_HD|C zq~+Oo@zDtg zgyPTDZKk${_bU#EC&CTO7f+-6wS64;!!Rjng86|aZBB|#N8_JtaWI_I(PpM7-2|U2 zQ%&drVzP5}R*{^k=E?HBB7PU}-s^mgW$f#5j~-SGvsa}0ku76Dr$Vvf6XLD9FjnVu zyXWd}rR>-|PuoWbEV5nQz$K1pps{q_8*J-KpPftUOm@EK8Zz8jIA7hgh@u= z84qOYs}XB+Z&aWkSeBz(3ZIk;4bLrg3B)ZFKM844379}nc(1YFrs0k2;!SLs{TLHg$+rXm1=SS7Y`YLDXl5^v>T!h>y2? z829P7Ri)ct1e4RbcNrrvLEIAl_OR7gAKh5SX=Tw?Ig6iXv-ArGnXHPAxm=wGxNF!$ zqt?i5sbT~?V;PKi+SxJ|xmaUrw@SH>tnG~+Z$JXO;)kV~S6Hcp+dYJ5d~&QDdx#gw zZSaw(ZjqtWmiVDK%anwg`|b0|l&PyzJXw)_!2aG$laYn@@1r@tA+xMH|YBgQou1LnK>v?rAjYe_>;Ri9xT>b%Ho)zZ=&5tkS z1m}BokEU4!*-w^LG=3YMyo~d$ab7^jDdM&}ae)U)hb!IfmVa?5_`TTknf~h57jQ7O zcL)uZ51yH=Xg2?T7^iex;4RT|I$6=d{3A&OUl@;{$=P;Uy+;WfUp&3rqtARbFN=ul zH%&^k9)IcUzZXyWtFxEB3?}HV7DPuwPp}@-HgT+HPaMv-1fl)P;VRDq4g2N} zY`6@6N%t&-?3_d1qd$HfOCfjLlyo&t5it}0OpjB5wBaP?<#&q`Qh*4x3&^?slpX(k z5I`FUWO^M)2HU&BE${id+k2V+jLrxNe8C#Z`@pR@AdgJ_4;r{4PQ3#t{vYH23hfDj z$OvjZN8px00LX9xxB#^L>w9e7Jbz`P3E?}FlV_I!IE(}YqCWu-23r1wTf4je>0dj% zCCbbMU>EcWJ5L7&;-Q<3#7yfaClH|G(w`CHdnh zkPla6c!>d_us$h>?gUdWAR2x#dBJ^Q_P@%NgkwOsq2xb!#3>i`6JUbvB?);5>!iPV zaDo5u{HKUQ2q!GO{D${D`WsGAh9P7iEJXZfI12fj;Y3-25Kovj{*6xv{~J%3Lnfpk z)Zf1;qGSK4#t8`sh3;+|xd^r6Z!Xiv|K&QVBnepvrPgm2&$z!w<%IAe k#1qDYzwxJ&{xii+Mu)l@q`(aNIja~z*1+^QPXGDqfAy$IU;qFB literal 0 HcmV?d00001 diff --git a/config.py b/config.py index ee4ae3a..cec1cec 100644 --- a/config.py +++ b/config.py @@ -23,6 +23,7 @@ if NOW.weekday() == 0: else: DATE_YESTERDAY = (NOW - timedelta(days=1)).strftime("%d.%m.%Y") +# --- Настройки LLM / Ollama --- OLLAMA_URL = "http://192.168.11.3:11434/api/generate" OLLAMA_MODEL = "qwen2.5:14b" MODEL_NAME = OLLAMA_MODEL @@ -30,6 +31,17 @@ MODEL_NAME = OLLAMA_MODEL KNOWLEDGE_BASE_PATH = os.path.join(DATA_DIR, "knowledge_base.json") EXCEPTIONS_PATH = os.path.join(BASE_DIR, "exceptions.json") +# --- Настройки подключения к MS SQL Server (1С:ЗУП 3.1) --- +ZUP_SQL_CONFIG = { + "driver": "{ODBC Driver 18 for SQL Server}", # или "{ODBC Driver 17 for SQL Server}" + "server": os.getenv("ZUP_SQL_SERVER", "ACCOUNT-01"), + "database": os.getenv("ZUP_SQL_DB", "ZUP30"), # Замените на точное имя базы ЗУП на ACCOUNT-01 + "user": os.getenv("ZUP_SQL_USER", "scud_reader"), # Логин SQL Server + "password": os.getenv("ZUP_SQL_PASS", "Rhfcysq90"), # Пароль SQL Server + "trust_server_certificate": "yes", # Доверять сертификату сервера + "encrypt": "no" # "yes", если на MS SQL включено обязательное SSL-шифрование +} + def find_dated_file(prefix, date_str, search_dirs=[ZUP_1C_DIR, SCUD_DIR, DATA_DIR, "."]): """ diff --git a/data/scud_orion_ai.db b/data/scud_orion_ai.db index f0d73855a80bf9d9fd4278fe9982e068e2e2df51..93cbca7ffd6daa2a97612bde9124a006cdc7d78b 100644 GIT binary patch delta 68218 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 TnvEyDos+50v(~$UCuaU1*N{<$ delta 46522 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 N1-o<+sq+|u{{!$eQqKSY diff --git a/modules/data_loader.py b/modules/data_loader.py index 75edaf4..3378002 100644 --- a/modules/data_loader.py +++ b/modules/data_loader.py @@ -5,6 +5,8 @@ from config import ( normalize_fio, clean_scud_fio_light, load_exceptions, DATE_TODAY, DATE_YESTERDAY, find_dated_file, ZUP_1C_DIR, SCUD_DIR ) +# Импортируем прямую SQL-выгрузку отсутствий из 1С +from modules.zup_extractor import fetch_zup_absences_from_sql warnings.filterwarnings('ignore', category=UserWarning, module='pandas') @@ -24,42 +26,51 @@ def is_excluded(fio, dept, pos, exceptions): def load_staff_data(date_str): """ - Загружает файл Штатного расписания 1С за конкретную дату. - Если файла за эту дату нет — возвращает None без подмены на старые даты. + Загружает файл Штатного расписания 1С за конкретную дату из папки 1c. """ filepath = find_dated_file("Штат", date_str) if not filepath: - return None + fallback_path = os.path.join(ZUP_1C_DIR, "штат.xlsx") + if os.path.exists(fallback_path): + filepath = fallback_path + else: + return None - df_raw = pd.read_excel(filepath, skiprows=8) - df_staff = df_raw.iloc[:, [1, 5, 12]].copy() - df_staff.columns = ['ФИО', 'Подразделение', 'Должность'] - df_staff = df_staff.dropna(subset=['ФИО']).reset_index(drop=True) - df_staff = df_staff[~df_staff['ФИО'].astype(str).str.contains('Всего|Организация|Сотрудник|ФИО', case=False, na=False)] - df_staff['fio_clean'] = df_staff['ФИО'].apply(normalize_fio) - return df_staff + try: + df_raw = pd.read_excel(filepath, skiprows=8) + + # Индексы столбцов в файле 1С: 1 — ФИО, 5 — Подразделение, 12 — Должность + df_staff = df_raw.iloc[:, [1, 5, 12]].copy() + df_staff.columns = ['ФИО', 'Подразделение', 'Должность'] + + df_staff = df_staff.dropna(subset=['ФИО']).reset_index(drop=True) + df_staff = df_staff[~df_staff['ФИО'].astype(str).str.contains('Всего|Организация|Сотрудник|ФИО', case=False, na=False)] + df_staff['fio_clean'] = df_staff['ФИО'].apply(normalize_fio) + return df_staff + except Exception as e: + print(f"[❌] Ошибка загрузки штата из {filepath}: {e}") + return None def load_absent_data(date_str): """ - Загружает файл Отсутствий сотрудников 1С за конкретную дату. - Если файла за эту дату нет — возвращает None без подмены на старые даты. + Загружает документально подтвержденные отсутствия сотрудников + НАПРЯМУЮ из базы MS SQL 1С:ЗУП за указанную дату. """ - filepath = find_dated_file("Отсутствия", date_str) - if not filepath: + try: + df_absent = fetch_zup_absences_from_sql(date_str) + + if df_absent is not None and not df_absent.empty: + df_absent = df_absent.dropna(subset=['ФИО', 'Вид_отсутствия']) + df_absent = df_absent[~df_absent['ФИО'].astype(str).str.contains('АО "ЛЕНМОРНИИПРОЕКТ"|Сотрудник', case=False, na=False)] + df_absent['fio_clean'] = df_absent['ФИО'].apply(normalize_fio) + return df_absent[['fio_clean', 'Вид_отсутствия']].dropna(subset=['fio_clean']) + else: + return None + except Exception as e: + print(f"[⚠️] Ошибка SQL-выгрузки отсутствий за {date_str}: {e}") return None - df_raw = pd.read_excel(filepath, skiprows=3) - df_absent = df_raw[1:].copy().reset_index(drop=True) - df_absent = df_absent.rename(columns={ - df_absent.columns[0]: 'ФИО', - df_absent.columns[2]: 'Вид_отсутствия' - }) - df_absent = df_absent[['ФИО', 'Вид_отсутствия']].dropna(subset=['ФИО', 'Вид_отсутствия']) - df_absent = df_absent[~df_absent['ФИО'].astype(str).str.contains('АО "ЛЕНМОРНИИПРОЕКТ"|Сотрудник', case=False, na=False)] - df_absent['fio_clean'] = df_absent['ФИО'].apply(normalize_fio) - return df_absent[['fio_clean', 'Вид_отсутствия']].dropna(subset=['fio_clean']) - def load_scud_data(target_date_type="today"): """Загружает файл СКУД за 'today' или 'yesterday'.""" @@ -100,7 +111,7 @@ def load_scud_data(target_date_type="today"): def load_all_data(): """ Загружает слитные датасеты за Сегодня и за Вчера. - Если файла 1С за Сегодня нет, соответствующие датасеты вернет как None. + Если данных за Сегодня нет, возвращает для них None. """ df_scud_today = load_scud_data(target_date_type="today") try: diff --git a/modules/database.py b/modules/database.py index d5abfe0..3a622e6 100644 --- a/modules/database.py +++ b/modules/database.py @@ -1,5 +1,6 @@ import os import sqlite3 +import json import pandas as pd from datetime import datetime from config import DATA_DIR @@ -94,21 +95,38 @@ def init_db(): conn.commit() - # Автоматически загружаем базовые правила компании + # Автоматически загружаем базовые правила и системный промпт sync_knowledge_base_to_db() def sync_knowledge_base_to_db(): """ - Автоматически мигрирует все правила из knowledge_base.json в таблицу ai_knowledge_base SQLite. + Автоматически мигрирует правила из knowledge_base.json и системный промпт в таблицу ai_knowledge_base SQLite. """ - kb_path = os.path.join(os.path.dirname(DATA_DIR), "knowledge_base.json") + system_ai_prompt = ( + "СИСТЕМНЫЙ ПРОМПТ ИИ (MATCHING & VERIFICATION):\n" + "Ты — экспертный ИИ-аудитор СКУД и кадрового учета 1С. Твоя задача — проводить интеллектуальный анализ аномалий " + "и сопоставление (Fuzzy Matching) нераспознанных ФИО из СКУД с эталонным Штатным расписанием 1С.\n\n" + "1. ЗАЩИТА ОТ ПОЛНЫХ ТЁЗОК (FULL NAME COLLISION):\n" + " - Если в эталонном штате 1С присутствуют два или более сотрудников с ОДИНАКОВЫМИ ФИО (полные тёзки), " + "ты ОБЯЗАН учитывать контекст: Подразделение и Должность.\n" + " - Ни в коем случае не объединяй записи разных людей! Если контекст не позволяет однозначно определить, кто именно из тёзок совершил проход, ПОМЕТЬ СЛУЧАЙ КАК НЕОДНОЗНАЧНЫЙ и НЕ делай автоматическую подмену.\n\n" + "2. ПРАВИЛА СОПОСТАВЛЕНИЯ (MATCHING RULES):\n" + " - Допускаются исправления мелких опечаток, перестановки порядка (Имя Фамилия -> Фамилия Имя), замена букв Е/Ё, И/Й.\n" + " - Учитывай сокращения инициалов (например, 'Иванов И.В.' -> 'Иванов Иван Васильевич').\n" + " - Если уверенность в совпадении меньше 85% — НЕ сопоставляй, оставляй запись как нераспознанную.\n\n" + "3. ФОРМАТ ВЫХОДНЫХ ДАННЫХ:\n" + " Верни строго JSON-объект без вводных слов и Markdown-разметки: {\"mappings\": [...], \"unmatched\": [...]}" + ) + rules_to_insert = [ + system_ai_prompt, "ГЛОБАЛЬНОЕ ПРАВИЛО 1: Любое физическое присутствие сотрудника по СКУД при наличии в 1С документа отсутствия (отпуск, больничный, уход за ребенком и др.), КРОМЕ командировок и служебных поездок — ЯВЛЯЕТСЯ СТРОГОЙ ИСТИННОЙ АНОМАЛИЕЙ.", "ГЛОБАЛЬНОЕ ПРАВИЛО 2: Документы отсутствий из 1С:ЗУП имеют 100% высший приоритет над статическим реестром удалёнщиков.", "ГЛОБАЛЬНОЕ ПРАВИЛО 3: Удалённые сотрудники имеют право беспрепятственно работать в офисе по СКУД в любое время (это не является аномалией)." ] + kb_path = os.path.join(os.path.dirname(DATA_DIR), "knowledge_base.json") if os.path.exists(kb_path): try: with open(kb_path, "r", encoding="utf-8") as f: @@ -124,11 +142,12 @@ def sync_knowledge_base_to_db(): cursor = conn.cursor() for rule in rules_to_insert: cursor.execute( - "INSERT OR IGNORE INTO ai_knowledge_base (rule_text) VALUES (?)", - (rule.strip(),) + "INSERT OR IGNORE INTO ai_knowledge_base (rule_text, added_by) VALUES (?, ?)", + (rule.strip(), "System_AI") ) conn.commit() - + + def save_scud_to_db(df_scud, date_str): """Оптимизированное сохранение логов СКУД за дату.""" if df_scud.empty: diff --git a/modules/zup_extractor.py b/modules/zup_extractor.py index 1aa9ff5..f765f7a 100644 --- a/modules/zup_extractor.py +++ b/modules/zup_extractor.py @@ -1,40 +1,39 @@ import os import logging -from datetime import date +from datetime import date, datetime import pyodbc import pandas as pd -from config import DATA_DIR, normalize_fio +from config import DATA_DIR, normalize_fio, ZUP_SQL_CONFIG logger = logging.getLogger(__name__) -# Конфигурация MS SQL Server 1С:ЗУП 3.1 -ZUP_SQL_CONFIG = { - "driver": "{ODBC Driver 18 for SQL Server}", - "server": os.getenv("ZUP_MS_SQL_SERVER", "192.168.1.10"), # Укажите IP MS SQL 1С - "database": os.getenv("ZUP_MS_SQL_DB", "zup_db"), - "user": os.getenv("ZUP_MS_SQL_USER", "sa"), - "password": os.getenv("ZUP_MS_SQL_PASS", "your_password"), -} - def get_zup_connection_string() -> str: - """Формирует строку подключения pyodbc к MS SQL Server.""" + """Формирует строку подключения pyodbc к MS SQL Server из config.py.""" return ( f"DRIVER={ZUP_SQL_CONFIG['driver']};" f"SERVER={ZUP_SQL_CONFIG['server']};" f"DATABASE={ZUP_SQL_CONFIG['database']};" f"UID={ZUP_SQL_CONFIG['user']};" f"PWD={ZUP_SQL_CONFIG['password']};" - f"TrustServerCertificate=yes;" - f"Encrypt=no;" + f"TrustServerCertificate={ZUP_SQL_CONFIG.get('trust_server_certificate', 'yes')};" + f"Encrypt={ZUP_SQL_CONFIG.get('encrypt', 'no')};" ) -def fetch_zup_absences_from_sql(target_date: date) -> pd.DataFrame: +def fetch_zup_absences_from_sql(target_date) -> pd.DataFrame: """ Извлекает оперативные отсутствия и действующие декреты из MS SQL 1С:ЗУП 3.1 - на указанную дату. + на указанную дату (принимает как datetime.date, так и строку 'DD.MM.YYYY' / 'DD_MM_YYYY'). """ + if isinstance(target_date, str): + clean_date_str = target_date.replace('_', '.') + try: + target_date = datetime.strptime(clean_date_str, "%d.%m.%Y").date() + except ValueError: + logger.error(f"[❌] Неверный формат даты для SQL-запроса: {target_date}. Ожидался DD.MM.YYYY") + return pd.DataFrame() + query = """ DECLARE @TargetDate DATE = ?; @@ -86,17 +85,21 @@ def fetch_zup_absences_from_sql(target_date: date) -> pd.DataFrame: ORDER BY [ФИО] ASC; """ - conn_str = get_zup_connection_string() - with pyodbc.connect(conn_str) as conn: - df = pd.read_sql(query, conn, params=[target_date]) - - if not df.empty: - df['fio_clean'] = df['ФИО'].apply(normalize_fio) - return df + try: + conn_str = get_zup_connection_string() + with pyodbc.connect(conn_str, timeout=5) as conn: + df = pd.read_sql(query, conn, params=[target_date]) + + if not df.empty: + df['fio_clean'] = df['ФИО'].apply(normalize_fio) + return df + except Exception as e: + logger.error(f"[❌] Ошибка SQL-выгрузки отсутствий за {target_date}: {e}") + return pd.DataFrame() def fetch_zup_staff_from_sql() -> pd.DataFrame: - """Извлекает весь актуальный штат из MS SQL 1С:ЗУП.""" + """Резервная выгрузка штата из MS SQL.""" query = """ SELECT DISTINCT LTRIM(RTRIM(ref_emp._Description)) AS [ФИО], @@ -107,53 +110,48 @@ def fetch_zup_staff_from_sql() -> pd.DataFrame: AND ref_emp._Marked = 0x00 ORDER BY [ФИО] ASC; """ - conn_str = get_zup_connection_string() - with pyodbc.connect(conn_str) as conn: - df = pd.read_sql(query, conn) - - if not df.empty: - df['fio_clean'] = df['ФИО'].apply(normalize_fio) - return df - - -def sync_zup_to_excel(target_date: date) -> bool: - """ - Извлекает данные из MS SQL и автоматически создает локальные Excel-файлы 1С: - data/1c/Штат_DD_MM_YYYY.xlsx - data/1c/Отсутствия_DD_MM_YYYY.xlsx - """ try: - date_str_file = target_date.strftime("%d_%m_%Y") + conn_str = get_zup_connection_string() + with pyodbc.connect(conn_str, timeout=5) as conn: + df = pd.read_sql(query, conn) + + if not df.empty: + df['fio_clean'] = df['ФИО'].apply(normalize_fio) + return df + except Exception as e: + logger.error(f"[❌] Ошибка выгрузки штата из MS SQL: {e}") + return pd.DataFrame() + + +def sync_zup_to_excel(target_date) -> bool: + """Создает дамп в Excel при необходимости.""" + try: + if isinstance(target_date, str): + clean_date_str = target_date.replace('_', '.') + target_date_obj = datetime.strptime(clean_date_str, "%d.%m.%Y").date() + else: + target_date_obj = target_date + + date_str_file = target_date_obj.strftime("%d_%m_%Y") c_1c_dir = os.path.join(DATA_DIR, "1c") os.makedirs(c_1c_dir, exist_ok=True) df_staff = fetch_zup_staff_from_sql() - df_absences = fetch_zup_absences_from_sql(target_date) + df_absences = fetch_zup_absences_from_sql(target_date_obj) - logger.info(f"[1С Direct SQL] Выгрузка за {target_date.strftime('%d.%m.%Y')}: Штат ({len(df_staff)} чел.), Отсутствия ({len(df_absences)} чел.)") - - # Сохранение в формате, который ожидает data_loader.py staff_excel_path = os.path.join(c_1c_dir, f"Штат_{date_str_file}.xlsx") absences_excel_path = os.path.join(c_1c_dir, f"Отсутствия_{date_str_file}.xlsx") - # Формируем структуру Excel с нужным количеством пропущенных строк (skiprows) with pd.ExcelWriter(staff_excel_path, engine='openpyxl') as writer: - # Пустой заголовок (8 строк) для эмуляции отчета 1С dummy_headers = pd.DataFrame([[""] * 13] * 8) dummy_headers.to_excel(writer, index=False, header=False) - - # Данные df_staff[['ФИО', 'Подразделение', 'Должность']].to_excel(writer, startrow=8, index=False) with pd.ExcelWriter(absences_excel_path, engine='openpyxl') as writer: - # Пустой заголовок (3 строки) для эмуляции отчета 1С dummy_headers = pd.DataFrame([[""] * 3] * 3) dummy_headers.to_excel(writer, index=False, header=False) - - # Данные df_absences[['ФИО', 'Вид_отсутствия']].to_excel(writer, startrow=3, index=False) - logger.info(f"[✓] Успешно созданы файлы 1С за {target_date.strftime('%d.%m.%Y')}: {staff_excel_path}, {absences_excel_path}") return True except Exception as e: diff --git a/scripts/db_cli.py b/scripts/db_cli.py index 377a8ac..63f2884 100644 --- a/scripts/db_cli.py +++ b/scripts/db_cli.py @@ -76,10 +76,16 @@ if __name__ == "__main__": print(df.to_string(index=False) if not df.empty else "Аномалий в базе пока нет.") elif cmd == "rules": - df = query_db("SELECT * FROM ai_knowledge_base ORDER BY id ASC") - if df is not None: + df = query_db("SELECT id, added_by, created_at, rule_text FROM ai_knowledge_base ORDER BY id ASC") + if df is not None and not df.empty: print("\n🧠 ПРАВИЛА БАЗЫ ЗНАНИЙ ИИ (ОБУЧЕНИЕ):") - print(df.to_string(index=False) if not df.empty else "База знаний пуста.") + print("=" * 80) + for _, row in df.iterrows(): + print(f"📌 [ID: {row['id']}] | Добавил: {row['added_by']} | Дата: {row['created_at']}") + print(f"{row['rule_text']}") + print("-" * 80) + else: + print("\n🧠 База знаний пуста.") elif cmd == "scud" and len(sys.argv) > 2: date_str = sys.argv[2] diff --git a/test_zup_conn.py b/test_zup_conn.py new file mode 100644 index 0000000..1039635 --- /dev/null +++ b/test_zup_conn.py @@ -0,0 +1,56 @@ +import sys +import pyodbc +from config import ZUP_SQL_CONFIG + +def test_connection(): + print("=" * 60) + print("🧪 ПРОВЕРКА ПОДКЛЮЧЕНИЯ К MS SQL SERVER (1С:ЗУП)") + print("=" * 60) + print(f" • Сервер: {ZUP_SQL_CONFIG['server']}") + print(f" • База: {ZUP_SQL_CONFIG['database']}") + print(f" • Логин: {ZUP_SQL_CONFIG['user']}") + print(f" • Драйвер: {ZUP_SQL_CONFIG['driver']}") + print("-" * 60) + + conn_str = ( + f"DRIVER={ZUP_SQL_CONFIG['driver']};" + f"SERVER={ZUP_SQL_CONFIG['server']};" + f"DATABASE={ZUP_SQL_CONFIG['database']};" + f"UID={ZUP_SQL_CONFIG['user']};" + f"PWD={ZUP_SQL_CONFIG['password']};" + f"TrustServerCertificate={ZUP_SQL_CONFIG['trust_server_certificate']};" + f"Encrypt={ZUP_SQL_CONFIG['encrypt']};" + ) + + try: + print("⏳ Установка соединения...") + with pyodbc.connect(conn_str, timeout=10) as conn: + cursor = conn.cursor() + + # 1. Проверка версии SQL Сервера + cursor.execute("SELECT @@VERSION;") + db_version = cursor.fetchone()[0] + print("✅ Подключение успешно установлено!\n") + print(f"📋 Версия MS SQL Server:\n{db_version.splitlines()[0]}\n") + + # 2. Проверка доступа к таблице физических лиц _Reference299 + cursor.execute("SELECT COUNT(*) FROM dbo._Reference299 WITH (NOLOCK);") + count_phys = cursor.fetchone()[0] + print(f"📊 Записей в таблице физлиц (_Reference299): {count_phys} шт.") + + # 3. Проверка доступа к регистру кадровых состояний _InfoRg16921 + cursor.execute("SELECT COUNT(*) FROM dbo._InfoRg16921 WITH (NOLOCK);") + count_states = cursor.fetchone()[0] + print(f"📊 Записей в регистре состояний (_InfoRg16921): {count_states} шт.") + + print("\n🎉 Все проверки успешно пройдены!") + + except pyodbc.Error as ex: + sqlstate = ex.args[0] if ex.args else "UNKNOWN" + print("\n❌ ОШИБКА ПОДКЛЮЧЕНИЯ!") + print(f"Код ошибки: {sqlstate}") + print(f"Детали:\n{ex}") + sys.exit(1) + +if __name__ == "__main__": + test_connection() \ No newline at end of file diff --git a/update_kb.py b/update_kb.py new file mode 100644 index 0000000..e66ff4c --- /dev/null +++ b/update_kb.py @@ -0,0 +1,45 @@ +import sqlite3 +import os +from config import DATA_DIR + +DB_PATH = os.path.join(DATA_DIR, "scud_orion_ai.db") + +system_ai_prompt = ( + "СИСТЕМНЫЙ ПРОМПТ ИИ (MATCHING & VERIFICATION):\n" + "Ты — экспертный ИИ-аудитор СКУД и кадрового учета 1С. Твоя задача — проводить интеллектуальный анализ аномалий " + "и сопоставление (Fuzzy Matching) нераспознанных ФИО из СКУД с эталонным Штатным расписанием 1С.\n\n" + "1. ЗАЩИТА ОТ ПОЛНЫХ ТЁЗОК (FULL NAME COLLISION):\n" + " - Если в эталонном штате 1С присутствуют два или более сотрудников с ОДИНАКОВЫМИ ФИО (полные тёзки), " + "ты ОБЯЗАН учитывать контекст: Подразделение и Должность.\n" + " - Ни в коем случае не объединяй записи разных людей! Если контекст не позволяет однозначно определить, кто именно из тёзок совершил проход, ПОМЕТЬ СЛУЧАЙ КАК НЕОДНОЗНАЧНЫЙ и НЕ делай автоматическую подмену.\n\n" + "2. ПРАВИЛА СОПОСТАВЛЕНИЯ (MATCHING RULES):\n" + " - Допускаются исправления мелких опечаток, перестановки порядка (Имя Фамилия -> Фамилия Имя), замена букв Е/Ё, И/Й.\n" + " - Учитывай сокращения инициалов (например, 'Иванов И.В.' -> 'Иванов Иван Васильевич').\n" + " - Если уверенность в совпадении меньше 85% — НЕ сопоставляй, оставляй запись как нераспознанную.\n\n" + "3. ФОРМАТ ВЫХОДНЫХ ДАННЫХ:\n" + " Верни строго JSON-объект без вводных слов и Markdown-разметки: {\"mappings\": [...], \"unmatched\": [...]}" +) + +rules = [ + (system_ai_prompt, "System_AI"), + ("ГЛОБАЛЬНОЕ ПРАВИЛО 1: Любое физическое присутствие сотрудника по СКУД при наличии в 1С документа отсутствия (отпуск, больничный, уход за ребенком и др.), КРОМЕ командировок и служебных поездок — ЯВЛЯЕТСЯ СТРОГОЙ ИСТИННОЙ АНОМАЛИЕЙ.", "Human"), + ("ГЛОБАЛЬНОЕ ПРАВИЛО 2: Документы отсутствий из 1С:ЗУП имеют 100% высший приоритет над статическим реестром удалёнщиков.", "Human"), + ("ГЛОБАЛЬНОЕ ПРАВИЛО 3: Удалённые сотрудники имеют право беспрепятственно работать в офисе по СКУД в любое время (это не является аномалией).", "Human") +] + +conn = sqlite3.connect(DB_PATH) +cursor = conn.cursor() + +# Очищаем таблицу перед записью, чтобы избежать дублей и UNIQUE constraint error +cursor.execute("DELETE FROM ai_knowledge_base;") + +for rule_text, added_by in rules: + cursor.execute( + "INSERT INTO ai_knowledge_base (rule_text, added_by) VALUES (?, ?)", + (rule_text, added_by) + ) + +conn.commit() +conn.close() + +print("✅ База знаний успешно перезаписана с включением системного промпта ИИ!") \ No newline at end of file diff --git a/zup_detective.py b/zup_detective.py new file mode 100644 index 0000000..3f9dd25 --- /dev/null +++ b/zup_detective.py @@ -0,0 +1,63 @@ +import pyodbc +from config import ZUP_SQL_CONFIG + +print("="*60) +print("🕵️‍♂️ ZUP DETECTIVE: ПОИСК СТАТУСА 'УВОЛЕН'") +print("="*60) + +conn_str = ( + f"DRIVER={ZUP_SQL_CONFIG['driver']};" + f"SERVER={ZUP_SQL_CONFIG['server']};" + f"DATABASE={ZUP_SQL_CONFIG['database']};" + f"UID={ZUP_SQL_CONFIG['user']};" + f"PWD={ZUP_SQL_CONFIG['password']};" + f"TrustServerCertificate=yes;" +) + +with pyodbc.connect(conn_str) as conn: + cursor = conn.cursor() + + # 1. Получаем ID наших подопытных + cursor.execute("SELECT TOP 1 _IDRRef FROM dbo._Reference299 WHERE _Description LIKE '%Шумский Алексей Анатольевич%'") + id_work = cursor.fetchone()[0] + + cursor.execute("SELECT TOP 1 _IDRRef FROM dbo._Reference299 WHERE _Description LIKE '%Щелканов Дмитрий Викторович%'") + id_fired = cursor.fetchone()[0] + + # 2. Сканируем два самых больших кадровых регистра, которые нашел наш сканер + for table in ['_InfoRg16684', '_InfoRg32796']: + print(f"\n🔍 АНАЛИЗ РЕГИСТРА: {table}") + + # Ищем все колонки-ссылки + cursor.execute(f"SELECT name FROM sys.columns WHERE object_id = OBJECT_ID('{table}') AND system_type_id = 173 AND max_length = 16") + cols_bin = [r[0] for r in cursor.fetchall()] + + found = False + for col in cols_bin: + cursor.execute(f"SELECT COUNT(*) FROM dbo.{table} WITH (NOLOCK) WHERE {col} = ?", (id_work,)) + if cursor.fetchone()[0] > 0: + print(f"✅ Найдена колонка связи с Сотрудником: {col}") + + # Забираем полные строки обоих людей + cursor.execute(f"SELECT * FROM dbo.{table} WITH (NOLOCK) WHERE {col} = ?", (id_work,)) + data_work = cursor.fetchone() + all_cols = [c[0] for c in cursor.description] + + cursor.execute(f"SELECT * FROM dbo.{table} WITH (NOLOCK) WHERE {col} = ?", (id_fired,)) + data_fired = cursor.fetchone() + + if data_work and data_fired: + print("\n⚖️ ОТЛИЧИЯ В ДАННЫХ (Работает vs Уволен):") + for i, c in enumerate(all_cols): + # Выводим только те поля, где есть отличия + if data_work[i] != data_fired[i]: + print(f"Поле [{c}]:") + print(f" 🟢 Шумский: {data_work[i]}") + print(f" 🔴 Щелканов: {data_fired[i]}\n") + found = True + break + + if found: + break + +print("✅ Расследование завершено!") \ No newline at end of file diff --git a/zup_scanner.py b/zup_scanner.py new file mode 100644 index 0000000..d3ae8dd --- /dev/null +++ b/zup_scanner.py @@ -0,0 +1,60 @@ +import pyodbc +from config import ZUP_SQL_CONFIG + +print("="*60) +print("🔍 ЗАПУСК СКАНЕРА СТРУКТУРЫ 1С:ЗУП 3.1") +print("="*60) + +conn_str = ( + f"DRIVER={ZUP_SQL_CONFIG['driver']};" + f"SERVER={ZUP_SQL_CONFIG['server']};" + f"DATABASE={ZUP_SQL_CONFIG['database']};" + f"UID={ZUP_SQL_CONFIG['user']};" + f"PWD={ZUP_SQL_CONFIG['password']};" + f"TrustServerCertificate=yes;" + f"Encrypt=no;" +) + +with pyodbc.connect(conn_str) as conn: + cursor = conn.cursor() + + print("⏳ Анализ справочников...") + cursor.execute("SELECT name FROM sys.tables WHERE name LIKE '_Reference%'") + for row in cursor.fetchall(): + t = row[0] + try: + cursor.execute(f"SELECT TOP 5 CAST(_Description AS NVARCHAR(255)) FROM {t} WITH (NOLOCK) WHERE _Description <> ''") + vals = [r[0].strip() for r in cursor.fetchall() if r[0]] + if not vals: continue + text = " ".join(vals).lower() + + # Ищем сотрудников (исключая физлиц _Reference299) + if t != '_Reference299' and any(w in text for w in ["александров", "иванов", "смирнов", "петрова", "сергеев"]): + print(f"👤 СОТРУДНИКИ ({t}): {vals[:3]}") + # Ищем должности + elif any(w in text for w in ["инженер", "специалист", "директор", "уборщик"]): + print(f"💼 ДОЛЖНОСТИ ({t}): {vals[:3]}") + # Ищем подразделения + elif any(w in text for w in ["отдел", "управление", "служба"]): + print(f"🏢 ПОДРАЗДЕЛЕНИЯ ({t}): {vals[:3]}") + except: + pass + + print("\n⏳ Анализ регистров кадровой истории...") + cursor.execute("SELECT name FROM sys.tables WHERE name LIKE '_InfoRg%'") + for row in cursor.fetchall(): + t = row[0] + try: + # Ищем широкие регистры (Текущие кадровые данные имеют много колонок) + cursor.execute(f"SELECT COUNT(*) FROM sys.columns WHERE object_id = OBJECT_ID('{t}')") + col_count = cursor.fetchone()[0] + + cursor.execute(f"SELECT COUNT(*) FROM {t} WITH (NOLOCK)") + row_count = cursor.fetchone()[0] + + if col_count > 15 and row_count > 500: + print(f"📋 ШИРОКИЙ РЕГИСТР КАДРОВ ({t}) -> Колонок: {col_count}, Строк: {row_count}") + except: + pass + +print("\n✅ Сканирование завершено!") \ No newline at end of file