iuiaoin / wechat-gptbot

A wechat robot based on ChatGPT with no risk, very stable! 🚀
MIT License
595 stars 116 forks source link

[Feat]: 可以允许设置消息队列嘛 #73

Closed QAbot-zh closed 1 year ago

QAbot-zh commented 1 year ago

Search for answers in existing issues

Feature description

现在只能返回一条Reply消息,如果允许返回一个list(Reply)消息队列的话,可以让对话更丰富、友好,比如长对话可以通过程序切分成多条回复,以及消息队列可以支持图文消息,这样在回复图片消息前还可以回复一些友好的提示语

Motivation

No response

QAbot-zh commented 1 year ago

对wechat.py做了如下修改,目前看运行正常

    def send(self, replies: Union[Reply, List[Reply]], msg: Message):
        if replies is None:
            return
        if isinstance(replies, Reply) or not isinstance(replies, list):
            replies = [replies]
        for reply in replies:
            if reply.type == ReplyType.IMAGE:
                img_path = serialize_img(reply.content)
                wx_id = msg.room_id if msg.is_group else msg.sender_id
                send_image(img_path, wx_id)
            elif reply.type == ReplyType.VIDEO:
                file_path = serialize_video(reply.content)
                wx_id = msg.room_id if msg.is_group else msg.sender_id
                send_file(file_path, wx_id)
            else:
                reply_msg = serialize_text(reply.content, msg)
                self.ws.send(reply_msg)
iuiaoin commented 1 year ago

@undefinedcodezhong 可以的, 不过更推荐直接在插件里封装,组成一个Reply List之后在loop中直接调用event.channel.send()即可

QAbot-zh commented 1 year ago

@undefinedcodezhong 可以的, 不过更推荐直接在插件里封装,组成一个Reply List之后在loop中直接调用event.channel.send()即可

不是很理解,就是直接在对应的plugin里调用event.channel.send(),不走wechat.py里的send()嘛,可以有个例子参考一下嘛

iuiaoin commented 1 year ago

对的,就类似这样

def will_generate_reply(self, event: Event) -> None:
    replies = self.build_replies()
    for reply in replies:
        event.channel.send(reply, event.message)
    event.reply = None
    event.bypass()
QAbot-zh commented 1 year ago

可以,这方式很优雅很喜欢,这样在回复比较耗时操作的时候,还可以先发送一些让用户耐心等待之类的提示信息了。爆赞!

QAbot-zh commented 1 year ago

@iuiaoin 还有个小问题,在chatgpt.py里是没有event对象的,所以它的消息回复只能走wechat.py,那样还有什么方式可以实现多消息回复,比如之前在这个issue下的例子,即在chatgpt回复完,将其中的代码块以图片消息再发送给用户,原先的解决方案就还是我前面用到reply list形式: https://github.com/iuiaoin/wechat-gptbot/issues/76#issue-1833124128

iuiaoin commented 1 year ago

@undefinedcodezhong 那把上面的逻辑移到 will_send_reply 中应该就可以了

def will_send_reply(self, event: Event) -> None:
    replies = self.build_replies(event.reply)
    for reply in replies:
        event.channel.send(reply, event.message)
    event.reply = None
    event.bypass()

def build_replies(self, botReply: Reply) -> List[Reply]:
    replies = [ botReply ]
    if self.contains_code(botReply):
        image_url = self.generate_codeImage(botReply.content)
        codeReply = Reply(ReplyType.IMAGE, image_url)
        replies.append(codeReply)
    return replies
QAbot-zh commented 1 year ago

@iuiaoin 可是will_send_reply不是plugin才有的函数嘛,wechat.py的handle_reply()这部分:

        reply = Bot().reply(e1.context)   #这里获取了chatgpt的回复内容

        e2 = PluginManager().emit(
            Event(
                EventType.WILL_SEND_REPLY,
                {
                    "channel": self,
                    "message": e1.message,
                    "context": e1.context,
                    "reply": reply,
                },
            )
        )
        self.send(e2.reply, e2.message)    #这里调用了wechat的接口发送消息

意思在这里循环调用self.send()?

iuiaoin commented 1 year ago

@undefinedcodezhong 我的意思是把 code2image 封装成 plugin, 不需要touch wechat.py, 设计plugin system的初衷是把强化类的功能都尽量使用plugin的形式来进行扩展, 而项目中只保留基本的功能且暴露一致的接口, 这样用户可以自由选择自己想要的feature并且后面咱重构(替换更好用的windows hook)的时候也不会遇到太大的困难。

QAbot-zh commented 1 year ago

了解了,很好的想法