mirror of
https://github.com/langbot-app/LangBot.git
synced 2026-06-02 12:05:54 +00:00
Compare commits
71 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3052510591 | ||
|
|
777a5617db | ||
|
|
e17c1087e9 | ||
|
|
633695175a | ||
|
|
9e78bf3d21 | ||
|
|
43aa68a55d | ||
|
|
b8308f8c57 | ||
|
|
466bfbddeb | ||
|
|
b6da07b225 | ||
|
|
2f2159239a | ||
|
|
67d1ca8a65 | ||
|
|
497a393e83 | ||
|
|
782c0e22ea | ||
|
|
2932fc6dfd | ||
|
|
0a9eab2113 | ||
|
|
50a673a8ec | ||
|
|
9e25d0f9e4 | ||
|
|
23cd7be711 | ||
|
|
025b9e33f1 | ||
|
|
bab2f64913 | ||
|
|
b00e09aa9c | ||
|
|
0b109fdc7a | ||
|
|
018fea2ddb | ||
|
|
f8a3cc4352 | ||
|
|
6ab853acc1 | ||
|
|
e825dea02f | ||
|
|
cf8740d16e | ||
|
|
9c4809e26f | ||
|
|
0a232fd9ef | ||
|
|
23016a0791 | ||
|
|
cdcc67ff23 | ||
|
|
92274bfc34 | ||
|
|
2fed6f61ba | ||
|
|
59b2cd26d2 | ||
|
|
f7b87e99d2 | ||
|
|
70bc985145 | ||
|
|
070dbe9108 | ||
|
|
a63fa6d955 | ||
|
|
c7703809b0 | ||
|
|
37eb74338f | ||
|
|
77d5585b7c | ||
|
|
6cab3ef029 | ||
|
|
820a7b78fc | ||
|
|
c51dffef3a | ||
|
|
983bc3da3c | ||
|
|
09be956a58 | ||
|
|
5eded50c53 | ||
|
|
6d8eebd314 | ||
|
|
19a0572b5f | ||
|
|
6272e98474 | ||
|
|
45042fe7d4 | ||
|
|
d85e840126 | ||
|
|
804889f1de | ||
|
|
919c996434 | ||
|
|
00823b3d62 | ||
|
|
af54efd24a | ||
|
|
b1c9b121f6 | ||
|
|
7b5649d153 | ||
|
|
52bf716d84 | ||
|
|
c149dd7b66 | ||
|
|
65d5a1ed63 | ||
|
|
5516754bbb | ||
|
|
08082f2ee3 | ||
|
|
8489266080 | ||
|
|
51c7e0b235 | ||
|
|
628b6b0bb4 | ||
|
|
7e024d860d | ||
|
|
c2f6273f70 | ||
|
|
96e401ec7b | ||
|
|
ae8ac65447 | ||
|
|
2d4f59f36e |
5
.gitignore
vendored
5
.gitignore
vendored
@@ -22,4 +22,7 @@ cmdpriv.json
|
|||||||
tips.py
|
tips.py
|
||||||
.venv
|
.venv
|
||||||
bin/
|
bin/
|
||||||
.vscode
|
.vscode
|
||||||
|
test_*
|
||||||
|
venv/
|
||||||
|
hugchat.json
|
||||||
17
README.md
17
README.md
@@ -7,7 +7,9 @@
|
|||||||
[English](README_en.md) | 简体中文
|
[English](README_en.md) | 简体中文
|
||||||
|
|
||||||
[](https://github.com/RockChinQ/QChatGPT/releases/latest)
|
[](https://github.com/RockChinQ/QChatGPT/releases/latest)
|
||||||
|

|
||||||
|
|
||||||
|
> 2023/4/27 正在对纯Python实现的QQ登录框架、YAML配置文件、异步编程等功能进行概念验证,欢迎体验[LightQChat](https://github.com/RockChinQ/LightQChat)项目
|
||||||
> 2023/4/24 支持使用go-cqhttp登录QQ,请查看[此文档](https://github.com/RockChinQ/QChatGPT/wiki/go-cqhttp%E9%85%8D%E7%BD%AE)
|
> 2023/4/24 支持使用go-cqhttp登录QQ,请查看[此文档](https://github.com/RockChinQ/QChatGPT/wiki/go-cqhttp%E9%85%8D%E7%BD%AE)
|
||||||
> 2023/3/18 现已支持GPT-4 API(内测),请查看`config-template.py`中的`completion_api_params`
|
> 2023/3/18 现已支持GPT-4 API(内测),请查看`config-template.py`中的`completion_api_params`
|
||||||
> 2023/3/15 逆向库已支持New Bing,使用方法查看[插件文档](https://github.com/RockChinQ/revLibs)
|
> 2023/3/15 逆向库已支持New Bing,使用方法查看[插件文档](https://github.com/RockChinQ/revLibs)
|
||||||
@@ -32,6 +34,7 @@
|
|||||||
- ChatGPT网页版GPT-3.5模型, 由[插件](https://github.com/RockChinQ/revLibs)接入
|
- ChatGPT网页版GPT-3.5模型, 由[插件](https://github.com/RockChinQ/revLibs)接入
|
||||||
- ChatGPT网页版GPT-4模型, 目前需要ChatGPT Plus订阅, 由[插件](https://github.com/RockChinQ/revLibs)接入
|
- ChatGPT网页版GPT-4模型, 目前需要ChatGPT Plus订阅, 由[插件](https://github.com/RockChinQ/revLibs)接入
|
||||||
- New Bing逆向库, 由[插件](https://github.com/RockChinQ/revLibs)接入
|
- New Bing逆向库, 由[插件](https://github.com/RockChinQ/revLibs)接入
|
||||||
|
- HuggingChat, 由[插件](https://github.com/RockChinQ/revLibs)接入, 仅支持英文
|
||||||
|
|
||||||
### 故事续写
|
### 故事续写
|
||||||
|
|
||||||
@@ -159,6 +162,9 @@
|
|||||||
|
|
||||||
### - 注册OpenAI账号
|
### - 注册OpenAI账号
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>点此查看步骤</summary>
|
||||||
|
|
||||||
> 若您要直接使用非OpenAI的模型(如New Bing),可跳过此步骤,直接进行之后的部署,完成后按照相关插件的文档进行配置即可
|
> 若您要直接使用非OpenAI的模型(如New Bing),可跳过此步骤,直接进行之后的部署,完成后按照相关插件的文档进行配置即可
|
||||||
|
|
||||||
参考以下文章自行注册
|
参考以下文章自行注册
|
||||||
@@ -169,6 +175,8 @@
|
|||||||
注册成功后请前往[个人中心查看](https://beta.openai.com/account/api-keys)api_key
|
注册成功后请前往[个人中心查看](https://beta.openai.com/account/api-keys)api_key
|
||||||
完成注册后,使用以下自动化或手动部署步骤
|
完成注册后,使用以下自动化或手动部署步骤
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
### - 自动化部署
|
### - 自动化部署
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
@@ -176,6 +184,8 @@
|
|||||||
|
|
||||||
#### Docker方式
|
#### Docker方式
|
||||||
|
|
||||||
|
> docker方式目前仅支持使用mirai登录,若您不**熟悉**docker的操作及相关知识,强烈建议您使用其他方式部署,我们**不会且难以**解决您主机上多个容器的连接问题。
|
||||||
|
|
||||||
请查看[此文档](res/docs/docker_deploy.md)
|
请查看[此文档](res/docs/docker_deploy.md)
|
||||||
由[@mikumifa](https://github.com/mikumifa)贡献
|
由[@mikumifa](https://github.com/mikumifa)贡献
|
||||||
|
|
||||||
@@ -280,7 +290,7 @@ python3 main.py
|
|||||||
|
|
||||||
### 更多
|
### 更多
|
||||||
|
|
||||||
欢迎提交新的插件
|
[插件列表](https://github.com/stars/RockChinQ/lists/qchatgpt-%E6%8F%92%E4%BB%B6),欢迎提出issue以提交新的插件
|
||||||
|
|
||||||
- [revLibs](https://github.com/RockChinQ/revLibs) - 将ChatGPT网页版接入此项目,关于[官方接口和网页版有什么区别](https://github.com/RockChinQ/QChatGPT/wiki/%E5%AE%98%E6%96%B9%E6%8E%A5%E5%8F%A3%E3%80%81ChatGPT%E7%BD%91%E9%A1%B5%E7%89%88%E3%80%81ChatGPT-API%E5%8C%BA%E5%88%AB)
|
- [revLibs](https://github.com/RockChinQ/revLibs) - 将ChatGPT网页版接入此项目,关于[官方接口和网页版有什么区别](https://github.com/RockChinQ/QChatGPT/wiki/%E5%AE%98%E6%96%B9%E6%8E%A5%E5%8F%A3%E3%80%81ChatGPT%E7%BD%91%E9%A1%B5%E7%89%88%E3%80%81ChatGPT-API%E5%8C%BA%E5%88%AB)
|
||||||
- [Switcher](https://github.com/RockChinQ/Switcher) - 支持通过指令切换使用的模型
|
- [Switcher](https://github.com/RockChinQ/Switcher) - 支持通过指令切换使用的模型
|
||||||
@@ -292,6 +302,7 @@ python3 main.py
|
|||||||
- [chordfish-k/QChartGPT_Emoticon_Plugin](https://github.com/chordfish-k/QChartGPT_Emoticon_Plugin) - 使机器人根据回复内容发送表情包
|
- [chordfish-k/QChartGPT_Emoticon_Plugin](https://github.com/chordfish-k/QChartGPT_Emoticon_Plugin) - 使机器人根据回复内容发送表情包
|
||||||
- [oliverkirk-sudo/ChatPoeBot](https://github.com/oliverkirk-sudo/ChatPoeBot) - 接入[Poe](https://poe.com/)上的机器人
|
- [oliverkirk-sudo/ChatPoeBot](https://github.com/oliverkirk-sudo/ChatPoeBot) - 接入[Poe](https://poe.com/)上的机器人
|
||||||
- [lieyanqzu/WeatherPlugin](https://github.com/lieyanqzu/WeatherPlugin) - 天气查询插件
|
- [lieyanqzu/WeatherPlugin](https://github.com/lieyanqzu/WeatherPlugin) - 天气查询插件
|
||||||
|
- [SysStatPlugin](https://github.com/RockChinQ/SysStatPlugin) - 查看系统状态
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
## 😘致谢
|
## 😘致谢
|
||||||
@@ -304,6 +315,6 @@ python3 main.py
|
|||||||
|
|
||||||
以及所有[贡献者](https://github.com/RockChinQ/QChatGPT/graphs/contributors)和其他为本项目提供支持的朋友们。
|
以及所有[贡献者](https://github.com/RockChinQ/QChatGPT/graphs/contributors)和其他为本项目提供支持的朋友们。
|
||||||
|
|
||||||
<!-- ## 👍赞赏
|
## 👍赞赏
|
||||||
|
|
||||||
<img alt="赞赏码" src="res/mm_reward_qrcode_1672840549070.png" width="400" height="400"/> -->
|
<img alt="赞赏码" src="res/mm_reward_qrcode_1672840549070.png" width="400" height="400"/>
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
English | [简体中文](README.md)
|
English | [简体中文](README.md)
|
||||||
|
|
||||||
[](https://github.com/RockChinQ/QChatGPT/releases/latest)
|
[](https://github.com/RockChinQ/QChatGPT/releases/latest)
|
||||||
|

|
||||||
|
|
||||||
- Refer to [Wiki](https://github.com/RockChinQ/QChatGPT/wiki) to get further information.
|
- Refer to [Wiki](https://github.com/RockChinQ/QChatGPT/wiki) to get further information.
|
||||||
- Official QQ group: 656285629
|
- Official QQ group: 656285629
|
||||||
@@ -27,6 +28,7 @@ English | [简体中文](README.md)
|
|||||||
- ChatGPT website edition (GPT-3.5), see [revLibs plugin](https://github.com/RockChinQ/revLibs)
|
- ChatGPT website edition (GPT-3.5), see [revLibs plugin](https://github.com/RockChinQ/revLibs)
|
||||||
- ChatGPT website edition (GPT-4), ChatGPT plus subscription required, see [revLibs plugin](https://github.com/RockChinQ/revLibs)
|
- ChatGPT website edition (GPT-4), ChatGPT plus subscription required, see [revLibs plugin](https://github.com/RockChinQ/revLibs)
|
||||||
- New Bing, see [revLibs plugin](https://github.com/RockChinQ/revLibs)
|
- New Bing, see [revLibs plugin](https://github.com/RockChinQ/revLibs)
|
||||||
|
- HuggingChat, see [revLibs plugin](https://github.com/RockChinQ/revLibs), English only
|
||||||
|
|
||||||
### Story
|
### Story
|
||||||
|
|
||||||
|
|||||||
@@ -195,6 +195,10 @@ encourage_sponsor_at_start = True
|
|||||||
# 注意:较大的prompt_submit_length会导致OpenAI账户额度消耗更快
|
# 注意:较大的prompt_submit_length会导致OpenAI账户额度消耗更快
|
||||||
prompt_submit_length = 2048
|
prompt_submit_length = 2048
|
||||||
|
|
||||||
|
# 是否在token超限报错时自动重置会话
|
||||||
|
# 可在tips.py中编辑提示语
|
||||||
|
auto_reset = True
|
||||||
|
|
||||||
# OpenAI补全API的参数
|
# OpenAI补全API的参数
|
||||||
# 请在下方填写模型,程序自动选择接口
|
# 请在下方填写模型,程序自动选择接口
|
||||||
# 现已支持的模型有:
|
# 现已支持的模型有:
|
||||||
@@ -241,6 +245,14 @@ process_message_timeout = 30
|
|||||||
# 回复消息时是否显示[GPT]前缀
|
# 回复消息时是否显示[GPT]前缀
|
||||||
show_prefix = False
|
show_prefix = False
|
||||||
|
|
||||||
|
# 回复前的强制延迟时间,降低机器人被腾讯风控概率
|
||||||
|
# *此机制对命令和消息、私聊及群聊均生效
|
||||||
|
# 每次处理时从以下的范围取一个随机秒数,
|
||||||
|
# 当此次消息处理时间低于此秒数时,将会强制延迟至此秒数
|
||||||
|
# 例如:[1.5, 3],则每次处理时会随机取一个1.5-3秒的随机数,若处理时间低于此随机数,则强制延迟至此随机秒数
|
||||||
|
# 若您不需要此功能,请将force_delay_range设置为[0, 0]
|
||||||
|
force_delay_range = [1.5, 3]
|
||||||
|
|
||||||
# 应用长消息处理策略的阈值
|
# 应用长消息处理策略的阈值
|
||||||
# 当回复消息长度超过此值时,将使用长消息处理策略
|
# 当回复消息长度超过此值时,将使用长消息处理策略
|
||||||
blob_message_threshold = 256
|
blob_message_threshold = 256
|
||||||
|
|||||||
254
main.py
254
main.py
@@ -48,8 +48,8 @@ def init_db():
|
|||||||
def ensure_dependencies():
|
def ensure_dependencies():
|
||||||
import pkg.utils.pkgmgr as pkgmgr
|
import pkg.utils.pkgmgr as pkgmgr
|
||||||
pkgmgr.run_pip(["install", "openai", "Pillow", "nakuru-project-idk", "--upgrade",
|
pkgmgr.run_pip(["install", "openai", "Pillow", "nakuru-project-idk", "--upgrade",
|
||||||
"-i", "https://pypi.douban.com/simple/",
|
"-i", "https://pypi.tuna.tsinghua.edu.cn/simple",
|
||||||
"--trusted-host", "pypi.douban.com"])
|
"--trusted-host", "pypi.tuna.tsinghua.edu.cn"])
|
||||||
|
|
||||||
|
|
||||||
known_exception_caught = False
|
known_exception_caught = False
|
||||||
@@ -134,127 +134,139 @@ def start(first_time_init=False):
|
|||||||
|
|
||||||
known_exception_caught = False
|
known_exception_caught = False
|
||||||
try:
|
try:
|
||||||
|
|
||||||
sh = reset_logging()
|
|
||||||
pkg.utils.context.context['logger_handler'] = sh
|
|
||||||
|
|
||||||
# 检查是否设置了管理员
|
|
||||||
if not (hasattr(config, 'admin_qq') and config.admin_qq != 0):
|
|
||||||
# logging.warning("未设置管理员QQ,管理员权限指令及运行告警将无法使用,如需设置请修改config.py中的admin_qq字段")
|
|
||||||
while True:
|
|
||||||
try:
|
|
||||||
config.admin_qq = int(input("未设置管理员QQ,管理员权限指令及运行告警将无法使用,请输入管理员QQ号: "))
|
|
||||||
# 写入到文件
|
|
||||||
|
|
||||||
# 读取文件
|
|
||||||
config_file_str = ""
|
|
||||||
with open("config.py", "r", encoding="utf-8") as f:
|
|
||||||
config_file_str = f.read()
|
|
||||||
# 替换
|
|
||||||
config_file_str = config_file_str.replace("admin_qq = 0", "admin_qq = " + str(config.admin_qq))
|
|
||||||
# 写入
|
|
||||||
with open("config.py", "w", encoding="utf-8") as f:
|
|
||||||
f.write(config_file_str)
|
|
||||||
|
|
||||||
print("管理员QQ已设置,如需修改请修改config.py中的admin_qq字段")
|
|
||||||
time.sleep(4)
|
|
||||||
break
|
|
||||||
except ValueError:
|
|
||||||
print("请输入数字")
|
|
||||||
|
|
||||||
import pkg.openai.manager
|
|
||||||
import pkg.database.manager
|
|
||||||
import pkg.openai.session
|
|
||||||
import pkg.qqbot.manager
|
|
||||||
import pkg.openai.dprompt
|
|
||||||
import pkg.qqbot.cmds.aamgr
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
pkg.openai.dprompt.register_all()
|
|
||||||
pkg.qqbot.cmds.aamgr.register_all()
|
sh = reset_logging()
|
||||||
pkg.qqbot.cmds.aamgr.apply_privileges()
|
pkg.utils.context.context['logger_handler'] = sh
|
||||||
|
|
||||||
|
# 检查是否设置了管理员
|
||||||
|
if not (hasattr(config, 'admin_qq') and config.admin_qq != 0):
|
||||||
|
# logging.warning("未设置管理员QQ,管理员权限指令及运行告警将无法使用,如需设置请修改config.py中的admin_qq字段")
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
config.admin_qq = int(input("未设置管理员QQ,管理员权限指令及运行告警将无法使用,请输入管理员QQ号: "))
|
||||||
|
# 写入到文件
|
||||||
|
|
||||||
|
# 读取文件
|
||||||
|
config_file_str = ""
|
||||||
|
with open("config.py", "r", encoding="utf-8") as f:
|
||||||
|
config_file_str = f.read()
|
||||||
|
# 替换
|
||||||
|
config_file_str = config_file_str.replace("admin_qq = 0", "admin_qq = " + str(config.admin_qq))
|
||||||
|
# 写入
|
||||||
|
with open("config.py", "w", encoding="utf-8") as f:
|
||||||
|
f.write(config_file_str)
|
||||||
|
|
||||||
|
print("管理员QQ已设置,如需修改请修改config.py中的admin_qq字段")
|
||||||
|
time.sleep(4)
|
||||||
|
break
|
||||||
|
except ValueError:
|
||||||
|
print("请输入数字")
|
||||||
|
|
||||||
|
import pkg.openai.manager
|
||||||
|
import pkg.database.manager
|
||||||
|
import pkg.openai.session
|
||||||
|
import pkg.qqbot.manager
|
||||||
|
import pkg.openai.dprompt
|
||||||
|
import pkg.qqbot.cmds.aamgr
|
||||||
|
|
||||||
|
try:
|
||||||
|
pkg.openai.dprompt.register_all()
|
||||||
|
pkg.qqbot.cmds.aamgr.register_all()
|
||||||
|
pkg.qqbot.cmds.aamgr.apply_privileges()
|
||||||
|
except Exception as e:
|
||||||
|
logging.error(e)
|
||||||
|
traceback.print_exc()
|
||||||
|
|
||||||
|
# 配置openai api_base
|
||||||
|
if "reverse_proxy" in config.openai_config and config.openai_config["reverse_proxy"] is not None:
|
||||||
|
import openai
|
||||||
|
openai.api_base = config.openai_config["reverse_proxy"]
|
||||||
|
|
||||||
|
# 主启动流程
|
||||||
|
database = pkg.database.manager.DatabaseManager()
|
||||||
|
|
||||||
|
database.initialize_database()
|
||||||
|
|
||||||
|
openai_interact = pkg.openai.manager.OpenAIInteract(config.openai_config['api_key'])
|
||||||
|
|
||||||
|
# 加载所有未超时的session
|
||||||
|
pkg.openai.session.load_sessions()
|
||||||
|
|
||||||
|
# 初始化qq机器人
|
||||||
|
qqbot = pkg.qqbot.manager.QQBotManager(first_time_init=first_time_init)
|
||||||
|
|
||||||
|
# 加载插件
|
||||||
|
import pkg.plugin.host
|
||||||
|
pkg.plugin.host.load_plugins()
|
||||||
|
|
||||||
|
pkg.plugin.host.initialize_plugins()
|
||||||
|
|
||||||
|
if first_time_init: # 不是热重载之后的启动,则启动新的bot线程
|
||||||
|
|
||||||
|
import mirai.exceptions
|
||||||
|
|
||||||
|
def run_bot_wrapper():
|
||||||
|
global known_exception_caught
|
||||||
|
try:
|
||||||
|
logging.info("使用账号: {}".format(qqbot.bot_account_id))
|
||||||
|
qqbot.adapter.run_sync()
|
||||||
|
except TypeError as e:
|
||||||
|
if str(e).__contains__("argument 'debug'"):
|
||||||
|
logging.error(
|
||||||
|
"连接bot失败:{}, 解决方案: https://github.com/RockChinQ/QChatGPT/issues/82".format(e))
|
||||||
|
known_exception_caught = True
|
||||||
|
elif str(e).__contains__("As of 3.10, the *loop*"):
|
||||||
|
logging.error(
|
||||||
|
"Websockets版本过低:{}, 解决方案: https://github.com/RockChinQ/QChatGPT/issues/5".format(e))
|
||||||
|
known_exception_caught = True
|
||||||
|
|
||||||
|
except websockets.exceptions.InvalidStatus as e:
|
||||||
|
logging.error(
|
||||||
|
"mirai-api-http端口无法使用:{}, 解决方案: https://github.com/RockChinQ/QChatGPT/issues/22".format(
|
||||||
|
e))
|
||||||
|
known_exception_caught = True
|
||||||
|
except mirai.exceptions.NetworkError as e:
|
||||||
|
logging.error("连接mirai-api-http失败:{}, 请检查是否已按照文档启动mirai".format(e))
|
||||||
|
known_exception_caught = True
|
||||||
|
except Exception as e:
|
||||||
|
if str(e).__contains__("404"):
|
||||||
|
logging.error(
|
||||||
|
"mirai-api-http端口无法使用:{}, 解决方案: https://github.com/RockChinQ/QChatGPT/issues/22".format(
|
||||||
|
e))
|
||||||
|
known_exception_caught = True
|
||||||
|
elif str(e).__contains__("signal only works in main thread"):
|
||||||
|
logging.error(
|
||||||
|
"hypercorn异常:{}, 解决方案: https://github.com/RockChinQ/QChatGPT/issues/86".format(
|
||||||
|
e))
|
||||||
|
known_exception_caught = True
|
||||||
|
elif str(e).__contains__("did not receive a valid HTTP"):
|
||||||
|
logging.error(
|
||||||
|
"mirai-api-http端口无法使用:{}, 解决方案: https://github.com/RockChinQ/QChatGPT/issues/22".format(
|
||||||
|
e))
|
||||||
|
else:
|
||||||
|
import traceback
|
||||||
|
traceback.print_exc()
|
||||||
|
logging.error(
|
||||||
|
"捕捉到未知异常:{}, 请前往 https://github.com/RockChinQ/QChatGPT/issues 查找或提issue".format(e))
|
||||||
|
known_exception_caught = True
|
||||||
|
raise e
|
||||||
|
finally:
|
||||||
|
time.sleep(12)
|
||||||
|
threading.Thread(
|
||||||
|
target=run_bot_wrapper
|
||||||
|
).start()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.error(e)
|
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
|
if isinstance(e, KeyboardInterrupt):
|
||||||
# 配置openai api_base
|
logging.info("程序被用户中止")
|
||||||
if "reverse_proxy" in config.openai_config and config.openai_config["reverse_proxy"] is not None:
|
sys.exit(0)
|
||||||
import openai
|
elif isinstance(e, SyntaxError):
|
||||||
openai.api_base = config.openai_config["reverse_proxy"]
|
logging.error("配置文件存在语法错误,请检查配置文件:\n1. 是否存在中文符号\n2. 是否已按照文件中的说明填写正确")
|
||||||
|
sys.exit(1)
|
||||||
# 主启动流程
|
else:
|
||||||
database = pkg.database.manager.DatabaseManager()
|
logging.error("初始化失败:{}".format(e))
|
||||||
|
sys.exit(1)
|
||||||
database.initialize_database()
|
|
||||||
|
|
||||||
openai_interact = pkg.openai.manager.OpenAIInteract(config.openai_config['api_key'])
|
|
||||||
|
|
||||||
# 加载所有未超时的session
|
|
||||||
pkg.openai.session.load_sessions()
|
|
||||||
|
|
||||||
# 初始化qq机器人
|
|
||||||
qqbot = pkg.qqbot.manager.QQBotManager(first_time_init=first_time_init)
|
|
||||||
|
|
||||||
# 加载插件
|
|
||||||
import pkg.plugin.host
|
|
||||||
pkg.plugin.host.load_plugins()
|
|
||||||
|
|
||||||
pkg.plugin.host.initialize_plugins()
|
|
||||||
|
|
||||||
if first_time_init: # 不是热重载之后的启动,则启动新的bot线程
|
|
||||||
|
|
||||||
import mirai.exceptions
|
|
||||||
|
|
||||||
def run_bot_wrapper():
|
|
||||||
global known_exception_caught
|
|
||||||
try:
|
|
||||||
logging.info("使用账号: {}".format(qqbot.bot_account_id))
|
|
||||||
qqbot.adapter.run_sync()
|
|
||||||
except TypeError as e:
|
|
||||||
if str(e).__contains__("argument 'debug'"):
|
|
||||||
logging.error(
|
|
||||||
"连接bot失败:{}, 解决方案: https://github.com/RockChinQ/QChatGPT/issues/82".format(e))
|
|
||||||
known_exception_caught = True
|
|
||||||
elif str(e).__contains__("As of 3.10, the *loop*"):
|
|
||||||
logging.error(
|
|
||||||
"Websockets版本过低:{}, 解决方案: https://github.com/RockChinQ/QChatGPT/issues/5".format(e))
|
|
||||||
known_exception_caught = True
|
|
||||||
|
|
||||||
except websockets.exceptions.InvalidStatus as e:
|
|
||||||
logging.error(
|
|
||||||
"mirai-api-http端口无法使用:{}, 解决方案: https://github.com/RockChinQ/QChatGPT/issues/22".format(
|
|
||||||
e))
|
|
||||||
known_exception_caught = True
|
|
||||||
except mirai.exceptions.NetworkError as e:
|
|
||||||
logging.error("连接mirai-api-http失败:{}, 请检查是否已按照文档启动mirai".format(e))
|
|
||||||
known_exception_caught = True
|
|
||||||
except Exception as e:
|
|
||||||
if str(e).__contains__("404"):
|
|
||||||
logging.error(
|
|
||||||
"mirai-api-http端口无法使用:{}, 解决方案: https://github.com/RockChinQ/QChatGPT/issues/22".format(
|
|
||||||
e))
|
|
||||||
known_exception_caught = True
|
|
||||||
elif str(e).__contains__("signal only works in main thread"):
|
|
||||||
logging.error(
|
|
||||||
"hypercorn异常:{}, 解决方案: https://github.com/RockChinQ/QChatGPT/issues/86".format(
|
|
||||||
e))
|
|
||||||
known_exception_caught = True
|
|
||||||
elif str(e).__contains__("did not receive a valid HTTP"):
|
|
||||||
logging.error(
|
|
||||||
"mirai-api-http端口无法使用:{}, 解决方案: https://github.com/RockChinQ/QChatGPT/issues/22".format(
|
|
||||||
e))
|
|
||||||
else:
|
|
||||||
import traceback
|
|
||||||
traceback.print_exc()
|
|
||||||
logging.error(
|
|
||||||
"捕捉到未知异常:{}, 请前往 https://github.com/RockChinQ/QChatGPT/issues 查找或提issue".format(e))
|
|
||||||
known_exception_caught = True
|
|
||||||
raise e
|
|
||||||
finally:
|
|
||||||
time.sleep(12)
|
|
||||||
threading.Thread(
|
|
||||||
target=run_bot_wrapper
|
|
||||||
).start()
|
|
||||||
finally:
|
finally:
|
||||||
# 判断若是Windows,输出选择模式可能会暂停程序的警告
|
# 判断若是Windows,输出选择模式可能会暂停程序的警告
|
||||||
if os.name == 'nt':
|
if os.name == 'nt':
|
||||||
@@ -268,7 +280,7 @@ def start(first_time_init=False):
|
|||||||
import config
|
import config
|
||||||
if config.msg_source_adapter == "yirimirai":
|
if config.msg_source_adapter == "yirimirai":
|
||||||
logging.info("QQ: {}, MAH: {}".format(config.mirai_http_api_config['qq'], config.mirai_http_api_config['host']+":"+str(config.mirai_http_api_config['port'])))
|
logging.info("QQ: {}, MAH: {}".format(config.mirai_http_api_config['qq'], config.mirai_http_api_config['host']+":"+str(config.mirai_http_api_config['port'])))
|
||||||
logging.critical('程序启动完成,如长时间未显示 "成功登录到账号xxxxx" ,并且不回复消息,请查看 '
|
logging.critical('程序启动完成,如长时间未显示 "成功登录到账号xxxxx" ,并且不回复消息,解决办法(请勿到群里问): '
|
||||||
'https://github.com/RockChinQ/QChatGPT/issues/37')
|
'https://github.com/RockChinQ/QChatGPT/issues/37')
|
||||||
elif config.msg_source_adapter == 'nakuru':
|
elif config.msg_source_adapter == 'nakuru':
|
||||||
logging.info("host: {}, port: {}, http_port: {}".format(config.nakuru_config['host'], config.nakuru_config['port'], config.nakuru_config['http_port']))
|
logging.info("host: {}, port: {}, http_port: {}".format(config.nakuru_config['host'], config.nakuru_config['port'], config.nakuru_config['http_port']))
|
||||||
|
|||||||
@@ -53,6 +53,7 @@
|
|||||||
"inappropriate_message_tips": "[百度云]请珍惜机器人,当前返回内容不合规",
|
"inappropriate_message_tips": "[百度云]请珍惜机器人,当前返回内容不合规",
|
||||||
"encourage_sponsor_at_start": true,
|
"encourage_sponsor_at_start": true,
|
||||||
"prompt_submit_length": 2048,
|
"prompt_submit_length": 2048,
|
||||||
|
"auto_reset": true,
|
||||||
"completion_api_params": {
|
"completion_api_params": {
|
||||||
"model": "gpt-3.5-turbo",
|
"model": "gpt-3.5-turbo",
|
||||||
"temperature": 0.9,
|
"temperature": 0.9,
|
||||||
@@ -67,6 +68,10 @@
|
|||||||
"include_image_description": true,
|
"include_image_description": true,
|
||||||
"process_message_timeout": 30,
|
"process_message_timeout": 30,
|
||||||
"show_prefix": false,
|
"show_prefix": false,
|
||||||
|
"force_delay_range": [
|
||||||
|
1.5,
|
||||||
|
3
|
||||||
|
],
|
||||||
"blob_message_threshold": 256,
|
"blob_message_threshold": 256,
|
||||||
"blob_message_strategy": "forward",
|
"blob_message_strategy": "forward",
|
||||||
"wait_last_done": true,
|
"wait_last_done": true,
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ def load_sessions():
|
|||||||
|
|
||||||
|
|
||||||
# 获取指定名称的session,如果不存在则创建一个新的
|
# 获取指定名称的session,如果不存在则创建一个新的
|
||||||
def get_session(session_name: str):
|
def get_session(session_name: str) -> 'Session':
|
||||||
global sessions
|
global sessions
|
||||||
if session_name not in sessions:
|
if session_name not in sessions:
|
||||||
sessions[session_name] = Session(session_name)
|
sessions[session_name] = Session(session_name)
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import sys
|
|||||||
import shutil
|
import shutil
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
|
import pkg.utils.updater as updater
|
||||||
import pkg.utils.context as context
|
import pkg.utils.context as context
|
||||||
import pkg.plugin.switch as switch
|
import pkg.plugin.switch as switch
|
||||||
import pkg.plugin.settings as settings
|
import pkg.plugin.settings as settings
|
||||||
@@ -79,7 +80,7 @@ def walk_plugin_path(module, prefix='', path_prefix=''):
|
|||||||
__current_module_path__ = "plugins/"+path_prefix + item.name + '.py'
|
__current_module_path__ = "plugins/"+path_prefix + item.name + '.py'
|
||||||
|
|
||||||
importlib.import_module(module.__name__ + '.' + item.name)
|
importlib.import_module(module.__name__ + '.' + item.name)
|
||||||
logging.info('加载模块: plugins/{} 成功'.format(path_prefix + item.name + '.py'))
|
logging.debug('加载模块: plugins/{} 成功'.format(path_prefix + item.name + '.py'))
|
||||||
except:
|
except:
|
||||||
logging.error('加载模块: plugins/{} 失败: {}'.format(path_prefix + item.name + '.py', sys.exc_info()))
|
logging.error('加载模块: plugins/{} 失败: {}'.format(path_prefix + item.name + '.py', sys.exc_info()))
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
@@ -177,6 +178,43 @@ def uninstall_plugin(plugin_name: str) -> str:
|
|||||||
return "plugins/"+plugin_path
|
return "plugins/"+plugin_path
|
||||||
|
|
||||||
|
|
||||||
|
def update_plugin(plugin_name: str):
|
||||||
|
"""更新插件"""
|
||||||
|
# 检查是否有远程地址记录
|
||||||
|
target_plugin_dir = "plugins/" + __plugins__[plugin_name]['path'].replace("\\", "/").split("plugins/")[1].split("/")[0]
|
||||||
|
|
||||||
|
remote_url = updater.get_remote_url(target_plugin_dir)
|
||||||
|
if remote_url == "https://github.com/RockChinQ/QChatGPT" or remote_url == "https://gitee.com/RockChin/QChatGPT" \
|
||||||
|
or remote_url == "" or remote_url is None or remote_url == "http://github.com/RockChinQ/QChatGPT" or remote_url == "http://gitee.com/RockChin/QChatGPT":
|
||||||
|
raise Exception("插件没有远程地址记录,无法更新")
|
||||||
|
|
||||||
|
# 把远程clone到temp/plugins/update/插件名
|
||||||
|
logging.info("克隆插件储存库: {}".format(remote_url))
|
||||||
|
|
||||||
|
from dulwich import porcelain
|
||||||
|
clone_target_dir = "temp/plugins/update/"+target_plugin_dir.split("/")[-1]+"/"
|
||||||
|
|
||||||
|
if os.path.exists(clone_target_dir):
|
||||||
|
shutil.rmtree(clone_target_dir)
|
||||||
|
|
||||||
|
if not os.path.exists(clone_target_dir):
|
||||||
|
os.makedirs(clone_target_dir)
|
||||||
|
repo = porcelain.clone(remote_url, clone_target_dir, checkout=True)
|
||||||
|
|
||||||
|
# 检查此目录是否包含requirements.txt
|
||||||
|
if os.path.exists(clone_target_dir+"requirements.txt"):
|
||||||
|
logging.info("检测到requirements.txt,正在安装依赖")
|
||||||
|
import pkg.utils.pkgmgr
|
||||||
|
pkg.utils.pkgmgr.install_requirements(clone_target_dir+"requirements.txt")
|
||||||
|
|
||||||
|
import pkg.utils.log as log
|
||||||
|
log.reset_logging()
|
||||||
|
|
||||||
|
# 将temp/plugins/update/插件名 覆盖到 plugins/插件名
|
||||||
|
shutil.rmtree(target_plugin_dir)
|
||||||
|
|
||||||
|
shutil.copytree(clone_target_dir, target_plugin_dir)
|
||||||
|
|
||||||
class EventContext:
|
class EventContext:
|
||||||
"""事件上下文"""
|
"""事件上下文"""
|
||||||
eid = 0
|
eid = 0
|
||||||
@@ -344,3 +382,6 @@ class PluginHost:
|
|||||||
event_context.__return_value__))
|
event_context.__return_value__))
|
||||||
|
|
||||||
return event_context
|
return event_context
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
pass
|
||||||
|
|||||||
@@ -260,8 +260,8 @@ def execute(context: Context) -> list:
|
|||||||
|
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
logging.debug('执行指令: {}'.format(path))
|
|
||||||
node = __command_list__[path]
|
node = __command_list__[path]
|
||||||
|
logging.debug('执行指令: {}'.format(path))
|
||||||
|
|
||||||
# 检查权限
|
# 检查权限
|
||||||
if ctx.privilege < node['privilege']:
|
if ctx.privilege < node['privilege']:
|
||||||
|
|||||||
@@ -97,37 +97,34 @@ class PluginUpdateCommand(AbstractCommandNode):
|
|||||||
plugin_list = plugin_host.__plugins__
|
plugin_list = plugin_host.__plugins__
|
||||||
|
|
||||||
reply = []
|
reply = []
|
||||||
def closure():
|
|
||||||
try:
|
|
||||||
import pkg.utils.context
|
|
||||||
updated = []
|
|
||||||
for key in plugin_list:
|
|
||||||
plugin = plugin_list[key]
|
|
||||||
if updater.is_repo("/".join(plugin['path'].split('/')[:-1])):
|
|
||||||
success = updater.pull_latest("/".join(plugin['path'].split('/')[:-1]))
|
|
||||||
if success:
|
|
||||||
updated.append(plugin['name'])
|
|
||||||
|
|
||||||
# 检查是否有requirements.txt
|
if len(ctx.crt_params) > 0:
|
||||||
pkg.utils.context.get_qqbot_manager().notify_admin("正在安装依赖...")
|
def closure():
|
||||||
for key in plugin_list:
|
try:
|
||||||
plugin = plugin_list[key]
|
import pkg.utils.context
|
||||||
if os.path.exists("/".join(plugin['path'].split('/')[:-1])+"/requirements.txt"):
|
|
||||||
logging.info("{}检测到requirements.txt,安装依赖".format(plugin['name']))
|
updated = []
|
||||||
import pkg.utils.pkgmgr
|
|
||||||
pkg.utils.pkgmgr.install_requirements("/".join(plugin['path'].split('/')[:-1])+"/requirements.txt")
|
|
||||||
|
|
||||||
import pkg.utils.log as log
|
if ctx.crt_params[0] == 'all':
|
||||||
log.reset_logging()
|
for key in plugin_list:
|
||||||
|
plugin_host.update_plugin(key)
|
||||||
|
updated.append(key)
|
||||||
|
else:
|
||||||
|
if ctx.crt_params[0] in plugin_list:
|
||||||
|
plugin_host.update_plugin(ctx.crt_params[0])
|
||||||
|
updated.append(ctx.crt_params[0])
|
||||||
|
else:
|
||||||
|
raise Exception("未找到插件: {}".format(ctx.crt_params[0]))
|
||||||
|
|
||||||
pkg.utils.context.get_qqbot_manager().notify_admin("已更新插件: {}".format(", ".join(updated)))
|
pkg.utils.context.get_qqbot_manager().notify_admin("已更新插件: {}, 请发送 !reload 重载插件".format(", ".join(updated)))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.error("插件更新失败:{}".format(e))
|
logging.error("插件更新失败:{}".format(e))
|
||||||
pkg.utils.context.get_qqbot_manager().notify_admin("插件更新失败:{} 请尝试手动更新插件".format(e))
|
pkg.utils.context.get_qqbot_manager().notify_admin("插件更新失败:{} 请尝试手动更新插件".format(e))
|
||||||
|
|
||||||
|
reply = ["[bot]正在更新插件,请勿重复发起..."]
|
||||||
threading.Thread(target=closure).start()
|
threading.Thread(target=closure).start()
|
||||||
reply = ["[bot]正在更新所有插件,请勿重复发起..."]
|
else:
|
||||||
|
reply = ["[bot]请指定要更新的插件, 或使用 !plugin update all 更新所有插件"]
|
||||||
return True, reply
|
return True, reply
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ def config_operation(cmd, params):
|
|||||||
config = pkg.utils.context.get_config()
|
config = pkg.utils.context.get_config()
|
||||||
reply_str = ""
|
reply_str = ""
|
||||||
if len(params) == 0:
|
if len(params) == 0:
|
||||||
reply = ["[bot]err:请输入配置项"]
|
reply = ["[bot]err:请输入!cmd cfg查看使用方法"]
|
||||||
else:
|
else:
|
||||||
cfg_name = params[0]
|
cfg_name = params[0]
|
||||||
if cfg_name == 'all':
|
if cfg_name == 'all':
|
||||||
@@ -26,45 +26,61 @@ def config_operation(cmd, params):
|
|||||||
else:
|
else:
|
||||||
reply_str += "{}: {}\n".format(cfg, getattr(config, cfg))
|
reply_str += "{}: {}\n".format(cfg, getattr(config, cfg))
|
||||||
reply = [reply_str]
|
reply = [reply_str]
|
||||||
elif cfg_name in dir(config):
|
|
||||||
if len(params) == 1:
|
|
||||||
# 按照配置项类型进行格式化
|
|
||||||
if isinstance(getattr(config, cfg_name), str):
|
|
||||||
reply_str = "[bot]配置项{}: \"{}\"\n".format(cfg_name, getattr(config, cfg_name))
|
|
||||||
elif isinstance(getattr(config, cfg_name), dict):
|
|
||||||
reply_str = "[bot]配置项{}: {}\n".format(cfg_name,
|
|
||||||
json.dumps(getattr(config, cfg_name),
|
|
||||||
ensure_ascii=False, indent=4))
|
|
||||||
else:
|
|
||||||
reply_str = "[bot]配置项{}: {}\n".format(cfg_name, getattr(config, cfg_name))
|
|
||||||
reply = [reply_str]
|
|
||||||
else:
|
|
||||||
cfg_value = " ".join(params[1:])
|
|
||||||
# 类型转换,如果是json则转换为字典
|
|
||||||
if cfg_value == 'true':
|
|
||||||
cfg_value = True
|
|
||||||
elif cfg_value == 'false':
|
|
||||||
cfg_value = False
|
|
||||||
elif cfg_value.isdigit():
|
|
||||||
cfg_value = int(cfg_value)
|
|
||||||
elif cfg_value.startswith('{') and cfg_value.endswith('}'):
|
|
||||||
cfg_value = json.loads(cfg_value)
|
|
||||||
else:
|
|
||||||
try:
|
|
||||||
cfg_value = float(cfg_value)
|
|
||||||
except ValueError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
# 检查类型是否匹配
|
|
||||||
if isinstance(getattr(config, cfg_name), type(cfg_value)):
|
|
||||||
setattr(config, cfg_name, cfg_value)
|
|
||||||
pkg.utils.context.set_config(config)
|
|
||||||
reply = ["[bot]配置项{}修改成功".format(cfg_name)]
|
|
||||||
else:
|
|
||||||
reply = ["[bot]err:配置项{}类型不匹配".format(cfg_name)]
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
reply = ["[bot]err:未找到配置项 {}".format(cfg_name)]
|
cfg_entry_path = cfg_name.split('.')
|
||||||
|
|
||||||
|
try:
|
||||||
|
if len(params) == 1:
|
||||||
|
cfg_entry = getattr(config, 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)
|
||||||
|
reply = [reply_str]
|
||||||
|
else:
|
||||||
|
cfg_value = " ".join(params[1:])
|
||||||
|
# 类型转换,如果是json则转换为字典
|
||||||
|
# if cfg_value == 'true':
|
||||||
|
# cfg_value = True
|
||||||
|
# elif cfg_value == 'false':
|
||||||
|
# cfg_value = False
|
||||||
|
# elif cfg_value.isdigit():
|
||||||
|
# cfg_value = int(cfg_value)
|
||||||
|
# elif cfg_value.startswith('{') and cfg_value.endswith('}'):
|
||||||
|
# cfg_value = json.loads(cfg_value)
|
||||||
|
# else:
|
||||||
|
# try:
|
||||||
|
# cfg_value = float(cfg_value)
|
||||||
|
# except ValueError:
|
||||||
|
# pass
|
||||||
|
cfg_value = eval(cfg_value)
|
||||||
|
|
||||||
|
cfg_entry = getattr(config, 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
|
||||||
|
reply = ["[bot]配置项{}修改成功".format(cfg_name)]
|
||||||
|
else:
|
||||||
|
reply = ["[bot]err:配置项{}类型不匹配".format(cfg_name)]
|
||||||
|
else:
|
||||||
|
setattr(config, cfg_entry_path[0], cfg_value)
|
||||||
|
reply = ["[bot]配置项{}修改成功".format(cfg_name)]
|
||||||
|
except AttributeError:
|
||||||
|
reply = ["[bot]err:未找到配置项 {}".format(cfg_name)]
|
||||||
|
except ValueError:
|
||||||
|
reply = ["[bot]err:未找到配置项 {}".format(cfg_name)]
|
||||||
|
# else:
|
||||||
|
# reply = ["[bot]err:未找到配置项 {}".format(cfg_name)]
|
||||||
|
|
||||||
return reply
|
return reply
|
||||||
|
|
||||||
|
|||||||
@@ -102,6 +102,9 @@ class QQBotManager:
|
|||||||
|
|
||||||
enable_banlist = False
|
enable_banlist = False
|
||||||
|
|
||||||
|
enable_private = True
|
||||||
|
enable_group = True
|
||||||
|
|
||||||
ban_person = []
|
ban_person = []
|
||||||
ban_group = []
|
ban_group = []
|
||||||
|
|
||||||
@@ -128,6 +131,7 @@ class QQBotManager:
|
|||||||
self.bot_account_id = self.adapter.bot_account_id
|
self.bot_account_id = self.adapter.bot_account_id
|
||||||
else:
|
else:
|
||||||
self.adapter = pkg.utils.context.get_qqbot_manager().adapter
|
self.adapter = pkg.utils.context.get_qqbot_manager().adapter
|
||||||
|
self.bot_account_id = pkg.utils.context.get_qqbot_manager().bot_account_id
|
||||||
|
|
||||||
pkg.utils.context.set_qqbot_manager(self)
|
pkg.utils.context.set_qqbot_manager(self)
|
||||||
|
|
||||||
@@ -241,6 +245,11 @@ class QQBotManager:
|
|||||||
self.ban_group = banlist.group
|
self.ban_group = banlist.group
|
||||||
logging.info("加载禁用列表: person: {}, group: {}".format(self.ban_person, self.ban_group))
|
logging.info("加载禁用列表: person: {}, group: {}".format(self.ban_person, self.ban_group))
|
||||||
|
|
||||||
|
if hasattr(banlist, "enable_private"):
|
||||||
|
self.enable_private = banlist.enable_private
|
||||||
|
if hasattr(banlist, "enable_group"):
|
||||||
|
self.enable_group = banlist.enable_group
|
||||||
|
|
||||||
config = pkg.utils.context.get_config()
|
config = pkg.utils.context.get_config()
|
||||||
if os.path.exists("sensitive.json") \
|
if os.path.exists("sensitive.json") \
|
||||||
and config.sensitive_word_filter is not None \
|
and config.sensitive_word_filter is not None \
|
||||||
@@ -268,7 +277,9 @@ class QQBotManager:
|
|||||||
import config
|
import config
|
||||||
reply = ''
|
reply = ''
|
||||||
|
|
||||||
if event.sender.id == self.bot_account_id:
|
if not self.enable_private:
|
||||||
|
logging.debug("已在banlist.py中禁用所有私聊")
|
||||||
|
elif event.sender.id == self.bot_account_id:
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
if Image in event.message_chain:
|
if Image in event.message_chain:
|
||||||
@@ -341,8 +352,10 @@ class QQBotManager:
|
|||||||
replys = [tips_custom.replys_message]
|
replys = [tips_custom.replys_message]
|
||||||
|
|
||||||
return replys
|
return replys
|
||||||
|
|
||||||
if Image in event.message_chain:
|
if not self.enable_group:
|
||||||
|
logging.debug("已在banlist.py中禁用所有群聊")
|
||||||
|
elif Image in event.message_chain:
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
if At(self.bot_account_id) in event.message_chain and response_at(event.group.id):
|
if At(self.bot_account_id) in event.message_chain and response_at(event.group.id):
|
||||||
|
|||||||
@@ -114,8 +114,12 @@ def process_normal_message(text_message: str, mgr, config, launcher_type: str,
|
|||||||
reply = handle_exception("{}会话调用API失败:{}".format(session_name, e),
|
reply = handle_exception("{}会话调用API失败:{}".format(session_name, e),
|
||||||
"[bot]err:RateLimitError,请重试或联系作者,或等待修复")
|
"[bot]err:RateLimitError,请重试或联系作者,或等待修复")
|
||||||
except openai.error.InvalidRequestError as e:
|
except openai.error.InvalidRequestError as e:
|
||||||
reply = handle_exception("{}API调用参数错误:{}\n".format(
|
if config.auto_reset and "This model's maximum context length is" in str(e):
|
||||||
session_name, e), "[bot]err:API调用参数错误,请联系管理员,或等待修复")
|
session.reset()
|
||||||
|
reply = [tips_custom.session_auto_reset_message]
|
||||||
|
else:
|
||||||
|
reply = handle_exception("{}API调用参数错误:{}\n".format(
|
||||||
|
session_name, e), "[bot]err:API调用参数错误,请联系管理员,或等待修复")
|
||||||
except openai.error.ServiceUnavailableError as e:
|
except openai.error.ServiceUnavailableError as e:
|
||||||
reply = handle_exception("{}API调用服务不可用:{}".format(session_name, e), "[bot]err:API调用服务不可用,请重试或联系管理员,或等待修复")
|
reply = handle_exception("{}API调用服务不可用:{}".format(session_name, e), "[bot]err:API调用服务不可用,请重试或联系管理员,或等待修复")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|||||||
@@ -74,12 +74,16 @@ def process_message(launcher_type: str, launcher_id: int, text_message: str, mes
|
|||||||
import config
|
import config
|
||||||
if config.income_msg_check:
|
if config.income_msg_check:
|
||||||
if mgr.reply_filter.is_illegal(text_message):
|
if mgr.reply_filter.is_illegal(text_message):
|
||||||
return MessageChain(Plain("[bot] 你的提问中有不合适的内容, 请更换措辞~"))
|
return MessageChain(Plain("[bot] 消息中存在不合适的内容, 请更换措辞"))
|
||||||
|
|
||||||
pkg.openai.session.get_session(session_name).acquire_response_lock()
|
pkg.openai.session.get_session(session_name).acquire_response_lock()
|
||||||
|
|
||||||
text_message = text_message.strip()
|
text_message = text_message.strip()
|
||||||
|
|
||||||
|
|
||||||
|
# 为强制消息延迟计时
|
||||||
|
start_time = time.time()
|
||||||
|
|
||||||
# 处理消息
|
# 处理消息
|
||||||
try:
|
try:
|
||||||
|
|
||||||
@@ -168,4 +172,23 @@ def process_message(launcher_type: str, launcher_id: int, text_message: str, mes
|
|||||||
finally:
|
finally:
|
||||||
pkg.openai.session.get_session(session_name).release_response_lock()
|
pkg.openai.session.get_session(session_name).release_response_lock()
|
||||||
|
|
||||||
|
# 检查延迟时间
|
||||||
|
if config.force_delay_range[1] == 0:
|
||||||
|
delay_time = 0
|
||||||
|
else:
|
||||||
|
import random
|
||||||
|
|
||||||
|
# 从延迟范围中随机取一个值(浮点)
|
||||||
|
rdm = random.uniform(config.force_delay_range[0], config.force_delay_range[1])
|
||||||
|
|
||||||
|
spent = time.time() - start_time
|
||||||
|
|
||||||
|
# 如果花费时间小于延迟时间,则延迟
|
||||||
|
delay_time = rdm - spent if rdm - spent > 0 else 0
|
||||||
|
|
||||||
|
# 延迟
|
||||||
|
if delay_time > 0:
|
||||||
|
logging.info("[风控] 强制延迟{:.2f}秒(如需关闭,请到config.py修改force_delay_range字段)".format(delay_time))
|
||||||
|
time.sleep(delay_time)
|
||||||
|
|
||||||
return MessageChain(reply)
|
return MessageChain(reply)
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ class NakuruProjectMessageConverter(MessageConverter):
|
|||||||
elif type(message_chain) is list:
|
elif type(message_chain) is list:
|
||||||
msg_list = message_chain
|
msg_list = message_chain
|
||||||
else:
|
else:
|
||||||
raise Exception("Unknown message type: " + str(message_chain) + type(message_chain))
|
raise Exception("Unknown message type: " + str(message_chain) + str(type(message_chain)))
|
||||||
|
|
||||||
nakuru_msg_list = []
|
nakuru_msg_list = []
|
||||||
|
|
||||||
@@ -157,7 +157,6 @@ class NakuruProjectEventConverter(EventConverter):
|
|||||||
raise Exception("未支持转换的事件类型: " + str(event))
|
raise Exception("未支持转换的事件类型: " + str(event))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class NakuruProjectAdapter(MessageSourceAdapter):
|
class NakuruProjectAdapter(MessageSourceAdapter):
|
||||||
"""nakuru-project适配器"""
|
"""nakuru-project适配器"""
|
||||||
bot: nakuru.CQHTTP
|
bot: nakuru.CQHTTP
|
||||||
@@ -183,6 +182,9 @@ class NakuruProjectAdapter(MessageSourceAdapter):
|
|||||||
},
|
},
|
||||||
timeout=5
|
timeout=5
|
||||||
)
|
)
|
||||||
|
if resp.status_code == 403:
|
||||||
|
logging.error("go-cqhttp拒绝访问,请检查config.py中nakuru_config的token是否与go-cqhttp设置的access-token匹配")
|
||||||
|
raise Exception("go-cqhttp拒绝访问,请检查config.py中nakuru_config的token是否与go-cqhttp设置的access-token匹配")
|
||||||
self.bot_account_id = int(resp.json()['data']['user_id'])
|
self.bot_account_id = int(resp.json()['data']['user_id'])
|
||||||
|
|
||||||
def send_message(
|
def send_message(
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -34,13 +34,18 @@ def pull_latest(repo_path: str) -> bool:
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def is_newer_ignored_bugfix_ver(new_tag: str, old_tag: str):
|
def is_newer(new_tag: str, old_tag: str):
|
||||||
"""判断版本是否更新,忽略第四位版本"""
|
"""判断版本是否更新,忽略第四位版本和第一位版本"""
|
||||||
if new_tag == old_tag:
|
if new_tag == old_tag:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
new_tag = new_tag.split(".")
|
new_tag = new_tag.split(".")
|
||||||
old_tag = old_tag.split(".")
|
old_tag = old_tag.split(".")
|
||||||
|
|
||||||
|
# 判断主版本是否相同
|
||||||
|
if new_tag[0] != old_tag[0]:
|
||||||
|
return False
|
||||||
|
|
||||||
if len(new_tag) < 4:
|
if len(new_tag) < 4:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@@ -97,7 +102,7 @@ def update_all(cli: bool = False) -> bool:
|
|||||||
else:
|
else:
|
||||||
print("更新日志: {}".format(rls_notes))
|
print("更新日志: {}".format(rls_notes))
|
||||||
|
|
||||||
if latest_rls == {} and not is_newer_ignored_bugfix_ver(latest_tag_name, current_tag): # 没有新版本
|
if latest_rls == {} and not is_newer(latest_tag_name, current_tag): # 没有新版本
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# 下载最新版本的zip到temp目录
|
# 下载最新版本的zip到temp目录
|
||||||
@@ -254,7 +259,7 @@ def is_new_version_available() -> bool:
|
|||||||
latest_tag_name = rls['tag_name']
|
latest_tag_name = rls['tag_name']
|
||||||
break
|
break
|
||||||
|
|
||||||
return is_newer_ignored_bugfix_ver(latest_tag_name, current_tag)
|
return is_newer(latest_tag_name, current_tag)
|
||||||
|
|
||||||
|
|
||||||
def get_rls_notes() -> list:
|
def get_rls_notes() -> list:
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
requests~=2.28.1
|
requests~=2.31.0
|
||||||
openai~=0.27.4
|
openai~=0.27.7
|
||||||
dulwich~=0.21.3
|
dulwich~=0.21.5
|
||||||
colorlog~=6.6.0
|
colorlog~=6.6.0
|
||||||
yiri-mirai~=0.2.6.1
|
yiri-mirai~=0.2.7
|
||||||
websockets
|
websockets
|
||||||
urllib3~=1.26.10
|
urllib3~=1.26.10
|
||||||
func_timeout~=4.3.5
|
func_timeout~=4.3.5
|
||||||
|
|||||||
@@ -4,5 +4,11 @@
|
|||||||
"time": "2023-04-24 16:05:20",
|
"time": "2023-04-24 16:05:20",
|
||||||
"timestamp": 1682323520,
|
"timestamp": 1682323520,
|
||||||
"content": "现已支持使用go-cqhttp替换mirai作为QQ登录框架, 请更新并查看 https://github.com/RockChinQ/QChatGPT/wiki/go-cqhttp%E9%85%8D%E7%BD%AE"
|
"content": "现已支持使用go-cqhttp替换mirai作为QQ登录框架, 请更新并查看 https://github.com/RockChinQ/QChatGPT/wiki/go-cqhttp%E9%85%8D%E7%BD%AE"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"time": "2023-05-21 17:33:18",
|
||||||
|
"timestamp": 1684661598,
|
||||||
|
"content": "NewBing不再需要鉴权,若您正在使用revLibs逆向库插件,请立即使用!plugin update revLibs命令更新插件到最新版。"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -1,3 +1,13 @@
|
|||||||
|
# 是否处理群聊消息
|
||||||
|
# 为False时忽略所有群聊消息
|
||||||
|
# 优先级高于下方禁用列表
|
||||||
|
enable_group = True
|
||||||
|
|
||||||
|
# 是否处理私聊消息
|
||||||
|
# 为False时忽略所有私聊消息
|
||||||
|
# 优先级高于下方禁用列表
|
||||||
|
enable_private = True
|
||||||
|
|
||||||
# 是否启用禁用列表
|
# 是否启用禁用列表
|
||||||
enable = True
|
enable = True
|
||||||
|
|
||||||
|
|||||||
@@ -5,20 +5,23 @@
|
|||||||
## 步骤
|
## 步骤
|
||||||
|
|
||||||
1. 从[go-cqhttp的Release](https://github.com/Mrs4s/go-cqhttp/releases/latest)下载最新的go-cqhttp可执行文件(建议直接下载可执行文件压缩包,而不是安装器)
|
1. 从[go-cqhttp的Release](https://github.com/Mrs4s/go-cqhttp/releases/latest)下载最新的go-cqhttp可执行文件(建议直接下载可执行文件压缩包,而不是安装器)
|
||||||
2. 解压并运行,首次运行会询问需要开放的网络协议,**请填入`02`并回车**
|
2. 解压并运行,首次运行会询问需要开放的网络协议,**请填入`02`并回车,必须输入`02`❗❗❗❗❗❗❗**
|
||||||
|
|
||||||
```
|
<h1> 你这里必须得输入`02`,你懂么,`0`必须得输入,看好了,看好下面输入什么了吗?别他妈的搁那就输个`2`完了启动连不上还跑群里问,问一个我踢一个。 </h1>
|
||||||
C:\Softwares\go-cqhttp.old> .\go-cqhttp.exe
|
|
||||||
未找到配置文件,正在为您生成配置文件中!
|
```
|
||||||
请选择你需要的通信方式:
|
C:\Softwares\go-cqhttp.old> .\go-cqhttp.exe
|
||||||
> 0: HTTP通信
|
未找到配置文件,正在为您生成配置文件中!
|
||||||
> 1: 云函数服务
|
请选择你需要的通信方式:
|
||||||
> 2: 正向 Websocket 通信
|
> 0: HTTP通信
|
||||||
> 3: 反向 Websocket 通信
|
> 1: 云函数服务
|
||||||
请输入你需要的编号(0-9),可输入多个,同一编号也可输入多个(如: 233)
|
> 2: 正向 Websocket 通信
|
||||||
您的选择是:02
|
> 3: 反向 Websocket 通信
|
||||||
```
|
请输入你需要的编号(0-9),可输入多个,同一编号也可输入多个(如: 233)
|
||||||
提示已生成`config.yml`文件,关闭go-cqhttp。
|
您的选择是:02
|
||||||
|
```
|
||||||
|
|
||||||
|
提示已生成`config.yml`文件,关闭go-cqhttp。
|
||||||
|
|
||||||
3. 打开go-cqhttp同目录的`config.yml`
|
3. 打开go-cqhttp同目录的`config.yml`
|
||||||
|
|
||||||
@@ -64,4 +67,4 @@
|
|||||||
|
|
||||||
4. 配置完成,重新启动go-cqhttp
|
4. 配置完成,重新启动go-cqhttp
|
||||||
|
|
||||||
> 若启动后登录不成功,请尝试根据[此文档](https://docs.go-cqhttp.org/guide/config.html#%E8%AE%BE%E5%A4%87%E4%BF%A1%E6%81%AF)修改`device.json`的协议编号。
|
> 若启动后登录不成功,请尝试根据[此文档](https://docs.go-cqhttp.org/guide/config.html#%E8%AE%BE%E5%A4%87%E4%BF%A1%E6%81%AF)修改`device.json`的协议编号。
|
||||||
|
|||||||
@@ -225,7 +225,7 @@
|
|||||||
格式: `!cfg <配置项名称> <配置项新值>`
|
格式: `!cfg <配置项名称> <配置项新值>`
|
||||||
以修改`default_prompt`示例
|
以修改`default_prompt`示例
|
||||||
```
|
```
|
||||||
!cfg default_prompt 我是Rock Chin
|
!cfg default_prompt "我是Rock Chin"
|
||||||
```
|
```
|
||||||
|
|
||||||
输出示例
|
输出示例
|
||||||
@@ -243,7 +243,15 @@
|
|||||||
```
|
```
|
||||||
!~all
|
!~all
|
||||||
!~default_prompt
|
!~default_prompt
|
||||||
!~default_prompt 我是Rock Chin
|
!~default_prompt "我是Rock Chin"
|
||||||
|
```
|
||||||
|
|
||||||
|
5. 配置项名称支持使用点号(.)拼接以索引子配置项
|
||||||
|
|
||||||
|
例如: `openai_config.api_key`将索引`config`字典中的`openai_config`字典中的`api_key`字段,可以通过这个方式查看或修改此子配置项
|
||||||
|
|
||||||
|
```
|
||||||
|
!~openai_config.api_key
|
||||||
```
|
```
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
@@ -367,4 +375,5 @@ prompt_submit_length = <模型单次请求token数上限> - 情景预设中token
|
|||||||
|
|
||||||
### 加入黑名单
|
### 加入黑名单
|
||||||
|
|
||||||
编辑`banlist.py`,设置`enable = True`,并在其中的`person`或`group`列表中加入要封禁的人或群聊,修改完成后重启程序或进行热重载
|
- 支持禁用所有`私聊`或`群聊`,请查看`banlist.py`中的`enable_private`和`enable_group`字段
|
||||||
|
- 编辑`banlist.py`,设置`enable = True`,并在其中的`person`或`group`列表中加入要封禁的人或群聊,修改完成后重启程序或进行热重载
|
||||||
@@ -23,15 +23,16 @@ QChatGPT 插件使用Wiki
|
|||||||
|
|
||||||
## 管理
|
## 管理
|
||||||
|
|
||||||
### !plugin 指令
|
### !plugin 命令
|
||||||
|
|
||||||
```
|
```
|
||||||
!plugin 列出所有已安装的插件
|
!plugin 列出所有已安装的插件
|
||||||
!plugin get <储存库地址> 从Git储存库安装插件(需要管理员权限)
|
!plugin get <储存库地址> 从Git储存库安装插件(需要管理员权限)
|
||||||
!plugin update 更新所有插件(需要管理员权限,仅支持从储存库安装的插件)
|
!plugin update all 更新所有插件(需要管理员权限,仅支持从储存库安装的插件)
|
||||||
!plugin del <插件名> 删除插件(需要管理员权限)
|
!plugin update <插件名> 更新指定插件
|
||||||
!plugin on <插件名> 启用插件(需要管理员权限)
|
!plugin del <插件名> 删除插件(需要管理员权限)
|
||||||
!plugin off <插件名> 禁用插件(需要管理员权限)
|
!plugin on <插件名> 启用插件(需要管理员权限)
|
||||||
|
!plugin off <插件名> 禁用插件(需要管理员权限)
|
||||||
```
|
```
|
||||||
|
|
||||||
### 控制插件执行顺序
|
### 控制插件执行顺序
|
||||||
|
|||||||
@@ -27,8 +27,11 @@ replys_message = "[bot]err:请求超时"
|
|||||||
# 指令权限不足提示
|
# 指令权限不足提示
|
||||||
command_admin_message = "[bot]err:权限不足: "
|
command_admin_message = "[bot]err:权限不足: "
|
||||||
# 指令无效提示
|
# 指令无效提示
|
||||||
command_err_message = "[bot]err:指令执行出错:"
|
command_err_message = "[bot]err:指令不存在:"
|
||||||
|
|
||||||
# 会话重置提示
|
# 会话重置提示
|
||||||
command_reset_message = "[bot]:会话已重置"
|
command_reset_message = "[bot]会话已重置"
|
||||||
command_reset_name_message = "[bot]:会话已重置,使用场景预设:"
|
command_reset_name_message = "[bot]会话已重置,使用场景预设:"
|
||||||
|
|
||||||
|
# 会话自动重置时的提示
|
||||||
|
session_auto_reset_message = "[bot]会话token超限,已自动重置,请重新发送消息"
|
||||||
|
|||||||
Reference in New Issue
Block a user