From 7c88da9ab1ba6c53947e6df5d3cf98a55410e909 Mon Sep 17 00:00:00 2001 From: KiriAky 107 Date: Fri, 27 Mar 2026 00:06:17 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E5=96=84=E6=95=B0=E6=8D=AE=E5=BA=93?= =?UTF-8?q?=E8=B0=83=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../__pycache__/health.cpython-312.pyc | Bin 0 -> 2430 bytes .../__pycache__/library.cpython-312.pyc | Bin 0 -> 5618 bytes .../endpoints/__pycache__/rag.cpython-312.pyc | Bin 0 -> 4089 bytes .../__pycache__/tasks.cpython-312.pyc | Bin 0 -> 1598 bytes .../__pycache__/templates.cpython-312.pyc | Bin 0 -> 8294 bytes backend/app/config.py | 11 +- .../__pycache__/mongodb.cpython-312.pyc | Bin 0 -> 9721 bytes .../__pycache__/mysql.cpython-312.pyc | Bin 9688 -> 9629 bytes .../__pycache__/redis_db.cpython-312.pyc | Bin 0 -> 10535 bytes backend/app/core/database/mysql.py | 4 +- backend/app/core/database/redis_db.py | 2 +- .../excel_storage_service.cpython-312.pyc | Bin 0 -> 19214 bytes .../__pycache__/rag_service.cpython-312.pyc | Bin 0 -> 13101 bytes .../table_rag_service.cpython-312.pyc | Bin 0 -> 17869 bytes .../template_fill_service.cpython-312.pyc | Bin 0 -> 10985 bytes backend/app/services/rag_service.py | 236 +++++++++--------- backend/requirements.txt | 5 +- frontend/src/pages/ExcelParse.tsx | 4 +- 18 files changed, 133 insertions(+), 129 deletions(-) create mode 100644 backend/app/api/endpoints/__pycache__/health.cpython-312.pyc create mode 100644 backend/app/api/endpoints/__pycache__/library.cpython-312.pyc create mode 100644 backend/app/api/endpoints/__pycache__/rag.cpython-312.pyc create mode 100644 backend/app/api/endpoints/__pycache__/tasks.cpython-312.pyc create mode 100644 backend/app/api/endpoints/__pycache__/templates.cpython-312.pyc create mode 100644 backend/app/core/database/__pycache__/mongodb.cpython-312.pyc create mode 100644 backend/app/core/database/__pycache__/redis_db.cpython-312.pyc create mode 100644 backend/app/services/__pycache__/excel_storage_service.cpython-312.pyc create mode 100644 backend/app/services/__pycache__/rag_service.cpython-312.pyc create mode 100644 backend/app/services/__pycache__/table_rag_service.cpython-312.pyc create mode 100644 backend/app/services/__pycache__/template_fill_service.cpython-312.pyc diff --git a/backend/app/api/endpoints/__pycache__/health.cpython-312.pyc b/backend/app/api/endpoints/__pycache__/health.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..21a536bef85f643c88ab79896a1c3a83f20ed138 GIT binary patch literal 2430 zcmb_eZEO@p7@pbP+xyz~+ABxPS9>Rga?t=mNI(q9OtI-Z{HR zIa16ONWg|q#n47R+7L_?5lo0CC4|_-U;b&W371V1HG0>Y_~S}zg6I!tc5mC0h(C;z z%Pot!?xZK`fq(&sm-#sS)OnN4M@!U;yq!xdyRwyC zHbZtJ4pkwxgQ2tzM)sWGZkDOh>SuU+pYpDn_ZBL=eb4Z&dZu@Eg?CNX7p}=HBB6K+ zy*COYUly};nw!J&|r7}9g zVb*XZv)bEaZ+b>a@4y3q^}Pir4^FOxPfjnK_@eB&Ko&KW{v{FqVt%g(`8!=Pm=`+%ajns zJ885}6^+it=sp|nAyIU#0icIOVm=w`8E5T-$BfLWPWGvhy;#AFKpAXLFhXb`YVmN5KJb`cOAG%pL&U@E;kFF!XMePQ|r4TmW# z0`i(J>KV;&Q+X0QnKoP+!iN+IX<;vRQnDawSyhT5HLj@0aKCm~LTOz|sn%4ylu(eW zW4B2qYF&ti6%z@}Qk>7|lA7u^+=`a!Na3WYleGm)@Z|`q%c75!`+}u?tEbUf$QeF~ z?0BhdPq(@kr#i|0+g?`^NZW@*d4E>Zk(g|27o{$w%57pgO{&sH>~u;|b*;@hlC|lq zAy{TiI*6n${2ZCNnpEvq(oBQLIZ&zri<)w~^MPQlHDA}5+g;)~N7JOY?x8n0?hTH4 z*W{OlPwg(bI7evG>p!>k-K}HZP=3Ypr&=l2H0i5<=xhGg*KE?}JRrC-FEsS;8W&pf z!qWb(aUpE?OHQuYGY7b!_d>Yj0=3H~11m1YF2p7Rs~-l|j|bLI1UCE-2<7Wn%p|&4VyUxTHdn3*4XvoA@LTWdgc#Ai( zi5=Zw;u|5gH&OgZRXIhi!{kL}>8kUECY|G?&eEH0Cn%Xw;C^6UA2#zA8L+O;ozJK4 zee$>bYU1>2jGPVb%CsY_A{}Y#rte;xzJI@P<>d6xP+?%W>~i@`p>L?zf4gx0qk=h= z>5Xabrq_W)_A$V#Xe^`x9HO|7;zaZsQMDTDfpEU{FBs=)d9n746^Yy5qd z=9Oa(Cp;q9n@%W)(0|_Zt^VTOd;ia#&8aH)EYir#9b3(661uhRYC2M}>let#Yjl+4 zYklV?^j|`|MH-@b z2xk}ua=-BaHhvG57r=@suw@)<`O)p~Zyak_^PM}K<4ZhXTql?IECKg$B9-W({sN&Z_b@}3E}yu|RZsb3#_b+~SD$G|&}0O?Zl3Ui?3 dx4EqoaGAxG2VWd!2R9F>^W5b#bP`Mt{Vx*Lp8o&< literal 0 HcmV?d00001 diff --git a/backend/app/api/endpoints/__pycache__/library.cpython-312.pyc b/backend/app/api/endpoints/__pycache__/library.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a30bc1785529a52a0098981db4f77be1098bc219 GIT binary patch literal 5618 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 literal 0 HcmV?d00001 diff --git a/backend/app/api/endpoints/__pycache__/rag.cpython-312.pyc b/backend/app/api/endpoints/__pycache__/rag.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0b45d0c8707db7a29f5362abe77042180b620457 GIT binary patch literal 4089 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 bxqAwXIKG^ro-+C_vsj=KFHxEl00sUZ52sEj literal 0 HcmV?d00001 diff --git a/backend/app/config.py b/backend/app/config.py index 5e0e871..879555d 100644 --- a/backend/app/config.py +++ b/backend/app/config.py @@ -45,11 +45,20 @@ class Settings(BaseSettings): @property def mysql_url(self) -> str: - """生成MySQL连接URL""" + """生成MySQL连接URL (同步)""" return ( f"mysql+pymysql://{self.MYSQL_USER}:{self.MYSQL_PASSWORD}" f"@{self.MYSQL_HOST}:{self.MYSQL_PORT}/{self.MYSQL_DATABASE}" f"?charset={self.MYSQL_CHARSET}" ) + @property + def async_mysql_url(self) -> str: + """生成MySQL连接URL (异步)""" + return ( + f"mysql+aiomysql://{self.MYSQL_USER}:{self.MYSQL_PASSWORD}" + f"@{self.MYSQL_HOST}:{self.MYSQL_PORT}/{self.MYSQL_DATABASE}" + f"?charset={self.MYSQL_CHARSET}" + ) + settings = Settings() \ No newline at end of file diff --git a/backend/app/core/database/__pycache__/mongodb.cpython-312.pyc b/backend/app/core/database/__pycache__/mongodb.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..479f37b13c1e32f0fd2536467098f7806a210543 GIT binary patch literal 9721 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 literal 0 HcmV?d00001 diff --git a/backend/app/core/database/__pycache__/mysql.cpython-312.pyc b/backend/app/core/database/__pycache__/mysql.cpython-312.pyc index 0f1ebba1f18d01fce1d8f8389d10dbc15b937b3f..0347b2cac5c64247ec9807e6427ca76f4e514621 100644 GIT binary patch delta 705 zcma)(%WD%s7{GV(*lpr2P12_3xv5Et1_U9A8j<=yiiOlzT0v};kZekf+0CZ2RtSU| zFB0OZeituo5k!QX%7T}mVxW_GfxS>cNy zI2mKTzqM7F+YnyZ$RxbBZ4wWBw513K@9g9Lfvy!>7^cbO`6FYP29t2W5c>$$*%&ui z&>A%<51-fxr$cFIi*kO6%HZPedY&5_TFhSP%q~B?&Bwp;aaiW2^lfh5LXwbj&XA1$ z)G1lSq|w;tN)@fHY76wN5z)(tD~R(tCmfJ?%J4obsftp0NUvfrKvh{T7NjbjG{S_1 zX7t#gVkJ3P@uXcD+qIs1z@M9;* J8l=Zw{RZB9s|Nr8 delta 755 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 literal 0 HcmV?d00001 diff --git a/backend/app/core/database/mysql.py b/backend/app/core/database/mysql.py index 6e5b318..9ecfe9b 100644 --- a/backend/app/core/database/mysql.py +++ b/backend/app/core/database/mysql.py @@ -37,7 +37,7 @@ class MySQLDB: def __init__(self): # 异步引擎 (用于 FastAPI 异步操作) self.async_engine = create_async_engine( - settings.mysql_url, + settings.async_mysql_url, echo=settings.DEBUG, # SQL 日志 pool_pre_ping=True, # 连接前检测 pool_size=10, @@ -55,7 +55,7 @@ class MySQLDB: # 同步引擎 (用于 Celery 同步任务) self.sync_engine = create_engine( - settings.mysql_url.replace("mysql+pymysql", "mysql"), + settings.mysql_url, echo=settings.DEBUG, pool_pre_ping=True, pool_size=5, diff --git a/backend/app/core/database/redis_db.py b/backend/app/core/database/redis_db.py index 780a07b..83b21e9 100644 --- a/backend/app/core/database/redis_db.py +++ b/backend/app/core/database/redis_db.py @@ -6,7 +6,7 @@ Redis 数据库连接管理模块 import json import logging from datetime import timedelta -from typing import Any, Optional +from typing import Any, Dict, Optional import redis.asyncio as redis diff --git a/backend/app/services/__pycache__/excel_storage_service.cpython-312.pyc b/backend/app/services/__pycache__/excel_storage_service.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..91bd26381c0bd830c0707ddac55b69b8406a6ed6 GIT binary patch literal 19214 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 NJZ38iQE6nz|36hNs}%qM literal 0 HcmV?d00001 diff --git a/backend/app/services/__pycache__/rag_service.cpython-312.pyc b/backend/app/services/__pycache__/rag_service.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..856ba0a75dae5d1dcacc37ae6541b9127f18affa GIT binary patch literal 13101 zcmbVTdvqJsnIB0rdfW0#e#n+B$4-fYF$sARLTHGc*bp4R<`EMRie}=-@rxM=$3Aw} z&`@Lu#O^|^G=wNT7KK+#mo83#CD86U>FytukW;Bs@7Z)4Iq=syaeF9i&z}9hJDQQ~ zC`}L7(VaW@J@-zLtFL)#N8VoHZW#1 zUi|d4OD}~T0@vf?dOX}sKHl9U?CIsZIbLww=-BG^3W6i~{;QW>oJ@|5fBo!XsT1SZ zIAn{H7B!oD21L5S>+y;7cCX+Q^*j1}-rgQ}ms2Gcwx;@ROLq&|dV%x#ygeO)2YZo& zHkFuP4v7hhqhJFlTzpt~HAk}=j^SudyGLCH<$GwBK1jFg1{kMS%x(2{_jPd%y&iuz z4CpU_3YXp=Ngn#?>`$MaJ@I<-)akE2I3b$*+#Q_D(~F-9^X%q)Zr1H{do-zm@qufN z@AD3bCa59R5aoiD6o%CBmf9hT8lX<9T288Y6BP1hh@2Xc7PziG=^O#OayT5{-PyEZ z*N*<4d->i@&g0v))!W4h_j7KxbwKcO?(SW?-JX4154+3V*SAaH_$R#{PT0k}J6x%k z`n~~C?{ay2ygrv}uw>!)*2@JYFq)7L(Fm2OSQenC^<{}tM}U4IXC5+PyY$#ekGq?5 zxkRJO)!obbyD)8bxt{R5yHX`Omy7N7K()LQLZ*JTeuDtdI~K z5FMm`M_0_L)l7A$b&i6^WW!Y9lxM2+gO)$xtJE0VdElo6TtW=<_rvNg-ui*1;M%6KjH>8GbpOnakl!NK}Nd^la`y zrahO`vp{(s{PLj=q`5qa_((l1TLAU)*+OVtfH`cD+z*Upg|Q0RYPJ|!mvBWetDG!7 zltK?ysD<;ncC9j~RSZ28?NPHf=(hyEpqw+oTLqMqDsOgpD`R1vP*Mr?Y-|;*RQZ6x zxkN-fXq5=dUksBa@Q{HA5>$8;;)W^;D?AM^2#lGmK;D$v9axrvDT*R*NHHX^$U-v6 zQY^9%BbWJ*ZAj?Ml~d^_)YQvw1HfG^JPxtdX%H=3_im150YZ?5xh|3M_ORT3(ExNy zAV3gxNWxxL06J&AfC>U&63{tvkk{Si9pqRZI~OfmH#fJox|&-W8XtBwG~W+(`T+X? z$)Fv7QpM*%EdjsOArU>&++bmPITh{$!9oceAp-8(bSH9OMWSv+fIehQ+`JMVxrrsU z@GvK;fF%!E5*5{iLuV>#;}xr;6{`dEd3_mSkOkX-u!xH}|9=nxB2k_2TpUK8@F@%K zQx>~ZhSZGevV?)fRdTcU*=bNJC<$58Tw@b0N<}5Xs{i(Uj#8`!#z#n46pm8IXnD3O zYCtuha?*Z8nq=Tu@~!6q-IKpKlziq*ly9#--{P-^A|&g~+;r9V4}rYf;PB%>b&g9P zf0#V;Pa7OgJ#U8$UWbuH4~_TS+1Sv~+_KGe&yI%1?V_WD^8pM?^3jzhJcX)w99YzL z^>%b{yhwX{KzuHRtPG+N^Cak2S_^~anG{5DJzcmATknBrgt}m|#7$LEQ&q%t!%WTE z5BJB{?TD`15v#d3&@gRwBr2E0D{qNb-V(2DjaIhCDjx_m9NIBsE;xMm=-m<9ZJ#v7 zH?~DLwnc7xAo74K@;DoRyf^xIZ^YFXDShI+nV-{9=4DsY95N`Ox!*$Knl$$)?3+S$ zP%#x`8c|U`h0(K7Vn(UL=5ikt(s>q|km*5wW>Rqmm}I3xxlM|eG>d47XgA6Cg2|`D z5-p{4pN#xP)C9y+2@~dTgh*uepsFMqn-Peb8}4!Ui6)ZX+U52&-%E&ucVhMB7%e7{ z0*OGL1nr=gcL@-2gZ8UPB(wNt=tj63B0?mGH;itGnCuC2Uff(AHCIoYYi7zS<7Lih zne*MH@#VKgm)|zk@Y#;jJ7UYX$I9*jGPz48lhWJHn>QjQRA#4yAHg8=XCS(pQUNs> zaBmdohwM~H?>m8frA7w-BbzM>tU6;~=o-qW&_XT6R}QN(TALO%g;&5172rfhA5T*( zJ*+yQ>R0ts`!zeMe${)LewCB)BTXbfd3yG}H~%VOEz}n7hv+NnFC)|(tu+*o9j=L*Yo^Uh6OLL$0lTu1tInHO|7FHfdWBLO3NUy3 z==MnY+Q}y-J(02v)8^X}=KTMiW1#S_LM?Rrv}$v?>R{bUY7!G47&ez`&XjE~)O=pZ zK=Sia4djYCiRuJV%X2FPnCk5)?F=}&)haSAN}$!hr;`)qTnMcTdJD~S4i z9M=Z`E)b0ZtQd7qA0W6Ftd>5nJfK zFcZtG4=@Q!anL&Y4-vh@rY)k;=iUwKJ8JEsagUelVx@Gxlx8`>!+Rw<%n{sZA-SG( zcljYZb03f=3D%oojjo0DLf-YT9`*w`5!5?1k?0!WO6@Q+MDry>ptrM3XXcnNB!(eH zz9SD0=1>&0z+SZ2%Q4Nc)~6uG5R`!ZrDb)mXx`P!_V2I`=9NWH8PavAhO`|jxgN+O zMVfTNIEw>o7}74pkpZLAN>}Fs(PTd zJE4f*0+Fbd6j&Z{%a7((@}r-p1}D=&{Lx9!gCHc*oxR>3VvUKpE;q}f4JYZs1e!#K z<#zi!KxUyrn;wU6z}H67gOA(qWaKqTObW>8hJL{&1q${w1*>Z=HBag|50H;jPRaU&ZNns>Ydq6PjU+$=&IyFlInai|2aQ-)Lx)M1TB-9dTOkAh)4tQpdD zLdC^lTzx2yriN)Kr~YnvNwaE@mMQ59c$uAG7+I^zhK{U)yQIB>jOqD}Al_%e$#+s! zRMe0fzEPX{MnrC{Ptm%EwDRcig%0$INv+6|aZ&3ib zphyEid31r1fYL(luYr2Bm7;KmhC!x4-=%V`^s^I{y+vV2n|bcT z)rrQzqL6)*bgM%T&|v9$)GDByVNE~8B&F@AoO)v5&W@f&C+tTbC!Y(Y_*fQ25-Yc~ zom7c=0A^2eywBz9b@lkW!Fj0L)79(tt-1w0CBC(*p$^0P2Kqq35!GHc&7jUa$$N=b zv8V-?Ft}Iv&E&-`U<1kIktEJux3HH-kB7*(dEPxBno;ibdwqL}=S4HP$rXs)~GAMz-h)SEnAc?%JsPnR}F5+B<1Q|*&KraMCFp@ko2tb2n z8KALH4E8{=paLalg!+R8m$E@q));prsJI)$n*1G~mFx4}yu#}Gehh;a% z3Raxdg$iF<9n`#hYgiZ1MG98T6j~?NkFO7I3$L3lTouqK^yb6HQDaMKbWhg;Ry`TbrY|Hb)+6k3Zyz!oMZ#w3)+N zp!UbjRZ(+QNORs?dzqoiR(yMgz&8{#1mE^c_?FfCbbaj*xFJ)dLZ=v>D$AaqP48z_sP*%JsjbLciujXy!Z@2C zM4`C=FA-_8;M$PFxt$7%rF+i6OKhLzOF9*FOSc-*_|R2O0-hXXZI{hMm%?@#y$Ej6 z!%PQatb%|;a0-RiD`?l`Dc1(9yEBD#x?%m09@Y)|<5h>uFaz}bE($|>>}44A-%d;{ z3PT2#A)^>rEk1n;N)G8{)Pg!XEMxVrC~`$b9crK{pMsK|$moj#Yw%UeS!sy@+Q0Fb zvKxS-TCnL%e#Fw*&}q=MXOF-6)v4E{W2j3(wejzb)Rsgtq5q{ENev19hwiOjB@`Ds0y;Gd}N@%8%LU6S+g5gZLMlHUc9 zs1-Oj@7XJAxUBVzsGw0<*K-+^4oKZbZH2gCw`k9CkB z#sRG4;vm_^$G|q0xfEzx?ME#{qP*Ed&nDmh8CZ{(es)kY8u@Kd=v483e59NZz}FIe zEObHS%RA}XJ>ViPfx(IlA$V2ktI&;Lg9sdlmcqlsqr<`dVPj}0VqZPU#Vi{m`i)on z0r9KIcQ!%dT1Lb_YeL^kb~tO1^;eD&f-$-^l}&Fsj>voB9dZW*!Ao0J1@ScY~F`YftBBxKWvvyYMCF;$M& zm(QkKv%1CpVLV5wp;m$>*bln(PD%xThiW8GG3eMR-!6W349@|G<6p6lFTMWM zrK7=?HoU&Tfe+E=>fQI9!od>`V~`c7!Y1`smf(2;{ zKh6JHEq0|ZIDuiM>U;6y zf4MmI0s_`6;SCN^&F|*hp;nt8fi|-)_>V7s{G!8;%j=Ma`JYeV0R01ppT;audYy$5 zB8|X1|09eD;Ajcp36dXK*YDI1CdCB+kutP$$^#Jt0wzzd^)Veg( z8METW597t0{4r;+Z8~R3$US4PIsV9zN5c6>AA>X47J#|jnmH}Cy#7?>+m*4B^(QMs zn}e!g?NMF0GFq~pTo|c<3nOrs3q9DTQB$PY8LkUgP9FG`=UnY?>VI7y+qyH-*dA$r zEK=k;uYdd-6LcBLS@PE_TB`I`0X3{IZZB`RRrAYwb0b6l>Q<&veGQQOPy)%UD$SVc zsdYg93dljXsQ?V9&Ts^Rn#+tF}a^i-!Dftq3PeFFn3O7eAkM3z>1R9G5s z5h*i)KIExnJhS=H)8LkUT>ic6`59j*&qsrJCd~&NxM<#^s96-Ux+LJ{;=2ko5(jKH zhlBzn*+3dps?-V&GuMIXtZs*^T(@brg3`0JV*sCUM=^3?L=>{^kdlwxnlX1ABGJHe-EKJP z2O!;znI4Q-jPT-5mb14!xaY=!ItWG{fFn3q7g#)t3;!KENm=!h0UtG0Cu*0y)$&?P zthDJwOYn(F_Z0m>$Jyf8+HF6}548lEBc)9V`wtM65;v_p_1N2w#mYCHd@QUAZVs|X zw}l^zmT!c@?H9noc-QD%adSn~Trq8~L?i0Ja|aSPuR3+$?E|sWO(ze8tAqK$TaQ+R z4~#L9(oG3_b=Zb%#C^UFV_?_TJ;O=ADJmCV$Oao=gQXK)RB@cDukoDGS;3>7$s@w?Xj}4#ROBwRq`{D{ zS%Y~SArf^xEIDA19C~P6@~C<6*cZP8BV2OnLNwmYkuE{s4Jq)#_4tUxhVRFM0gM6| z{RE?*Vid#(C5JRmw6J+JIZ1?MC^Q1F<1K2(6rK*PMkIR>84u)sQ}!<3#XEDx>@X+o_b{gF-4g5~pAac)Tg zvouTtBrMxFM?w0m@7$Kp2j($(d6|tV33}!zc!X=nW0IX(eO7a}^{oE%rs&$c=CSDV zdNp%O_t%xthKJ{|Y)((ZW%3&Q#OljtBh#n~3G);_ zFP9cEZt{lDxjGB84vXM1zeLBZlU5iP*I7dL9BxPma0gh27c~)fM{wPVlB$J+EzCi- zmbRDdHraP#i8JI7O(GDhau+o7|4NV>q@oedx$5EUZI8D@x=m^TPtL!XZW+ z1}7$(GOqY9B8%_z8>Q>{oA@`NDvEny7esR!l}dG4O{?g6Bc(F`p340_W%xan^Iue5 zjH>%11vv%(Nv%mzRTm7lKuO$SiyCaf^)W;3i1r&Tt*X9ELG(@TR*h=iWs1c2Ybi_F L^IcDw$ddg(ofN(K literal 0 HcmV?d00001 diff --git a/backend/app/services/__pycache__/table_rag_service.cpython-312.pyc b/backend/app/services/__pycache__/table_rag_service.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..22392986310dcccf432df65f2604f07e8c765a93 GIT binary patch literal 17869 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 np.ndarray: + """归一化向量""" + norms = np.linalg.norm(vectors, axis=1, keepdims=True) + norms = np.where(norms == 0, 1, norms) + return vectors / norms + def index_field( self, table_name: str, @@ -62,39 +74,20 @@ class RAGService: field_description: str, sample_values: Optional[List[str]] = None ): - """ - 将字段信息索引到向量数据库 - - Args: - table_name: 表名 - field_name: 字段名 - field_description: 字段语义描述 - sample_values: 示例值 - """ + """将字段信息索引到向量数据库""" if not self._initialized: self._init_vector_store() - # 构造完整文本 text = f"表名: {table_name}, 字段: {field_name}, 描述: {field_description}" if sample_values: text += f", 示例值: {', '.join(sample_values)}" - # 创建文档 doc_id = f"{table_name}.{field_name}" - doc = LangchainDocument( + doc = SimpleDocument( page_content=text, - metadata={ - "table_name": table_name, - "field_name": field_name, - "doc_id": doc_id - } + metadata={"table_name": table_name, "field_name": field_name, "doc_id": doc_id} ) - - # 添加到向量存储 - if self.vector_store is None: - self._init_vector_store() - - self.vector_store.add_documents([doc], ids=[doc_id]) + self._add_documents([doc], [doc_id]) logger.debug(f"已索引字段: {doc_id}") def index_document_content( @@ -103,131 +96,134 @@ class RAGService: content: str, metadata: Optional[Dict[str, Any]] = None ): - """ - 将文档内容索引到向量数据库 - - Args: - doc_id: 文档ID - content: 文档内容 - metadata: 元数据 - """ + """将文档内容索引到向量数据库""" if not self._initialized: self._init_vector_store() - doc = LangchainDocument( + doc = SimpleDocument( page_content=content, metadata=metadata or {"doc_id": doc_id} ) - - if self.vector_store is None: - self._init_vector_store() - - self.vector_store.add_documents([doc], ids=[doc_id]) + self._add_documents([doc], [doc_id]) logger.debug(f"已索引文档: {doc_id}") - def retrieve( - self, - query: str, - top_k: int = 5 - ) -> List[Dict[str, Any]]: - """ - 根据查询检索相关文档 + def _add_documents(self, documents: List[SimpleDocument], doc_ids: List[str]): + """批量添加文档到向量索引""" + if not documents: + return - Args: - query: 用户查询 - top_k: 返回数量 + texts = [doc.page_content for doc in documents] + embeddings = self.embedding_model.encode(texts, convert_to_numpy=True) + embeddings = self._normalize_vectors(embeddings).astype('float32') - Returns: - 相关文档列表 - """ + if self.index is None: + self._init_vector_store() + + id_list = [hash(did) for did in doc_ids] + id_array = np.array(id_list, dtype='int64') + self.index.add_with_ids(embeddings, id_array) + + for doc, did in zip(documents, doc_ids): + self.documents.append({"id": did, "content": doc.page_content, "metadata": doc.metadata}) + self.doc_ids.append(did) + + def retrieve(self, query: str, top_k: int = 5) -> List[Dict[str, Any]]: + """根据查询检索相关文档""" if not self._initialized: self._init_vector_store() - if self.vector_store is None: + if self.index is None or self.index.ntotal == 0: return [] - # 执行相似度搜索 - docs_and_scores = self.vector_store.similarity_search_with_score( - query, - k=top_k - ) + query_embedding = self.embedding_model.encode([query], convert_to_numpy=True) + query_embedding = self._normalize_vectors(query_embedding).astype('float32') + + scores, indices = self.index.search(query_embedding, min(top_k, self.index.ntotal)) results = [] - for doc, score in docs_and_scores: + for score, idx in zip(scores[0], indices[0]): + if idx < 0: + continue + doc = self.documents[idx] results.append({ - "content": doc.page_content, - "metadata": doc.metadata, - "score": float(score), # 距离分数,越小越相似 - "doc_id": doc.metadata.get("doc_id", "") + "content": doc["content"], + "metadata": doc["metadata"], + "score": float(score), + "doc_id": doc["id"] }) logger.debug(f"检索到 {len(results)} 条相关文档") return results def retrieve_by_table(self, table_name: str, top_k: int = 5) -> List[Dict[str, Any]]: - """ - 检索指定表的字段 - - Args: - table_name: 表名 - top_k: 返回数量 - - Returns: - 相关字段列表 - """ + """检索指定表的字段""" return self.retrieve(f"表名: {table_name}", top_k) def get_vector_count(self) -> int: """获取向量总数""" - if self.vector_store is None: + if self.index is None: return 0 - return len(self.vector_store.docstore._dict) + return self.index.ntotal - def save_index(self, persist_path: str): - """ - 保存向量索引到磁盘 + def save_index(self, persist_path: str = None): + """保存向量索引到磁盘""" + if persist_path is None: + persist_path = self._persist_dir - Args: - persist_path: 保存路径 - """ - if self.vector_store is not None: - self.vector_store.save_local(persist_path) + if self.index is not None: + os.makedirs(persist_path, exist_ok=True) + faiss.write_index(self.index, os.path.join(persist_path, "index.faiss")) + with open(os.path.join(persist_path, "documents.pkl"), "wb") as f: + pickle.dump(self.documents, f) logger.info(f"向量索引已保存到: {persist_path}") - def load_index(self, persist_path: str): - """ - 从磁盘加载向量索引 + def load_index(self, persist_path: str = None): + """从磁盘加载向量索引""" + if persist_path is None: + persist_path = self._persist_dir - Args: - persist_path: 保存路径 - """ - if not os.path.exists(persist_path): - logger.warning(f"向量索引文件不存在: {persist_path}") + index_file = os.path.join(persist_path, "index.faiss") + docs_file = os.path.join(persist_path, "documents.pkl") + + if not os.path.exists(index_file): + logger.warning(f"向量索引文件不存在: {index_file}") return self._init_embeddings() - self.vector_store = FAISS.load_local( - persist_path, - self.embeddings, - allow_dangerous_deserialization=True - ) + self.index = faiss.read_index(index_file) + + with open(docs_file, "rb") as f: + self.documents = pickle.load(f) + + self.doc_ids = [d["id"] for d in self.documents] self._initialized = True - logger.info(f"向量索引已从 {persist_path} 加载") + logger.info(f"向量索引已从 {persist_path} 加载,共 {len(self.documents)} 条") def delete_by_doc_id(self, doc_id: str): """根据文档ID删除索引""" - if self.vector_store is not None: - self.vector_store.delete(ids=[doc_id]) + if self.index is not None: + remaining = [d for d in self.documents if d["id"] != doc_id] + self.documents = remaining + self.doc_ids = [d["id"] for d in self.documents] + + self.index.reset() + if self.documents: + texts = [d["content"] for d in self.documents] + embeddings = self.embedding_model.encode(texts, convert_to_numpy=True) + embeddings = self._normalize_vectors(embeddings).astype('float32') + id_array = np.array([hash(did) for did in self.doc_ids], dtype='int64') + self.index.add_with_ids(embeddings, id_array) + logger.debug(f"已删除索引: {doc_id}") def clear(self): """清空所有索引""" self._init_vector_store() - if self.vector_store is not None: - self.vector_store.delete(ids=list(self.vector_store.docstore._dict.keys())) + if self.index is not None: + self.index.reset() + self.documents = [] + self.doc_ids = [] logger.info("已清空所有向量索引") -# ==================== 全局单例 ==================== - rag_service = RAGService() diff --git a/backend/requirements.txt b/backend/requirements.txt index bc2b712..28f756b 100644 --- a/backend/requirements.txt +++ b/backend/requirements.txt @@ -15,6 +15,7 @@ python-dotenv==1.0.0 # ==================== 数据库 - MySQL (结构化数据) ==================== pymysql==1.1.0 +aiomysql==0.2.0 sqlalchemy==2.0.25 # ==================== 数据库 - MongoDB (非结构化数据) ==================== @@ -29,7 +30,7 @@ celery==5.3.4 # ==================== RAG / 向量数据库 ==================== # chromadb==0.4.22 # Windows 需要 C++ 编译环境,如需安装请使用预编译版本或 WSL -sentence-transformers==2.2.2 +sentence-transformers==2.7.0 faiss-cpu==1.8.0 # ==================== 文档解析 ==================== @@ -40,8 +41,6 @@ markdown-it-py==3.0.0 chardet==5.2.0 # ==================== AI / LLM ==================== -langchain==0.1.0 -langchain-community==0.0.10 httpx==0.25.2 # ==================== 数据处理与可视化 ==================== diff --git a/frontend/src/pages/ExcelParse.tsx b/frontend/src/pages/ExcelParse.tsx index 316e459..8556025 100644 --- a/frontend/src/pages/ExcelParse.tsx +++ b/frontend/src/pages/ExcelParse.tsx @@ -30,7 +30,7 @@ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@ import { Checkbox } from '@/components/ui/checkbox'; import { toast } from 'sonner'; import { cn } from '@/lib/utils'; -import { backendApi, type ExcelParseResult, type ExcelUploadOptions, aiApi, analysisChartsApi } from '@/db/backend-api'; +import { backendApi, type ExcelParseResult, type ExcelUploadOptions, aiApi } from '@/db/backend-api'; import { Table as TableComponent, TableBody, @@ -179,7 +179,7 @@ const ExcelParse: React.FC = () => { setAnalysisCharts(null); try { - const result = await analysisChartsApi.extractAndGenerateCharts({ + const result = await aiApi.extractAndGenerateCharts({ analysis_text: analysisText, original_filename: uploadedFile?.name || 'unknown', file_type: 'excel'