diff --git a/chatgpt_key_record b/chatgpt_key_record new file mode 100644 index 000000000..e69de29bb diff --git a/configs/config.yaml b/configs/config.yaml index 973c1d0ed..a01de698a 100644 --- a/configs/config.yaml +++ b/configs/config.yaml @@ -1,5 +1,11 @@ openai: + # 注意:在1.7版本已支持多key自动切换,方法: + # key: + # - xxxxx + # - xxxxxx + # 在下方非注释的地方使用以上格式 key: + - chatGPTConfigs: engine: text-davinci-003 max_tokens: 800 @@ -8,6 +14,7 @@ openai: frequency_penalty: 0.4 presence_penalty: 0.3 total_tokens_limit: 700 + qqbot: appid: token: @@ -16,7 +23,7 @@ qqbot: uniqueSessionMode: false # QChannelBot 的版本 -version: 1.6 beta +version: 1.7 beta # [Beta] 转储历史记录时间间隔(分钟) dump_history_interval: 10 \ No newline at end of file diff --git a/cores/openai/core.py b/cores/openai/core.py index 588f652e2..f5e8971ab 100644 --- a/cores/openai/core.py +++ b/cores/openai/core.py @@ -1,19 +1,46 @@ import openai import yaml from util.errors.errors import PromptExceededError - +import json +import time inst = None class ChatGPT: def __init__(self): + self.key_list = [] with open("./configs/config.yaml", 'r', encoding='utf-8') as ymlfile: cfg = yaml.safe_load(ymlfile) if cfg['openai']['key'] != '': print("读取ChatGPT Key成功") - openai.api_key = cfg['openai']['key'] + self.key_list = cfg['openai']['key'] + print(f"Key列表: {self.key_list}") + # openai.api_key = cfg['openai']['key'] else: print("请先去完善ChatGPT的Key。详情请前往https://beta.openai.com/account/api-keys") + + with open("chatgpt_key_record", 'r', encoding='utf-8') as keyfile: + try: + self.key_stat = json.load(keyfile) + except Exception as e: + print(e) + self.key_stat = {} + finally: + for key in self.key_list: + if key not in self.key_stat: + self.key_stat[key] = {'exceed': False, 'used': 0} + if openai.api_key is None: + print("切换") + openai.api_key = key + else: + if self.key_stat[key]['exceed']: + print(f"Key: {key} 已超额") + continue + else: + openai.api_key = key + print(f"使用Key: {key}, 已使用token: {self.key_stat[key]['used']}") + break + self.save_key_record() chatGPT_configs = cfg['openai']['chatGPTConfigs'] print(f'加载ChatGPTConfigs: {chatGPT_configs}') @@ -23,21 +50,67 @@ class ChatGPT: inst = self def chat(self, prompt): - print("[OpenAI API]收到") try: response = openai.Completion.create( prompt=prompt, **self.chatGPT_configs ) - except(openai.error.InvalidRequestError) as e: - raise PromptExceededError("OpenAI遇到错误:输入了一个不合法的请求。\n"+str(e)) + # except(openai.error.InvalidRequestError) as e: + # raise PromptExceededError("OpenAI遇到错误:输入了一个不合法的请求。\n"+str(e)) + except Exception as e: + print(e) + if 'You exceeded' in str(e): + print("当前Key已超额,正在切换") + self.key_stat[openai.api_key]['exceed'] = True + self.save_key_record() + response, is_switched = self.handle_switch_key(prompt) + if not is_switched: + # 所有Key都超额 + raise e # print(response['usage']) + self.key_stat[openai.api_key]['used'] += response['usage']['total_tokens'] + self.save_key_record() print("[ChatGPT] "+response["choices"][0]["text"]) return response["choices"][0]["text"].strip(), response['usage']['total_tokens'] + def handle_switch_key(self, 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']}") + try: + response = openai.Completion.create( + prompt=prompt, + **self.chatGPT_configs + ) + return response, True + except Exception as e: + print(e) + if 'You exceeded' in str(e): + print("当前Key已超额,正在切换") + self.key_stat[openai.api_key]['exceed'] = True + self.save_key_record() + time.sleep(1) + continue + if is_all_exceed: + print("所有Key已超额") + return None, False + def getConfigs(self): return self.openai_configs + + def save_key_record(self): + with open("chatgpt_key_record", 'w', encoding='utf-8') as f: + json.dump(self.key_stat, f) + + def get_key_stat(self): + return self.key_stat + def get_key_list(self): + return self.key_list def getInst() -> ChatGPT: global inst diff --git a/cores/qqbot/core.py b/cores/qqbot/core.py index aa67732bb..232b2347d 100644 --- a/cores/qqbot/core.py +++ b/cores/qqbot/core.py @@ -85,7 +85,7 @@ def dump_history(): db = dbConn() while True: try: - print("转储历史记录...") + # print("转储历史记录...") for key in session_dict: # print("TEST: "+str(db.get_session(key))) data = session_dict[key] @@ -96,7 +96,7 @@ def dump_history(): db.update_session(key, json.dumps(data_json)) else: db.insert_session(key, json.dumps(data_json)) - print("转储历史记录完毕") + # print("转储历史记录完毕") except BaseException as e: print(e) # 每隔10分钟转储一次 @@ -278,7 +278,24 @@ def oper_msg(message, at=False, loop=None): if k == "key": continue chatgpt_cfg_str += f"{k}: {v}" - send_qq_msg(message, f"ChatGPT配置:\n - {chatgpt_cfg_str}\n QQChannelChatGPT 版本: {version}") + + key_stat = chatgpt.get_key_stat() + key_list = chatgpt.get_key_list() + chatgpt_cfg_str += '\n\n配额使用情况:\n' + index = 1 + max = 900000 + for key in key_list: + if key in key_stat: + if key_stat[key]['exceed']: + chatgpt_cfg_str += f"#{index}: 已寄\n" + index += 1 + continue + # chatgpt_cfg_str += f"#{index}: {round(key_stat[key]['used']/max*100, 2)}%\n" + chatgpt_cfg_str += f"#{index}: {key_stat[key]['used']}/{max}\n" + index += 1 + chatgpt_cfg_str += '\n注: 配额情况在某些极端情况下具有一定的不准确性。\n' + print("生成...") + send_qq_msg(message, f"ChatGPT配置:\n {chatgpt_cfg_str}\n QQChannelChatGPT 版本: {version}") return if qq_msg == "/count": try: