Skip to content

Commit

Permalink
Merge pull request zhayujie#1328 from zhayujie/feat-1.3.3
Browse files Browse the repository at this point in the history
feat: support global plugin config for docker env
  • Loading branch information
zhayujie committed Jul 21, 2023
2 parents 2361e3c + 9ef8e1b commit e0d2e34
Show file tree
Hide file tree
Showing 8 changed files with 120 additions and 41 deletions.
28 changes: 26 additions & 2 deletions config.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
"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"], # 开启自动回复的群名称列表
Expand All @@ -37,7 +37,8 @@
"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的调用频率限制
Expand Down Expand Up @@ -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())
19 changes: 10 additions & 9 deletions plugins/banwords/banwords.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,17 @@ class Banwords(Plugin):
def __init__(self):
super().__init__()
try:
# load config
conf = super().load_config()
curdir = os.path.dirname(__file__)
config_path = os.path.join(curdir, "config.json")
conf = None
if not os.path.exists(config_path):
conf = {"action": "ignore"}
with open(config_path, "w") as f:
json.dump(conf, f, indent=4)
else:
with open(config_path, "r") as f:
conf = json.load(f)
if not conf:
# 配置不存在则写入默认配置
config_path = os.path.join(curdir, "config.json")
if not os.path.exists(config_path):
conf = {"action": "ignore"}
with open(config_path, "w") as f:
json.dump(conf, f, indent=4)

self.searchr = WordsSearch()
self.action = conf["action"]
banwords_path = os.path.join(curdir, "banwords.txt")
Expand Down
9 changes: 2 additions & 7 deletions plugins/bdunit/bdunit.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,9 @@ class BDunit(Plugin):
def __init__(self):
super().__init__()
try:
curdir = os.path.dirname(__file__)
config_path = os.path.join(curdir, "config.json")
conf = None
if not os.path.exists(config_path):
conf = super().load_config()
if not conf:
raise Exception("config.json not found")
else:
with open(config_path, "r") as f:
conf = json.load(f)
self.service_id = conf["service_id"]
self.api_key = conf["api_key"]
self.secret_key = conf["secret_key"]
Expand Down
24 changes: 24 additions & 0 deletions plugins/config.json.template
Original file line number Diff line number Diff line change
@@ -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"
}
}
}
17 changes: 7 additions & 10 deletions plugins/godcmd/godcmd.py
Original file line number Diff line number Diff line change
Expand Up @@ -178,16 +178,13 @@ class Godcmd(Plugin):
def __init__(self):
super().__init__()

curdir = os.path.dirname(__file__)
config_path = os.path.join(curdir, "config.json")
gconf = None
if not os.path.exists(config_path):
gconf = {"password": "", "admin_users": []}
with open(config_path, "w") as f:
json.dump(gconf, f, indent=4)
else:
with open(config_path, "r") as f:
gconf = json.load(f)
config_path = os.path.join(os.path.dirname(__file__), "config.json")
gconf = super().load_config()
if not gconf:
if not os.path.exists(config_path):
gconf = {"password": "", "admin_users": []}
with open(config_path, "w") as f:
json.dump(gconf, f, indent=4)
if gconf["password"] == "":
self.temp_password = "".join(random.sample(string.digits, 4))
logger.info("[Godcmd] 因未设置口令,本次的临时口令为%s。" % self.temp_password)
Expand Down
22 changes: 22 additions & 0 deletions plugins/plugin.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,28 @@
import os
import json
from config import pconf
from common.log import logger


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

def load_config(self) -> dict:
"""
加载当前插件配置
:return: 插件配置字典
"""
# 优先获取 plugins/config.json 中的全局配置
plugin_conf = pconf(self.name)
if not plugin_conf:
# 全局配置不存在,则获取插件目录下的配置
plugin_config_path = os.path.join(self.path, "config.json")
if os.path.exists(plugin_config_path):
with open(plugin_config_path, "r") as f:
plugin_conf = json.load(f)
logger.debug(f"loading plugin config, plugin_name={self.name}, conf={plugin_conf}")
return plugin_conf

def get_help_text(self, **kwargs):
return "暂无帮助信息"
30 changes: 27 additions & 3 deletions plugins/plugin_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
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 *

Expand Down Expand Up @@ -62,6 +62,28 @@ def load_config(self):
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"
Expand All @@ -88,7 +110,7 @@ def scan_plugins(self):
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]
Expand Down Expand Up @@ -123,7 +145,7 @@ def activate_plugins(self): # 生成新开启的插件实例
try:
instance = plugincls()
except Exception as e:
logger.exception("Failed to init %s, diabled. %s" % (name, e))
logger.warn("Failed to init %s, diabled. %s" % (name, e))
self.disable_plugin(name)
failed_plugins.append(name)
continue
Expand All @@ -149,6 +171,8 @@ def reload_plugin(self, name: str):
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():
Expand Down
12 changes: 2 additions & 10 deletions plugins/tool/tool.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
from bridge.context import ContextType
from bridge.reply import Reply, ReplyType
from common import const
from common.log import logger
from config import conf
from plugins import *

Expand Down Expand Up @@ -119,15 +118,8 @@ def on_handle_context(self, e_context: EventContext):
return

def _read_json(self) -> dict:
curdir = os.path.dirname(__file__)
config_path = os.path.join(curdir, "config.json")
tool_config = {"tools": [], "kwargs": {}}
if not os.path.exists(config_path):
return tool_config
else:
with open(config_path, "r") as f:
tool_config = json.load(f)
return tool_config
default_config = {"tools": [], "kwargs": {}}
return super().load_config() or default_config

def _build_tool_kwargs(self, kwargs: dict):
tool_model_name = kwargs.get("model_name")
Expand Down

0 comments on commit e0d2e34

Please sign in to comment.