diff --git a/.github/workflows/update-override-all.yml b/.github/workflows/update-override-all.yml deleted file mode 100644 index 83ef6a6b..00000000 --- a/.github/workflows/update-override-all.yml +++ /dev/null @@ -1,52 +0,0 @@ -name: Check and Update override_all - -on: - push: - paths: - - 'config-template.py' - pull_request: - types: - - closed - branches: - - master - paths: - - 'config-template.py' - -jobs: - update-override-all: - name: check and update - if: github.event.pull_request.merged == true || github.event_name == 'push' - runs-on: ubuntu-latest - steps: - - name: Checkout repository - uses: actions/checkout@v2 - - - name: Set up Python - uses: actions/setup-python@v2 - with: - python-version: 3.x - - - name: Install dependencies - run: | - python -m pip install --upgrade pip - - - name: Copy Scripts - run: | - cp res/scripts/generate_override_all.py . - - - name: Run generate_override_all.py - run: python3 generate_override_all.py - - - name: Check for changes in override-all.json - id: check_changes - run: | - git diff --exit-code override-all.json || echo "::set-output name=changes_detected::true" - - - name: Commit and push changes - if: steps.check_changes.outputs.changes_detected == 'true' - run: | - git config --global user.email "github-actions[bot]@users.noreply.github.com" - git config --global user.name "GitHub Actions" - git add override-all.json - git commit -m "Update override-all.json" - git push diff --git a/.gitignore b/.gitignore index b9069a7f..7b2a70a9 100644 --- a/.gitignore +++ b/.gitignore @@ -33,3 +33,4 @@ bard.json !/docker-compose.yaml res/instance_id.json .DS_Store +/data \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index d977b91a..e64b3d74 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,15 +1,8 @@ FROM python:3.10.13-bullseye -WORKDIR /QChatGPT +WORKDIR /app -COPY . /QChatGPT/ +COPY . . -RUN ls +RUN python -m pip install -r requirements.txt -RUN python -m pip install -r requirements.txt && \ - python -m pip install -U websockets==10.0 && \ - python -m pip install -U httpcore httpx openai - -# 生成配置文件 -RUN python main.py - -CMD [ "python", "main.py" ] \ No newline at end of file +CMD [ "python", "start.py" ] \ No newline at end of file diff --git a/HiraginoSansGB.ttc b/HiraginoSansGB.ttc deleted file mode 100644 index 0b0123aa..00000000 Binary files a/HiraginoSansGB.ttc and /dev/null differ diff --git a/banlist-template.py b/banlist-template.py deleted file mode 100644 index dcaf375e..00000000 --- a/banlist-template.py +++ /dev/null @@ -1,30 +0,0 @@ -# 是否处理群聊消息 -# 为False时忽略所有群聊消息 -# 优先级高于下方禁用列表 -enable_group = True - -# 是否处理私聊消息 -# 为False时忽略所有私聊消息 -# 优先级高于下方禁用列表 -enable_private = True - -# 是否启用禁用列表 -enable = True - -# 禁用规则(黑名单) -# person为个人,其中的QQ号会被禁止与机器人进行私聊或群聊交互 -# 示例: person = [2854196310, 1234567890, 9876543210] -# group为群组,其中的群号会被禁止与机器人进行交互 -# 示例: group = [123456789, 987654321, 1234567890] -# -# 支持正则表达式,字符串都将被识别为正则表达式,例如: -# person = [12345678, 87654321, "2854.*"] -# group = [123456789, 987654321, "1234.*"] -# 若要排除某个QQ号或群号(即允许使用),可以在前面加上"!",例如: -# person = ["!1234567890"] -# group = ["!987654321"] -# 排除规则优先级高于包含规则,即如果同时存在包含规则和排除规则,排除规则将生效,例如: -# person = ["1234.*", "!1234567890"] -# 那么1234567890将不会被禁用,而其他以1234开头的QQ号都会被禁用 -person = [2854196310] # 2854196310是Q群管家机器人的QQ号,默认屏蔽以免出现循环 -group = [204785790, 691226829] # 本项目交流群的群号,默认屏蔽,避免在交流群测试机器人 diff --git a/config-template.py b/config-template.py deleted file mode 100644 index 6808bb8a..00000000 --- a/config-template.py +++ /dev/null @@ -1,372 +0,0 @@ -# 配置文件: 注释里标[必需]的参数必须修改, 其他参数根据需要修改, 但请勿删除 -import logging - -# 消息处理协议适配器 -# 目前支持以下适配器: -# - "yirimirai": mirai的通信框架,YiriMirai框架适配器, 请同时填写下方mirai_http_api_config -# - "nakuru": go-cqhttp通信框架,请同时填写下方nakuru_config -msg_source_adapter = "yirimirai" - -# [必需(与nakuru二选一,取决于msg_source_adapter)] Mirai的配置 -# 请到配置mirai的步骤中的教程查看每个字段的信息 -# adapter: 选择适配器,目前支持HTTPAdapter和WebSocketAdapter -# host: 运行mirai的主机地址 -# port: 运行mirai的主机端口 -# verifyKey: mirai-api-http的verifyKey -# qq: 机器人的QQ号 -# -# 注意: QQ机器人配置不支持热重载及热更新 -mirai_http_api_config = { - "adapter": "WebSocketAdapter", - "host": "localhost", - "port": 8080, - "verifyKey": "yirimirai", - "qq": 1234567890 -} - -# [必需(与mirai二选一,取决于msg_source_adapter)] -# 使用nakuru-project框架连接go-cqhttp的配置 -nakuru_config = { - "host": "localhost", # go-cqhttp的地址 - "port": 6700, # go-cqhttp的正向websocket端口 - "http_port": 5700, # go-cqhttp的正向http端口 - "token": "" # 若在go-cqhttp的config.yml设置了access_token, 则填写此处 -} - -# [必需] OpenAI的配置 -# api_key: OpenAI的API Key -# http_proxy: 请求OpenAI时使用的代理,None为不使用,https和socks5暂不能使用 -# 若只有一个api-key,请直接修改以下内容中的"openai_api_key"为你的api-key -# -# 如准备了多个api-key,可以以字典的形式填写,程序会自动选择可用的api-key -# 例如 -# openai_config = { -# "api_key": { -# "default": "sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", -# "key1": "sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", -# "key2": "sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", -# }, -# "http_proxy": "http://127.0.0.1:12345" -# } -# -# 现已支持反向代理,可以添加reverse_proxy字段以使用反向代理 -# 使用反向代理可以在国内使用OpenAI的API,反向代理的配置请参考 -# https://github.com/Ice-Hazymoon/openai-scf-proxy -# -# 反向代理填写示例: -# openai_config = { -# "api_key": { -# "default": "sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", -# "key1": "sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", -# "key2": "sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", -# }, -# "reverse_proxy": "http://example.com:12345/v1" -# } -# -# 作者开设公用反向代理地址: https://api.openai.rockchin.top/v1 -# 随时可能关闭,仅供测试使用,有条件建议使用正向代理或者自建反向代理 -openai_config = { - "api_key": { - "default": "openai_api_key" - }, - "http_proxy": None, - "reverse_proxy": None -} - -# api-key切换策略 -# active:每次请求时都会切换api-key -# passive:仅当api-key超额时才会切换api-key -switch_strategy = "active" - -# [必需] 管理员QQ号,用于接收报错等通知及执行管理员级别命令 -# 支持多个管理员,可以使用list形式设置,例如: -# admin_qq = [12345678, 87654321] -admin_qq = 0 - -# 情景预设(机器人人格) -# 每个会话的预设信息,影响所有会话,无视命令重置 -# 可以通过这个字段指定某些情况的回复,可直接用自然语言描述指令 -# 例如: -# default_prompt = "如果我之后想获取帮助,请你说“输入!help获取帮助”" -# 这样用户在不知所措的时候机器人就会提示其输入!help获取帮助 -# 可参考 https://github.com/PlexPt/awesome-chatgpt-prompts-zh -# -# 如果需要多个情景预设,并在运行期间方便切换,请使用字典的形式填写,例如 -# default_prompt = { -# "default": "如果我之后想获取帮助,请你说“输入!help获取帮助”", -# "linux-terminal": "我想让你充当 Linux 终端。我将输入命令,您将回复终端应显示的内容。", -# "en-dict": "我想让你充当英英词典,对于给出的英文单词,你要给出其中文意思以及英文解释,并且给出一个例句,此外不要有其他反馈。", -# } -# -# 在使用期间即可通过命令: -# !reset [名称] -# 来使用指定的情景预设重置会话 -# 例如: -# !reset linux-terminal -# 若不指定名称,则使用默认情景预设 -# -# 也可以使用命令: -# !default <名称> -# 将指定的情景预设设置为默认情景预设 -# 例如: -# !default linux-terminal -# 之后的会话重置时若不指定名称,则使用linux-terminal情景预设 -# -# 还可以加载文件中的预设文字,使用方法请查看:https://github.com/RockChinQ/QChatGPT/wiki/%E5%8A%9F%E8%83%BD%E4%BD%BF%E7%94%A8#%E9%A2%84%E8%AE%BE%E6%96%87%E5%AD%97 -default_prompt = { - "default": "如果用户之后想获取帮助,请你说“输入!help获取帮助”。", -} - -# 情景预设格式 -# 参考值:默认方式:normal | 完整情景:full_scenario -# 默认方式 的格式为上述default_prompt中的内容,或prompts目录下的文件名 -# 完整情景方式 的格式为JSON,在scenario目录下的JSON文件中列出对话的每个回合,编写方法见scenario/default-template.json -# 编写方法请查看:https://github.com/RockChinQ/QChatGPT/wiki/%E5%8A%9F%E8%83%BD%E4%BD%BF%E7%94%A8#%E9%A2%84%E8%AE%BE%E6%96%87%E5%AD%97full_scenario%E6%A8%A1%E5%BC%8F -preset_mode = "normal" - -# 群内响应规则 -# 符合此消息的群内消息即使不包含at机器人也会响应 -# 支持消息前缀匹配及正则表达式匹配 -# 支持设置是否响应at消息、随机响应概率 -# 注意:由消息前缀(prefix)匹配的消息中将会删除此前缀,正则表达式(regexp)匹配的消息不会删除匹配的部分 -# 前缀匹配优先级高于正则表达式匹配 -# 正则表达式简明教程:https://www.runoob.com/regexp/regexp-tutorial.html -# -# 支持针对不同群设置不同的响应规则,例如: -# response_rules = { -# "default": { -# "at": True, -# "prefix": ["/ai", "!ai", "!ai", "ai"], -# "regexp": [], -# "random_rate": 0.0, -# }, -# "12345678": { -# "at": False, -# "prefix": ["/ai", "!ai", "!ai", "ai"], -# "regexp": [], -# "random_rate": 0.0, -# }, -# } -# -# 以上设置将会在群号为12345678的群中关闭at响应 -# 未单独设置的群将使用default规则 -response_rules = { - "default": { - "at": True, # 是否响应at机器人的消息 - "prefix": ["/ai", "!ai", "!ai", "ai"], - "regexp": [], # "为什么.*", "怎么?样.*", "怎么.*", "如何.*", "[Hh]ow to.*", "[Ww]hy not.*", "[Ww]hat is.*", ".*怎么办", ".*咋办" - "random_rate": 0.0, # 随机响应概率,0.0-1.0,0.0为不随机响应,1.0为响应所有消息, 仅在前几项判断不通过时生效 - }, -} - - -# 消息忽略规则 -# 适用于私聊及群聊 -# 符合此规则的消息将不会被响应 -# 支持消息前缀匹配及正则表达式匹配 -# 此设置优先级高于response_rules -# 用以过滤mirai等其他层级的命令 -# @see https://github.com/RockChinQ/QChatGPT/issues/165 -# -# *需要同时开启下方 income_msg_check 才会生效 -ignore_rules = { - "prefix": ["/"], - "regexp": [] -} - -# 是否检查收到的消息中是否包含敏感词 -# 若收到的消息无法通过下方指定的敏感词检查策略,则发送提示信息 -income_msg_check = False - -# 敏感词过滤开关,以同样数量的*代替敏感词回复 -# 请在sensitive.json中添加敏感词 -sensitive_word_filter = True - -# 是否启用百度云内容安全审核 -# 注册方式查看 https://cloud.baidu.com/doc/ANTIPORN/s/Wkhu9d5iy -baidu_check = False - -# 百度云API_KEY 24位英文数字字符串 -baidu_api_key = "" - -# 百度云SECRET_KEY 32位的英文数字字符串 -baidu_secret_key = "" - -# 不合规消息自定义返回 -inappropriate_message_tips = "[百度云]请珍惜机器人,当前返回内容不合规" - -# 启动时是否发送赞赏码 -# 仅当使用量已经超过2048字时发送 -encourage_sponsor_at_start = True - -# 每次向OpenAI接口发送对话记录上下文的字符数 -# 最大不超过(4096 - max_tokens)个字符,max_tokens为下方completion_api_params中的max_tokens -# 注意:较大的prompt_submit_length会导致OpenAI账户额度消耗更快 -prompt_submit_length = 3072 - -# 是否在token超限报错时自动重置会话 -# 可在tips.py中编辑提示语 -auto_reset = True - -# OpenAI补全API的参数 -# 请在下方填写模型,程序自动选择接口 -# 模型文档:https://platform.openai.com/docs/models -# 现已支持的模型有: -# -# ChatCompletions 接口: -# # GPT 4 系列 -# "gpt-4-1106-preview", -# "gpt-4-vision-preview", -# "gpt-4", -# "gpt-4-32k", -# "gpt-4-0613", -# "gpt-4-32k-0613", -# "gpt-4-0314", # legacy -# "gpt-4-32k-0314", # legacy -# # GPT 3.5 系列 -# "gpt-3.5-turbo-1106", -# "gpt-3.5-turbo", -# "gpt-3.5-turbo-16k", -# "gpt-3.5-turbo-0613", # legacy -# "gpt-3.5-turbo-16k-0613", # legacy -# "gpt-3.5-turbo-0301", # legacy -# -# Completions接口: -# "gpt-3.5-turbo-instruct", -# -# 具体请查看OpenAI的文档: https://beta.openai.com/docs/api-reference/completions/create -# 请将内容修改到config.py中,请勿修改config-template.py -# -# 支持通过 One API 接入多种模型,请在上方的openai_config中设置One API的代理地址, -# 并在此填写您要使用的模型名称,详细请参考:https://github.com/songquanpeng/one-api -# -# 支持的 One API 模型: -# "SparkDesk", -# "chatglm_pro", -# "chatglm_std", -# "chatglm_lite", -# "qwen-v1", -# "qwen-plus-v1", -# "ERNIE-Bot", -# "ERNIE-Bot-turbo", -# "gemini-pro", -completion_api_params = { - "model": "gpt-3.5-turbo", - "temperature": 0.9, # 数值越低得到的回答越理性,取值范围[0, 1] -} - -# OpenAI的Image API的参数 -# 具体请查看OpenAI的文档: https://platform.openai.com/docs/api-reference/images/create -image_api_params = { - "model": "dall-e-2", # 默认使用 dall-e-2 模型,也可以改为 dall-e-3 - # 图片尺寸 - # dall-e-2 模型支持 256x256, 512x512, 1024x1024 - # dall-e-3 模型支持 1024x1024, 1792x1024, 1024x1792 - "size": "256x256", -} - -# 跟踪函数调用 -# 为True时,在每次GPT进行Function Calling时都会输出发送一条回复给用户 -# 同时,一次提问内所有的Function Calling和普通回复消息都会单独发送给用户 -trace_function_calls = True - -# 群内回复消息时是否引用原消息 -quote_origin = False - -# 群内回复消息时是否at发送者 -at_sender = False - -# 回复绘图时是否包含图片描述 -include_image_description = True - -# 消息处理的超时时间,单位为秒 -process_message_timeout = 120 - -# 回复消息时是否显示[GPT]前缀 -show_prefix = False - -# 回复前的强制延迟时间,降低机器人被腾讯风控概率 -# *此机制对命令和消息、私聊及群聊均生效 -# 每次处理时从以下的范围取一个随机秒数, -# 当此次消息处理时间低于此秒数时,将会强制延迟至此秒数 -# 例如:[1.5, 3],则每次处理时会随机取一个1.5-3秒的随机数,若处理时间低于此随机数,则强制延迟至此随机秒数 -# 若您不需要此功能,请将force_delay_range设置为[0, 0] -force_delay_range = [0, 0] - -# 应用长消息处理策略的阈值 -# 当回复消息长度超过此值时,将使用长消息处理策略 -blob_message_threshold = 256 - -# 长消息处理策略 -# - "image": 将长消息转换为图片发送 -# - "forward": 将长消息转换为转发消息组件发送 -blob_message_strategy = "forward" - -# 允许等待 -# 同一会话内,是否等待上一条消息处理完成后再处理下一条消息 -# 若设置为False,若上一条未处理完时收到了新消息,将会丢弃新消息 -# 丢弃消息时的提示信息可以在tips.py中修改 -wait_last_done = True - -# 文字转图片时使用的字体文件路径 -# 当策略为"image"时生效 -# 若在Windows系统下,程序会自动使用Windows自带的微软雅黑字体 -# 若未填写或不存在且不是Windows,将禁用文字转图片功能,改为使用转发消息组件 -font_path = "" - -# 消息处理超时重试次数 -retry_times = 3 - -# 消息处理出错时是否向用户隐藏错误详细信息 -# 设置为True时,仅向管理员发送错误详细信息 -# 设置为False时,向用户及管理员发送错误详细信息 -hide_exce_info_to_user = False - -# 每个会话的过期时间,单位为秒 -# 默认值20分钟 -session_expire_time = 1200 - -# 会话限速 -# 单会话内每分钟可进行的对话次数 -# 若不需要限速,可以设置为一个很大的值 -# 默认值60次,基本上不会触发限速 -# -# 若要设置针对某特定群的限速,请使用如下格式: -# { -# "group_<群号>": 60, -# "default": 60, -# } -# 若要设置针对某特定用户私聊的限速,请使用如下格式: -# { -# "person_<用户QQ>": 60, -# "default": 60, -# } -# 同时设置多个群和私聊的限速,示例: -# { -# "group_12345678": 60, -# "group_87654321": 60, -# "person_234567890": 60, -# "person_345678901": 60, -# "default": 60, -# } -# -# 注意: 未指定的都使用default的限速值,default不可删除 -rate_limitation = { - "default": 60, -} - -# 会话限速策略 -# - "wait": 每次对话获取到回复时,等待一定时间再发送回复,保证其不会超过限速均值 -# - "drop": 此分钟内,若对话次数超过限速次数,则丢弃之后的对话,每自然分钟重置 -rate_limit_strategy = "drop" - -# 是否在启动时进行依赖库更新 -upgrade_dependencies = False - -# 是否上报统计信息 -# 用于统计机器人的使用情况,数据不公开,不会收集任何敏感信息。 -# 仅实例识别UUID、上报时间、字数使用量、绘图使用量、插件使用情况、用户信息,其他信息不会上报 -report_usage = True - -# 日志级别 -logging_level = logging.INFO diff --git a/override-all.json b/override-all.json deleted file mode 100644 index d790edb7..00000000 --- a/override-all.json +++ /dev/null @@ -1,90 +0,0 @@ -{ - "comment": "这是override.json支持的字段全集, 关于override.json机制, 请查看https://github.com/RockChinQ/QChatGPT/pull/271", - "msg_source_adapter": "yirimirai", - "mirai_http_api_config": { - "adapter": "WebSocketAdapter", - "host": "localhost", - "port": 8080, - "verifyKey": "yirimirai", - "qq": 1234567890 - }, - "nakuru_config": { - "host": "localhost", - "port": 6700, - "http_port": 5700, - "token": "" - }, - "openai_config": { - "api_key": { - "default": "openai_api_key" - }, - "http_proxy": null, - "reverse_proxy": null - }, - "switch_strategy": "active", - "admin_qq": 0, - "default_prompt": { - "default": "如果用户之后想获取帮助,请你说“输入!help获取帮助”。" - }, - "preset_mode": "normal", - "response_rules": { - "default": { - "at": true, - "prefix": [ - "/ai", - "!ai", - "!ai", - "ai" - ], - "regexp": [], - "random_rate": 0.0 - } - }, - "ignore_rules": { - "prefix": [ - "/" - ], - "regexp": [] - }, - "income_msg_check": false, - "sensitive_word_filter": true, - "baidu_check": false, - "baidu_api_key": "", - "baidu_secret_key": "", - "inappropriate_message_tips": "[百度云]请珍惜机器人,当前返回内容不合规", - "encourage_sponsor_at_start": true, - "prompt_submit_length": 3072, - "auto_reset": true, - "completion_api_params": { - "model": "gpt-3.5-turbo", - "temperature": 0.9 - }, - "image_api_params": { - "model": "dall-e-2", - "size": "256x256" - }, - "trace_function_calls": true, - "quote_origin": false, - "at_sender": false, - "include_image_description": true, - "process_message_timeout": 120, - "show_prefix": false, - "force_delay_range": [ - 0, - 0 - ], - "blob_message_threshold": 256, - "blob_message_strategy": "forward", - "wait_last_done": true, - "font_path": "", - "retry_times": 3, - "hide_exce_info_to_user": false, - "session_expire_time": 1200, - "rate_limitation": { - "default": 60 - }, - "rate_limit_strategy": "drop", - "upgrade_dependencies": false, - "report_usage": true, - "logging_level": 20 -} \ No newline at end of file diff --git a/pkg/audit/center/groups/main.py b/pkg/audit/center/groups/main.py index 24e5287b..3a31a65b 100644 --- a/pkg/audit/center/groups/main.py +++ b/pkg/audit/center/groups/main.py @@ -12,8 +12,7 @@ class V2MainDataAPI(apigroup.APIGroup): super().__init__(prefix+"/main", ap) async def do(self, *args, **kwargs): - config = self.ap.cfg_mgr.data - if not config['report_usage']: + if not self.ap.system_cfg.data['report-usage']: return None return await super().do(*args, **kwargs) diff --git a/pkg/audit/center/groups/plugin.py b/pkg/audit/center/groups/plugin.py index 312d5e86..627b116c 100644 --- a/pkg/audit/center/groups/plugin.py +++ b/pkg/audit/center/groups/plugin.py @@ -12,8 +12,7 @@ class V2PluginDataAPI(apigroup.APIGroup): super().__init__(prefix+"/plugin", ap) async def do(self, *args, **kwargs): - config = self.ap.cfg_mgr.data - if not config['report_usage']: + if not self.ap.system_cfg.data['report-usage']: return None return await super().do(*args, **kwargs) diff --git a/pkg/audit/center/groups/usage.py b/pkg/audit/center/groups/usage.py index 02d89387..8a8bdf04 100644 --- a/pkg/audit/center/groups/usage.py +++ b/pkg/audit/center/groups/usage.py @@ -12,8 +12,7 @@ class V2UsageDataAPI(apigroup.APIGroup): super().__init__(prefix+"/usage", ap) async def do(self, *args, **kwargs): - config = self.ap.cfg_mgr.data - if not config['report_usage']: + if not self.ap.system_cfg.data['report-usage']: return None return await super().do(*args, **kwargs) diff --git a/pkg/command/cmdmgr.py b/pkg/command/cmdmgr.py index cf2dbc88..03f84e21 100644 --- a/pkg/command/cmdmgr.py +++ b/pkg/command/cmdmgr.py @@ -5,8 +5,9 @@ import typing from ..core import app, entities as core_entities from ..provider import entities as llm_entities from . import entities, operator, errors +from ..config import manager as cfg_mgr -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: @@ -21,6 +22,23 @@ class CommandManager: self.ap = ap async def initialize(self): + + # 设置各个类的路径 + def set_path(cls: operator.CommandOperator, ancestors: list[str]): + cls.path = '.'.join(ancestors + [cls.name]) + for op in operator.preregistered_operators: + if op.parent_class == cls: + set_path(op, ancestors + [cls.name]) + + for cls in operator.preregistered_operators: + if cls.parent_class is None: + set_path(cls, []) + + # 应用命令权限配置 + for cls in operator.preregistered_operators: + if cls.path in self.ap.command_cfg.data['privilege']: + cls.lowest_privilege = self.ap.command_cfg.data['privilege'][cls.path] + # 实例化所有类 self.cmd_list = [cls(self.ap) for cls in operator.preregistered_operators] @@ -85,9 +103,11 @@ class CommandManager: """ 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 + + print(f'privilege: {privilege}') ctx = entities.ExecuteContext( query=query, diff --git a/pkg/command/operator.py b/pkg/command/operator.py index 1b29e6c0..48ca8daf 100644 --- a/pkg/command/operator.py +++ b/pkg/command/operator.py @@ -24,6 +24,7 @@ def operator_class( cls.help = help cls.usage = usage cls.parent_class = parent_class + cls.lowest_privilege = privilege preregistered_operators.append(cls) @@ -41,6 +42,9 @@ class CommandOperator(metaclass=abc.ABCMeta): name: str """名称,搜索到时若符合则使用""" + path: str + """路径,所有父节点的name的连接,用于定义命令权限""" + alias: list[str] """同name""" diff --git a/pkg/command/operators/cfg.py b/pkg/command/operators/cfg.py deleted file mode 100644 index b67ff3e6..00000000 --- a/pkg/command/operators/cfg.py +++ /dev/null @@ -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))) diff --git a/pkg/command/operators/help.py b/pkg/command/operators/help.py index c99c2948..570e103c 100644 --- a/pkg/command/operators/help.py +++ b/pkg/command/operators/help.py @@ -16,7 +16,7 @@ class HelpOperator(operator.CommandOperator): self, context: entities.ExecuteContext ) -> typing.AsyncGenerator[entities.CommandReturn, None]: - help = self.ap.tips_mgr.data['help_message'] + help = self.ap.system_cfg.data['help-message'] help += '\n发送命令 !cmd 可查看命令列表' diff --git a/pkg/config/manager.py b/pkg/config/manager.py index 8377a51a..b75f0202 100644 --- a/pkg/config/manager.py +++ b/pkg/config/manager.py @@ -4,6 +4,9 @@ from . import model as file_model from .impls import pymodule, json as json_file +managers: ConfigManager = [] + + class ConfigManager: """配置文件管理器""" diff --git a/pkg/core/app.py b/pkg/core/app.py index cd9607b0..f91d8986 100644 --- a/pkg/core/app.py +++ b/pkg/core/app.py @@ -31,9 +31,15 @@ class Application: 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 diff --git a/pkg/core/boot.py b/pkg/core/boot.py index c251624d..ef5fe2ec 100644 --- a/pkg/core/boot.py +++ b/pkg/core/boot.py @@ -32,7 +32,7 @@ async def make_app() -> app.Application: generated_files = await files.generate_files() if generated_files: - print("以下文件不存在,已自动生成,请修改配置文件后重启:") + print("以下文件不存在,已自动生成,请按需修改配置文件后重启:") for file in generated_files: print("-", file) @@ -52,31 +52,23 @@ async def make_app() -> app.Application: # 生成标识符 identifier.init() - cfg_mgr = await config.load_python_module_config("config.py", "config-template.py") - cfg = cfg_mgr.data + # ========== 加载配置文件 ========== - # 检查是否携带了 --override 或 -r 参数 - if "--override" in sys.argv or "-r" in sys.argv: - use_override = True + command_cfg = await config.load_json_config("data/config/command.json", "templates/command.json") + pipeline_cfg = await config.load_json_config("data/config/pipeline.json", "templates/pipeline.json") + 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.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) await proxy_mgr.initialize() @@ -95,8 +87,8 @@ async def make_app() -> app.Application: "platform": sys.platform, }, runtime_info={ - "admin_id": "{}".format(cfg["admin_qq"]), - "msg_source": cfg["msg_source_adapter"], + "admin_id": "{}".format(system_cfg.data["admin-sessions"]), + "msg_source": platform_cfg.data["platform-adapter"], }, ) ap.ctr_mgr = center_v2_api diff --git a/pkg/core/bootutils/files.py b/pkg/core/bootutils/files.py index 25a8ba5b..975e3aad 100644 --- a/pkg/core/bootutils/files.py +++ b/pkg/core/bootutils/files.py @@ -6,19 +6,25 @@ import sys required_files = { - "config.py": "config-template.py", - "banlist.py": "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", + "plugins/__init__.py": "templates/__init__.py", + "plugins/plugins.json": "templates/plugin-settings.json", + "data/config/command.json": "templates/command.json", + "data/config/pipeline.json": "templates/pipeline.json", + "data/config/platform.json": "templates/platform.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 = [ - "plugins", - "prompts", "temp", - "logs" + "data", + "data/prompts", + "data/scenario", + "data/logs", + "data/config", + "plugins" ] async def generate_files() -> list[str]: diff --git a/pkg/core/bootutils/log.py b/pkg/core/bootutils/log.py index 4bc0e4de..a63b7c92 100644 --- a/pkg/core/bootutils/log.py +++ b/pkg/core/bootutils/log.py @@ -21,7 +21,7 @@ async def init_logging() -> logging.Logger: if "DEBUG" in os.environ and os.environ["DEBUG"] in ["true", "1"]: 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() ) diff --git a/pkg/core/controller.py b/pkg/core/controller.py index 9cf4727a..12403aff 100644 --- a/pkg/core/controller.py +++ b/pkg/core/controller.py @@ -8,8 +8,6 @@ from . import app, entities from ..pipeline import entities as pipeline_entities from ..plugin import events -DEFAULT_QUERY_CONCURRENCY = 10 - class Controller: """总控制器 @@ -21,7 +19,7 @@ class Controller: def __init__(self, ap: app.Application): 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): """事件处理循环 @@ -150,9 +148,9 @@ class Controller: try: await self._execute_from_stage(0, query) except Exception as e: - self.ap.logger.error(f"处理请求时出错 {query}: {e}") - # self.ap.logger.debug(f"处理请求时出错 {query}: {e}", exc_info=True) - traceback.print_exc() + self.ap.logger.error(f"处理请求时出错 query_id={query.query_id}: {e}") + self.ap.logger.debug(f"Traceback: {traceback.format_exc()}") + # traceback.print_exc() finally: self.ap.logger.debug(f"Query {query} processed") diff --git a/pkg/pipeline/bansess/bansess.py b/pkg/pipeline/bansess/bansess.py index a0f63c36..f56babe2 100644 --- a/pkg/pipeline/bansess/bansess.py +++ b/pkg/pipeline/bansess/bansess.py @@ -9,13 +9,8 @@ from ...config import manager as cfg_mgr @stage.stage_class('BanSessionCheckStage') class BanSessionCheckStage(stage.PipelineStage): - banlist_mgr: cfg_mgr.ConfigManager - async def initialize(self): - self.banlist_mgr = await cfg_mgr.load_python_module_config( - "banlist.py", - "res/templates/banlist-template.py" - ) + pass async def process( self, @@ -23,54 +18,28 @@ class BanSessionCheckStage(stage.PipelineStage): stage_inst_name: str ) -> entities.StageProcessResult: - if not self.banlist_mgr.data['enable']: - return entities.StageProcessResult( - result_type=entities.ResultType.CONTINUE, - new_query=query - ) - + found = False + + mode = self.ap.pipeline_cfg.data['access-control']['mode'] + + 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 - if query.launcher_type == 'group': - if not self.banlist_mgr.data['enable_group']: # 未启用群聊响应 - 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 + if mode == 'blacklist': + result = found return entities.StageProcessResult( result_type=entities.ResultType.CONTINUE if not result else entities.ResultType.INTERRUPT, 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 '' ) diff --git a/pkg/pipeline/cntfilter/cntfilter.py b/pkg/pipeline/cntfilter/cntfilter.py index 78412458..9982a51e 100644 --- a/pkg/pipeline/cntfilter/cntfilter.py +++ b/pkg/pipeline/cntfilter/cntfilter.py @@ -24,10 +24,10 @@ class ContentFilterStage(stage.PipelineStage): async def initialize(self): 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)) - 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)) for filter in self.filter_chain: @@ -41,7 +41,7 @@ class ContentFilterStage(stage.PipelineStage): """请求llm前处理消息 只要有一个不通过就不放行,只放行 PASS 的消息 """ - if not self.ap.cfg_mgr.data['income_msg_check']: + if not self.ap.pipeline_cfg.data['income-msg-check']: return entities.StageProcessResult( result_type=entities.ResultType.CONTINUE, new_query=query diff --git a/pkg/pipeline/cntfilter/filters/baiduexamine.py b/pkg/pipeline/cntfilter/filters/baiduexamine.py index a658897b..f72fe960 100644 --- a/pkg/pipeline/cntfilter/filters/baiduexamine.py +++ b/pkg/pipeline/cntfilter/filters/baiduexamine.py @@ -19,8 +19,8 @@ class BaiduCloudExamine(filter_model.ContentFilter): BAIDU_EXAMINE_TOKEN_URL, params={ "grant_type": "client_credentials", - "client_id": self.ap.cfg_mgr.data['baidu_api_key'], - "client_secret": self.ap.cfg_mgr.data['baidu_secret_key'] + "client_id": self.ap.pipeline_cfg.data['baidu-cloud-examine']['api-key'], + "client_secret": self.ap.pipeline_cfg.data['baidu-cloud-examine']['api-secret'] } ) as resp: return (await resp.json())['access_token'] @@ -56,6 +56,6 @@ class BaiduCloudExamine(filter_model.ContentFilter): return entities.FilterResult( level=entities.ResultLevel.BLOCK, replacement=message, - user_notice=self.ap.cfg_mgr.data['inappropriate_message_tips'], + user_notice="消息中存在不合适的内容, 请修改", console_notice=f"百度云判定结果:{conclusion}" - ) \ No newline at end of file + ) diff --git a/pkg/pipeline/cntfilter/filters/banwords.py b/pkg/pipeline/cntfilter/filters/banwords.py index 9451c7b8..587f81c3 100644 --- a/pkg/pipeline/cntfilter/filters/banwords.py +++ b/pkg/pipeline/cntfilter/filters/banwords.py @@ -13,8 +13,8 @@ class BanWordFilter(filter_model.ContentFilter): async def initialize(self): self.sensitive = await cfg_mgr.load_json_config( - "sensitive.json", - "res/templates/sensitive-template.json" + "data/config/sensitive-words.json", + "templates/sensitive-words.json" ) async def process(self, message: str) -> entities.FilterResult: @@ -39,6 +39,6 @@ class BanWordFilter(filter_model.ContentFilter): return entities.FilterResult( level=entities.ResultLevel.MASKED if found else entities.ResultLevel.PASS, replacement=message, - user_notice='[bot] 消息中存在不合适的内容, 请更换措辞' if found else '', + user_notice='消息中存在不合适的内容, 请修改' if found else '', console_notice='' ) \ No newline at end of file diff --git a/pkg/pipeline/cntfilter/filters/cntignore.py b/pkg/pipeline/cntfilter/filters/cntignore.py index 81408868..92fe94e8 100644 --- a/pkg/pipeline/cntfilter/filters/cntignore.py +++ b/pkg/pipeline/cntfilter/filters/cntignore.py @@ -15,8 +15,8 @@ class ContentIgnore(filter_model.ContentFilter): ] async def process(self, message: str) -> entities.FilterResult: - if 'prefix' in self.ap.cfg_mgr.data['ignore_rules']: - for rule in self.ap.cfg_mgr.data['ignore_rules']['prefix']: + if 'prefix' in self.ap.pipeline_cfg.data['ignore-rules']: + for rule in self.ap.pipeline_cfg.data['ignore-rules']['prefix']: if message.startswith(rule): return entities.FilterResult( level=entities.ResultLevel.BLOCK, @@ -25,8 +25,8 @@ class ContentIgnore(filter_model.ContentFilter): console_notice='根据 ignore_rules 中的 prefix 规则,忽略消息' ) - if 'regexp' in self.ap.cfg_mgr.data['ignore_rules']: - for rule in self.ap.cfg_mgr.data['ignore_rules']['regexp']: + if 'regexp' in self.ap.pipeline_cfg.data['ignore-rules']: + for rule in self.ap.pipeline_cfg.data['ignore-rules']['regexp']: if re.search(rule, message): return entities.FilterResult( level=entities.ResultLevel.BLOCK, diff --git a/pkg/pipeline/longtext/longtext.py b/pkg/pipeline/longtext/longtext.py index 72c36cdf..85de47c1 100644 --- a/pkg/pipeline/longtext/longtext.py +++ b/pkg/pipeline/longtext/longtext.py @@ -19,9 +19,9 @@ class LongTextProcessStage(stage.PipelineStage): strategy_impl: strategy.LongTextStrategy async def initialize(self): - config = self.ap.cfg_mgr.data - if self.ap.cfg_mgr.data['blob_message_strategy'] == 'image': - use_font = config['font_path'] + config = self.ap.platform_cfg.data['long-text-process'] + if config['strategy'] == 'image': + use_font = config['font-path'] try: # 检查是否存在 if not os.path.exists(use_font): @@ -33,23 +33,25 @@ class LongTextProcessStage(stage.PipelineStage): config['blob_message_strategy'] = "forward" else: self.ap.logger.info("使用Windows自带字体:" + use_font) - self.ap.cfg_mgr.data['font_path'] = use_font + config['font-path'] = use_font else: 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: traceback.print_exc() self.ap.logger.error("加载字体文件失败({}),更换为转发消息组件以发送长消息,您可以在config.py中调整相关设置。".format(use_font)) - self.ap.cfg_mgr.data['blob_message_strategy'] = "forward" + + self.ap.platform_cfg.data['long-text-process']['strategy'] = "forward" - if self.ap.cfg_mgr.data['blob_message_strategy'] == 'image': + if config['strategy'] == 'image': 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) await self.strategy_impl.initialize() 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))) return entities.StageProcessResult( result_type=entities.ResultType.CONTINUE, diff --git a/pkg/pipeline/longtext/strategies/image.py b/pkg/pipeline/longtext/strategies/image.py index 4f789098..1d350f60 100644 --- a/pkg/pipeline/longtext/strategies/image.py +++ b/pkg/pipeline/longtext/strategies/image.py @@ -19,7 +19,7 @@ class Text2ImageStrategy(strategy_model.LongTextStrategy): text_render_font: ImageFont.FreeTypeFont 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]: img_path = self.text_to_image( diff --git a/pkg/pipeline/preproc/preproc.py b/pkg/pipeline/preproc/preproc.py index 1df5daf9..ad0d7ff6 100644 --- a/pkg/pipeline/preproc/preproc.py +++ b/pkg/pipeline/preproc/preproc.py @@ -52,7 +52,7 @@ class PreProcessor(stage.PipelineStage): query.messages = event_ctx.event.prompt # 根据模型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] @@ -63,7 +63,7 @@ class PreProcessor(stage.PipelineStage): result_type=entities.ResultType.INTERRUPT, new_query=query, user_notice='输入内容过长,请减少情景预设或者输入内容长度', - console_notice='输入内容过长,请减少情景预设或者输入内容长度,或者增大配置文件中的 prompt_submit_length 项(但不能超过所用模型最大tokens数)' + console_notice='输入内容过长,请减少情景预设或者输入内容长度,或者增大配置文件中的 submit-messages-tokens 项(但不能超过所用模型最大tokens数)' ) query.messages.pop(0) # pop第一个肯定是role=user的 diff --git a/pkg/pipeline/process/handlers/chat.py b/pkg/pipeline/process/handlers/chat.py index c34f2298..26c99a2e 100644 --- a/pkg/pipeline/process/handlers/chat.py +++ b/pkg/pipeline/process/handlers/chat.py @@ -54,6 +54,12 @@ class ChatMessageHandler(handler.MessageHandler): ) 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: query.message_chain = mirai.MessageChain([ mirai.Plain(event_ctx.event.alter) @@ -83,7 +89,7 @@ class ChatMessageHandler(handler.MessageHandler): yield entities.StageProcessResult( result_type=entities.ResultType.INTERRUPT, 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}', debug_notice=traceback.format_exc() ) diff --git a/pkg/pipeline/process/handlers/command.py b/pkg/pipeline/process/handlers/command.py index 50600a36..d5873e38 100644 --- a/pkg/pipeline/process/handlers/command.py +++ b/pkg/pipeline/process/handlers/command.py @@ -23,8 +23,8 @@ class CommandHandler(handler.MessageHandler): 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 spt = str(query.message_chain).strip().split(' ') diff --git a/pkg/pipeline/ratelimit/algos/fixedwin.py b/pkg/pipeline/ratelimit/algos/fixedwin.py index 4996fbaa..bb69b0dd 100644 --- a/pkg/pipeline/ratelimit/algos/fixedwin.py +++ b/pkg/pipeline/ratelimit/algos/fixedwin.py @@ -55,16 +55,16 @@ class FixedWindowAlgo(algo.ReteLimitAlgo): # 获取当前分钟的访问次数 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']: - limitation = self.ap.cfg_mgr.data['rate_limitation'][session_name] + if session_name in self.ap.pipeline_cfg.data['rate-limit']['fixwin']: + limitation = self.ap.pipeline_cfg.data['rate-limit']['fixwin'][session_name] # 如果访问次数超过了限制 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 - 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) diff --git a/pkg/pipeline/ratelimit/ratelimit.py b/pkg/pipeline/ratelimit/ratelimit.py index 2e3c6706..cc8e4ac1 100644 --- a/pkg/pipeline/ratelimit/ratelimit.py +++ b/pkg/pipeline/ratelimit/ratelimit.py @@ -42,7 +42,7 @@ class RateLimit(stage.PipelineStage): result_type=entities.ResultType.INTERRUPT, new_query=query, 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": await self.algo.release_access( diff --git a/pkg/pipeline/respback/respback.py b/pkg/pipeline/respback/respback.py index 0a60a793..52b23ab6 100644 --- a/pkg/pipeline/respback/respback.py +++ b/pkg/pipeline/respback/respback.py @@ -20,7 +20,7 @@ class SendResponseBackStage(stage.PipelineStage): 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( "根据规则强制延迟回复: %s s", diff --git a/pkg/pipeline/resprule/resprule.py b/pkg/pipeline/resprule/resprule.py index 6335a7d4..894bbce1 100644 --- a/pkg/pipeline/resprule/resprule.py +++ b/pkg/pipeline/resprule/resprule.py @@ -33,13 +33,13 @@ class GroupRespondRuleCheckStage(stage.PipelineStage): 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( result_type=entities.ResultType.CONTINUE, new_query=query ) - rules = self.ap.cfg_mgr.data['response_rules'] + rules = self.ap.pipeline_cfg.data['respond-rules'] use_rule = rules['default'] diff --git a/pkg/pipeline/resprule/rules/prefix.py b/pkg/pipeline/resprule/rules/prefix.py index 31ead5ab..b23f5f8f 100644 --- a/pkg/pipeline/resprule/rules/prefix.py +++ b/pkg/pipeline/resprule/rules/prefix.py @@ -16,6 +16,7 @@ class PrefixRule(rule_model.GroupRespondRule): for prefix in prefixes: if message_text.startswith(prefix): + return entities.RuleJudgeResult( matching=True, replacement=mirai.MessageChain([ diff --git a/pkg/pipeline/resprule/rules/random.py b/pkg/pipeline/resprule/rules/random.py index 1e8354b5..932d00be 100644 --- a/pkg/pipeline/resprule/rules/random.py +++ b/pkg/pipeline/resprule/rules/random.py @@ -14,7 +14,7 @@ class RandomRespRule(rule_model.GroupRespondRule): message_chain: mirai.MessageChain, rule_dict: dict ) -> entities.RuleJudgeResult: - random_rate = rule_dict['random_rate'] + random_rate = rule_dict['random'] return entities.RuleJudgeResult( matching=random.random() < random_rate, diff --git a/pkg/pipeline/wrapper/wrapper.py b/pkg/pipeline/wrapper/wrapper.py index 0625a3d9..0278b603 100644 --- a/pkg/pipeline/wrapper/wrapper.py +++ b/pkg/pipeline/wrapper/wrapper.py @@ -85,7 +85,7 @@ class ResponseWrapper(stage.PipelineStage): 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=events.NormalMessageResponded( diff --git a/pkg/platform/manager.py b/pkg/platform/manager.py index 277d8ff5..7c07459d 100644 --- a/pkg/platform/manager.py +++ b/pkg/platform/manager.py @@ -31,19 +31,16 @@ class PlatformManager: async def initialize(self): - config = self.ap.cfg_mgr.data - - logging.debug("Use adapter:" + config['msg_source_adapter']) - if config['msg_source_adapter'] == 'yirimirai': + if self.ap.platform_cfg.data['platform-adapter'] == 'yiri-mirai': from pkg.platform.sources.yirimirai import YiriMiraiAdapter - mirai_http_api_config = config['mirai_http_api_config'] - self.bot_account_id = config['mirai_http_api_config']['qq'] + mirai_http_api_config = self.ap.platform_cfg.data['yiri-mirai-config'] + self.bot_account_id = mirai_http_api_config['qq'] self.adapter = YiriMiraiAdapter(mirai_http_api_config) - elif config['msg_source_adapter'] == 'nakuru': - from pkg.platform.sources.nakuru import NakuruProjectAdapter - self.adapter = NakuruProjectAdapter(config['nakuru_config']) - self.bot_account_id = self.adapter.bot_account_id + # elif config['msg_source_adapter'] == 'nakuru': + # from pkg.platform.sources.nakuru import NakuruProjectAdapter + # self.adapter = NakuruProjectAdapter(config['nakuru_config']) + # self.bot_account_id = self.adapter.bot_account_id # 保存 account_id 到审计模块 from ..audit.center import apigroup @@ -99,7 +96,7 @@ class PlatformManager: ) # nakuru不区分好友和陌生人,故仅为yirimirai注册陌生人事件 - if config['msg_source_adapter'] == 'yirimirai': + if self.ap.platform_cfg.data['platform-adapter'] == 'yiri-mirai': self.adapter.register_listener( StrangerMessage, on_stranger_message @@ -133,27 +130,23 @@ class PlatformManager: ) 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'] and isinstance(event, GroupMessage): msg.insert( 0, Plain(" \n") ) - - # 当回复的正文中包含换行时,quote可能会自带at,此时就不再单独添加at,只添加换行 - if "\n" not in str(msg[1]) or config['msg_source_adapter'] == 'nakuru': - msg.insert( - 0, - At( - event.sender.id - ) + msg.insert( + 0, + At( + event.sender.id ) + ) await self.adapter.reply_message( event, 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 +154,16 @@ class PlatformManager: await self.notify_admin_message_chain(MessageChain([Plain("[bot]{}".format(message))])) async def notify_admin_message_chain(self, message: mirai.MessageChain): - config = self.ap.cfg_mgr.data - if config['admin_qq'] != 0 and config['admin_qq'] != []: - logging.info("通知管理员:{}".format(message)) + if self.ap.system_cfg.data['admin-sessions'] != []: admin_list = [] - - if type(config['admin_qq']) == int: - admin_list.append(config['admin_qq']) + for admin in self.ap.system_cfg.data['admin-sessions']: + admin_list.append(admin) for adm in admin_list: self.adapter.send_message( - "person", - adm, + adm.split("_")[0], + adm.split("_")[1], message ) diff --git a/pkg/plugin/setting.py b/pkg/plugin/setting.py index 156a99e6..1ffc0009 100644 --- a/pkg/plugin/setting.py +++ b/pkg/plugin/setting.py @@ -17,7 +17,7 @@ class SettingManager: async def initialize(self): self.settings = await cfg_mgr.load_json_config( 'plugins/plugins.json', - 'res/templates/plugin-setting-template.json' + 'templates/plugin-settings.json' ) async def sync_setting( diff --git a/pkg/provider/requester/apis/chatcmpl.py b/pkg/provider/requester/apis/chatcmpl.py index d82152bd..8630d4e3 100644 --- a/pkg/provider/requester/apis/chatcmpl.py +++ b/pkg/provider/requester/apis/chatcmpl.py @@ -22,8 +22,8 @@ class OpenAIChatCompletion(api.LLMAPIRequester): async def initialize(self): self.client = openai.AsyncClient( api_key="", - base_url=self.ap.cfg_mgr.data["openai_config"]["reverse_proxy"], - timeout=self.ap.cfg_mgr.data["process_message_timeout"], + base_url=self.ap.provider_cfg.data['openai-config']['base_url'], + timeout=self.ap.provider_cfg.data['openai-config']['request-timeout'], ) async def _req( @@ -51,7 +51,7 @@ class OpenAIChatCompletion(api.LLMAPIRequester): ) -> llm_entities.Message: 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 if use_model.tool_call_supported: diff --git a/pkg/provider/requester/modelmgr.py b/pkg/provider/requester/modelmgr.py index ab5ff9e4..dd942970 100644 --- a/pkg/provider/requester/modelmgr.py +++ b/pkg/provider/requester/modelmgr.py @@ -29,7 +29,7 @@ class ModelManager: async def initialize(self): openai_chat_completion = chatcmpl.OpenAIChatCompletion(self.ap) 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) diff --git a/pkg/provider/session/sessionmgr.py b/pkg/provider/session/sessionmgr.py index a20e2b52..a7812504 100644 --- a/pkg/provider/session/sessionmgr.py +++ b/pkg/provider/session/sessionmgr.py @@ -25,10 +25,15 @@ class SessionManager: if query.launcher_type == session.launcher_type and query.launcher_id == session.launcher_id: 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( launcher_type=query.launcher_type, 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) return session @@ -41,7 +46,7 @@ class SessionManager: conversation = core_entities.Conversation( prompt=await self.ap.prompt_mgr.get_prompt(session.use_prompt_name), 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(), ) session.conversations.append(conversation) diff --git a/pkg/provider/sysprompt/loaders/scenario.py b/pkg/provider/sysprompt/loaders/scenario.py index 917de486..a559ff73 100644 --- a/pkg/provider/sysprompt/loaders/scenario.py +++ b/pkg/provider/sysprompt/loaders/scenario.py @@ -14,8 +14,8 @@ class ScenarioPromptLoader(loader.PromptLoader): async def load(self): """加载Prompt """ - for file in os.listdir("scenarios"): - with open("scenarios/{}".format(file), "r", encoding="utf-8") as f: + for file in os.listdir("data/scenarios"): + with open("data/scenarios/{}".format(file), "r", encoding="utf-8") as f: file_str = f.read() file_name = file.split(".")[0] file_json = json.loads(file_str) diff --git a/pkg/provider/sysprompt/loaders/single.py b/pkg/provider/sysprompt/loaders/single.py index 0b109630..57e06ed2 100644 --- a/pkg/provider/sysprompt/loaders/single.py +++ b/pkg/provider/sysprompt/loaders/single.py @@ -14,7 +14,7 @@ class SingleSystemPromptLoader(loader.PromptLoader): """加载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( name=name, messages=[ @@ -26,8 +26,8 @@ class SingleSystemPromptLoader(loader.PromptLoader): ) self.prompts.append(prompt) - for file in os.listdir("prompts"): - with open("prompts/{}".format(file), "r", encoding="utf-8") as f: + for file in os.listdir("data/prompts"): + with open("data/prompts/{}".format(file), "r", encoding="utf-8") as f: file_str = f.read() file_name = file.split(".")[0] prompt = entities.Prompt( diff --git a/pkg/provider/sysprompt/sysprompt.py b/pkg/provider/sysprompt/sysprompt.py index 5df28ee7..5500bb10 100644 --- a/pkg/provider/sysprompt/sysprompt.py +++ b/pkg/provider/sysprompt/sysprompt.py @@ -23,7 +23,7 @@ class PromptManager: "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) diff --git a/pkg/utils/proxy.py b/pkg/utils/proxy.py index 1c5ee18c..74228b86 100644 --- a/pkg/utils/proxy.py +++ b/pkg/utils/proxy.py @@ -1,5 +1,8 @@ from __future__ import annotations +import os +import sys + from ..core import app @@ -14,17 +17,15 @@ class ProxyManager: self.forward_proxies = {} 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 ( - { - "http": config["openai_config"]["proxy"], - "https": config["openai_config"]["proxy"], - } - if "proxy" in config["openai_config"] - and (config["openai_config"]["proxy"] is not None) - else None - ) + if 'http' in self.ap.system_cfg.data['network-proxies']: + self.forward_proxies['http'] = self.ap.system_cfg.data['network-proxies']['http'] + if 'https' in self.ap.system_cfg.data['network-proxies']: + self.forward_proxies['https'] = self.ap.system_cfg.data['network-proxies']['https'] - def get_forward_proxies(self) -> str: + def get_forward_proxies(self) -> dict: return self.forward_proxies diff --git a/res/templates/cmdpriv-template.json b/res/templates/cmdpriv-template.json deleted file mode 100644 index 33603878..00000000 --- a/res/templates/cmdpriv-template.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "comment": "以下为命令权限,请设置到cmdpriv.json中。关于此功能的说明,请查看:https://github.com/RockChinQ/QChatGPT/wiki/%E5%8A%9F%E8%83%BD%E4%BD%BF%E7%94%A8#%E5%91%BD%E4%BB%A4%E6%9D%83%E9%99%90%E6%8E%A7%E5%88%B6", - "draw": 1, - "func": 1, - "plugin": 1, - "plugin.get": 2, - "plugin.update": 2, - "plugin.del": 2, - "plugin.off": 2, - "plugin.on": 2, - "default": 1, - "default.set": 2, - "del": 1, - "del.all": 1, - "delhst": 2, - "delhst.all": 2, - "last": 1, - "list": 1, - "next": 1, - "prompt": 1, - "resend": 1, - "reset": 1, - "cfg": 2, - "cmd": 1, - "help": 1, - "reload": 2, - "update": 2, - "usage": 1, - "version": 1 -} \ No newline at end of file diff --git a/plugins/__init__.py b/templates/__init__.py similarity index 100% rename from plugins/__init__.py rename to templates/__init__.py diff --git a/templates/command.json b/templates/command.json new file mode 100644 index 00000000..55360fc6 --- /dev/null +++ b/templates/command.json @@ -0,0 +1,3 @@ +{ + "privilege": {} +} \ No newline at end of file diff --git a/templates/pipeline.json b/templates/pipeline.json new file mode 100644 index 00000000..7284fdaf --- /dev/null +++ b/templates/pipeline.json @@ -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 + } + } +} \ No newline at end of file diff --git a/templates/platform.json b/templates/platform.json new file mode 100644 index 00000000..a25ba3e5 --- /dev/null +++ b/templates/platform.json @@ -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 +} \ No newline at end of file diff --git a/res/templates/plugin-setting-template.json b/templates/plugin-settings.json similarity index 100% rename from res/templates/plugin-setting-template.json rename to templates/plugin-settings.json diff --git a/templates/provider.json b/templates/provider.json new file mode 100644 index 00000000..23360277 --- /dev/null +++ b/templates/provider.json @@ -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获取帮助“。" + } +} \ No newline at end of file diff --git a/scenario/default-template.json b/templates/scenario-template.json similarity index 100% rename from scenario/default-template.json rename to templates/scenario-template.json diff --git a/res/templates/sensitive-template.json b/templates/sensitive-words.json similarity index 100% rename from res/templates/sensitive-template.json rename to templates/sensitive-words.json diff --git a/templates/system.json b/templates/system.json new file mode 100644 index 00000000..c7b0118e --- /dev/null +++ b/templates/system.json @@ -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" +} \ No newline at end of file diff --git a/test.html b/test.html deleted file mode 100644 index bdb9b804..00000000 --- a/test.html +++ /dev/null @@ -1,10 +0,0 @@ - -
-Test
-This is a test for QChatGPT.
- - \ No newline at end of file diff --git a/tips-custom-template.py b/tips-custom-template.py deleted file mode 100644 index 129f957f..00000000 --- a/tips-custom-template.py +++ /dev/null @@ -1,37 +0,0 @@ -import config -# ---------------------------------------------自定义提示语--------------------------------------------- - -# 消息处理出错时向用户发送的提示信息,仅当config.py中hide_exce_info_to_user为True时生效 -# 设置为空字符串时,不发送提示信息 -alter_tip_message = '[bot]err:出错了,请稍后再试' - -# drop策略时,超过限速均值时,丢弃的对话的提示信息,仅当config.py中rate_limitation_strategy为"drop"时生效 -# 若设置为空字符串,则不发送提示信息 -rate_limit_drop_tip = "本分钟对话次数超过限速次数,此对话被丢弃" - -# 只允许同时处理一条消息时,新消息被丢弃时的提示信息 -# 当config.py中的wait_last_done为False时生效 -# 若设置为空字符串,则不发送提示信息 -message_drop_tip = "[bot]当前有一条消息正在处理,请等待处理完成" - -# 命令 !help帮助消息 -help_message = """此机器人通过调用大型语言模型生成回复,不具有情感。 -你可以用自然语言与其交流,回复的消息中[GPT]开头的为模型生成的语言,[bot]开头的为程序提示。 -欢迎到github.com/RockChinQ/QChatGPT 给个star""" - -# 私聊消息超时提示 -reply_message = "[bot]err:请求超时" -# 群聊消息超时提示 -replys_message = "[bot]err:请求超时" - -# 命令权限不足提示 -command_admin_message = "[bot]err:权限不足: " -# 命令无效提示 -command_err_message = "[bot]err:命令不存在:" - -# 会话重置提示 -command_reset_message = "[bot]会话已重置" -command_reset_name_message = "[bot]会话已重置,使用场景预设:" - -# 会话自动重置时的提示 -session_auto_reset_message = "[bot]会话token超限,已自动重置,请重新发送消息" diff --git a/未命名.txt b/未命名.txt deleted file mode 100644 index ad396935..00000000 Binary files a/未命名.txt and /dev/null differ