mirror of
https://github.com/langbot-app/LangBot.git
synced 2026-06-02 12:05:54 +00:00
Compare commits
60 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d46c94d7c3 | ||
|
|
2db9c00530 | ||
|
|
66d8d159f9 | ||
|
|
9fa1446284 | ||
|
|
b3e4cb48c7 | ||
|
|
0bca7b2247 | ||
|
|
7812e03c9d | ||
|
|
7a852ae5af | ||
|
|
706d9e61c1 | ||
|
|
8f0ed4ff4b | ||
|
|
3415b6f121 | ||
|
|
256ba6fb86 | ||
|
|
d30b2b9afe | ||
|
|
be943ca1fc | ||
|
|
1ddab2a97a | ||
|
|
e15fd4695c | ||
|
|
ffa4b1b4a1 | ||
|
|
f8eee3a2a6 | ||
|
|
eeee7a8343 | ||
|
|
8447b73fcb | ||
|
|
2863945d5f | ||
|
|
cb1f8ca6f7 | ||
|
|
1d9964bcb1 | ||
|
|
15cb8016d3 | ||
|
|
895cc0a2c5 | ||
|
|
20bf349e4e | ||
|
|
e297763da1 | ||
|
|
e471970654 | ||
|
|
12faaaced8 | ||
|
|
083cbc55cc | ||
|
|
8aa7a3273d | ||
|
|
255e2c4385 | ||
|
|
9856306870 | ||
|
|
527ab8b8a7 | ||
|
|
f8e19ba9b3 | ||
|
|
7649dbfbbc | ||
|
|
81e734644d | ||
|
|
ae55cf5b1e | ||
|
|
af539546ef | ||
|
|
0031ce57d0 | ||
|
|
2f48a2ce57 | ||
|
|
6068ab7100 | ||
|
|
29a7dccef4 | ||
|
|
e2073da86e | ||
|
|
ae079526f7 | ||
|
|
947bae8e26 | ||
|
|
a68e29dff6 | ||
|
|
a588d7f960 | ||
|
|
66224e5a32 | ||
|
|
07abad6a14 | ||
|
|
83d02aaaac | ||
|
|
5865ac017c | ||
|
|
4061a92f8e | ||
|
|
d37c31b31c | ||
|
|
973ef0078f | ||
|
|
48dcd257da | ||
|
|
da03911610 | ||
|
|
b6f7f3b73f | ||
|
|
2050d20ea7 | ||
|
|
ac1fb4a63a |
8
.github/workflows/sync-wiki.yml
vendored
8
.github/workflows/sync-wiki.yml
vendored
@@ -26,6 +26,8 @@ jobs:
|
||||
- name: Commit and Push Changes
|
||||
run: |
|
||||
cd wiki
|
||||
git add .
|
||||
git commit -m "Update wiki"
|
||||
git push
|
||||
if git diff --name-only; then
|
||||
git add .
|
||||
git commit -m "Update wiki"
|
||||
git push
|
||||
fi
|
||||
|
||||
@@ -42,7 +42,7 @@ jobs:
|
||||
- name: Check for changes in cmdpriv-template.json
|
||||
id: check_changes
|
||||
run: |
|
||||
if git diff --name-only | grep -q "cmdpriv-template.json"; then
|
||||
if git diff --name-only | grep -q "res/templates/cmdpriv-template.json"; then
|
||||
echo "::set-output name=changes_detected::true"
|
||||
else
|
||||
echo "::set-output name=changes_detected::false"
|
||||
@@ -53,6 +53,6 @@ jobs:
|
||||
run: |
|
||||
git config --global user.name "GitHub Actions Bot"
|
||||
git config --global user.email "<github-actions@github.com>"
|
||||
git add cmdpriv-template.json
|
||||
git add res/templates/cmdpriv-template.json
|
||||
git commit -m "Update cmdpriv-template.json"
|
||||
git push
|
||||
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -17,4 +17,5 @@ scenario/
|
||||
override.json
|
||||
cookies.json
|
||||
res/announcement_saved
|
||||
cmdpriv.json
|
||||
cmdpriv.json
|
||||
tips.py
|
||||
11
README.md
11
README.md
@@ -1,5 +1,9 @@
|
||||
# QChatGPT🤖
|
||||
|
||||
[English](README_en.md) | 简体中文
|
||||
|
||||
[](https://github.com/RockChinQ/QChatGPT/releases/latest)
|
||||
|
||||
> 2023/3/18 现已支持GPT-4 API(内测),请查看`config-template.py`中的`completion_api_params`
|
||||
> 2023/3/15 逆向库已支持New Bing,使用方法查看[插件文档](https://github.com/RockChinQ/revLibs)
|
||||
|
||||
@@ -126,6 +130,12 @@
|
||||
- 目前已支持正向代理访问接口
|
||||
- 详细请查看config.py中的`openai_config`的说明
|
||||
</details>
|
||||
<details>
|
||||
<summary>✅支持自定义提示内容</summary>
|
||||
|
||||
- 允许用户自定义报错、帮助等提示信息
|
||||
- 请查看`tips.py`
|
||||
</details>
|
||||
</details>
|
||||
|
||||
详情请查看[Wiki功能使用页](https://github.com/RockChinQ/QChatGPT/wiki/%E5%8A%9F%E8%83%BD%E4%BD%BF%E7%94%A8#%E5%8A%9F%E8%83%BD%E7%82%B9%E5%88%97%E4%B8%BE)
|
||||
@@ -251,6 +261,7 @@ python3 main.py
|
||||
- [RockChinQ/WaitYiYan](https://github.com/RockChinQ/WaitYiYan) - 实时获取百度`文心一言`等待列表人数
|
||||
- [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/)上的机器人
|
||||
- [lieyanqzu/WeatherPlugin](https://github.com/lieyanqzu/WeatherPlugin) - 天气查询插件
|
||||
</details>
|
||||
|
||||
## 😘致谢
|
||||
|
||||
194
README_en.md
Normal file
194
README_en.md
Normal file
@@ -0,0 +1,194 @@
|
||||
# QChatGPT🤖
|
||||
|
||||
English | [简体中文](README.md)
|
||||
|
||||
[](https://github.com/RockChinQ/QChatGPT/releases/latest)
|
||||
|
||||
- Refer to [Wiki](https://github.com/RockChinQ/QChatGPT/wiki) to get further information.
|
||||
- Official QQ group: 656285629
|
||||
- Community QQ group: 362515018
|
||||
- QQ channel robot: [QQChannelChatGPT](https://github.com/Soulter/QQChannelChatGPT)
|
||||
- Any contribution is welcome, please refer to [CONTRIBUTING.md](CONTRIBUTING.md)
|
||||
|
||||
## 🍺List of supported models
|
||||
|
||||
<details>
|
||||
<summary>Details</summary>
|
||||
|
||||
### Chat
|
||||
|
||||
- OpenAI GPT-3.5 (ChatGPT API), default model
|
||||
- OpenAI GPT-3, supported natively, switch to it in `config.py`
|
||||
- OpenAI GPT-4, supported natively, qualification for internal testing required, switch to it in `config.py`
|
||||
- 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)
|
||||
- New Bing, see [revLibs plugin](https://github.com/RockChinQ/revLibs)
|
||||
|
||||
### Story
|
||||
|
||||
- NovelAI API, see [QCPNovelAi plugin](https://github.com/dominoar/QCPNovelAi)
|
||||
|
||||
### Image
|
||||
|
||||
- OpenAI DALL·E, supported natively, see [Wiki(cn)](https://github.com/RockChinQ/QChatGPT/wiki/%E5%8A%9F%E8%83%BD%E4%BD%BF%E7%94%A8#%E5%8A%9F%E8%83%BD%E7%82%B9%E5%88%97%E4%B8%BE)
|
||||
- NovelAI API, see [QCPNovelAi plugin](https://github.com/dominoar/QCPNovelAi)
|
||||
|
||||
### Voice
|
||||
|
||||
- TTS+VITS, see [QChatPlugins](https://github.com/dominoar/QChatPlugins)
|
||||
- Plachta/VITS-Umamusume-voice-synthesizer, see [chat_voice plugin](https://github.com/oliverkirk-sudo/chat_voice)
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
Install this [plugin](https://github.com/RockChinQ/Switcher) to switch between different models.
|
||||
|
||||
## ✅Function Points
|
||||
|
||||
<details>
|
||||
<summary>Details</summary>
|
||||
|
||||
- ✅Sensitive word filtering, avoid being banned
|
||||
- ✅Multiple responding rules, including regular expression matching
|
||||
- ✅Multiple api-key management, automatic switching when exceeding
|
||||
- ✅Support for customizing the preset prompt text
|
||||
- ✅Chat, story, image, voice, etc. models are supported
|
||||
- ✅Support for hot reloading and hot updating
|
||||
- ✅Support for plugin loading
|
||||
- ✅Blacklist mechanism for private chat and group chat
|
||||
- ✅Excellent long message processing strategy
|
||||
- ✅Reply rate limitation
|
||||
- ✅Support for network proxy
|
||||
- ✅Support for customizing the output format
|
||||
</details>
|
||||
|
||||
More details, see [Wiki(cn)](https://github.com/RockChinQ/QChatGPT/wiki/%E5%8A%9F%E8%83%BD%E4%BD%BF%E7%94%A8#%E5%8A%9F%E8%83%BD%E7%82%B9%E5%88%97%E4%B8%BE)
|
||||
|
||||
## 🔩Deployment
|
||||
|
||||
**If you encounter any problems during deployment, please search in the issue of [QChatGPT](https://github.com/RockChinQ/QChatGPT/issues) or [qcg-installer](https://github.com/RockChinQ/qcg-installer/issues) first.**
|
||||
|
||||
### - Register OpenAI account
|
||||
|
||||
> If you want to use a model other than OpenAI (such as New Bing), you can skip this step and directly refer to following steps, and then configure it according to the relevant plugin documentation.
|
||||
|
||||
To register OpenAI account, please refer to the following articles(in Chinese):
|
||||
|
||||
> [国内注册ChatGPT的方法(100%可用)](https://www.pythonthree.com/register-openai-chatgpt/)
|
||||
> [手把手教你如何注册ChatGPT,超级详细](https://guxiaobei.com/51461)
|
||||
|
||||
Check your api-key in [personal center](https://beta.openai.com/account/api-keys) after registration, and then follow the following steps to deploy.
|
||||
|
||||
### - Deploy Automatically
|
||||
|
||||
<details>
|
||||
<summary>Details</summary>
|
||||
|
||||
#### Docker
|
||||
|
||||
See [this document(cn)](res/docs/docker_deploy.md)
|
||||
Contributed by [@mikumifa](https://github.com/mikumifa)
|
||||
|
||||
#### Installer
|
||||
|
||||
Use [this installer](https://github.com/RockChinQ/qcg-installer) to deploy.
|
||||
|
||||
- The installer currently only supports some platforms, please refer to the repository document for details, and manually deploy for other platforms
|
||||
|
||||
</details>
|
||||
|
||||
### - Deploy Manually
|
||||
<details>
|
||||
<summary>Manually deployment supports any platforms</summary>
|
||||
|
||||
- Python 3.9.x or higher
|
||||
|
||||
#### Configure Mirai
|
||||
|
||||
Follow [this tutorial(cn)](https://yiri-mirai.wybxc.cc/tutorials/01/configuration) to configure Mirai and YiriMirai.
|
||||
After starting mirai-console, use the `login` command to log in to the QQ account, and keep the mirai-console running.
|
||||
|
||||
#### Configure QChatGPT
|
||||
|
||||
1. Clone the repository
|
||||
|
||||
```bash
|
||||
git clone https://github.com/RockChinQ/QChatGPT
|
||||
cd QChatGPT
|
||||
```
|
||||
|
||||
2. Install dependencies
|
||||
|
||||
```bash
|
||||
pip3 install requests yiri-mirai openai colorlog func_timeout dulwich Pillow
|
||||
```
|
||||
|
||||
3. Generate `config.py`
|
||||
|
||||
```bash
|
||||
python3 main.py
|
||||
```
|
||||
|
||||
4. Edit `config.py`
|
||||
|
||||
5. Run
|
||||
|
||||
```bash
|
||||
python3 main.py
|
||||
```
|
||||
|
||||
Any problems, please refer to the issues page.
|
||||
|
||||
</details>
|
||||
|
||||
## 🚀Usage
|
||||
|
||||
**After deployment, please read: [Commands(cn)](https://github.com/RockChinQ/QChatGPT/wiki/%E5%8A%9F%E8%83%BD%E4%BD%BF%E7%94%A8#%E6%9C%BA%E5%99%A8%E4%BA%BA%E6%8C%87%E4%BB%A4)**
|
||||
|
||||
**For more details, please refer to the [Wiki(cn)](https://github.com/RockChinQ/QChatGPT/wiki/%E5%8A%9F%E8%83%BD%E4%BD%BF%E7%94%A8#%E4%BD%BF%E7%94%A8%E6%96%B9%E5%BC%8F)**
|
||||
|
||||
|
||||
## 🧩Plugin Ecosystem
|
||||
|
||||
Plugin [usage](https://github.com/RockChinQ/QChatGPT/wiki/%E6%8F%92%E4%BB%B6%E4%BD%BF%E7%94%A8) and [development](https://github.com/RockChinQ/QChatGPT/wiki/%E6%8F%92%E4%BB%B6%E5%BC%80%E5%8F%91) are supported.
|
||||
|
||||
<details>
|
||||
<summary>List of plugins (cn)</summary>
|
||||
|
||||
### Examples
|
||||
|
||||
在`tests/plugin_examples`目录下,将其整个目录复制到`plugins`目录下即可使用
|
||||
|
||||
- `cmdcn` - 主程序指令中文形式
|
||||
- `hello_plugin` - 在收到消息`hello`时回复相应消息
|
||||
- `urlikethisijustsix` - 收到冒犯性消息时回复相应消息
|
||||
|
||||
### More Plugins
|
||||
|
||||
欢迎提交新的插件
|
||||
|
||||
- [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%E4%B8%8EChatGPT%E7%BD%91%E9%A1%B5%E7%89%88)
|
||||
- [Switcher](https://github.com/RockChinQ/Switcher) - 支持通过指令切换使用的模型
|
||||
- [hello_plugin](https://github.com/RockChinQ/hello_plugin) - `hello_plugin` 的储存库形式,插件开发模板
|
||||
- [dominoar/QChatPlugins](https://github.com/dominoar/QchatPlugins) - dominoar编写的诸多新功能插件(语音输出、Ranimg、屏蔽词规则等)
|
||||
- [dominoar/QCP-NovelAi](https://github.com/dominoar/QCP-NovelAi) - NovelAI 故事叙述与绘画
|
||||
- [oliverkirk-sudo/chat_voice](https://github.com/oliverkirk-sudo/chat_voice) - 文字转语音输出,使用HuggingFace上的[VITS-Umamusume-voice-synthesizer模型](https://huggingface.co/spaces/Plachta/VITS-Umamusume-voice-synthesizer)
|
||||
- [RockChinQ/WaitYiYan](https://github.com/RockChinQ/WaitYiYan) - 实时获取百度`文心一言`等待列表人数
|
||||
- [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/)上的机器人
|
||||
- [lieyanqzu/WeatherPlugin](https://github.com/lieyanqzu/WeatherPlugin) - 天气查询插件
|
||||
</details>
|
||||
|
||||
## 😘Thanks
|
||||
|
||||
- [@the-lazy-me](https://github.com/the-lazy-me) video tutorial creator
|
||||
- [@mikumifa](https://github.com/mikumifa) Docker deployment
|
||||
- [@dominoar](https://github.com/dominoar) Plugin development
|
||||
- [@万神的星空](https://github.com/qq255204159) Packages publisher
|
||||
- [@ljcduo](https://github.com/ljcduo) GPT-4 API internal test account
|
||||
|
||||
And all [contributors](https://github.com/RockChinQ/QChatGPT/graphs/contributors) and other friends who support this project.
|
||||
|
||||
<!-- ## 👍赞赏
|
||||
|
||||
<img alt="赞赏码" src="res/mm_reward_qrcode_1672840549070.png" width="400" height="400"/> -->
|
||||
@@ -33,9 +33,9 @@ mirai_http_api_config = {
|
||||
# },
|
||||
# "http_proxy": "http://127.0.0.1:12345"
|
||||
# }
|
||||
#
|
||||
#
|
||||
# 现已支持反向代理,可以添加reverse_proxy字段以使用反向代理
|
||||
# 使用反向代理可以在国内使用OpenAI的API,反向代理的配置请参考
|
||||
# 使用反向代理可以在国内使用OpenAI的API,反向代理的配置请参考
|
||||
# https://github.com/Ice-Hazymoon/openai-scf-proxy
|
||||
#
|
||||
# 反向代理填写示例:
|
||||
@@ -63,7 +63,7 @@ admin_qq = 0
|
||||
# 情景预设(机器人人格)
|
||||
# 每个会话的预设信息,影响所有会话,无视指令重置
|
||||
# 可以通过这个字段指定某些情况的回复,可直接用自然语言描述指令
|
||||
# 例如:
|
||||
# 例如:
|
||||
# default_prompt = "如果我之后想获取帮助,请你说“输入!help获取帮助”"
|
||||
# 这样用户在不知所措的时候机器人就会提示其输入!help获取帮助
|
||||
# 可参考 https://github.com/PlexPt/awesome-chatgpt-prompts-zh
|
||||
@@ -81,14 +81,14 @@ admin_qq = 0
|
||||
# 例如:
|
||||
# !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获取帮助”",
|
||||
@@ -160,7 +160,7 @@ prompt_submit_length = 2048
|
||||
# OpenAI补全API的参数
|
||||
# 请在下方填写模型,程序自动选择接口
|
||||
# 现已支持的模型有:
|
||||
#
|
||||
#
|
||||
# 'gpt-4'
|
||||
# 'gpt-4-0314'
|
||||
# 'gpt-4-32k'
|
||||
@@ -226,11 +226,6 @@ retry_times = 3
|
||||
# 设置为False时,向用户及管理员发送错误详细信息
|
||||
hide_exce_info_to_user = False
|
||||
|
||||
# 消息处理出错时向用户发送的提示信息
|
||||
# 仅当hide_exce_info_to_user为True时生效
|
||||
# 设置为空字符串时,不发送提示信息
|
||||
alter_tip_message = '出错了,请稍后再试'
|
||||
|
||||
# 线程池相关配置
|
||||
# 该参数决定机器人可以同时处理几个人的消息,超出线程池数量的请求会被阻塞,不会被丢弃
|
||||
# 如果你不清楚该参数的意义,请不要更改
|
||||
@@ -246,23 +241,41 @@ user_pool_num = 6
|
||||
|
||||
# 每个会话的过期时间,单位为秒
|
||||
# 默认值20分钟
|
||||
session_expire_time = 60 * 20
|
||||
session_expire_time = 1200
|
||||
|
||||
# 会话限速
|
||||
# 单会话内每分钟可进行的对话次数
|
||||
# 若不需要限速,可以设置为一个很大的值
|
||||
# 默认值60次,基本上不会触发限速
|
||||
rate_limitation = 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 = "wait"
|
||||
|
||||
# drop策略时,超过限速均值时,丢弃的对话的提示信息
|
||||
# 仅当rate_limitation_strategy为"drop"时生效
|
||||
# 若设置为空字符串,则不发送提示信息
|
||||
rate_limit_drop_tip = "本分钟对话次数超过限速次数,此对话被丢弃"
|
||||
rate_limit_strategy = "drop"
|
||||
|
||||
# 是否在启动时进行依赖库更新
|
||||
upgrade_dependencies = True
|
||||
@@ -274,8 +287,3 @@ report_usage = True
|
||||
|
||||
# 日志级别
|
||||
logging_level = logging.INFO
|
||||
|
||||
# 定制帮助消息
|
||||
help_message = """此机器人通过调用大型语言模型生成回复,不具有情感。
|
||||
你可以用自然语言与其交流,回复的消息中[GPT]开头的为模型生成的语言,[bot]开头的为程序提示。
|
||||
欢迎到github.com/RockChinQ/QChatGPT 给个star"""
|
||||
128
main.py
128
main.py
@@ -11,6 +11,8 @@ import traceback
|
||||
|
||||
sys.path.append(".")
|
||||
|
||||
from pkg.utils.log import init_runtime_log_file, reset_logging
|
||||
|
||||
try:
|
||||
import colorlog
|
||||
except ImportError:
|
||||
@@ -18,6 +20,7 @@ except ImportError:
|
||||
import pkg.utils.pkgmgr as pkgmgr
|
||||
try:
|
||||
pkgmgr.install_requirements("requirements.txt")
|
||||
pkgmgr.install_upgrade("websockets")
|
||||
import colorlog
|
||||
except ImportError:
|
||||
print("依赖不满足,请查看 https://github.com/RockChinQ/qcg-installer/issues/15")
|
||||
@@ -30,13 +33,9 @@ from urllib3.exceptions import InsecureRequestWarning
|
||||
import pkg.utils.context
|
||||
|
||||
|
||||
log_colors_config = {
|
||||
'DEBUG': 'green', # cyan white
|
||||
'INFO': 'white',
|
||||
'WARNING': 'yellow',
|
||||
'ERROR': 'red',
|
||||
'CRITICAL': 'cyan',
|
||||
}
|
||||
# 是否使用override.json覆盖配置
|
||||
# 仅在启动时提供 --override 或 -r 参数时生效
|
||||
use_override = False
|
||||
|
||||
|
||||
def init_db():
|
||||
@@ -55,59 +54,23 @@ def ensure_dependencies():
|
||||
|
||||
known_exception_caught = False
|
||||
|
||||
log_file_name = "qchatgpt.log"
|
||||
|
||||
|
||||
def init_runtime_log_file():
|
||||
"""为此次运行生成日志文件
|
||||
格式: qchatgpt-yyyy-MM-dd-HH-mm-ss.log
|
||||
"""
|
||||
global log_file_name
|
||||
|
||||
# 检查logs目录是否存在
|
||||
if not os.path.exists("logs"):
|
||||
os.mkdir("logs")
|
||||
|
||||
# 检查本目录是否有qchatgpt.log,若有,移动到logs目录
|
||||
if os.path.exists("qchatgpt.log"):
|
||||
shutil.move("qchatgpt.log", "logs/qchatgpt.legacy.log")
|
||||
|
||||
log_file_name = "logs/qchatgpt-%s.log" % time.strftime("%Y-%m-%d-%H-%M-%S", time.localtime())
|
||||
|
||||
|
||||
def reset_logging():
|
||||
global log_file_name
|
||||
|
||||
def override_config():
|
||||
import config
|
||||
|
||||
if pkg.utils.context.context['logger_handler'] is not None:
|
||||
logging.getLogger().removeHandler(pkg.utils.context.context['logger_handler'])
|
||||
|
||||
for handler in logging.getLogger().handlers:
|
||||
logging.getLogger().removeHandler(handler)
|
||||
|
||||
logging.basicConfig(level=config.logging_level, # 设置日志输出格式
|
||||
filename=log_file_name, # log日志输出的文件位置和文件名
|
||||
format="[%(asctime)s.%(msecs)03d] %(filename)s (%(lineno)d) - [%(levelname)s] : %(message)s",
|
||||
# 日志输出的格式
|
||||
# -8表示占位符,让输出左对齐,输出长度都为8位
|
||||
datefmt="%Y-%m-%d %H:%M:%S" # 时间输出的格式
|
||||
)
|
||||
sh = logging.StreamHandler()
|
||||
sh.setLevel(config.logging_level)
|
||||
sh.setFormatter(colorlog.ColoredFormatter(
|
||||
fmt="%(log_color)s[%(asctime)s.%(msecs)03d] %(filename)s (%(lineno)d) - [%(levelname)s] : "
|
||||
"%(message)s",
|
||||
datefmt="%Y-%m-%d %H:%M:%S",
|
||||
log_colors=log_colors_config
|
||||
))
|
||||
logging.getLogger().addHandler(sh)
|
||||
pkg.utils.context.context['logger_handler'] = sh
|
||||
return sh
|
||||
# 检查override.json覆盖
|
||||
if os.path.exists("override.json") and use_override:
|
||||
override_json = json.load(open("override.json", "r", encoding="utf-8"))
|
||||
for key in override_json:
|
||||
if hasattr(config, key):
|
||||
setattr(config, key, override_json[key])
|
||||
logging.info("覆写配置[{}]为[{}]".format(key, override_json[key]))
|
||||
else:
|
||||
logging.error("无法覆写配置[{}]为[{}],该配置不存在,请检查override.json是否正确".format(key, override_json[key]))
|
||||
|
||||
|
||||
# 临时函数,用于加载config和上下文,未来统一放在config类
|
||||
def load_config():
|
||||
logging.info("检查config模块完整性.")
|
||||
# 完整性校验
|
||||
is_integrity = True
|
||||
config_template = importlib.import_module('config-template')
|
||||
@@ -119,26 +82,37 @@ def load_config():
|
||||
is_integrity = False
|
||||
|
||||
if not is_integrity:
|
||||
logging.warning("配置文件不完整,请依据config-template.py检查config.py")
|
||||
logging.warning("配置文件不完整,您可以依据config-template.py检查config.py")
|
||||
|
||||
# 检查override.json覆盖
|
||||
if os.path.exists("override.json"):
|
||||
override_json = json.load(open("override.json", "r", encoding="utf-8"))
|
||||
for key in override_json:
|
||||
if hasattr(config, key):
|
||||
setattr(config, key, override_json[key])
|
||||
logging.info("覆写配置[{}]为[{}]".format(key, override_json[key]))
|
||||
else:
|
||||
logging.error("无法覆写配置[{}]为[{}],该配置不存在,请检查override.json是否正确".format(key, override_json[key]))
|
||||
override_config()
|
||||
|
||||
if not is_integrity:
|
||||
logging.warning("以上配置已被设为默认值,将在5秒后继续启动... ")
|
||||
time.sleep(5)
|
||||
logging.warning("以上不存在的配置已被设为默认值,将在3秒后继续启动... ")
|
||||
time.sleep(3)
|
||||
|
||||
# 存进上下文
|
||||
pkg.utils.context.set_config(config)
|
||||
|
||||
|
||||
def complete_tips():
|
||||
"""根据tips-custom-template模块补全tips模块的属性"""
|
||||
is_integrity = True
|
||||
logging.info("检查tips模块完整性.")
|
||||
tips_template = importlib.import_module('tips-custom-template')
|
||||
tips = importlib.import_module('tips')
|
||||
for key in dir(tips_template):
|
||||
if not key.startswith("__") and not hasattr(tips, key):
|
||||
setattr(tips, key, getattr(tips_template, key))
|
||||
logging.warning("[{}]不存在".format(key))
|
||||
is_integrity = False
|
||||
|
||||
if not is_integrity:
|
||||
logging.warning("tips模块不完整,您可以依据tips-custom-template.py检查tips.py")
|
||||
logging.warning("以上配置已被设为默认值,将在3秒后继续启动... ")
|
||||
time.sleep(3)
|
||||
|
||||
|
||||
def start(first_time_init=False):
|
||||
"""启动流程,reload之后会被执行"""
|
||||
|
||||
@@ -356,12 +330,6 @@ def stop():
|
||||
|
||||
|
||||
def check_file():
|
||||
# 配置文件存在性校验
|
||||
if not os.path.exists('config.py'):
|
||||
shutil.copy('config-template.py', 'config.py')
|
||||
print('请先在config.py中填写配置')
|
||||
sys.exit(0)
|
||||
|
||||
# 检查是否有banlist.py,如果没有就把banlist-template.py复制一份
|
||||
if not os.path.exists('banlist.py'):
|
||||
shutil.copy('res/templates/banlist-template.py', 'banlist.py')
|
||||
@@ -378,6 +346,10 @@ def check_file():
|
||||
if not os.path.exists("cmdpriv.json"):
|
||||
shutil.copy("res/templates/cmdpriv-template.json", "cmdpriv.json")
|
||||
|
||||
# 检查tips_custom
|
||||
if not os.path.exists("tips.py"):
|
||||
shutil.copy("tips-custom-template.py", "tips.py")
|
||||
|
||||
# 检查temp目录
|
||||
if not os.path.exists("temp/"):
|
||||
os.mkdir("temp/")
|
||||
@@ -388,8 +360,19 @@ def check_file():
|
||||
if not os.path.exists(path):
|
||||
os.mkdir(path)
|
||||
|
||||
# 配置文件存在性校验
|
||||
if not os.path.exists('config.py'):
|
||||
shutil.copy('config-template.py', 'config.py')
|
||||
print('请先在config.py中填写配置')
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
def main():
|
||||
global use_override
|
||||
# 检查是否携带了 --override 或 -r 参数
|
||||
if '--override' in sys.argv or '-r' in sys.argv:
|
||||
use_override = True
|
||||
|
||||
# 初始化相关文件
|
||||
check_file()
|
||||
|
||||
@@ -401,6 +384,9 @@ def main():
|
||||
load_config()
|
||||
config = pkg.utils.context.get_config()
|
||||
|
||||
# 检查tips模块
|
||||
complete_tips()
|
||||
|
||||
# 配置线程池
|
||||
from pkg.utils import ThreadCtl
|
||||
thread_ctl = ThreadCtl(
|
||||
|
||||
@@ -63,16 +63,15 @@
|
||||
"font_path": "",
|
||||
"retry_times": 3,
|
||||
"hide_exce_info_to_user": false,
|
||||
"alter_tip_message": "出错了,请稍后再试",
|
||||
"sys_pool_num": 8,
|
||||
"admin_pool_num": 2,
|
||||
"user_pool_num": 6,
|
||||
"session_expire_time": 1200,
|
||||
"rate_limitation": 60,
|
||||
"rate_limit_strategy": "wait",
|
||||
"rate_limit_drop_tip": "本分钟对话次数超过限速次数,此对话被丢弃",
|
||||
"rate_limitation": {
|
||||
"default": 60
|
||||
},
|
||||
"rate_limit_strategy": "drop",
|
||||
"upgrade_dependencies": true,
|
||||
"report_usage": true,
|
||||
"logging_level": 20,
|
||||
"help_message": "此机器人通过调用大型语言模型生成回复,不具有情感。\n你可以用自然语言与其交流,回复的消息中[GPT]开头的为模型生成的语言,[bot]开头的为程序提示。\n欢迎到github.com/RockChinQ/QChatGPT 给个star"
|
||||
"logging_level": 20
|
||||
}
|
||||
@@ -69,7 +69,7 @@ class ModelRequest:
|
||||
self.error_info = "{}\n该错误可能是由于http_proxy格式设置错误引起的"
|
||||
except Exception as e:
|
||||
self.error_info = "{}\n由于请求异常产生的未知错误,请查看日志".format(e)
|
||||
raise Exception(self.error_info)
|
||||
raise type(e)(self.error_info)
|
||||
|
||||
def request(self, **kwargs):
|
||||
"""向接口发起请求"""
|
||||
|
||||
@@ -156,8 +156,8 @@ def install_plugin(repo_url: str):
|
||||
import pkg.utils.pkgmgr
|
||||
pkg.utils.pkgmgr.install_requirements("plugins/"+repo_url.split(".git")[0].split("/")[-1]+"/requirements.txt")
|
||||
|
||||
import main
|
||||
main.reset_logging()
|
||||
import pkg.utils.log as log
|
||||
log.reset_logging()
|
||||
|
||||
|
||||
def uninstall_plugin(plugin_name: str) -> str:
|
||||
|
||||
@@ -9,6 +9,9 @@ import json
|
||||
|
||||
|
||||
__command_list__ = {}
|
||||
|
||||
import tips as tips_custom
|
||||
|
||||
"""命令树
|
||||
|
||||
结构:
|
||||
@@ -262,7 +265,7 @@ def execute(context: Context) -> list:
|
||||
|
||||
# 检查权限
|
||||
if ctx.privilege < node['privilege']:
|
||||
raise CommandPrivilegeError('权限不足: {}'.format(path))
|
||||
raise CommandPrivilegeError(tips_custom.command_admin_message+"{}".format(path))
|
||||
|
||||
# 执行
|
||||
execed, reply = node['cls'].process(ctx)
|
||||
@@ -275,7 +278,7 @@ def execute(context: Context) -> list:
|
||||
path = path + '.' + ctx.crt_command
|
||||
except KeyError:
|
||||
traceback.print_exc()
|
||||
raise CommandPrivilegeError('找不到指令: {}'.format(path))
|
||||
raise CommandPrivilegeError(tips_custom.command_err_message+"{}".format(path))
|
||||
|
||||
|
||||
def register_all():
|
||||
|
||||
@@ -117,8 +117,8 @@ class PluginUpdateCommand(AbstractCommandNode):
|
||||
import pkg.utils.pkgmgr
|
||||
pkg.utils.pkgmgr.install_requirements("/".join(plugin['path'].split('/')[:-1])+"/requirements.txt")
|
||||
|
||||
import main
|
||||
main.reset_logging()
|
||||
import pkg.utils.log as log
|
||||
log.reset_logging()
|
||||
|
||||
pkg.utils.context.get_qqbot_manager().notify_admin("已更新插件: {}".format(", ".join(updated)))
|
||||
except Exception as e:
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
from ..aamgr import AbstractCommandNode, Context
|
||||
import tips as tips_custom
|
||||
|
||||
import pkg.openai.session
|
||||
import pkg.utils.context
|
||||
@@ -22,12 +23,12 @@ class ResetCommand(AbstractCommandNode):
|
||||
|
||||
if len(params) == 0:
|
||||
pkg.openai.session.get_session(session_name).reset(explicit=True)
|
||||
reply = ["[bot]会话已重置"]
|
||||
reply = [tips_custom.command_reset_message]
|
||||
else:
|
||||
try:
|
||||
import pkg.openai.dprompt as dprompt
|
||||
pkg.openai.session.get_session(session_name).reset(explicit=True, use_prompt=params[0])
|
||||
reply = ["[bot]会话已重置,使用场景预设:{}".format(dprompt.mode_inst().get_full_name(params[0]))]
|
||||
reply = [tips_custom.command_reset_name_message+"{}".format(dprompt.mode_inst().get_full_name(params[0]))]
|
||||
except Exception as e:
|
||||
reply = ["[bot]会话重置失败:{}".format(e)]
|
||||
|
||||
|
||||
84
pkg/qqbot/cmds/system/cconfig.py
Normal file
84
pkg/qqbot/cmds/system/cconfig.py
Normal file
@@ -0,0 +1,84 @@
|
||||
from ..aamgr import AbstractCommandNode, Context
|
||||
import json
|
||||
|
||||
|
||||
def config_operation(cmd, params):
|
||||
reply = []
|
||||
import pkg.utils.context
|
||||
config = pkg.utils.context.get_config()
|
||||
reply_str = ""
|
||||
if len(params) == 0:
|
||||
reply = ["[bot]err:请输入配置项"]
|
||||
else:
|
||||
cfg_name = params[0]
|
||||
if cfg_name == 'all':
|
||||
reply_str = "[bot]所有配置项:\n\n"
|
||||
for cfg in dir(config):
|
||||
if not cfg.startswith('__') and not cfg == 'logging':
|
||||
# 根据配置项类型进行格式化,如果是字典则转换为json并格式化
|
||||
if isinstance(getattr(config, cfg), str):
|
||||
reply_str += "{}: \"{}\"\n".format(cfg, getattr(config, cfg))
|
||||
elif isinstance(getattr(config, cfg), dict):
|
||||
# 不进行unicode转义,并格式化
|
||||
reply_str += "{}: {}\n".format(cfg,
|
||||
json.dumps(getattr(config, cfg),
|
||||
ensure_ascii=False, indent=4))
|
||||
else:
|
||||
reply_str += "{}: {}\n".format(cfg, getattr(config, cfg))
|
||||
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:
|
||||
reply = ["[bot]err:未找到配置项 {}".format(cfg_name)]
|
||||
|
||||
return reply
|
||||
|
||||
|
||||
@AbstractCommandNode.register(
|
||||
parent=None,
|
||||
name="cfg",
|
||||
description="配置项管理",
|
||||
usage="!cfg <配置项> [配置值]\n!cfg all",
|
||||
aliases=[],
|
||||
privilege=2
|
||||
)
|
||||
class CfgCommand(AbstractCommandNode):
|
||||
@classmethod
|
||||
def process(cls, ctx: Context) -> tuple[bool, list]:
|
||||
return True, config_operation(ctx.command, ctx.params)
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
from ..aamgr import AbstractCommandNode, Context, __command_list__
|
||||
|
||||
|
||||
@AbstractCommandNode.register(
|
||||
parent=None,
|
||||
name="cmd",
|
||||
description="显示指令列表",
|
||||
usage="!help\n!help <指令名称>",
|
||||
aliases=[],
|
||||
privilege=1
|
||||
)
|
||||
class CmdCommand(AbstractCommandNode):
|
||||
@classmethod
|
||||
def process(cls, ctx: Context) -> tuple[bool, list]:
|
||||
command_list = __command_list__
|
||||
|
||||
reply = []
|
||||
|
||||
if len(ctx.params) == 0:
|
||||
reply_str = "[bot]当前所有指令:\n\n"
|
||||
|
||||
# 遍历顶级指令
|
||||
for key in command_list:
|
||||
command = command_list[key]
|
||||
if command['parent'] is None:
|
||||
reply_str += "!{} - {}\n".format(key, command['description'])
|
||||
|
||||
reply_str += "\n请使用 !cmd <指令名称> 来查看指令的详细信息"
|
||||
|
||||
reply = [reply_str]
|
||||
else:
|
||||
command_name = ctx.params[0]
|
||||
if command_name in command_list:
|
||||
reply = [command_list[command_name]['cls'].help()]
|
||||
else:
|
||||
reply = ["[bot]指令 {} 不存在".format(command_name)]
|
||||
|
||||
return True, reply
|
||||
|
||||
@@ -12,8 +12,13 @@ from ..aamgr import AbstractCommandNode, Context
|
||||
class HelpCommand(AbstractCommandNode):
|
||||
@classmethod
|
||||
def process(cls, ctx: Context) -> tuple[bool, list]:
|
||||
import tips
|
||||
reply = ["[bot] "+tips.help_message + "\n请输入 !cmd 查看指令列表"]
|
||||
|
||||
# 警告config.help_message过时
|
||||
import config
|
||||
reply = [(config.help_message) + "\n请输入 !cmds 查看指令列表"]
|
||||
if hasattr(config, "help_message"):
|
||||
reply[0] += "\n\n警告:config.py中的help_message已过时,不再生效,请使用tips.py中的help_message替代"
|
||||
|
||||
return True, reply
|
||||
|
||||
@@ -54,7 +54,7 @@ def process_command(session_name: str, text_message: str, mgr, config,
|
||||
try:
|
||||
reply = cmdmgr.execute(context)
|
||||
except cmdmgr.CommandPrivilegeError as e:
|
||||
reply = ["[bot]err:{}".format(e)]
|
||||
reply = ["{}".format(e)]
|
||||
|
||||
return reply
|
||||
except Exception as e:
|
||||
|
||||
@@ -19,6 +19,7 @@ import pkg.utils.context
|
||||
|
||||
import pkg.plugin.host as plugin_host
|
||||
import pkg.plugin.models as plugin_models
|
||||
import tips as tips_custom
|
||||
|
||||
|
||||
# 检查消息是否符合泛响应匹配机制
|
||||
@@ -264,7 +265,7 @@ class QQBotManager:
|
||||
if failed == self.retry:
|
||||
pkg.openai.session.get_session('person_{}'.format(event.sender.id)).release_response_lock()
|
||||
self.notify_admin("{} 请求超时".format("person_{}".format(event.sender.id)))
|
||||
reply = ["[bot]err:请求超时"]
|
||||
reply = [tips_custom.reply_message]
|
||||
|
||||
if reply:
|
||||
return self.send(event, reply, check_quote=False)
|
||||
@@ -304,7 +305,7 @@ class QQBotManager:
|
||||
if failed == self.retry:
|
||||
pkg.openai.session.get_session('group_{}'.format(event.group.id)).release_response_lock()
|
||||
self.notify_admin("{} 请求超时".format("group_{}".format(event.group.id)))
|
||||
replys = ["[bot]err:请求超时"]
|
||||
replys = [tips_custom.replys_message]
|
||||
|
||||
return replys
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import pkg.openai.session
|
||||
import pkg.plugin.host as plugin_host
|
||||
import pkg.plugin.models as plugin_models
|
||||
import pkg.qqbot.blob as blob
|
||||
import tips as tips_custom
|
||||
|
||||
|
||||
def handle_exception(notify_admin: str = "", set_reply: str = "") -> list:
|
||||
@@ -14,7 +15,7 @@ def handle_exception(notify_admin: str = "", set_reply: str = "") -> list:
|
||||
import config
|
||||
pkg.utils.context.get_qqbot_manager().notify_admin(notify_admin)
|
||||
if config.hide_exce_info_to_user:
|
||||
return [config.alter_tip_message] if config.alter_tip_message else []
|
||||
return [tips_custom.alter_tip_message] if tips_custom.alter_tip_message else []
|
||||
else:
|
||||
return [set_reply]
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ import pkg.plugin.models as plugin_models
|
||||
import pkg.qqbot.ignore as ignore
|
||||
import pkg.qqbot.banlist as banlist
|
||||
import pkg.qqbot.blob as blob
|
||||
import tips as tips_custom
|
||||
|
||||
processing = []
|
||||
|
||||
@@ -118,7 +119,8 @@ def process_message(launcher_type: str, launcher_id: int, text_message: str, mes
|
||||
if config.rate_limit_strategy == "drop":
|
||||
if ratelimit.is_reach_limit(session_name):
|
||||
logging.info("根据限速策略丢弃[{}]消息: {}".format(session_name, text_message))
|
||||
return MessageChain(["[bot]"+config.rate_limit_drop_tip]) if config.rate_limit_drop_tip != "" else []
|
||||
|
||||
return MessageChain(["[bot]"+tips_custom.rate_limit_drop_tip]) if tips_custom.rate_limit_drop_tip != "" else []
|
||||
|
||||
before = time.time()
|
||||
# 触发插件事件
|
||||
|
||||
@@ -10,6 +10,20 @@ __crt_minute_usage__ = {}
|
||||
__timer_thr__: threading.Thread = None
|
||||
|
||||
|
||||
def get_limitation(session_name: str) -> int:
|
||||
"""获取会话的限制次数"""
|
||||
import config
|
||||
|
||||
if type(config.rate_limitation) == dict:
|
||||
# 如果被指定了
|
||||
if session_name in config.rate_limitation:
|
||||
return config.rate_limitation[session_name]
|
||||
else:
|
||||
return config.rate_limitation["default"]
|
||||
elif type(config.rate_limitation) == int:
|
||||
return config.rate_limitation
|
||||
|
||||
|
||||
def add_usage(session_name: str):
|
||||
"""增加会话的对话次数"""
|
||||
global __crt_minute_usage__
|
||||
@@ -56,9 +70,7 @@ def get_rest_wait_time(session_name: str, spent: float) -> float:
|
||||
"""获取会话此回合的剩余等待时间"""
|
||||
global __crt_minute_usage__
|
||||
|
||||
import config
|
||||
|
||||
min_seconds_per_round = 60.0 / config.rate_limitation
|
||||
min_seconds_per_round = 60.0 / get_limitation(session_name)
|
||||
|
||||
if session_name in __crt_minute_usage__:
|
||||
return max(0, min_seconds_per_round - spent)
|
||||
@@ -70,10 +82,8 @@ def is_reach_limit(session_name: str) -> bool:
|
||||
"""判断会话是否超过限制"""
|
||||
global __crt_minute_usage__
|
||||
|
||||
import config
|
||||
|
||||
if session_name in __crt_minute_usage__:
|
||||
return __crt_minute_usage__[session_name] >= config.rate_limitation
|
||||
return __crt_minute_usage__[session_name] >= get_limitation(session_name)
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
66
pkg/utils/log.py
Normal file
66
pkg/utils/log.py
Normal file
@@ -0,0 +1,66 @@
|
||||
import os
|
||||
import time
|
||||
import logging
|
||||
import shutil
|
||||
|
||||
|
||||
log_file_name = "qchatgpt.log"
|
||||
|
||||
|
||||
log_colors_config = {
|
||||
'DEBUG': 'green', # cyan white
|
||||
'INFO': 'white',
|
||||
'WARNING': 'yellow',
|
||||
'ERROR': 'red',
|
||||
'CRITICAL': 'cyan',
|
||||
}
|
||||
|
||||
|
||||
def init_runtime_log_file():
|
||||
"""为此次运行生成日志文件
|
||||
格式: qchatgpt-yyyy-MM-dd-HH-mm-ss.log
|
||||
"""
|
||||
global log_file_name
|
||||
|
||||
# 检查logs目录是否存在
|
||||
if not os.path.exists("logs"):
|
||||
os.mkdir("logs")
|
||||
|
||||
# 检查本目录是否有qchatgpt.log,若有,移动到logs目录
|
||||
if os.path.exists("qchatgpt.log"):
|
||||
shutil.move("qchatgpt.log", "logs/qchatgpt.legacy.log")
|
||||
|
||||
log_file_name = "logs/qchatgpt-%s.log" % time.strftime("%Y-%m-%d-%H-%M-%S", time.localtime())
|
||||
|
||||
|
||||
def reset_logging():
|
||||
global log_file_name
|
||||
|
||||
import config
|
||||
import pkg.utils.context
|
||||
import colorlog
|
||||
|
||||
if pkg.utils.context.context['logger_handler'] is not None:
|
||||
logging.getLogger().removeHandler(pkg.utils.context.context['logger_handler'])
|
||||
|
||||
for handler in logging.getLogger().handlers:
|
||||
logging.getLogger().removeHandler(handler)
|
||||
|
||||
logging.basicConfig(level=config.logging_level, # 设置日志输出格式
|
||||
filename=log_file_name, # log日志输出的文件位置和文件名
|
||||
format="[%(asctime)s.%(msecs)03d] %(filename)s (%(lineno)d) - [%(levelname)s] : %(message)s",
|
||||
# 日志输出的格式
|
||||
# -8表示占位符,让输出左对齐,输出长度都为8位
|
||||
datefmt="%Y-%m-%d %H:%M:%S" # 时间输出的格式
|
||||
)
|
||||
sh = logging.StreamHandler()
|
||||
sh.setLevel(config.logging_level)
|
||||
sh.setFormatter(colorlog.ColoredFormatter(
|
||||
fmt="%(log_color)s[%(asctime)s.%(msecs)03d] %(filename)s (%(lineno)d) - [%(levelname)s] : "
|
||||
"%(message)s",
|
||||
datefmt="%Y-%m-%d %H:%M:%S",
|
||||
log_colors=log_colors_config
|
||||
))
|
||||
logging.getLogger().addHandler(sh)
|
||||
pkg.utils.context.context['logger_handler'] = sh
|
||||
return sh
|
||||
@@ -1,21 +1,25 @@
|
||||
from pip._internal import main as pipmain
|
||||
|
||||
import main
|
||||
import pkg.utils.log as log
|
||||
|
||||
|
||||
def install(package):
|
||||
pipmain(['install', package])
|
||||
main.reset_logging()
|
||||
log.reset_logging()
|
||||
|
||||
def install_upgrade(package):
|
||||
pipmain(['install', '--upgrade', package])
|
||||
log.reset_logging()
|
||||
|
||||
|
||||
def run_pip(params: list):
|
||||
pipmain(params)
|
||||
main.reset_logging()
|
||||
log.reset_logging()
|
||||
|
||||
|
||||
def install_requirements(file):
|
||||
pipmain(['install', '-r', file, "--upgrade"])
|
||||
main.reset_logging()
|
||||
log.reset_logging()
|
||||
|
||||
|
||||
def ensure_dulwich():
|
||||
|
||||
@@ -41,15 +41,20 @@ def reload_all(notify=True):
|
||||
importlib.reload(__import__('config'))
|
||||
importlib.reload(__import__('main'))
|
||||
importlib.reload(__import__('banlist'))
|
||||
importlib.reload(__import__('tips'))
|
||||
context.context = this_context
|
||||
|
||||
# 重载插件
|
||||
import plugins
|
||||
walk(plugins)
|
||||
|
||||
# 初始化相关文件
|
||||
main.check_file()
|
||||
|
||||
# 执行启动流程
|
||||
logging.info("执行程序启动流程")
|
||||
main.load_config()
|
||||
main.complete_tips()
|
||||
context.get_thread_ctl().reload(
|
||||
admin_pool_num=context.get_config().admin_pool_num,
|
||||
user_pool_num=context.get_config().user_pool_num
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
requests~=2.28.1
|
||||
openai~=0.27.2
|
||||
openai~=0.27.4
|
||||
dulwich~=0.21.3
|
||||
colorlog~=6.6.0
|
||||
yiri-mirai~=0.2.6.1
|
||||
websockets~=10.4
|
||||
websockets
|
||||
urllib3~=1.26.10
|
||||
func_timeout~=4.3.5
|
||||
Pillow
|
||||
@@ -13,5 +13,5 @@ for key in cmdsmgr.__command_list__:
|
||||
template[key] = cmdsmgr.__command_list__[key]['privilege']
|
||||
|
||||
# 写入cmdpriv-template.json
|
||||
with open('cmdpriv-template.json', 'w') as f:
|
||||
with open('res/templates/cmdpriv-template.json', 'w') as f:
|
||||
f.write(json.dumps(template, indent=4, ensure_ascii=False))
|
||||
@@ -19,6 +19,7 @@
|
||||
"prompt": 1,
|
||||
"resend": 1,
|
||||
"reset": 1,
|
||||
"cfg": 2,
|
||||
"cmd": 1,
|
||||
"help": 1,
|
||||
"reload": 2,
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
## 简介
|
||||
|
||||
调用OpenAI官方提供的API接口,结合mirai和YiriMirai框架,将QQ消息与语言模型连接,实现更加智能的对话机器人。
|
||||
调用OpenAI官方提供的API接口,结合mirai和YiriMirai框架,将QQ消息与语言模型连接,实现更加智能的对话机器人
|
||||
|
||||
## 技术栈
|
||||
|
||||
|
||||
@@ -96,6 +96,12 @@
|
||||
- “丢弃”策略:此分钟内对话次数达到限制时,丢弃之后的对话
|
||||
- 详细请查看config.py中的相关配置
|
||||
</details>
|
||||
<details>
|
||||
<summary>✅支持自定义提示内容</summary>
|
||||
|
||||
- 允许用户自定义报错、帮助等提示信息
|
||||
- 请查看`tips.py`
|
||||
</details>
|
||||
|
||||
## 限制
|
||||
|
||||
|
||||
29
tips-custom-template.py
Normal file
29
tips-custom-template.py
Normal file
@@ -0,0 +1,29 @@
|
||||
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 = "本分钟对话次数超过限速次数,此对话被丢弃"
|
||||
|
||||
# 指令!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]:会话已重置,使用场景预设:"
|
||||
Reference in New Issue
Block a user