From b05a03e1989c8a4eb7d23cc526100359437565ff Mon Sep 17 00:00:00 2001 From: hubian <908234780@qq.com> Date: Sat, 11 Apr 2026 12:22:03 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20Matrix=E8=BF=9E=E6=8E=A5=E6=94=B9?= =?UTF-8?q?=E4=B8=BA=E9=9D=9E=E9=98=BB=E5=A1=9E=E6=A8=A1=E5=BC=8F=EF=BC=8C?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E6=9C=8D=E5=8A=A1=E5=90=AF=E5=8A=A8=E9=98=BB?= =?UTF-8?q?=E5=A1=9E=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ai_chat.db | Bin 61440 -> 61440 bytes logs/ai-chat.log | 81 +++--------------- reset_config.py | 25 ++++++ .../__pycache__/ai_service.cpython-310.pyc | Bin 2956 -> 3308 bytes .../matrix_service.cpython-310.pyc | Bin 5038 -> 5803 bytes services/ai_service.py | 67 ++++++++------- services/matrix_service.py | 36 ++++++-- 7 files changed, 104 insertions(+), 105 deletions(-) create mode 100644 reset_config.py diff --git a/ai_chat.db b/ai_chat.db index be46afd048ccc1f3c0cfa8ed1a2890b1b2bb2ec2..4aa5ce0578900f5ffbbff6f0fe2fe6c0bd8a4e15 100644 GIT binary patch delta 815 zcmZ{izi-n(6vxlC8`Y8QXVWrNAd#U`hN|wJ@6Nv#C@d@p78Wyv(j=;=M5<6x(k0

psEokb z8h2l=HaDs%JTES>aey7mcd*C&)M@ALL;_4K>Qd@>p*#Zj9nPP-t$Hhk=S3b)1MUZ$ zTg1n<&#!POCgDVm9Y4O+OO!_whQ5Q~6CA-loWc&gPt4LAh>vbh-5E}#V9I4F_jFY< zd6603SGmXx4=D@C+%(K1SsNgIUvFrGEX4SKYRTXMmK220K@@$PDZ(ElLm$B}_yPSa z#6iA7+^<}l6IF)T!&QU>Q5_?Q;WK>5LR7aQjvIGV=6n>D-|i{}33>>6!g>c!9!e@& zl+xdZRvIr}RcPI1HD0YRFH=X!znS=B**rM2{qs?cO^P#$c~LZy;0(c8Vy>TpDWoi` cYL-4ha3cDChwC%)qB_>FyI$(f;6xc`M!}5oKb_F~eEEjS8~r5J zOl_Ii7!*adLFy6Xw|8fZF$Sk;d!%+8aXLKUV`6|%X2oZA(aVo#C87GPFnojX6mhtGLj?{nN;`B5k6^WzEo&|t5Ycb6xH zY1?ke4QxA&lQzNV68W(G#uy02IP#^&zfU3Kd*^ zD0!(+NfE>#Q0FzkM7l-*69p_pjKTk$UYFo-seq7H!PPde-D>{)=E|Eh%ZtCSAgcWX zaiwwlkFjrGrVZi#2j0QdGC}ACZ)AjVp}M7EFRSt-G(H)K zbBJK)2$4uv%G3#%o%c$^?#LEs^06yjM$}UB4yn5BF>V`Tg;`|2?~E{C=$r)=UdrQX zX(#Lj^WPx*KZLXN2H-bFcyA!h!%;?5LWyq<;ZVb&ReDKDqH0a1S||g0`kXQZxFUko zn3HP?HKC>go-$2PYgVqQP}kt=Bu&xutXk8eemf%UH=z$=RUD<-ALwHS?WCJ$q`hQ- z(5|E8YPP0_`j`p(sD>KdGNZ)pH6t|U6LkV}Gv=*2shOckyJ3D?A@{`dJO!knT`Ez@ z^y*gzztUdk%`Ndsmvj zSXjC%2b=pM>gT;;xxfO~ zEBOzMmzl#E&phaK%H@Kacd)r{%=bz+WRdQ#1fw2zt5It;bueDku9K5xwmclA=J!_q z0U`igK>^@+{zWoi#WD(Wg)?ClowIh}jkA(p=|BV`h3_B8fVS_;aJY8JGGs`D2X08h z2;3s`D#0KOZ;Ubrgv%Ey&Id3Z^*~~Mj=Cz0Rq|B2p%!=7zC8ZWy7lqCOy#SQBfeUi zSI;%y|I^Z)nZ`Q{uxa=2zP0k+mDWN8^j3(wfA_-Yw;&RIQO_v{D5bzSZE^f z%!1y*0XjATy9533!IwF^5O z+@Mgnov4rpLALyNQK3NFL7~0~x|9MwO2Bu}CeS4XbV-d^2uc(xhsf(1=#TmX;P>gR zREv}fnW}?QY1DvTkg+l~X#$i=hq?m&!Id0ol~ywXbxfljbknLLX`o0o)S5A!c7|H0 zhX$yX8mSffUaKX-#Jo`_FOcfdJ@61Y3c6CWLTlcnU3H0H4K2EbYHz}9YsoN4yT@hj zN~E->`fQMxx58vys-@`GFm;CTOF=S(axa;dXwSIHFU2)fH&i8;)a67o9HotKL$e*sAn(QEQ)s?`2G7(<{v|Bp<1MSLBfbuY znK?zCLGM@4>_CG=6zZ$ThfeZmpjg%M%vUz@Kn~(U@);lExQGft7?Z!UD1Bm7(K=JDsTLyfa?VNxJ{IDY|~5kI~M&0aL$0wYu$P?)$5;5X+lqUR+vPrMG2 z$Qld*So*>59|HqyRJ-9tg^W|-jj)lCz{&sgm`?*+E#NCg$WYo2brb&8sSa#;B>!7| z^xUJ}kE&ZYGIVvUY!Y8`C8x-2TUa){8fm3~<&=!crZ8Ls2iBtJj!8_ZNAF4OcqVGkriEeK)XUp;v|~aKCd+PVWZei+=aDEH z_~-(sNWc~yiymP7D2^KGE)FBC$B)$iHy2^P6ff|*cz}HTP9>&-hyiADhho|P11jEz AEC2ui literal 2956 zcmZuz-ESMm5#PJp``}TOWI0x%)<{{kNW<0=Ejx7*p-oI%a;(;&lFDsh2I=9#T}daA zJbLeFS?sZh;W!1_stJ&wC?Y!$fgp`vVk2l#r0B;(fj;-O`&v+z|A9WZMctV@l9FXF zvBTM!*{|98&77af*aX^3fB&cV;Q%53!ol9A!QdqH;Kx81DG{bHwW5?1_}40GRV!&# zTB23Gq$`QeC>gPhSu(k~W${#7DcOvc(o8Q6Fr$=ti7=B{Zxd!+RZD|>@G2<{F?E6D zQjM>`CU#+N`}#)b=k4r7cIWohJ0E=7`S`cnpSC+6{i5*7oP8HeNHM2Ldd>?%NoTxr zD6RQ===n9b(mcEzhV|)ue(L#SlT#<2n*{po^wjf5k3O5fG$rX}Xp*{(&@baUdz%S^ zlhA`@Ae_JrNl9e~n94P#L8n|>G?>nexAhX;C&l~FlFmk$%?)mj5til_8;ECQ*dWYE z^)!nr8)Cy?Z8HV#d{Cwea|>Kt^2)p@Ew}DDZ@K}OCUUEMUFubz@k*J(p?VE@75ZuD z!8njescRvLh@(Vm-3nFUv`DLGLJFMD2<)R2bA}wAnLShZ;kok;IMO*)SeO+S%$7rY z#owR3AW|sJ^rSD(&&-|^7$!HVqyeui#?xY}L`=jmXz$JCm;EZwU-sNue$ub=TDjt` z<=1?%8r0n~pD4pkL^961-b8uX4f8>A^#BA;m!GV!OUrS*nio3G2rL{JKy1ZU29@SW z-&>PClZSkR=CN;H047qv2P8tDD3JzK4Ye)Glt|emOpUZna)Y)NvF1HaJ*pn_~~ z{%-r%x9?utxbx@F8V5m8m`etoKYX6(rn61!NH%_}?-q0VJ`YKw;x8?6A*oke^u-{o z5W6fP2Vf{OjXHBf?v(x7qPO%ohypY-R6{Y8QRoIZp!xXj^&hZ5BdsbA0(XfA(g;Gq z-KsPM4;!LZMhN#BzAW~?K@V;NxdQH4A>az-hT77=A!G#{b3tn_ znR#7r>7lklnZ;5Y$}?n+F#9a|@adKj87n%tmqt2EZ)l0UWk%+f(I((rbIWX#mK6ag z02~?UgV2Y@$ZHVE%%+5rtKC@&gzHpy<>1vdcpCg&fX-}qkm1H1IJTYbwj@J9%7_!h z&R;io+Q01F`eNtSjlM~rDTt+DxZj()rW7JAZk<^Rqwp&HBs_;#b*s zkiuMN^P|qk8=ZHqbw2x|Z+q`RK1NB|uhuIZQ(SP*JjGqXMfTpXTd!BVvWw#UO5oRS zsxnh(gv-A0nz6Jwa5_2m#QF6)zq1&(?HBL<19II>J;tsW1#b!rH<=E3wa$eLLBpk8 zbuT-izshR?`WssD-H#gS)`Psb$Q+y_NO-J{EQFv+AjK>I6^%g!HKGfuG=Qqr z(j$FEX9JMC09Y)uL1Vz7?g9c1p>>Qj&mM1R=!RES z@v=f{$D2=u)>bOA+Da?M4n(O-M2OIifFC1Q6*jU;g-AwhWQ=U3*+GxA)t1d3i)^%w zfEyz}0x-TtE}ozyv{nYzTRn(gJh2AS6QE=1KBVDnuyZB};eVkG7xe zwM9+tP~$1^bRQsHsKuWNy(G|AiZL)1UqbR_B!_{V7f&LK9~vTyGD19qn&*&UW!_U}(ipvH0u|y#Pz5J}K>X83#s6XDF(^6%fB_1qu$3oZ zY{5T$YY-*()qm6b-@HG0zj^3EbadCxX~kkOr<}>9v7Xo5Dt8=dI}TLIMg{o+$GO;W zD_xC-2giCZ4k1B=39Ma`zUliF@ogLzknCP5=CFJU$Y=za0KZc#@`N&~AGSxIjODpu zX*v$`%Z?L2jx@scx>sA;-9q3eRq`MvR%%en6uic{xN3`2sKv4`5at5E2t)=6?kerw jPnSm>O0jK9$ diff --git a/services/__pycache__/matrix_service.cpython-310.pyc b/services/__pycache__/matrix_service.cpython-310.pyc index e6d6fb2b62f3de3748cfa3ee65aa973552e68c03..c2447825c4c24657b6457d34772da365f697c28a 100644 GIT binary patch delta 1876 zcmZ8hU2GIp6ux(6c4u~X_NUuYC@oDPB+aG>h(V-A!D=Fq&>}TKK$$Fir*%uayWE)t z+HAWeHl{(qCKpT$HrWyph0q0RB&JAAeBr^wN5ej-4{lo?)x;O0c+MSQtFxIiXU^ZA z^PTU`Z2R?RBH3^_NZ@My{z1C9=2qkfO2@=cbiLKg4BOwQumB5A_zvkT#LNkD$Y5bR zz#?|APh(LQo6ru0Se<=69MZ=whF9K*2Gprg&5O&Nup)$ zpt4${zYEvjR_t-L0vRB1Q>HTQoLV5358nKID@wS17D_5L-Bn5kLqEMlrj;2=2?MVc zH~`OHtl}#LL561NZo>3kWR$vQfx6-M6y7UyjsNDpRZ9kUgaryu3qwhzmuSR|4xgfA zRH0-fDr15L<;kBPAP3=ZMwKxIV?FI8JxLNF@s9rbDxr!2?KayvmQ zL8(}|r2B4u4Zy!wx~q3?FU{Ut{AMr;(U@p5It)GU*xX7p@v70^ z@&cqO($fRqq@ zpX;B&@#@erpvyfVehT2HKqerLnFmOw8Q=&EcL5x#gafPk3+g2peOmQm01#zV9aA$! zpQj)mZm<+8kdiq=Fi4g(o-~sPIc=SvkNz_EPOS&aJrmtu7NXqd13O- z;`Q>vC)cWz(-?U6qwaL9oschRMR(Ifb~f+kSJe_Gr;AU^RcFsGOitxjFZb4*pWa&f z@=9l0z7E_Q+Nw9-uil(qDqmcjzq&YoV|fp^~~pqFvsTkW)#n& zz#b~`BxB-2prc!JhBGPt96Gk4Lr6f&k_&z%rYdR!jli#!8so~Nh!&wE4Iah1 zvhK!Oa*9IYlS=^wzXjjH?M#61h{Jb|Gyo~+0FZ|%=a3Xdbr*pZswItS@|4MU;Kn-O zhHtnNxB)93X>|Q19Zu@g<0Lcu%QJu}>L?wf8K3t=q96kujj3>$;7;fsHKxv2KfLKt zqguRoZSj0LJy{PRy$FqVKg2om4ImyLB)O-D7d~Dpmpj`Y`oNJe_)2(qtJ;CuP7oEJ zGicj6xtQ7l6NmN; z(QGfuNbP8r4fFk2Qj*S0Wiuyi?j+rGHsfV>VEKSI&@K$zjba0cij1~^RVUIZn z8)(;ulDS+u)6W^2{s+LzV9O99M#HC}pGV;b&4@-qABPX~Y1rAhE9hdWC_=?AX!+?b6L@vHI nj;u0>L5+YBjjcBt;~_B2v?sZ*XL~M_7ST<030^8~ThX@_{AnAY0RfBMKYZ zOis8#UKE2oG6zHn8C!H9(-}BHzK0=O7G1~|#8aYsgUz_YoMK+@c7^w9@JKa{!>bdC z)?{-G7hK~_=Ia<4a+na8?i&f;G)0E;H`qIWf%p&Ht;0zP`1Y3b5 z--N`z#^w36miqi}EoPmw!ffs*u_d2k8cPbx9{^k7z^=L^5>}J{xA`=C8@E~EA92#Q zqa|2kURK5CIB)bTu*%NhqX$3y{>3**^nOtH)ZgYC;HvZ1kXo~9rC~g2zGm|rXux?9 zjEv&h$yJWDhU-UM@rwxSfW}#D2*5Eh_S5f8JfyiyqHUo&%FpS7i_B*vNl-*1{%sty>$IJDq zUyEe07)X!HUdo+N)A>U~;~2&^0$($@1_m!?x-(ZhFH{m4emEK>!*NoPiBAo-4?3Sf zzGXJzK>DGOr`4UpNf=d63Io;{cJOpLu6kXshkCZ`R5l;Pab-4;qe#gy^^W^GjH%o1 z5jd@Wbq7{crFJC}%km5!@eO6u~s&5|-QuGqSn~bTY;yU{ItGLrQgN&DvG)K$+*R`K4F9h1jAMNla>GiXw*~J%P6sN6q7_ir%^ wtgPi050#wKiLMUYl|`hzzLx3xBC7g+%dF7VhLL(u{?d4l%16}2u1OgD2asI^?EnA( diff --git a/services/ai_service.py b/services/ai_service.py index eb6357f..494c70e 100644 --- a/services/ai_service.py +++ b/services/ai_service.py @@ -2,45 +2,40 @@ AI服务 - 调用大模型API """ import httpx -from typing import List, Dict, Optional +from typing import List, Dict, AsyncGenerator import json import logging logger = logging.getLogger(__name__) -# 默认配置 -DEFAULT_API_BASE = "http://192.168.2.17:19007/v1" -DEFAULT_API_KEY = "xxxx" -DEFAULT_MODEL = "auto" - class AIService: - def __init__(self, api_base: str = None, api_key: str = None, model: str = None): - self.api_base = api_base or DEFAULT_API_BASE - self.api_key = api_key or DEFAULT_API_KEY - self.model = model or DEFAULT_MODEL + def __init__(self): + self.api_base = "" + self.api_key = "" + self.model = "" + self.use_mock = True def update_config(self, api_base: str, api_key: str, model: str): """更新配置""" self.api_base = api_base self.api_key = api_key self.model = model - logger.info(f"AI配置已更新: {api_base}, model={model}") - self.api_base = api_base - self.api_key = api_key - self.model = model + # 如果配置完整则使用真实API,否则使用mock + self.use_mock = not (api_base and model) + logger.info(f"AI配置已更新: api_base={api_base}, model={model}, use_mock={self.use_mock}") - async def chat(self, messages: List[Dict], stream: bool = False) -> str: + async def chat(self, messages: List[Dict]) -> str: """ 调用AI模型进行对话 - - Args: - messages: 对话历史 [{"role": "user", "content": "..."}] - stream: 是否流式输出 - - Returns: - AI回复内容 """ + # 如果使用mock模式,返回模拟回复 + if self.use_mock: + logger.info("使用Mock模式回复") + last_msg = messages[-1]['content'] if messages else "你好" + return f"这是一个测试回复。您说的是:{last_msg}\n\n请配置有效的AI服务地址和模型,才能获得真正的AI回复。" + + # 调用真实API url = f"{self.api_base}/chat/completions" headers = { "Authorization": f"Bearer {self.api_key}", @@ -49,21 +44,35 @@ class AIService: payload = { "model": self.model, "messages": messages, - "stream": stream, "temperature": 0.7, "max_tokens": 2000 } - async with httpx.AsyncClient(timeout=60.0) as client: - response = await client.post(url, headers=headers, json=payload) - response.raise_for_status() - data = response.json() - return data['choices'][0]['message']['content'] + logger.info(f"调用AI API: {url}, model={self.model}") + + try: + async with httpx.AsyncClient(timeout=60.0) as client: + response = await client.post(url, headers=headers, json=payload) + response.raise_for_status() + data = response.json() + return data['choices'][0]['message']['content'] + except Exception as e: + logger.error(f"AI API调用失败: {e}") + # API失败时返回模拟回复 + last_msg = messages[-1]['content'] if messages else "你好" + return f"AI服务暂时不可用(错误:{str(e)})。您说的是:{last_msg}" - async def chat_stream(self, messages: List[Dict]): + async def chat_stream(self, messages: List[Dict]) -> AsyncGenerator[str, None]: """ 流式调用AI模型 """ + if self.use_mock: + last_msg = messages[-1]['content'] if messages else "你好" + reply = f"这是一个测试回复。您说的是:{last_msg}" + for char in reply: + yield char + return + url = f"{self.api_base}/chat/completions" headers = { "Authorization": f"Bearer {self.api_key}", diff --git a/services/matrix_service.py b/services/matrix_service.py index 63f8af9..567474f 100644 --- a/services/matrix_service.py +++ b/services/matrix_service.py @@ -45,12 +45,18 @@ class MatrixBot: return False try: - self.client = AsyncClient(self.homeserver, self.username) + # 创建客户端 + self.client = AsyncClient( + self.homeserver, + self.username, + store_path="/tmp/matrix_store" + ) - # 如果有access_token,直接使用 + # 如果有access_token,直接设置 if self.access_token: self.client.access_token = self.access_token - logger.info(f"Matrix连接成功(使用token): {self.username}") + self.client.user_id = self.username + logger.info(f"Matrix已设置access_token: {self.username}") self.is_running = True return True @@ -71,6 +77,7 @@ class MatrixBot: async def start_sync(self, message_handler: Callable = None): """开始同步消息""" if not self.client: + logger.warning("Matrix客户端未初始化") return self.on_message_callback = message_handler @@ -78,8 +85,27 @@ class MatrixBot: # 注册消息处理器 self.client.add_event_callback(self._handle_room_message, RoomMessageText) - # 开始同步循环 - await self.client.sync_forever(timeout=30000) + # 首先执行一次同步获取房间信息 + try: + sync_response = await self.client.sync(timeout=10000) + logger.info(f"Matrix初始同步完成") + except Exception as e: + logger.warning(f"Matrix初始同步失败: {e}, 将尝试继续") + + # 启动后台同步任务(不阻塞) + asyncio.create_task(self._sync_loop()) + logger.info("Matrix同步任务已启动") + + async def _sync_loop(self): + """后台同步循环""" + while self.is_running: + try: + # 使用较短的超时,避免长时间阻塞 + await self.client.sync(timeout=5000) + await asyncio.sleep(1) # 每秒同步一次 + except Exception as e: + logger.warning(f"Matrix同步错误: {e}") + await asyncio.sleep(5) # 出错后等待5秒再重试 async def _handle_room_message(self, room: MatrixRoom, event: RoomMessageText): """处理收到的房间消息"""