Browse Source

feat: add plugin global config to support docker volumes

master
zhayujie 1 year ago
parent
commit
954e55f4b4
8 changed files with 90 additions and 8 deletions
  1. +26
    -2
      config.py
  2. +1
    -1
      plugins/banwords/banwords.py
  3. +1
    -1
      plugins/bdunit/bdunit.py
  4. +24
    -0
      plugins/config-template.json
  5. +1
    -1
      plugins/godcmd/godcmd.py
  6. +10
    -0
      plugins/plugin.py
  7. +26
    -2
      plugins/plugin_manager.py
  8. +1
    -1
      plugins/tool/tool.py

+ 26
- 2
config.py View File

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

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


+ 1
- 1
plugins/bdunit/bdunit.py View File

@@ -36,7 +36,7 @@ class BDunit(Plugin):
raise Exception("config.json not found") raise Exception("config.json not found")
else: else:
with open(config_path, "r") as f: 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.service_id = conf["service_id"]
self.api_key = conf["api_key"] self.api_key = conf["api_key"]
self.secret_key = conf["secret_key"] self.secret_key = conf["secret_key"]


+ 24
- 0
plugins/config-template.json View File

@@ -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 View File

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


+ 10
- 0
plugins/plugin.py View File

@@ -1,6 +1,16 @@
import os
from config import pconf

class Plugin: class Plugin:
def __init__(self): def __init__(self):
self.handlers = {} self.handlers = {}


def load_config(self) -> dict:
"""
加载当前插件配置
:return: 插件配置字典
"""
return pconf(self.name)

def get_help_text(self, **kwargs): def get_help_text(self, **kwargs):
return "暂无帮助信息" return "暂无帮助信息"

+ 26
- 2
plugins/plugin_manager.py View File

@@ -9,7 +9,7 @@ import sys
from common.log import logger from common.log import logger
from common.singleton import singleton from common.singleton import singleton
from common.sorted_dict import SortedDict from common.sorted_dict import SortedDict
from config import conf
from config import conf, write_plugin_config


from .event import * from .event import *


@@ -62,6 +62,28 @@ class PluginManager:
self.save_config() self.save_config()
return pconf 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): def scan_plugins(self):
logger.info("Scaning plugins ...") logger.info("Scaning plugins ...")
plugins_dir = "./plugins" plugins_dir = "./plugins"
@@ -88,7 +110,7 @@ class PluginManager:
self.loaded[plugin_path] = importlib.import_module(import_path) self.loaded[plugin_path] = importlib.import_module(import_path)
self.current_plugin_path = None self.current_plugin_path = None
except Exception as e: 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 continue
pconf = self.pconf pconf = self.pconf
news = [self.plugins[name] for name in self.plugins] news = [self.plugins[name] for name in self.plugins]
@@ -149,6 +171,8 @@ class PluginManager:
def load_plugins(self): def load_plugins(self):
self.load_config() self.load_config()
self.scan_plugins() self.scan_plugins()
# 加载全量插件配置
self._load_all_config()
pconf = self.pconf pconf = self.pconf
logger.debug("plugins.json config={}".format(pconf)) logger.debug("plugins.json config={}".format(pconf))
for name, plugin in pconf["plugins"].items(): for name, plugin in pconf["plugins"].items():


+ 1
- 1
plugins/tool/tool.py View File

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


def _build_tool_kwargs(self, kwargs: dict): def _build_tool_kwargs(self, kwargs: dict):


Loading…
Cancel
Save