From b100f12e7f17a8446ee707ef59afc8b2abb7bf61 Mon Sep 17 00:00:00 2001 From: Rock Chin <1010553892@qq.com> Date: Thu, 30 Mar 2023 11:11:39 +0000 Subject: [PATCH] =?UTF-8?q?refactor:=20=E5=AE=8C=E6=88=90=E6=89=80?= =?UTF-8?q?=E6=9C=89=E6=8C=87=E4=BB=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pkg/qqbot/cmds/func/__init__.py | 0 pkg/qqbot/cmds/func/draw.py | 35 ++++++ pkg/qqbot/cmds/mgr.py | 3 - pkg/qqbot/cmds/plugin/__init__.py | 0 pkg/qqbot/cmds/plugin/plugin.py | 195 ++++++++++++++++++++++++++++++ pkg/qqbot/cmds/session/default.py | 4 +- pkg/qqbot/command.py | 2 +- pkg/utils/reloader.py | 5 + 8 files changed, 238 insertions(+), 6 deletions(-) create mode 100644 pkg/qqbot/cmds/func/__init__.py create mode 100644 pkg/qqbot/cmds/func/draw.py create mode 100644 pkg/qqbot/cmds/plugin/__init__.py create mode 100644 pkg/qqbot/cmds/plugin/plugin.py diff --git a/pkg/qqbot/cmds/func/__init__.py b/pkg/qqbot/cmds/func/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/pkg/qqbot/cmds/func/draw.py b/pkg/qqbot/cmds/func/draw.py new file mode 100644 index 00000000..f8cee754 --- /dev/null +++ b/pkg/qqbot/cmds/func/draw.py @@ -0,0 +1,35 @@ +from ..mgr import AbstractCommandNode, Context +import logging + +from mirai import Image +import config + + +@AbstractCommandNode.register( + parent=None, + name="draw", + description="使用DALL·E生成图片", + usage="!draw <图片提示语>", + aliases=[], + privilege=1 +) +class DrawCommand(AbstractCommandNode): + @classmethod + def process(cls, ctx: Context) -> tuple[bool, list]: + import pkg.openai.session + + reply = [] + if len(ctx.params) == 0: + reply = ["[bot]err: 未提供图片描述文字"] + else: + session = pkg.openai.session.get_session(ctx.session_name) + + res = session.draw_image(" ".join(ctx.params)) + + logging.debug("draw_image result:{}".format(res)) + reply = [Image(url=res['data'][0]['url'])] + if not (hasattr(config, 'include_image_description') + and not config.include_image_description): + reply.append(" ".join(ctx.params)) + + return True, reply diff --git a/pkg/qqbot/cmds/mgr.py b/pkg/qqbot/cmds/mgr.py index 351b3809..66c9efb6 100644 --- a/pkg/qqbot/cmds/mgr.py +++ b/pkg/qqbot/cmds/mgr.py @@ -288,9 +288,6 @@ def register_all(): # 排除__开头的属性 global __command_list__, __tree_index__ - __command_list__ = {} - __tree_index__ = {} - import pkg.qqbot.cmds def walk(module, prefix, path_prefix): diff --git a/pkg/qqbot/cmds/plugin/__init__.py b/pkg/qqbot/cmds/plugin/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/pkg/qqbot/cmds/plugin/plugin.py b/pkg/qqbot/cmds/plugin/plugin.py new file mode 100644 index 00000000..e97253da --- /dev/null +++ b/pkg/qqbot/cmds/plugin/plugin.py @@ -0,0 +1,195 @@ +from ..mgr import AbstractCommandNode, Context + +import os + +import pkg.plugin.host as plugin_host +import pkg.utils.updater as updater + + +@AbstractCommandNode.register( + parent=None, + name="plugin", + description="插件管理", + usage="!plugin\n!plugin get <插件仓库地址>\!plugin update\n!plugin del <插件名>\n!plugin on <插件名>\n!plugin off <插件名>", + aliases=[], + privilege=2 +) +class PluginCommand(AbstractCommandNode): + @classmethod + def process(cls, ctx: Context) -> tuple[bool, list]: + reply = [] + plugin_list = plugin_host.__plugins__ + if len(ctx.params) == 0: + # 列出所有插件 + + reply_str = "[bot]所有插件({}):\n".format(len(plugin_host.__plugins__)) + idx = 0 + for key in plugin_host.iter_plugins_name(): + plugin = plugin_list[key] + reply_str += "\n#{} {} {}\n{}\nv{}\n作者: {}\n"\ + .format((idx+1), plugin['name'], + "[已禁用]" if not plugin['enabled'] else "", + plugin['description'], + plugin['version'], plugin['author']) + + if updater.is_repo("/".join(plugin['path'].split('/')[:-1])): + remote_url = updater.get_remote_url("/".join(plugin['path'].split('/')[:-1])) + if remote_url != "https://github.com/RockChinQ/QChatGPT" and remote_url != "https://gitee.com/RockChin/QChatGPT": + reply_str += "源码: "+remote_url+"\n" + + idx += 1 + + reply = [reply_str] + return True, reply + elif ctx.params[0].startswith("http"): + reply = ["[bot]err: 此命令已启用,请使用 !plugin get <插件仓库地址> 进行安装"] + return True, reply + else: + return False, [] + + +@AbstractCommandNode.register( + parent=PluginCommand, + name="get", + description="安装插件", + usage="!plugin get <插件仓库地址>", + aliases=[], + privilege=2 +) +class PluginGetCommand(AbstractCommandNode): + @classmethod + def process(cls, ctx: Context) -> tuple[bool, list]: + import threading + import logging + import pkg.utils.context + + if len(ctx.crt_params) == 0: + reply = ["[bot]err: 请提供插件仓库地址"] + return True, reply + + reply = [] + def closure(): + try: + plugin_host.install_plugin(ctx.crt_params[0]) + pkg.utils.context.get_qqbot_manager().notify_admin("插件安装成功,请发送 !reload 指令重载插件") + except Exception as e: + logging.error("插件安装失败:{}".format(e)) + pkg.utils.context.get_qqbot_manager().notify_admin("插件安装失败:{}".format(e)) + + threading.Thread(target=closure, args=()).start() + reply = ["[bot]正在安装插件..."] + return True, reply + + +@AbstractCommandNode.register( + parent=PluginCommand, + name="update", + description="更新所有插件", + usage="!plugin update", + aliases=[], + privilege=2 +) +class PluginUpdateCommand(AbstractCommandNode): + @classmethod + def process(cls, ctx: Context) -> tuple[bool, list]: + import threading + import logging + plugin_list = plugin_host.__plugins__ + + reply = [] + def closure(): + import pkg.utils.context + updated = [] + for key in plugin_list: + plugin = plugin_list[key] + if updater.is_repo("/".join(plugin['path'].split('/')[:-1])): + success = updater.pull_latest("/".join(plugin['path'].split('/')[:-1])) + if success: + updated.append(plugin['name']) + + # 检查是否有requirements.txt + pkg.utils.context.get_qqbot_manager().notify_admin("正在安装依赖...") + for key in plugin_list: + plugin = plugin_list[key] + if os.path.exists("/".join(plugin['path'].split('/')[:-1])+"/requirements.txt"): + logging.info("{}检测到requirements.txt,安装依赖".format(plugin['name'])) + import pkg.utils.pkgmgr + pkg.utils.pkgmgr.install_requirements("/".join(plugin['path'].split('/')[:-1])+"/requirements.txt") + + import main + main.reset_logging() + + pkg.utils.context.get_qqbot_manager().notify_admin("已更新插件: {}".format(", ".join(updated))) + + threading.Thread(target=closure).start() + reply = ["[bot]正在更新所有插件,请勿重复发起..."] + return True, reply + + +@AbstractCommandNode.register( + parent=PluginCommand, + name="del", + description="删除插件", + usage="!plugin del <插件名>", + aliases=[], + privilege=2 +) +class PluginDelCommand(AbstractCommandNode): + @classmethod + def process(cls, ctx: Context) -> tuple[bool, list]: + plugin_list = plugin_host.__plugins__ + reply = [] + + if len(ctx.crt_params) < 1: + reply = ["[bot]err: 未指定插件名"] + else: + plugin_name = ctx.crt_params[0] + if plugin_name in plugin_list: + unin_path = plugin_host.uninstall_plugin(plugin_name) + reply = ["[bot]已删除插件: {} ({}), 请发送 !reload 重载插件".format(plugin_name, unin_path)] + else: + reply = ["[bot]err:未找到插件: {}, 请使用!plugin指令查看插件列表".format(plugin_name)] + + return True, reply + + +@AbstractCommandNode.register( + parent=PluginCommand, + name="on", + description="启用指定插件", + usage="!plugin on <插件名>", + aliases=[], + privilege=2 +) +@AbstractCommandNode.register( + parent=PluginCommand, + name="off", + description="禁用指定插件", + usage="!plugin off <插件名>", + aliases=[], + privilege=2 +) +class PluginOnOffCommand(AbstractCommandNode): + @classmethod + def process(cls, ctx: Context) -> tuple[bool, list]: + import pkg.plugin.switch as plugin_switch + + plugin_list = plugin_host.__plugins__ + reply = [] + + print(ctx.params) + new_status = ctx.params[0] == 'on' + + if len(ctx.crt_params) < 1: + reply = ["[bot]err: 未指定插件名"] + else: + plugin_name = ctx.crt_params[0] + if plugin_name in plugin_list: + plugin_list[plugin_name]['enabled'] = new_status + plugin_switch.dump_switch() + reply = ["[bot]已{}插件: {}".format("启用" if new_status else "禁用", plugin_name)] + else: + reply = ["[bot]err:未找到插件: {}, 请使用!plugin指令查看插件列表".format(plugin_name)] + + return True, reply + diff --git a/pkg/qqbot/cmds/session/default.py b/pkg/qqbot/cmds/session/default.py index bb6519f6..33982874 100644 --- a/pkg/qqbot/cmds/session/default.py +++ b/pkg/qqbot/cmds/session/default.py @@ -5,7 +5,7 @@ from ..mgr import AbstractCommandNode, Context parent=None, name="default", description="操作情景预设", - usage="!default\n!default [指定情景预设为默认]", + usage="!default\n!default set [指定情景预设为默认]", aliases=[], privilege=1 ) @@ -35,7 +35,7 @@ class DefaultCommand(AbstractCommandNode): reply_str += "\n\n" reply_str += "\n当前默认情景预设:{}\n".format(dprompt.mode_inst().get_using_name()) - reply_str += "请使用 !default <情景预设名称> 来设置默认情景预设" + reply_str += "请使用 !default set <情景预设名称> 来设置默认情景预设" reply = [reply_str] elif params[0] != "set": reply = ["[bot]err: 已弃用,请使用!default set <情景预设名称> 来设置默认情景预设"] diff --git a/pkg/qqbot/command.py b/pkg/qqbot/command.py index 42ddd7f6..3527c5a8 100644 --- a/pkg/qqbot/command.py +++ b/pkg/qqbot/command.py @@ -42,7 +42,7 @@ def process_command(session_name: str, text_message: str, mgr, config, command=cmd, crt_command=cmd, params=params, - crt_params=params, + crt_params=params[:], session_name=session_name, text_message=text_message, launcher_type=launcher_type, diff --git a/pkg/utils/reloader.py b/pkg/utils/reloader.py index 0449a40c..46399d09 100644 --- a/pkg/utils/reloader.py +++ b/pkg/utils/reloader.py @@ -28,6 +28,11 @@ def reload_all(notify=True): import main main.stop() + # 删除所有已注册的指令 + import pkg.qqbot.cmds.mgr as cmdsmgr + cmdsmgr.__command_list__ = {} + cmdsmgr.__tree_index__ = {} + # 重载所有模块 context.context['exceeded_keys'] = context.get_openai_manager().key_mgr.exceeded this_context = context.context