Przeglądaj źródła

feat: add plugin global config to support docker volumes

zhayujie 2 lat temu
rodzic
commit
954e55f4b4

+ 26 - 2
config.py

@@ -25,7 +25,7 @@ available_setting = {
     "single_chat_reply_suffix": "",  # 私聊时自动回复的后缀,\n 可以换行    
     "group_chat_prefix": ["@bot"],  # 群聊时包含该前缀则会触发机器人回复 
     "group_chat_reply_prefix": "",  # 群聊时自动回复的前缀
-    "group_chat_reply_suffix": "",   # 群聊时自动回复的后缀,\n 可以换行
+    "group_chat_reply_suffix": "",  # 群聊时自动回复的后缀,\n 可以换行
     "group_chat_keyword": [],  # 群聊时包含该关键词则会触发机器人回复
     "group_at_off": False,  # 是否关闭群聊时@bot的触发
     "group_name_white_list": ["ChatGPT测试群", "ChatGPT测试群2"],  # 开启自动回复的群名称列表
@@ -37,7 +37,8 @@ available_setting = {
     "image_create_size": "256x256",  # 图片大小,可选有 256x256, 512x512, 1024x1024
     # chatgpt会话参数
     "expires_in_seconds": 3600,  # 无操作会话的过期时间
-    "character_desc": "你是ChatGPT, 一个由OpenAI训练的大型语言模型, 你旨在回答并解决人们的任何问题,并且可以使用多种语言与人交流。",  # 人格描述
+    # 人格描述
+    "character_desc": "你是ChatGPT, 一个由OpenAI训练的大型语言模型, 你旨在回答并解决人们的任何问题,并且可以使用多种语言与人交流。",
     "conversation_max_tokens": 1000,  # 支持上下文记忆的最多字符数
     # chatgpt限流配置
     "rate_limit_chatgpt": 20,  # chatgpt的调用频率限制
@@ -228,3 +229,26 @@ def subscribe_msg():
     trigger_prefix = conf().get("single_chat_prefix", [""])[0]
     msg = conf().get("subscribe_msg", "")
     return msg.format(trigger_prefix=trigger_prefix)
+
+
+# global plugin config
+plugin_config = {}
+
+
+def write_plugin_config(pconf: dict):
+    """
+    写入插件全局配置
+    :param pconf: 全量插件配置
+    """
+    global plugin_config
+    for k in pconf:
+        plugin_config[k.lower()] = pconf[k]
+
+
+def pconf(plugin_name: str) -> dict:
+    """
+    根据插件名称获取配置
+    :param plugin_name: 插件名称
+    :return: 该插件的配置项
+    """
+    return plugin_config.get(plugin_name.lower())

+ 1 - 1
plugins/banwords/banwords.py

@@ -33,7 +33,7 @@ class Banwords(Plugin):
                     json.dump(conf, f, indent=4)
             else:
                 with open(config_path, "r") as f:
-                    conf = json.load(f)
+                    conf = super().load_config() or json.load(f)
             self.searchr = WordsSearch()
             self.action = conf["action"]
             banwords_path = os.path.join(curdir, "banwords.txt")

+ 1 - 1
plugins/bdunit/bdunit.py

@@ -36,7 +36,7 @@ class BDunit(Plugin):
                 raise Exception("config.json not found")
             else:
                 with open(config_path, "r") as f:
-                    conf = json.load(f)
+                    conf = super().load_config() or json.load(f)
             self.service_id = conf["service_id"]
             self.api_key = conf["api_key"]
             self.secret_key = conf["secret_key"]

+ 24 - 0
plugins/config-template.json

@@ -0,0 +1,24 @@
+{
+    "godcmd": {
+        "password": "",
+        "admin_users": []
+    },
+    "banwords": {
+        "action": "replace",
+        "reply_filter": true,
+        "reply_action": "ignore"
+    },
+    "tool": {
+        "tools": [
+            "python",
+            "url-get",
+            "terminal",
+            "meteo-weather"
+        ],
+        "kwargs": {
+            "top_k_results": 2,
+            "no_default": false,
+            "model_name": "gpt-3.5-turbo"
+        }
+    }
+}

+ 1 - 1
plugins/godcmd/godcmd.py

@@ -187,7 +187,7 @@ class Godcmd(Plugin):
                 json.dump(gconf, f, indent=4)
         else:
             with open(config_path, "r") as f:
-                gconf = json.load(f)
+                gconf = super().load_config() or json.load(f)
         if gconf["password"] == "":
             self.temp_password = "".join(random.sample(string.digits, 4))
             logger.info("[Godcmd] 因未设置口令,本次的临时口令为%s。" % self.temp_password)

+ 10 - 0
plugins/plugin.py

@@ -1,6 +1,16 @@
+import os
+from config import pconf
+
 class Plugin:
     def __init__(self):
         self.handlers = {}
 
+    def load_config(self) -> dict:
+        """
+        加载当前插件配置
+        :return: 插件配置字典
+        """
+        return pconf(self.name)
+
     def get_help_text(self, **kwargs):
         return "暂无帮助信息"

+ 26 - 2
plugins/plugin_manager.py

@@ -9,7 +9,7 @@ import sys
 from common.log import logger
 from common.singleton import singleton
 from common.sorted_dict import SortedDict
-from config import conf
+from config import conf, write_plugin_config
 
 from .event import *
 
@@ -62,6 +62,28 @@ class PluginManager:
             self.save_config()
         return pconf
 
+    @staticmethod
+    def _load_all_config():
+        """
+        背景: 目前插件配置存放于每个插件目录的config.json下,docker运行时不方便进行映射,故增加统一管理的入口,优先
+        加载 plugins/config.json,原插件目录下的config.json 不受影响
+
+        从 plugins/config.json 中加载所有插件的配置并写入 config.py 的全局配置中,供插件中使用
+        插件实例中通过 config.pconf(plugin_name) 即可获取该插件的配置
+        """
+        all_config_path = "./plugins/config.json"
+        try:
+            if os.path.exists(all_config_path):
+                # read from all plugins config
+                with open(all_config_path, "r", encoding="utf-8") as f:
+                    all_conf = json.load(f)
+                    logger.info(f"load all config from plugins/config.json: {all_conf}")
+
+                # write to global config
+                write_plugin_config(all_conf)
+        except Exception as e:
+            logger.error(e)
+
     def scan_plugins(self):
         logger.info("Scaning plugins ...")
         plugins_dir = "./plugins"
@@ -88,7 +110,7 @@ class PluginManager:
                             self.loaded[plugin_path] = importlib.import_module(import_path)
                         self.current_plugin_path = None
                     except Exception as e:
-                        logger.exception("Failed to import plugin %s: %s" % (plugin_name, e))
+                        logger.warn("Failed to import plugin %s: %s" % (plugin_name, e))
                         continue
         pconf = self.pconf
         news = [self.plugins[name] for name in self.plugins]
@@ -149,6 +171,8 @@ class PluginManager:
     def load_plugins(self):
         self.load_config()
         self.scan_plugins()
+        # 加载全量插件配置
+        self._load_all_config()
         pconf = self.pconf
         logger.debug("plugins.json config={}".format(pconf))
         for name, plugin in pconf["plugins"].items():

+ 1 - 1
plugins/tool/tool.py

@@ -126,7 +126,7 @@ class Tool(Plugin):
             return tool_config
         else:
             with open(config_path, "r") as f:
-                tool_config = json.load(f)
+                tool_config = super().load_config() or json.load(f)
         return tool_config
 
     def _build_tool_kwargs(self, kwargs: dict):