From 9fed469a4cc2a246f4f7c24258b850ce7bb58aa9 Mon Sep 17 00:00:00 2001 From: eddie32 Date: Sun, 8 Sep 2024 11:23:27 +0800 Subject: [PATCH] init framework --- .gitignore | 1 + api/__init__.py | 4 + api/__pycache__/__init__.cpython-311.pyc | Bin 0 -> 157 bytes api/__pycache__/router.cpython-311.pyc | Bin 0 -> 1085 bytes api/constants/__init__.py | 3 + .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 167 bytes .../__pycache__/base_enum.cpython-311.pyc | Bin 0 -> 1205 bytes .../__pycache__/status_code.cpython-311.pyc | Bin 0 -> 926 bytes api/constants/base_enum.py | 24 ++++ api/constants/status_code.py | 22 +++ api/router.py | 26 ++++ api/view/__init__.py | 4 + api/view/__pycache__/__init__.cpython-311.pyc | Bin 0 -> 162 bytes .../trial_sentinel.cpython-311.pyc | Bin 0 -> 2461 bytes api/view/base/__init__.py | 3 + .../base/__pycache__/__init__.cpython-311.pyc | Bin 0 -> 167 bytes .../base/__pycache__/view.cpython-311.pyc | Bin 0 -> 3483 bytes api/view/base/view.py | 68 +++++++++ api/view/trial_sentinel.py | 51 +++++++ api_entry.py | 27 ++++ framework/__init__.py | 4 + .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 163 bytes framework/inori_log/__init__.py | 5 + .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 299 bytes .../__pycache__/log_and_raise.cpython-311.pyc | Bin 0 -> 928 bytes .../__pycache__/logger.cpython-311.pyc | Bin 0 -> 2088 bytes framework/inori_log/log_and_raise.py | 14 ++ framework/inori_log/logger.py | 41 ++++++ framework/inori_plugin_manager/README.md | 4 + framework/inori_plugin_manager/__init__.py | 3 + framework/inori_plugin_manager/base_plugin.py | 14 ++ .../inori_plugin_manager/plugin_manager.py | 131 ++++++++++++++++++ framework/inori_utils/__init__.py | 4 + .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 175 bytes framework/inori_utils/log_utils/__init__.py | 5 + .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 317 bytes framework/inori_utils/scheduler/__init__.py | 114 +++++++++++++++ framework/inori_utils/utils/__init__.py | 7 + .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 417 bytes .../utils/__pycache__/base64.cpython-311.pyc | Bin 0 -> 3432 bytes .../__pycache__/config_loader.cpython-311.pyc | Bin 0 -> 1563 bytes .../utils/__pycache__/data.cpython-311.pyc | Bin 0 -> 2074 bytes .../utils/__pycache__/file.cpython-311.pyc | Bin 0 -> 4105 bytes .../utils/__pycache__/http.cpython-311.pyc | Bin 0 -> 3666 bytes .../__pycache__/json_encoder.cpython-311.pyc | Bin 0 -> 2909 bytes .../utils/__pycache__/utils.cpython-311.pyc | Bin 0 -> 3854 bytes framework/inori_utils/utils/base64.py | 46 ++++++ framework/inori_utils/utils/config_loader.py | 24 ++++ framework/inori_utils/utils/data.py | 48 +++++++ framework/inori_utils/utils/file.py | 75 ++++++++++ framework/inori_utils/utils/http.py | 65 +++++++++ framework/inori_utils/utils/json_encoder.py | 38 +++++ framework/inori_utils/utils/utils.py | 66 +++++++++ logger.py | 19 +++ main.py | 46 ++++++ static/.gitkeep | 0 56 files changed, 1006 insertions(+) create mode 100644 .gitignore create mode 100644 api/__init__.py create mode 100644 api/__pycache__/__init__.cpython-311.pyc create mode 100644 api/__pycache__/router.cpython-311.pyc create mode 100644 api/constants/__init__.py create mode 100644 api/constants/__pycache__/__init__.cpython-311.pyc create mode 100644 api/constants/__pycache__/base_enum.cpython-311.pyc create mode 100644 api/constants/__pycache__/status_code.cpython-311.pyc create mode 100644 api/constants/base_enum.py create mode 100644 api/constants/status_code.py create mode 100644 api/router.py create mode 100644 api/view/__init__.py create mode 100644 api/view/__pycache__/__init__.cpython-311.pyc create mode 100644 api/view/__pycache__/trial_sentinel.cpython-311.pyc create mode 100644 api/view/base/__init__.py create mode 100644 api/view/base/__pycache__/__init__.cpython-311.pyc create mode 100644 api/view/base/__pycache__/view.cpython-311.pyc create mode 100644 api/view/base/view.py create mode 100644 api/view/trial_sentinel.py create mode 100644 api_entry.py create mode 100644 framework/__init__.py create mode 100644 framework/__pycache__/__init__.cpython-311.pyc create mode 100644 framework/inori_log/__init__.py create mode 100644 framework/inori_log/__pycache__/__init__.cpython-311.pyc create mode 100644 framework/inori_log/__pycache__/log_and_raise.cpython-311.pyc create mode 100644 framework/inori_log/__pycache__/logger.cpython-311.pyc create mode 100644 framework/inori_log/log_and_raise.py create mode 100644 framework/inori_log/logger.py create mode 100644 framework/inori_plugin_manager/README.md create mode 100644 framework/inori_plugin_manager/__init__.py create mode 100644 framework/inori_plugin_manager/base_plugin.py create mode 100644 framework/inori_plugin_manager/plugin_manager.py create mode 100644 framework/inori_utils/__init__.py create mode 100644 framework/inori_utils/__pycache__/__init__.cpython-311.pyc create mode 100644 framework/inori_utils/log_utils/__init__.py create mode 100644 framework/inori_utils/log_utils/__pycache__/__init__.cpython-311.pyc create mode 100644 framework/inori_utils/scheduler/__init__.py create mode 100644 framework/inori_utils/utils/__init__.py create mode 100644 framework/inori_utils/utils/__pycache__/__init__.cpython-311.pyc create mode 100644 framework/inori_utils/utils/__pycache__/base64.cpython-311.pyc create mode 100644 framework/inori_utils/utils/__pycache__/config_loader.cpython-311.pyc create mode 100644 framework/inori_utils/utils/__pycache__/data.cpython-311.pyc create mode 100644 framework/inori_utils/utils/__pycache__/file.cpython-311.pyc create mode 100644 framework/inori_utils/utils/__pycache__/http.cpython-311.pyc create mode 100644 framework/inori_utils/utils/__pycache__/json_encoder.cpython-311.pyc create mode 100644 framework/inori_utils/utils/__pycache__/utils.cpython-311.pyc create mode 100644 framework/inori_utils/utils/base64.py create mode 100644 framework/inori_utils/utils/config_loader.py create mode 100644 framework/inori_utils/utils/data.py create mode 100644 framework/inori_utils/utils/file.py create mode 100644 framework/inori_utils/utils/http.py create mode 100644 framework/inori_utils/utils/json_encoder.py create mode 100644 framework/inori_utils/utils/utils.py create mode 100644 logger.py create mode 100644 main.py create mode 100644 static/.gitkeep diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b6edfe9 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/static/ diff --git a/api/__init__.py b/api/__init__.py new file mode 100644 index 0000000..ec4839a --- /dev/null +++ b/api/__init__.py @@ -0,0 +1,4 @@ +# -*- coding: utf-8 -*- +# @Time : 2024/9/8 +# @Author : liuboyuan +# @Description : diff --git a/api/__pycache__/__init__.cpython-311.pyc b/api/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..44fef7987f10e660227807e71a39bd701ce2476e GIT binary patch literal 157 zcmZ3^%ge<81g8Y=rX>OC#~=<2FhUuh*?^4c3@Hr344RC7D;bKIfc(!O$zKM}RxtrZ z`B|ySB{6Q9#mN~tj_Ij+B{69bc0p!LA`r*NXXa&=#K-FuRQ}?y$<0qG%}KQ@Vg(ui WvZ9zDNPJ*sWMurn03(W+fnor=btLit literal 0 HcmV?d00001 diff --git a/api/__pycache__/router.cpython-311.pyc b/api/__pycache__/router.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6cc672f06b9ffbd939418c97aaac7d98fa36ff0d GIT binary patch literal 1085 zcmZ`%-Afcv6u+}Gv(E0aSSp!)v1mOkq#Fnt5`ldP^&pbHxNHo=&fRrvc6YclTLvpE zVX~r852At@TMuejnFW1V^f&B=kPHcdj%#lV(u+@>JDZa}bUF9j-#zEtd(ZuyGw=6% z5sWuS)?+_h2yM{K-r)X%ol5|wkc?zTMF}R%FciB~SAq?*HfB{W!H0Rk9A*_J?3Q`V z$ZlK}zWkBVC8jDO~p;G6vs(J zq#-5?F{WE1IHn9nAxmfQfLNG2bD*Y>;W!Y=Gy66Uq;ZSR?h3lq7=inSTtjSznSuXh zTr+5v9pW-5zyBTQM25|9bKqHYybKy|GOC;aG_c1SFf<1_EIN4rJ1nrkrAHvz8-QWu zX07=#YkbmLnJ7&xlorOUl}FnjmP!-L8`=9_JElXEh?EEb108`bRnl)a-?-X)vqw$q zTe(T=!TZh6lbt=+tff!e%g?OWPdC4g?LSuGtRp}}Mjw{GWUW_IrI&M?AK%(hyG$s3 z2C~_Dw_uHoZ;fWRo{U!B4-gzzbORGC2S_RnK<^InrpLx&LeflLF>pdR{gN#Is~@2i zF*zj}O9gpCX(0l&_%zAr7xi=uDrkC~a+{u5T2)2r)agk|N?^C;az~_xqy})*h;%7> zv|sI{y%332u%<+SjYuV{7VVx{tt1uNN19l%ky^N_8m5jxWzp|LsOju{=y|Bv*t*)- zT1GDZoUMw&shsa|-&+02LR~XR-d9<3o;AVuU1<0wG)xEceMKR(DufEQtaF~>>xJsJ zBG&76Vt!dUnvMqNMe7D6QilmAH pP}b1V!a*s!5r4Q)bGppB{I0C0?Da9{r)$dymVDG+{;TZF{s2M-I3)l8 literal 0 HcmV?d00001 diff --git a/api/constants/__init__.py b/api/constants/__init__.py new file mode 100644 index 0000000..d1d3be5 --- /dev/null +++ b/api/constants/__init__.py @@ -0,0 +1,3 @@ +# -*- coding: utf-8 -*- +# @Time : 2024/3/27 +# @Author : liuboyuan diff --git a/api/constants/__pycache__/__init__.cpython-311.pyc b/api/constants/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..97bb00f12aebc0dc9246ebeabb5a0ce61f3ed0b7 GIT binary patch literal 167 zcmZ3^%ge<81YtM((*l9?V-N=h7@>^MY(U0zh7^Wi22Do4l?+8pK>lZt^l9)6IyC5?r5r~uX^NLFn^Gb?i;^Q;(GE3s)^$IF~aoFVM gr7F`rv zMqDUvDxq%NiGsf&%Q`E;N9itQTy^C+Gn0}uLC}-T$$8!TefOK2cez{^(C&SGQG3q- zzEd(XJq@A~20h@wnF|e8VGIk@TtfC5yHr>VgUOEI&(S=?&Mk!Zk^fj(cRWl+pwo0Gwa|3B+LX-Gi zw|&u`M~q*uU;X&_<>#AE2X8wEA3i%M$%#=+$BY)x_24PgPg-lxXXQQ%^(VI578q#0 zaBDuTxNv;=#--|A>D7f3RBvtg&Lj8Qx@ZQ~S`xQ5sy053*YpFs8Ti$QNX8P#s?^#H zHOJ#(D>oupqLkiPM6Lth=9hN124*25Didr;<(TaX29s<#E6{jssDVR|Mm*P3gdfc|%w3D$c?m1XCTheO@8EnQX zhQ_)G0wH6desYdPWBQ*-a`XoLZFHTJ&%Ra|XoY<}H&mE@ZV2d(R50@0`$@q7BinsI z@hUY}skt~RU^D+e>u95Rw^;0$TDho(8eK|Bmntqvx>?BtU6o_=N+QTrc^*>|+P{Nt fs4~WeSzyZpI6M9w8Vd|zrrmaMMAhFjS~1)oEjjZ5 literal 0 HcmV?d00001 diff --git a/api/constants/__pycache__/status_code.cpython-311.pyc b/api/constants/__pycache__/status_code.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2b719b412db3ca384b4f53e34e4dc8925a7a1233 GIT binary patch literal 926 zcmZWn&1(}u6rb7MY|^x;V5<@7!4Ev7hJYubsIVq!8ryDa(|T9}L(FV7HrcesVCp$3#;?-=J$SYes5-X-fNG?ji6oc z`8hSsA@qwmttK|X{xtwgh$4zJD2o-08RjxvmRER;RLr3WqWm19g37P+2yMV@v~^fE zS`JbK>WCwsSY?b4TcV+*XAKpQE36sWt4Uo=wKoI6O=mvc&yfN@LNT`A@ca&wloF`}2>A`OU|rPss=w zT@baOENp*Yv5Su@^Q*w0KFn8Mec1iD2K*Vuvustv+;R>|(UHmVuqBSfBC*K{ z%QF!h4$CAe-;hS4A*;Iy$e1)PjmE8>#!7-i;ovY~;&8}v$}tj>CZsoLAHEeGTn-K- z#`3v4YO0VJOzWxJ8R?d)6%tboJd;i&VWx7LUPx*MJpoI>&`AoOCNOh1&q}OrSQY96 zV9a*k68cI)-&XfIGg7V_Pro@>?(H{6%g6ktTt0cRBzS8gI^s7Ytmk`L$z-3y5>%+D zJS#-Y3s(rVuMoHiWk%{zp(V((XKmDBguH)` lGV+%W54acSs&SpzUqk1bk!_K+m|Lm<_<`2I>6fXb( literal 0 HcmV?d00001 diff --git a/api/constants/base_enum.py b/api/constants/base_enum.py new file mode 100644 index 0000000..f92ad5a --- /dev/null +++ b/api/constants/base_enum.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- +# @Time : 2024/3/27 +# @Author : liuboyuan + +from enum import Enum + + +class EnumBase(Enum): + """枚举基础类""" + @property + def code(self): + return self.value + + @code.getter + def code(self): + return self.value[0] + + @property + def desc(self): + return self.value + + @desc.getter + def desc(self): + return self.value[1] \ No newline at end of file diff --git a/api/constants/status_code.py b/api/constants/status_code.py new file mode 100644 index 0000000..7b320c0 --- /dev/null +++ b/api/constants/status_code.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +# @Time : 2024/3/27 +# @Author : liuboyuan + + +from enum import unique +from api.constants.base_enum import EnumBase + + +@unique +class Codes(EnumBase): + """API状态枚举值""" + # 20000~30000 预留系统状态 + SUCCESS = (20000, '操作成功') + FAILURE = (20001, '操作失败') + LOGOUT = (20002, '退出登陆成功') + TOKEN_INVALID = (20003, 'token失效') + INVALID_PARAMS = (20010, '无效参数') + PARAMS_CHECK_FAILED = (20011, '参数检查失败') + + # 30001~40000 预留业务状态 + NO_DATA = (30001, '未查询到数据') diff --git a/api/router.py b/api/router.py new file mode 100644 index 0000000..dffc8f9 --- /dev/null +++ b/api/router.py @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- +# @Time : 2024/9/8 +# @Author : liuboyuan +# @Description : +from flask_restx import Api + +from api.view.trial_sentinel import chat_api_namespace +from logger import s_log + +route_map = { + 'agent_chat': chat_api_namespace +} + + +def init_app_router(api: Api, prefix: str): + """ + 初始化应用程序路由。 + + :param api: Flask-RESTPlus或其他API对象实例 + :param prefix: API前缀字符串 + """ + # 遍历全局route_map,注册每个命名空间 + for path_suffix, namespace in route_map.items(): + full_path = f'{prefix}/{path_suffix}' + api.add_namespace(namespace, full_path) + s_log.info('注册所有路由 registered routers') diff --git a/api/view/__init__.py b/api/view/__init__.py new file mode 100644 index 0000000..ec4839a --- /dev/null +++ b/api/view/__init__.py @@ -0,0 +1,4 @@ +# -*- coding: utf-8 -*- +# @Time : 2024/9/8 +# @Author : liuboyuan +# @Description : diff --git a/api/view/__pycache__/__init__.cpython-311.pyc b/api/view/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3b05228f0347af0d8d78b7f427611435860c29e3 GIT binary patch literal 162 zcmZ3^%ge<81RsR%rX>OC#~=<2FhUuh*?^4c3@Hr344RC7D;bKIfc(!O$zP_u*uC&Da}c> bD`Ewj0u(!H5Z}A=`EAEd?b5VOYSOCIB68J2Kj0#y5>X@w5mE#c%hKuUyQF8%kM7+O zQWX?IKZJ*9kb+W`O1MGrJwqVnY;LEH!Tw5^X%-* zK4xcrJNrW<5+p#2@f+h;MMD0@PMf?N!ukRT^F$#Er;{R=`1qT*fhE%1a~hQCAEpc<@(+P%(J@h@;N68;YH5PVWO2Bxs0Ijesv4#wS2PLwd8$=R ztz1g+EHEk;Rih&3RpuSnR9!KwFf4QL{I|`S`P;vLe)r1P){aLML&@7;e&0OzUGwJ) zxBmEakz=8bH5tjHA8qn&259w^XPo{8ZNw+2|LR`It_NtHz zjB_E-UPBR8Y|CwQj@m%QDpE51!0h7>GB!qgu;)Pp0ZcuHs*f8Ot>l9v!3e33{ zx2|7res<~Zm8-XZ{rHfz9rVq=rkm%!x^?ZRI~UG6W1M?J{a{?=ncp&0T7vt={1w?S zCd*X8BcCWMQ(XW-blU)Ffq(!hKoA%Syo&mX4){dt=dBa#d1b>BI`pI1(xzNA5~9TP$QXVyiAMqDKzyWL$p#%yNy&D z2Pq}c1T>7dN=&FsDh9>~t`yydT2G~Hn5Sc%*h9@A*o;%aZ16>UzsS`i1FMn2mB?T< zvm8m+Bk38w0eZb2-Mt#!vl87?eQh~69hw8Px=p_x>sQ!H%H+{gpP<1P|=Ydb6ypB0;-VEhJb+Wob>#Jhb}+_@s| zTo(K5Vt9IqY2{Lfm&B+4M*&=qA2x3Z5yKOd}1AX&DmMMW^@$z%D_xqEi$v58aQGLgP9D86WBoDBdJH z!gL?nL|V2?)rsK{nlPnyTp##fbTau8Jp?+e55_fMErH`WI3>5gMxN>X8synp_tzi? zYu#Uiq-u}*ZYBn1-#!0P?Z`W|#PQ|C@p|HTjr88+wytu0D_r0C!DX($&O!F}aS+DM UY^MY(U0zh7^Wi22Do4l?+8pK>lZt^l9)6IyC5?r5s1q&Q_EwL5{pw~;^Q;(GE3s)^$IF~aoFVM grWaw6i($Y(+FLG z-!4Hxp}JAP{Uzyk1!&WS)t81nK#!C3tUj}fVx`2{s z7O?*=3Z)me1A~_Vzf$ZImFa~Gfl=N0Kt8#FcaSNJC8;njpUKF$Uo)LUBUbB{q)6H{;a> z-5n^byamWw3xNBRD8mVNINuWIoAJ-JFLI4(uF>EcGu+;D?74v%W|6B+le+gq#^9P3 zoB&GeI!uB>MWsN8D39o2eII}eNH4jrB$ad|;pQ*Vmw|evIASRe%#jI!J(;eks%dh+ zYBGwf%K-|L*#iu&f(CB~VA4^oANv6-C`iQQM5a)%TM5e}<6DczE+zYj*y8{u(Q@Us zyS|;7nq3*+&YX*>*px#6?$ORF&sPXQ4msT(ycKvuMHhk&u@vior{Dk^4_JP%2{`No zqnAi0!QjiS54)1oV9^#Qn509Yhpax{R%(e4EU%PXVUqMk^jpUS4RY)w$T>^oTo08i zdPLcJT#20f5#&5YIW$}1U!co;Ny14K{;E(OvcNPdy24YSY5VFuJ#u7NZNoT@hqr;` z+MnOb{%UUZowFe&w~(E2-bC-oBMxn6igNv+Bp-xw0OP$K;4T%q31%O0EMD?Oy=E$+m2tVW&E$J5%n=R$t1q z%x`}4(9GUNes`MRokNtnKI7kYX-BFv!*8A0xx_za@Q*F~ccuN`PWzjH>T6!`8@^_! zsSd)jV~O8m@O#QwP8l!$-0+=(YVjEUh9$ni;2VJHQf=DbK&I*W>-P*_57azMV2KYH ze4v!2^X8c0>x7!>xLfJHQzn%*e3dDWmLbPU zcx@->m+9_&J3@`1QTikrp#p3d(S5#Ac|G6X!B+#}uuz^p0=LQ-VsO76D80+<9cla42J zyq92%xT5$@W2x zIAmp)R)U0ybDK^(H@6JaGGfyYiQ$0|B=fo))3pQ8=);;s0z0-|4BncDWc>OlCa!9& z@_S^jNYbjWxn^7SKfvFIE>V^C34k0;QB=-@D1OpIzPsp2WuQ5 gK@CQE%^=YzuQ}&a6w%`ErX>OC#~=<2FhUuh*?^4c3@Hr344RC7D;bKIfc(!O$zNv9RxtrZ z`B|ySB{6Q9#mN~tj_Ij+B{69bc0p!LT2W$dYI%N9c1(PHW?p7Ve7s&kkBzyxJ{mIE@TGo&!2Fy=7iGDa~ng4j$sOu5Wa%s@7C zFoPz`OGcm~O~zYnKKbeCsYO7Ra87=Dd}>iqeo=g4UP^pXVrFrwpC-#KHlR3AMG-Sl z!!2HrBDi!B3s7t&!)GAL@XNv3Dkh*PKPxr4B*rbXI5{K7F+DY}Bqj~QF35~YD@x2w zEzd8?j>*i+FUpJuniUftpP83g5+AQuQ2C3)CO1E&G$+-r2;@nS1B(rT#0O?ZM#c{u W42;qj7^INV4FJb9 literal 0 HcmV?d00001 diff --git a/framework/inori_log/__pycache__/log_and_raise.cpython-311.pyc b/framework/inori_log/__pycache__/log_and_raise.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..fd33c169f55e3db328abec9991763e81ac115d61 GIT binary patch literal 928 zcmZ`%&1(}u6o0e3+1;ewR;X=^AOs3E3)bF?2&NyNS_QR-5C}_Vl5V@nhS?38kV6p< z{s%1-At$YP>CuA+|Ab8mG%N^$C-D*pUV8G)uBrXNx3j-_A2aXG`^|hXj1-{!{&iGY zlmLDRV=T$P%4idneV{;z12s}0MCg(u6{I9kohnSG2`23*OWRhRI*f{XdH zeA}&;%8uoEW%;}SfQq`XM@I1vaVD3e?gn;8~ zEuMSIR$ti)l&wK3^LFWAv6ssAQ@KFNjj$j-rHDvV3st|>u>`57(VtOGDz?P1#gXH&&7Kp&*T5t*eVhOJg7`(qXeRyBXb`v3F); zBWqYB&}|XwLrX#k#6oIQw2;RZTJR^#mW3`Cgh1&-X&)@9FL~;@v+kGGbLXBpbH496 z=gxPs>_Y%Ye?3cg3kdzrKI(vviI;D32t7b5Qn@V3aS4uNv?uFHc-*%);Z?l}tl|Xk zK~qTO?;};%@gTGdy9NnC6IF59{U#X?(gao7>(~LmyRd7p)SwcQCT(}r`K@o&*KWfh z&~#7Gs>Nuv^Ayd_lUlB({}fICshaXhP1SQ9Dsde}1Aj7uC`W~?naOBmZcR+CtPI1) z8b5MnbYvve>abZ^;66YaN^mNIYI3SagIcDcmiIZRC=Z?mD$KerDX$wQ(WzkBNn20F zQhbX`5oj;$mw&sxvRg#Wx^6f6(IQ56qwWYTF&{4M0Ny>O5h{4>mVOkt_B!l<)o#Ob zoj)UbYrZX>+kIK*+VX*!tU-Zq*W=I`QBFN$fiHO5Cvsh|gLU6;PnyM3vu$EGRXgTwaM!iXuDc-f%0IFu*rt(Mg3*!s%`8j1Fer+-; zQEX}1G{r_Tr%@3`UjZ*vVnkZcYLr*CTlowPr1FGlhOMN{tf~lmelcC6SMioGuv>2Z2&jk-LT^02@Fe^w{Ozr$`Zvo@m!H4;%fvqZDgJZ39Ew#!u~Oh5 z_}b>`m-oK7_b^iq_Emy?hluMKIPeEHXC4O1{{D);-|_b!boV?KpZFj7w?BSj|&JwJbkUN@-^6ZSP?21Btijp(ce3sFEMfoJ3 z%pObR+4(6Y7N4C|=Ekp0l1pIvJtA+xi$oY=_tQmeTC6L8ij7qb_ddJ1FFQ99hv;?w z;+d%Cj(K7!<&wIgC<{@JTm;Tq_rh)6iolbMxT6rsX_l4DXu~ZMBcdB=vnlCm+N>st zp&OZ|EYy%05seU&G(<4#>_?m@d3T734B^RnhWZ#{_pNr^UZAKKRNV|IX2Gd=9EtL- zSJKba8+Cdmy;m#n7#Riu`+Hiy0Xp<@99Kmlr~Rp-j-tD&$X9gNi>^>nu6A80%7?yl z9Mtmv=pV-Ww<#Dw*k4-v)f;lWp{lQ|)VF0jzHr$WuCS-KIPn6DpT#%gPGF#nqZJ%= zaI^}n>5XYe?l0qk3LbFq0AtN;%)soG@lXX1Ie3V%T*GJ?U#{TGPW?HQ5$=I-?!o^9 De|5{z literal 0 HcmV?d00001 diff --git a/framework/inori_log/log_and_raise.py b/framework/inori_log/log_and_raise.py new file mode 100644 index 0000000..4ab50f5 --- /dev/null +++ b/framework/inori_log/log_and_raise.py @@ -0,0 +1,14 @@ +# -*- coding: utf-8 -*- +# @Time : 2024/7/8 +# @Author : liuboyuan +from typing import Type +import loguru + + +def log_error_and_raise(error_message: str, log_handler: loguru.logger, + exception_class: str | Type[BaseException] = 'general'): + if exception_class == 'general': + log_handler.error(f"General Error Message: {error_message}") + raise Exception(error_message) + log_handler.error(f"Error Type: {exception_class} Error Message: {error_message}") + raise exception_class(error_message) diff --git a/framework/inori_log/logger.py b/framework/inori_log/logger.py new file mode 100644 index 0000000..80dee80 --- /dev/null +++ b/framework/inori_log/logger.py @@ -0,0 +1,41 @@ +from loguru import logger +import os +import sys + +LOG_FILE_NAME = "app.log" +ROTATION_TIME = "02:00" + + +# TODO: 适配多进程 +# TODO: exception处理 +class Logger: + def __init__(self, name="inori", log_dir="static", log_file=LOG_FILE_NAME, debug=False): + current_folder = os.path.join(os.getcwd(), log_dir, str(name)) + if not os.path.exists(log_dir): + os.makedirs(current_folder) + log_file_path = os.path.join(current_folder, log_file) + # print(f'log_file: {log_file_path}') + # Remove default loguru response_handler + logger.remove() + + # Add console response_handler with a specific log level + level = "DEBUG" if debug else "INFO" + logger.add(sys.stdout, level=level) + # logger.configure(extra={ + # "thread": threading.current_thread().name + # }) + # logger.add(sys.stdout, format="on {extra[thread]}", level=level) + # Add file response_handler with a specific log level and timed rotation + logger.add(log_file_path, rotation=ROTATION_TIME, level="DEBUG") + # logger.add('client.log', rotation="00:00", level="DEBUG") + self.logger = logger + # self.logger = logger.bind(thread=threading.current_thread().name) + + +if __name__ == "__main__": + log = Logger(debug=True).logger + + log.debug("This is a debug message.") + log.info("This is an info message.") + log.warning("This is a warning message.") + log.error("This is an error message.") diff --git a/framework/inori_plugin_manager/README.md b/framework/inori_plugin_manager/README.md new file mode 100644 index 0000000..30f5354 --- /dev/null +++ b/framework/inori_plugin_manager/README.md @@ -0,0 +1,4 @@ +# Plugin Center Base Class + + + diff --git a/framework/inori_plugin_manager/__init__.py b/framework/inori_plugin_manager/__init__.py new file mode 100644 index 0000000..e4849f1 --- /dev/null +++ b/framework/inori_plugin_manager/__init__.py @@ -0,0 +1,3 @@ +# -*- coding: utf-8 -*- +# @Time : 2024/7/5 +# @Author : liuboyuan diff --git a/framework/inori_plugin_manager/base_plugin.py b/framework/inori_plugin_manager/base_plugin.py new file mode 100644 index 0000000..472932e --- /dev/null +++ b/framework/inori_plugin_manager/base_plugin.py @@ -0,0 +1,14 @@ +# -*- coding: utf-8 -*- +# @Time : 2024/4/6 +# @Author : liuboyuan +# @Description : + +from abc import ABC, abstractmethod + + +class BasePlugin(ABC): + name: str + + @abstractmethod + def run(self, *args, **kwargs): + pass diff --git a/framework/inori_plugin_manager/plugin_manager.py b/framework/inori_plugin_manager/plugin_manager.py new file mode 100644 index 0000000..5ebc5b2 --- /dev/null +++ b/framework/inori_plugin_manager/plugin_manager.py @@ -0,0 +1,131 @@ +# -*- coding: utf-8 -*- +# @Time : 2024/4/6 +# @Author : liuboyuan +# @Description : + + +from __future__ import annotations +import importlib +import inspect +import os +import sys +from types import ModuleType +from typing import Optional, Dict, List, Tuple + +from .base_plugin import BasePlugin +from inori_log import Logger + + +def reload_module(module_name): + if module_name in sys.modules: + del sys.modules[module_name] + + # 重新导入模块 + spec = importlib.util.find_spec(module_name) + if spec is not None: + module = importlib.util.module_from_spec(spec) + spec.loader.exec_module(module) + sys.modules[module_name] = module + return module + else: + raise ImportError(f"Module '{module_name}' not found") + + +class PluginManager: + plugins: Dict[str: (BasePlugin, ModuleType)] = {} + + def __init__(self, plugin_folder: str, plugin_name='plugin', logger_dir='static'): + self.plugin_log = Logger(name=plugin_name, + log_dir=logger_dir, + debug=True).logger + self.load_plugins_from_folder(plugin_folder) + + + def test_init(self): + m = importlib.import_module('test.plugin3') + print(m) # module object + items = inspect.getmembers(m, inspect.isclass) + print(dict(items)) + + for name, obj in inspect.getmembers(m): + if inspect.isclass(obj) and issubclass(obj, BasePlugin) and obj != BasePlugin: + obj().run() + + def test_update(self): + new_module = importlib.reload(sys.modules['test.plugin3']) + print(new_module) + + # 获取模块全部函数 + items = inspect.getmembers(new_module, inspect.isclass) + print(dict(items)) + + for name, obj in inspect.getmembers(new_module): + if inspect.isclass(obj) and issubclass(obj, BasePlugin) and obj != BasePlugin: + obj().run() + + def redirect_log(self, log_dir): + self.plugin_log = Logger(name='plugin', + log_dir=log_dir, + debug=True).logger + + def get_plugin(self, name: str) -> Optional[BasePlugin]: + return self.plugins.get(name.lower())[0] + + def add_plugin(self, plugin: Tuple[BasePlugin, ModuleType], plugin_name: str): + name = plugin_name.lower() + if name in self.plugins: + print(f'Plugin {name} already registered') + self.unload_plugin(name) + # raise ValueError(f"Plugin {name} already exists") + self.plugins[name] = plugin + + def get_plugin_list(self) -> List[str]: + return list(self.plugins.keys()) + + def register_module(self, module: ModuleType, module_name: str) -> None: + for name, obj in inspect.getmembers(module): + if inspect.isclass(obj) and issubclass(obj, BasePlugin) and obj != BasePlugin: + plugin_instance = obj() + self.add_plugin((plugin_instance, module), module_name) + self.plugin_log.info(f"Registered plugin - {module_name}:{name}:{obj}") + + def print_functions(self, module: ModuleType): + items = inspect.getmembers(module, inspect.isclass) + print(dict(items)) + + def load_plugins_from_folder(self, folder: str): + # Ensure the folder starts with './' for proper relative path handling + if not folder.startswith('./'): + folder = './' + folder + + # Get absolute path from relative path + folder = os.path.abspath(folder) + + # Extract the root package name from the folder path + root_package = folder[len(os.getcwd()) + 1:].replace(os.sep, '.') + self.plugin_log.info(f"Scanning plugins from folder: {root_package}") + + for file in os.listdir(folder): + file_path = os.path.join(folder, file) + if file.endswith(".py") and file != "__init__.py": + module_name = f"{root_package}.{file[:-3]}" + try: + if module_name in self.plugins: + self.unload_plugin(module_name) + self.plugin_log.info(f"Reloading module: {module_name}") + module = importlib.reload(sys.modules[module_name]) + self.register_module(module, module_name) + else: + self.plugin_log.info(f"Importing new module: {module_name}") + module = importlib.import_module(module_name) + self.register_module(module, module_name) + except Exception as e: + self.plugin_log.opt(exception=e).error(f"Invalid Python file with grammar error: {e}") + continue + + elif os.path.isdir(file_path) and not file.startswith("__"): + self.load_plugins_from_folder(file_path) + + def unload_plugin(self, name): + self.plugins.pop(name, None) + self.plugin_log.info(f"plugin {name} unload") diff --git a/framework/inori_utils/__init__.py b/framework/inori_utils/__init__.py new file mode 100644 index 0000000..ec4839a --- /dev/null +++ b/framework/inori_utils/__init__.py @@ -0,0 +1,4 @@ +# -*- coding: utf-8 -*- +# @Time : 2024/9/8 +# @Author : liuboyuan +# @Description : diff --git a/framework/inori_utils/__pycache__/__init__.cpython-311.pyc b/framework/inori_utils/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c945763ba7376d64f2dc5ad9565e77c8c359dc6f GIT binary patch literal 175 zcmZ3^%ge<81W}@Q(~^MnV-N=h7@>^MY(U0zh7^Wi22Do4l?+8pK>lZt@tC)bI z{H)aEk{Gwl;^d4R$Mn>^l9)6IyC5?rttc@!wLHHlJ0>$PzbG@lv?Md9I3_+mGcU6w qK3=b&@)w6qZhlH>PO4oIE6_-grN#U};sY}yBjX1K7*WIw6axStr7SrB literal 0 HcmV?d00001 diff --git a/framework/inori_utils/log_utils/__init__.py b/framework/inori_utils/log_utils/__init__.py new file mode 100644 index 0000000..d93af88 --- /dev/null +++ b/framework/inori_utils/log_utils/__init__.py @@ -0,0 +1,5 @@ +# -*- coding: utf-8 -*- +# @Time : 2024/7/8 +# @Author : liuboyuan +from framework.inori_log import Logger +LOG = Logger(debug=True).logger diff --git a/framework/inori_utils/log_utils/__pycache__/__init__.cpython-311.pyc b/framework/inori_utils/log_utils/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d2e4cf1a925d6e0841f94af7479593b46bc90dda GIT binary patch literal 317 zcmZ3^%ge<81YcjTNb3jEk3k$5V1_b2n*bTp8B!Qh7;_kM8KW2(8JHMS8B>_nFfU_d zU|0>r5Rk{NlY4qU62`* zR+N~VTAp8&9Ro40v?Md9I0k4`JcJb=pP83g5+AQuQ2C3)CO1E&G$+-rh#P1)$lb+8 uK;i>4BO~Jn4hBZq3k)*I=mr~4L)rwB3v3b>*(9!jkbDC(2o`YywE+MnKUFgT literal 0 HcmV?d00001 diff --git a/framework/inori_utils/scheduler/__init__.py b/framework/inori_utils/scheduler/__init__.py new file mode 100644 index 0000000..f2c46d3 --- /dev/null +++ b/framework/inori_utils/scheduler/__init__.py @@ -0,0 +1,114 @@ +# -*- coding: utf-8 -*- +# @Time : 2024/7/10 +# @Author : liuboyuan +# @description : https://github.com/josiahcarlson/parse-crontab +import datetime +import math +import threading +import time +from framework.inori_utils.log_utils import LOG + + +def cal_next_job(trigger_method): + from crontab import CronTab + ct = CronTab(trigger_method) + now = datetime.datetime.utcnow() + delay = math.ceil(ct.next(now, default_utc=True)) + return delay + + +class Task: + def __init__(self, name, cron_expression, func, manual=False, **kwargs): + self.name = name + self.trigger_method = cron_expression + self.func = func + self.func_kwargs = kwargs + self.active = True + self.alive = False + self.manual = manual + self.timer = None + + def execute(self): + """执行任务的函数,并在完成后重新调度""" + self.alive = True + try: + self.func(**self.func_kwargs) + finally: + self.alive = False + if self.active and not self.manual: + self.reschedule() + + def reschedule(self): + """重新调度任务""" + if self.timer: + self.timer.cancel() + next_run_time = cal_next_job(self.trigger_method) + if next_run_time >= 0: + self.timer = threading.Timer(next_run_time, self.execute) + self.timer.start() + + +class ScheduledTaskManager: + def __init__(self): + self.tasks = [] + self.running = False + self.thread = None + + def add_task(self, name, cron_expression, func, manual=False, **kwargs): + """向任务管理器中添加任务""" + task = Task(name, cron_expression, func, manual, **kwargs) + self.tasks.append(task) + + def _run(self): + """内部使用,用于运行所有已添加的任务""" + self.running = True + while self.running: + for task in self.tasks: + if task.active and not task.alive and not task.timer: + if not task.manual: + self.schedule_task(task) + time.sleep(1) + + def schedule_task(self, task): + """首次调度一个任务""" + next_run_time = cal_next_job(task.trigger_method) + if next_run_time >= 0: + task.timer = threading.Timer(next_run_time, task.execute) + task.timer.start() + + def start(self): + """开始执行所有已添加的任务""" + if not self.running: + self.thread = threading.Thread(target=self._run) + self.thread.start() + + def stop(self): + """停止所有正在执行的任务和线程""" + if self.running: + self.running = False + if self.thread: + self.thread.join() + for task in self.tasks: + if task.timer: + task.timer.cancel() + task.timer = None + task.alive = False + + +# 示例使用 +def print_task_name(task_name): + LOG.debug(f"Executing task: {task_name}") + + +if __name__ == "__main__": + task_manager = ScheduledTaskManager() + task_manager.add_task("Task1", "*/5 * * * * * *", print_task_name) + # task_manager.add_task("Task2", "*/5 * * * * * *", print_task_name, manual=True) + task_manager.start() + time.sleep(10) + task_manager.stop() + print('=== restart ===') + task_manager.add_task("Task2", "*/8 * * * * * *", print_task_name) + task_manager.start() + time.sleep(24) + task_manager.stop() diff --git a/framework/inori_utils/utils/__init__.py b/framework/inori_utils/utils/__init__.py new file mode 100644 index 0000000..b6a5a2c --- /dev/null +++ b/framework/inori_utils/utils/__init__.py @@ -0,0 +1,7 @@ +from .config_loader import ConfigLoader +from .utils import * +from .http import * +from .file import * +from .json_encoder import * +from .base64 import * +from .data import * diff --git a/framework/inori_utils/utils/__pycache__/__init__.cpython-311.pyc b/framework/inori_utils/utils/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b70e126a866b7828d842e33e78112a3815d08fc5 GIT binary patch literal 417 zcmY+8PfNov7{=eM-5j#wL3i>4NIiHG4SCkcewrdwv3lr%&9Bz^?h)lbr6 z33&1(UWDCtGHp|EFAw=WZ+QQ`2f;Sj_!)nuAC_Nr(nZgi)ulCWkU)YsWats0+V^)bW1A$%OrdZ1%$_RtMFqE(BPt{BE)bL zIXyrUQHH)LHc$|;@XXBsjG_!upeGwhO;D1$#>YKn3YQt1(vHK#^uiR49AiIuo3aN6tkiHEri z2bbdt&zXuorb^7?#(CTja2swp5lu?6!N%o;;qHkj@~$05dC#sL#d)_RoA1kroQg-H za==B*+jRqfU;326_rwwra<*HFq$7qq6_F%aGRmyQl0r4~(>C96pt8_5L z5?C6Xl8J&=yYl`ab{y|$*#8iFcaZ5cQm0+7wXi(oLe2#g~o!gD=+NQgeF~RDhO?Pq3y1CH>wFobm2(0bCR#hhUZ{6 zL{bH23wA4tB3a`JX`e7jZ`((6K6b(>z@mJLseFBilu zd2vf_wI*)U#cc(#DK9o@VzVwbXJ4P>S5I)O$!fX}N4Iv^gt{wLWljQs^n+FCmp6$S zflP1^Ib+Oe0oAr)>3Zi1xKlQ4INgG(upOSc9RNoWHj~a<;xI0CkPLQi_9hy|7=5x* zLdVcG91dX9*8_~fY<H%ipmqim*d*Git_|-nORuebt;$~~66wS-M#u!|GGL|r0rYl^-WIdHcFQsT@uVZTx zfH&0oN+SRSC-41y_s6>}xwj8OuT|~Q0r@>Tzo)>5@_b0++jYKuf@?Q-{ND{p{Gjtm5nbA~gPErfALw+k*o^MDWa5)Sany3op2EmYw#SI zH?Ng!qML4^t4odN*p9pkuW3PAYCI}&ycR&K3h97+NasTZ{!pGjr170P-#Ni`E;pW? z8Gi?n&divBm~`g7od`msB-8cV`SN)g&>4fyK%$xM*%=Y?Eu4R`en%Oop73*OgCPJn zqHRdw2AMPL2{Z^{c>;nML*Atsbl@{MQUzo>|J3adr!L)@{^;DJi{~Ex{KL$zHy(X@ z`Qi9a`^~aC{maE^^}VT^qtiF8JRJZ2LH7L$b5(OH0;SI%J00nhyHk<$sb+tvl7jOL;zh4j>r+In8}Tb z#f=xny|K7#2*o1aO@lqr=S=67)}nN>=$vFH$fX{wr~p~?L_ih7`Tnt5t$c%CzF`(| zuB~eGRLusxCXlPY)%abbR^Ou6w`eu3dQIzj;g8C7h05A|WvzN#t8CCK8)nO4g}H1I z{-RR;rm#5otkKh_PoFitIH$Y_N?vGbuVL@iaP8~L?)fpG;~SBFxtLYsJPhbJ;wA9X z48DZEVTYO0v|Uoyndj8?C0^$Ax#v{$C2NM+4D~fOJdc|R&87iv(Vm2d3CoT@lH;NE<2?|7dU?9hW9ny*v$bryW#yf6IQpyoTS`;J4k zp5)h0aO=%H0lARgbiiYMc(CAaW~nnXq*+7ETx7bKsm3*AWieV><~^;alhQz3-bX?} z(sZV10JAK{c(wvzA?u~TSvQA8@Bl21SzT_sNi79|#cRe6%p&Mit24(Xuma=#c#NGz mv{#G0MLE!e@!=xh;UeE*OgWaIhsWU0HoU}Q2$$tx9{C?$X!VZ( literal 0 HcmV?d00001 diff --git a/framework/inori_utils/utils/__pycache__/config_loader.cpython-311.pyc b/framework/inori_utils/utils/__pycache__/config_loader.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8c32f4d893d8af4338637fa120d8584affb47b83 GIT binary patch literal 1563 zcmZuxPiq@j5TCdIypGpZlsLh?SfVBcK_m58LMaV_ibCS1_$CC4(5~cF*1O7kYn-?u z@gWD-2<$?s4I$LMxD7t^1LR9cK~S@xQ%Px{2Nma(Q)hOy8>!Ch?(fZ;nKy6d&Ak0} ze*OX={c?5K_*Me=lO_o%W9IBjWDdXri@C7QDvS{?xzf5^kt1Gqm5M4s87$=qSn4r) zI>9fdie|~HP|#k}w7^2+mhUy3=G__>HpjVq`JY&<#3BXa;YRG0-7$zo5S zB3lxoV#$cArJ!Rq@p#*>SvIdHtH}ukA>()U3Bmyc6S`xRoZuHz2h3Dw!74mwD+P(u z(om~M@nWQku-%3ryZqZbw{BGLa=&HQgX&j~sIR#N!$uj+U{ zcg&5zaYZ%8*rn-45f|GJL)|nT&k0O(>q>k)aWch3Y~ZFMi?9vDs~`Q~{pjr|-MJln z&QJ(-iZmgrTa@%?$Q(ciT8RdZ(j-$6G9A{DrfaqeTt@{S!7L7;+_Zy&%&Aqv8G$J~ zz87kKn?^xf<@0$yha=A*Y+am60oRgLEFx^fY36eGyS>M|j}JG0)B2gxAXDn;B|eYJ z_b2fWYOr#M3ANHBj?yMebToF@FYgAz<%ivfa(SN4t*>t$t>CkXasqG`lb~GTpED*ZM|oVB~s6ZfIQG&wgL- zmUqghy3w8cLtlKUFCH%R^`(Kn)YF%S`dnAAB(;y^FFH#R;ga;wHj&`ivx|UK>FQ8dE=| z=@>LsEsfwj#NNqgVJ0-29>YvBye!-VfM*Scf2qT#>HZp*H+=FYA?w4bWJ5~q-vLeX4xdwLA#~u_7Cirqy#EA27~5JEBj#q=`a0h&wH1|#M!;P_uTWo zdA@w!=bq1-?<*@!2*&fjBR#*DAoPSRa)Zh$+clsB5sR*(PY_Fiq*z@Cve4ah&J^C@ zjmUaC0DeIv=DcA`LZS{{*%1bPIlty7BoxZ8ayH~0hG#jy(S|-9w1M3yJ*t;ziRx2* z_^zTndXb>Wj$L`)DYDeP+)|(=-DPT2Cn1SGlnVyu-qAz){C0sN=?ZPaaQ@|d4Jb7A znOMGKEa@dm(uJX3%lR6D4exrj2qk(sO8$U^peFlA4MlMcd&aGm5PUD4w+aB6%rLg( z8T{)^dhUMu_9}ibg_nXj8pPLPsaP~UHG%Kl*$Uiydgm&ZH=fAjCe_92aqx}-GwTo? zR`b@p{4D&1=1=SjLJ$X%B5U8rU9p;p?YB$m>%ZZLKj)nw1@=$xGIw#q_8~{VmlHIv zU)J$t2>VvCFZk@c2&5u_<&A$frtpoG)cR6-b_Gx0O2vMJ&9v{fW|oi1bE21bSr;B*P1!`00xde+%3Dh8*>4G4<9-zkVniPr-M=ag#gZFg~k z$gy@f9Qf)Pl!7As0YXO4Yml+V-?X4l zlr|(w8#1WE(6U*3FxWoRe)B@$LIxSj-cZH$Hs5*Q;O0KY-#R(s8(C-%4Mv+1^{0~c zr+g#0t}%2n$|ma0ChN{-5LMm0`O0gddVl+0Os)S?pmdfBm>x5Yj~FnETv~iR!JJMq zr{n6xu-O>uh@4C?ElH*&uFgy~vg~LE=~QeGzpOUVkG%>#_^ zc>3-<;3~|RicJ$TtJNT2R=-M5&f$r*baWA`adH5>!?{?+v;)pUE5=-Hd2(SZ2JJc`-3IjK8M4P@uK`kf zJGmhEI`T6-!p9(FlsSxy<-T5dOdeaXhI%8y;=qH>#1U)qh*cijG&27EQJU4OG!T6z$5Dh|`iK@)>Hx)LP+pv2s4gml_LgeQe*xpRruF~; literal 0 HcmV?d00001 diff --git a/framework/inori_utils/utils/__pycache__/file.cpython-311.pyc b/framework/inori_utils/utils/__pycache__/file.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8526d515cfb9bae4a7a701dfdf1604e9bcccba5a GIT binary patch literal 4105 zcmeHKU2GFq7QT0WJTs0BNlD9(h!_YhI7Ed2-A$uVnh?;oYNJXZt;nXbT#u6ub!_X- zxGrccva7U&Hfpo9+gL!g=`IRkDQwh-7IwF^@YF}Uvf5~*JQW94`(gxwQ4@iBG!IZo!-r8o`ZqPzALdII>6ZvMeZJoZWD1!;%i|a> zbJOJ*$^!OnAq!jF46MHFS_Ch+Kfv2u+^~g2$b8)vj>YvDNE%2yZU%?qQ7uAjDQQGV zP}gi_NRLK>vCv4wpf*%h{i*Lj*WfE8ek>9;2M_5+`1NSda3p394mo^69~>f}pNf+= z2K88+=)t6^M~y*;QhQG)j@wPl1GD~GQm0Ny12}-qMaBjoqiCVQKk@4iy5H^2G)(_? zR?jtb<{LV*Lg#&$Md9jSEP;US5#15kBX?gAs_c=4HC(fMu7%nidIqIAlUgi|V?vp; z&{{l#Hqs7vvr!ES&ea@v;g!XYPu>3K7q_on`Em3Q%u-h(1nHw{ItkMJ>{9Q}{N7pV zn!fwx-wQX!s4)zh647QL8Mc*Lw-4gm*ZHYvp3`=5)=w<}W$mQ_u z)peoS0`*`E6m7NuYKARRhX6JpNW#*xY(y z?d-bT=H2SnH(n+D9Zn+>`^!>#*dt`2JPVLOA zos<404^p?BPyPAi*^{&BZ+??GncMVoe$&g7zM=;;JwD|<7QzhU>8#Ygie%vDQ{(vTo)$+KR{%7@0I*N<-r;bPj3!Cw#rPqbMe%kW&dP z=vb}LVZt1SYJ3zOF3AHzau^IbRbhMzP*{RHs|vTTy$4uys)7T3iu-CPyJ_qo-?6}o z#7g+@PtsE7R2+3%auqymQy0(wZSnLCC^TR@AUT+ojBqFhwrxpw@MU{Ki9{r(*#gDB z-9*9OA2$!hlQHceA#q}h38Kf$fM6?bOg0Ztvn6PEL03oKqIA? zChc?vZUZwU7JaC}KYF0ZDdL(1|LTc>jFR(j$@{ky5wGl+9-d#X77^#)!N{aIzh>Rk zzBBv&xc{U5MTDDn%r~!{dhyJQndJEsx#qTfb6d8#ZMi7Y1w5>0Mi{wA%{`!`B3p@L zSb11$d3ni;d;oeZ?yZmo*`HmtJF^~$bLHecd3jH^d=+_6rxrb^am~1QdE6NH)_#na zU@OL&d!9s@y*=ysn|>d#H`fb2Ez->vp7JWD{AR{)#l2p1^U0Q8k-x=pz~2%u&{X#F0%Jn|F(XsJbtgVdD~YTN+k)kHT8@IYQ$td=7oW)mt=a zQ7?_kd7=KS0Ueivjw>WT1yu%@yBGfoZ4sJ@1EcD;T9RD2UXLx%uJo2J)m>cM9!nj# z)VQ1zA%KzjD@?v$vVJAA_|XlDWroedh3hp9mh>+*L!_n2FF!A>9-r${10K=@Q-l^^ z+Z%byB%!bwiblycDrF7ULn0&bHzRN=_1A=K`)h(?-5R>%Q2A_H0$?&$UPYb(n|t6k zE&+j7xXNjTEwg-1Y0oR|G`-vAqVPjs{m@QxTeGu)(PjvFvgl_3; z+%5e-(c!FCN~Wswqnms6i4NM;iS91`ZzuW*j&${to$$5-9$Nx8>7YuG&^4hEnwxClifLTdCG@Xl58O3rym4}5`bbV`%PUSw&JO>Nr7`&x{mnANw1fFh z5U~Gw?2O9VBZDaWftL`WdCx%nliWQL*OJl5bL2UYLH9()2_OJUjEgeD-cf~q=FzHA r_Hmh_2jgb}m}Me2VtTBsqE9vAHB?X{PkAx4I+tv8xr&T(EViEk&4@=- literal 0 HcmV?d00001 diff --git a/framework/inori_utils/utils/__pycache__/http.cpython-311.pyc b/framework/inori_utils/utils/__pycache__/http.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5e702961e377fd3b2438beab213bfcf8afbff795 GIT binary patch literal 3666 zcma)8|4&=j6~FI`zuVa1OMrZV?KE5s1Kq$Uw1X1{mnGA$E)# z;F#hVKfuEn7cz~R2h1>L7x+uefCXw3)K?1AHPJ{I_xp`k;a=l~JQDFamp*n}>Bv#@b1?Lf04<_!xWFRHe(QmXcLM zVq_jHFB#Su5@X`uiE(MZtW$0YX3($PnXjMHAx8YhYIqZmECq-~|v&RVcm+OF(Pn$(7}cFd&iF83-=tkgfl15>p{@X1-S5;G06 zkO{Wlk?oPw+YRe!AFEk{ayTpoRgI@&K-j>y0i(8XbZjUh%OORxsM44yM^%mMd9`0- zPCYS2)!}0=`dpd?GAbm!-KJUkw^bZ{u;leXI4~ko%@m_Q5_XkHWDAyCo%fKJ>#8F{};_7uykOa2O1U7iD^3PzuXb z8j7k?NEs|jH0+OzYgTLwjfg7sf@w?@>#1WE~wjM@PJCg|{UR{`%~tv+=Wei!1)Cyu0p7>~d`G)pT3deK_YnoZwfi zu7r?uq#OzOeQC@GGY3z>^S9TQhqFgJb4NRi{jB?R&V3qI*=tfSO!r^?>AxEeebI0z zJ(6wk=NkN3duz_#8b7n*XqXP(I+1mFa}Mt&VN3^BYHCxXb9G5MB`3Hq9q!c2b6m!; zH^cAUf+LZqQ-J`fYK<|0uuuo6F7<43EEKu z>ecYO%g@8yk}*G7K^>!}lI<8biZ5O-X#Td$^*o?dq=22bWnr8mAtAzaJo%io2Kv;40?$F~aM~n9$07=?#{nc7iu^(wQ8b~z z^V4P!J`>%8?L#Q`q1cb&00;#Sq=Sn-2QAH}V zvn0VLm;@Q-1m==;l8bRbsBH8lfPo#OvN84k`o}Zte|~r4FUy5%i(kdxDa^mK_QB2d zKP?ppA6~yynEHHeW_kU=)xwPrx&t9ad~`omNL*XJe|>%G!@}joqK&oGRNH32|uFZZ5-ADHm4;TLM=zemiz2h)cvKKTs1j39s$7I!G zKEq7`??A-41WEA2ydHBVhSwRkHwaor!LKdmy+HyJ zyTkmB!55e0qYP#71wNh71UAXT-GGa+0zUy(plwQ8K$>q^sv)oI00iL zRn!AF9K*Ne-e>G@(RZ`L?E?a|WCRKBc{T`uy_X`tPVDQBhJ%<3UU-{P8Wx3edUz+C zM{$^rOW_gk5k1A9Fs&23&+qq7xVi&U2-E|^sz|*PHeD0a!QbuUDZU5IBvL9P|;81Y#(K0rql&3xgaUIXXoNu-(K+Zzq3n$5^gARNpQjUNUVHOG#OQxI&JOK~Vg zBC%Ygz;Ys;Xww}Y!n*(ss513;gybN=DO00bysbfJ@UO~5cu@{Bs1_< zw(qU&?$4y{#vVEAiR3(yj3<)!G|nCWy>r^K;;FxCpF5fLwB$T38Bfcmi`4BY?f!KQ zad}d&Wp;O@FMudMS!ZX?*_m;6=IffKPwE`>S0vpZzzOI}C{CjIK8hDX=%jlNgSAb% zMkFSl|MqBo4=rGX9z%3CS-Y)ylYF~qBA&)XjqV$5hsBT+=t|Kk-MyF5F6PO(bLYH8 z$J|xk&<ZFP?s& zMMc!_m9!N!wdag$oqxx*&L5ITiWfXRy{Q+C;#W&|Q$J<#yvQU^tQ}*r5Dkg1&{NPw z_$et6n;gS1n^wZO<2Crp6GvSC<;nAz%4f$^Ylc)jn`RfY528>ZybkPEihWH?!zOu# H(7pX1_r|o~ literal 0 HcmV?d00001 diff --git a/framework/inori_utils/utils/__pycache__/json_encoder.cpython-311.pyc b/framework/inori_utils/utils/__pycache__/json_encoder.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..689700f74510f9af4f9bd8453f3dda7bcfa8a565 GIT binary patch literal 2909 zcmeHJO>7%Q6rNdo{S(``#GwfxZB0{3t%#7)DhgJp_$vj}rl>g}Sw<^ocir0E*k*Q3 zNQu-OA`ws}5)_miQmKa|U?t_0+(6<0cSj0RG*V8S5EoZ&CDaq|&3c_Uwh#!3Q^)J~ z=6&zYo0+%!-pse5P#b~v=#THxugZk{hJw>T7OiRkTO=CMs6i4orwIvU$#9Lk6K;x_ z%OK-&LZ(C_mx$(`A)2ha*Ib0G!{2TRkI;EQ=hfvyIV_fCDIB%&B=0)tYy~q?%AY4xP_o)jCN~jU=R5lBOD+@g-cd zaHjugiWla3!}EV_6K{w6qO6XgaV4`&_T@m4&V6933H3bPeLOUXRh}-^B}K zD_X<+;g;x;mgv(Cnszs>>IFylFIN?D#--^YpB+>5UWcPS$k#wvuLH2>zPdmfb@z_$ zYxaB1Q7h4rQYUZAn3yy-3S%;=Cl-JsY&j!@$DC2ppXkb66C?6M7hOH6d;GtU3RoyTY zr9{~&aA0C8zRoZi7}gO%FvY7wKp;lWuOj*7Qx)>h2z$|S^&g7v5%KyC7Vvse0q;)= zF9d;*?32Pv*#B5~86Kbv&r9|^5T|_E2^0n7R@dRr)~P(t;-J$=M0T9P-b+9Zrr-dA zNV>4ok3<+Fq}ESO5b%B=?j4w>jkk_$-EN9l^?L*%8;8y-yxHK@$)y@*49YXsP%dk5 z(=o*oVwClQbFsXr*dT8gbvB2WA*b51L9oH{Vd9dpriSmt=hRa1Pw;N5B1r+P#h8#u%>LE=eLNI8CV*4V><=Z`dw&7g!ub z+_U*Tkcx{^T4^IRI32*>E@>}2&n`JvZhUr0Pr31_c-kn`xn@$1oPL1t!+l+Mvy~V* R_gRxArDvhCHxUt+zW`v60@VNj literal 0 HcmV?d00001 diff --git a/framework/inori_utils/utils/__pycache__/utils.cpython-311.pyc b/framework/inori_utils/utils/__pycache__/utils.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..cd0009ebe6fbd62b565aaa93574367d83ce1c265 GIT binary patch literal 3854 zcmb7H?Qayv8K2qRd-LA;`~ox>Y-8Z$oE_{Mh=^ZG)qo+S!inlO0@w6(z1<^g&U>fX zb#2f&x+YXH$dNBiB|B-X98uzcOe$3ML%x+i;VwF<)=Ef`s?eZ*aphJ*{?y;>oj13( zsnofh-#$C<&oj^So4GGSp*n)}pMTy>_Ie5VJO9{9LRHw9fUrmuqRI&gNzm$A_)9_-kvDn(izG`5c<)RKRfHAju)3uO!Pw%+CLQ0T zz4xf)V`?T9PpFuPCJjEpq0Qkl1LLo=^n{u)$Iod-;?2}guBy5@o~+0jZ9K{1lj?Mu zT^rZ*G}B^Jrj|0sYp^GC-D;=~9ZRNJY)aQ=n2h0JUt;V7DZmB_`&XjHT$ZgR_Sm@H{afmAvXPjT@cVL=SVxX)N&UV=uNe$_DJlNr{GQeI;m z1mwsgIXwTPrM55k+;1yI`^(Y(k~~nB2a3{wJ%~#~XG@dl>ekTYnpe}rGqftywApG) z$TrPksa3~XqvRePiAt8J=_cd7Em2QTTY-vBT$?5o)@U2z+xUI$e$>_@8;1co@~vF| z-pqXV)?4#${Vm-2b-1$>j+VpGlH666yNXg*MPq06=;LTSjt}m{XUUc4XN9a#!1vDN z)&*@F$1&QhI4fnPEWKur%)D7KAyC5eD4B1Xk1BYxy%-HX?$Jzj(ujI22~icdf@Yju zRn6FM;;AXsl6a*hUQ@4I9=pWgK6i+x%4RnuHC>6J-garb3F|-;zURg-0PyLCJ?ljD z9I#@nXPz<>B>fD+9-nH$ZODB58=M zi@dRy1RLf~R?OyX8m4i~_A`9A9VJW58Uwo>J>6t-g{mn_R$R`YR1FAz5Jngu1W{0@ z8JZ5q))O#~q9sgAOsP5yDW-otQK5^9X+oM2QztX#^%!r(I???Avcb*6qhN17v3#;5 zA1cd-it_Q#NAEV@x%Ank2aTUzDN4t8YUl*}4EisUt7O&{*b2>phi{JJ%Rddi;L>*Q z+6$6Z8OS~s*NthF#WHb?8LSVJw<8 zwdP2nqu3n5Gv{}I`0E!!w?p}v!gIxaT_t~a+238XpEbELcX8(?IBxbU%>4fxF|*G; zj>PT95pQdodXx5S(qo%+fcY>TTujh1wH_8oYAF*|(K7558a$6|90R~40ePY2c1!-u zQgbQLS`M`4Uf!)p4&^TFq#!;Sr@oCp1GdK!KRxe@E2v*}$n`}sE9_3kS(+6TN%7qG zuE2Dw+#=-d-NKO8ft>c$jWDGf)pqzNMpRHh~~ zmM4))8!Donn_7kYnQvOYL|Qk|fdw#{!I$N*p=`IBW?)Um&Z36jM2rsr2>3u~PFrd& zOcw*ar9f{v(7R5kXXruSBY$u{knddTyZho-jYa=p$v;^34?C@eczmYueo`3uNZ!g@ukh6aVkKqsYza)Mo4f*~`hkUNfloyp;w~apmDs*F? zMXzD2YiJ`YJeyqE5l~DG^>!>2jN&-XRxkeE-V-GCIwz^h$>w24 z(8iKdnqgXAbp~6eSiWQ`ZbD++sKd63DXP4eLbm zwAwI7Ig`hi_mt$evfKvB3AC;Sn-(tKzPQ|3==iYfIfG3bQP6K|5z~#%n@*H1M0VO+=JAmIHiwODo{jU3oshKGiQ7iQP(4sR2 zcc|*^V>2+s4~UrzJAI?W(Bs$Cn3;|xa1l@S4B3}c<8+VH|$-T;NH~aE&+>Vcba_XZ~)fG-WY<$@Cu<0*4 zzDtLP%fJJ}*?VIs`7mT}veL1u5BK9e2 zpBpw)RotDgaN7-c(?2wsR;E(wX?6*U4m63h9+9{OK}WL7f str: + binary_data = char.encode() + padded = binary_data + b'\x00' * (3 - (len(binary_data) % 3)) # 添加填充以确保能被3整除 + encoded = base64.b64encode(padded)[:length].decode().replace('/', '-') # 使用'-'替换'/' + return encoded + + +def base64_decoder(encoded: str) -> str: + decoded_binary = base64.b64decode(encoded.replace('-', '/')) # 使用'/'替换'-' + decoded_text = decoded_binary.rstrip(b'\x00').decode() + return decoded_text + + +def encode_base64(text: str) -> str: + return "".join(base64_encoder(char) for char in text).strip() + + +def decode_base64(text: str) -> str: + return "".join(base64_decoder(encoded) for encoded in text).strip() + + +def image_to_base64(image_path): + """ + 将图片文件转换为Base64编码字符串。 + + :param image_path: 图片文件的路径 + :return: Base64编码的字符串 + """ + with open(image_path, "rb") as image_file: + # 读取图片的二进制数据 + encoded_string = base64.b64encode(image_file.read()) + # 将二进制数据转换为字符串并移除换行符(如果有的话) + return encoded_string.decode('utf-8') + + +def encode_credentials(username, password): + credentials = f"{username}:{password}" + encoded_credentials = base64.b64encode(credentials.encode('utf-8')).decode('utf-8') + return encoded_credentials diff --git a/framework/inori_utils/utils/config_loader.py b/framework/inori_utils/utils/config_loader.py new file mode 100644 index 0000000..bbeef9f --- /dev/null +++ b/framework/inori_utils/utils/config_loader.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- +# @Time : 2024/4/6 +# @Author : liuboyuan +# @Description : + +from configparser import ConfigParser +from framework.inori_utils.log_utils import LOG +import os.path + + +class ConfigLoader: + def __init__(self): + self.config = ConfigParser() + + def get(self, section, option): + return self.config.get(section, option) + + def read(self, path, errorMsg): + if not os.path.exists(path): + LOG.error(errorMsg) + exit(1) + self.config.read(path) + LOG.info(f'读取config成功 {path}') + diff --git a/framework/inori_utils/utils/data.py b/framework/inori_utils/utils/data.py new file mode 100644 index 0000000..fb9a06a --- /dev/null +++ b/framework/inori_utils/utils/data.py @@ -0,0 +1,48 @@ +# -*- coding: utf-8 -*- +# @Time : 2024/5/18 +# @Author : liuboyuan +# @Description : + +# used in sd api +def update_nested_key(data, key, new_values): + """ + 递归更新嵌套字典中指定键的值。 + + :param data: 需要更新的嵌套字典。 + :param key: 要查找并更新的键名。 + :param new_values: 要添加到列表的新值,可以是单个值或列表。 + :return: 更新后的字典。 + """ + if isinstance(data, dict): + for k, v in data.items(): + if k == key and isinstance(v, list): + # 确保new_values是一个列表 + if not isinstance(new_values, list): + new_values = [new_values] + # data[k].extend(new_values) # 更新列表 + data[k][0].update(new_values[0]) + else: + update_nested_key(v, key, new_values) # 递归调用 + elif isinstance(data, list): + for item in data: + update_nested_key(item, key, new_values) # 处理列表中的每个元素 + return data + + +def update_dict_list(row_item, key, value): + """ + 向指定字典的列表型值中添加一个元素。 + + 参数: + row_item (dict): 要更新的字典。 + key (str): 字典中要更新的键名,对应的值应为列表类型。 + value: 要添加到列表中的值。 + + 异常: + ValueError: 如果key对应的值不是列表,将抛出此异常。 + """ + # 检查键是否存在且对应的值是列表 + if key in row_item and isinstance(row_item[key], list): + row_item[key].append(value) + else: + raise ValueError(f"键'{key}'不存在或对应的值不是一个列表。") diff --git a/framework/inori_utils/utils/file.py b/framework/inori_utils/utils/file.py new file mode 100644 index 0000000..9ab0c04 --- /dev/null +++ b/framework/inori_utils/utils/file.py @@ -0,0 +1,75 @@ +# -*- coding: utf-8 -*- +# @Time : 2024/4/26 +# @Author : liuboyuan +import os +import zipfile +import tarfile + + +def user_file_builder(root_folder, user_id, file_name): + return os.path.join(root_folder, user_id, file_name) + + +def compress_directory(dir_path, output_zip_path): + """ + 将指定的目录及其所有内容压缩到指定的ZIP文件中。 + :param dir_path: 要压缩的目录路径 + :param output_zip_path: 输出ZIP文件的路径 + """ + with zipfile.ZipFile(output_zip_path, 'w', zipfile.ZIP_DEFLATED) as zipf: + for root, dirs, files in os.walk(dir_path): + for file in files: + # 获取文件绝对路径 + abs_file_path = os.path.join(root, file) + + # 计算相对路径(相对于要压缩的根目录) + arc_rel_path = os.path.relpath(abs_file_path, start=dir_path) + + # 添加文件到压缩包内,保持其目录结构 + zipf.write(abs_file_path, arcname=arc_rel_path) + + +def list_files(directory): + """ + 列出指定目录下的所有文件。 + + :param directory: 要列出文件的目录路径 + """ + res = [] + try: + with os.scandir(directory) as entries: + for entry in entries: + if entry.is_file(): + res.append(entry.name) + # print(entry.name) + except FileNotFoundError: + print(f"目录 '{directory}' 未找到。") + finally: + return res + + +def unzip_file(zip_file_path, output_folder): + """ + 解压zip文件到指定的文件夹。 + + :param zip_file_path: zip文件的路径 + :param output_folder: 解压后文件存放的文件夹路径 + """ + with zipfile.ZipFile(zip_file_path, 'r') as zip_ref: + zip_ref.extractall(output_folder) + print(f"文件已解压到: {output_folder}") + os.remove(zip_file_path) + + + +def untar_file(tar_file_path, output_folder): + """ + 解压tar文件到指定的文件夹。 + + :param tar_file_path: tar文件的路径 + :param output_folder: 解压后文件存放的文件夹路径 + """ + with tarfile.open(tar_file_path, 'r:') as tar_ref: + tar_ref.extractall(output_folder) + print(f"文件已解压到: {output_folder}") + os.remove(tar_file_path) \ No newline at end of file diff --git a/framework/inori_utils/utils/http.py b/framework/inori_utils/utils/http.py new file mode 100644 index 0000000..220d9ec --- /dev/null +++ b/framework/inori_utils/utils/http.py @@ -0,0 +1,65 @@ +# -*- coding: utf-8 -*- +# @Time : 2024/4/18 +# @Author : liuboyuan +import urllib3 +import json +from urllib.parse import urlencode +import time +from framework.inori_utils.log_utils import LOG + + +def http_get(url, params=None): + timeout = urllib3.Timeout(connect=2.0, read=3.0) + http = urllib3.PoolManager(num_pools=1, timeout=timeout) + print(url) + if params is None: + resp = http.request('GET', url) + print(resp) + else: + resp = http.request("GET", f"{url}?{urlencode(params)}") + res = json.loads(resp.data.decode('utf-8')) + if not isinstance(res, dict): + res = json.loads(res) + + return resp.status, res + + +def http_post(url, body=None): + if body is None: + body = {} + http = urllib3.PoolManager() + resp = http.request("POST", url, + headers={'Content-Type': 'application/json'}, + body=json.dumps(body)) + res = json.loads(resp.data.decode('utf-8')) + if not isinstance(res, dict): + print('reloads') + res = json.loads(res) + return resp.status, res + + +def retry_decorator(max_retries=3, delay=1, condition=False): + """ + 重试装饰器。如果被装饰的函数返回False,则会自动重试指定次数。 + + :param condition: 在何种情况下执行这个重试装饰器 + :param max_retries: 重试的最大次数,默认为3次。 + :param delay: 每次重试之间的延迟时间(秒),默认为1秒。 + """ + + def decorator(func): + def wrapper(*args, **kwargs): + retries = 0 + while retries < max_retries: + result = func(*args, **kwargs) + if result is not condition: + return result + LOG.error(f"Function returned condition {condition}, retrying ({retries + 1}/{max_retries})...") + retries += 1 + time.sleep(delay) # 等待一段时间后重试 + LOG.error(f"Failed after {max_retries} retries.") + return False # 最大重试次数后仍然失败,返回False + + return wrapper + + return decorator diff --git a/framework/inori_utils/utils/json_encoder.py b/framework/inori_utils/utils/json_encoder.py new file mode 100644 index 0000000..b19e2d5 --- /dev/null +++ b/framework/inori_utils/utils/json_encoder.py @@ -0,0 +1,38 @@ +# -*- coding: utf-8 -*- +# @Time : 2024/4/28 +# @Author : liuboyuan + +import json +import numpy as np +from flask.json.provider import DefaultJSONProvider +from json import JSONEncoder + + +class NumpyEncoder(DefaultJSONProvider): + def default(self, obj): + if isinstance(obj, (np.int_, np.intc, np.intp, np.int8, + np.int16, np.int32, np.int64, np.uint8, + np.uint16, np.uint32, np.uint64)): + return int(obj) + elif isinstance(obj, (np.float_, np.float16, np.float32, np.float64)): + return float(obj) + elif isinstance(obj, (np.ndarray,)): + return obj.tolist() + return super().default(obj) + + +class NumpyJSONEncoder(JSONEncoder): + def default(self, obj): + if isinstance(obj, (np.int_, np.intc, np.intp, np.int8, + np.int16, np.int32, np.int64, np.uint8, + np.uint16, np.uint32, np.uint64)): + return int(obj) + elif isinstance(obj, (np.float_, np.float16, np.float32, np.float64)): + return float(obj) + elif isinstance(obj, (np.ndarray,)): + return obj.tolist() + return super().default(obj) + + +def json_numpy_encoder(obj): + return json.dumps(obj, cls=NumpyJSONEncoder) diff --git a/framework/inori_utils/utils/utils.py b/framework/inori_utils/utils/utils.py new file mode 100644 index 0000000..6d8a02a --- /dev/null +++ b/framework/inori_utils/utils/utils.py @@ -0,0 +1,66 @@ +from datetime import datetime +import json +import time + + +def replace_for_unix(f): + return f.replace("\\", "/") + + +def timestringstamp() -> str: + return time.strftime("%Y%m%d%H%M%S", time.localtime()) + + +def unixtimestamp() -> int: + # print("call unix to get timestamp") + return int(datetime.now().timestamp()) + + +def find_key_for_value(data, target_value): + for item in data: + for key, value in item.items(): + if value == target_value: + return key + return None + + +def is_empty_dict(obj): + return isinstance(obj, dict) and len(obj) == 0 + + +def generate_answer_pairs(N): + result = [] + for i in range(1, N + 1): + east_str = f"参考答案{i}" + west_str = f"答案权重{i}" + result.append((east_str, west_str)) + return result + + +def filter_ip(ip): + ip = ip.replace('.', '-') + ip = ip.replace(':', '-') + return ip + + +def file_writer(file_path, content): + with open(file_path, 'w', encoding='utf-8') as f: + json.dump(content, f, ensure_ascii=False, indent=4) + f.close() + + +def flatten(lst): + result = [] + for i in lst: + if isinstance(i, list): + result.extend(flatten(i)) + else: + result.append(i) + return result + + +def snake_to_camel(snake_str): + components = snake_str.split('_') + # We capitalize the first letter of each component except the first one + # with the 'title' method and join them together. + return components[0] + ''.join(x.title() for x in components[1:]) \ No newline at end of file diff --git a/logger.py b/logger.py new file mode 100644 index 0000000..be5dcc5 --- /dev/null +++ b/logger.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- +# @Time : 2024/7/5 +# @Author : liuboyuan +from framework.inori_log import Logger + +s_log = Logger( + name='inori', + log_dir='static', + debug=True +).logger + + +def register_logger(): + global s_log + s_log = Logger( + name='inori', + log_dir='static', + debug=True + ).logger diff --git a/main.py b/main.py new file mode 100644 index 0000000..f3b2298 --- /dev/null +++ b/main.py @@ -0,0 +1,46 @@ +#!flask/bin/python +import sys +import os + + +sys.path.append(os.path.dirname(os.path.abspath(__file__))) +# CORS +from flask_cors import CORS +# Router +from api.router import init_app_router +# APP及Router description +from api_entry import app, rest_api_description +# encoder +from framework.inori_utils.utils import NumpyEncoder +# log +from logger import s_log +# api中间件 +# import api.middleware.modify_mime + +app.json = NumpyEncoder(app) +s_log.info("初始化json numpy序列化工具") + + +CORS(app, resources={r"/*": { + "origins": "*", + "methods": ["GET", "PUT", "POST", "OPTIONS", "DELETE", "PATCH"], + "allowed_headers": [ + "Origin", "Content-Length", + "Content-Type", "User-Agent", + "Referrer", "Host", "Token", + "User", "Authorization", "Uuid", "Auth-Server", + "X-Requested-With"], +}}, supports_credentials=True) + + +if os.environ.get('WORKER_ENV') == 'prod': + # 生产环境路由不需要前缀 + s_log.info('running in production mode') + init_app_router(rest_api_description, '') +else: + s_log.info("running in development mode") + init_app_router(rest_api_description, '/fischl_api/v1') + +if __name__ == '__main__': + # 运行程序 + app.run(host='0.0.0.0', port=5010, debug=False) diff --git a/static/.gitkeep b/static/.gitkeep new file mode 100644 index 0000000..e69de29