選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

app.py 10KB

4ヶ月前
3ヶ月前
2ヶ月前
4ヶ月前
4ヶ月前
4ヶ月前
4ヶ月前
4ヶ月前
4ヶ月前
4ヶ月前
3ヶ月前
2ヶ月前
3ヶ月前
3ヶ月前
2ヶ月前
2ヶ月前
2ヶ月前
3ヶ月前
2ヶ月前
2ヶ月前
2ヶ月前
2ヶ月前
2ヶ月前
2ヶ月前
2ヶ月前
3ヶ月前
2ヶ月前
2ヶ月前
3ヶ月前
4ヶ月前
3ヶ月前
3ヶ月前
2ヶ月前
3ヶ月前
4ヶ月前
3ヶ月前
3ヶ月前
3ヶ月前
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. from flask import Flask, send_from_directory, request,jsonify
  2. from flask_restful import Api,got_request_exception
  3. from resources.messages_resource import MessagesResource
  4. from resources.contacts_resources import DeleteFriendResource,GetFriendsInfoResource
  5. from resources.config_reources import GetWxchatConfigResource ,SaveWxchatConfigResource
  6. from resources.groups_resources import GetGroupsInfoResource
  7. from resources.login_resources import GetLoginInfoResource,GetLoginWxQRCodeResource,LoginWxCaptchCodeResource
  8. from resources.sns_resources import SendSNSTextResource,SendSNSImageResource, SendSNSVideoResource
  9. from common.log import logger, log_exception
  10. from common.interceptors import before_request, after_request, handle_exception
  11. import threading
  12. from common import kafka_helper, redis_helper,utils
  13. from model import Models
  14. import logging
  15. from config import load_config
  16. from wechat.biz import start_kafka_consumer_thread
  17. from wechat import gewe_chat
  18. import os,time,json,time
  19. from voice.ali.ali_voice import AliVoice
  20. # 自定义错误消息
  21. errors = {
  22. 'UserAlreadyExistsError': {
  23. 'message': "A user with that username already exists.",
  24. 'status': 409,
  25. },
  26. 'ResourceDoesNotExist': {
  27. 'message': "A resource with that ID no longer exists.",
  28. 'status': 410,
  29. 'extra': "Any extra information you want.",
  30. },
  31. }
  32. def worker():
  33. kafka_helper.start()
  34. redis_helper.start()
  35. start_wxchat_thread()
  36. start_kafka_consumer_thread()
  37. def fetch_and_save_contacts():
  38. """
  39. 获取联系人列表并保存到缓存
  40. """
  41. wxchat=gewe_chat.wxchat
  42. while True:
  43. try:
  44. login_keys = list(redis_helper.redis_helper.client.scan_iter(match='__AI_OPS_WX__:LOGININFO:*'))
  45. logger.info(f"Fetching login keys: {login_keys}")
  46. # 遍历每一个获取到的登录键
  47. for k in login_keys:
  48. try:
  49. r= redis_helper.redis_helper.get_hash(k)
  50. # print(r)
  51. token_id = r.get('tokenId')
  52. app_id = r.get('appId')
  53. wxid = r.get('wxid')
  54. status=r.get('status')
  55. if status=='1':
  56. ret,msg,contacts_list = wxchat.fetch_contacts_list(token_id, app_id)
  57. if ret==200:
  58. friend_wxids = [c for c in contacts_list['friends'] if c not in ['fmessage', 'medianote','weixin','weixingongzhong']] # 可以调整截取范围
  59. wxchat.save_contacts_brief_to_cache(token_id, app_id, wxid, friend_wxids)
  60. logger.info(f'微信ID {wxid} 登录APPID {app_id} 成功,联系人已定时保存')
  61. chatrooms=contacts_list['chatrooms']
  62. wxchat.save_groups_info_to_cache(token_id, app_id, wxid, chatrooms)
  63. wxchat.save_groups_members_to_cache(token_id, app_id, wxid, chatrooms)
  64. logger.info(f'微信ID {wxid} 登录APPID {app_id} 成功,群信息已定时保存')
  65. else:
  66. logger.warning(f'{msg}-微信ID {wxid} 登录APPID {app_id} 不能获取好友和群资料')
  67. else:
  68. logger.info(f'微信ID {wxid} 未登录 {app_id} ,联系人不能定时保存')
  69. time.sleep(3)
  70. except Exception as e:
  71. logger.error(f'处理好友和群资料出错 login key {k}: {str(e)}', exc_info=True)
  72. except Exception as e:
  73. logger.error(f'发送错误 {str(e)}', exc_info=True)
  74. time.sleep(3600*1)
  75. def auto_add_contacts_from_chatrooms():
  76. logger.info('自动从群添加好友')
  77. wxchat=gewe_chat.wxchat
  78. while True:
  79. login_keys = list(redis_helper.redis_helper.client.scan_iter(match='__AI_OPS_WX__:LOGININFO:*'))
  80. #logger.info(f"Fetching login keys: {login_keys}")
  81. # 遍历每一个获取到的登录键
  82. for k in login_keys:
  83. r= redis_helper.redis_helper.get_hash(k)
  84. # print(r)
  85. token_id = r.get('tokenId')
  86. app_id = r.get('appId')
  87. nickname=r.get('nickName')
  88. wxid = r.get('wxid')
  89. status=r.get('status')
  90. # 启动线程处理登录信息
  91. thread = threading.Thread(target=process_add_contacts_from_chatrooms, args=(wxchat,status, wxid, token_id, app_id))
  92. thread.start()
  93. time.sleep(3)
  94. #time.sleep(60*10)
  95. time.sleep(3600*24)
  96. def process_add_contacts_from_chatrooms(wxchat:gewe_chat.GeWeChatCom,status, wxid, token_id, app_id):
  97. if status == '1':
  98. c = wxchat.get_wxchat_config_from_cache(wxid)
  99. contacts = wxchat.get_contacts_brief_from_cache(wxid)
  100. contact_wxids = [c.get('userName') for c in contacts]
  101. chatrooms = c.get('addContactsFromChatroomIdWhiteList', [])
  102. for chatroom_id in chatrooms:
  103. chatroom = wxchat.get_group_info_from_cache(wxid, chatroom_id)
  104. chatroom_member=wxchat.get_group_members_from_cache(wxid, chatroom_id)
  105. chatroom_nickname = chatroom.get('nickName')
  106. chatroom_owner_wxid = chatroom_member.get('chatroomOwner', None)
  107. admin_wxid = chatroom_member.get('adminWxid', None)
  108. logger.info(f'{chatroom_nickname} 的群主是 {chatroom_owner_wxid},管理员是{admin_wxid}')
  109. contact_wxids_set = set(contact_wxids)
  110. if admin_wxid is not None:
  111. contact_wxids_set.add(admin_wxid)
  112. if chatroom_owner_wxid is not None:
  113. contact_wxids_set.add(chatroom_owner_wxid)
  114. contact_wxids_set.add(wxid)
  115. unavailable_wixds=wxchat.check_wixd_group_add_contacts_history(wxid,chatroom_id)
  116. contact_wxids_set.update(unavailable_wixds)
  117. chatroot_member_list = chatroom.get('memberList', [])
  118. remaining_chatroot_members = [x for x in chatroot_member_list if x.get('wxid') not in contact_wxids_set]
  119. nickname = next((member['nickName'] for member in chatroot_member_list if member['wxid'] == wxid), None)
  120. logger.info(f'{nickname}-{wxid} 在 {chatroom_nickname} 群里还可以邀请的好友有:{[x.get("nickName") for x in remaining_chatroot_members]}')
  121. for m in remaining_chatroot_members:
  122. ret, msg, data = wxchat.add_group_member_as_friend(token_id, app_id, chatroom_id, m.get('wxid'), f'我是群聊"{chatroom_nickname}"群的{nickname}')
  123. if ret==200:
  124. contact_wxids= m.get('wxid')
  125. history=Models.AddGroupContactsHistory.model_validate({
  126. "chatroomId":chatroom_id,
  127. "wxid":wxid,
  128. "contactWixd":contact_wxids,
  129. "addTime":int(time.time())
  130. })
  131. wxchat.save_group_add_contacts_history(wxid,chatroom_id,contact_wxids,history)
  132. else:
  133. logger.info(f'群好友邀请失败原因:{data}')
  134. logger.info(f'{nickname} 向 {chatroom_nickname}-{chatroom_id} 群的 {m.get("nickName")}-{m.get("wxid")} 发送好友邀请 {msg}')
  135. time.sleep(10)
  136. time.sleep(20)
  137. else:
  138. logger.info(f'微信ID {wxid} 未登录 {app_id} ,群成员不能定时定时')
  139. def start_wxchat_thread():
  140. # gewe_chat.start()
  141. scan_wx_login_info()
  142. # 启动同步联系人线程
  143. threading.Thread(target=fetch_and_save_contacts).start()
  144. threading.Thread(target=auto_add_contacts_from_chatrooms).start()
  145. def scan_wx_login_info():
  146. gewe_chat.start()
  147. wxchat = gewe_chat.wxchat
  148. cursor = 0
  149. while True:
  150. cursor, login_keys = redis_helper.redis_helper.client.scan(cursor, match='__AI_OPS_WX__:LOGININFO:*')
  151. for k in login_keys:
  152. r = redis_helper.redis_helper.get_hash(k)
  153. app_id=r.get("appId")
  154. #tel=r.get("mobile")
  155. token_id=r.get("tokenId")
  156. wxid=r.get("wxid")
  157. is_online = wxchat.check_online(token_id, app_id)
  158. if is_online:
  159. logger.info(f'微信ID {wxid} 在APPID {app_id} 已经在线')
  160. else:
  161. # 尝试重连
  162. res = wxchat.reconnection(token_id, app_id)
  163. if res.get('ret') == 200:
  164. logger.info(f'微信ID {wxid} 在APPID {app_id} 重连成功')
  165. # 同步联系人
  166. #fetch_and_save_contacts(wxchat, token_id, app_id, k)
  167. else:
  168. print("重连失败,重新登录...")
  169. print("发送离线消息到kafka")
  170. redis_helper.redis_helper.update_hash_field(k,'status',0)
  171. time.sleep(3)
  172. # 如果游标为 0,则表示扫描完成
  173. if cursor == 0:
  174. break
  175. app = Flask(__name__)
  176. # api = Api(app)
  177. flask_api = Api(app,errors=errors, catch_all_404s=True)
  178. # 设置日志(logger 已在 log.py 中配置)
  179. app.logger.handlers.clear() # 清除 Flask 默认的日志处理器
  180. app.logger.addHandler(logger.handlers[1]) # 使用文件日志处理器
  181. app.logger.setLevel(logging.DEBUG) # 设置日志级别
  182. # 添加拦截器
  183. app.before_request(before_request)
  184. app.after_request(after_request)
  185. app.register_error_handler(Exception, handle_exception)
  186. # 定义路由
  187. flask_api.add_resource(MessagesResource, '/messages')
  188. flask_api.add_resource(DeleteFriendResource, '/api/contacts/deletefriend')
  189. flask_api.add_resource(GetFriendsInfoResource, '/api/contacts/getfriends')
  190. flask_api.add_resource(GetWxchatConfigResource, '/api/wxchat/getconfig')
  191. flask_api.add_resource(SaveWxchatConfigResource, '/api/wxchat/saveconfig')
  192. flask_api.add_resource(GetGroupsInfoResource, '/api/groups/getchatroominfo')
  193. flask_api.add_resource(GetLoginInfoResource, '/api/agent/getlogin')
  194. flask_api.add_resource(GetLoginWxQRCodeResource, '/api/agent/getwxqrcode')
  195. flask_api.add_resource(LoginWxCaptchCodeResource, '/api/agent/logincaptchcode')
  196. flask_api.add_resource(SendSNSTextResource, '/api/sns/sendtext')
  197. flask_api.add_resource(SendSNSImageResource, '/api/sns/sendimages')
  198. flask_api.add_resource(SendSNSVideoResource, '/api/sns/sendvideo')
  199. load_config()
  200. worker()
  201. if __name__ == '__main__':
  202. # 获取环境变量
  203. environment = os.environ.get('environment', 'default')
  204. port = 80 if environment == 'default' else 5000
  205. app.run(debug=False, host='0.0.0.0', port=port)