mirror of
https://github.com/langbot-app/LangBot.git
synced 2026-06-10 07:46:02 +00:00
refactor: 基本启动流程
This commit is contained in:
0
pkg/boot/__init__.py
Normal file
0
pkg/boot/__init__.py
Normal file
31
pkg/boot/app.py
Normal file
31
pkg/boot/app.py
Normal file
@@ -0,0 +1,31 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
|
||||
from ..qqbot import manager as qqbot_mgr
|
||||
from ..openai import manager as openai_mgr
|
||||
from ..config import manager as config_mgr
|
||||
from ..database import manager as database_mgr
|
||||
from ..utils.center import v2 as center_mgr
|
||||
|
||||
|
||||
class Application:
|
||||
im_mgr: qqbot_mgr.QQBotManager = None
|
||||
|
||||
llm_mgr: openai_mgr.OpenAIInteract = None
|
||||
|
||||
cfg_mgr: config_mgr.ConfigManager = None
|
||||
|
||||
tips_mgr: config_mgr.ConfigManager = None
|
||||
|
||||
db_mgr: database_mgr.DatabaseManager = None
|
||||
|
||||
ctr_mgr: center_mgr.V2CenterAPI = None
|
||||
|
||||
logger: logging.Logger = None
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
async def run(self):
|
||||
pass
|
||||
124
pkg/boot/boot.py
Normal file
124
pkg/boot/boot.py
Normal file
@@ -0,0 +1,124 @@
|
||||
from __future__ import print_function
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
from . import files
|
||||
from . import deps
|
||||
from . import log
|
||||
from . import config
|
||||
|
||||
from . import app
|
||||
from ..audit import identifier
|
||||
from ..database import manager as db_mgr
|
||||
from ..openai import manager as llm_mgr
|
||||
from ..openai import session as llm_session
|
||||
from ..openai import dprompt as llm_dprompt
|
||||
from ..qqbot import manager as im_mgr
|
||||
from ..qqbot.cmds import aamgr as im_cmd_aamgr
|
||||
from ..plugin import host as plugin_host
|
||||
from ..utils.center import v2 as center_v2
|
||||
from ..utils import updater
|
||||
from ..utils import context
|
||||
|
||||
use_override = False
|
||||
|
||||
|
||||
async def make_app() -> app.Application:
|
||||
global use_override
|
||||
|
||||
generated_files = await files.generate_files()
|
||||
|
||||
if generated_files:
|
||||
print("以下文件不存在,已自动生成,请修改配置文件后重启:")
|
||||
for file in generated_files:
|
||||
print("-", file)
|
||||
|
||||
sys.exit(0)
|
||||
|
||||
missing_deps = await deps.check_deps()
|
||||
|
||||
if missing_deps:
|
||||
print("以下依赖包未安装,将自动安装,请完成后重启程序:")
|
||||
for dep in missing_deps:
|
||||
print("-", dep)
|
||||
await deps.install_deps(missing_deps)
|
||||
sys.exit(0)
|
||||
|
||||
qcg_logger = await log.init_logging()
|
||||
|
||||
# 生成标识符
|
||||
identifier.init()
|
||||
|
||||
cfg_mgr = await config.load_config()
|
||||
context.set_config_manager(cfg_mgr)
|
||||
cfg = cfg_mgr.data
|
||||
|
||||
# 检查是否携带了 --override 或 -r 参数
|
||||
if '--override' in sys.argv or '-r' in sys.argv:
|
||||
use_override = True
|
||||
|
||||
if use_override:
|
||||
overrided = await config.override_config_manager(cfg_mgr)
|
||||
if overrided:
|
||||
qcg_logger.info("以下配置项已使用 override.json 覆盖:" + ",".join(overrided))
|
||||
|
||||
tips_mgr = await config.load_tips()
|
||||
|
||||
# 初始化文字转图片
|
||||
from pkg.utils import text2img
|
||||
# TODO make it async
|
||||
text2img.initialize()
|
||||
|
||||
# 检查管理员QQ号
|
||||
if cfg_mgr.data['admin_qq'] == 0:
|
||||
qcg_logger.warning("未设置管理员QQ号,将无法使用管理员命令,请在 config.py 中修改 admin_qq")
|
||||
|
||||
# TODO make it async
|
||||
llm_dprompt.register_all()
|
||||
im_cmd_aamgr.register_all()
|
||||
im_cmd_aamgr.apply_privileges()
|
||||
|
||||
# 构建组建实例
|
||||
ap = app.Application()
|
||||
ap.logger = qcg_logger
|
||||
ap.cfg_mgr = cfg_mgr
|
||||
ap.tips_mgr = tips_mgr
|
||||
|
||||
center_v2_api = center_v2.V2CenterAPI(
|
||||
basic_info={
|
||||
"host_id": identifier.identifier['host_id'],
|
||||
"instance_id": identifier.identifier['instance_id'],
|
||||
"semantic_version": updater.get_current_tag(),
|
||||
"platform": sys.platform,
|
||||
},
|
||||
runtime_info={
|
||||
"admin_id": "{}".format(cfg['admin_qq']),
|
||||
"msg_source": cfg['msg_source_adapter'],
|
||||
}
|
||||
)
|
||||
ap.ctr_mgr = center_v2_api
|
||||
|
||||
db_mgr_inst = db_mgr.DatabaseManager(ap)
|
||||
# TODO make it async
|
||||
db_mgr_inst.initialize_database()
|
||||
ap.db_mgr = db_mgr_inst
|
||||
|
||||
llm_mgr_inst = llm_mgr.OpenAIInteract(ap)
|
||||
ap.llm_mgr = llm_mgr_inst
|
||||
# TODO make it async
|
||||
llm_session.load_sessions()
|
||||
|
||||
im_mgr_inst = im_mgr.QQBotManager(first_time_init=True, ap=ap)
|
||||
ap.im_mgr = im_mgr_inst
|
||||
|
||||
# TODO make it async
|
||||
plugin_host.load_plugins()
|
||||
# plugin_host.initialize_plugins()
|
||||
|
||||
return ap
|
||||
|
||||
|
||||
async def main():
|
||||
app_inst = await make_app()
|
||||
await app_inst.run()
|
||||
43
pkg/boot/config.py
Normal file
43
pkg/boot/config.py
Normal file
@@ -0,0 +1,43 @@
|
||||
import json
|
||||
|
||||
from ..config import manager as config_mgr
|
||||
from ..config.impls import pymodule
|
||||
|
||||
|
||||
async def load_config() -> config_mgr.ConfigManager:
|
||||
"""加载配置文件"""
|
||||
cfg_inst = pymodule.PythonModuleConfigFile(
|
||||
"config.py",
|
||||
"config-template.py"
|
||||
)
|
||||
|
||||
cfg_mgr = config_mgr.ConfigManager(cfg_inst)
|
||||
await cfg_mgr.load_config()
|
||||
|
||||
return cfg_mgr
|
||||
|
||||
|
||||
async def load_tips() -> config_mgr.ConfigManager:
|
||||
"""加载提示文件"""
|
||||
tips_inst = pymodule.PythonModuleConfigFile(
|
||||
"tips.py",
|
||||
"tips-custom-template.py"
|
||||
)
|
||||
|
||||
tips_mgr = config_mgr.ConfigManager(tips_inst)
|
||||
await tips_mgr.load_config()
|
||||
|
||||
return tips_mgr
|
||||
|
||||
|
||||
async def override_config_manager(cfg_mgr: config_mgr.ConfigManager) -> list[str]:
|
||||
override_json = json.load(open("override.json", "r", encoding="utf-8"))
|
||||
overrided = []
|
||||
|
||||
config = cfg_mgr.data
|
||||
for key in override_json:
|
||||
if key in config:
|
||||
config[key] = override_json[key]
|
||||
overrided.append(key)
|
||||
|
||||
return overrided
|
||||
34
pkg/boot/deps.py
Normal file
34
pkg/boot/deps.py
Normal file
@@ -0,0 +1,34 @@
|
||||
import pip
|
||||
|
||||
required_deps = {
|
||||
"requests": "requests",
|
||||
"openai": "openai",
|
||||
"dulwich": "dulwich",
|
||||
"colorlog": "colorlog",
|
||||
"mirai": "yiri-mirai-rc",
|
||||
"func_timeout": "func_timeout",
|
||||
"PIL": "pillow",
|
||||
"nakuru": "nakuru-project-idk",
|
||||
"CallingGPT": "CallingGPT",
|
||||
"tiktoken": "tiktoken",
|
||||
"yaml": "pyyaml",
|
||||
"aiohttp": "aiohttp",
|
||||
}
|
||||
|
||||
|
||||
async def check_deps() -> list[str]:
|
||||
global required_deps
|
||||
|
||||
missing_deps = []
|
||||
for dep in required_deps:
|
||||
try:
|
||||
__import__(dep)
|
||||
except ImportError:
|
||||
missing_deps.append(dep)
|
||||
return missing_deps
|
||||
|
||||
async def install_deps(deps: list[str]):
|
||||
global required_deps
|
||||
|
||||
for dep in deps:
|
||||
pip.main(["install", required_deps[dep]])
|
||||
37
pkg/boot/files.py
Normal file
37
pkg/boot/files.py
Normal file
@@ -0,0 +1,37 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import shutil
|
||||
import sys
|
||||
|
||||
|
||||
required_files = {
|
||||
"config.py": "config-template.py",
|
||||
"banlist.py": "res/templates/banlist-template.py",
|
||||
"tips.py": "tips-custom-template.py",
|
||||
"sensitive.json": "res/templates/sensitive-template.json",
|
||||
"scenario/default.json": "scenario/default-template.json",
|
||||
"cmdpriv.json": "res/templates/cmdpriv-template.json",
|
||||
}
|
||||
|
||||
required_paths = [
|
||||
"plugins",
|
||||
"prompts",
|
||||
"temp",
|
||||
"logs"
|
||||
]
|
||||
|
||||
async def generate_files() -> list[str]:
|
||||
global required_files, required_paths
|
||||
|
||||
for required_paths in required_paths:
|
||||
if not os.path.exists(required_paths):
|
||||
os.mkdir(required_paths)
|
||||
|
||||
generated_files = []
|
||||
for file in required_files:
|
||||
if not os.path.exists(file):
|
||||
shutil.copyfile(required_files[file], file)
|
||||
generated_files.append(file)
|
||||
|
||||
return generated_files
|
||||
47
pkg/boot/log.py
Normal file
47
pkg/boot/log.py
Normal file
@@ -0,0 +1,47 @@
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
|
||||
import colorlog
|
||||
|
||||
|
||||
log_colors_config = {
|
||||
'DEBUG': 'green', # cyan white
|
||||
'INFO': 'white',
|
||||
'WARNING': 'yellow',
|
||||
'ERROR': 'red',
|
||||
'CRITICAL': 'cyan',
|
||||
}
|
||||
|
||||
|
||||
async def init_logging() -> logging.Logger:
|
||||
|
||||
level = logging.INFO
|
||||
|
||||
if 'DEBUG' in os.environ and os.environ['DEBUG'] in ['true', '1']:
|
||||
level = logging.DEBUG
|
||||
|
||||
log_file_name = "logs/qcg-%s.log" % time.strftime("%Y-%m-%d-%H-%M-%S", time.localtime())
|
||||
|
||||
qcg_logger = logging.getLogger("qcg")
|
||||
|
||||
qcg_logger.setLevel(level)
|
||||
|
||||
log_handlers: logging.Handler = [
|
||||
logging.StreamHandler(sys.stdout),
|
||||
logging.FileHandler(log_file_name)
|
||||
]
|
||||
|
||||
for handler in log_handlers:
|
||||
handler.setLevel(level)
|
||||
handler.setFormatter(
|
||||
colorlog.ColoredFormatter(
|
||||
fmt="[%(asctime)s.%(msecs)03d] %(pathname)s (%(lineno)d) - [%(levelname)s] :\n%(message)s",
|
||||
datefmt="%Y-%m-%d %H:%M:%S",
|
||||
log_colors=log_colors_config
|
||||
)
|
||||
)
|
||||
qcg_logger.addHandler(handler)
|
||||
|
||||
return qcg_logger
|
||||
0
pkg/boot/misc.py
Normal file
0
pkg/boot/misc.py
Normal file
Reference in New Issue
Block a user