Compare commits

...

12 Commits

Author SHA1 Message Date
Soulter 4366572675 feat: 支持/gpt指令,查看配置 2023-03-02 09:46:29 +08:00
Soulter ffa3a0be3f Merge branch 'master' of https://github.com/Soulter/QQChannelChatGPT 2023-03-02 09:34:31 +08:00
Soulter 4dc214b27e feat: 支持官方ChatGPT API
perf: 提高了稳定性
2023-03-02 09:34:16 +08:00
Soulter 2baee48ff7 Update README.md 2023-02-28 19:26:57 +08:00
Soulter 74ae9cbee0 Update README.md 2023-02-28 08:46:52 +08:00
Soulter 1bfa325a6c Update README.md 2023-02-28 08:46:02 +08:00
Soulter 5663c1d6b2 Merge branch 'master' of https://github.com/Soulter/QQChannelChatGPT 2023-02-28 08:35:26 +08:00
Soulter 9a96456a77 feat: 支持在配置文件设置是否关闭私聊功能
fix: 修复了人格功能的一些bug
2023-02-28 08:35:05 +08:00
Soulter 9f741ef749 feat: 支持在配置文件设置是否关闭私聊功能
fix: 修复人格功能的一些bug
2023-02-28 08:34:04 +08:00
Soulter dadaa10924 Update requirements.txt 2023-02-27 09:18:23 +08:00
Soulter 6b596dcb12 Update README.md 2023-02-18 22:59:42 +08:00
Soulter 6d4d2bf84d fix: 修复了/help菜单的一些bug 2023-02-18 22:53:40 +08:00
6 changed files with 122 additions and 54 deletions
+12 -14
View File
@@ -1,23 +1,15 @@
## ⭐体验
扫码加入QQ频道
![image](https://user-images.githubusercontent.com/37870767/217891261-7f2bbede-a70a-4e9b-9cdd-15dcb06f6629.png)
使用手机QQ扫码加入QQ频道(频道名: GPT机器人 | 频道号: x42d56aki2)
![image](https://user-images.githubusercontent.com/37870767/221722540-d4b0fada-4fa2-4063-bb00-1bb3e4d9a747.png)
**推荐Windows一键安装(版本更新更及时)!!**
**请前往Release下载最新版本**
**详细部署教程链接**https://soulter.top/posts/qpdg.html
**详细部署教程链接**https://soulter.top/posts/qpdg.html
**Windows用户推荐Windows一键安装,请前往Release下载最新版本**
**详细部署教程链接**https://soulter.top/posts/qpdg.html
有任何问题请加频道反馈。
## ⭐功能:
### 基本功能
@@ -61,7 +53,7 @@
</details>
<details>
<summary>✅ 支持指令控制</summary>
<summary>✅ 支持多种指令控制</summary>
- 详见下方`指令功能`
@@ -85,18 +77,24 @@
- `/token`查看当前缓存的总token数
- `/count` 查看统计
- `/status` 查看chatGPT的配置
- `/help` 查看帮助
- `/key` 动态添加key
- `/set` 人格设置面板
## 📰使用方法:
**详细部署教程链接**https://soulter.top/posts/qpdg.html
### 安装第三方库
使用Python的pip工具安装
- `qq-botpy` QQ频道官方Python SDK
- `openai` (OpenAI )
- `openai` (OpenAI Python SDK)
```shell
pip install -r requirements.txt
```
> ⚠注意,由于qq-botpy需要运行在`Python 3.8+`的版本上,因此本项目也需要在此之上运行
> ⚠注意,由于qq-botpy需要运行在`Python 3.8+`的版本上,因此本项目也需要在此之上运行
### 配置
+23 -10
View File
@@ -6,15 +6,16 @@ openai:
# 在下方非注释的地方使用以上格式
key:
-
chatGPTConfigs:
engine: text-davinci-003
max_tokens: 800
temperature: 0.8
engine: "gpt-3.5-turbo"
max_tokens: 1000
temperature: 0.9
top_p: 1
frequency_penalty: 0.4
presence_penalty: 0.3
total_tokens_limit: 700
frequency_penalty: 0
presence_penalty: 0
total_tokens_limit: 2000
qqbot:
appid:
token:
@@ -22,8 +23,20 @@ qqbot:
# 设置是否一个人一个会话
uniqueSessionMode: false
# QChannelBot 的版本
version: 1.7 beta
# QChannelBot 的版本,请勿修改此字段,否则可能产生一些bug
version: 2.4 RealChatGPT Ver.
# [Beta] 转储历史记录时间间隔(分钟)
dump_history_interval: 10
dump_history_interval: 10
# 一个用户只能在time秒内发送count条消息
limit:
time: 60
count: 5
# 公告
notice: "此机器人由Github项目QQChannelChatGPT驱动。"
# 是否打开私信功能
# 设置为true则频道成员可以私聊机器人。
# 设置为false则频道成员不能私聊机器人。
direct_message_mode: true
+22 -17
View File
@@ -17,25 +17,28 @@ class ChatGPT:
with open(abs_path+"configs/config.yaml", 'r', encoding='utf-8') as ymlfile:
cfg = yaml.safe_load(ymlfile)
if cfg['openai']['key'] != '' or cfg['openai']['key'] != '修改我!!':
print("读取ChatGPT Key成功")
print("[System] 读取ChatGPT Key成功")
self.key_list = cfg['openai']['key']
# openai.api_key = cfg['openai']['key']
else:
input("请先去完善ChatGPT的Key。详情请前往https://beta.openai.com/account/api-keys")
input("[System] 请先去完善ChatGPT的Key。详情请前往https://beta.openai.com/account/api-keys")
# init key record
self.init_key_record()
chatGPT_configs = cfg['openai']['chatGPTConfigs']
print(f'加载ChatGPTConfigs: {chatGPT_configs}')
print(f'[System] 加载ChatGPTConfigs: {chatGPT_configs}')
self.chatGPT_configs = chatGPT_configs
self.openai_configs = cfg['openai']
def chat(self, prompt, image_mode = False):
# ChatGPT API 2023/3/2
messages = [{"role": "user", "content": prompt}]
try:
if not image_mode:
response = openai.Completion.create(
prompt=prompt,
response = openai.ChatCompletion.create(
messages=messages,
**self.chatGPT_configs
)
else:
@@ -47,7 +50,7 @@ class ChatGPT:
except Exception as e:
print(e)
if 'You exceeded' in str(e) or 'Billing hard limit has been reached' in str(e) or 'No API key provided.' in str(e):
print("当前Key已超额,正在切换")
print("[System] 当前Key已超额,正在切换")
self.key_stat[openai.api_key]['exceed'] = True
self.save_key_record()
@@ -57,8 +60,8 @@ class ChatGPT:
raise e
else:
if not image_mode:
response = openai.Completion.create(
prompt=prompt,
response = openai.ChatCompletion.create(
messages=messages,
**self.chatGPT_configs
)
else:
@@ -70,30 +73,31 @@ class ChatGPT:
if not image_mode:
self.key_stat[openai.api_key]['used'] += response['usage']['total_tokens']
self.save_key_record()
print("[ChatGPT] "+str(response["choices"][0]["text"]))
return str(response["choices"][0]["text"]).strip(), response['usage']['total_tokens']
print("[ChatGPT] "+str(response["choices"][0]["message"]["content"]))
return str(response["choices"][0]["message"]["content"]).strip(), response['usage']['total_tokens']
else:
return response['data'][0]['url']
def handle_switch_key(self, prompt):
messages = [{"role": "user", "content": prompt}]
while True:
is_all_exceed = True
for key in self.key_stat:
if not self.key_stat[key]['exceed']:
is_all_exceed = False
openai.api_key = key
print(f"切换到Key: {key}, 已使用token: {self.key_stat[key]['used']}")
print(f"[System] 切换到Key: {key}, 已使用token: {self.key_stat[key]['used']}")
if prompt != '':
try:
response = openai.Completion.create(
prompt=prompt,
response = openai.ChatCompletion.create(
messages=messages,
**self.chatGPT_configs
)
return response, True
except Exception as e:
print(e)
if 'You exceeded' in str(e):
print("当前Key已超额,正在切换")
print("[System] 当前Key已超额,正在切换")
self.key_stat[openai.api_key]['exceed'] = True
self.save_key_record()
time.sleep(1)
@@ -101,7 +105,7 @@ class ChatGPT:
else:
return True
if is_all_exceed:
print("所有Key已超额")
print("[System] 所有Key已超额")
return None, False
def getConfigs(self):
@@ -126,9 +130,10 @@ class ChatGPT:
def check_key(self, key):
pre_key = openai.api_key
openai.api_key = key
messages = [{"role": "user", "content": "1"}]
try:
openai.Completion.create(
prompt="1",
response = openai.ChatCompletion.create(
messages=messages,
**self.chatGPT_configs
)
openai.api_key = pre_key
+52 -11
View File
@@ -15,6 +15,7 @@ import os
import sys
from cores.qqbot.personality import personalities
history_dump_interval = 10
# QQBotClient实例
client = ''
@@ -51,9 +52,18 @@ announcement = ""
# 人格信息
now_personality = {}
# 机器人私聊模式
direct_message_mode = True
# 适配pyinstaller
abs_path = os.path.dirname(os.path.realpath(sys.argv[0])) + '/'
# 版本
version = '2.4 RealChatGPT Ver.'
# gpt配置信息
gpt_config = {}
def new_sub_thread(func, args=()):
thread = threading.Thread(target=func, args=args, daemon=True)
thread.start()
@@ -68,10 +78,11 @@ class botClient(botpy.Client):
# 收到私聊消息
async def on_direct_message_create(self, message: DirectMessage):
toggle_count(at=False, message=message)
# executor.submit(oper_msg, message, True)
# await oper_msg(message=message, at=False)
new_sub_thread(oper_msg, (message, False))
if direct_message_mode:
toggle_count(at=False, message=message)
# executor.submit(oper_msg, message, True)
# await oper_msg(message=message, at=False)
new_sub_thread(oper_msg, (message, False))
# 写入统计信息
def toggle_count(at: bool, message):
@@ -117,7 +128,7 @@ def dump_history():
# 每隔10分钟转储一次
time.sleep(10*history_dump_interval)
# 上传统计信息
# 上传统计信息并检查更新
def upload():
global object_id
while True:
@@ -136,7 +147,7 @@ def upload():
'Content-Type': 'application/json'
}
key_stat = chatgpt.get_key_stat()
d = {"data": {"guild_count": guild_count, "guild_msg_count": guild_msg_count, "guild_direct_msg_count": guild_direct_msg_count, "session_count": session_count, 'addr': addr, 'winver': '2.21', 'key_stat':key_stat}}
d = {"data": {"guild_count": guild_count, "guild_msg_count": guild_msg_count, "guild_direct_msg_count": guild_direct_msg_count, "session_count": session_count, 'addr': addr, 'winver': '2.3', 'key_stat':key_stat}}
d = json.dumps(d).encode("utf-8")
res = requests.put(f'https://uqfxtww1.lc-cn-n1-shared.com/1.1/classes/bot_record/{object_id}', headers = headers, data = d)
if json.loads(res.text)['code'] == 1:
@@ -202,10 +213,24 @@ def initBot(chatgpt_inst):
# 创建上传定时器线程
threading.Thread(target=upload, daemon=True).start()
global config, uniqueSession, history_dump_interval, frequency_count, frequency_time,announcement
global gpt_config, config, uniqueSession, history_dump_interval, frequency_count, frequency_time,announcement, direct_message_mode, version
with open(abs_path+"configs/config.yaml", 'r', encoding='utf-8') as ymlfile:
cfg = yaml.safe_load(ymlfile)
config = cfg
# 得到私聊模式配置
if 'direct_message_mode' in cfg:
direct_message_mode = cfg['direct_message_mode']
print("[System] 私聊功能: "+str(direct_message_mode))
# 得到GPT配置信息
if 'openai' in cfg and 'chatGPTConfigs' in cfg['openai']:
gpt_config = cfg['openai']['chatGPTConfigs']
# 得到版本
if 'version' in cfg:
version = cfg['version']
print("[System] QQChannelChatGPT版本: "+str(version))
# 得到发言频率配置
if 'limit' in cfg:
@@ -215,7 +240,7 @@ def initBot(chatgpt_inst):
if 'time' in cfg['limit']:
frequency_time = cfg['limit']['time']
announcement += '[QQChannelChatGPT项目]\n所有回答与腾讯公司无关。出现问题请前往[ChatGPT机器人]官方频道\n\n'
announcement += '[QQChannelChatGPT项目]\n所有回答与腾讯公司无关。出现问题请前往[GPT机器人]官方频道\n\n'
# 得到公告配置
if 'notice' in cfg:
print('[System] 公告配置: '+cfg['notice'])
@@ -234,11 +259,15 @@ def initBot(chatgpt_inst):
print(f"[System] QQ开放平台AppID: {cfg['qqbot']['appid']} 令牌: {cfg['qqbot']['token']}")
print("[System] 如果有任何问题,请在https://github.com/Soulter/QQChannelChatGPT上提交issue说明问题!或者添加QQ905617992\n")
print("\n[System] 如果有任何问题,请在https://github.com/Soulter/QQChannelChatGPT上提交issue说明问题!或者添加QQ905617992")
print("[System] 请给https://github.com/Soulter/QQChannelChatGPT点个star!")
print("[System] 请给https://github.com/Soulter/QQChannelChatGPT点个star!")
input("\n仔细阅读完以上信息后,输入任意信息并回车以继续")
try:
run_bot(cfg['qqbot']['appid'], cfg['qqbot']['token'])
except BaseException as e:
input(f"\n[System-Error] 启动QQ机器人时出现错误,原因如下:{e}\n可能是没有填写QQBOT appid和token?请在config中完善你的appid和token\n配置教程:https://soulter.top/posts/qpdg.html\n")
'''
启动机器人
@@ -487,7 +516,7 @@ def oper_msg(message, at=False, loop=None):
while t > max_tokens:
if index >= len(cache_data_list):
break
if cache_data_list[index]['level'] != 'max':
if 'level' in cache_data_list[index] and cache_data_list[index]['level'] != 'max':
t -= int(cache_data_list[index]['single_tokens'])
del cache_data_list[index]
else:
@@ -591,6 +620,10 @@ def command_oper(qq_msg, message, session_id, name, user_id, user_name, at):
else:
msg=f"会话的token数: {get_user_usage_tokens(session_dict[session_id])}\n系统最大缓存token数: {max_tokens}"
if qq_msg == '/gpt':
global gpt_config
msg=f"OpenAI GPT配置:\n {gpt_config}"
if qq_msg == "/status" or qq_msg == "/状态":
chatgpt_cfg_str = ""
key_stat = chatgpt.get_key_stat()
@@ -616,7 +649,15 @@ def command_oper(qq_msg, message, session_id, name, user_id, user_name, at):
msg = f"当前会话数: {len(session_dict)}\n共有频道数: {guild_count} \n共有消息数: {guild_msg_count}\n私信数: {guild_direct_msg_count}\n历史会话数: {session_count}"
if qq_msg == "/help":
msg = "[Github项目名: QQChannelChatGPT,有问题请前往提交issue,欢迎赞助支持我!]\n\n指令面板:\n/status 查看机器人key状态\n/count 查看机器人统计信息\n/reset 重置会话\n/his 查看历史记录\n/token 查看会话token数\n/help 查看帮助\n/key 人格指令菜单"
ol_version = 'Unknown'
try:
global version
res = requests.get("https://soulter.top/channelbot/update.json")
res_obj = json.loads(res.text)
ol_version = res_obj['version']
except BaseException:
pass
msg = f"[Github项目名: QQChannelChatGPT,有问题请前往提交issue,欢迎Star此项目~]\n\n当前版本:{version}\n最新版本:{str(ol_version)}\n请及时更新!\n\n指令面板:\n/status 查看机器人key状态\n/count 查看机器人统计信息\n/reset 重置会话\n/his 查看历史记录\n/token 查看会话token数\n/help 查看帮助\n/set 人格指令菜单\n/key 动态添加key"
if qq_msg[:4] == "/key":
if len(qq_msg) == 4:
+2 -2
View File
@@ -1,3 +1,3 @@
requests~=2.28.2
requests~=2.27.1
openai~=0.26.5
qq-botpy~=1.1.2
qq-botpy~=1.1.2
+11
View File
@@ -0,0 +1,11 @@
import logging
from logging.handlers import RotatingFileHandler
import colorlog
logger = logging.getLogger("QQChannelChatGPT")
logger.setLevel(logging.DEBUG)
handler = colorlog.StreamHandler()
fmt = "%(log_color)s[%(name)s] %(message)s"
handler.setFormatter(colorlog.ColoredFormatter(
fmt))
logger.addHandler(handler)