You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

165 lines
8.8KB

  1. import web
  2. import time
  3. import channel.wechatmp.reply as reply
  4. import channel.wechatmp.receive as receive
  5. from config import conf
  6. from common.log import logger
  7. from bridge.context import *
  8. from channel.wechatmp.common import *
  9. from channel.wechatmp.wechatmp_channel import WechatMPChannel
  10. # This class is instantiated once per query
  11. class Query():
  12. def GET(self):
  13. return verify_server(web.input())
  14. def POST(self):
  15. # Make sure to return the instance that first created, @singleton will do that.
  16. channel = WechatMPChannel()
  17. try:
  18. query_time = time.time()
  19. webData = web.data()
  20. logger.debug("[wechatmp] Receive request:\n" + webData.decode("utf-8"))
  21. wechatmp_msg = receive.parse_xml(webData)
  22. if wechatmp_msg.msg_type == 'text':
  23. from_user = wechatmp_msg.from_user_id
  24. to_user = wechatmp_msg.to_user_id
  25. message = wechatmp_msg.content.decode("utf-8")
  26. message_id = wechatmp_msg.msg_id
  27. logger.info("[wechatmp] {}:{} Receive post query {} {}: {}".format(web.ctx.env.get('REMOTE_ADDR'), web.ctx.env.get('REMOTE_PORT'), from_user, message_id, message))
  28. supported = True
  29. if "【收到不支持的消息类型,暂无法显示】" in message:
  30. supported = False # not supported, used to refresh
  31. cache_key = from_user
  32. reply_text = ""
  33. # New request
  34. if cache_key not in channel.cache_dict and cache_key not in channel.running:
  35. # The first query begin, reset the cache
  36. context = channel._compose_context(ContextType.TEXT, message, isgroup=False, msg=wechatmp_msg)
  37. logger.debug("[wechatmp] context: {} {}".format(context, wechatmp_msg))
  38. if message_id in channel.received_msgs: # received and finished
  39. return
  40. if supported and context:
  41. # set private openai_api_key
  42. # if from_user is not changed in itchat, this can be placed at chat_channel
  43. user_data = conf().get_user_data(from_user)
  44. context['openai_api_key'] = user_data.get('openai_api_key') # None or user openai_api_key
  45. channel.received_msgs[message_id] = wechatmp_msg
  46. channel.running.add(cache_key)
  47. channel.produce(context)
  48. else:
  49. trigger_prefix = conf().get('single_chat_prefix',[''])[0]
  50. if trigger_prefix or not supported:
  51. if trigger_prefix:
  52. content = textwrap.dedent(f"""\
  53. 请输入'{trigger_prefix}'接你想说的话跟我说话。
  54. 例如:
  55. {trigger_prefix}你好,很高兴见到你。""")
  56. else:
  57. content = textwrap.dedent("""\
  58. 你好,很高兴见到你。
  59. 请跟我说话吧。""")
  60. else:
  61. logger.error(f"[wechatmp] unknown error")
  62. content = textwrap.dedent("""\
  63. 未知错误,请稍后再试""")
  64. replyMsg = reply.TextMsg(wechatmp_msg.from_user_id, wechatmp_msg.to_user_id, content)
  65. return replyMsg.send()
  66. channel.query1[cache_key] = False
  67. channel.query2[cache_key] = False
  68. channel.query3[cache_key] = False
  69. # Request again
  70. elif cache_key in channel.running and channel.query1.get(cache_key) == True and channel.query2.get(cache_key) == True and channel.query3.get(cache_key) == True:
  71. channel.query1[cache_key] = False #To improve waiting experience, this can be set to True.
  72. channel.query2[cache_key] = False #To improve waiting experience, this can be set to True.
  73. channel.query3[cache_key] = False
  74. elif cache_key in channel.cache_dict:
  75. # Skip the waiting phase
  76. channel.query1[cache_key] = True
  77. channel.query2[cache_key] = True
  78. channel.query3[cache_key] = True
  79. assert not (cache_key in channel.cache_dict and cache_key in channel.running)
  80. if channel.query1.get(cache_key) == False:
  81. # The first query from wechat official server
  82. logger.debug("[wechatmp] query1 {}".format(cache_key))
  83. channel.query1[cache_key] = True
  84. cnt = 0
  85. while cache_key not in channel.cache_dict and cnt < 45:
  86. cnt = cnt + 1
  87. time.sleep(0.1)
  88. if cnt == 45:
  89. # waiting for timeout (the POST query will be closed by wechat official server)
  90. time.sleep(1)
  91. # and do nothing
  92. return
  93. else:
  94. pass
  95. elif channel.query2.get(cache_key) == False:
  96. # The second query from wechat official server
  97. logger.debug("[wechatmp] query2 {}".format(cache_key))
  98. channel.query2[cache_key] = True
  99. cnt = 0
  100. while cache_key not in channel.cache_dict and cnt < 45:
  101. cnt = cnt + 1
  102. time.sleep(0.1)
  103. if cnt == 45:
  104. # waiting for timeout (the POST query will be closed by wechat official server)
  105. time.sleep(1)
  106. # and do nothing
  107. return
  108. else:
  109. pass
  110. elif channel.query3.get(cache_key) == False:
  111. # The third query from wechat official server
  112. logger.debug("[wechatmp] query3 {}".format(cache_key))
  113. channel.query3[cache_key] = True
  114. cnt = 0
  115. while cache_key not in channel.cache_dict and cnt < 40:
  116. cnt = cnt + 1
  117. time.sleep(0.1)
  118. if cnt == 40:
  119. # Have waiting for 3x5 seconds
  120. # return timeout message
  121. reply_text = "【正在思考中,回复任意文字尝试获取回复】"
  122. logger.info("[wechatmp] Three queries has finished For {}: {}".format(from_user, message_id))
  123. replyPost = reply.TextMsg(from_user, to_user, reply_text).send()
  124. return replyPost
  125. else:
  126. pass
  127. if float(time.time()) - float(query_time) > 4.8:
  128. reply_text = "【正在思考中,回复任意文字尝试获取回复】"
  129. logger.info("[wechatmp] Timeout for {} {}, return".format(from_user, message_id))
  130. replyPost = reply.TextMsg(from_user, to_user, reply_text).send()
  131. return replyPost
  132. if cache_key in channel.cache_dict:
  133. content = channel.cache_dict[cache_key]
  134. if len(content.encode('utf8'))<=MAX_UTF8_LEN:
  135. reply_text = channel.cache_dict[cache_key]
  136. channel.cache_dict.pop(cache_key)
  137. else:
  138. continue_text = "\n【未完待续,回复任意文字以继续】"
  139. splits = split_string_by_utf8_length(content, MAX_UTF8_LEN - len(continue_text.encode('utf-8')), max_split= 1)
  140. reply_text = splits[0] + continue_text
  141. channel.cache_dict[cache_key] = splits[1]
  142. logger.info("[wechatmp] {}:{} Do send {}".format(web.ctx.env.get('REMOTE_ADDR'), web.ctx.env.get('REMOTE_PORT'), reply_text))
  143. replyPost = reply.TextMsg(from_user, to_user, reply_text).send()
  144. return replyPost
  145. elif wechatmp_msg.msg_type == 'event':
  146. logger.info("[wechatmp] Event {} from {}".format(wechatmp_msg.content, wechatmp_msg.from_user_id))
  147. content = subscribe_msg()
  148. replyMsg = reply.TextMsg(wechatmp_msg.from_user_id, wechatmp_msg.to_user_id, content)
  149. return replyMsg.send()
  150. else:
  151. logger.info("暂且不处理")
  152. return "success"
  153. except Exception as exc:
  154. logger.exception(exc)
  155. return exc