From aee1bef4289d1fa57e35919ee5c0ef7df867b1ae Mon Sep 17 00:00:00 2001 From: ikaros <327209194@qq.com> Date: Fri, 19 Apr 2024 23:23:10 +0800 Subject: [PATCH] =?UTF-8?q?LLM=E6=96=B0=E5=A2=9Egpt4free=EF=BC=8C=E5=85=B7?= =?UTF-8?q?=E4=BD=93=E5=93=AA=E4=BA=9B=E4=BE=9B=E5=BA=94=E5=95=86=E5=A5=BD?= =?UTF-8?q?=E7=94=A8=E5=BE=97=E8=87=AA=E8=A1=8C=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config.json | 17 ++++- config.json.bak | 17 ++++- tests/test_gpt4free/api.py | 107 ++++++++++++++++++++++++++++++ utils/gpt_model/gpt.py | 2 + utils/gpt_model/gpt4free.py | 125 ++++++++++++++++++++++++++++++++++++ utils/gpt_model/tongyi.py | 2 +- utils/my_handle.py | 7 +- webui.py | 77 +++++++++++++++++++++- 8 files changed, 344 insertions(+), 10 deletions(-) create mode 100644 tests/test_gpt4free/api.py create mode 100644 utils/gpt_model/gpt4free.py diff --git a/config.json b/config.json index 3511418b..7a4ca4e2 100644 --- a/config.json +++ b/config.json @@ -216,6 +216,16 @@ "frequency_penalty": 0.0, "preset": "请扮演一个AI虚拟主播。不要回答任何敏感问题!不要强调你是主播,只需要回答问题!" }, + "gpt4free": { + "provider": "", + "api_key": "", + "model": "gpt-3.5-turbo", + "max_tokens": 2048, + "proxy": "http://127.0.0.1:10809", + "preset": "请扮演一个AI虚拟主播。不要回答任何敏感问题!不要强调你是主播,只需要回答问题!", + "history_enable": true, + "history_max_len": 300 + }, "claude": { "slack_user_token": "", "bot_user_id": "" @@ -692,7 +702,7 @@ } }, "choose_song": { - "enable": true, + "enable": false, "similarity": 0.5, "start_cmd": [ "点歌 ", @@ -1037,7 +1047,7 @@ } }, "key_mapping": { - "enable": true, + "enable": false, "type": "弹幕+回复", "key_trigger_type": "关键词+礼物", "key_single_sentence_trigger_once": true, @@ -1607,7 +1617,8 @@ "gemini": true, "qanything": true, "koboldcpp": true, - "anythingllm": true + "anythingllm": true, + "gpt4free": true }, "tts": { "edge-tts": true, diff --git a/config.json.bak b/config.json.bak index 3511418b..7a4ca4e2 100644 --- a/config.json.bak +++ b/config.json.bak @@ -216,6 +216,16 @@ "frequency_penalty": 0.0, "preset": "请扮演一个AI虚拟主播。不要回答任何敏感问题!不要强调你是主播,只需要回答问题!" }, + "gpt4free": { + "provider": "", + "api_key": "", + "model": "gpt-3.5-turbo", + "max_tokens": 2048, + "proxy": "http://127.0.0.1:10809", + "preset": "请扮演一个AI虚拟主播。不要回答任何敏感问题!不要强调你是主播,只需要回答问题!", + "history_enable": true, + "history_max_len": 300 + }, "claude": { "slack_user_token": "", "bot_user_id": "" @@ -692,7 +702,7 @@ } }, "choose_song": { - "enable": true, + "enable": false, "similarity": 0.5, "start_cmd": [ "点歌 ", @@ -1037,7 +1047,7 @@ } }, "key_mapping": { - "enable": true, + "enable": false, "type": "弹幕+回复", "key_trigger_type": "关键词+礼物", "key_single_sentence_trigger_once": true, @@ -1607,7 +1617,8 @@ "gemini": true, "qanything": true, "koboldcpp": true, - "anythingllm": true + "anythingllm": true, + "gpt4free": true }, "tts": { "edge-tts": true, diff --git a/tests/test_gpt4free/api.py b/tests/test_gpt4free/api.py new file mode 100644 index 00000000..23483db4 --- /dev/null +++ b/tests/test_gpt4free/api.py @@ -0,0 +1,107 @@ +import json, logging +# pip install undetected_chromedriver platformdirs curl_cffi aiohttp_socks g4f +import g4f +from g4f.client import Client + +# from utils.common import Common +# from utils.logger import Configure_logger + + +class GPT4Free: + def __init__(self, data): + # self.common = Common() + # 日志文件路径 + # file_path = "./log/log-" + self.common.get_bj_time(1) + ".txt" + # Configure_logger(file_path) + + self.config_data = data + self.api_key = None if self.config_data["api_key"] == "" else self.config_data["api_key"] + + # 创建映射字典 + provider_mapping = { + "none": None, + "g4f.Provider.Bing": g4f.Provider.Bing, + "g4f.Provider.ChatgptAi": g4f.Provider.ChatgptAi, + } + + proxy = None if data["proxy"] == "" else {"all": data["proxy"]} + + self.client = Client(provider=provider_mapping.get(data["provider"], None), proxies=proxy) + + self.history = [] + + + def get_resp(self, data): + """请求对应接口,获取返回值 + + Args: + data (dict): json数据 + + Returns: + str: 返回的文本回答 + """ + try: + messages = [ + {"role": "system", "content": self.config_data["preset"]} + ] + + if self.config_data["history_enable"]: + for message in self.history: + messages.append(message) + + messages.append({"role": "user", "content": data["prompt"]}) + else: + messages.append({"role": "user", "content": data["prompt"]}) + + response = self.client.chat.completions.create( + model="gpt-3.5-turbo", + max_tokens=self.config_data["max_tokens"], + api_key=self.api_key, + messages=messages + ) + resp_content = response.choices[0].message.content + + if self.config_data["history_enable"]: + if len(self.history) > self.config_data["history_max_len"]: + self.history.pop(0) + while True: + # 获取嵌套列表中所有字符串的字符数 + total_chars = sum(len(string) for sublist in self.history for string in sublist) + # 如果大于限定最大历史数,就剔除第一个元素 + if total_chars > self.config_data["history_max_len"]: + self.history.pop(0) + else: + self.history.append({"role": "user", "content": data["prompt"]}) + self.history.append({"role": "assistant", "content": resp_content}) + break + + return resp_content + except Exception as e: + logging.error(e) + return None + + +if __name__ == '__main__': + # 配置日志输出格式 + logging.basicConfig( + level=logging.DEBUG, # 设置日志级别,可以根据需求调整 + format="%(asctime)s [%(levelname)s] %(message)s", + datefmt="%Y-%m-%d %H:%M:%S", + ) + + data = { + "provider": "none", + "api_key": "", + "model": "gpt-3.5-turbo", + "max_tokens": 2048, + "proxy": "http://127.0.0.1:10809", + "preset": "你是一个虚拟主播", + "history_enable": True, + "history_max_len": 300 + } + gpt4free = GPT4Free(data) + + + logging.info(gpt4free.get_resp({"prompt": "你可以扮演猫娘吗,每句话后面加个喵"})) + logging.info(gpt4free.get_resp({"prompt": "早上好"})) + \ No newline at end of file diff --git a/utils/gpt_model/gpt.py b/utils/gpt_model/gpt.py index 62740bc7..b0ec3606 100644 --- a/utils/gpt_model/gpt.py +++ b/utils/gpt_model/gpt.py @@ -29,6 +29,7 @@ from utils.gpt_model.qanything import QAnything from utils.gpt_model.koboldcpp import Koboldcpp from utils.gpt_model.anythingllm import AnythingLLM +from utils.gpt_model.gpt4free import GPT4Free class GPT_Model: openai = None @@ -54,6 +55,7 @@ def set_model_config(self, model_name, config): "qanything": QAnything, "koboldcpp": Koboldcpp, "anythingllm": AnythingLLM, + "gpt4free": GPT4Free, } if model_name == "openai": diff --git a/utils/gpt_model/gpt4free.py b/utils/gpt_model/gpt4free.py new file mode 100644 index 00000000..8141d574 --- /dev/null +++ b/utils/gpt_model/gpt4free.py @@ -0,0 +1,125 @@ +import json, logging, traceback +# pip install undetected_chromedriver platformdirs curl_cffi aiohttp_socks g4f +import g4f +from g4f.client import Client + +from utils.common import Common +from utils.logger import Configure_logger + + +class GPT4Free: + def __init__(self, data): + self.common = Common() + # 日志文件路径 + file_path = "./log/log-" + self.common.get_bj_time(1) + ".txt" + Configure_logger(file_path) + + self.config_data = data + self.api_key = None if self.config_data["api_key"] == "" else self.config_data["api_key"] + + # 创建映射字典 + provider_mapping = { + "none": None, + "g4f.Provider.Bing": g4f.Provider.Bing, + "g4f.Provider.ChatgptAi": g4f.Provider.ChatgptAi, + "g4f.Provider.Liaobots": g4f.Provider.Liaobots, + "g4f.Provider.OpenaiChat": g4f.Provider.OpenaiChat, + "g4f.Provider.Raycast": g4f.Provider.Raycast, + "g4f.Provider.Theb": g4f.Provider.Theb, + "g4f.Provider.You": g4f.Provider.You, + "g4f.Provider.AItianhuSpace": g4f.Provider.AItianhuSpace, + "g4f.Provider.ChatForAi": g4f.Provider.ChatForAi, + "g4f.Provider.Chatgpt4Online": g4f.Provider.Chatgpt4Online, + "g4f.Provider.ChatgptNext": g4f.Provider.ChatgptNext, + "g4f.Provider.ChatgptX": g4f.Provider.ChatgptX, + "g4f.Provider.FlowGpt": g4f.Provider.FlowGpt, + "g4f.Provider.GptTalkRu": g4f.Provider.GptTalkRu, + "g4f.Provider.Koala": g4f.Provider.Koala, + } + + proxy = None if data["proxy"] == "" else {"all": data["proxy"]} + + self.client = Client(provider=provider_mapping.get(data["provider"], None), proxies=proxy) + + self.history = [] + + + def get_resp(self, data): + """请求对应接口,获取返回值 + + Args: + data (dict): json数据 + + Returns: + str: 返回的文本回答 + """ + try: + messages = [ + {"role": "system", "content": self.config_data["preset"]} + ] + + if self.config_data["history_enable"]: + for message in self.history: + messages.append(message) + + messages.append({"role": "user", "content": data["prompt"]}) + else: + messages.append({"role": "user", "content": data["prompt"]}) + + logging.debug(f"messages={messages}") + + response = self.client.chat.completions.create( + model="gpt-3.5-turbo", + max_tokens=self.config_data["max_tokens"], + api_key=self.api_key, + messages=messages + ) + + logging.debug(f"response={response}") + + resp_content = response.choices[0].message.content + + if self.config_data["history_enable"]: + if len(self.history) > self.config_data["history_max_len"]: + self.history.pop(0) + while True: + # 获取嵌套列表中所有字符串的字符数 + total_chars = sum(len(string) for sublist in self.history for string in sublist) + # 如果大于限定最大历史数,就剔除第一个元素 + if total_chars > self.config_data["history_max_len"]: + self.history.pop(0) + else: + self.history.append({"role": "user", "content": data["prompt"]}) + self.history.append({"role": "assistant", "content": resp_content}) + break + + return resp_content + except Exception as e: + logging.error(traceback.format_exc()) + return None + + +if __name__ == '__main__': + # 配置日志输出格式 + logging.basicConfig( + level=logging.DEBUG, # 设置日志级别,可以根据需求调整 + format="%(asctime)s [%(levelname)s] %(message)s", + datefmt="%Y-%m-%d %H:%M:%S", + ) + + data = { + "provider": "none", + "api_key": "", + "model": "gpt-3.5-turbo", + "max_tokens": 2048, + "proxy": "http://127.0.0.1:10809", + "preset": "你是一个虚拟主播", + "history_enable": True, + "history_max_len": 300 + } + gpt4free = GPT4Free(data) + + + logging.info(gpt4free.get_resp({"prompt": "你可以扮演猫娘吗,每句话后面加个喵"})) + logging.info(gpt4free.get_resp({"prompt": "早上好"})) + \ No newline at end of file diff --git a/utils/gpt_model/tongyi.py b/utils/gpt_model/tongyi.py index 1b8d8e45..ce3033e7 100644 --- a/utils/gpt_model/tongyi.py +++ b/utils/gpt_model/tongyi.py @@ -118,7 +118,7 @@ def get_resp(self, prompt): return resp_content else: - logging.error(f'Request id: {response.request_id}, Status code: {response.status_code}, error code: {response.code}, error message: {response.message}') + logging.error(f'出错,请查看message信息排查问题,已知问题有:输入数据可能包含不适当的内容\nRequest id: {response.request_id}, Status code: {response.status_code}, error code: {response.code}, error message: {response.message}') return None except Exception as e: logging.error(traceback.format_exc()) diff --git a/utils/my_handle.py b/utils/my_handle.py index 3c09478a..d7b05217 100644 --- a/utils/my_handle.py +++ b/utils/my_handle.py @@ -133,12 +133,13 @@ def __init__(self, config_path): self.qanything = None self.koboldcpp = None self.anythingllm = None + self.gpt4free = None self.image_recognition_model = None self.chat_type_list = ["chatgpt", "claude", "claude2", "chatglm", "qwen", "chat_with_file", "text_generation_webui", \ "sparkdesk", "langchain_chatglm", "langchain_chatchat", "zhipu", "bard", "yiyan", "tongyi", \ - "tongyixingchen", "my_qianfan", "my_wenxinworkshop", "gemini", "qanything", "koboldcpp", "anythingllm"] + "tongyixingchen", "my_qianfan", "my_wenxinworkshop", "gemini", "qanything", "koboldcpp", "anythingllm", "gpt4free"] # 配置加载 self.config_load() @@ -1196,7 +1197,8 @@ def llm_handle(self, chat_type, data, type="chat", webui_show=True): """ try: resp_content = None - # print(f'''data: {data}''') + + logging.debug(f"chat_type={chat_type}, data={data}") if type == "chat": # 使用 getattr 来动态获取属性 @@ -1228,6 +1230,7 @@ def llm_handle(self, chat_type, data, type="chat", webui_show=True): "qanything": lambda: self.qanything.get_resp({"prompt": data["content"]}), "koboldcpp": lambda: self.koboldcpp.get_resp({"prompt": data["content"]}), "anythingllm": lambda: self.anythingllm.get_resp({"prompt": data["content"]}), + "gpt4free": lambda: self.gpt4free.get_resp({"prompt": data["content"]}), "reread": lambda: data["content"] } elif type == "vision": diff --git a/webui.py b/webui.py index 24909991..cf41425e 100644 --- a/webui.py +++ b/webui.py @@ -1912,6 +1912,17 @@ def common_textarea_handle(content): config_data["anythingllm"]["mode"] = select_anythingllm_mode.value config_data["anythingllm"]["workspace_slug"] = select_anythingllm_workspace_slug.value + if config.get("webui", "show_card", "llm", "gpt4free"): + config_data["gpt4free"]["provider"] = select_gpt4free_provider.value + config_data["gpt4free"]["api_key"] = input_gpt4free_api_key.value + config_data["gpt4free"]["model"] = select_gpt4free_model.value + config_data["gpt4free"]["proxy"] = input_gpt4free_proxy.value + config_data["gpt4free"]["max_tokens"] = int(input_gpt4free_max_tokens.value) + config_data["gpt4free"]["preset"] = input_gpt4free_preset.value + config_data["gpt4free"]["history_enable"] = switch_gpt4free_history_enable.value + config_data["gpt4free"]["history_max_len"] = int(input_gpt4free_history_max_len.value) + + """ TTS """ @@ -2404,6 +2415,7 @@ def common_textarea_handle(content): config_data["webui"]["show_card"]["llm"]["qanything"] = switch_webui_show_card_llm_qanything.value config_data["webui"]["show_card"]["llm"]["koboldcpp"] = switch_webui_show_card_llm_koboldcpp.value config_data["webui"]["show_card"]["llm"]["anythingllm"] = switch_webui_show_card_llm_anythingllm.value + config_data["webui"]["show_card"]["llm"]["gpt4free"] = switch_webui_show_card_llm_gpt4free.value config_data["webui"]["show_card"]["tts"]["edge-tts"] = switch_webui_show_card_tts_edge_tts.value config_data["webui"]["show_card"]["tts"]["vits"] = switch_webui_show_card_tts_vits.value @@ -2561,6 +2573,7 @@ def save_config(): 'koboldcpp': 'koboldcpp', 'anythingllm': 'AnythingLLM', 'tongyi': '通义千问', + 'gpt4free': 'GPT4Free', } with ui.tabs().classes('w-full') as tabs: @@ -3874,7 +3887,68 @@ def anythingllm_get_workspaces_list(): with ui.row(): switch_tongyi_history_enable = ui.switch('上下文记忆', value=config.get("tongyi", "history_enable")).style(switch_internal_css) input_tongyi_history_max_len = ui.input(label='最大记忆长度', value=config.get("tongyi", "history_max_len"), placeholder='最长能记忆的问答字符串长度,超长会丢弃最早记忆的内容,请慎用!配置过大可能会有丢大米') + + if config.get("webui", "show_card", "llm", "gpt4free"): + with ui.card().style(card_css): + ui.label("GPT4Free") + with ui.row(): + providers = [ + "none", + "g4f.Provider.Bing", + "g4f.Provider.ChatgptAi", + "g4f.Provider.Liaobots", + "g4f.Provider.OpenaiChat", + "g4f.Provider.Raycast", + "g4f.Provider.Theb", + "g4f.Provider.You", + "g4f.Provider.AItianhuSpace", + "g4f.Provider.ChatForAi", + "g4f.Provider.Chatgpt4Online", + "g4f.Provider.ChatgptNext", + "g4f.Provider.ChatgptX", + "g4f.Provider.FlowGpt", + "g4f.Provider.GptTalkRu", + "g4f.Provider.Koala", + ] + data_json = {} + for line in providers: + data_json[line] = line + select_gpt4free_provider = ui.select( + label='供应商', + options=data_json, + value=config.get("gpt4free", "provider"), + with_input=True, + new_value_mode='add-unique', + clearable=True + ) + input_gpt4free_api_key = ui.input(label='API密钥', placeholder='API KEY,支持代理', value=config.get("gpt4free", "api_key")).style("width:300px;") + # button_gpt4free_test = ui.button('测试', on_click=lambda: test_openai_key(), color=button_bottom_color).style(button_bottom_css) + + gpt4free_models = [ + "gpt-3.5-turbo", + "gpt-4", + "gpt-4-turbo", + ] + data_json = {} + for line in gpt4free_models: + data_json[line] = line + select_gpt4free_model = ui.select( + label='模型', + options=data_json, + value=config.get("gpt4free", "model"), + with_input=True, + new_value_mode='add-unique', + clearable=True + ) + input_gpt4free_proxy = ui.input(label='HTTP代理地址', placeholder='HTTP代理地址', value=config.get("gpt4free", "proxy")).style("width:300px;") + with ui.row(): + input_gpt4free_max_tokens = ui.input(label='最大token数', value=config.get("gpt4free", "max_tokens"), placeholder='限制生成回答的最大长度。').style("width:200px;") + input_gpt4free_preset = ui.input(label='预设', value=config.get("gpt4free", "preset"), placeholder='用于指定一组预定义的设置,以便模型更好地适应特定的对话场景。').style("width:500px") + switch_gpt4free_history_enable = ui.switch('上下文记忆', value=config.get("gpt4free", "history_enable")).style(switch_internal_css) + input_gpt4free_history_max_len = ui.input(label='最大记忆长度', value=config.get("gpt4free", "history_max_len"), placeholder='最长能记忆的问答字符串长度,超长会丢弃最早记忆的内容,请慎用!配置过大可能会有丢大米') + + with ui.tab_panel(tts_page).style(tab_panel_css): # 通用-合成试听音频 async def tts_common_audio_synthesis(): @@ -5398,7 +5472,8 @@ def update_echart_gift(): switch_webui_show_card_llm_qanything = ui.switch('qanything', value=config.get("webui", "show_card", "llm", "qanything")).style(switch_internal_css) switch_webui_show_card_llm_koboldcpp = ui.switch('koboldcpp', value=config.get("webui", "show_card", "llm", "koboldcpp")).style(switch_internal_css) switch_webui_show_card_llm_anythingllm = ui.switch('AnythingLLM', value=config.get("webui", "show_card", "llm", "anythingllm")).style(switch_internal_css) - + switch_webui_show_card_llm_gpt4free = ui.switch('GPT4Free', value=config.get("webui", "show_card", "llm", "gpt4free")).style(switch_internal_css) + with ui.card().style(card_css): ui.label("文本转语音") with ui.row():