refactor: 迁移旧的处理模块

This commit is contained in:
Rock Chin 2023-03-27 13:09:40 +00:00
parent 564c5d937d
commit b799de7995
8 changed files with 249 additions and 0 deletions

View File

@ -133,6 +133,7 @@ def cmd_update(cmd: str, params: list, session_name: str,
threading.Thread(target=update_task, daemon=True).start() threading.Thread(target=update_task, daemon=True).start()
reply = ["[bot]正在更新,请耐心等待,请勿重复发起更新..."] reply = ["[bot]正在更新,请耐心等待,请勿重复发起更新..."]
return reply
def config_operation(cmd, params): def config_operation(cmd, params):

217
pkg/qqbot/cmds/mgr.py Normal file
View File

@ -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': <class 'pkg.qqbot.cmds.cmd1.CommandCmd1'>,
'sub': {
'cmd1-1': {
'description': 'cmd1-1 description',
'usage': 'cmd1-1 usage',
'aliases': ['cmd1-1 alias1', 'cmd1-1 alias2'],
'privilege': 0,
'cls': <class 'pkg.qqbot.cmds.cmd1.CommandCmd1_1'>,
'sub': {}
},
}
},
'cmd2': {
'description': 'cmd2 description',
'usage': 'cmd2 usage',
'aliases': ['cmd2 alias1', 'cmd2 alias2'],
'privilege': 0,
'cls': <class 'pkg.qqbot.cmds.cmd2.CommandCmd2'>,
'sub': {
'cmd2-1': {
'description': 'cmd2-1 description',
'usage': 'cmd2-1 usage',
'aliases': ['cmd2-1 alias1', 'cmd2-1 alias2'],
'privilege': 0,
'cls': <class 'pkg.qqbot.cmds.cmd2.CommandCmd2_1'>,
'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': <class 'pkg.qqbot.cmds.cmd2.CommandCmd2_1_1'>,
'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))

View File

@ -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, ''