Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/wechatmp' into wechatmp
Browse files Browse the repository at this point in the history
  • Loading branch information
JS00000 committed Apr 21, 2023
2 parents 650e0b4 + cca49da commit 3a08b00
Show file tree
Hide file tree
Showing 9 changed files with 289 additions and 430 deletions.
60 changes: 29 additions & 31 deletions channel/wechatmp/active_reply.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@

import web

from channel.wechatmp.wechatmp_message import parse_xml
from channel.wechatmp.passive_reply_message import TextMsg
from channel.wechatmp.wechatmp_message import WeChatMPMessage
from bridge.context import *
from bridge.reply import ReplyType
from bridge.reply import *
from channel.wechatmp.common import *
from channel.wechatmp.wechatmp_channel import WechatMPChannel
from wechatpy import parse_message
from common.log import logger
from config import conf

from wechatpy.replies import create_reply

# This class is instantiated once per query
class Query:
Expand All @@ -21,16 +21,25 @@ def POST(self):
# Make sure to return the instance that first created, @singleton will do that.
channel = WechatMPChannel()
try:
webData = web.data()
message = web.data() # todo crypto
# logger.debug("[wechatmp] Receive request:\n" + webData.decode("utf-8"))
wechatmp_msg = parse_xml(webData)
if (
wechatmp_msg.msg_type == "text"
or wechatmp_msg.msg_type == "voice"
# or wechatmp_msg.msg_type == "image"
):
msg = parse_message(message)
if msg.type == "event":
logger.info(
"[wechatmp] Event {} from {}".format(
msg.event, msg.source
)
)
if msg.event in ["subscribe", "subscribe_scan"]:
reply_text = subscribe_msg()
replyPost = create_reply(reply_text, msg)
return replyPost.render()
else:
return "success"
wechatmp_msg = WeChatMPMessage(msg, client=channel.client)
if wechatmp_msg.ctype in [ContextType.TEXT, ContextType.IMAGE, ContextType.VOICE]:
from_user = wechatmp_msg.from_user_id
message = wechatmp_msg.content
content = wechatmp_msg.content
message_id = wechatmp_msg.msg_id

logger.info(
Expand All @@ -39,16 +48,17 @@ def POST(self):
web.ctx.env.get("REMOTE_PORT"),
from_user,
message_id,
message,
content,
)
)
if (wechatmp_msg.msg_type == "voice" and conf().get("voice_reply_voice") == True):
rtype = ReplyType.VOICE
if msg.type == "voice" and wechatmp_msg.ctype == ContextType.TEXT and conf().get("voice_reply_voice", False):
context = channel._compose_context(
wechatmp_msg.ctype, content, isgroup=False, desire_rtype=ReplyType.VOICE, msg=wechatmp_msg
)
else:
rtype = None
context = channel._compose_context(
ContextType.TEXT, message, isgroup=False, desire_rtype=rtype, msg=wechatmp_msg
)
context = channel._compose_context(
wechatmp_msg.ctype, content, isgroup=False, msg=wechatmp_msg
)
if context:
# set private openai_api_key
# if from_user is not changed in itchat, this can be placed at chat_channel
Expand All @@ -59,18 +69,6 @@ def POST(self):
channel.produce(context)
# The reply will be sent by channel.send() in another thread
return "success"

elif wechatmp_msg.msg_type == "event":
logger.info(
"[wechatmp] Event {} from {}".format(
wechatmp_msg.Event, wechatmp_msg.from_user_id
)
)
content = subscribe_msg()
replyMsg = TextMsg(
wechatmp_msg.from_user_id, wechatmp_msg.to_user_id, content
)
return replyMsg.send()
else:
logger.info("暂且不处理")
return "success"
Expand Down
32 changes: 12 additions & 20 deletions channel/wechatmp/common.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import hashlib
import textwrap
import web

from config import conf

from wechatpy.utils import check_signature
from wechatpy.crypto import WeChatCrypto
from wechatpy.exceptions import InvalidSignatureException
MAX_UTF8_LEN = 2048


Expand All @@ -12,38 +14,28 @@ class WeChatAPIException(Exception):

def verify_server(data):
try:
if len(data) == 0:
return "None"
signature = data.signature
timestamp = data.timestamp
nonce = data.nonce
echostr = data.echostr
token = conf().get("wechatmp_token") # 请按照公众平台官网\基本配置中信息填写

