您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

pipeline_endpoint.py 67KB

1 个月前
3 周前
1 个月前
3 周前
1 天前
1 个月前
4 周前
1 个月前
4 周前
4 周前
1 个月前
4 周前
1 个月前
3 周前
3 周前
5 天前
1 个月前
3 周前
2 周前
3 周前
1 个月前
1 个月前
1 个月前
1 个月前
1 天前
1 天前
1 个月前
16 小时前
1 个月前
1 天前
1 个月前
16 小时前
1 天前
1 个月前
1 个月前
1 个月前
3 周前
1 个月前
3 周前
3 周前
3 周前
1 个月前
1 个月前
1 个月前
1 个月前
1 个月前
4 周前
1 个月前
1 个月前
4 周前
1 个月前
4 周前
4 周前
4 周前
4 周前
4 周前
3 周前
4 周前
4 周前
1 个月前
1 个月前
1 个月前
1 个月前
1 个月前
4 周前
4 周前
1 个月前
1周前
16 小时前
1 个月前
16 小时前
1 个月前
16 小时前
1 个月前
1 个月前
1周前
1 个月前
16 小时前
6 天前
6 天前
5 天前
5 天前
16 小时前
1 个月前
1 个月前
1 个月前
1 个月前
4 周前
1 个月前
1 个月前
6 天前
1 个月前
4 周前
1 个月前
4 周前
1 个月前
5 天前
1 个月前
1周前
1 天前
1 个月前
1 个月前
1 个月前
1 个月前
1周前
1 个月前
1 天前
1 天前
1 个月前
1 个月前
4 周前
1 个月前
1 个月前
1 个月前
1 个月前
1周前
1 个月前
4 天前
1 个月前
4 周前
1 个月前
1 个月前
1 个月前
1 个月前
4 周前
1 个月前
1 个月前
1 个月前
1 个月前
1 个月前
1 个月前
1 个月前
1 个月前
1 个月前
4 周前
4 周前
4 周前
1 个月前
4 周前
3 周前
4 周前
4 周前
1 个月前
4 周前
1 个月前
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348
  1. from voice.ali.ali_voice import AliVoice
  2. from common.log import logger
  3. import xml.etree.ElementTree as ET
  4. import os,json,asyncio,aiohttp,random
  5. from aiohttp import ClientError
  6. from voice import audio_convert
  7. from fastapi import APIRouter,Request
  8. from pydantic import BaseModel
  9. from fastapi import APIRouter, Depends
  10. from typing import Dict, Any
  11. from model.models import AgentConfig,OperationType
  12. from common.utils import *
  13. from common.memory import *
  14. import traceback
  15. import sys
  16. timeout_duration = 8.0
  17. messages_router = APIRouter()
  18. #WX_BACKLIST=['fmessage', 'medianote','weixin','weixingongzhong','tmessage']
  19. WX_BACKLIST=['medianote','weixin','weixingongzhong','tmessage']
  20. @messages_router.post("/messages",response_model=None)
  21. async def get_messages(request: Request, body: Dict[str, Any]):
  22. logger.info(f"收到微信回调消息: {json.dumps(body, separators=(',', ':'),ensure_ascii=False)}")
  23. try:
  24. msg = body
  25. type_name =msg.get("TypeName")
  26. app_id = msg.get("Appid")
  27. k, loginfo = await request.app.state.gewe_service.get_login_info_by_app_id_async(app_id)
  28. if not k:
  29. logger.warning('找不到登录信息,不处理')
  30. return {"message": f"收到微信回调消息: {type_name}"}
  31. token_id=loginfo.get('tokenId','')
  32. wxid = msg.get("Wxid",'')
  33. if type_name == 'AddMsg':
  34. await handle_self_cmd_async(request,wxid,msg)
  35. msg_data = msg.get("Data")
  36. from_wxid = msg_data["FromUserName"]["string"]
  37. config=await request.app.state.redis_service.get_hash(f"__AI_OPS_WX__:WXCHAT_CONFIG")
  38. wxids = list(config.keys())
  39. meged_backlist_wxids=wxids+WX_BACKLIST
  40. # 公众号ID已gh_开头,屏蔽元宝
  41. if (from_wxid in meged_backlist_wxids and from_wxid != wxid) or 'gh_' in from_wxid or 'wxid_wi_' in from_wxid:
  42. logger.warning(f'来自微信ID {from_wxid} 在黑名单,发送给 {wxid} ,不处理')
  43. return {"message": "收到微信回调消息"}
  44. await handle_messages_async(request,token_id,msg)
  45. return {"message": "收到微信回调消息,处理完成"}
  46. except Exception as e:
  47. # 获取当前的堆栈跟踪
  48. tb = sys.exc_info()[2]
  49. # 为异常附加堆栈跟踪
  50. e = e.with_traceback(tb)
  51. # 输出详细的错误信息
  52. logger.error(f"处理微信回调消息出错: {json.dumps(body, separators=(',', ':'),ensure_ascii=False)}")
  53. logger.error(f"异常类型: {type(e).__name__}")
  54. logger.error(f"异常信息: {str(e)}")
  55. logger.error(f"堆栈跟踪: {traceback.format_exc()}")
  56. return {"message": "处理微信回调消息错误"}
  57. async def handle_self_cmd_async(request: Request,wxid,msg):
  58. '''
  59. 个人微信命令处理
  60. 如果是个人微信的指令,from_wxid == to_wxid
  61. commands = {
  62. '启用托管': True,
  63. '关闭托管': False
  64. }
  65. '''
  66. msg_data=msg.get("Data")
  67. to_wxid=msg_data["ToUserName"]["string"]
  68. from_wxid=msg_data["FromUserName"]["string"]
  69. msg_content=msg_data["Content"]["string"]
  70. if from_wxid == to_wxid and wxid == to_wxid:
  71. commands = {
  72. '启用托管': True,
  73. '关闭托管': False
  74. }
  75. if msg_content in commands:
  76. c_dict = await request.app.state.gewe_service.get_wxchat_config_from_cache_async(wxid)
  77. if c_dict:
  78. agent_config=AgentConfig.model_validate(c_dict)
  79. agent_config.agentEnabled=commands[msg_content]
  80. await request.app.state.gewe_service.save_wxchat_config_async(wxid, agent_config.model_dump())
  81. logger.info(f'{wxid} {"启动" if commands[msg_content] else "关闭"}托管')
  82. return {"message": "收到微信回调消息"}
  83. async def handle_messages_async(request: Request,token_id,msg):
  84. #msg_data=msg.get("Data")
  85. type_name =msg.get("TypeName")
  86. wxid = msg.get("Wxid",'')
  87. match type_name:
  88. case 'AddMsg':
  89. await handle_add_messages_async(request,token_id,msg,wxid)
  90. case 'ModContacts':
  91. await handle_mod_contacts_async(request,token_id,msg,wxid)
  92. case 'DelContacts':
  93. await handle_del_contacts_async(request,token_id,msg,wxid)
  94. case 'Offline':
  95. await handle_offline_async(request,token_id,msg,wxid)
  96. case _:
  97. logger.warning(f'未知消息类型:{type_name}')
  98. async def gpt_client_async(request, messages: list, wixd: str, friend_wxid: str):
  99. max_retries = 3
  100. retry_delay = 5 # 重试间隔时间(秒)
  101. for attempt in range(max_retries):
  102. try:
  103. c = await request.app.state.gewe_service.get_wxchat_config_from_cache_async(wixd)
  104. api_key = c.get('agentTokenId', "sk-jr69ONIehfGKe9JFphuNk4DU5Y5wooHKHhQv7oSnFzVbwCnW65fXO9kvH")
  105. base_url="http://106.15.182.218:3000"
  106. environment = os.environ.get('environment', 'default')
  107. if environment != 'default':
  108. base_url="http://172.19.42.59:3000"
  109. api_url = f"{base_url}/api/v1/chat/completions"
  110. headers = {
  111. "Content-Type": "application/json",
  112. "Authorization": f"Bearer {api_key}"
  113. }
  114. session_id = f'{wixd}-{friend_wxid}'
  115. data = {
  116. "model": "",
  117. "messages": messages,
  118. "chatId": session_id,
  119. "detail": True
  120. }
  121. logger.info("[CHATGPT] 请求={}".format(json.dumps(data, ensure_ascii=False)))
  122. async with aiohttp.ClientSession() as session:
  123. async with session.post(url=api_url, headers=headers, data=json.dumps(data), timeout=1200) as response:
  124. response.raise_for_status()
  125. response_data = await response.json()
  126. return response_data
  127. except (ClientError, asyncio.TimeoutError) as e:
  128. logger.error(f"[CHATGPT] 请求失败(尝试 {attempt + 1}/{max_retries}): {e}")
  129. if attempt < max_retries - 1:
  130. await asyncio.sleep(retry_delay)
  131. else:
  132. raise
  133. async def handle_add_messages_async(request: Request,token_id,msg,wxid):
  134. wx_config =await request.app.state.gewe_service.get_wxchat_config_from_cache_async(wxid)
  135. # if not bool(wx_config.get("agentEnabled",False)):
  136. # logger.info(f'微信ID {wxid} 未托管,不处理')
  137. # return
  138. app_id = msg.get("Appid")
  139. msg_data = msg.get("Data")
  140. msg_type = msg_data.get("MsgType",None)
  141. from_wxid = msg_data["FromUserName"]["string"]
  142. to_wxid = msg_data["ToUserName"]["string"]
  143. msg_push_content=msg_data.get("PushContent")
  144. validated_config = AgentConfig.model_validate(wx_config)
  145. if not validated_config.agentEnabled:
  146. logger.info(f'微信ID {wxid} 未托管,不处理 {msg_type}')
  147. return
  148. handlers = {
  149. 1: handle_text_async,
  150. 3: handle_image_async,
  151. 34: handle_voice_async,
  152. 42: handle_name_card_async,
  153. 43: handle_video_async,
  154. 49: handle_xml_async,
  155. 37: handle_add_friend_notice_async,
  156. 10002: handle_10002_msg_async,
  157. 10000: handle_10000_msg_async
  158. }
  159. # (扫码进群情况)判断受否是群聊,并添加到通信录
  160. if check_chatroom(from_wxid) or check_chatroom(to_wxid):
  161. logger.info('群信息')
  162. chatroom_id=from_wxid
  163. ret,msg,data=await request.app.state.gewe_service.save_contract_list_async(token_id,app_id,chatroom_id,3)
  164. logger.info(f'保存到通讯录 chatroom_id {chatroom_id} {msg}')
  165. await request.app.state.gewe_service.update_group_info_to_cache_async(token_id,app_id,wxid,chatroom_id)
  166. await request.app.state.gewe_service.update_group_members_to_cache_async(token_id,app_id,wxid,chatroom_id)
  167. handlers[1]=handle_text_group_async
  168. handlers[3]=handle_image_group_async
  169. handlers[34]=handle_voice_group_async
  170. handlers[43]=handle_video_group_async
  171. handler = handlers.get(msg_type)
  172. if handler:
  173. return await handler(request,token_id,app_id, wxid,msg_data,from_wxid, to_wxid)
  174. else:
  175. logger.warning(f"微信回调消息类型 {msg_type} 未处理")
  176. async def handle_mod_contacts_async(request: Request,token_id,msg,wxid):
  177. '''
  178. 好友通过验证及好友资料变更的通知消息
  179. '''
  180. wxid = msg.get("Wxid")
  181. msg_data = msg.get("Data")
  182. app_id = msg.get("Appid")
  183. #
  184. #handle_mod_contacts(token_id,app_id,wxid,msg_data)
  185. #
  186. user_name=msg_data.get("UserName",{}).get("string","")
  187. if not check_chatroom(user_name):
  188. # loop = asyncio.get_event_loop()
  189. # future = asyncio.run_coroutine_threadsafe(
  190. # handle_mod_contacts_worker_async(request,token_id,app_id,wxid,msg_data),
  191. # loop
  192. # )
  193. await handle_mod_contacts_worker_async(request,token_id,app_id,wxid,msg_data)
  194. #判断是否好友关系
  195. # is_friends=True
  196. # if is_friends:
  197. # loop = asyncio.get_event_loop()
  198. # future = asyncio.run_coroutine_threadsafe(
  199. # handle_mod_contacts_worker_async(request,token_id,app_id,wxid,msg_data),
  200. # loop
  201. # )
  202. # contact_wxid =msg_data.get("UserName",{}).get("string","") #msg_data["UserName"]["string"]
  203. # nickname= msg_data.get("NickName",{}).get("string","")#msg_data["NickName"]["string"]
  204. # city=msg_data.get("City",None)
  205. # signature=msg_data.get("Signature",None)
  206. # province=msg_data.get("Province",None)
  207. # bigHeadImgUrl=msg_data.get("SnsUserInfo",{}).get("SnsBgimgId",None) #msg_data["SnsUserInfo"]["SnsBgimgId"]
  208. # country=msg_data.get("Country",None)
  209. # sex=msg_data.get("Sex",None)
  210. # pyInitial= msg_data.get("PyInitial",{}).get("string",None)#msg_data["PyInitial"]["string"]
  211. # quanPin=msg_data.get("QuanPin",{}).get("string",None) #msg_data["QuanPin"]["string"]
  212. # remark=msg_data.get("Remark",{}).get("string",None)
  213. # remarkPyInitial=msg_data.get("RemarkPyInitial",{}).get("string",None)
  214. # remarkQuanPin=msg_data.get("RemarkQuanPin",{}).get("string",None)
  215. # smallHeadImgUrl=msg_data.get("smallHeadImgUrl",None)
  216. # #推动到kafka
  217. # contact_data = {
  218. # "alias": None,
  219. # "bigHeadImgUrl": bigHeadImgUrl,
  220. # "cardImgUrl": None,
  221. # "city": city,
  222. # "country": country,
  223. # "description": None,
  224. # "labelList": None,
  225. # "nickName": nickname,
  226. # "phoneNumList": None,
  227. # "province": province,
  228. # "pyInitial": pyInitial,
  229. # "quanPin": quanPin,
  230. # "remark": remark,
  231. # "remarkPyInitial": remarkPyInitial,
  232. # "remarkQuanPin": remarkQuanPin,
  233. # "sex": sex,
  234. # "signature": signature,
  235. # "smallHeadImgUrl": smallHeadImgUrl,
  236. # "snsBgImg": None,
  237. # "userName": contact_wxid
  238. # }
  239. # input_message=wx_mod_contact_message(wxid,contact_data)
  240. # await request.app.state.kafka_service.send_message_async(input_message)
  241. # else:
  242. # logger.info('删除好友通知')
  243. # contact_wxid =msg_data.get("UserName",{}).get("string","")
  244. # # 推送到kafka
  245. # input_message=wx_del_contact_message(wxid,contact_wxid)
  246. # await request.app.state.kafka_service.send_message_async(input_message)
  247. else:
  248. logger.info('群信息变更通知')
  249. chatroom_id=user_name
  250. ret,msg,data=await request.app.state.gewe_service.save_contract_list_async(token_id,app_id,chatroom_id,3)
  251. logger.info(f'保存到通讯录 chatroom_id {chatroom_id} {msg}')
  252. await request.app.state.gewe_service.update_group_info_to_cache_async(token_id,app_id,wxid,chatroom_id)
  253. await request.app.state.gewe_service.update_group_members_to_cache_async(token_id,app_id,wxid,chatroom_id)
  254. # group_info_members=await request.app.state.gewe_service.get_group_info_members_from_cache_async(wxid,chatroom_id)
  255. # k_message=wx_mod_group_info_members_message(wxid,group_info_members)
  256. # 全量推送
  257. #all_groups_info_menbers=await request.app.state.gewe_service.get_groups_info_members_from_cache_async(wxid)
  258. #k_message=wx_groups_info_members_message(wxid,all_groups_info_menbers)
  259. k_message=wx_groups_info_members_key_message(wxid)
  260. await request.app.state.kafka_service.send_message_async(k_message)
  261. async def handle_del_contacts_async(request: Request,token_id,msg,wxid):
  262. '''
  263. 删除好友通知/退出群聊
  264. '''
  265. msg_data = msg.get("Data")
  266. username=msg_data["UserName"]["string"]
  267. if check_chatroom(username):
  268. logger.info('退出群聊')
  269. wxid = msg.get("Wxid")
  270. chatroom_id=username
  271. await request.app.state.redis_service.delete_hash_field(f'__AI_OPS_WX__:GROUPS_INFO:{wxid}',chatroom_id)
  272. await request.app.state.redis_service.delete_hash_field(f'__AI_OPS_WX__:GROUPS_MEMBERS:{wxid}',chatroom_id)
  273. logger.info(f'清除 chatroom_id{chatroom_id} 数据')
  274. # 推送删除群资料到kafka
  275. k_message=wx_del_group_message(wxid,chatroom_id)
  276. await request.app.state.kafka_service.send_message_async(k_message)
  277. else:
  278. logger.info('删除好友通知')
  279. # 推送到kafka
  280. input_message=wx_del_contact_message(wxid,username)
  281. await request.app.state.kafka_service.send_message_async(input_message)
  282. async def handle_offline_async(request: Request,token_id,msg,wxid):
  283. '''
  284. 已经离线
  285. '''
  286. wxid = msg.get("Wxid")
  287. app_id = msg.get("Appid")
  288. logger.warning(f'微信ID {wxid}在设备{app_id}已经离线')
  289. k,r=await request.app.state.gewe_service.get_login_info_by_app_id_async(app_id)
  290. print(k)
  291. await request.app.state.redis_service.update_hash_field(k,'status',0)
  292. await request.app.state.redis_service.update_hash_field(k,'modify_at',int(time.time()))
  293. # 推送到kafka
  294. input_message=wx_offline_message(app_id,wxid)
  295. await request.app.state.kafka_service.send_message_async(input_message)
  296. async def handle_mod_contacts_worker_async(request:Request,token_id,app_id,wxid,msg_data):
  297. '''
  298. 好友通过验证及好友资料变更的通知消息
  299. '''
  300. logger.info('好友通过验证及好友资料变更的通知消息')
  301. if not check_chatroom(msg_data["UserName"]["string"]):
  302. contact_wxid = msg_data["UserName"]["string"]
  303. ret,msg,contacts_list = await request.app.state.gewe_service.fetch_contacts_list_async(token_id, app_id)
  304. friend_wxids = [c for c in contacts_list['friends'] if c not in ['fmessage', 'medianote','weixin','weixingongzhong','tmessage']] # 可以调整截取范围
  305. print(f'{wxid}的好友资料变更,数量 {len(friend_wxids)}')
  306. data = await request.app.state.gewe_service.save_contacts_brief_to_cache_async(token_id, app_id, wxid, friend_wxids)
  307. #k_message = wx_all_contacts_message(wxid, data)
  308. k_message = wx_all_contacts_key_message(wxid)
  309. await request.app.state.kafka_service.send_message_async(k_message)
  310. else:
  311. logger.info('群聊好友通过验证及好友资料变更的通知消息')
  312. async def handle_text_async(request: Request,token_id,app_id, wxid,msg_data,from_wxid, to_wxid):
  313. '''
  314. 私聊文本消息
  315. '''
  316. config=await request.app.state.gewe_service.get_wxchat_config_from_cache_async(wxid)
  317. validated_config = AgentConfig.model_validate(config)
  318. if not validated_config.privateGroupChatEnabled:
  319. logger.warning(f"微信号 {wxid} 关闭好友和群自动回复功能,{handle_text_async.__name__} 不回复消息")
  320. return
  321. # 判断是否转人工处理功能
  322. is_human_handle_msg= await request.app.state.gewe_service.is_human_handle_msg_with_contact_wxid_async(wxid,from_wxid)
  323. if is_human_handle_msg:
  324. logger.warning(f'微信号 {wxid} 发送到微信号{to_wxid} 暂时工人接管30分钟中')
  325. return
  326. msg_content=msg_data["Content"]["string"]
  327. if wxid == from_wxid: #手动发送消息
  328. logger.info(f"{wxid} 手动发送消息")
  329. await request.app.state.gewe_service.save_contacts_brief_to_cache_async(token_id,app_id,wxid,[to_wxid])
  330. callback_to_user=msg_data["ToUserName"]["string"]
  331. # 转人工处理功能
  332. await request.app.state.gewe_service.set_human_handle_msg_with_contact_wxid_async(wxid,to_wxid,60*30)
  333. # 推送到kafka
  334. input_wx_content_dialogue_message=[{"type": "text", "text": msg_content}]
  335. input_message=dialogue_message(from_wxid,to_wxid,input_wx_content_dialogue_message)
  336. await request.app.state.kafka_service.send_message_async(input_message)
  337. logger.info("发送对话 %s",input_message)
  338. else:
  339. callback_to_user=msg_data["FromUserName"]["string"]
  340. # 判断哪些关键词存在于 msg_content 中
  341. keywords = ["预约", "报价", "购买", "价钱","价格", "多少钱", "下单"]
  342. found_keywords = [keyword for keyword in keywords if keyword in msg_content]
  343. if found_keywords:
  344. await request.app.state.gewe_service.set_human_handle_msg_with_contact_wxid_key_word_async(wxid,callback_to_user,60*30)
  345. logger.info(f"{wxid} 收到 {callback_to_user} 私聊消息匹配到关键词:{', '.join(found_keywords)}")
  346. # 回复好友
  347. await request.app.state.gewe_service.post_text_async(token_id, app_id, callback_to_user, "我这边目前有点忙,稍后回复您好吗?")
  348. await asyncio.sleep(random.uniform(1.5,3))
  349. # 推送到助理
  350. print('推送到助理')
  351. '''
  352. 长服AI商机提醒助理
  353. 管家助理
  354. 18664262743
  355. wxid_9pocbage7cdb22
  356. '''
  357. contacts_brief= await request.app.state.gewe_service.get_contacts_brief_from_cache_async(wxid)
  358. contact_nick_name=next(filter(lambda x:x.get("userName") == callback_to_user,contacts_brief),{}).get("nickName","")
  359. assistant_msg_content=f'AI管家转人工提醒:【{contact_nick_name}】有{found_keywords[0]}需求'
  360. await request.app.state.gewe_service.post_text_async(token_id, app_id, 'wxid_9pocbage7cdb22', assistant_msg_content)
  361. k,loginfo=await request.app.state.gewe_service.get_login_info_by_wxid_async('wxid_9pocbage7cdb22')
  362. if not k:
  363. logger.warning(f'助理微信号 wxid_9pocbage7cdb22 不存在')
  364. return
  365. staus=loginfo.get('status','0')
  366. if staus != '1':
  367. logger.warning(f'助理微信号 wxid_9pocbage7cdb22 不在线')
  368. return
  369. kf_token_id=loginfo.get('tokenId','')
  370. kf_appid=loginfo.get('appId','')
  371. await asyncio.sleep(random.uniform(1.5,3))
  372. assistant_msg_content=f'收到,{assistant_msg_content}'
  373. await request.app.state.gewe_service.post_text_async(kf_token_id, kf_appid, wxid, assistant_msg_content)
  374. return
  375. # 是否在转人工处理
  376. is_human_handle_msg_with_contact_wxid= await request.app.state.gewe_service.is_human_handle_msg_with_contact_wxid_key_word_async(wxid,callback_to_user)
  377. if is_human_handle_msg_with_contact_wxid:
  378. logger.warning(f'微信号 {wxid} 与 {callback_to_user} 有关键字匹配,暂时工人接管30分钟中,请查看长服AI商机提醒助理')
  379. return
  380. request.app.state.message_lock[app_id]= asyncio.Lock()
  381. # 创建并启动任务协程,将参数传递给 ai_chat_text 函数
  382. task = asyncio.create_task(
  383. ai_chat_text_async(request,token_id, app_id, wxid, msg_data, msg_content)
  384. )
  385. # 设置定时器,1秒后检查任务是否超时。这里需要使用 lambda 来传递参数
  386. timeout_timer = asyncio.create_task(
  387. check_timeout_async(task, request,token_id, wxid, app_id, callback_to_user)
  388. )
  389. # 等待任务协程完成
  390. await task
  391. # 取消定时器
  392. timeout_timer.cancel()
  393. #message_lock = asyncio.Lock()
  394. async def check_timeout_async(task: asyncio.Task, request: Request,token_id, wxid, app_id, callback_to_user):
  395. await asyncio.sleep(timeout_duration) # 等待超时时间
  396. if not task.done():
  397. message_lock=request.app.state.message_lock[app_id]
  398. async with message_lock:
  399. print(f"任务运行时间超过{timeout_duration}秒,token_id={token_id}, app_id={app_id}, callback_to_user={callback_to_user}")
  400. wx_config = await request.app.state.gewe_service.get_wxchat_config_from_cache_async(wxid)
  401. if bool(wx_config.get("chatWaitingMsgEnabled", True)):
  402. # if callback_to_user == 'wxid_mesh33pw13e721':
  403. # logger.info(f'wxid_mesh33pw13e721 不发送到微信有关等待的AI回复到微信')
  404. # else:
  405. # phrases = ["稍等一下", "辛苦等等", "马上就好", "很快就好", "请稍后", "请等会", "稍等1分钟","请别急,在整理","就好了"]
  406. # # 随机选择一个短语
  407. # random_phrase = random.choice(phrases)
  408. # await request.app.state.gewe_service.post_text_async(token_id, app_id, callback_to_user, random_phrase)
  409. phrases = ["稍等一下", "辛苦等等", "马上就好", "很快就好", "请稍后", "请等会", "稍等1分钟","请别急,在整理","就好了"]
  410. random_phrase = random.choice(phrases)
  411. await request.app.state.gewe_service.post_text_async(token_id, app_id, callback_to_user, random_phrase)
  412. #await request.app.state.gewe_service.post_text_async(token_id, app_id, callback_to_user, "亲,我正在组织回复的信息,请稍等一会")
  413. async def ai_chat_text_async(request: Request,token_id, app_id, wxid, msg_data, msg_content):
  414. start_time = time.time() # 记录任务开始时间
  415. callback_to_user = msg_data["FromUserName"]["string"]
  416. k,loginfo=await request.app.state.gewe_service.get_login_info_by_wxid_async(wxid)
  417. wxid_nickname=loginfo.get("nickName")
  418. contacts_brief:list=await request.app.state.gewe_service.get_contacts_brief_from_cache_async(wxid)
  419. #callback_to_user_nickname=next(filter(lambda x:x.get("userName") == callback_to_user,contacts_brief),None).get("nickName")
  420. callback_to_user_nickname = next(filter(lambda x: x.get("userName") == callback_to_user, contacts_brief), {}).get("nickName", "")
  421. hash_key = f'__AI_OPS_WX__:MESSAGES:{wxid}:{callback_to_user}'
  422. prompt = {"role": "user", "content": [{
  423. "type": "text",
  424. "text": msg_content
  425. }]}
  426. messages_to_send = await request.app.state.gewe_service.save_session_messages_to_cache_async(hash_key, prompt)
  427. # 收到的对话
  428. input_wx_content_dialogue_message = [{"type": "text", "text": msg_content}]
  429. input_message = dialogue_message(callback_to_user, wxid, input_wx_content_dialogue_message)
  430. await request.app.state.kafka_service.send_message_async(input_message)
  431. logger.info("发送对话 %s", input_message)
  432. cache_data = USER_INTERACTIVE_CACHE.get(wxid)
  433. if cache_data and cache_data.get('interactive'):
  434. o = get_first_char_if_digit(msg_content)
  435. if o is not None:
  436. userSelectOptions = cache_data.get('options')
  437. if o < len(userSelectOptions):
  438. o = o - 1
  439. msg_content = userSelectOptions[o].get("value")
  440. messages_to_send = [{"role": "user", "content": msg_content}]
  441. else:
  442. messages_to_send = [{"role": "user", "content": msg_content}]
  443. else:
  444. messages_to_send = [{"role": "user", "content": msg_content}]
  445. res = await gpt_client_async(request,messages_to_send, wxid, callback_to_user)
  446. reply_content = remove_markdown_symbol(res["choices"][0]["message"]["content"])
  447. description = ''
  448. userSelectOptions = []
  449. if isinstance(reply_content, list) and any(item.get("type") == "interactive" for item in reply_content):
  450. for item in reply_content:
  451. if item["type"] == "interactive" and item["interactive"]["type"] == "userSelect":
  452. params = item["interactive"]["params"]
  453. description = params.get("description")
  454. userSelectOptions = params.get("userSelectOptions", [])
  455. values_string = "\n".join(option["value"] for option in userSelectOptions)
  456. if description is not None:
  457. USER_INTERACTIVE_CACHE[wxid] = {
  458. "interactive": True,
  459. "options": userSelectOptions,
  460. }
  461. reply_content = description + '------------------------------\n' + values_string
  462. elif isinstance(reply_content, list) and any(item.get("type") == "text" for item in reply_content):
  463. USER_INTERACTIVE_CACHE[wxid] = {
  464. "interactive": False
  465. }
  466. text = ''
  467. for item in reply_content:
  468. if item["type"] == "text":
  469. text = item["text"]["content"]
  470. if text == '':
  471. # 去除上次上一轮对话再次请求
  472. cache_messages_str = await request.app.state.redis_service.get_hash_field(hash_key, "data")
  473. cache_messages = json.loads(cache_messages_str) if cache_messages_str else []
  474. if len(cache_messages) >= 3:
  475. cache_messages = cache_messages[:-3]
  476. await request.app.state.redis_service.update_hash_field(hash_key, "data", json.dumps(cache_messages, ensure_ascii=False))
  477. messages_to_send = await request.app.state.gewe_service.save_session_messages_to_cache_async(hash_key, prompt)
  478. res = await gpt_client_async(request,messages_to_send, wxid, callback_to_user)
  479. reply_content = remove_markdown_symbol(res["choices"][0]["message"]["content"])
  480. if isinstance(reply_content, list):
  481. reply_content = remove_markdown_symbol(reply_content[0].get('text').get("content"))
  482. else:
  483. reply_content = text
  484. else:
  485. USER_INTERACTIVE_CACHE[wxid] = {
  486. "interactive": False
  487. }
  488. reply_content = remove_markdown_symbol(res["choices"][0]["message"]["content"])
  489. if reply_content == '不回复':
  490. end_time = time.time() # 记录任务结束时间
  491. execution_time = end_time - start_time # 计算执行时间
  492. logger.warning(f"AI回答任务完成,耗时 {execution_time:.2f} 秒,AI回答<不回复>,跳过微信回复")
  493. await request.app.state.gewe_service.save_session_messages_to_cache_async(hash_key, {"role": "assistant", "content": reply_content})
  494. return
  495. message_lock=request.app.state.message_lock[app_id]
  496. # 昵称替换
  497. replacements = {
  498. '{昵称}': wxid_nickname,
  499. '{好友昵称}': callback_to_user_nickname
  500. }
  501. reply_content=replace_placeholders(reply_content, replacements)
  502. # 判断图片url
  503. img_urls,reply_content=extract_and_replace_image_urls(reply_content)
  504. if img_urls:
  505. #await request.app.state.gewe_service.post_text_async(token_id, app_id, callback_to_user, reply_content)
  506. async with message_lock:
  507. await ai_post_text_split_async_async(request, token_id, app_id, callback_to_user, reply_content)
  508. await asyncio.sleep(random.uniform(1.5, 3))
  509. for img_url in img_urls:
  510. await request.app.state.gewe_service.post_image_async(token_id, app_id, callback_to_user, img_url)
  511. await asyncio.sleep(random.uniform(1.5, 3))
  512. # 判断视频url
  513. video_urls,reply_content=extract_and_replace_video_urls(reply_content)
  514. if video_urls:
  515. #await request.app.state.gewe_service.post_text_async(token_id, app_id, callback_to_user, reply_content)
  516. async with message_lock:
  517. await ai_post_text_split_async_async(request, token_id, app_id, callback_to_user, reply_content)
  518. await asyncio.sleep(random.uniform(1.5, 3))
  519. for video_url in video_urls:
  520. parsed_url = urlparse(video_url)
  521. filename = os.path.basename(parsed_url.path)
  522. tmp_file_path = os.path.join(os.getcwd(),'tmp', filename) # 拼接完整路径
  523. thumbnail_path=tmp_file_path.replace('.mp4','.jpg')
  524. video_thumb_url,video_duration =download_video_and_get_thumbnail(video_url,thumbnail_path)
  525. logger.info(f'{wxid} 视频缩略图 {video_thumb_url} 时长 {video_duration}')
  526. ret,ret_msg,res = await request.app.state.gewe_service.post_video_async(token_id, app_id, callback_to_user, video_url,video_thumb_url,video_duration)
  527. if ret!=200:
  528. logger.warning(f'{wxid} 发送视频{video_url} 到 {callback_to_user} 失败,{ret_msg}')
  529. await asyncio.sleep(random.uniform(1.5, 3))
  530. # 发送AI微信回复
  531. #await request.app.state.gewe_service.post_text_async(token_id, app_id, callback_to_user, reply_content)
  532. if (not video_urls) and (not img_urls):
  533. async with message_lock:
  534. await ai_post_text_split_async_async(request, token_id, app_id, callback_to_user, reply_content)
  535. await request.app.state.gewe_service.save_session_messages_to_cache_async(hash_key, {"role": "assistant", "content": reply_content})
  536. # 回复的对话
  537. input_wx_content_dialogue_message = [{"type": "text", "text": reply_content}]
  538. input_message = dialogue_message(wxid, callback_to_user, input_wx_content_dialogue_message, True)
  539. await request.app.state.kafka_service.send_message_async(input_message)
  540. logger.info("发送对话 %s", input_message)
  541. end_time = time.time() # 记录任务结束时间
  542. execution_time = end_time - start_time # 计算执行时间
  543. logger.info(f"AI回答任务完成,耗时 {execution_time:.2f} 秒")
  544. # async def ai_post_text_split_async_async(request: Request, token_id, app_id, callback_to_user, reply_content):
  545. # parts = reply_content.split('\n\n')
  546. # for part in parts:
  547. # await request.app.state.gewe_service.post_text_async(token_id, app_id, callback_to_user, part)
  548. # await asyncio.sleep(random.uniform(1.5, 3))
  549. async def ai_post_text_split_async_async(request: Request, token_id, app_id, callback_to_user, reply_content):
  550. parts = reply_content.split('\n\n')
  551. i = 0
  552. while i < len(parts):
  553. current_part = parts[i].strip() # 去除首尾空白字符
  554. # 如果当前段长度小于30个汉字,则尝试与下一段合并
  555. while len(current_part) < 30 and i + 1 < len(parts):
  556. i += 1
  557. current_part += "\n " + parts[i].strip() # 合并下一段
  558. # 打印合并后的内容
  559. await request.app.state.gewe_service.post_text_async(token_id, app_id, callback_to_user, current_part)
  560. await asyncio.sleep(random.uniform(1.5, 3))
  561. i += 1
  562. async def handle_text_group_async(request: Request,token_id,app_id, wxid,msg_data,from_wxid, to_wxid):
  563. '''
  564. 群聊文本消息
  565. '''
  566. msg_content=msg_data["Content"]["string"]
  567. msg_push_content=msg_data.get("PushContent")
  568. k,login_info=await request.app.state.gewe_service.get_login_info_by_app_id_async(app_id)
  569. nickname=login_info.get("nickName")
  570. config=await request.app.state.gewe_service.get_wxchat_config_from_cache_async(wxid)
  571. validated_config = AgentConfig.model_validate(config)
  572. if not validated_config.privateGroupChatEnabled:
  573. logger.warning(f"微信号 {wxid} 关闭好友和群自动回复功能,{handle_text_group_async.__name__} 不回复消息")
  574. return
  575. if from_wxid == to_wxid: #手动发送消息
  576. logger.info("Active message sending detected")
  577. await request.app.state.gewe_service.save_contacts_brief_to_cache_async(token_id,app_id,wxid,[to_wxid])
  578. callback_to_user=msg_data["ToUserName"]["string"]
  579. input_wx_content_dialogue_message=[{"type": "text", "text": msg_content}]
  580. input_message=dialogue_message(from_wxid,to_wxid,input_wx_content_dialogue_message)
  581. await request.app.state.kafka_service.send_message_async(input_message)
  582. logger.info("发送对话 %s",input_message)
  583. else:
  584. c = await request.app.state.gewe_service.get_wxchat_config_from_cache_async(wxid)
  585. chatroom_id_white_list = c.get("chatroomIdWhiteList", [])
  586. if not chatroom_id_white_list:
  587. logger.info('白名单为空或未定义,不处理')
  588. return
  589. if from_wxid not in chatroom_id_white_list:
  590. logger.info(f'群ID {from_wxid} 不在白名单中,不处理')
  591. return
  592. if '在群聊中@了你' in msg_push_content or '@'+nickname in msg_push_content:
  593. callback_to_user=msg_data["FromUserName"]["string"]
  594. hash_key = f'__AI_OPS_WX__:MESSAGES:{wxid}:{callback_to_user}'
  595. prompt={"role": "user", "content": [{
  596. "type": "text",
  597. "text": msg_content
  598. }]}
  599. messages_to_send=await request.app.state.gewe_service.save_session_messages_to_cache_async(hash_key, prompt)
  600. # 收到的对话
  601. input_wx_content_dialogue_message=[{"type": "text", "text": msg_content}]
  602. input_message=dialogue_message(callback_to_user,wxid,input_wx_content_dialogue_message)
  603. await request.app.state.kafka_service.send_message_async(input_message)
  604. logger.info("发送对话 %s",input_message)
  605. cache_data = USER_INTERACTIVE_CACHE.get(wxid)
  606. if cache_data and cache_data.get('interactive') :
  607. o=get_first_char_if_digit(msg_content)
  608. if o is not None:
  609. userSelectOptions=cache_data.get('options')
  610. if o < len(userSelectOptions):
  611. o=o-1
  612. msg_content=userSelectOptions[o].get("value")
  613. messages_to_send=[{"role": "user", "content": msg_content}]
  614. else:
  615. messages_to_send=[{"role": "user", "content": msg_content}]
  616. else:
  617. messages_to_send=[{"role": "user", "content": msg_content}]
  618. res=await gpt_client_async(request,messages_to_send,wxid,callback_to_user)
  619. reply_content=remove_markdown_symbol(res["choices"][0]["message"]["content"])
  620. description = ''
  621. userSelectOptions = []
  622. if isinstance(reply_content, list) and any(item.get("type") == "interactive" for item in reply_content):
  623. for item in reply_content:
  624. if item["type"] == "interactive" and item["interactive"]["type"] == "userSelect":
  625. params = item["interactive"]["params"]
  626. description = params.get("description")
  627. userSelectOptions = params.get("userSelectOptions", [])
  628. values_string = "\n".join(option["value"] for option in userSelectOptions)
  629. if description is not None:
  630. USER_INTERACTIVE_CACHE[wxid] = {
  631. "interactive":True,
  632. "options": userSelectOptions,
  633. }
  634. reply_content=description + '------------------------------\n'+values_string
  635. elif isinstance(reply_content, list) and any(item.get("type") == "text" for item in reply_content):
  636. USER_INTERACTIVE_CACHE[wxid] = {
  637. "interactive":False
  638. }
  639. text=''
  640. for item in reply_content:
  641. if item["type"] == "text":
  642. text=item["text"]["content"]
  643. if text=='':
  644. # 去除上次上一轮对话再次请求
  645. cache_messages_str=await request.app.state.redis_service.get_hash_field(hash_key,"data")
  646. cache_messages = json.loads(cache_messages_str) if cache_messages_str else []
  647. if len(cache_messages) >= 3:
  648. cache_messages = cache_messages[:-3]
  649. await request.app.state.redis_service.update_hash_field(hash_key,"data",json.dumps(cache_messages,ensure_ascii=False))
  650. messages_to_send=await request.app.state.gewe_service.save_session_messages_to_cache_async(hash_key, prompt)
  651. res=await gpt_client_async(request,messages_to_send,wxid,callback_to_user)
  652. reply_content=remove_markdown_symbol(res["choices"][0]["message"]["content"])
  653. else:
  654. reply_content=text
  655. else:
  656. USER_INTERACTIVE_CACHE[wxid] = {
  657. "interactive":False
  658. }
  659. reply_content=res["choices"][0]["message"]["content"]
  660. reply_content='@'+extract_nickname(msg_push_content) + reply_content
  661. await request.app.state.gewe_service.post_text_async(token_id,app_id,callback_to_user,reply_content)
  662. await request.app.state.gewe_service.save_session_messages_to_cache_async(hash_key, {"role": "assistant", "content": reply_content})
  663. # 回复的对话
  664. reply_content=f'{wxid}:\n'+ reply_content
  665. input_wx_content_dialogue_message=[{"type": "text", "text": reply_content}]
  666. input_message=dialogue_message(wxid,callback_to_user,input_wx_content_dialogue_message,True)
  667. await request.app.state.kafka_service.send_message_async(input_message)
  668. logger.info("发送对话 %s",input_message)
  669. else:
  670. logger.info('群聊公开消息')
  671. callback_to_user=msg_data["FromUserName"]["string"]
  672. group_dialogue_message=[{"type": "text", "text": msg_content}]
  673. input_message=dialogue_message(callback_to_user,wxid,group_dialogue_message)
  674. await request.app.state.kafka_service.send_message_async(input_message)
  675. logger.info("发送对话 %s",input_message)
  676. return
  677. async def handle_image_async(request: Request,token_id,app_id, wxid,msg_data,from_wxid, to_wxid):
  678. '''
  679. 私聊图片消息
  680. '''
  681. msg_content=msg_data["Content"]["string"]
  682. callback_to_user=from_wxid
  683. hash_key = f'__AI_OPS_WX__:MESSAGES:{wxid}:{callback_to_user}'
  684. wx_img_url= await request.app.state.gewe_service.download_image_msg_async(token_id,app_id,msg_content)
  685. if not wx_img_url:
  686. logger.warning(f'{wxid} 下载 {callback_to_user} 图片失败')
  687. return
  688. oss_access_key_id="LTAI5tRTG6pLhTpKACJYoPR5"
  689. oss_access_key_secret="E7dMzeeMxq4VQvLg7Tq7uKf3XWpYfN"
  690. oss_endpoint="http://oss-cn-shanghai.aliyuncs.com"
  691. oss_bucket_name="cow-agent"
  692. oss_prefix="cow"
  693. img_url=upload_oss(oss_access_key_id, oss_access_key_secret, oss_endpoint, oss_bucket_name, wx_img_url, oss_prefix)
  694. prompt={
  695. "role": "user",
  696. "content": [{
  697. "type": "image_url",
  698. "image_url": {"url": img_url}
  699. }]
  700. }
  701. await request.app.state.gewe_service.save_session_messages_to_cache_async(hash_key, prompt)
  702. await request.app.state.gewe_service.post_text_async(token_id,app_id,callback_to_user,'已经上传了图片,有什么可以为您服务')
  703. logger.info(f"上传图片 URL: {img_url}")
  704. wx_content_dialogue_message=[{"type": "image_url", "image_url": {"url": img_url}}]
  705. input_message=dialogue_message(wxid,callback_to_user,wx_content_dialogue_message)
  706. await request.app.state.kafka_service.send_message_async(input_message)
  707. logger.info("发送对话 %s",input_message)
  708. async def handle_image_group_async(request: Request,token_id,app_id, wxid,msg_data,from_wxid, to_wxid):
  709. logger.info('群聊图片消息')
  710. msg_content=msg_data["Content"]["string"]
  711. callback_to_user=msg_data["FromUserName"]["string"]
  712. aeskey = re.search(r'aeskey="([^"]+)"', msg_content).group(1)
  713. cdnthumburl = re.search(r'cdnthumburl="([^"]+)"', msg_content).group(1)
  714. md5 = re.search(r'md5="([^"]+)"', msg_content).group(1)
  715. cdnthumblength = re.search(r'cdnthumblength="([^"]+)"', msg_content).group(1)
  716. cdnthumbheight = re.search(r'cdnthumbheight="([^"]+)"', msg_content).group(1)
  717. cdnthumbwidth = re.search(r'cdnthumbwidth="([^"]+)"', msg_content).group(1)
  718. length = re.search(r'length="([^"]+)"', msg_content).group(1)
  719. img_xml=f'<?xml version=\"1.0\"?>\n<msg>\n\t<img aeskey=\"{aeskey}\" encryver=\"1\" cdnthumbaeskey=\"{aeskey}\" cdnthumburl=\"{cdnthumburl}\" cdnthumblength=\"{cdnthumblength}\" cdnthumbheight=\"{cdnthumbheight}\" cdnthumbwidth=\"{cdnthumbwidth}\" cdnmidheight=\"0\" cdnmidwidth=\"0\" cdnhdheight=\"0\" cdnhdwidth=\"0\" cdnmidimgurl=\"{cdnthumburl}\" length=\"{length}\" md5=\"{md5}\" />\n\t<platform_signature></platform_signature>\n\t<imgdatahash></imgdatahash>\n</msg>'
  720. wx_img_url= await request.app.state.gewe_service.download_image_msg_async(token_id,app_id,img_xml)
  721. if not wx_img_url:
  722. logger.warning(f'{wxid} 下载 {callback_to_user} 图片失败')
  723. return
  724. oss_url=wx_img_url_to_oss_url(wx_img_url)
  725. reply_content = re.sub(r'<\?xml.*', f'{oss_url}', msg_content, flags=re.DOTALL)
  726. #reply_content=f'{wxid}:\n{oss_url}'
  727. input_wx_content_dialogue_message=[{"type": "text", "text": reply_content}]
  728. input_message=dialogue_message(callback_to_user,wxid,input_wx_content_dialogue_message,False)
  729. await request.app.state.kafka_service.send_message_async(input_message)
  730. logger.info("发送对话 %s",input_message)
  731. async def handle_voice_async(request: Request,token_id,app_id, wxid,msg_data,from_wxid, to_wxid):
  732. '''
  733. 私聊语音消息
  734. '''
  735. callback_to_user=from_wxid
  736. msg_content=msg_data["Content"]["string"]
  737. msg_id=msg_data["MsgId"]
  738. request.app.state.message_lock[app_id]=asyncio.Lock()
  739. config=await request.app.state.gewe_service.get_wxchat_config_from_cache_async(wxid)
  740. validated_config = AgentConfig.model_validate(config)
  741. if not validated_config.privateGroupChatEnabled:
  742. logger.warning(f"微信号 {wxid} 关闭好友和群自动回复功能,{handle_voice_async.__name__} 不回复消息")
  743. return
  744. file_url=await request.app.state.gewe_service.download_audio_msg_async(token_id,app_id,msg_id,msg_content)
  745. react_silk_path=await save_to_local_from_url_async(file_url)
  746. react_wav_path = os.path.splitext(react_silk_path)[0] + ".wav"
  747. audio_convert.any_to_wav(react_silk_path,react_wav_path)
  748. react_voice_text=AliVoice().voiceToText(react_wav_path)
  749. os.remove(react_silk_path)
  750. os.remove(react_wav_path)
  751. hash_key = f'__AI_OPS_WX__:MESSAGES:{wxid}:{callback_to_user}'
  752. messages=await request.app.state.gewe_service.save_session_messages_to_cache_async(hash_key, {"role": "user", "content": react_voice_text})
  753. ai_res=await gpt_client_async(request,messages,wxid,callback_to_user)
  754. ai_res_content=remove_markdown_symbol(ai_res["choices"][0]["message"]["content"])
  755. has_url=contains_url(ai_res_content)
  756. if not has_url:
  757. voice_during,voice_url=wx_voice(ai_res_content)
  758. if voice_during < 60 * 1000:
  759. ret,ret_msg,res=await request.app.state.gewe_service.post_voice_async(token_id,app_id,callback_to_user,voice_url,voice_during)
  760. else:
  761. ret,ret_msg,res=await request.app.state.gewe_service.post_text_async(token_id,app_id,callback_to_user,ai_res_content)
  762. logger.warning(f'回应语音消息长度 {voice_during/1000}秒,超过60秒,转为文本回复')
  763. if ret==200:
  764. logger.info((f'{wxid} 向 {callback_to_user} 发送语音文本【{ai_res_content}】{ret_msg}'))
  765. else:
  766. logger.warning((f'{wxid} 向 {callback_to_user} 发送语音文本【{ai_res_content}】{ret_msg}'))
  767. ret,ret_msg,res==await request.app.state.gewe_service.post_text_async(token_id,app_id,callback_to_user,ai_res_content)
  768. logger.info((f'{wxid} 向 {callback_to_user} 发送文本【{ai_res_content}】{ret_msg}'))
  769. else:
  770. # logger.info(f"回复内容包含网址,不发送语音,回复文字内容:{ai_res_content}")
  771. # ret,ret_msg,res=await request.app.state.gewe_service.post_text_async(token_id,app_id,callback_to_user,ai_res_content)
  772. reply_content=ai_res_content
  773. # 判断图片url
  774. img_urls,reply_content=extract_and_replace_image_urls(reply_content)
  775. if img_urls:
  776. message_lock=request.app.state.message_lock[app_id]
  777. #await request.app.state.gewe_service.post_text_async(token_id, app_id, callback_to_user, reply_content)
  778. async with message_lock:
  779. await ai_post_text_split_async_async(request, token_id, app_id, callback_to_user, reply_content)
  780. await asyncio.sleep(random.uniform(1.5, 3))
  781. for img_url in img_urls:
  782. await request.app.state.gewe_service.post_image_async(token_id, app_id, callback_to_user, img_url)
  783. await asyncio.sleep(random.uniform(1.5, 3))
  784. # 判断视频url
  785. video_urls,reply_content=extract_and_replace_video_urls(reply_content)
  786. if video_urls:
  787. #await request.app.state.gewe_service.post_text_async(token_id, app_id, callback_to_user, reply_content)
  788. async with message_lock:
  789. await ai_post_text_split_async_async(request, token_id, app_id, callback_to_user, reply_content)
  790. await asyncio.sleep(random.uniform(1.5, 3))
  791. for video_url in video_urls:
  792. parsed_url = urlparse(video_url)
  793. filename = os.path.basename(parsed_url.path)
  794. tmp_file_path = os.path.join(os.getcwd(),'tmp', filename) # 拼接完整路径
  795. thumbnail_path=tmp_file_path.replace('.mp4','.jpg')
  796. video_thumb_url,video_duration =download_video_and_get_thumbnail(video_url,thumbnail_path)
  797. logger.info(f'{wxid} 视频缩略图 {video_thumb_url} 时长 {video_duration}')
  798. ret,ret_msg,res = await request.app.state.gewe_service.post_video_async(token_id, app_id, callback_to_user, video_url,video_thumb_url,video_duration)
  799. if ret!=200:
  800. logger.warning(f'{wxid} 发送视频{video_url} 到 {callback_to_user} 失败,{ret_msg}')
  801. await asyncio.sleep(random.uniform(1.5, 3))
  802. # 发送AI微信回复
  803. #await request.app.state.gewe_service.post_text_async(token_id, app_id, callback_to_user, reply_content)
  804. if (not video_urls) and (not img_urls):
  805. async with message_lock:
  806. await ai_post_text_split_async_async(request, token_id, app_id, callback_to_user, reply_content)
  807. await request.app.state.gewe_service.save_session_messages_to_cache_async(hash_key, {"role": "assistant", "content": ai_res_content})
  808. # 构造对话消息并发送到 Kafka
  809. input_wx_content_dialogue_message = [{"type": "text", "text": ai_res_content}]
  810. input_message = dialogue_message(wxid, callback_to_user, input_wx_content_dialogue_message,True)
  811. await request.app.state.kafka_service.send_message_async(input_message)
  812. logger.info("发送对话 %s", input_message)
  813. async def handle_voice_group_async(request: Request,token_id,app_id, wxid,msg_data,from_wxid, to_wxid):
  814. logger.info('群聊语音消息')
  815. async def handle_name_card_async(request: Request,token_id,app_id, wxid,msg_data,from_wxid, to_wxid):
  816. logger.info('名片消息')
  817. try:
  818. msg_content_xml=msg_data["Content"]["string"]
  819. # 解析XML字符串
  820. root = ET.fromstring(msg_content_xml)
  821. # 提取alias属性
  822. alias_value = root.get("alias")
  823. # 加好友资料
  824. scene = int(root.get("scene"))
  825. v3 = root.get("username")
  826. v4 = root.get("antispamticket")
  827. logger.info(f"alias_value: {alias_value}, scene: {scene}, v3: {v3}, v4: {v4}")
  828. # 判断appid 是否已经创建3天
  829. k, login_info = await request.app.state.gewe_service.get_login_info_by_wxid_async(wxid)
  830. creation_timestamp=int(login_info.get('create_at',time.time()))
  831. current_timestamp = time.time()
  832. three_days_seconds = 3 * 24 * 60 * 60 # 三天的秒数
  833. diff_flag=(current_timestamp - creation_timestamp) >= three_days_seconds
  834. if not diff_flag:
  835. log_content=f'名片添加好友功能,{wxid} 用户创建不够三天,不能使用该功能'
  836. logger.warning(log_content)
  837. return
  838. # 将加好友资料添加到待加好友队列
  839. #gewe_chat.wxchat.enqueue_to_add_contacts(wxid,scene,v3,v4)
  840. _,loginfo=await request.app.state.gewe_service.get_login_info_by_wxid_async(wxid)
  841. nickname=loginfo.get('nickName')
  842. add_contact_content=f'您好,我是{nickname}'
  843. #gewe_chat.wxchat.add_contacts(token_id,app_id,scene,Models.OperationType.ADD_FRIEND,v3,v4,add_contact_content)
  844. await request.app.state.gewe_service.add_contacts_async(token_id,app_id,scene,OperationType.ADD_FRIEND.value,v3,v4,add_contact_content)
  845. except ET.ParseError as e:
  846. logger.error(f"XML解析错误: {e}")
  847. except KeyError as e:
  848. logger.error(f"字典键错误: {e}")
  849. except Exception as e:
  850. logger.error(f"未知错误: {e}")
  851. async def handle_video_async(request: Request,token_id,app_id, wxid,msg_data,from_wxid, to_wxid):
  852. logger.info('视频消息')
  853. try:
  854. msg_content_xml=msg_data["Content"]["string"]
  855. wx_video_url=await request.app.state.gewe_service.download_video_msg_async(token_id,app_id,msg_content_xml)
  856. if not wx_video_url:
  857. logger.warning(f'处理微信视频消息异常')
  858. return
  859. callback_to_user=from_wxid
  860. print(wx_video_url)
  861. file_url=url_file_to_oss(wx_video_url)
  862. if not file_url:
  863. logger.warning(f'处理微信视频上传到oss异常')
  864. return
  865. wx_content_dialogue_message = [{"type": "file", "file_url": {"url":file_url}}]
  866. k_message = dialogue_message(callback_to_user,wxid, wx_content_dialogue_message)
  867. await request.app.state.kafka_service.send_message_async(k_message)
  868. logger.info("发送对话 %s",k_message)
  869. except Exception as e:
  870. logger.error(f"出现错误: {e}")
  871. async def handle_video_group_async(request: Request,token_id,app_id, wxid,msg_data,from_wxid, to_wxid):
  872. logger.info('群聊视频消息')
  873. try:
  874. msg_content=msg_data["Content"]["string"]
  875. xml_match = re.search(r'<\?xml.*</msg>', msg_content, re.DOTALL)
  876. if not xml_match:
  877. logger.info(f'找不到视频地址')
  878. return
  879. msg_content_xml=xml_match.group(0)
  880. wx_video_url=await request.app.state.gewe_service.download_video_msg_async(token_id,app_id,msg_content_xml)
  881. if not wx_video_url:
  882. logger.warning(f'处理微信视频消息异常')
  883. return
  884. callback_to_user=from_wxid
  885. print(wx_video_url)
  886. file_url=url_file_to_oss(wx_video_url)
  887. if not file_url:
  888. logger.warning(f'处理微信视频上传到oss异常')
  889. return
  890. reply_content = re.sub(r'<\?xml.*', f'{file_url}', msg_content, flags=re.DOTALL)
  891. input_wx_content_dialogue_message=[{"type": "text", "text": reply_content}]
  892. k_message=dialogue_message(callback_to_user,wxid,input_wx_content_dialogue_message,False)
  893. await request.app.state.kafka_service.send_message_async(k_message)
  894. logger.info("发送对话 %s",k_message)
  895. except Exception as e:
  896. logger.error(f"出现错误: {e}")
  897. async def handle_xml_async(request: Request,token_id,app_id, wxid,msg_data,from_wxid, to_wxid):
  898. '''
  899. 处理xml
  900. '''
  901. try:
  902. msg_content_xml=msg_data["Content"]["string"]
  903. root = ET.fromstring(msg_content_xml)
  904. type_value = int(root.find(".//appmsg/type").text)
  905. handlers = {
  906. 57: handle_xml_reference_async,
  907. 5: handle_xml_invite_group_async
  908. }
  909. handler = handlers.get(type_value)
  910. if handler:
  911. return await handler(request,token_id,app_id, wxid,msg_data,from_wxid, to_wxid)
  912. # elif "邀请你加入了群聊" in msg_content_xml: # 邀请加入群聊
  913. # logger.warning(f"xml消息 {type_value} 邀请你加入了群聊.todo")
  914. else:
  915. print(f"xml消息 {type_value} 未解析")
  916. except ET.ParseError as e:
  917. logger.error(f"解析XML失败: {e}")
  918. except Exception as e:
  919. logger.error(f"未知错误: {e}")
  920. return
  921. async def handle_xml_reference_async(request: Request,token_id,app_id, wxid,msg_data,from_wxid, to_wxid):
  922. '''
  923. 引用消息
  924. 判断此类消息的逻辑:$.Data.MsgType=49 并且 解析$.Data.Content.string中的xml msg.appmsg.type=57
  925. '''
  926. callback_to_user=from_wxid
  927. hash_key = f'__AI_OPS_WX__:MESSAGES:{wxid}:{callback_to_user}'
  928. msg_content= msg_data["PushContent"]
  929. prompt={"role": "user", "content": [{
  930. "type": "text",
  931. "text": msg_content
  932. }]}
  933. # 收到的对话
  934. messages_to_send=await request.app.state.gewe_service.save_session_messages_to_cache_async(hash_key, prompt)
  935. input_wx_content_dialogue_message=[{"type": "text", "text": msg_content}]
  936. input_message=dialogue_message(callback_to_user,wxid,input_wx_content_dialogue_message)
  937. await request.app.state.kafka_service.send_message_async(input_message)
  938. logger.info("发送对话 %s",input_message)
  939. # 回复的对话
  940. res=await gpt_client_async(request,messages_to_send,wxid,callback_to_user)
  941. reply_content=remove_markdown_symbol(res["choices"][0]["message"]["content"])
  942. input_wx_content_dialogue_message=[{"type": "text", "text": reply_content}]
  943. input_message=dialogue_message(wxid,callback_to_user,input_wx_content_dialogue_message,True)
  944. await request.app.state.kafka_service.kafka_client.produce_message(input_message)
  945. logger.info("发送对话 %s",input_message)
  946. await request.app.state.gewe_service.save_session_messages_to_cache_async(hash_key, {"role": "assistant", "content": reply_content})
  947. await request.app.state.gewe_service.post_text_async(token_id,app_id,callback_to_user,reply_content)
  948. async def handle_xml_invite_group_async (request: Request,token_id,app_id, wxid,msg_data,from_wxid, to_wxid):
  949. '''
  950. 群聊邀请
  951. 判断此类消息的逻辑:$.Data.MsgType=49
  952. 并且 解析$.Data.Content.string中的xml msg.appmsg.title=邀请你加入群聊(根据手机设置的系统语言title会有调整,不同语言关键字不同)
  953. '''
  954. logger.info(f'{wxid} 群聊邀请')
  955. msg_content_xml=msg_data["Content"]["string"]
  956. root = ET.fromstring(msg_content_xml)
  957. title_value = root.find(".//appmsg/title").text
  958. if '邀请你加入群聊' in title_value:
  959. invite_url = root.find('.//url').text
  960. ret,msg,data=await request.app.state.gewe_service.agree_join_room_async(token_id,app_id,invite_url)
  961. if ret==200:
  962. logger.info(f'群聊邀请,同意加入群聊 {msg} {data}')
  963. chatroom_id=data.get('chatroomId','')
  964. # if not chatroom_id:
  965. # logger.warning(f'群聊邀请,同意加入群聊失败 {msg} {data}')
  966. # return
  967. ret,msg,data=await request.app.state.gewe_service.save_contract_list_async(token_id,app_id,chatroom_id,3)
  968. logger.info(f'群聊邀请,保存到通讯录 chatroom_id {chatroom_id} {msg}')
  969. await request.app.state.gewe_service.update_group_info_to_cache_async(token_id,app_id,wxid,chatroom_id)
  970. await request.app.state.gewe_service.update_group_members_to_cache_async(token_id,app_id,wxid,chatroom_id)
  971. # # 单个群信息推送到kafka
  972. # group_info_members=await request.app.state.gewe_service.get_group_info_members_from_cache_async(wxid,chatroom_id)
  973. # k_message=wx_mod_group_info_members_message(wxid,group_info_members)
  974. # 全量群信息推送到kafka
  975. #all_groups_info_menbers=await request.app.state.gewe_service.get_groups_info_members_from_cache_async(wxid)
  976. #k_message=wx_groups_info_members_message(wxid,all_groups_info_menbers)
  977. k_message=wx_groups_info_members_key_message(wxid)
  978. await request.app.state.kafka_service.send_message_async(k_message)
  979. else:
  980. logger.warning(f'群聊邀请,同意加入群聊失败 {msg} {data}')
  981. async def handle_add_friend_notice_async(request: Request,token_id,app_id, wxid,msg_data,from_wxid, to_wxid):
  982. '''
  983. 好友添加请求通知
  984. '''
  985. logger.info('好友添加请求通知')
  986. try:
  987. msg_content_xml=msg_data["Content"]["string"]
  988. root = ET.fromstring(msg_content_xml)
  989. msg_content = root.attrib.get('content', None)
  990. v3= root.attrib.get('encryptusername', None)
  991. v4= root.attrib.get('ticket', None)
  992. scene=root.attrib.get('scene', None)
  993. to_contact_wxid=root.attrib.get('fromusername', None)
  994. wxid=msg_data["ToUserName"]["string"]
  995. # 自动同意好友
  996. # print(v3)
  997. # print(v4)
  998. # print(scene)
  999. # print(msg_content)
  1000. # 操作类型,2添加好友 3同意好友 4拒绝好友
  1001. #option=2
  1002. option=3
  1003. reply_add_contact_contact="亲,我是你的好友"
  1004. ret,ret_msg=await request.app.state.gewe_service.add_contacts_async(token_id,app_id,scene,option,v3,v4,reply_add_contact_contact)
  1005. if ret==200:
  1006. logger.info('自动添加好友成功')
  1007. # 好友发送的文字
  1008. hash_key = f'__AI_OPS_WX__:MESSAGES:{wxid}:{to_contact_wxid}'
  1009. prompt={"role": "user", "content": [{"type": "text","text": msg_content}]}
  1010. messages_to_send=await request.app.state.gewe_service.save_session_messages_to_cache_async(hash_key, prompt)
  1011. input_wx_content_dialogue_message=[{"type": "text", "text": msg_content}]
  1012. input_message=dialogue_message(to_contact_wxid,wxid,input_wx_content_dialogue_message)
  1013. await request.app.state.kafka_service.send_message_async(input_message)
  1014. logger.info("发送对话 %s",input_message)
  1015. callback_to_user=to_contact_wxid
  1016. res=await gpt_client_async(request,messages_to_send,wxid,callback_to_user)
  1017. reply_content=remove_markdown_symbol(res["choices"][0]["message"]["content"])
  1018. #保存好友信息
  1019. await request.app.state.gewe_service.save_contacts_brief_to_cache_async(token_id,app_id, wxid,[to_contact_wxid])
  1020. # 保存到缓存
  1021. await request.app.state.gewe_service.save_session_messages_to_cache_async(hash_key, {"role": "assistant", "content": reply_content})
  1022. # 发送信息
  1023. await request.app.state.gewe_service.post_text_async(token_id,app_id, to_contact_wxid,reply_content)
  1024. # 发送到kafka
  1025. input_wx_content_dialogue_message=[{"type": "text", "text": reply_content}]
  1026. input_message=dialogue_message(wxid,to_contact_wxid,input_wx_content_dialogue_message,True)
  1027. request.app.state.kafka_service.send_message_async(input_message)
  1028. logger.info("发送对话 %s",input_message)
  1029. else:
  1030. logger.warning("添加好友失败")
  1031. except ET.ParseError as e:
  1032. logger.error(f"解析XML失败: {e}")
  1033. except Exception as e:
  1034. logger.error(f"未知错误: {e}")
  1035. return
  1036. async def handle_10002_msg_async(request: Request,token_id,app_id, wxid,msg_data,from_wxid, to_wxid):
  1037. '''
  1038. 群聊邀请
  1039. 撤回消息
  1040. 拍一拍消息
  1041. 地理位置
  1042. 踢出群聊通知
  1043. 解散群聊通知
  1044. 发布群公告
  1045. '''
  1046. try:
  1047. msg_content_xml=msg_data["Content"]["string"]
  1048. # 群聊邀请
  1049. if '邀请你加入了群聊' in msg_content_xml and check_chatroom(msg_data["FromUserName"]["string"]):
  1050. chatroom_id=msg_data["FromUserName"]["string"]
  1051. ret,msg,data=await request.app.state.gewe_service.save_contract_list_async(token_id,app_id,chatroom_id,3)
  1052. logger.info(f'群聊邀请,保存到通讯录 chatroom_id {chatroom_id} {msg}')
  1053. await request.app.state.gewe_service.update_group_info_to_cache_async(token_id,app_id,wxid,chatroom_id)
  1054. await request.app.state.gewe_service.update_group_members_to_cache_async(token_id,app_id,wxid,chatroom_id)
  1055. # #推送群资料到kafka
  1056. # group_info_members=await request.app.state.gewe_service.get_group_info_members_from_cache_async(wxid,chatroom_id)
  1057. # k_message=wx_mod_group_info_members_message(wxid,group_info_members)
  1058. # await request.app.state.kafka_service.send_message_async(k_message)
  1059. # 全量群信息推送到kafka
  1060. #all_groups_info_menbers=await request.app.state.gewe_service.get_groups_info_members_from_cache_async(wxid)
  1061. #k_message=wx_groups_info_members_message(wxid,all_groups_info_menbers)
  1062. k_message=wx_groups_info_members_key_message(wxid)
  1063. await request.app.state.kafka_service.send_message_async(k_message)
  1064. if '移出了群聊' in msg_content_xml and 'sysmsgtemplate' in msg_content_xml :
  1065. chatroom_id=msg_data["FromUserName"]["string"]
  1066. ret,msg,data=await request.app.state.gewe_service.save_contract_list_async(token_id,app_id,chatroom_id,2)
  1067. logger.info(f'移出群聊,移除从通讯录 chatroom_id {chatroom_id} {msg}')
  1068. await request.app.state.redis_service.delete_hash_field(f'__AI_OPS_WX__:GROUPS_INFO:{wxid}',chatroom_id)
  1069. await request.app.state.redis_service.delete_hash_field(f'__AI_OPS_WX__:GROUPS_MEMBERS:{wxid}',chatroom_id)
  1070. logger.info(f'清除 chatroom_id{chatroom_id} 数据')
  1071. # 推送删除群资料到kafka
  1072. k_message=wx_del_group_message(wxid,chatroom_id)
  1073. await request.app.state.kafka_service.send_message_async(k_message)
  1074. if '已解散该群聊' in msg_content_xml and 'sysmsgtemplate' in msg_content_xml :
  1075. chatroom_id=msg_data["FromUserName"]["string"]
  1076. ret,msg,data=await request.app.state.gewe_service.save_contract_list_async(token_id,app_id,chatroom_id,2)
  1077. logger.info(f'解散群聊,移除从通讯录 chatroom_id {chatroom_id} {msg}')
  1078. await request.app.state.redis_service.delete_hash_field(f'__AI_OPS_WX__:GROUPS_INFO:{wxid}',chatroom_id)
  1079. await request.app.state.redis_service.delete_hash_field(f'__AI_OPS_WX__:GROUPS_MEMBERS:{wxid}',chatroom_id)
  1080. logger.info(f'清除 chatroom_id{chatroom_id} 数据')
  1081. # 推送删除群资料到kafka
  1082. k_message=wx_del_group_message(wxid,chatroom_id)
  1083. await request.app.state.kafka_service.send_message_async(k_message)
  1084. if 'mmchatroombarannouncememt' in msg_content_xml :
  1085. chatroom_id=msg_data["FromUserName"]["string"]
  1086. logger.info(f'发布群公告 chatroom_id {chatroom_id}')
  1087. await request.app.state.gewe_service.update_group_info_to_cache_async(token_id,app_id,wxid,chatroom_id)
  1088. await request.app.state.gewe_service.update_group_members_to_cache_async(token_id,app_id,wxid,chatroom_id)
  1089. # #推送群资料到kafka
  1090. # group_info_members=await request.app.state.gewe_service.get_group_info_members_from_cache_async(wxid,chatroom_id)
  1091. # k_message=wx_mod_group_info_members_message(wxid,group_info_members)
  1092. # await request.app.state.kafka_service.send_message_async(k_message)、
  1093. # 全量群信息推送到kafka
  1094. #all_groups_info_menbers=await request.app.state.gewe_service.get_groups_info_members_from_cache_async(wxid)
  1095. #k_message=wx_groups_info_members_message(wxid,all_groups_info_menbers)
  1096. k_message=wx_groups_info_members_key_message(wxid)
  1097. await request.app.state.kafka_service.send_message_async(k_message)
  1098. if 'roomtoolstips' in msg_content_xml :
  1099. chatroom_id=msg_data["FromUserName"]["string"]
  1100. logger.info(f'群待办 chatroom_id {chatroom_id} ')
  1101. await request.app.state.gewe_service.update_group_info_to_cache_async(token_id,app_id,wxid,chatroom_id)
  1102. await request.app.state.gewe_service.update_group_members_to_cache_async(token_id,app_id,wxid,chatroom_id)
  1103. # #推送群资料到kafka
  1104. # group_info_members=await request.app.state.gewe_service.get_group_info_members_from_cache_async(wxid,chatroom_id)
  1105. # k_message=wx_mod_group_info_members_message(wxid,group_info_members)
  1106. # await request.app.state.kafka_service.send_message_async(k_message)
  1107. # 全量群信息推送到kafka
  1108. #all_groups_info_menbers=await request.app.state.gewe_service.get_groups_info_members_from_cache_async(wxid)
  1109. #k_message=wx_groups_info_members_message(wxid,all_groups_info_menbers)
  1110. k_message=wx_groups_info_members_key_message(wxid)
  1111. await request.app.state.kafka_service.send_message_async(k_message)
  1112. except ET.ParseError as e:
  1113. logger.error(f"解析XML失败: {e}")
  1114. except Exception as e:
  1115. logger.error(f"未知错误: {e}")
  1116. return
  1117. async def handle_10000_msg_async(request: Request,token_id,app_id, wxid,msg_data,from_wxid, to_wxid):
  1118. '''
  1119. 修改群名称
  1120. 更换群主通知
  1121. 被移除群聊通知
  1122. '''
  1123. content=msg_data.get("Content","").get("string","")
  1124. if '修改群名' or '新群主' or '被移除群聊通知' in content and check_chatroom(from_wxid):
  1125. chatroom_id=from_wxid
  1126. logger.info(f'{content} chatroom_id {chatroom_id} ')
  1127. await request.app.state.gewe_service.update_group_info_to_cache_async(token_id,app_id,wxid,chatroom_id)
  1128. await request.app.state.gewe_service.update_group_members_to_cache_async(token_id,app_id,wxid,chatroom_id)
  1129. # group_info_members=await request.app.state.gewe_service.get_group_info_members_from_cache_async(wxid,chatroom_id)
  1130. # k_message=wx_mod_group_info_members_message(wxid,group_info_members)
  1131. # await request.app.state.kafka_service.send_message_async(k_message)
  1132. # 全量群信息推送到kafka
  1133. #all_groups_info_menbers=await request.app.state.gewe_service.get_groups_info_members_from_cache_async(wxid)
  1134. #k_message=wx_groups_info_members_message(wxid,all_groups_info_menbers)
  1135. k_message=wx_groups_info_members_key_message(wxid)
  1136. await request.app.state.kafka_service.send_message_async(k_message)
  1137. return