From 5b1dd3dce95a93aad0509dbc7d9b9eff40095fe1 Mon Sep 17 00:00:00 2001 From: Soulter <37870767+Soulter@users.noreply.github.com> Date: Thu, 11 May 2023 21:35:25 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=8F=92=E4=BB=B6=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- addons/plugins/helloworld/helloworld.py | 26 +++++++++++++++++++++++++ cores/qqbot/core.py | 7 ++++--- model/command/command.py | 26 ++++++++++++++++++++++++- util/plugin_util.py | 19 ++++++++++++++++++ 4 files changed, 74 insertions(+), 4 deletions(-) create mode 100644 addons/plugins/helloworld/helloworld.py create mode 100644 util/plugin_util.py diff --git a/addons/plugins/helloworld/helloworld.py b/addons/plugins/helloworld/helloworld.py new file mode 100644 index 000000000..ec2474215 --- /dev/null +++ b/addons/plugins/helloworld/helloworld.py @@ -0,0 +1,26 @@ +class HelloWorldPlugin: + """ + 初始化函数, 可以选择直接pass + """ + def __init__(self) -> None: + print("这是HelloWorld测试插件, 发送 helloworld 即可触发此插件。") + + """ + 入口函数,机器人会调用此函数。 + 参数规范: message: 消息文本; role: 身份; platform: 消息平台 + 返回规范: bool: 是否hit到此插件(所有的消息均会调用每一个载入的插件, 如果没有hit到, 则应返回False) + Tuple: None或者长度为3的元组。当没有hit到时, 返回None. hit到时, 第1个参数为指令是否调用成功, 第2个参数为返回的消息文本, 第3个参数为指令名称 + 例子:做一个名为"yuanshen"的插件;当接收到消息为“原神 可莉”, 如果不想要处理此消息,则返回False, None;如果想要处理,但是执行失败了,返回True, tuple([False, "请求失败啦~", "yuanshen"]) + ;执行成功了,返回True, tuple([True, "结果文本", "yuanshen"]) + """ + def run(self, message: str, role: str, platform: str): + + # 这里是插件核心处理逻辑 + if message == "helloworld": + return True, tuple([True, "Hello World~", "helloworld"]) + else: + return False, None + + # 热知识:检测消息开头指令,使用以下方法 + # if message.startswith("原神"): + # pass \ No newline at end of file diff --git a/cores/qqbot/core.py b/cores/qqbot/core.py index d8d1e42bd..b2798a758 100644 --- a/cores/qqbot/core.py +++ b/cores/qqbot/core.py @@ -522,7 +522,7 @@ def oper_msg(message, group=False, msg_ref = None, platform = None): if chosen_provider == OPENAI_OFFICIAL: hit, command_result = command_openai_official.check_command(qq_msg, session_id, user_name, role, platform=platform) - # hit: 是否触发了指令. + # hit: 是否触发了指令 if not hit: # 请求ChatGPT获得结果 try: @@ -582,8 +582,9 @@ def oper_msg(message, group=False, msg_ref = None, platform = None): if command_result != None: command = command_result[2] if command == "keyword": - with open("keyword.json", "r", encoding="utf-8") as f: - keywords = json.load(f) + if os.path.exists("keyword.json"): + with open("keyword.json", "r", encoding="utf-8") as f: + keywords = json.load(f) # QQ昵称 if command == "nick": diff --git a/model/command/command.py b/model/command/command.py index 181152a06..c744ebdde 100644 --- a/model/command/command.py +++ b/model/command/command.py @@ -7,6 +7,7 @@ import sys import requests from model.provider.provider import Provider import json +import util.plugin_util as putil PLATFORM_QQCHAN = 'qqchan' PLATFORM_GOCQ = 'gocq' @@ -16,10 +17,33 @@ class Command: def __init__(self, provider: Provider): self.provider = Provider - @abc.abstractmethod def check_command(self, message, role, platform): + # 插件 + plugins = [] + try: + go = True + if os.path.exists("addons/plugins"): + plugins = putil.get_modules("addons/plugins") + elif os.path.exists("QQChannelChatGPT/addons/plugins"): + plugins = putil.get_modules("QQChannelChatGPT/addons/plugins") + else: + go = False + + if go: + print(f"[DEBUG] 当前加载的插件:{plugins}") + for p in plugins: + module = __import__("addons.plugins." + p + "." + p, fromlist=[p]) + cls = putil.get_classes(module) + obj = getattr(module, cls[0])() + hit, res = obj.run(message, role, platform) + if hit: + return True, res + except BaseException as e: + print(f"[Debug] 插件加载出现问题,原因: {str(e)}\n已安装插件: {plugins}\n如果你没有相关装插件的想法, 请直接忽略此报错, 不影响其他功能的运行。") + if self.command_start_with(message, "nick"): return True, self.set_nick(message, platform) + return False, None ''' diff --git a/util/plugin_util.py b/util/plugin_util.py new file mode 100644 index 000000000..9403bf95b --- /dev/null +++ b/util/plugin_util.py @@ -0,0 +1,19 @@ +import os +import inspect + +# 找出模块里所有的类名 +def get_classes(arg): + classes = [] + clsmembers = inspect.getmembers(arg, inspect.isclass) + for (name, _) in clsmembers: + classes.append(name) + return classes + +# 获取一个文件夹下所有的模块 +def get_modules(path): + modules = [] + for root, dirs, files in os.walk(path): + for file in files: + if file.endswith(".py") and not file.startswith("__"): + modules.append(file[:-3]) + return modules \ No newline at end of file