data_list = [token, timestamp, nonce]
data_list.sort()
sha1 = hashlib.sha1()
# map(sha1.update, data_list) #python2
sha1.update("".join(data_list).encode("utf-8"))
hashcode = sha1.hexdigest()
print("handle/GET func: hashcode, signature: ", hashcode, signature)
if hashcode == signature:
return echostr
else:
return ""
except Exception as Argument:
return Argument
check_signature(token, signature, timestamp, nonce)
return echostr
except InvalidSignatureException:
raise web.Forbidden("Invalid signature")
except Exception as e:
raise web.Forbidden(str(e))


def subscribe_msg():
trigger_prefix = conf().get("single_chat_prefix", [""])
trigger_prefix = conf().get("single_chat_prefix", [""])[0]
msg = textwrap.dedent(
f"""\
感谢您的关注!
这里是ChatGPT,可以自由对话。
资源有限,回复较慢,请勿着急。
支持语音对话。
暂时不支持图片输入
支持图片输入
支持图片输出,画字开头的消息将按要求创作图片。
支持tool、角色扮演和文字冒险等丰富的插件。
输入'{trigger_prefix}#帮助' 查看详细指令。"""
Expand Down
107 changes: 57 additions & 50 deletions channel/wechatmp/passive_reply.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@

import web

from channel.wechatmp.wechatmp_message import parse_xml
from channel.wechatmp.passive_reply_message import TextMsg, VoiceMsg, ImageMsg
from channel.wechatmp.wechatmp_message import WeChatMPMessage
from bridge.context import *
from bridge.reply import ReplyType
from bridge.reply import *
from channel.wechatmp.common import *
from channel.wechatmp.wechatmp_channel import WechatMPChannel
from common.log import logger
from config import conf

from wechatpy import parse_message
from wechatpy.replies import create_reply, ImageReply, VoiceReply

# This class is instantiated once per query
class Query:
Expand All @@ -22,36 +22,38 @@ def POST(self):
try:
request_time = time.time()
channel = WechatMPChannel()
webData = web.data()
logger.debug("[wechatmp] Receive post data:\n" + webData.decode("utf-8"))
wechatmp_msg = parse_xml(webData)
if wechatmp_msg.msg_type == "text" or wechatmp_msg.msg_type == "voice":
message = web.data() # todo crypto
msg = parse_message(message)
logger.debug("[wechatmp] Receive post data:\n" + message.decode("utf-8"))

if msg.type in ["text", "voice", "image"]:
wechatmp_msg = WeChatMPMessage(msg, client=channel.client)
from_user = wechatmp_msg.from_user_id
to_user = wechatmp_msg.to_user_id
message = wechatmp_msg.content
content = wechatmp_msg.content
message_id = wechatmp_msg.msg_id

supported = True
if "【收到不支持的消息类型,暂无法显示】" in message:
if "【收到不支持的消息类型,暂无法显示】" in content:
supported = False # not supported, used to refresh

# New request
if (
from_user not in channel.cache_dict
and from_user not in channel.running
or message.startswith("#")
or content.startswith("#")
and message_id not in channel.request_cnt # insert the godcmd
):
# The first query begin
if (wechatmp_msg.msg_type == "voice" and conf().get("voice_reply_voice") == True):
rtype = ReplyType.VOICE
if msg.type == "voice" and wechatmp_msg.ctype == ContextType.TEXT and conf().get("voice_reply_voice", False):
context = channel._compose_context(
wechatmp_msg.ctype, content, isgroup=False, desire_rtype=ReplyType.VOICE, msg=wechatmp_msg
)
else:
rtype = None
context = channel._compose_context(
ContextType.TEXT, message, isgroup=False, desire_rtype=rtype, msg=wechatmp_msg
)
context = channel._compose_context(
wechatmp_msg.ctype, content, isgroup=False, msg=wechatmp_msg
)
logger.debug(
"[wechatmp] context: {} {}".format(context, wechatmp_msg)
"[wechatmp] context: {} {} {}".format(context, wechatmp_msg, supported)
)

if supported and context:
Expand All @@ -65,26 +67,27 @@ def POST(self):
trigger_prefix = conf().get("single_chat_prefix", [""])[0]
if trigger_prefix or not supported:
if trigger_prefix:
content = textwrap.dedent(
reply_text = textwrap.dedent(
f"""\
请输入'{trigger_prefix}'接你想说的话跟我说话。
例如:
{trigger_prefix}你好,很高兴见到你。"""
)
else:
content = textwrap.dedent(
reply_text = textwrap.dedent(
"""\
你好,很高兴见到你。
请跟我说话吧。"""
)
else:
logger.error(f"[wechatmp] unknown error")
content = textwrap.dedent(
reply_text = textwrap.dedent(
"""\
未知错误,请稍后再试"""
)
replyPost = TextMsg(wechatmp_msg.from_user_id, wechatmp_msg.to_user_id, content).send()
return replyPost

replyPost = create_reply(reply_text, msg)
return replyPost.render()


# Wechat official server will request 3 times (5 seconds each), with the same message_id.
Expand All @@ -98,7 +101,7 @@ def POST(self):
message_id,
web.ctx.env.get("REMOTE_ADDR"),
web.ctx.env.get("REMOTE_PORT"),
message
content
)
)

Expand All @@ -121,8 +124,8 @@ def POST(self):
else: # request_cnt == 3:
# return timeout message
reply_text = "【正在思考中,回复任意文字尝试获取回复】"
replyPost = TextMsg(from_user, to_user, reply_text).send()
return replyPost
replyPost = create_reply(reply_text, msg)
return replyPost.render()

# reply is ready
channel.request_cnt.pop(message_id)
Expand All @@ -136,76 +139,80 @@ def POST(self):

# Only one request can access to the cached data
try:
(reply_type, content) = channel.cache_dict.pop(from_user)
(reply_type, reply_content) = channel.cache_dict.pop(from_user)
except KeyError:
return "success"

if (reply_type == "text"):
if len(content.encode("utf8")) <= MAX_UTF8_LEN:
reply_text = content
if len(reply_content.encode("utf8")) <= MAX_UTF8_LEN:
reply_text = reply_content
else:
continue_text = "\n【未完待续,回复任意文字以继续】"
splits = split_string_by_utf8_length(
content,
reply_content,
MAX_UTF8_LEN - len(continue_text.encode("utf-8")),
max_split=1,
)
reply_text = splits[0] + continue_text
channel.cache_dict[from_user] = ("text", splits[1])

logger.info(
"[wechatmp] Request {} do send to {} {}: {}\n{}".format(
request_cnt,
from_user,
message_id,
message,
content,
reply_text,
)
)
replyPost = TextMsg(from_user, to_user, reply_text).send()
return replyPost
replyPost = create_reply(reply_text, msg)
return replyPost.render()

elif (reply_type == "voice"):
media_id = content
media_id = reply_content
asyncio.run_coroutine_threadsafe(channel.delete_media(media_id), channel.delete_media_loop)
logger.info(
"[wechatmp] Request {} do send to {} {}: {} voice media_id {}".format(
request_cnt,
from_user,
message_id,
message,
content,
media_id,
)
)
replyPost = VoiceMsg(from_user, to_user, media_id).send()
return replyPost
replyPost = VoiceReply(message=msg)
replyPost.media_id = media_id
return replyPost.render()

elif (reply_type == "image"):
media_id = content
media_id = reply_content
asyncio.run_coroutine_threadsafe(channel.delete_media(media_id), channel.delete_media_loop)
logger.info(
"[wechatmp] Request {} do send to {} {}: {} image media_id {}".format(
request_cnt,
from_user,
message_id,
message,
content,
media_id,
)
)
replyPost = ImageMsg(from_user, to_user, media_id).send()
return replyPost
replyPost = ImageReply(message=msg)
replyPost.media_id = media_id
return replyPost.render()

elif wechatmp_msg.msg_type == "event":
elif msg.type == "event":
logger.info(
"[wechatmp] Event {} from {}".format(
wechatmp_msg.content, wechatmp_msg.from_user_id
msg.event, msg.source
)
)
content = subscribe_msg()
replyMsg = TextMsg(
wechatmp_msg.from_user_id, wechatmp_msg.to_user_id, content
)
return replyMsg.send()
if msg.event in ["subscribe", "subscribe_scan"]:
reply_text = subscribe_msg()
replyPost = create_reply(reply_text, msg)
return replyPost.render()
else:
return "success"

else:
logger.info("暂且不处理")
return "success"
Expand Down
Loading

0 comments on commit 3a08b00

Please sign in to comment.