From cfe463ae8bf8f10c295abf8046ce0c42319b78ce Mon Sep 17 00:00:00 2001 From: hz4th_coder Date: Fri, 10 Jul 2026 23:59:53 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=88=86=E7=B1=BB=E7=AE=A1?= =?UTF-8?q?=E7=90=86=E5=AF=BC=E5=87=BA=E5=AF=BC=E5=85=A5=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- __pycache__/auth.cpython-310.pyc | Bin 0 -> 2188 bytes __pycache__/config.cpython-310.pyc | Bin 0 -> 1280 bytes __pycache__/llm.cpython-310.pyc | Bin 0 -> 6636 bytes __pycache__/utils.cpython-310.pyc | Bin 0 -> 3610 bytes logs/app.log | 16 + modules/__pycache__/__init__.cpython-310.pyc | Bin 0 -> 182 bytes .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 189 bytes .../api_categories.cpython-310.pyc | Bin 0 -> 8310 bytes .../__pycache__/api_config.cpython-310.pyc | Bin 0 -> 904 bytes .../__pycache__/api_cpus.cpython-310.pyc | Bin 0 -> 4036 bytes .../__pycache__/api_gpus.cpython-310.pyc | Bin 0 -> 4066 bytes .../__pycache__/api_items.cpython-310.pyc | Bin 0 -> 4119 bytes .../__pycache__/api_knowledge.cpython-310.pyc | Bin 0 -> 3676 bytes .../__pycache__/api_models.cpython-310.pyc | Bin 0 -> 3935 bytes .../__pycache__/api_pin.cpython-310.pyc | Bin 0 -> 2797 bytes .../__pycache__/api_search.cpython-310.pyc | Bin 0 -> 3054 bytes .../__pycache__/api_smart.cpython-310.pyc | Bin 0 -> 6017 bytes .../__pycache__/api_upload.cpython-310.pyc | Bin 0 -> 2112 bytes .../routes/__pycache__/pages.cpython-310.pyc | Bin 0 -> 2043 bytes modules/routes/api_categories.py | 275 +++++++++++++++++- templates/admin.html | 225 +++++++++++++- 21 files changed, 512 insertions(+), 4 deletions(-) create mode 100644 __pycache__/auth.cpython-310.pyc create mode 100644 __pycache__/config.cpython-310.pyc create mode 100644 __pycache__/llm.cpython-310.pyc create mode 100644 __pycache__/utils.cpython-310.pyc create mode 100644 logs/app.log create mode 100644 modules/__pycache__/__init__.cpython-310.pyc create mode 100644 modules/routes/__pycache__/__init__.cpython-310.pyc create mode 100644 modules/routes/__pycache__/api_categories.cpython-310.pyc create mode 100644 modules/routes/__pycache__/api_config.cpython-310.pyc create mode 100644 modules/routes/__pycache__/api_cpus.cpython-310.pyc create mode 100644 modules/routes/__pycache__/api_gpus.cpython-310.pyc create mode 100644 modules/routes/__pycache__/api_items.cpython-310.pyc create mode 100644 modules/routes/__pycache__/api_knowledge.cpython-310.pyc create mode 100644 modules/routes/__pycache__/api_models.cpython-310.pyc create mode 100644 modules/routes/__pycache__/api_pin.cpython-310.pyc create mode 100644 modules/routes/__pycache__/api_search.cpython-310.pyc create mode 100644 modules/routes/__pycache__/api_smart.cpython-310.pyc create mode 100644 modules/routes/__pycache__/api_upload.cpython-310.pyc create mode 100644 modules/routes/__pycache__/pages.cpython-310.pyc diff --git a/__pycache__/auth.cpython-310.pyc b/__pycache__/auth.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e93c07ca5e4a2dbc3956ba187481b462785326a7 GIT binary patch literal 2188 zcmY*aTW?!M5I%eEK5?8jNiP(M8mNSf+87EC2vrqo#pQ(pYM=aKop{%=lXEe9_9$wU zJhTpNK`pch=!I6qP*7T_2_RKPz0m)$uhfbC)b~CyvnSUhd3JX8HuKFl<9Kk;)8KnL z{Ke#Zj;8&GldYc#lMmpR+yz0kibe_50}|>LouF<6Mrc;d(5hIWU9m%_;)HI+4Re)T z=v6$m#|#F-d?imbW>Sj{w)IMZ+H8nAY)9RsF3ruGm7Ub11M^yCm=z{RXr2yE5L&pT z(;>QJUTc%e=$d`!nthm#DElr}SQw$B9YS}}-O93??m4NI_NG69!`|mU_rp)p@nUc3 zc5nI2%3`N`>#Dc%-Q{Qh{=9nqQTNG@WgN~w?0)l0ul=O^{ly|@U#3mYs(vaO#oljU z^?(1fdwtRCE}vUnIMcm%t$TK{dvmc^i=%pTVr(*rqvGm~`Jzw5W>jtYNirRCTI}At zy0Uct`QwZIN7vx(Xa79RcD#M~9j_0bX?KXUrn%orN{-AO3sTnN%}B^0&LYZqRj{xX z_<~6X{b7laE@u?{stM_&JgC-VE}euWNi&Y5gKjkIr%OZ*1hG%6nRn8}Af&tQm9#k% zDUWIdJy`n;7%|Jo;g{?KA+)wOM`p1QR8L529|bIcO&$hPdu%d=$(tJ}o!mkd@;Wi)w*C zT^`%e0Mx0Z<=5Du#>~5-0RaL^Wo0e5Fv*7+>G+}6Y0-$IGDbbtIxUB)wFawAZDgeY zZzMJdTh9}h@ZF$p!$JoGVu6?>dqD{80q|hW-qO?l)ukG2-T2nu*bkQE7zm*u(jAiQ6Z)jFU;^fZj|z(#6zb)s z-X_$p1Ny=i4t3h34ewvjX0@g^OKy{I(Hr-K9K@hmB$_o~4V|&deydqdb8!F4&AXXP zFYIyBHyFoh=D zG6U->^T%OKUIDS589pF%VNl2fVlPZ;;8-%#JZ#Fa?RW0?Z~e;mfI)iel`z3(JO$}k zLxe%e+5#yeuVCXAYATpbp(4tTs%#v9Jt`j0P{c*50F$ssXp@9H z5Qg5-A{}PNTxJ`Y)qrTKydxX!>$5o`tXT+?AEbt`sd+@hvFZpH=x9+J=?Dj_?UaIM#x5&tfGbXt)@snc6oEccNM?_G~tx$&~CLF`5}Y*9Bc>G@s>0a z!KFD4H>+-`DoI)#kYF5HsL)aVYyoxCd-q5f(==d5@gGP1yO>(uIzaNerw<#hQyB6{ L!SRSYSRnrcSg2R$ literal 0 HcmV?d00001 diff --git a/__pycache__/config.cpython-310.pyc b/__pycache__/config.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..db7dcf9438568568419b2b8e85243de852570a5b GIT binary patch literal 1280 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 literal 0 HcmV?d00001 diff --git a/__pycache__/utils.cpython-310.pyc b/__pycache__/utils.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1a4d97e0672645807ab0e74dd7550897cc132a99 GIT binary patch literal 3610 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 literal 0 HcmV?d00001 diff --git a/modules/routes/__pycache__/api_items.cpython-310.pyc b/modules/routes/__pycache__/api_items.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..24097df3e466734485bb7749710d64dac62314ca GIT binary patch literal 4119 zcmb_f&2Jn@6|bu9p6Tfsk3ZtX&VB?Fa9{%V1PEVYFiA+lMl4Qy^}4FM zUj5$hSLJAI%pvgm>(q}o@0AJpJ2r-YCN!=?iT?(MlRDv)vw+qqJdJ>btj;L<%)kiE zx*1w^E6mk%+Ghp%(5~CMo(l@0Q+L8*y%?72B}#hCLkMjxbpVEGZPxk#&{EYUW>HDYq{qo?|$_3m;dx}+ z_GGN_VZ1wAg?d%jtF;Dvd_9souFsbm6xY=MS@6VSK#BhV zCIMVh@&V!OcgCw^k0vyw`*e>bY}4qP+~8)9adV698L1&JaEs@jkd)m51O|QbfD3z{ z_D2-B10x(5VP?p@Po7e4Z!vi@u~Npzc=-w8tDKI|eQ7P?1}eh~0!6Qk#K<759F!G|@ij2(Bqcw0_8_t@WGAOR zCRs{<%^o72Oy#%z*k238>H$^8x=0R~VvAQ4^$&2-ocS&@X#E0c@3(ZCrF ze~2~~y(5>Pl9Db-X%8?2L`a9o$rQK>7>r|%b7KWChP^SDAtf!y+=furwl5yV%G?p2 zl$cVA$O(8r5BgXcTVh8U+g_k|EHme@lO20a;lf*N#Wom++H``NbobR0f;;Rz0w{iM z0O(a{;PO#odaOhsVX>tXb)U9p`fUpn7u!5nBuxw^zpM&=?6&<@OYl3Y)b6aoo^K$- zgq(v}mD7*{8r<~~9btvZN$|@8m;)+5i*-zh;qYpK7p`${3G*xlZ6qZKu1wiK85HxA z6N5Y)Q=#%AjHu+5+44dmU&pyWgXRlp5GZ*8jB+|{TqQ2-QyYW0V#>rQ(NAG(p3;2` zmo8_^{35synEX6ER37uiUE4VdKvuwyi-<8_9H4_<66(~p0L`i7CGNb;qd}QhrYF~9 zy)P<<(+Mt7P%4%x4ylfEGM+a508&TSRdK`T!Ue-cOD^JsdNaR_HOvl)5sX36q@7?k zoq{we!`~F7jBQO&J8yq73-#TLr-@y)hTqb%H%tIrA+BD_-kVT4CVLFB2C`+(NI-y^ zaAjLNCdyaEUY13eQ4s@{nRag4bRR#q0?gqU_XXjc1vmjjDsSrX_wTK&!ts|61;`_h zM|KWF!t#A6{d1~Idw4#t^;?4LJ#(z+x@n~i@NRf+a*4x+ogWH%*S=R3~i%ZLG)h(Xs;?`Lp+w4c* z6?dVL5REL{I7W~)09gYlX(r|nCCvdPt<;JyCDtezPi3XRGk;&5k7Ena{ea8e{J z;sj$gPRZthAO6V*~A)R`9pN0o@qcUxgnx1qj$hoc>|kz!N@IvKo-G1}->g^Fk54ozv^*Z!AOxzLa5sY!w9{yaI9?sr z%1^QBm{gv)??YcgqUhs0JM$b`qVg?V(&hhr%vJlB*AYZUjynl6orcK&a@?gR{6C-- zvqa!#4w{Mg^}g~Mynw#*ggYPVJAI}2|K!%sAcl-vml35TT3-(`l-z#&{{_di!ome- z6(_?6@Z|)CWp_R;kk_&2G1APOvVfmJ-xx2%M<*Q;XNt~Va8|9* zRx|M8Es4a*Sf4Sx5w)8Bx?UTodg2FhCIWg*co|i;>*9^kb(M{$aO|$Nm8Ji$(3dEE zz-s-K$XcCDdKp@xiqU=f5| literal 0 HcmV?d00001 diff --git a/modules/routes/__pycache__/api_knowledge.cpython-310.pyc b/modules/routes/__pycache__/api_knowledge.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1d885e31930ea02935a06825fe9b0b9eb653a473 GIT binary patch literal 3676 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 KqlQr)=l=!PXkbbJ literal 0 HcmV?d00001 diff --git a/modules/routes/__pycache__/api_pin.cpython-310.pyc b/modules/routes/__pycache__/api_pin.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2548ab4a644aa146c9a9d796f613754d94e62882 GIT binary patch literal 2797 zcmb_d&u<$=6rP#gwRdgDO_MY~+hCwAL{PiX3WPABrD;o~HZ3G@u!L4y&)VM9>vd<> zEwLO4+6bDiSO0+u3ht-uvdgZ{7xD zV;KV1-xHr~&RT^0gD<0(4lftr4i_mQoKy&>oHeP>D$Lg^ny*)MikQ|k{8T07rz>gS zteC!4u@tU1Gk&&`^>dXRB`)KJJJx5FJWuiTeNs8XO>V(++|6$uQ=a>t@iCsi zPx`bnq3|OKKF*ISd{W^P2|mfE6h5W!V+lUZXB2)+;j;-o$LAG3t?-2eKh94md`97m z3H}l=GrRDC zENRmEsM&Gb!fQn`E!;aDH-y1v7__|F){-u>*Ke#`zP4^(S-o~yT32s=HXL3`hUUt} zjf?im>ZeOgTFt=WHg_UNTA_2-jfZKc?b&UwRn;));43`aNVh81qz_M0$_(v_7K* zR+xy*5pMm=`V_K~S*wC{l8eCzNt}cGNde5)K;(<;Htj*+Ir1&J%>?Vw&j}@W7zYPC zOfrwJ?WjTVtfbx!m1!?>ecR*W2zYpEml}cZmV&n1sy3Z_rD8I=7l_+o+o`%|8r}0z z!>$J06(xn1+KzDiGmXxzGwrRY5wuEvz&lMhEQz2K!DEodVtY$k<+|H)zif-;F{F)& zWM3_k?xGz9^?K9AbQjCbpz1Wkg*D3;_p`NF4%30z*ly?nVO7>5d_-nuqb6s3E5CTh?twUbJPm9N(1& zrX`d*K2&PNB+L;gOPL+vngt-tgE8qW)#)^ypc%NuDS!@_%_e;PKV-wrnS+F54TO^! z2q$~Ea6}HM2&_fC%W)j3t)d>(e#JD5X7CM7_qgqFZr}CXdk54>%;LN`H1lAjf%8Iv zvfV`kH4?}1>uEG6&=k<9V9zpaB{4AJd-6LK=l6BMyYr|l6r0-&OJ(&0B`=pi5K_N+ zV|`-@^zFMKNgnPwI!Fcea0%`wn1P5yv}INrkf;4 zPNBdD`iT# zky{VMmZDM~bR$*6DrRqZVW&$HHH!FG zkoqc|WY~ZSOI1~OG?^WV9ru7tya+qP{%uW;OE?hEaFs0FAvs|5=)5g|8esK2V}De6oMl@k=7Kn(~i wh`{V9W+S_JCL$A?CH$e6u@QzSGo4Invvizhn5mhWd^SV#+Q^+68Ebj^FP!dk>;M1& literal 0 HcmV?d00001 diff --git a/modules/routes/__pycache__/api_search.cpython-310.pyc b/modules/routes/__pycache__/api_search.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..fb3af0ab45f441c34a778073713354549e4af489 GIT binary patch literal 3054 zcmb_e&2Jk;6rY*>@OtAoj%x~~r38d3j7SWnY6}W!(l+tg3_#yVM}<(#ruU`hM7vJ5Iq zA6PPezp~{0>@+D3G@gZ}*uQHd%3L2GFI)^&RadPz}}=__F) zsPk$~$P^E5H-ZEj3rSq7&aD&;+4tVfiOCz&&O6s{Ov?1NTOaN=ulAY)SI1{2uigCM z`ee5+`|i}uk8ey)T$@yXD^i&bW7l_lSGdx4>s2QST<*;``%0jcI*Nzu+5Iq_CKRlb z76?HW=oZ7Ew%L}}CR=)&d_guy@{}+t1b@D^sjbmzB21B5qpMh3P*bSWP%~kCPUfhu zLm;gdnSfv_-Bdd5=@@9M#Zce%ShS`jy)DVMCe0}JgD{bLrQQJPf%GUWZ}(%+NI^LU z<-r7q3Tcr~POs7y-2zznw9WX?22mRGHP{PnlO>Xz?%MP{8)q&0HM`B=C=HofswUOh zFqn~g&5Z)y53Xe<<`uVAZMvcw*S49|DuIwj7%vALG&b^@q|r8&sl{MrIp+R0c{p2| zkE5Uz*MpiDy33`JUJC{+CUw^fhUc5-#JuCdK6y!5OLdpK(eQj@cDTMG=Hprkg3t(q zq{QQffNJkRN9rrm9u2FB@ZzXGR=_AAZwjP93zYqBvgYZ1qesKobHik8WbZFej3&>6 zpKXIf?gk-pYmGVA6Ad14ejEoej>wm^!cXC_(R28ZYx`m=dVQ3t~3H9}Ver6o9{0~A8Mh;xF8~FFAxxlGhg?~I z0LWt?c~*gj!h%t$H72YLf_2OEa~+Zv2dAW|aFs}U0TP5RR_cLF*LmOp(&L)c=jyMY z-@&l$AgOkcWfds!{c@?OWB(gx`3R^|hun2h$#ZH%aPQuD6*?|g?){A4AD13GYm7f4 zDR~uy;%NQ=M+tQwEkbz(?xZ50# ze+z{|?FDQhYGwZMeGGv;L5k#Ao@QyL3*%R7b(&i7Vk(&^HE>tEmvFM@=<~_6ZRG+0&UP zczXMP^E7s(C*&Ps8RMK}K(q*4vg(NdhoVhM+v5S`M&EITx-8VjA=%JR4{cmpqoEtk z`tBH_F~LA*Nb}^8f$of(DZ+gV7c0J*mI9sxJD6*Wrp$C+2ylTm;6-I4FL&GcTIjZO z9;~Yp^D6MIGjd?D7B7c^UkSQ~eoX6$a60~g+eh6Vm`HdUg(9^U1~q9WF^5eTO+J7f zim!vvf^hUEmFeDeGTVJybZ0sonshG;XTeE=u(1?-k-=Huu!)xv{7kBYMTeBe9$63h zM=)@zcub}o$B#Y7k;Yu;CW{<{+sRXE$)*?A=Bky$*J5vD(rAckn5f-L%W?4e1J2T& yN24=aSD8!%9MgnKCTiw=yXY|qPPy}P8AIf#%T*@@?G)rCn^~Gotpb$6Ed2+9`ngL0 literal 0 HcmV?d00001 diff --git a/modules/routes/__pycache__/api_smart.cpython-310.pyc b/modules/routes/__pycache__/api_smart.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7bc055e8384e61169cc5ab0e269f79671ff2af8d GIT binary patch literal 6017 zcmbVQ>u(&@6`$Ac&dff%e#Ry*lVHdK_R^MCK;4u;c%&kR61RmdbhOz!wl~>V?##xq zH7kWWQGf~wBt+E`s->BwmlMsJS`I1(pzjJ1H{U8Y1mFC6jm{D8=@d@sxI?8)yEce8w4XvdV?RC65mx3B){gKH}vU;Eu}um0xM z{MGkAyz+88e{J=hE9cLTAA0JDy^b}?Oim3=QS@EETy=ALXgySEx(!*b`C&r3r<$$@ z=7d+TmFJdnMwmSM#?VP)MX#;vF71Jvxl6+N1o1Up;f6Dg@f&j zq2(1%yUaqKX%waBI*Vn0!KqZL;n=+EJCUp*>(z$u_-?gPfm)$eY?K|ZT9kf?9IN}w zf=S@gad~IpXui@`SCy6#7;TLlZdGf=nAhhO@bMt#?F!=FE?*ahh?Uh9RmA6DEZ+#g zw-SErf-X>h}?Nz0n6n(2|V2bRtBKo(;psD<25JPyR z&ue2!4fY9=V&Gz|)h7l6^Rz18o>%bXAoc|vQ?NJoQWZZHs6k={0gJC262oF7NCtX4 zy^3{ZeMN<{?P!kT4A#&7`qS5c-|;y1vGubbUi;*=(D2=aZM}EJ2=&QY-ZUWuhsqWxq7oE)?bHFK1*SfD73G<{qD8*-dX=Aq>{{aqkrPr$%*RZ zgczTA{DFz14@?{j?dTQ4Df(fGqp9=KwHQulsew2n0Py@`wITbliR=RjGu_AL%5Ft? zVLFOYuilg;oMpmmmN0s=@=mPIWh8xBXi_i}WQ0068Kd1OV}u55;7d|GjFl1KUKlSn zV0IztWJA4HUkpvpmvf|wO!B%)ebJSfWOdm&tSe>n-5c)KbZYR z?!s=8+&3J)>G5SS@)9YNWJJwO%s2=-#k8w`hW=3~q!0>e81NIZbB zj*A3?mf3+rBTyn>3lhS5CEhXtV3r?an6!oM#|g^Xrbq&80I~A%z!0eoU=f*%1^~|l z*ge)tMKE*%*;w=u^aLq_r!9M=L_Yv)05b$Xaf}AW6ux1IbjAG;=7%wkVBCRmbXoyi zrNkK4CFfOew}8{+F963Wu@k)APDS7tSY7VajGqRW*&Q$&@H2t6q5`CMU5tQi_ZNUH z%9#<6MgBx-hn*_Sc+KNIA1n(vWYhEORVT_{a)1^N5*Y$n)5GMZ#qtnMkdGiOQfhOG zLde^2KO^^p<_vj&R^*8EqH&!fNA3U#?UHoi{}j%%Vd8YzD<7}8aMtE=IQ9Z%S(l*z z4qbK^y+=c<>^Y5ct>y~kUJ0lw`A!7L@-Eu-Fi1|9chlyv5>Unu&CWV6*T-=!Cu!jn z5e{kAhT@u|SALT?LgvtDHert#(R)LE!963tL313>dd02f((*eb_%;!GvAmB60Z#O> zJ?qE^Afr0OYgT+uQXI?g6ZtL?Lhp!hG!As45vJ@SDXFt56uaSQBMjr88=Bb*yZFD& z_z1$!?1U?gw2Ej7*N`e_vDb1x;W}Zz=T1fk9U4zPd2AL%RHEu44+yV>b-f=MiZGGG zmCm~puE<-xa8;Stk@Gd?3~;)y!&S9FM{QyFs8N}JH}EZ)J8MZA(Q+bvfwNZlEPLVB{BmNnzFcv0vfrNup<}W?gJa)`!vm4 z+vAU2q8Ef=hBB<<*Bu}jRZZ+H6q(!oBujo0CCup91r~X?fkdg0;x9^wlmIEkMUj}& z5NV&w<5;-7pCc@?L4KM?yz^k5VRAAmN46A&DxRVbB3oRi-0LH_eCjo|6$9m|J|mxp zG>jc3yCOm!#GQD6!D;*3`=;j!x)NJf)$7?$_4x^z_eY0$5)s-%!0 z<$i`S)X_P%2wkyW5xVeCHu&#wis}yzSg9&0m1j$F*$1t<#Ty;%Gzq_`B$>JUqufA8rsMLKapXS!KnN6c zWZGN$PNk*!2u*Zxy038;hkgxRoX%aGf-VkSp|=mA920Sdfkag5v}5QPV?nGPC(wwx zMDXa?z$efx9t;xRL4GcRj}$+L8IeX;q;q#T!}A&5w~rwQ9T@sP3uTjy^26-)eaRMz z5}}~)`#DAn{T_{39*uT9KtaWwp@P0|i8@5|eKcm#*I*?;DaoacMJv(cJmcH#BuX(9 zP$C= z8wqU8?&y?BqciB`sCsv9#HOgs-x7{=YII7JdgU+?YI!1u83VV5OxZc_NJzO`?ge>? zm~oKh178R}dg3N+5yR_p<_Kmt+9P=@ZN$|?uUgxv#3JC_M@#k-A^70ROHL4XJCQqx zP+2tFDT%m4koQA^9*5Ew_cJn29D}Jr+(v!Gr4d&vT=|eqHtHiTgiup4jGn?&Xh-Ix z<|e9f=uO)}nE{vU9_qE^G?DKSIY@-7B2L>4y5)js_@-t&k9m)t$)f(DwuIV~E-rt0 zgObrk)cAi)BWg{us`RkM^6+M~jvyN47eU*WADQQ2T-V7k6uQ7?ZAITeXIa1mu!f2( z#^y~3!(YW8G`R6WROB%tuhF(-;FKnt7?uY&5c#VWl0F{kqOkla-E@>76uzkv{acj) z`u>rYo+h#g(oulX_kU1;5LZ42(p7*E_vv%M~w* z)K2eFsq()MGEMWQ>h=#p_qCKZN(_UFRR*`soN8o+if*t;~K)HZ@Ttx;`NOB EU#RP^=l}o! literal 0 HcmV?d00001 diff --git a/modules/routes/__pycache__/api_upload.cpython-310.pyc b/modules/routes/__pycache__/api_upload.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..52012ebe69967335592613d77fb14f038ec6dea7 GIT binary patch literal 2112 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 literal 0 HcmV?d00001 diff --git a/modules/routes/api_categories.py b/modules/routes/api_categories.py index 3a7ec16..9e83f1e 100644 --- a/modules/routes/api_categories.py +++ b/modules/routes/api_categories.py @@ -2,10 +2,11 @@ 分类管理 API """ import uuid +import json from datetime import datetime -from flask import Blueprint, request, jsonify -from config import CATEGORIES_FILE -from utils import load_data, save_data +from flask import Blueprint, request, jsonify, Response +from config import CATEGORIES_FILE, DATA_DIR +from utils import load_data, save_data, load_config cat_bp = Blueprint('api_categories', __name__) @@ -70,3 +71,271 @@ def api_toggle_category_visible(category_id): category['visible'] = not category.get('visible', True) save_data(CATEGORIES_FILE, categories) return jsonify({'success': True, 'visible': category['visible']}) + + +# ─── 导出分类相关数据 ─────────────────────────────────────────────────────── + +@cat_bp.route('/api/categories/export', methods=['GET']) +def api_export_categories(): + """导出所有分类及其相关数据(子类别、参数字段、关联数据项)""" + try: + # 获取所有分类 + categories = load_data(CATEGORIES_FILE) + + # 获取各类别下的数据 + export_data = { + 'categories': categories, + 'export_time': datetime.now().strftime('%Y-%m-%d %H:%M:%S'), + 'version': '1.0' + } + + # 加载各类别数据文件 + # 内置分类:AI模型、GPU、CPU + models_file = DATA_DIR / 'models.json' + gpus_file = DATA_DIR / 'gpus.json' + cpus_file = DATA_DIR / 'cpus.json' + + if models_file.exists(): + export_data['models'] = load_data(models_file) + if gpus_file.exists(): + export_data['gpus'] = load_data(gpus_file) + if cpus_file.exists(): + export_data['cpus'] = load_data(cpus_file) + + # 动态分类数据(每个自定义分类有独立的数据文件) + for cat in categories: + cat_id = cat['id'] + # 排除内置分类 + if cat_id in ['ai-models', 'gpus', 'cpus']: + continue + # 查找该分类的数据文件 + cat_data_file = DATA_DIR / f'{cat_id}.json' + if cat_data_file.exists(): + export_data[cat_id] = load_data(cat_data_file) + + # 导出为 JSON 文件 + json_str = json.dumps(export_data, ensure_ascii=False, indent=2) + + response = Response( + json_str, + mimetype='application/json', + headers={ + 'Content-Disposition': f'attachment; filename=param-hub-categories-export-{datetime.now().strftime("%Y%m%d%H%M%S")}.json' + } + ) + return response + except Exception as e: + return jsonify({'error': str(e)}), 500 + + +@cat_bp.route('/api/categories/export/', methods=['GET']) +def api_export_single_category(category_id): + """导出单个分类及其相关数据""" + try: + categories = load_data(CATEGORIES_FILE) + category = next((c for c in categories if c['id'] == category_id), None) + if not category: + return jsonify({'error': 'Category not found'}), 404 + + export_data = { + 'category': category, + 'export_time': datetime.now().strftime('%Y-%m-%d %H:%M:%S'), + 'version': '1.0' + } + + # 加载该分类的数据 + if category_id == 'ai-models': + models_file = DATA_DIR / 'models.json' + if models_file.exists(): + export_data['items'] = load_data(models_file) + elif category_id == 'gpus': + gpus_file = DATA_DIR / 'gpus.json' + if gpus_file.exists(): + export_data['items'] = load_data(gpus_file) + elif category_id == 'cpus': + cpus_file = DATA_DIR / 'cpus.json' + if cpus_file.exists(): + export_data['items'] = load_data(cpus_file) + else: + # 动态分类 + cat_data_file = DATA_DIR / f'{category_id}.json' + if cat_data_file.exists(): + export_data['items'] = load_data(cat_data_file) + + json_str = json.dumps(export_data, ensure_ascii=False, indent=2) + + response = Response( + json_str, + mimetype='application/json', + headers={ + 'Content-Disposition': f'attachment; filename={category_id}-export-{datetime.now().strftime("%Y%m%d%H%M%S")}.json' + } + ) + return response + except Exception as e: + return jsonify({'error': str(e)}), 500 + + +# ─── 导入分类相关数据 ─────────────────────────────────────────────────────── + +@cat_bp.route('/api/categories/import', methods=['POST']) +def api_import_categories(): + """导入分类及其相关数据""" + try: + import_data = request.get_json() + + if not import_data: + return jsonify({'error': '无导入数据'}), 400 + + # 验证数据结构 + if 'categories' not in import_data: + return jsonify({'error': '缺少 categories 字段'}), 400 + + # 导入模式:merge(合并)或 replace(替换) + mode = request.args.get('mode', 'merge') + + result = { + 'success': True, + 'imported_categories': 0, + 'imported_items': 0, + 'skipped': [], + 'updated': [] + } + + # 处理分类 + existing_categories = load_data(CATEGORIES_FILE) + imported_categories = import_data['categories'] + + for cat in imported_categories: + existing = next((c for c in existing_categories if c['id'] == cat['id']), None) + if existing: + if mode == 'replace': + # 替换模式:更新现有分类 + existing.update(cat) + result['updated'].append(cat['id']) + else: + # 合并模式:跳过已存在的分类 + result['skipped'].append(cat['id']) + else: + # 新分类:添加 + existing_categories.append(cat) + result['imported_categories'] += 1 + + save_data(CATEGORIES_FILE, existing_categories) + + # 导入各类别数据 + data_mappings = { + 'models': 'models.json', + 'gpus': 'gpus.json', + 'cpus': 'cpus.json' + } + + for key, filename in data_mappings.items(): + if key in import_data: + data_file = DATA_DIR / filename + existing_items = load_data(data_file) if data_file.exists() else [] + imported_items = import_data[key] + + for item in imported_items: + existing = next((i for i in existing_items if i['id'] == item['id']), None) + if existing: + if mode == 'replace': + existing.update(item) + else: + continue # 合并模式跳过 + else: + existing_items.append(item) + result['imported_items'] += 1 + + save_data(data_file, existing_items) + + # 导入动态分类数据 + for cat in imported_categories: + cat_id = cat['id'] + if cat_id in ['ai-models', 'gpus', 'cpus']: + continue + if cat_id in import_data: + data_file = DATA_DIR / f'{cat_id}.json' + existing_items = load_data(data_file) if data_file.exists() else [] + imported_items = import_data[cat_id] + + for item in imported_items: + existing = next((i for i in existing_items if i['id'] == item['id']), None) + if existing: + if mode == 'replace': + existing.update(item) + else: + continue + else: + existing_items.append(item) + result['imported_items'] += 1 + + save_data(data_file, existing_items) + + return jsonify(result) + except Exception as e: + return jsonify({'error': str(e)}), 500 + + +@cat_bp.route('/api/categories/import/', methods=['POST']) +def api_import_single_category(category_id): + """导入单个分类数据""" + try: + import_data = request.get_json() + + if not import_data: + return jsonify({'error': '无导入数据'}), 400 + + if 'category' not in import_data: + return jsonify({'error': '缺少 category 字段'}), 400 + + mode = request.args.get('mode', 'merge') + + result = { + 'success': True, + 'imported_items': 0, + 'updated_items': 0 + } + + # 处理分类 + categories = load_data(CATEGORIES_FILE) + imported_cat = import_data['category'] + + existing = next((c for c in categories if c['id'] == category_id), None) + if existing: + if mode == 'replace': + existing.update(imported_cat) + else: + categories.append(imported_cat) + + save_data(CATEGORIES_FILE, categories) + + # 处理数据项 + if 'items' in import_data: + if category_id == 'ai-models': + data_file = DATA_DIR / 'models.json' + elif category_id == 'gpus': + data_file = DATA_DIR / 'gpus.json' + elif category_id == 'cpus': + data_file = DATA_DIR / 'cpus.json' + else: + data_file = DATA_DIR / f'{category_id}.json' + + existing_items = load_data(data_file) if data_file.exists() else [] + imported_items = import_data['items'] + + for item in imported_items: + existing = next((i for i in existing_items if i['id'] == item['id']), None) + if existing: + if mode == 'replace': + existing.update(item) + result['updated_items'] += 1 + else: + existing_items.append(item) + result['imported_items'] += 1 + + save_data(data_file, existing_items) + + return jsonify(result) + except Exception as e: + return jsonify({'error': str(e)}), 500 diff --git a/templates/admin.html b/templates/admin.html index 44353c6..eb01437 100644 --- a/templates/admin.html +++ b/templates/admin.html @@ -128,7 +128,11 @@