From b799de799513913ccfea7289762ee3837aae5682 Mon Sep 17 00:00:00 2001 From: Rock Chin <1010553892@qq.com> Date: Mon, 27 Mar 2023 13:09:40 +0000 Subject: [PATCH] =?UTF-8?q?refactor:=20=E8=BF=81=E7=A7=BB=E6=97=A7?= =?UTF-8?q?=E7=9A=84=E5=A4=84=E7=90=86=E6=A8=A1=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pkg/qqbot/{cmds => cmds.old}/__init__.py | 0 pkg/qqbot/{cmds => cmds.old}/func.py | 0 pkg/qqbot/{cmds => cmds.old}/model.py | 0 pkg/qqbot/{cmds => cmds.old}/plugin.py | 0 pkg/qqbot/{cmds => cmds.old}/session.py | 0 pkg/qqbot/{cmds => cmds.old}/system.py | 1 + pkg/qqbot/cmds/mgr.py | 217 +++++++++++++++++++++++ pkg/qqbot/cmds/session/reset.py | 31 ++++ 8 files changed, 249 insertions(+) rename pkg/qqbot/{cmds => cmds.old}/__init__.py (100%) rename pkg/qqbot/{cmds => cmds.old}/func.py (100%) rename pkg/qqbot/{cmds => cmds.old}/model.py (100%) rename pkg/qqbot/{cmds => cmds.old}/plugin.py (100%) rename pkg/qqbot/{cmds => cmds.old}/session.py (100%) rename pkg/qqbot/{cmds => cmds.old}/system.py (99%) create mode 100644 pkg/qqbot/cmds/mgr.py create mode 100644 pkg/qqbot/cmds/session/reset.py diff --git a/pkg/qqbot/cmds/__init__.py b/pkg/qqbot/cmds.old/__init__.py similarity index 100% rename from pkg/qqbot/cmds/__init__.py rename to pkg/qqbot/cmds.old/__init__.py diff --git a/pkg/qqbot/cmds/func.py b/pkg/qqbot/cmds.old/func.py similarity index 100% rename from pkg/qqbot/cmds/func.py rename to pkg/qqbot/cmds.old/func.py diff --git a/pkg/qqbot/cmds/model.py b/pkg/qqbot/cmds.old/model.py similarity index 100% rename from pkg/qqbot/cmds/model.py rename to pkg/qqbot/cmds.old/model.py diff --git a/pkg/qqbot/cmds/plugin.py b/pkg/qqbot/cmds.old/plugin.py similarity index 100% rename from pkg/qqbot/cmds/plugin.py rename to pkg/qqbot/cmds.old/plugin.py diff --git a/pkg/qqbot/cmds/session.py b/pkg/qqbot/cmds.old/session.py similarity index 100% rename from pkg/qqbot/cmds/session.py rename to pkg/qqbot/cmds.old/session.py diff --git a/pkg/qqbot/cmds/system.py b/pkg/qqbot/cmds.old/system.py similarity index 99% rename from pkg/qqbot/cmds/system.py rename to pkg/qqbot/cmds.old/system.py index 1d6c6717..d57e4285 100644 --- a/pkg/qqbot/cmds/system.py +++ b/pkg/qqbot/cmds.old/system.py @@ -133,6 +133,7 @@ def cmd_update(cmd: str, params: list, session_name: str, threading.Thread(target=update_task, daemon=True).start() reply = ["[bot]正在更新,请耐心等待,请勿重复发起更新..."] + return reply def config_operation(cmd, params): diff --git a/pkg/qqbot/cmds/mgr.py b/pkg/qqbot/cmds/mgr.py new file mode 100644 index 00000000..b04b8ee0 --- /dev/null +++ b/pkg/qqbot/cmds/mgr.py @@ -0,0 +1,217 @@ +import logging +import copy + + +__commands_tree__ = {} +"""命令树 + +结构: +{ + 'cmd1': { + 'description': 'cmd1 description', + 'usage': 'cmd1 usage', + 'aliases': ['cmd1 alias1', 'cmd1 alias2'], + 'privilege': 0, + 'cls': , + 'sub': { + 'cmd1-1': { + 'description': 'cmd1-1 description', + 'usage': 'cmd1-1 usage', + 'aliases': ['cmd1-1 alias1', 'cmd1-1 alias2'], + 'privilege': 0, + 'cls': , + 'sub': {} + }, + } + }, + 'cmd2': { + 'description': 'cmd2 description', + 'usage': 'cmd2 usage', + 'aliases': ['cmd2 alias1', 'cmd2 alias2'], + 'privilege': 0, + 'cls': , + 'sub': { + 'cmd2-1': { + 'description': 'cmd2-1 description', + 'usage': 'cmd2-1 usage', + 'aliases': ['cmd2-1 alias1', 'cmd2-1 alias2'], + 'privilege': 0, + 'cls': , + 'sub': { + 'cmd2-1-1': { + 'description': 'cmd2-1-1 description', + 'usage': 'cmd2-1-1 usage', + 'aliases': ['cmd2-1-1 alias1', 'cmd2-1-1 alias2'], + 'privilege': 0, + 'cls': , + 'sub': {} + }, + } + }, + } + } +} +""" + +__tree_index__: dict[str, list] = {} +"""命令树索引 + +结构: +{ + 'pkg.qqbot.cmds.cmd1.CommandCmd1': ['cmd1'], # 顶级指令 + 'pkg.qqbot.cmds.cmd1.CommandCmd1_1': ['cmd1', 'cmd1-1'], # 类名: 节点路径 + 'pkg.qqbot.cmds.cmd2.CommandCmd2': ['cmd2'], + 'pkg.qqbot.cmds.cmd2.CommandCmd2_1': ['cmd2', 'cmd2-1'], + 'pkg.qqbot.cmds.cmd2.CommandCmd2_1_1': ['cmd2', 'cmd2-1', 'cmd2-1-1'], +} +""" + + +class Context: + """命令执行上下文""" + command: str + """顶级指令文本""" + + crt_command: str + """当前子指令文本""" + + params: list + """完整参数列表""" + + crt_params: list + """当前子指令参数列表""" + + session_name: str + """会话名""" + + text_message: str + """指令完整文本""" + + launcher_type: str + """指令发起者类型""" + + launcher_id: int + """指令发起者ID""" + + sender_id: int + """指令发送者ID""" + + is_admin: bool + """[过时]指令发送者是否为管理员""" + + privilege: int + """指令发送者权限等级""" + + def __init__(self, **kwargs): + self.__dict__.update(kwargs) + + +class AbstractCommand: + """指令抽象类""" + + name: str + """指令名""" + + description: str + """指令描述""" + + usage: str + """指令用法""" + + aliases: list[str] + """指令别名""" + + privilege: int + """指令权限等级, 权限大于等于此值的用户才能执行指令""" + + @classmethod + def process(cls, ctx: Context) -> tuple[bool, list, str]: + """指令处理函数 + + :param ctx: 指令执行上下文 + + :return: (是否执行, 回复列表(若执行), 下一级指令(若未执行)) + """ + raise NotImplementedError + + @staticmethod + def register(cls: type, name: str, parent: type = None): + """注册指令 + + :param cls: 指令类 + :param name: 指令名 + :param parent: 父指令类 + """ + global __commands_tree__, __tree_index__ + + if parent is None: + # 顶级指令注册 + __commands_tree__[name] = { + 'description': cls.description, + 'usage': cls.usage, + 'aliases': cls.aliases, + 'privilege': cls.privilege, + 'cls': cls, + 'sub': {} + } + __tree_index__[cls.__module__ + '.' + cls.__name__] = [name] + else: + # 从索引取出路径 + path = [] + try: + path = __tree_index__[parent.__module__ + '.' + parent.__name__] + except KeyError: + raise ValueError('register parent command first: {}'.format(parent.__name__)) + # 从树取出父节点 + node = __commands_tree__ + for p in path: + node = node[p]['sub'] + + # 注册子指令 + node[name] = { + 'description': cls.description, + 'usage': cls.usage, + 'aliases': cls.aliases, + 'privilege': cls.privilege, + 'cls': cls, + 'sub': {} + } + # 更新索引 + __tree_index__[cls.__module__ + '.' + cls.__name__] = path + [name] + +# 传入Context对象,广搜命令树,返回执行结果 +# 若命令被处理,返回reply列表 +# 若命令未被处理,继续执行下一级指令 +# 若命令不存在,报异常 +def execute(context: Context) -> list: + """执行指令 + + :param ctx: 指令执行上下文 + + :return: 回复列表 + """ + global __commands_tree__ + + # 拷贝ctx + ctx: Context = copy.deepcopy(context) + + # 从树取出顶级指令 + node = __commands_tree__ + + # 搜当前顶层,找不到则报错 + while True: + try: + # 检查权限 + if ctx.privilege < node[ctx.crt_command]['privilege']: + raise ValueError('权限不足') + # 执行 + execed, reply, ctx.crt_command = node[ctx.crt_command]['cls'].process(ctx) + if execed: + return reply + else: + # 从树取出下一级指令 + node = node[ctx.crt_command]['sub'] + # 删除crt_params第一个参数 + ctx.crt_params.pop(0) + except KeyError: + raise ValueError('找不到指令: {}'.format(ctx.command)) diff --git a/pkg/qqbot/cmds/session/reset.py b/pkg/qqbot/cmds/session/reset.py new file mode 100644 index 00000000..8247e0f2 --- /dev/null +++ b/pkg/qqbot/cmds/session/reset.py @@ -0,0 +1,31 @@ +from ..mgr import AbstractCommand, Context + +import pkg.openai.session +import pkg.utils.context + +class ResetCommand(AbstractCommand): + name = 'reset' + description = '重置当前会话' + usage = 'reset' + aliases = ['重置', '重置会话'] + privilege = 0 + + @classmethod + def process(cls, ctx: Context) -> tuple[bool, list, str]: + params = ctx.params + session_name = ctx.session_name + + reply = "" + + if len(params) == 0: + pkg.openai.session.get_session(session_name).reset(explicit=True) + reply = ["[bot]会话已重置"] + else: + try: + import pkg.openai.dprompt as dprompt + pkg.openai.session.get_session(session_name).reset(explicit=True, use_prompt=params[0]) + reply = ["[bot]会话已重置,使用场景预设:{}".format(dprompt.mode_inst().get_full_name(params[0]))] + except Exception as e: + reply = ["[bot]会话重置失败:{}".format(e)] + + return True, reply, '' \ No newline at end of file