mirror of
https://github.com/langbot-app/LangBot.git
synced 2026-06-02 03:55:55 +00:00
refactor: 配置文件均改为json
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -33,3 +33,4 @@ bard.json
|
|||||||
!/docker-compose.yaml
|
!/docker-compose.yaml
|
||||||
res/instance_id.json
|
res/instance_id.json
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
/data
|
||||||
@@ -12,8 +12,7 @@ class V2MainDataAPI(apigroup.APIGroup):
|
|||||||
super().__init__(prefix+"/main", ap)
|
super().__init__(prefix+"/main", ap)
|
||||||
|
|
||||||
async def do(self, *args, **kwargs):
|
async def do(self, *args, **kwargs):
|
||||||
config = self.ap.cfg_mgr.data
|
if not self.ap.system_cfg.data['report-usage']:
|
||||||
if not config['report_usage']:
|
|
||||||
return None
|
return None
|
||||||
return await super().do(*args, **kwargs)
|
return await super().do(*args, **kwargs)
|
||||||
|
|
||||||
|
|||||||
@@ -12,8 +12,7 @@ class V2PluginDataAPI(apigroup.APIGroup):
|
|||||||
super().__init__(prefix+"/plugin", ap)
|
super().__init__(prefix+"/plugin", ap)
|
||||||
|
|
||||||
async def do(self, *args, **kwargs):
|
async def do(self, *args, **kwargs):
|
||||||
config = self.ap.cfg_mgr.data
|
if not self.ap.system_cfg.data['report-usage']:
|
||||||
if not config['report_usage']:
|
|
||||||
return None
|
return None
|
||||||
return await super().do(*args, **kwargs)
|
return await super().do(*args, **kwargs)
|
||||||
|
|
||||||
|
|||||||
@@ -12,8 +12,7 @@ class V2UsageDataAPI(apigroup.APIGroup):
|
|||||||
super().__init__(prefix+"/usage", ap)
|
super().__init__(prefix+"/usage", ap)
|
||||||
|
|
||||||
async def do(self, *args, **kwargs):
|
async def do(self, *args, **kwargs):
|
||||||
config = self.ap.cfg_mgr.data
|
if not self.ap.system_cfg.data['report-usage']:
|
||||||
if not config['report_usage']:
|
|
||||||
return None
|
return None
|
||||||
return await super().do(*args, **kwargs)
|
return await super().do(*args, **kwargs)
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ from ..core import app, entities as core_entities
|
|||||||
from ..provider import entities as llm_entities
|
from ..provider import entities as llm_entities
|
||||||
from . import entities, operator, errors
|
from . import entities, operator, errors
|
||||||
|
|
||||||
from .operators import func, plugin, default, reset, list as list_cmd, last, next, delc, resend, prompt, cfg, cmd, help, version, update
|
from .operators import func, plugin, default, reset, list as list_cmd, last, next, delc, resend, prompt, cmd, help, version, update
|
||||||
|
|
||||||
|
|
||||||
class CommandManager:
|
class CommandManager:
|
||||||
@@ -85,10 +85,12 @@ class CommandManager:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
privilege = 1
|
privilege = 1
|
||||||
if query.sender_id == self.ap.cfg_mgr.data['admin_qq'] \
|
|
||||||
or query.sender_id in self.ap.cfg_mgr['admin_qq']:
|
if f'{query.launcher_type.value}_{query.launcher_id}' in self.ap.system_cfg.data['admin-sessions']:
|
||||||
privilege = 2
|
privilege = 2
|
||||||
|
|
||||||
|
print(f'privilege: {privilege}')
|
||||||
|
|
||||||
ctx = entities.ExecuteContext(
|
ctx = entities.ExecuteContext(
|
||||||
query=query,
|
query=query,
|
||||||
session=session,
|
session=session,
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ def operator_class(
|
|||||||
cls.help = help
|
cls.help = help
|
||||||
cls.usage = usage
|
cls.usage = usage
|
||||||
cls.parent_class = parent_class
|
cls.parent_class = parent_class
|
||||||
|
cls.lowest_privilege = privilege
|
||||||
|
|
||||||
preregistered_operators.append(cls)
|
preregistered_operators.append(cls)
|
||||||
|
|
||||||
|
|||||||
@@ -1,98 +0,0 @@
|
|||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
import typing
|
|
||||||
import json
|
|
||||||
|
|
||||||
from .. import operator, entities, cmdmgr, errors
|
|
||||||
|
|
||||||
|
|
||||||
@operator.operator_class(
|
|
||||||
name="cfg",
|
|
||||||
help="配置项管理",
|
|
||||||
usage='!cfg <配置项> [配置值]\n!cfg all',
|
|
||||||
privilege=2
|
|
||||||
)
|
|
||||||
class CfgOperator(operator.CommandOperator):
|
|
||||||
|
|
||||||
async def execute(
|
|
||||||
self,
|
|
||||||
context: entities.ExecuteContext
|
|
||||||
) -> typing.AsyncGenerator[entities.CommandReturn, None]:
|
|
||||||
"""执行
|
|
||||||
"""
|
|
||||||
reply = ''
|
|
||||||
|
|
||||||
params = context.crt_params
|
|
||||||
cfg_mgr = self.ap.cfg_mgr
|
|
||||||
|
|
||||||
false = False
|
|
||||||
true = True
|
|
||||||
|
|
||||||
reply_str = ""
|
|
||||||
if len(params) == 0:
|
|
||||||
yield entities.CommandReturn(error=errors.ParamNotEnoughError('请提供配置项名称'))
|
|
||||||
else:
|
|
||||||
cfg_name = params[0]
|
|
||||||
if cfg_name == 'all':
|
|
||||||
reply_str = "[bot]所有配置项:\n\n"
|
|
||||||
for cfg in cfg_mgr.data.keys():
|
|
||||||
if not cfg.startswith('__') and not cfg == 'logging':
|
|
||||||
# 根据配置项类型进行格式化,如果是字典则转换为json并格式化
|
|
||||||
if isinstance(cfg_mgr.data[cfg], str):
|
|
||||||
reply_str += "{}: \"{}\"\n".format(cfg, cfg_mgr.data[cfg])
|
|
||||||
elif isinstance(cfg_mgr.data[cfg], dict):
|
|
||||||
# 不进行unicode转义,并格式化
|
|
||||||
reply_str += "{}: {}\n".format(cfg,
|
|
||||||
json.dumps(cfg_mgr.data[cfg],
|
|
||||||
ensure_ascii=False, indent=4))
|
|
||||||
else:
|
|
||||||
reply_str += "{}: {}\n".format(cfg, cfg_mgr.data[cfg])
|
|
||||||
yield entities.CommandReturn(text=reply_str)
|
|
||||||
else:
|
|
||||||
cfg_entry_path = cfg_name.split('.')
|
|
||||||
|
|
||||||
try:
|
|
||||||
if len(params) == 1: # 未指定配置值,返回配置项值
|
|
||||||
cfg_entry = cfg_mgr.data[cfg_entry_path[0]]
|
|
||||||
if len(cfg_entry_path) > 1:
|
|
||||||
for i in range(1, len(cfg_entry_path)):
|
|
||||||
cfg_entry = cfg_entry[cfg_entry_path[i]]
|
|
||||||
|
|
||||||
if isinstance(cfg_entry, str):
|
|
||||||
reply_str = "[bot]配置项{}: \"{}\"\n".format(cfg_name, cfg_entry)
|
|
||||||
elif isinstance(cfg_entry, dict):
|
|
||||||
reply_str = "[bot]配置项{}: {}\n".format(cfg_name,
|
|
||||||
json.dumps(cfg_entry,
|
|
||||||
ensure_ascii=False, indent=4))
|
|
||||||
else:
|
|
||||||
reply_str = "[bot]配置项{}: {}\n".format(cfg_name, cfg_entry)
|
|
||||||
|
|
||||||
yield entities.CommandReturn(text=reply_str)
|
|
||||||
else:
|
|
||||||
cfg_value = " ".join(params[1:])
|
|
||||||
|
|
||||||
cfg_value = eval(cfg_value)
|
|
||||||
|
|
||||||
cfg_entry = cfg_mgr.data[cfg_entry_path[0]]
|
|
||||||
if len(cfg_entry_path) > 1:
|
|
||||||
for i in range(1, len(cfg_entry_path) - 1):
|
|
||||||
cfg_entry = cfg_entry[cfg_entry_path[i]]
|
|
||||||
if isinstance(cfg_entry[cfg_entry_path[-1]], type(cfg_value)):
|
|
||||||
cfg_entry[cfg_entry_path[-1]] = cfg_value
|
|
||||||
yield entities.CommandReturn(text="配置项{}修改成功".format(cfg_name))
|
|
||||||
else:
|
|
||||||
# reply = ["[bot]err:配置项{}类型不匹配".format(cfg_name)]
|
|
||||||
yield entities.CommandReturn(error=errors.CommandOperationError("配置项{}类型不匹配".format(cfg_name)))
|
|
||||||
else:
|
|
||||||
cfg_mgr.data[cfg_entry_path[0]] = cfg_value
|
|
||||||
# reply = ["[bot]配置项{}修改成功".format(cfg_name)]
|
|
||||||
yield entities.CommandReturn(text="配置项{}修改成功".format(cfg_name))
|
|
||||||
except KeyError:
|
|
||||||
# reply = ["[bot]err:未找到配置项 {}".format(cfg_name)]
|
|
||||||
yield entities.CommandReturn(error=errors.CommandOperationError("未找到配置项 {}".format(cfg_name)))
|
|
||||||
except NameError:
|
|
||||||
# reply = ["[bot]err:值{}不合法(字符串需要使用双引号包裹)".format(cfg_value)]
|
|
||||||
yield entities.CommandReturn(error=errors.CommandOperationError("值{}不合法(字符串需要使用双引号包裹)".format(cfg_value)))
|
|
||||||
except ValueError:
|
|
||||||
# reply = ["[bot]err:未找到配置项 {}".format(cfg_name)]
|
|
||||||
yield entities.CommandReturn(error=errors.CommandOperationError("未找到配置项 {}".format(cfg_name)))
|
|
||||||
@@ -16,7 +16,7 @@ class HelpOperator(operator.CommandOperator):
|
|||||||
self,
|
self,
|
||||||
context: entities.ExecuteContext
|
context: entities.ExecuteContext
|
||||||
) -> typing.AsyncGenerator[entities.CommandReturn, None]:
|
) -> typing.AsyncGenerator[entities.CommandReturn, None]:
|
||||||
help = self.ap.tips_mgr.data['help_message']
|
help = self.ap.system_cfg.data['help-message']
|
||||||
|
|
||||||
help += '\n发送命令 !cmd 可查看命令列表'
|
help += '\n发送命令 !cmd 可查看命令列表'
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,9 @@ from . import model as file_model
|
|||||||
from .impls import pymodule, json as json_file
|
from .impls import pymodule, json as json_file
|
||||||
|
|
||||||
|
|
||||||
|
managers: ConfigManager = []
|
||||||
|
|
||||||
|
|
||||||
class ConfigManager:
|
class ConfigManager:
|
||||||
"""配置文件管理器"""
|
"""配置文件管理器"""
|
||||||
|
|
||||||
|
|||||||
@@ -31,9 +31,15 @@ class Application:
|
|||||||
|
|
||||||
tool_mgr: llm_tool_mgr.ToolManager = None
|
tool_mgr: llm_tool_mgr.ToolManager = None
|
||||||
|
|
||||||
cfg_mgr: config_mgr.ConfigManager = None
|
command_cfg: config_mgr.ConfigManager = None
|
||||||
|
|
||||||
tips_mgr: config_mgr.ConfigManager = None
|
pipeline_cfg: config_mgr.ConfigManager = None
|
||||||
|
|
||||||
|
platform_cfg: config_mgr.ConfigManager = None
|
||||||
|
|
||||||
|
provider_cfg: config_mgr.ConfigManager = None
|
||||||
|
|
||||||
|
system_cfg: config_mgr.ConfigManager = None
|
||||||
|
|
||||||
ctr_mgr: center_mgr.V2CenterAPI = None
|
ctr_mgr: center_mgr.V2CenterAPI = None
|
||||||
|
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ async def make_app() -> app.Application:
|
|||||||
generated_files = await files.generate_files()
|
generated_files = await files.generate_files()
|
||||||
|
|
||||||
if generated_files:
|
if generated_files:
|
||||||
print("以下文件不存在,已自动生成,请修改配置文件后重启:")
|
print("以下文件不存在,已自动生成,请按需修改配置文件后重启:")
|
||||||
for file in generated_files:
|
for file in generated_files:
|
||||||
print("-", file)
|
print("-", file)
|
||||||
|
|
||||||
@@ -52,31 +52,23 @@ async def make_app() -> app.Application:
|
|||||||
# 生成标识符
|
# 生成标识符
|
||||||
identifier.init()
|
identifier.init()
|
||||||
|
|
||||||
cfg_mgr = await config.load_python_module_config("config.py", "config-template.py")
|
# ========== 加载配置文件 ==========
|
||||||
cfg = cfg_mgr.data
|
|
||||||
|
|
||||||
# 检查是否携带了 --override 或 -r 参数
|
command_cfg = await config.load_json_config("data/config/command.json", "templates/command.json")
|
||||||
if "--override" in sys.argv or "-r" in sys.argv:
|
pipeline_cfg = await config.load_json_config("data/config/pipeline.json", "templates/pipeline.json")
|
||||||
use_override = True
|
platform_cfg = await config.load_json_config("data/config/platform.json", "templates/platform.json")
|
||||||
|
provider_cfg = await config.load_json_config("data/config/provider.json", "templates/provider.json")
|
||||||
|
system_cfg = await config.load_json_config("data/config/system.json", "templates/system.json")
|
||||||
|
|
||||||
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_python_module_config(
|
|
||||||
"tips.py", "tips-custom-template.py"
|
|
||||||
)
|
|
||||||
|
|
||||||
# 检查管理员QQ号
|
|
||||||
if cfg_mgr.data["admin_qq"] == 0:
|
|
||||||
qcg_logger.warning("未设置管理员QQ号,将无法使用管理员命令,请在 config.py 中修改 admin_qq")
|
|
||||||
|
|
||||||
# 构建组建实例
|
|
||||||
ap = app.Application()
|
ap = app.Application()
|
||||||
ap.logger = qcg_logger
|
ap.logger = qcg_logger
|
||||||
ap.cfg_mgr = cfg_mgr
|
|
||||||
ap.tips_mgr = tips_mgr
|
ap.command_cfg = command_cfg
|
||||||
|
ap.pipeline_cfg = pipeline_cfg
|
||||||
|
ap.platform_cfg = platform_cfg
|
||||||
|
ap.provider_cfg = provider_cfg
|
||||||
|
ap.system_cfg = system_cfg
|
||||||
|
|
||||||
proxy_mgr = proxy.ProxyManager(ap)
|
proxy_mgr = proxy.ProxyManager(ap)
|
||||||
await proxy_mgr.initialize()
|
await proxy_mgr.initialize()
|
||||||
@@ -95,8 +87,8 @@ async def make_app() -> app.Application:
|
|||||||
"platform": sys.platform,
|
"platform": sys.platform,
|
||||||
},
|
},
|
||||||
runtime_info={
|
runtime_info={
|
||||||
"admin_id": "{}".format(cfg["admin_qq"]),
|
"admin_id": "{}".format(system_cfg.data["admin-sessions"]),
|
||||||
"msg_source": cfg["msg_source_adapter"],
|
"msg_source": platform_cfg.data["platform-adapter"],
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
ap.ctr_mgr = center_v2_api
|
ap.ctr_mgr = center_v2_api
|
||||||
|
|||||||
@@ -6,19 +6,25 @@ import sys
|
|||||||
|
|
||||||
|
|
||||||
required_files = {
|
required_files = {
|
||||||
"config.py": "config-template.py",
|
"plugins/__init__.py": "templates/__init__.py",
|
||||||
"banlist.py": "banlist-template.py",
|
"plugins/plugins.json": "templates/plugin-settings.json",
|
||||||
"tips.py": "tips-custom-template.py",
|
"data/config/command.json": "templates/command.json",
|
||||||
"sensitive.json": "res/templates/sensitive-template.json",
|
"data/config/pipeline.json": "templates/pipeline.json",
|
||||||
"scenario/default.json": "scenario/default-template.json",
|
"data/config/platform.json": "templates/platform.json",
|
||||||
"cmdpriv.json": "res/templates/cmdpriv-template.json",
|
"data/config/provider.json": "templates/provider.json",
|
||||||
|
"data/config/system.json": "templates/system.json",
|
||||||
|
"data/config/sensitive-words.json": "templates/sensitive-words.json",
|
||||||
|
"data/scenario/default.json": "templates/scenario-template.json",
|
||||||
}
|
}
|
||||||
|
|
||||||
required_paths = [
|
required_paths = [
|
||||||
"plugins",
|
|
||||||
"prompts",
|
|
||||||
"temp",
|
"temp",
|
||||||
"logs"
|
"data",
|
||||||
|
"data/prompts",
|
||||||
|
"data/scenario",
|
||||||
|
"data/logs",
|
||||||
|
"data/config",
|
||||||
|
"plugins"
|
||||||
]
|
]
|
||||||
|
|
||||||
async def generate_files() -> list[str]:
|
async def generate_files() -> list[str]:
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ async def init_logging() -> logging.Logger:
|
|||||||
if "DEBUG" in os.environ and os.environ["DEBUG"] in ["true", "1"]:
|
if "DEBUG" in os.environ and os.environ["DEBUG"] in ["true", "1"]:
|
||||||
level = logging.DEBUG
|
level = logging.DEBUG
|
||||||
|
|
||||||
log_file_name = "logs/qcg-%s.log" % time.strftime(
|
log_file_name = "data/logs/qcg-%s.log" % time.strftime(
|
||||||
"%Y-%m-%d-%H-%M-%S", time.localtime()
|
"%Y-%m-%d-%H-%M-%S", time.localtime()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -8,8 +8,6 @@ from . import app, entities
|
|||||||
from ..pipeline import entities as pipeline_entities
|
from ..pipeline import entities as pipeline_entities
|
||||||
from ..plugin import events
|
from ..plugin import events
|
||||||
|
|
||||||
DEFAULT_QUERY_CONCURRENCY = 10
|
|
||||||
|
|
||||||
|
|
||||||
class Controller:
|
class Controller:
|
||||||
"""总控制器
|
"""总控制器
|
||||||
@@ -21,7 +19,7 @@ class Controller:
|
|||||||
|
|
||||||
def __init__(self, ap: app.Application):
|
def __init__(self, ap: app.Application):
|
||||||
self.ap = ap
|
self.ap = ap
|
||||||
self.semaphore = asyncio.Semaphore(DEFAULT_QUERY_CONCURRENCY)
|
self.semaphore = asyncio.Semaphore(self.ap.system_cfg.data['pipeline-concurrency'])
|
||||||
|
|
||||||
async def consumer(self):
|
async def consumer(self):
|
||||||
"""事件处理循环
|
"""事件处理循环
|
||||||
@@ -150,9 +148,9 @@ class Controller:
|
|||||||
try:
|
try:
|
||||||
await self._execute_from_stage(0, query)
|
await self._execute_from_stage(0, query)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.ap.logger.error(f"处理请求时出错 {query}: {e}")
|
self.ap.logger.error(f"处理请求时出错 query_id={query.query_id}: {e}")
|
||||||
# self.ap.logger.debug(f"处理请求时出错 {query}: {e}", exc_info=True)
|
self.ap.logger.debug(f"Traceback: {traceback.format_exc()}")
|
||||||
traceback.print_exc()
|
# traceback.print_exc()
|
||||||
finally:
|
finally:
|
||||||
self.ap.logger.debug(f"Query {query} processed")
|
self.ap.logger.debug(f"Query {query} processed")
|
||||||
|
|
||||||
|
|||||||
@@ -23,54 +23,28 @@ class BanSessionCheckStage(stage.PipelineStage):
|
|||||||
stage_inst_name: str
|
stage_inst_name: str
|
||||||
) -> entities.StageProcessResult:
|
) -> entities.StageProcessResult:
|
||||||
|
|
||||||
if not self.banlist_mgr.data['enable']:
|
found = False
|
||||||
return entities.StageProcessResult(
|
|
||||||
result_type=entities.ResultType.CONTINUE,
|
mode = self.ap.pipeline_cfg.data['access-control']['mode']
|
||||||
new_query=query
|
|
||||||
)
|
sess_list = self.ap.pipeline_cfg.data['access-control'][mode]
|
||||||
|
|
||||||
|
if (query.launcher_type == 'group' and 'group_*' in sess_list) \
|
||||||
|
or (query.launcher_type == 'person' and 'person_*' in sess_list):
|
||||||
|
found = True
|
||||||
|
else:
|
||||||
|
for sess in sess_list:
|
||||||
|
if sess == f"{query.launcher_type}_{query.launcher_id}":
|
||||||
|
found = True
|
||||||
|
break
|
||||||
|
|
||||||
result = False
|
result = False
|
||||||
|
|
||||||
if query.launcher_type == 'group':
|
if mode == 'blacklist':
|
||||||
if not self.banlist_mgr.data['enable_group']: # 未启用群聊响应
|
result = found
|
||||||
result = True
|
|
||||||
# 检查是否显式声明发起人QQ要被person忽略
|
|
||||||
elif query.sender_id in self.banlist_mgr.data['person']:
|
|
||||||
result = True
|
|
||||||
else:
|
|
||||||
for group_rule in self.banlist_mgr.data['group']:
|
|
||||||
if type(group_rule) == int:
|
|
||||||
if group_rule == query.launcher_id:
|
|
||||||
result = True
|
|
||||||
elif type(group_rule) == str:
|
|
||||||
if group_rule.startswith('!'):
|
|
||||||
reg_str = group_rule[1:]
|
|
||||||
if re.match(reg_str, str(query.launcher_id)):
|
|
||||||
result = False
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
if re.match(group_rule, str(query.launcher_id)):
|
|
||||||
result = True
|
|
||||||
elif query.launcher_type == 'person':
|
|
||||||
if not self.banlist_mgr.data['enable_private']:
|
|
||||||
result = True
|
|
||||||
else:
|
|
||||||
for person_rule in self.banlist_mgr.data['person']:
|
|
||||||
if type(person_rule) == int:
|
|
||||||
if person_rule == query.launcher_id:
|
|
||||||
result = True
|
|
||||||
elif type(person_rule) == str:
|
|
||||||
if person_rule.startswith('!'):
|
|
||||||
reg_str = person_rule[1:]
|
|
||||||
if re.match(reg_str, str(query.launcher_id)):
|
|
||||||
result = False
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
if re.match(person_rule, str(query.launcher_id)):
|
|
||||||
result = True
|
|
||||||
|
|
||||||
return entities.StageProcessResult(
|
return entities.StageProcessResult(
|
||||||
result_type=entities.ResultType.CONTINUE if not result else entities.ResultType.INTERRUPT,
|
result_type=entities.ResultType.CONTINUE if not result else entities.ResultType.INTERRUPT,
|
||||||
new_query=query,
|
new_query=query,
|
||||||
debug_notice=f'根据禁用列表忽略消息: {query.launcher_type}_{query.launcher_id}' if result else ''
|
debug_notice=f'根据访问控制忽略消息: {query.launcher_type}_{query.launcher_id}' if result else ''
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -24,10 +24,10 @@ class ContentFilterStage(stage.PipelineStage):
|
|||||||
async def initialize(self):
|
async def initialize(self):
|
||||||
self.filter_chain.append(cntignore.ContentIgnore(self.ap))
|
self.filter_chain.append(cntignore.ContentIgnore(self.ap))
|
||||||
|
|
||||||
if self.ap.cfg_mgr.data['sensitive_word_filter']:
|
if self.ap.pipeline_cfg.data['check-sensitive-words']:
|
||||||
self.filter_chain.append(banwords.BanWordFilter(self.ap))
|
self.filter_chain.append(banwords.BanWordFilter(self.ap))
|
||||||
|
|
||||||
if self.ap.cfg_mgr.data['baidu_check']:
|
if self.ap.pipeline_cfg.data['baidu-cloud-examine']['enable']:
|
||||||
self.filter_chain.append(baiduexamine.BaiduCloudExamine(self.ap))
|
self.filter_chain.append(baiduexamine.BaiduCloudExamine(self.ap))
|
||||||
|
|
||||||
for filter in self.filter_chain:
|
for filter in self.filter_chain:
|
||||||
@@ -41,7 +41,7 @@ class ContentFilterStage(stage.PipelineStage):
|
|||||||
"""请求llm前处理消息
|
"""请求llm前处理消息
|
||||||
只要有一个不通过就不放行,只放行 PASS 的消息
|
只要有一个不通过就不放行,只放行 PASS 的消息
|
||||||
"""
|
"""
|
||||||
if not self.ap.cfg_mgr.data['income_msg_check']:
|
if not self.ap.pipeline_cfg.data['income-msg-check']:
|
||||||
return entities.StageProcessResult(
|
return entities.StageProcessResult(
|
||||||
result_type=entities.ResultType.CONTINUE,
|
result_type=entities.ResultType.CONTINUE,
|
||||||
new_query=query
|
new_query=query
|
||||||
|
|||||||
@@ -19,8 +19,8 @@ class BaiduCloudExamine(filter_model.ContentFilter):
|
|||||||
BAIDU_EXAMINE_TOKEN_URL,
|
BAIDU_EXAMINE_TOKEN_URL,
|
||||||
params={
|
params={
|
||||||
"grant_type": "client_credentials",
|
"grant_type": "client_credentials",
|
||||||
"client_id": self.ap.cfg_mgr.data['baidu_api_key'],
|
"client_id": self.ap.pipeline_cfg.data['baidu-cloud-examine']['api-key'],
|
||||||
"client_secret": self.ap.cfg_mgr.data['baidu_secret_key']
|
"client_secret": self.ap.pipeline_cfg.data['baidu-cloud-examine']['api-secret']
|
||||||
}
|
}
|
||||||
) as resp:
|
) as resp:
|
||||||
return (await resp.json())['access_token']
|
return (await resp.json())['access_token']
|
||||||
@@ -56,6 +56,6 @@ class BaiduCloudExamine(filter_model.ContentFilter):
|
|||||||
return entities.FilterResult(
|
return entities.FilterResult(
|
||||||
level=entities.ResultLevel.BLOCK,
|
level=entities.ResultLevel.BLOCK,
|
||||||
replacement=message,
|
replacement=message,
|
||||||
user_notice=self.ap.cfg_mgr.data['inappropriate_message_tips'],
|
user_notice="消息中存在不合适的内容, 请修改",
|
||||||
console_notice=f"百度云判定结果:{conclusion}"
|
console_notice=f"百度云判定结果:{conclusion}"
|
||||||
)
|
)
|
||||||
@@ -13,8 +13,8 @@ class BanWordFilter(filter_model.ContentFilter):
|
|||||||
|
|
||||||
async def initialize(self):
|
async def initialize(self):
|
||||||
self.sensitive = await cfg_mgr.load_json_config(
|
self.sensitive = await cfg_mgr.load_json_config(
|
||||||
"sensitive.json",
|
"data/config/sensitive-words.json",
|
||||||
"res/templates/sensitive-template.json"
|
"templates/sensitive-words.json"
|
||||||
)
|
)
|
||||||
|
|
||||||
async def process(self, message: str) -> entities.FilterResult:
|
async def process(self, message: str) -> entities.FilterResult:
|
||||||
@@ -39,6 +39,6 @@ class BanWordFilter(filter_model.ContentFilter):
|
|||||||
return entities.FilterResult(
|
return entities.FilterResult(
|
||||||
level=entities.ResultLevel.MASKED if found else entities.ResultLevel.PASS,
|
level=entities.ResultLevel.MASKED if found else entities.ResultLevel.PASS,
|
||||||
replacement=message,
|
replacement=message,
|
||||||
user_notice='[bot] 消息中存在不合适的内容, 请更换措辞' if found else '',
|
user_notice='消息中存在不合适的内容, 请修改' if found else '',
|
||||||
console_notice=''
|
console_notice=''
|
||||||
)
|
)
|
||||||
@@ -15,8 +15,8 @@ class ContentIgnore(filter_model.ContentFilter):
|
|||||||
]
|
]
|
||||||
|
|
||||||
async def process(self, message: str) -> entities.FilterResult:
|
async def process(self, message: str) -> entities.FilterResult:
|
||||||
if 'prefix' in self.ap.cfg_mgr.data['ignore_rules']:
|
if 'prefix' in self.ap.pipeline_cfg.data['ignore-rules']:
|
||||||
for rule in self.ap.cfg_mgr.data['ignore_rules']['prefix']:
|
for rule in self.ap.pipeline_cfg.data['ignore-rules']['prefix']:
|
||||||
if message.startswith(rule):
|
if message.startswith(rule):
|
||||||
return entities.FilterResult(
|
return entities.FilterResult(
|
||||||
level=entities.ResultLevel.BLOCK,
|
level=entities.ResultLevel.BLOCK,
|
||||||
@@ -25,8 +25,8 @@ class ContentIgnore(filter_model.ContentFilter):
|
|||||||
console_notice='根据 ignore_rules 中的 prefix 规则,忽略消息'
|
console_notice='根据 ignore_rules 中的 prefix 规则,忽略消息'
|
||||||
)
|
)
|
||||||
|
|
||||||
if 'regexp' in self.ap.cfg_mgr.data['ignore_rules']:
|
if 'regexp' in self.ap.pipeline_cfg.data['ignore-rules']:
|
||||||
for rule in self.ap.cfg_mgr.data['ignore_rules']['regexp']:
|
for rule in self.ap.pipeline_cfg.data['ignore-rules']['regexp']:
|
||||||
if re.search(rule, message):
|
if re.search(rule, message):
|
||||||
return entities.FilterResult(
|
return entities.FilterResult(
|
||||||
level=entities.ResultLevel.BLOCK,
|
level=entities.ResultLevel.BLOCK,
|
||||||
|
|||||||
@@ -19,9 +19,9 @@ class LongTextProcessStage(stage.PipelineStage):
|
|||||||
strategy_impl: strategy.LongTextStrategy
|
strategy_impl: strategy.LongTextStrategy
|
||||||
|
|
||||||
async def initialize(self):
|
async def initialize(self):
|
||||||
config = self.ap.cfg_mgr.data
|
config = self.ap.platform_cfg.data['long-text-process']
|
||||||
if self.ap.cfg_mgr.data['blob_message_strategy'] == 'image':
|
if config['strategy'] == 'image':
|
||||||
use_font = config['font_path']
|
use_font = config['font-path']
|
||||||
try:
|
try:
|
||||||
# 检查是否存在
|
# 检查是否存在
|
||||||
if not os.path.exists(use_font):
|
if not os.path.exists(use_font):
|
||||||
@@ -33,23 +33,25 @@ class LongTextProcessStage(stage.PipelineStage):
|
|||||||
config['blob_message_strategy'] = "forward"
|
config['blob_message_strategy'] = "forward"
|
||||||
else:
|
else:
|
||||||
self.ap.logger.info("使用Windows自带字体:" + use_font)
|
self.ap.logger.info("使用Windows自带字体:" + use_font)
|
||||||
self.ap.cfg_mgr.data['font_path'] = use_font
|
config['font-path'] = use_font
|
||||||
else:
|
else:
|
||||||
self.ap.logger.warn("未找到字体文件,且无法使用系统自带字体,更换为转发消息组件以发送长消息,您可以在config.py中调整相关设置。")
|
self.ap.logger.warn("未找到字体文件,且无法使用系统自带字体,更换为转发消息组件以发送长消息,您可以在config.py中调整相关设置。")
|
||||||
self.ap.cfg_mgr.data['blob_message_strategy'] = "forward"
|
|
||||||
|
self.ap.platform_cfg.data['long-text-process']['strategy'] = "forward"
|
||||||
except:
|
except:
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
self.ap.logger.error("加载字体文件失败({}),更换为转发消息组件以发送长消息,您可以在config.py中调整相关设置。".format(use_font))
|
self.ap.logger.error("加载字体文件失败({}),更换为转发消息组件以发送长消息,您可以在config.py中调整相关设置。".format(use_font))
|
||||||
self.ap.cfg_mgr.data['blob_message_strategy'] = "forward"
|
|
||||||
|
|
||||||
if self.ap.cfg_mgr.data['blob_message_strategy'] == 'image':
|
self.ap.platform_cfg.data['long-text-process']['strategy'] = "forward"
|
||||||
|
|
||||||
|
if config['strategy'] == 'image':
|
||||||
self.strategy_impl = image.Text2ImageStrategy(self.ap)
|
self.strategy_impl = image.Text2ImageStrategy(self.ap)
|
||||||
elif self.ap.cfg_mgr.data['blob_message_strategy'] == 'forward':
|
elif config['strategy'] == 'forward':
|
||||||
self.strategy_impl = forward.ForwardComponentStrategy(self.ap)
|
self.strategy_impl = forward.ForwardComponentStrategy(self.ap)
|
||||||
await self.strategy_impl.initialize()
|
await self.strategy_impl.initialize()
|
||||||
|
|
||||||
async def process(self, query: core_entities.Query, stage_inst_name: str) -> entities.StageProcessResult:
|
async def process(self, query: core_entities.Query, stage_inst_name: str) -> entities.StageProcessResult:
|
||||||
if len(str(query.resp_message_chain)) > self.ap.cfg_mgr.data['blob_message_threshold']:
|
if len(str(query.resp_message_chain)) > self.ap.platform_cfg.data['long-text-process']['threshold']:
|
||||||
query.resp_message_chain = MessageChain(await self.strategy_impl.process(str(query.resp_message_chain)))
|
query.resp_message_chain = MessageChain(await self.strategy_impl.process(str(query.resp_message_chain)))
|
||||||
return entities.StageProcessResult(
|
return entities.StageProcessResult(
|
||||||
result_type=entities.ResultType.CONTINUE,
|
result_type=entities.ResultType.CONTINUE,
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ class Text2ImageStrategy(strategy_model.LongTextStrategy):
|
|||||||
text_render_font: ImageFont.FreeTypeFont
|
text_render_font: ImageFont.FreeTypeFont
|
||||||
|
|
||||||
async def initialize(self):
|
async def initialize(self):
|
||||||
self.text_render_font = ImageFont.truetype(self.ap.cfg_mgr.data['font_path'], 32, encoding="utf-8")
|
self.text_render_font = ImageFont.truetype(self.ap.platform_cfg.data['long-text-process']['font-path'], 32, encoding="utf-8")
|
||||||
|
|
||||||
async def process(self, message: str) -> list[MessageComponent]:
|
async def process(self, message: str) -> list[MessageComponent]:
|
||||||
img_path = self.text_to_image(
|
img_path = self.text_to_image(
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ class PreProcessor(stage.PipelineStage):
|
|||||||
query.messages = event_ctx.event.prompt
|
query.messages = event_ctx.event.prompt
|
||||||
|
|
||||||
# 根据模型max_tokens剪裁
|
# 根据模型max_tokens剪裁
|
||||||
max_tokens = min(query.use_model.max_tokens, self.ap.cfg_mgr.data['prompt_submit_length'])
|
max_tokens = min(query.use_model.max_tokens, self.ap.pipeline_cfg.data['submit-messages-tokens'])
|
||||||
|
|
||||||
test_messages = query.prompt.messages + query.messages + [query.user_message]
|
test_messages = query.prompt.messages + query.messages + [query.user_message]
|
||||||
|
|
||||||
@@ -63,7 +63,7 @@ class PreProcessor(stage.PipelineStage):
|
|||||||
result_type=entities.ResultType.INTERRUPT,
|
result_type=entities.ResultType.INTERRUPT,
|
||||||
new_query=query,
|
new_query=query,
|
||||||
user_notice='输入内容过长,请减少情景预设或者输入内容长度',
|
user_notice='输入内容过长,请减少情景预设或者输入内容长度',
|
||||||
console_notice='输入内容过长,请减少情景预设或者输入内容长度,或者增大配置文件中的 prompt_submit_length 项(但不能超过所用模型最大tokens数)'
|
console_notice='输入内容过长,请减少情景预设或者输入内容长度,或者增大配置文件中的 submit-messages-tokens 项(但不能超过所用模型最大tokens数)'
|
||||||
)
|
)
|
||||||
|
|
||||||
query.messages.pop(0) # pop第一个肯定是role=user的
|
query.messages.pop(0) # pop第一个肯定是role=user的
|
||||||
|
|||||||
@@ -54,6 +54,12 @@ class ChatMessageHandler(handler.MessageHandler):
|
|||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
|
|
||||||
|
if not self.ap.provider_cfg.data['enable-chat']:
|
||||||
|
yield entities.StageProcessResult(
|
||||||
|
result_type=entities.ResultType.INTERRUPT,
|
||||||
|
new_query=query,
|
||||||
|
)
|
||||||
|
|
||||||
if event_ctx.event.alter is not None:
|
if event_ctx.event.alter is not None:
|
||||||
query.message_chain = mirai.MessageChain([
|
query.message_chain = mirai.MessageChain([
|
||||||
mirai.Plain(event_ctx.event.alter)
|
mirai.Plain(event_ctx.event.alter)
|
||||||
@@ -83,7 +89,7 @@ class ChatMessageHandler(handler.MessageHandler):
|
|||||||
yield entities.StageProcessResult(
|
yield entities.StageProcessResult(
|
||||||
result_type=entities.ResultType.INTERRUPT,
|
result_type=entities.ResultType.INTERRUPT,
|
||||||
new_query=query,
|
new_query=query,
|
||||||
user_notice=self.ap.tips_mgr.data['alter_tip_message'] if self.ap.cfg_mgr.data['hide_exce_info_to_user'] else f'{e}',
|
user_notice='请求失败' if self.ap.platform_cfg.data['hide-exception-info'] else f'{e}',
|
||||||
error_notice=f'{e}',
|
error_notice=f'{e}',
|
||||||
debug_notice=traceback.format_exc()
|
debug_notice=traceback.format_exc()
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -23,8 +23,8 @@ class CommandHandler(handler.MessageHandler):
|
|||||||
|
|
||||||
|
|
||||||
privilege = 1
|
privilege = 1
|
||||||
if query.sender_id == self.ap.cfg_mgr.data['admin_qq'] \
|
|
||||||
or query.sender_id in self.ap.cfg_mgr['admin_qq']:
|
if f'{query.launcher_type.value}_{query.launcher_id}' in self.ap.system_cfg.data['admin-sessions']:
|
||||||
privilege = 2
|
privilege = 2
|
||||||
|
|
||||||
spt = str(query.message_chain).strip().split(' ')
|
spt = str(query.message_chain).strip().split(' ')
|
||||||
|
|||||||
@@ -55,16 +55,16 @@ class FixedWindowAlgo(algo.ReteLimitAlgo):
|
|||||||
# 获取当前分钟的访问次数
|
# 获取当前分钟的访问次数
|
||||||
count = container.records.get(now, 0)
|
count = container.records.get(now, 0)
|
||||||
|
|
||||||
limitation = self.ap.cfg_mgr.data['rate_limitation']['default']
|
limitation = self.ap.pipeline_cfg.data['rate-limit']['fixwin']['default']
|
||||||
|
|
||||||
if session_name in self.ap.cfg_mgr.data['rate_limitation']:
|
if session_name in self.ap.pipeline_cfg.data['rate-limit']['fixwin']:
|
||||||
limitation = self.ap.cfg_mgr.data['rate_limitation'][session_name]
|
limitation = self.ap.pipeline_cfg.data['rate-limit']['fixwin'][session_name]
|
||||||
|
|
||||||
# 如果访问次数超过了限制
|
# 如果访问次数超过了限制
|
||||||
if count >= limitation:
|
if count >= limitation:
|
||||||
if self.ap.cfg_mgr.data['rate_limit_strategy'] == 'drop':
|
if self.ap.pipeline_cfg.data['rate-limit']['strategy'] == 'drop':
|
||||||
return False
|
return False
|
||||||
elif self.ap.cfg_mgr.data['rate_limit_strategy'] == 'wait':
|
elif self.ap.pipeline_cfg.data['rate-limit']['strategy'] == 'wait':
|
||||||
# 等待下一分钟
|
# 等待下一分钟
|
||||||
await asyncio.sleep(60 - time.time() % 60)
|
await asyncio.sleep(60 - time.time() % 60)
|
||||||
|
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ class RateLimit(stage.PipelineStage):
|
|||||||
result_type=entities.ResultType.INTERRUPT,
|
result_type=entities.ResultType.INTERRUPT,
|
||||||
new_query=query,
|
new_query=query,
|
||||||
console_notice=f"根据限速规则忽略 {query.launcher_type.value}:{query.launcher_id} 消息",
|
console_notice=f"根据限速规则忽略 {query.launcher_type.value}:{query.launcher_id} 消息",
|
||||||
user_notice=self.ap.tips_mgr.data['rate_limit_drop_tip']
|
user_notice=f"请求数超过限速器设定值,已丢弃本消息。"
|
||||||
)
|
)
|
||||||
elif stage_inst_name == "ReleaseRateLimitOccupancy":
|
elif stage_inst_name == "ReleaseRateLimitOccupancy":
|
||||||
await self.algo.release_access(
|
await self.algo.release_access(
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ class SendResponseBackStage(stage.PipelineStage):
|
|||||||
async def process(self, query: core_entities.Query, stage_inst_name: str) -> entities.StageProcessResult:
|
async def process(self, query: core_entities.Query, stage_inst_name: str) -> entities.StageProcessResult:
|
||||||
"""处理
|
"""处理
|
||||||
"""
|
"""
|
||||||
random_delay = random.uniform(*self.ap.cfg_mgr.data['force_delay_range'])
|
random_delay = random.uniform(*self.ap.platform_cfg.data['force-delay'])
|
||||||
|
|
||||||
self.ap.logger.debug(
|
self.ap.logger.debug(
|
||||||
"根据规则强制延迟回复: %s s",
|
"根据规则强制延迟回复: %s s",
|
||||||
|
|||||||
@@ -33,13 +33,13 @@ class GroupRespondRuleCheckStage(stage.PipelineStage):
|
|||||||
|
|
||||||
async def process(self, query: core_entities.Query, stage_inst_name: str) -> entities.StageProcessResult:
|
async def process(self, query: core_entities.Query, stage_inst_name: str) -> entities.StageProcessResult:
|
||||||
|
|
||||||
if query.launcher_type != 'group':
|
if query.launcher_type.value != 'group':
|
||||||
return entities.StageProcessResult(
|
return entities.StageProcessResult(
|
||||||
result_type=entities.ResultType.CONTINUE,
|
result_type=entities.ResultType.CONTINUE,
|
||||||
new_query=query
|
new_query=query
|
||||||
)
|
)
|
||||||
|
|
||||||
rules = self.ap.cfg_mgr.data['response_rules']
|
rules = self.ap.pipeline_cfg.data['respond-rules']
|
||||||
|
|
||||||
use_rule = rules['default']
|
use_rule = rules['default']
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ class PrefixRule(rule_model.GroupRespondRule):
|
|||||||
|
|
||||||
for prefix in prefixes:
|
for prefix in prefixes:
|
||||||
if message_text.startswith(prefix):
|
if message_text.startswith(prefix):
|
||||||
|
|
||||||
return entities.RuleJudgeResult(
|
return entities.RuleJudgeResult(
|
||||||
matching=True,
|
matching=True,
|
||||||
replacement=mirai.MessageChain([
|
replacement=mirai.MessageChain([
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ class RandomRespRule(rule_model.GroupRespondRule):
|
|||||||
message_chain: mirai.MessageChain,
|
message_chain: mirai.MessageChain,
|
||||||
rule_dict: dict
|
rule_dict: dict
|
||||||
) -> entities.RuleJudgeResult:
|
) -> entities.RuleJudgeResult:
|
||||||
random_rate = rule_dict['random_rate']
|
random_rate = rule_dict['random']
|
||||||
|
|
||||||
return entities.RuleJudgeResult(
|
return entities.RuleJudgeResult(
|
||||||
matching=random.random() < random_rate,
|
matching=random.random() < random_rate,
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ class ResponseWrapper(stage.PipelineStage):
|
|||||||
|
|
||||||
query.resp_message_chain = mirai.MessageChain([mirai.Plain(reply_text)])
|
query.resp_message_chain = mirai.MessageChain([mirai.Plain(reply_text)])
|
||||||
|
|
||||||
if self.ap.cfg_mgr.data['trace_function_calls']:
|
if self.ap.platform_cfg.data['track-function-calls']:
|
||||||
|
|
||||||
event_ctx = await self.ap.plugin_mgr.emit_event(
|
event_ctx = await self.ap.plugin_mgr.emit_event(
|
||||||
event=events.NormalMessageResponded(
|
event=events.NormalMessageResponded(
|
||||||
|
|||||||
@@ -31,19 +31,16 @@ class PlatformManager:
|
|||||||
|
|
||||||
async def initialize(self):
|
async def initialize(self):
|
||||||
|
|
||||||
config = self.ap.cfg_mgr.data
|
if self.ap.platform_cfg.data['platform-adapter'] == 'yiri-mirai':
|
||||||
|
|
||||||
logging.debug("Use adapter:" + config['msg_source_adapter'])
|
|
||||||
if config['msg_source_adapter'] == 'yirimirai':
|
|
||||||
from pkg.platform.sources.yirimirai import YiriMiraiAdapter
|
from pkg.platform.sources.yirimirai import YiriMiraiAdapter
|
||||||
|
|
||||||
mirai_http_api_config = config['mirai_http_api_config']
|
mirai_http_api_config = self.ap.platform_cfg.data['yiri-mirai-config']
|
||||||
self.bot_account_id = config['mirai_http_api_config']['qq']
|
self.bot_account_id = mirai_http_api_config['qq']
|
||||||
self.adapter = YiriMiraiAdapter(mirai_http_api_config)
|
self.adapter = YiriMiraiAdapter(mirai_http_api_config)
|
||||||
elif config['msg_source_adapter'] == 'nakuru':
|
# elif config['msg_source_adapter'] == 'nakuru':
|
||||||
from pkg.platform.sources.nakuru import NakuruProjectAdapter
|
# from pkg.platform.sources.nakuru import NakuruProjectAdapter
|
||||||
self.adapter = NakuruProjectAdapter(config['nakuru_config'])
|
# self.adapter = NakuruProjectAdapter(config['nakuru_config'])
|
||||||
self.bot_account_id = self.adapter.bot_account_id
|
# self.bot_account_id = self.adapter.bot_account_id
|
||||||
|
|
||||||
# 保存 account_id 到审计模块
|
# 保存 account_id 到审计模块
|
||||||
from ..audit.center import apigroup
|
from ..audit.center import apigroup
|
||||||
@@ -99,7 +96,7 @@ class PlatformManager:
|
|||||||
)
|
)
|
||||||
|
|
||||||
# nakuru不区分好友和陌生人,故仅为yirimirai注册陌生人事件
|
# nakuru不区分好友和陌生人,故仅为yirimirai注册陌生人事件
|
||||||
if config['msg_source_adapter'] == 'yirimirai':
|
if self.ap.platform_cfg.data['platform-adapter'] == 'yiri-mirai':
|
||||||
self.adapter.register_listener(
|
self.adapter.register_listener(
|
||||||
StrangerMessage,
|
StrangerMessage,
|
||||||
on_stranger_message
|
on_stranger_message
|
||||||
@@ -133,27 +130,26 @@ class PlatformManager:
|
|||||||
)
|
)
|
||||||
|
|
||||||
async def send(self, event, msg, check_quote=True, check_at_sender=True):
|
async def send(self, event, msg, check_quote=True, check_at_sender=True):
|
||||||
config = self.ap.cfg_mgr.data
|
|
||||||
|
|
||||||
if check_at_sender and config['at_sender']:
|
if check_at_sender and self.ap.platform_cfg.data['at-sender']:
|
||||||
msg.insert(
|
msg.insert(
|
||||||
0,
|
0,
|
||||||
Plain(" \n")
|
Plain(" \n")
|
||||||
)
|
)
|
||||||
|
|
||||||
# 当回复的正文中包含换行时,quote可能会自带at,此时就不再单独添加at,只添加换行
|
# 当回复的正文中包含换行时,quote可能会自带at,此时就不再单独添加at,只添加换行
|
||||||
if "\n" not in str(msg[1]) or config['msg_source_adapter'] == 'nakuru':
|
# if "\n" not in str(msg[1]) or self.ap.platform_cfg.data['platform-adapter'] == 'nakuru':
|
||||||
msg.insert(
|
msg.insert(
|
||||||
0,
|
0,
|
||||||
At(
|
At(
|
||||||
event.sender.id
|
event.sender.id
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
)
|
||||||
|
|
||||||
await self.adapter.reply_message(
|
await self.adapter.reply_message(
|
||||||
event,
|
event,
|
||||||
msg,
|
msg,
|
||||||
quote_origin=True if config['quote_origin'] and check_quote else False
|
quote_origin=True if self.ap.platform_cfg.data['quote-origin'] and check_quote else False
|
||||||
)
|
)
|
||||||
|
|
||||||
# 通知系统管理员
|
# 通知系统管理员
|
||||||
@@ -161,19 +157,16 @@ class PlatformManager:
|
|||||||
await self.notify_admin_message_chain(MessageChain([Plain("[bot]{}".format(message))]))
|
await self.notify_admin_message_chain(MessageChain([Plain("[bot]{}".format(message))]))
|
||||||
|
|
||||||
async def notify_admin_message_chain(self, message: mirai.MessageChain):
|
async def notify_admin_message_chain(self, message: mirai.MessageChain):
|
||||||
config = self.ap.cfg_mgr.data
|
if self.ap.system_cfg.data['admin-sessions'] != []:
|
||||||
if config['admin_qq'] != 0 and config['admin_qq'] != []:
|
|
||||||
logging.info("通知管理员:{}".format(message))
|
|
||||||
|
|
||||||
admin_list = []
|
admin_list = []
|
||||||
|
for admin in self.ap.system_cfg.data['admin-sessions']:
|
||||||
if type(config['admin_qq']) == int:
|
admin_list.append(admin)
|
||||||
admin_list.append(config['admin_qq'])
|
|
||||||
|
|
||||||
for adm in admin_list:
|
for adm in admin_list:
|
||||||
self.adapter.send_message(
|
self.adapter.send_message(
|
||||||
"person",
|
adm.split("_")[0],
|
||||||
adm,
|
adm.split("_")[1],
|
||||||
message
|
message
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -22,8 +22,8 @@ class OpenAIChatCompletion(api.LLMAPIRequester):
|
|||||||
async def initialize(self):
|
async def initialize(self):
|
||||||
self.client = openai.AsyncClient(
|
self.client = openai.AsyncClient(
|
||||||
api_key="",
|
api_key="",
|
||||||
base_url=self.ap.cfg_mgr.data["openai_config"]["reverse_proxy"],
|
base_url=self.ap.provider_cfg.data['openai-config']['base_url'],
|
||||||
timeout=self.ap.cfg_mgr.data["process_message_timeout"],
|
timeout=self.ap.provider_cfg.data['openai-config']['request-timeout'],
|
||||||
)
|
)
|
||||||
|
|
||||||
async def _req(
|
async def _req(
|
||||||
@@ -51,7 +51,7 @@ class OpenAIChatCompletion(api.LLMAPIRequester):
|
|||||||
) -> llm_entities.Message:
|
) -> llm_entities.Message:
|
||||||
self.client.api_key = use_model.token_mgr.get_token()
|
self.client.api_key = use_model.token_mgr.get_token()
|
||||||
|
|
||||||
args = self.ap.cfg_mgr.data["completion_api_params"].copy()
|
args = self.ap.provider_cfg.data['openai-config']['chat-completions-params'].copy()
|
||||||
args["model"] = use_model.name if use_model.model_name is None else use_model.model_name
|
args["model"] = use_model.name if use_model.model_name is None else use_model.model_name
|
||||||
|
|
||||||
if use_model.tool_call_supported:
|
if use_model.tool_call_supported:
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ class ModelManager:
|
|||||||
async def initialize(self):
|
async def initialize(self):
|
||||||
openai_chat_completion = chatcmpl.OpenAIChatCompletion(self.ap)
|
openai_chat_completion = chatcmpl.OpenAIChatCompletion(self.ap)
|
||||||
await openai_chat_completion.initialize()
|
await openai_chat_completion.initialize()
|
||||||
openai_token_mgr = token.TokenManager(self.ap, list(self.ap.cfg_mgr.data['openai_config']['api_key'].values()))
|
openai_token_mgr = token.TokenManager(self.ap, list(self.ap.provider_cfg.data['openai-config']['api-keys']))
|
||||||
|
|
||||||
tiktoken_tokenizer = tiktoken.Tiktoken(self.ap)
|
tiktoken_tokenizer = tiktoken.Tiktoken(self.ap)
|
||||||
|
|
||||||
|
|||||||
@@ -25,10 +25,15 @@ class SessionManager:
|
|||||||
if query.launcher_type == session.launcher_type and query.launcher_id == session.launcher_id:
|
if query.launcher_type == session.launcher_type and query.launcher_id == session.launcher_id:
|
||||||
return session
|
return session
|
||||||
|
|
||||||
|
session_concurrency = self.ap.system_cfg.data['session-concurrency']['default']
|
||||||
|
|
||||||
|
if f'{query.launcher_type.value}_{query.launcher_id}' in self.ap.system_cfg.data['session-concurrency']:
|
||||||
|
session_concurrency = self.ap.system_cfg.data['session-concurrency'][f'{query.launcher_type.value}_{query.launcher_id}']
|
||||||
|
|
||||||
session = core_entities.Session(
|
session = core_entities.Session(
|
||||||
launcher_type=query.launcher_type,
|
launcher_type=query.launcher_type,
|
||||||
launcher_id=query.launcher_id,
|
launcher_id=query.launcher_id,
|
||||||
semaphore=asyncio.Semaphore(1) if self.ap.cfg_mgr.data['wait_last_done'] else asyncio.Semaphore(10000),
|
semaphore=asyncio.Semaphore(session_concurrency),
|
||||||
)
|
)
|
||||||
self.session_list.append(session)
|
self.session_list.append(session)
|
||||||
return session
|
return session
|
||||||
@@ -41,7 +46,7 @@ class SessionManager:
|
|||||||
conversation = core_entities.Conversation(
|
conversation = core_entities.Conversation(
|
||||||
prompt=await self.ap.prompt_mgr.get_prompt(session.use_prompt_name),
|
prompt=await self.ap.prompt_mgr.get_prompt(session.use_prompt_name),
|
||||||
messages=[],
|
messages=[],
|
||||||
use_model=await self.ap.model_mgr.get_model_by_name(self.ap.cfg_mgr.data['completion_api_params']['model']),
|
use_model=await self.ap.model_mgr.get_model_by_name(self.ap.provider_cfg.data['openai-config']['chat-completions-params']['model']),
|
||||||
use_funcs=await self.ap.tool_mgr.get_all_functions(),
|
use_funcs=await self.ap.tool_mgr.get_all_functions(),
|
||||||
)
|
)
|
||||||
session.conversations.append(conversation)
|
session.conversations.append(conversation)
|
||||||
|
|||||||
@@ -14,8 +14,8 @@ class ScenarioPromptLoader(loader.PromptLoader):
|
|||||||
async def load(self):
|
async def load(self):
|
||||||
"""加载Prompt
|
"""加载Prompt
|
||||||
"""
|
"""
|
||||||
for file in os.listdir("scenarios"):
|
for file in os.listdir("data/scenarios"):
|
||||||
with open("scenarios/{}".format(file), "r", encoding="utf-8") as f:
|
with open("data/scenarios/{}".format(file), "r", encoding="utf-8") as f:
|
||||||
file_str = f.read()
|
file_str = f.read()
|
||||||
file_name = file.split(".")[0]
|
file_name = file.split(".")[0]
|
||||||
file_json = json.loads(file_str)
|
file_json = json.loads(file_str)
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ class SingleSystemPromptLoader(loader.PromptLoader):
|
|||||||
"""加载Prompt
|
"""加载Prompt
|
||||||
"""
|
"""
|
||||||
|
|
||||||
for name, cnt in self.ap.cfg_mgr.data['default_prompt'].items():
|
for name, cnt in self.ap.provider_cfg.data['prompt'].items():
|
||||||
prompt = entities.Prompt(
|
prompt = entities.Prompt(
|
||||||
name=name,
|
name=name,
|
||||||
messages=[
|
messages=[
|
||||||
@@ -26,8 +26,8 @@ class SingleSystemPromptLoader(loader.PromptLoader):
|
|||||||
)
|
)
|
||||||
self.prompts.append(prompt)
|
self.prompts.append(prompt)
|
||||||
|
|
||||||
for file in os.listdir("prompts"):
|
for file in os.listdir("data/prompts"):
|
||||||
with open("prompts/{}".format(file), "r", encoding="utf-8") as f:
|
with open("data/prompts/{}".format(file), "r", encoding="utf-8") as f:
|
||||||
file_str = f.read()
|
file_str = f.read()
|
||||||
file_name = file.split(".")[0]
|
file_name = file.split(".")[0]
|
||||||
prompt = entities.Prompt(
|
prompt = entities.Prompt(
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ class PromptManager:
|
|||||||
"full_scenario": scenario.ScenarioPromptLoader
|
"full_scenario": scenario.ScenarioPromptLoader
|
||||||
}
|
}
|
||||||
|
|
||||||
loader_cls = loader_map[self.ap.cfg_mgr.data['preset_mode']]
|
loader_cls = loader_map[self.ap.provider_cfg.data['prompt-mode']]
|
||||||
|
|
||||||
self.loader_inst: loader.PromptLoader = loader_cls(self.ap)
|
self.loader_inst: loader.PromptLoader = loader_cls(self.ap)
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
from ..core import app
|
from ..core import app
|
||||||
|
|
||||||
|
|
||||||
@@ -14,17 +17,15 @@ class ProxyManager:
|
|||||||
self.forward_proxies = {}
|
self.forward_proxies = {}
|
||||||
|
|
||||||
async def initialize(self):
|
async def initialize(self):
|
||||||
config = self.ap.cfg_mgr.data
|
self.forward_proxies = {
|
||||||
|
"http": os.getenv("HTTP_PROXY") or os.getenv("http_proxy"),
|
||||||
|
"https": os.getenv("HTTPS_PROXY") or os.getenv("https_proxy"),
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
if 'http' in self.ap.system_cfg.data['network-proxies']:
|
||||||
{
|
self.forward_proxies['http'] = self.ap.system_cfg.data['network-proxies']['http']
|
||||||
"http": config["openai_config"]["proxy"],
|
if 'https' in self.ap.system_cfg.data['network-proxies']:
|
||||||
"https": config["openai_config"]["proxy"],
|
self.forward_proxies['https'] = self.ap.system_cfg.data['network-proxies']['https']
|
||||||
}
|
|
||||||
if "proxy" in config["openai_config"]
|
|
||||||
and (config["openai_config"]["proxy"] is not None)
|
|
||||||
else None
|
|
||||||
)
|
|
||||||
|
|
||||||
def get_forward_proxies(self) -> str:
|
def get_forward_proxies(self) -> dict:
|
||||||
return self.forward_proxies
|
return self.forward_proxies
|
||||||
|
|||||||
0
templates/__init__.py
Normal file
0
templates/__init__.py
Normal file
3
templates/command.json
Normal file
3
templates/command.json
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"privilege": {}
|
||||||
|
}
|
||||||
36
templates/pipeline.json
Normal file
36
templates/pipeline.json
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
{
|
||||||
|
"access-control":{
|
||||||
|
"mode": "blacklist",
|
||||||
|
"blacklist": [],
|
||||||
|
"whitelist": []
|
||||||
|
},
|
||||||
|
"respond-rules": {
|
||||||
|
"default": {
|
||||||
|
"at": true,
|
||||||
|
"prefix": [
|
||||||
|
"/ai", "!ai", "!ai", "ai"
|
||||||
|
],
|
||||||
|
"regexp": [],
|
||||||
|
"random": 0.0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"income-msg-check": true,
|
||||||
|
"ignore-rules": {
|
||||||
|
"prefix": ["/"],
|
||||||
|
"regexp": []
|
||||||
|
},
|
||||||
|
"check-sensitive-words": true,
|
||||||
|
"baidu-cloud-examine": {
|
||||||
|
"enable": false,
|
||||||
|
"api-key": "",
|
||||||
|
"api-secret": ""
|
||||||
|
},
|
||||||
|
"submit-messages-tokens": 3072,
|
||||||
|
"rate-limit": {
|
||||||
|
"strategy": "drop",
|
||||||
|
"algo": "fixwin",
|
||||||
|
"fixwin": {
|
||||||
|
"default": 60
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
20
templates/platform.json
Normal file
20
templates/platform.json
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"platform-adapter": "yiri-mirai",
|
||||||
|
"yiri-mirai-config": {
|
||||||
|
"adapter": "WebSocketAdapter",
|
||||||
|
"host": "localhost",
|
||||||
|
"port": 8080,
|
||||||
|
"verifyKey": "yirimirai",
|
||||||
|
"qq": 123456789
|
||||||
|
},
|
||||||
|
"track-function-calls": true,
|
||||||
|
"quote-origin": false,
|
||||||
|
"at-sender": false,
|
||||||
|
"force-delay": [0, 0],
|
||||||
|
"long-text-process": {
|
||||||
|
"threshold": 256,
|
||||||
|
"strategy": "forward",
|
||||||
|
"font-path": ""
|
||||||
|
},
|
||||||
|
"hide-exception-info": true
|
||||||
|
}
|
||||||
3
templates/plugin-settings.json
Normal file
3
templates/plugin-settings.json
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"plugins": []
|
||||||
|
}
|
||||||
17
templates/provider.json
Normal file
17
templates/provider.json
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"enable-chat": true,
|
||||||
|
"openai-config": {
|
||||||
|
"api-keys": [
|
||||||
|
"sk-1234567890"
|
||||||
|
],
|
||||||
|
"base_url": "https://api.openai.com/v1",
|
||||||
|
"chat-completions-params": {
|
||||||
|
"model": "gpt-3.5-turbo"
|
||||||
|
},
|
||||||
|
"request-timeout": 120
|
||||||
|
},
|
||||||
|
"prompt-mode": "normal",
|
||||||
|
"prompt": {
|
||||||
|
"default": "如果用户之后想获取帮助,请你说”输入!help获取帮助“。"
|
||||||
|
}
|
||||||
|
}
|
||||||
12
templates/scenario-template.json
Normal file
12
templates/scenario-template.json
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"prompt": [
|
||||||
|
{
|
||||||
|
"role": "system",
|
||||||
|
"content": "You are a helpful assistant. 如果我需要帮助,你要说“输入!help获得帮助”"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "assistant",
|
||||||
|
"content": "好的,我是一个能干的AI助手。 如果你需要帮助,我会说“输入!help获得帮助”"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
78
templates/sensitive-words.json
Normal file
78
templates/sensitive-words.json
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
{
|
||||||
|
"说明": "mask将替换敏感词中的每一个字,若mask_word值不为空,则将敏感词整个替换为mask_word的值",
|
||||||
|
"mask": "*",
|
||||||
|
"mask_word": "",
|
||||||
|
"words": [
|
||||||
|
"习近平",
|
||||||
|
"胡锦涛",
|
||||||
|
"江泽民",
|
||||||
|
"温家宝",
|
||||||
|
"李克强",
|
||||||
|
"李长春",
|
||||||
|
"毛泽东",
|
||||||
|
"邓小平",
|
||||||
|
"周恩来",
|
||||||
|
"马克思",
|
||||||
|
"社会主义",
|
||||||
|
"共产党",
|
||||||
|
"共产主义",
|
||||||
|
"大陆官方",
|
||||||
|
"北京政权",
|
||||||
|
"中华帝国",
|
||||||
|
"中国政府",
|
||||||
|
"共狗",
|
||||||
|
"六四事件",
|
||||||
|
"天安门",
|
||||||
|
"六四",
|
||||||
|
"政治局常委",
|
||||||
|
"两会",
|
||||||
|
"共青团",
|
||||||
|
"学潮",
|
||||||
|
"八九",
|
||||||
|
"二十大",
|
||||||
|
"民进党",
|
||||||
|
"台独",
|
||||||
|
"台湾独立",
|
||||||
|
"台湾国",
|
||||||
|
"国民党",
|
||||||
|
"台湾民国",
|
||||||
|
"中华民国",
|
||||||
|
"pornhub",
|
||||||
|
"Pornhub",
|
||||||
|
"[Yy]ou[Pp]orn",
|
||||||
|
"porn",
|
||||||
|
"Porn",
|
||||||
|
"[Xx][Vv]ideos",
|
||||||
|
"[Rr]ed[Tt]ube",
|
||||||
|
"[Xx][Hh]amster",
|
||||||
|
"[Ss]pank[Ww]ire",
|
||||||
|
"[Ss]pank[Bb]ang",
|
||||||
|
"[Tt]ube8",
|
||||||
|
"[Yy]ou[Jj]izz",
|
||||||
|
"[Bb]razzers",
|
||||||
|
"[Nn]aughty[ ]?[Aa]merica",
|
||||||
|
"作爱",
|
||||||
|
"做爱",
|
||||||
|
"性交",
|
||||||
|
"性爱",
|
||||||
|
"自慰",
|
||||||
|
"阴茎",
|
||||||
|
"淫妇",
|
||||||
|
"肛交",
|
||||||
|
"交配",
|
||||||
|
"性关系",
|
||||||
|
"性活动",
|
||||||
|
"色情",
|
||||||
|
"色图",
|
||||||
|
"涩图",
|
||||||
|
"裸体",
|
||||||
|
"小穴",
|
||||||
|
"淫荡",
|
||||||
|
"性爱",
|
||||||
|
"翻墙",
|
||||||
|
"VPN",
|
||||||
|
"科学上网",
|
||||||
|
"挂梯子",
|
||||||
|
"GFW"
|
||||||
|
]
|
||||||
|
}
|
||||||
11
templates/system.json
Normal file
11
templates/system.json
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"admin-sessions": [],
|
||||||
|
"network-proxies": {},
|
||||||
|
"report-usage": true,
|
||||||
|
"logging-level": "info",
|
||||||
|
"session-concurrency": {
|
||||||
|
"default": 1
|
||||||
|
},
|
||||||
|
"pipeline-concurrency": 20,
|
||||||
|
"help-message": "QChatGPT - 😎高稳定性、🧩支持插件、🌏实时联网的 ChatGPT QQ 机器人🤖\n链接:https://q.rkcn.top"
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user