feat: config
This commit is contained in:
+168
-150
@@ -2,169 +2,187 @@ from addons.dashboard.server import AstrBotDashBoard, DashBoardData
|
||||
from pydantic import BaseModel
|
||||
from typing import Union, Optional
|
||||
import uuid
|
||||
from util import general_utils as gu
|
||||
from util.cmd_config import CmdConfig
|
||||
from dataclasses import dataclass
|
||||
import sys
|
||||
import os
|
||||
|
||||
class DashBoardConfig(BaseModel):
|
||||
type: str["group", "item"]
|
||||
name: str
|
||||
description: str
|
||||
uuid: Optional[str] # 仅 item 才需要
|
||||
body: Optional[list['DashBoardConfig']] # 仅 group 才需要
|
||||
value: Optional[Union[list, dict, str, int, bool]] # 仅 item 才需要
|
||||
val_type: Optional[str] # 仅 item 才需要
|
||||
@dataclass
|
||||
class DashBoardConfig():
|
||||
config_type: str
|
||||
name: Optional[str] = None
|
||||
description: Optional[str] = None
|
||||
path: Optional[str] = None # 仅 item 才需要
|
||||
body: Optional[list['DashBoardConfig']] = None # 仅 group 才需要
|
||||
value: Optional[Union[list, dict, str, int, bool]] = None # 仅 item 才需要
|
||||
val_type: Optional[str] = None # 仅 item 才需要
|
||||
|
||||
class DashBoardHelper():
|
||||
def __init__(self, dashboard_data: DashBoardData, config: dict):
|
||||
self.parse_config(config)
|
||||
dashboard_data.configs = {
|
||||
"data": []
|
||||
}
|
||||
self.parse_default_config(dashboard_data, config)
|
||||
self.dashboard_data: DashBoardData = dashboard_data
|
||||
self.dashboard = AstrBotDashBoard(self.dashboard_data)
|
||||
self.key_map = {} # key: uuid, value: config key name
|
||||
self.cc = CmdConfig()
|
||||
|
||||
@self.dashboard.register("post_configs")
|
||||
def on_post_configs(configs: dict):
|
||||
self.dashboard_data.configs = configs
|
||||
|
||||
return True
|
||||
def on_post_configs(post_configs: dict):
|
||||
try:
|
||||
gu.log(f"收到配置更新请求", gu.LEVEL_INFO, tag="可视化面板")
|
||||
self.save_config(post_configs)
|
||||
self.parse_default_config(self.dashboard_data, self.cc.get_all())
|
||||
# 重启
|
||||
py = sys.executable
|
||||
os.execl(py, py, *sys.argv)
|
||||
except Exception as e:
|
||||
gu.log(f"在保存配置时发生错误:{e}", gu.LEVEL_ERROR, tag="可视化面板")
|
||||
raise e
|
||||
|
||||
|
||||
# 将 config.yaml、 中的配置解析到 dashboard_data.configs 中
|
||||
def parse_config(self, config: dict):
|
||||
self.dashboard_data.configs = {
|
||||
"data": []
|
||||
}
|
||||
'''
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"type": "group",
|
||||
"name": "机器人平台配置",
|
||||
"description": "机器人平台配置描述",
|
||||
"body": [
|
||||
{
|
||||
"type": "item",
|
||||
"val_type": "bool",
|
||||
"name": "启用 QQ 频道平台",
|
||||
"description": "机器人平台名称描述",
|
||||
"value": true
|
||||
},
|
||||
{
|
||||
"type": "item",
|
||||
"val_type": "string",
|
||||
"name": "QQ机器人APPID",
|
||||
"description": "机器人平台名称描述",
|
||||
"value": "123456"
|
||||
},
|
||||
{
|
||||
"type": "item",
|
||||
"val_type": "string",
|
||||
"name": "QQ机器人令牌",
|
||||
"description": "机器人平台名称描述",
|
||||
"value": "123456"
|
||||
},
|
||||
{
|
||||
"type": "divider"
|
||||
},
|
||||
{
|
||||
"type": "item",
|
||||
"val_type": "bool",
|
||||
"name": "启用 GO-CQHTTP 平台",
|
||||
"description": "机器人平台名称描述",
|
||||
"value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "group",
|
||||
"name": "代理配置",
|
||||
"description": "代理配置描述",
|
||||
"body": [
|
||||
{
|
||||
"type": "item",
|
||||
"val_type": "string",
|
||||
"name": "代理地址",
|
||||
"description": "代理配置描述",
|
||||
"value": "http://localhost:7890"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "group",
|
||||
"name": "其他配置",
|
||||
"description": "其他配置描述",
|
||||
"body": [
|
||||
{
|
||||
"type": "item",
|
||||
"val_type": "string",
|
||||
"name": "回复前缀",
|
||||
"description": "[xxxx] 你好! 其中xxxx是你可以填写的前缀。如果为空则不显示。",
|
||||
"value": "GPT"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
]
|
||||
}
|
||||
'''
|
||||
for k in config:
|
||||
if 'qqbot' in k and 'enable' in k['qqbot'] and 'gocqbot' in k and 'enable' in k['gocqbot']':
|
||||
self.dashboard_data.configs['data'].append({
|
||||
"type": "group",
|
||||
"name": "机器人平台配置",
|
||||
"description": "机器人平台配置描述",
|
||||
"body": [
|
||||
{
|
||||
"type": "item",
|
||||
"val_type": "bool",
|
||||
"name": "启用 QQ 频道平台",
|
||||
"description": "机器人平台名称描述",
|
||||
"value": k['qqbot']['enable'],
|
||||
"uuid": uuid.uuid4().hex
|
||||
},
|
||||
{
|
||||
"type": "item",
|
||||
"val_type": "string",
|
||||
"name": "QQ机器人APPID",
|
||||
"description": "机器人平台名称描述",
|
||||
"value": k['qqbot']['appid'],
|
||||
"uuid": uuid.uuid4().hex
|
||||
},
|
||||
{
|
||||
"type": "item",
|
||||
"val_type": "string",
|
||||
"name": "QQ机器人令牌",
|
||||
"description": "机器人平台名称描述",
|
||||
"value": k['qqbot']['token'],
|
||||
"uuid": uuid.uuid4().hex
|
||||
},
|
||||
{
|
||||
"type": "divider"
|
||||
},
|
||||
{
|
||||
"type": "item",
|
||||
"val_type": "bool",
|
||||
"name": "启用 GO-CQHTTP 平台",
|
||||
"description": "机器人平台名称描述",
|
||||
"value": k['gocqbot']['enable'],
|
||||
"uuid": uuid.uuid4().hex
|
||||
}
|
||||
]
|
||||
})
|
||||
def parse_default_config(self, dashboard_data: DashBoardData, config: dict):
|
||||
|
||||
try:
|
||||
bot_platform_group = DashBoardConfig(
|
||||
config_type="group",
|
||||
name="机器人平台配置",
|
||||
description="机器人平台配置描述",
|
||||
body=[
|
||||
DashBoardConfig(
|
||||
config_type="item",
|
||||
val_type="bool",
|
||||
name="启用 QQ 频道平台",
|
||||
description="机器人平台名称描述",
|
||||
value=config['qqbot']['enable'],
|
||||
path="qqbot.enable",
|
||||
),
|
||||
DashBoardConfig(
|
||||
config_type="item",
|
||||
val_type="string",
|
||||
name="QQ机器人APPID",
|
||||
description="机器人平台名称描述",
|
||||
value=config['qqbot']['appid'],
|
||||
path="qqbot.appid",
|
||||
),
|
||||
DashBoardConfig(
|
||||
config_type="item",
|
||||
val_type="string",
|
||||
name="QQ机器人令牌",
|
||||
description="机器人平台名称描述",
|
||||
value=config['qqbot']['token'],
|
||||
path="qqbot.token",
|
||||
),
|
||||
DashBoardConfig(
|
||||
config_type="divider"
|
||||
),
|
||||
DashBoardConfig(
|
||||
config_type="item",
|
||||
val_type="bool",
|
||||
name="启用 GO-CQHTTP 平台",
|
||||
description="机器人平台名称描述",
|
||||
value=config['gocqbot']['enable'],
|
||||
path="gocqbot.enable",
|
||||
)
|
||||
]
|
||||
)
|
||||
|
||||
if 'http_proxy' in k:
|
||||
self.dashboard_data.configs['data'].append({
|
||||
"type": "group",
|
||||
"name": "代理配置",
|
||||
"description": "代理配置描述",
|
||||
"body": [
|
||||
{
|
||||
"type": "item",
|
||||
"val_type": "string",
|
||||
"name": "代理地址",
|
||||
"description": "代理配置描述",
|
||||
"value": k['proxy'],
|
||||
"uuid": uuid.uuid4().hex
|
||||
}
|
||||
]
|
||||
})
|
||||
proxy_group = DashBoardConfig(
|
||||
config_type="group",
|
||||
name="代理配置",
|
||||
description="代理配置描述",
|
||||
body=[
|
||||
DashBoardConfig(
|
||||
config_type="item",
|
||||
val_type="string",
|
||||
name="HTTP 代理地址",
|
||||
description="代理配置描述",
|
||||
value=config['http_proxy'],
|
||||
path="proxy",
|
||||
),
|
||||
DashBoardConfig(
|
||||
config_type="item",
|
||||
val_type="string",
|
||||
name="HTTPS 代理地址",
|
||||
description="代理配置描述",
|
||||
value=config['https_proxy'],
|
||||
path="proxy",
|
||||
)
|
||||
]
|
||||
)
|
||||
|
||||
other_group = DashBoardConfig(
|
||||
config_type="group",
|
||||
name="其他配置",
|
||||
description="其他配置描述",
|
||||
body=[
|
||||
DashBoardConfig(
|
||||
config_type="item",
|
||||
val_type="string",
|
||||
name="回复前缀",
|
||||
description="[xxxx] 你好! 其中xxxx是你可以填写的前缀。如果为空则不显示。",
|
||||
value=config['reply_prefix'],
|
||||
path="reply_prefix",
|
||||
)
|
||||
]
|
||||
)
|
||||
|
||||
dashboard_data.configs['data'] = [
|
||||
bot_platform_group,
|
||||
proxy_group,
|
||||
other_group
|
||||
]
|
||||
|
||||
except Exception as e:
|
||||
gu.log(f"配置文件解析错误:{e}", gu.LEVEL_ERROR)
|
||||
raise e
|
||||
|
||||
|
||||
def save_config(self, post_config: dict):
|
||||
'''
|
||||
根据 path 解析并保存配置
|
||||
'''
|
||||
# for config in dashboard_data.configs['data']:
|
||||
# if config['config_type'] == "group":
|
||||
# for item in config['body']:
|
||||
# queue.append(item)
|
||||
|
||||
queue = []
|
||||
for config in post_config['data']:
|
||||
queue.append(config)
|
||||
|
||||
while len(queue) > 0:
|
||||
config = queue.pop(0)
|
||||
if config['config_type'] == "group":
|
||||
for item in config['body']:
|
||||
queue.append(item)
|
||||
elif config['config_type'] == "item":
|
||||
if config['path'] is None or config['path'] == "":
|
||||
continue
|
||||
|
||||
path = config['path'].split('.')
|
||||
if len(path) == 0:
|
||||
continue
|
||||
|
||||
if config['val_type'] == "bool":
|
||||
self.cc.put_by_dot_str(config['path'], config['value'])
|
||||
elif config['val_type'] == "string":
|
||||
self.cc.put_by_dot_str(config['path'], config['value'])
|
||||
elif config['val_type'] == "int":
|
||||
try:
|
||||
self.cc.put_by_dot_str(config['path'], int(config['value']))
|
||||
except:
|
||||
raise ValueError(f"配置项 {config['name']} 的值必须是整数")
|
||||
elif config['val_type'] == "float":
|
||||
try:
|
||||
self.cc.put_by_dot_str(config['path'], float(config['value']))
|
||||
except:
|
||||
raise ValueError(f"配置项 {config['name']} 的值必须是浮点数")
|
||||
else:
|
||||
raise NotImplementedError(f"未知或者未实现的的配置项类型:{config['val_type']}")
|
||||
|
||||
def run(self):
|
||||
self.dashboard.run()
|
||||
+17
-12
@@ -1,14 +1,16 @@
|
||||
from flask import Flask
|
||||
from flask import Flask, request
|
||||
import datetime
|
||||
from pydantic import BaseModel
|
||||
from util import general_utils as gu
|
||||
from dataclasses import dataclass
|
||||
|
||||
class DashBoardData(BaseModel):
|
||||
@dataclass
|
||||
class DashBoardData():
|
||||
stats: dict
|
||||
configs: dict
|
||||
logs: dict
|
||||
|
||||
class Response(BaseModel):
|
||||
|
||||
@dataclass
|
||||
class Response():
|
||||
status: str
|
||||
message: str
|
||||
data: dict
|
||||
@@ -37,17 +39,20 @@ class AstrBotDashBoard():
|
||||
|
||||
@self.dashboard_be.post("/configs")
|
||||
def post_configs():
|
||||
if self.funcs["post_configs"](self.dashboard_data.configs):
|
||||
post_configs = request.json
|
||||
try:
|
||||
self.funcs["post_configs"](post_configs)
|
||||
return Response(
|
||||
status="success",
|
||||
message="",
|
||||
message="保存成功~ 机器人正在重启以应用新的配置。",
|
||||
data=None
|
||||
).__dict__
|
||||
except Exception as e:
|
||||
return Response(
|
||||
status="error",
|
||||
message=e.__str__(),
|
||||
data=self.dashboard_data.configs
|
||||
).__dict__
|
||||
return Response(
|
||||
status="error",
|
||||
message="",
|
||||
data=self.dashboard_data.configs
|
||||
).__dict__
|
||||
|
||||
@self.dashboard_be.get("/logs")
|
||||
def get_logs():
|
||||
|
||||
+20
-6
@@ -40,6 +40,7 @@ import traceback
|
||||
from . global_object import GlobalObject
|
||||
from typing import Union, Callable
|
||||
from addons.dashboard.helper import DashBoardHelper
|
||||
from addons.dashboard.server import DashBoardData
|
||||
|
||||
# 缓存的会话
|
||||
session_dict = {}
|
||||
@@ -122,6 +123,8 @@ cc.init_attributes("openai_image_generate", {
|
||||
"style": "vivid",
|
||||
"quality": "standard",
|
||||
})
|
||||
cc.init_attributes("http_proxy", "")
|
||||
cc.init_attributes("https_proxy", "")
|
||||
# cc.init_attributes(["qq_forward_mode"], False)
|
||||
|
||||
# QQ机器人
|
||||
@@ -203,7 +206,9 @@ def initBot(cfg, prov):
|
||||
global keywords, _global_object
|
||||
|
||||
# 迁移旧配置
|
||||
gu.try_migrate_config()
|
||||
gu.try_migrate_config(cfg)
|
||||
# 使用新配置
|
||||
cfg = cc.get_all()
|
||||
|
||||
_event_loop = asyncio.new_event_loop()
|
||||
asyncio.set_event_loop(_event_loop)
|
||||
@@ -213,7 +218,13 @@ def initBot(cfg, prov):
|
||||
_global_object.base_config = cfg
|
||||
|
||||
if 'reply_prefix' in cfg:
|
||||
_global_object.reply_prefix = cfg['reply_prefix']
|
||||
# 适配旧版配置
|
||||
if isinstance(cfg['reply_prefix'], dict):
|
||||
for k in cfg['reply_prefix']:
|
||||
_global_object.reply_prefix = cfg['reply_prefix'][k]
|
||||
break
|
||||
else:
|
||||
_global_object.reply_prefix = cfg['reply_prefix']
|
||||
|
||||
# 语言模型提供商
|
||||
gu.log("--------加载语言模型--------", gu.LEVEL_INFO, fg=gu.FG_COLORS['yellow'])
|
||||
@@ -398,8 +409,12 @@ def initBot(cfg, prov):
|
||||
}
|
||||
|
||||
# 初始化dashboard
|
||||
dashboard_helper = DashBoardHelper(_global_object.dashboard_data)
|
||||
dashboard_helper.parse_config(cfg)
|
||||
_global_object.dashboard_data = DashBoardData(
|
||||
stats={},
|
||||
configs={},
|
||||
logs={}
|
||||
)
|
||||
dashboard_helper = DashBoardHelper(_global_object.dashboard_data, config=cc.get_all())
|
||||
dashboard_thread = threading.Thread(target=dashboard_helper.run, daemon=True)
|
||||
dashboard_thread.start()
|
||||
|
||||
@@ -736,8 +751,7 @@ async def oper_msg(message: Union[GroupMessage, FriendMessage, GuildMessage, Nak
|
||||
res = ""
|
||||
chatgpt_res = str(res)
|
||||
|
||||
if chosen_provider in _global_object.reply_prefix:
|
||||
chatgpt_res = _global_object.reply_prefix[chosen_provider] + chatgpt_res
|
||||
chatgpt_res = _global_object.reply_prefix + chatgpt_res
|
||||
except BaseException as e:
|
||||
gu.log(f"调用异常:{traceback.format_exc()}", gu.LEVEL_ERROR, max_len=100000)
|
||||
gu.log("调用语言模型例程时出现异常。原因: "+str(e), gu.LEVEL_ERROR)
|
||||
|
||||
@@ -33,9 +33,9 @@ def main():
|
||||
input("config.yaml 配置文件格式错误,请遵守 yaml 格式。")
|
||||
|
||||
# 设置代理
|
||||
if 'http_proxy' in cfg:
|
||||
if 'http_proxy' in cfg and cfg['http_proxy'] != '':
|
||||
os.environ['HTTP_PROXY'] = cfg['http_proxy']
|
||||
if 'https_proxy' in cfg:
|
||||
if 'https_proxy' in cfg and cfg['https_proxy'] != '':
|
||||
os.environ['HTTPS_PROXY'] = cfg['https_proxy']
|
||||
|
||||
os.environ['NO_PROXY'] = 'cn.bing.com,https://api.sgroup.qq.com'
|
||||
|
||||
@@ -37,6 +37,25 @@ class CmdConfig():
|
||||
with open(cpath, "w", encoding="utf-8-sig") as f:
|
||||
json.dump(d, f, indent=4, ensure_ascii=False)
|
||||
f.flush()
|
||||
|
||||
@staticmethod
|
||||
def put_by_dot_str(key: str, value):
|
||||
'''
|
||||
根据点分割的字符串,将值写入配置文件
|
||||
'''
|
||||
check_exist()
|
||||
with open(cpath, "r", encoding="utf-8-sig") as f:
|
||||
d = json.load(f)
|
||||
_d = d
|
||||
_ks = key.split(".")
|
||||
for i in range(len(_ks)):
|
||||
if i == len(_ks) - 1:
|
||||
_d[_ks[i]] = value
|
||||
else:
|
||||
_d = _d[_ks[i]]
|
||||
with open(cpath, "w", encoding="utf-8-sig") as f:
|
||||
json.dump(d, f, indent=4, ensure_ascii=False)
|
||||
f.flush()
|
||||
|
||||
@staticmethod
|
||||
def init_attributes(key: Union[str, list], init_val = ""):
|
||||
|
||||
Reference in New Issue
Block a user