Files
AstrBot/cores/qqbot/core.py
Soulter bbecabb303 perf: 改善稳定性
feat: 查看配置
2022-12-12 09:48:12 +08:00

214 lines
7.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import botpy
from botpy.message import Message
import yaml
import asyncio
import cores.openai.core
import re
from util.errors.errors import PromptExceededError
from botpy.message import DirectMessage
import json
chatgpt = ""
# db = ""
session_dict = {}
max_tokens = 2000
version = "1.3"
gpt_config = {
'engine': '',
'temperature': '',
'top_p': '',
'frequency_penalty': '',
'presence_penalty': '',
'max_tokens': '',
}
class botClient(botpy.Client):
async def on_at_message_create(self, message: Message):
await oper_msg(message=message, at=True)
async def on_direct_message_create(self, message: DirectMessage):
await oper_msg(message=message, at=False)
def initBot(chatgpt_inst):
global chatgpt
chatgpt = chatgpt_inst
# global db
# db = db_inst
global max_tokens
max_tokens = int(chatgpt_inst.getConfigs()['total_tokens_limit'])
global gpt_config
gpt_config = chatgpt_inst.getConfigs()
gpt_config['key'] = "***"
with open("./configs/config.yaml", 'r', encoding='utf-8') as ymlfile:
cfg = yaml.safe_load(ymlfile)
if cfg['qqbot']['appid'] != '' or cfg['qqbot']['token'] != '':
print("读取QQBot appid token 成功")
intents = botpy.Intents(public_guild_messages=True, direct_message=True)
client = botClient(intents=intents)
client.run(appid=cfg['qqbot']['appid'], token=cfg['qqbot']['token'])
else:
raise BaseException("请在config中完善你的appid和token")
async def get_chatGPT_response(prompts_str):
res = ''
usage = ''
res, usage = await chatgpt.chat(prompts_str)
# 处理结果文本
chatgpt_res = res.strip()
return res, usage
def get_prompts_by_cache_list(cache_data_list, divide=False, paging=False, size=5, page=1):
prompts = ""
if paging:
page_begin = (page-1)*size
page_end = page*size
if page_begin < 0:
page_begin = 0
if page_end > len(cache_data_list):
page_end = len(cache_data_list)
cache_data_list = cache_data_list[page_begin:page_end]
for item in cache_data_list:
prompts += str(item['prompt'])
if divide:
prompts += "----------\n"
return prompts
def get_user_usage_tokens(cache_list):
usage_tokens = 0
for item in cache_list:
usage_tokens += int(item['single_tokens'])
return usage_tokens
async def oper_msg(message, at=False):
print("[QQBOT] 接收到消息:"+ message.content)
qq_msg = ""
if at:
# 过滤用户id
pattern = r"<@!\d+>\s+(.+)"
# 多行匹配
pattern = re.compile(pattern, flags=re.MULTILINE)
result = re.search(pattern, message.content)
if result:
qq_msg = result.group(1).strip()
else:
qq_msg = message.content
# 检测用户id返回对应缓存的prompt
# session_id_pattern = r"<@!\d+>"
# session_id_result = re.search(session_id_pattern, message.content)
session_id = message.author.id
if session_id:
if qq_msg == "/reset":
session_dict[session_id] = []
await message.reply(content=f"{message.member.nick}(id: {session_id}) 的历史记录重置成功")
return
if qq_msg[:4] == "/his":
#分页每页5条
size_per_page = 3
page = 1
if qq_msg[5:]:
page = int(qq_msg[5:])
l = session_dict[session_id]
max_page = len(l)//size_per_page + 1 if len(l)%size_per_page != 0 else len(l)//size_per_page
p = get_prompts_by_cache_list(session_dict[session_id], divide=True, paging=True, size=size_per_page, page=page)
await message.reply(content=f"{message.member.nick} 的历史记录如下:\n{p}\n{page}页 | 共{max_page}\n*输入/his 2跳转到第2页")
return
if qq_msg == "/token":
await message.reply(content=f"{message.member.nick} 会话的token数: {get_user_usage_tokens(session_dict[session_id])}\n系统最大缓存token数: {max_tokens}")
return
if qq_msg == "/status":
chatgpt_cfg_str = ""
for k, v in gpt_config.items():
if k == "key":
v = "***"
chatgpt_cfg_str += f"{k}: {v}"
await message.reply(content=f"ChatGPT配置:\n - {chatgpt_cfg_str}\n QQChannelChatGPT 版本: {version}")
return
if session_id not in session_dict:
session_dict[session_id] = []
# 获取缓存
cache_prompt = ''
cache_data_list = session_dict[session_id]
cache_prompt = get_prompts_by_cache_list(cache_data_list)
cache_prompt += "Human: "+ qq_msg + "\nAI: "
# 请求chatGPT获得结果
try:
chatgpt_res, current_usage_tokens = await get_chatGPT_response(cache_prompt)
except (PromptExceededError) as e:
print("出现token超限, 清空对应缓存")
# 超过4097tokens错误清空缓存
session_dict[session_id] = []
cache_data_list = []
cache_prompt = "Human: "+ qq_msg + "\nAI: "
chatgpt_res, current_usage_tokens = await get_chatGPT_response(cache_prompt)
except (BaseException) as e:
print("OpenAI API错误:(")
await message.reply(content=f"OpenAI API错误:( 原因如下:\n{str(e)} \n*可前往github . com/Soulter/QQChannelChatGPT进行反馈")
# 超过指定tokens 尽可能的保留最多的条目直到小于max_tokens
# print("current_usage_tokens: ", current_usage_tokens)
# print("max_tokens: ", max_tokens)
if current_usage_tokens > max_tokens:
t = current_usage_tokens
cache_list = session_dict[session_id]
index = 0
while t > max_tokens:
t -= int(cache_list[index]['single_tokens'])
index += 1
session_dict[session_id] = cache_list[index:]
cache_data_list = session_dict[session_id]
cache_prompt = get_prompts_by_cache_list(cache_data_list)
# cache_prompt += chatgpt_res + "\n";
# 添加新条目进入缓存的prompt
if len(cache_data_list) > 0:
single_record = {
"prompt": f'Human: {qq_msg}\nAI: {chatgpt_res}\n',
"usage_tokens": current_usage_tokens,
"single_tokens": current_usage_tokens - int(cache_data_list[-1]['usage_tokens'])
}
else:
single_record = {
"prompt": f'Human: {qq_msg}\nAI: {chatgpt_res}\n',
"usage_tokens": current_usage_tokens,
"single_tokens": current_usage_tokens
}
# print(single_record)
cache_data_list.append(single_record)
# 写入数据库
# try:
# data = {
# "data": cache_data_list
# }
# data_str = json.dumps(data)
# if len(cache_data_list) > 1:
# db.update_session(session_id, data_str)
# else:
# db.insert_session(session_id, data_str)
# except Exception as e:
# print(e)
# print("数据库写入失败")
session_dict[session_id] = cache_data_list
# #检测是否存在url如果存在则去除url 防止被qq频道过滤
chatgpt_res = chatgpt_res.replace(".", " . ")
# 发送qq信息
try:
await message.reply(content=f"[ChatGPT]{chatgpt_res}")
except BaseException as e:
print("QQ频道API错误: \n"+str(e))
f_res = ""
for t in chatgpt_res:
f_res += t + ' '
await message.reply(content=f"QQ频道API错误{str(e)}\n下面是格式化后的回答:\n{f_res}")