diff --git a/addons/revChatGPT/revchatgpt.py b/addons/revChatGPT/revchatgpt.py index 7257642e9..31fbf54a9 100644 --- a/addons/revChatGPT/revchatgpt.py +++ b/addons/revChatGPT/revchatgpt.py @@ -3,8 +3,8 @@ from revChatGPT.V1 import Chatbot class revChatGPT: def __init__(self, config): - print("[RevChatGPT] 逆向库初始化:"+str(config)) - config['password'] = str(config['password']) + if 'password' in config: + config['password'] = str(config['password']) self.chatbot = Chatbot(config=config) def chat(self, prompt): diff --git a/configs/config.yaml b/configs/config.yaml index 7fcd33984..f577db6c9 100644 --- a/configs/config.yaml +++ b/configs/config.yaml @@ -56,20 +56,30 @@ direct_message_mode: true # enable设置为true后,将会停止使用上面正常的官方API调用而使用本逆向项目 # # 多账户可以保证每个请求都能得到及时的回复。 -# 关于account的格式 + + +# 关于account的格式,请你务必认真阅读以下格式。 + + +# account支持email+password、session_token、access_token多种方式登录。 +# 如果要使用session_token、access_token登录,直接添加新的一行(注意缩进!) - access_token: xxxxxxx即可 # account: +# - session_token: xxxxxxxx +# - access_token: xxxxxxxx # - email: 第1个账户 # password: 第1个账户密码 # - email: 第2个账户 # password: 第2个账户密码 # - .... # 请严格按照上面这个格式填写。 -# 这里我免费提供2个账号给大家,不过用的人一定会很多的,所以会造成一些bug,因此还是用自己的账号好一点。 +# 这里免费提供2个账号给大家,不过用的人一定会很多的,所以会造成一些bug,因此还是用自己的账号好一点。 # 需要账号可以联系我。QQ905617992 rev_ChatGPT: enable: false account: + - access_token: + # - session_token: xxxxxxxx - email: d.o.m.her.ry61.7@gmail.com password: 11111111 - email: ca.it.li.nal.o.i.si.o91@gmail.com diff --git a/cores/openai/core.py b/cores/openai/core.py index 1dd0f997e..b3466e9af 100644 --- a/cores/openai/core.py +++ b/cores/openai/core.py @@ -29,55 +29,37 @@ class ChatGPT: self.chatGPT_configs = chatGPT_configs self.openai_configs = cfg - def chat(self, prompt, image_mode = False): + def chat(self, req, image_mode = False): # ChatGPT API 2023/3/2 - messages = [{"role": "user", "content": prompt}] + # messages = [{"role": "user", "content": prompt}] try: - if not image_mode: - - response = openai.ChatCompletion.create( - messages=messages, - **self.chatGPT_configs - ) - else: - response = openai.Image.create( - prompt=prompt, - n=1, - size="512x512", - ) + response = openai.ChatCompletion.create( + messages=req, + **self.chatGPT_configs + ) 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("[System] 当前Key已超额,正在切换") + if 'You exceeded' in str(e) or 'Billing hard limit has been reached' in str(e) or 'No API key provided' in str(e) or 'Incorrect API key provided' in str(e): + print("[System] 当前Key已超额或者不正常,正在切换") self.key_stat[openai.api_key]['exceed'] = True self.save_key_record() - response, is_switched = self.handle_switch_key(prompt) + response, is_switched = self.handle_switch_key(req) if not is_switched: - # 所有Key都超额 + # 所有Key都超额或不正常 raise e else: - if not image_mode: - response = openai.ChatCompletion.create( - messages=messages, - **self.chatGPT_configs - ) - else: - response = openai.Image.create( - prompt=prompt, - n=1, - size="512x512", - ) - 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]["message"]["content"])) - return str(response["choices"][0]["message"]["content"]).strip(), response['usage']['total_tokens'] - else: - return response['data'][0]['url'] + response = openai.ChatCompletion.create( + messages=req, + **self.chatGPT_configs + ) + self.key_stat[openai.api_key]['used'] += response['usage']['total_tokens'] + self.save_key_record() + print("[ChatGPT] "+str(response["choices"][0]["message"]["content"])) + return str(response["choices"][0]["message"]["content"]).strip(), response['usage']['total_tokens'] - def handle_switch_key(self, prompt): - messages = [{"role": "user", "content": prompt}] + def handle_switch_key(self, req): + # messages = [{"role": "user", "content": prompt}] while True: is_all_exceed = True for key in self.key_stat: @@ -85,10 +67,10 @@ class ChatGPT: is_all_exceed = False openai.api_key = key print(f"[System] 切换到Key: {key}, 已使用token: {self.key_stat[key]['used']}") - if prompt != '': + if len(req) > 0: try: response = openai.ChatCompletion.create( - messages=messages, + messages=req, **self.chatGPT_configs ) return response, True diff --git a/cores/qqbot/core.py b/cores/qqbot/core.py index f660f8e02..d581a2af1 100644 --- a/cores/qqbot/core.py +++ b/cores/qqbot/core.py @@ -187,17 +187,18 @@ def initBot(cfg, prov): if 'account' in cfg['rev_ChatGPT']: from addons.revChatGPT.revchatgpt import revChatGPT for i in range(0, len(cfg['rev_ChatGPT']['account'])): - print(f"[System] 正在创建rev_ChatGPT负载{str(i)}: " + cfg['rev_ChatGPT']['account'][i]['email']) try: + print(f"[System] 创建rev_ChatGPT负载{str(i)}: " + str(cfg['rev_ChatGPT']['account'][i])) revstat = { 'obj': revChatGPT(cfg['rev_ChatGPT']['account'][i]), 'busy': False } rev_chatgpt.append(revstat) + except: print("[System] 创建rev_ChatGPT负载失败") else: - input("[System-err] 请退出本程序, 然后在配置文件中填写rev_ChatGPT的email和password") + input("[System-err] 请退出本程序, 然后在配置文件中填写rev_ChatGPT相关配置") elif prov == OPENAI_OFFICIAL: from cores.openai.core import ChatGPT chatgpt = ChatGPT(cfg['openai']) @@ -307,16 +308,23 @@ def run_bot(appid, token): ''' 得到OpenAI官方API的回复 ''' -def get_chatGPT_response(prompts_str, image_mode=False): +def get_chatGPT_response(context, request, image_mode=False): res = '' usage = '' + + req_list = [] + for i in context: + req_list.append(i['user']) + req_list.append(i['AI']) + req_list.append(request['user']) + if not image_mode: - res, usage = chatgpt.chat(prompts_str) + res, usage = chatgpt.chat(req_list) # 处理结果文本 chatgpt_res = res.strip() return res, usage else: - res = chatgpt.chat(prompts_str, image_mode = True) + res = chatgpt.chat(req_list, image_mode = True) return res ''' @@ -345,9 +353,11 @@ def get_rev_ChatGPT_response(prompts_str): def send_qq_msg(message, res, image_mode=False): if not image_mode: try: - asyncio.run_coroutine_threadsafe(message.reply(content=res), client.loop) - except: - raise + res = asyncio.run_coroutine_threadsafe(message.reply(content=res), client.loop) + res.result() + except BaseException as e: + print("[System-Error] 回复QQ消息失败") + raise e else: asyncio.run_coroutine_threadsafe(message.reply(image=res, content=""), client.loop) @@ -366,10 +376,13 @@ def get_prompts_by_cache_list(cache_data_list, divide=False, paging=False, size= 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']) + prompts += str(item['user']['role']) + ":\n" + str(item['user']['content']) + "\n" + prompts += str(item['AI']['role']) + ":\n" + str(item['AI']['content']) + "\n" + if divide: prompts += "----------\n" return prompts + def get_user_usage_tokens(cache_list): usage_tokens = 0 @@ -494,26 +507,44 @@ def oper_msg(message, at=False, loop=None): if provider == OPENAI_OFFICIAL: # 获取缓存 - cache_prompt = '' + # cache_prompt = '' cache_data_list = session_dict[session_id] - cache_prompt = get_prompts_by_cache_list(cache_data_list) - cache_prompt += "\nHuman: "+ qq_msg + "\nAI: " + # cache_prompt = get_prompts_by_cache_list(cache_data_list) + # cache_prompt += "\nHuman: "+ qq_msg + "\nAI: " + + # 创建一个新的Record + + record_obj = { + "user": { + "role": "user", + "content": qq_msg, + }, + "AI": {}, + 'usage_tokens': 0, + 'level': 'normal', + } + + if command_type == 1: + record_obj['user'] = 'system' + + print("[Debug] "+ str(cache_data_list)) # 请求chatGPT获得结果 try: - chatgpt_res, current_usage_tokens = get_chatGPT_response(prompts_str=cache_prompt) + chatgpt_res, current_usage_tokens = get_chatGPT_response(context=cache_data_list, request=record_obj) except (BaseException) as e: print("[System-Err] OpenAI API错误。原因如下:\n"+str(e)) if 'maximum context length' in str(e): print("token超限, 清空对应缓存") session_dict[session_id] = [] cache_data_list = [] - cache_prompt = "Human: "+ qq_msg + "\nAI: " - chatgpt_res, current_usage_tokens = get_chatGPT_response(prompts_str=cache_prompt) + chatgpt_res, current_usage_tokens = get_chatGPT_response(context=cache_data_list, request=record_obj) elif 'exceeded' in str(e): send_qq_msg(message, f"OpenAI API错误。原因:\n{str(e)} \n超额了。可自己搭建一个机器人(Github仓库:QQChannelChatGPT)") else: - send_qq_msg(message, f"OpenAI API错误。原因如下:\n{str(e)} \n前往官方频道反馈~") + f_res = re.sub(r'(https|http)?:\/\/(\w|\.|\/|\?|\=|\&|\%)*\b', '[被隐藏的链接]', str(e), flags=re.MULTILINE) + f_res = f_res.replace(".", "·") + send_qq_msg(message, f"OpenAI API错误。原因如下:\n{f_res} \n前往官方频道反馈~") return # 超过指定tokens, 尽可能的保留最多的条目,直到小于max_tokens @@ -530,28 +561,44 @@ def oper_msg(message, at=False, loop=None): index += 1 # 删除完后更新相关字段 session_dict[session_id] = cache_data_list - cache_prompt = get_prompts_by_cache_list(cache_data_list) + # cache_prompt = get_prompts_by_cache_list(cache_data_list) - # 添加新条目进入缓存的prompt + # 人格置顶 if command_type == 1: level = 'max' else: level = 'normal' - 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']), - "level": level - } + + # 添加新条目进入缓存的prompt + record_obj['AI'] = { + 'role': 'assistant', + 'content': chatgpt_res, + } + record_obj['usage_tokens'] = current_usage_tokens + if len(cache_data_list) > 0: + record_obj['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, - "level": level - } - cache_data_list.append(single_record) + record_obj['single_tokens'] = current_usage_tokens + record_obj['level'] = level + + cache_data_list.append(record_obj) + # if len(cache_data_list) > 0: + # single_record = { + # 'role': 'assistant', + # "content": chatgpt_res, + # "usage_tokens": current_usage_tokens, + # "single_tokens": current_usage_tokens - int(cache_data_list[-1]['usage_tokens']), + # "level": level + # } + # else: + # single_record = { + # 'role': 'assistant', + # "prompt": f'Human: {qq_msg}\nAI: {chatgpt_res}\n', + # "usage_tokens": current_usage_tokens, + # "single_tokens": current_usage_tokens, + # "level": level + # } + # cache_data_list.append(single_record) session_dict[session_id] = cache_data_list elif provider == REV_CHATGPT: @@ -574,7 +621,7 @@ def oper_msg(message, at=False, loop=None): gap_chatgpt_res = gap_chatgpt_res.replace(i, "***") # 发送信息 send_qq_msg(message, ''+gap_chatgpt_res) - except: + except BaseException as e: print("QQ频道API错误: \n"+str(e)) f_res = "" for t in chatgpt_res: @@ -582,9 +629,9 @@ def oper_msg(message, at=False, loop=None): try: send_qq_msg(message, ''+f_res) # send(message, f"QQ频道API错误:{str(e)}\n下面是格式化后的回答:\n{f_res}") - except: + except BaseException as e: # 如果还是不行则过滤url - f_res = re.sub(r'(https|http)?:\/\/(\w|\.|\/|\?|\=|\&|\%)*\b', '', f_res, flags=re.MULTILINE) + f_res = re.sub(r'(https|http)?:\/\/(\w|\.|\/|\?|\=|\&|\%)*\b', '[被隐藏的链接]', str(e), flags=re.MULTILINE) f_res = f_res.replace(".", "·") send_qq_msg(message, ''+f_res) # send(message, f"QQ频道API错误:{str(e)}\n下面是格式化后的回答:\n{f_res}")