mirror of
https://github.com/langbot-app/LangBot.git
synced 2026-06-02 03:55:55 +00:00
Merge pull request #677 from RockChinQ/refactor/asyncio/config
Refactor: 配置文件重构
This commit is contained in:
52
.github/workflows/update-override-all.yml
vendored
52
.github/workflows/update-override-all.yml
vendored
@@ -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
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -33,3 +33,4 @@ bard.json
|
||||
!/docker-compose.yaml
|
||||
res/instance_id.json
|
||||
.DS_Store
|
||||
/data
|
||||
15
Dockerfile
15
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" ]
|
||||
CMD [ "python", "start.py" ]
|
||||
Binary file not shown.
@@ -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] # 本项目交流群的群号,默认屏蔽,避免在交流群测试机器人
|
||||
@@ -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
|
||||
@@ -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
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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"""
|
||||
|
||||
|
||||
@@ -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,
|
||||
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 可查看命令列表'
|
||||
|
||||
|
||||
@@ -4,6 +4,9 @@ from . import model as file_model
|
||||
from .impls import pymodule, json as json_file
|
||||
|
||||
|
||||
managers: ConfigManager = []
|
||||
|
||||
|
||||
class ConfigManager:
|
||||
"""配置文件管理器"""
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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]:
|
||||
|
||||
@@ -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()
|
||||
)
|
||||
|
||||
|
||||
@@ -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")
|
||||
|
||||
|
||||
@@ -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 ''
|
||||
)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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}"
|
||||
)
|
||||
)
|
||||
|
||||
@@ -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=''
|
||||
)
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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的
|
||||
|
||||
@@ -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()
|
||||
)
|
||||
|
||||
@@ -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(' ')
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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']
|
||||
|
||||
|
||||
@@ -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([
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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
|
||||
)
|
||||
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
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
|
||||
}
|
||||
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获取帮助“。"
|
||||
}
|
||||
}
|
||||
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"
|
||||
}
|
||||
10
test.html
10
test.html
@@ -1,10 +0,0 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Test</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Test</h1>
|
||||
<p>Test</p>
|
||||
<p>This is a test for QChatGPT.</p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -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超限,已自动重置,请重新发送消息"
|
||||
Reference in New Issue
Block a user