From a7c960dcb07e46735743cb566443d835e44f15f9 Mon Sep 17 00:00:00 2001 From: XIao <46100050+Kilig947@users.noreply.github.com> Date: Sun, 31 Dec 2023 17:13:50 +0800 Subject: [PATCH 1/5] =?UTF-8?q?=E9=80=82=E9=85=8D=20google=20gemini=20?= =?UTF-8?q?=E4=BC=98=E5=8C=96=E4=B8=BA=E4=BB=8E=E7=94=A8=E6=88=B7input?= =?UTF-8?q?=E4=B8=AD=E6=8F=90=E5=8F=96=E6=96=87=E4=BB=B6=20(#1419)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 适配 google gemini 优化为从用户input中提取文件 --- config.py | 17 +- request_llms/bridge_all.py | 19 +++ request_llms/bridge_google_gemini.py | 101 ++++++++++++ request_llms/com_google.py | 198 +++++++++++++++++++++++ toolbox.py | 232 ++++++++++++++++----------- 5 files changed, 472 insertions(+), 95 deletions(-) create mode 100644 request_llms/bridge_google_gemini.py create mode 100644 request_llms/com_google.py diff --git a/config.py b/config.py index 861bbed..c202ca0 100644 --- a/config.py +++ b/config.py @@ -89,12 +89,14 @@ DEFAULT_FN_GROUPS = ['对话', '编程', '学术', '智能体'] LLM_MODEL = "gpt-3.5-turbo" # 可选 ↓↓↓ AVAIL_LLM_MODELS = ["gpt-3.5-turbo-1106","gpt-4-1106-preview","gpt-4-vision-preview", "gpt-3.5-turbo-16k", "gpt-3.5-turbo", "azure-gpt-3.5", - "api2d-gpt-3.5-turbo", 'api2d-gpt-3.5-turbo-16k', "gpt-4", "gpt-4-32k", "azure-gpt-4", "api2d-gpt-4", - "chatglm3", "moss", "claude-2"] -# P.S. 其他可用的模型还包括 ["zhipuai", "qianfan", "deepseekcoder", "llama2", "qwen-local", "gpt-3.5-turbo-0613", "gpt-3.5-turbo-16k-0613", "gpt-3.5-random" + "gemini-pro", "chatglm3", "moss", "claude-2"] +# P.S. 其他可用的模型还包括 [ +# "qwen-turbo", "qwen-plus", "qwen-max" +# "zhipuai", "qianfan", "deepseekcoder", "llama2", "qwen-local", "gpt-3.5-turbo-0613", +# "gpt-3.5-turbo-16k-0613", "gpt-3.5-random", "api2d-gpt-3.5-turbo", 'api2d-gpt-3.5-turbo-16k', # "spark", "sparkv2", "sparkv3", "chatglm_onnx", "claude-1-100k", "claude-2", "internlm", "jittorllms_pangualpha", "jittorllms_llama" -# “qwen-turbo", "qwen-plus", "qwen-max"] +# ] # 定义界面上“询问多个GPT模型”插件应该使用哪些模型,请从AVAIL_LLM_MODELS中选择,并在不同模型之间用`&`间隔,例如"gpt-3.5-turbo&chatglm3&azure-gpt-4" @@ -204,6 +206,10 @@ ANTHROPIC_API_KEY = "" CUSTOM_API_KEY_PATTERN = "" +# Google Gemini API-Key +GEMINI_API_KEY = '' + + # HUGGINGFACE的TOKEN,下载LLAMA时起作用 https://huggingface.co/docs/hub/security-tokens HUGGINGFACE_ACCESS_TOKEN = "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" @@ -292,6 +298,9 @@ NUM_CUSTOM_BASIC_BTN = 4 ├── "qwen-turbo" 等通义千问大模型 │ └── DASHSCOPE_API_KEY │ +├── "Gemini" +│ └── GEMINI_API_KEY +│ └── "newbing" Newbing接口不再稳定,不推荐使用 ├── NEWBING_STYLE └── NEWBING_COOKIES diff --git a/request_llms/bridge_all.py b/request_llms/bridge_all.py index 689b1f9..61e58a0 100644 --- a/request_llms/bridge_all.py +++ b/request_llms/bridge_all.py @@ -28,6 +28,9 @@ from .bridge_chatglm3 import predict as chatglm3_ui from .bridge_qianfan import predict_no_ui_long_connection as qianfan_noui from .bridge_qianfan import predict as qianfan_ui +from .bridge_google_gemini import predict as genai_ui +from .bridge_google_gemini import predict_no_ui_long_connection as genai_noui + colors = ['#FF00FF', '#00FFFF', '#FF0000', '#990099', '#009999', '#990044'] class LazyloadTiktoken(object): @@ -246,6 +249,22 @@ model_info = { "tokenizer": tokenizer_gpt35, "token_cnt": get_token_num_gpt35, }, + "gemini-pro": { + "fn_with_ui": genai_ui, + "fn_without_ui": genai_noui, + "endpoint": None, + "max_token": 1024 * 32, + "tokenizer": tokenizer_gpt35, + "token_cnt": get_token_num_gpt35, + }, + "gemini-pro-vision": { + "fn_with_ui": genai_ui, + "fn_without_ui": genai_noui, + "endpoint": None, + "max_token": 1024 * 32, + "tokenizer": tokenizer_gpt35, + "token_cnt": get_token_num_gpt35, + }, } # -=-=-=-=-=-=- api2d 对齐支持 -=-=-=-=-=-=- diff --git a/request_llms/bridge_google_gemini.py b/request_llms/bridge_google_gemini.py new file mode 100644 index 0000000..2438e09 --- /dev/null +++ b/request_llms/bridge_google_gemini.py @@ -0,0 +1,101 @@ +# encoding: utf-8 +# @Time : 2023/12/21 +# @Author : Spike +# @Descr : +import json +import re +import time +from request_llms.com_google import GoogleChatInit +from toolbox import get_conf, update_ui, update_ui_lastest_msg + +proxies, TIMEOUT_SECONDS, MAX_RETRY = get_conf('proxies', 'TIMEOUT_SECONDS', 'MAX_RETRY') +timeout_bot_msg = '[Local Message] Request timeout. Network error. Please check proxy settings in config.py.' + \ + '网络错误,检查代理服务器是否可用,以及代理设置的格式是否正确,格式须是[协议]://[地址]:[端口],缺一不可。' + + +def predict_no_ui_long_connection(inputs, llm_kwargs, history=[], sys_prompt="", observe_window=None, + console_slience=False): + # 检查API_KEY + if get_conf("GEMINI_API_KEY") == "": + raise ValueError(f"请配置 GEMINI_API_KEY。") + + genai = GoogleChatInit() + watch_dog_patience = 5 # 看门狗的耐心, 设置5秒即可 + gpt_replying_buffer = '' + stream_response = genai.generate_chat(inputs, llm_kwargs, history, sys_prompt) + for response in stream_response: + results = response.decode() + match = re.search(r'"text":\s*"((?:[^"\\]|\\.)*)"', results, flags=re.DOTALL) + error_match = re.search(r'\"message\":\s*\"(.*?)\"', results, flags=re.DOTALL) + if match: + try: + paraphrase = json.loads('{"text": "%s"}' % match.group(1)) + except: + raise ValueError(f"解析GEMINI消息出错。") + buffer = paraphrase['text'] + gpt_replying_buffer += buffer + if len(observe_window) >= 1: + observe_window[0] = gpt_replying_buffer + if len(observe_window) >= 2: + if (time.time() - observe_window[1]) > watch_dog_patience: raise RuntimeError("程序终止。") + if error_match: + raise RuntimeError(f'{gpt_replying_buffer} 对话错误') + return gpt_replying_buffer + + +def predict(inputs, llm_kwargs, plugin_kwargs, chatbot, history=[], system_prompt='', stream=True, additional_fn=None): + # 检查API_KEY + if get_conf("GEMINI_API_KEY") == "": + yield from update_ui_lastest_msg(f"请配置 GEMINI_API_KEY。", chatbot=chatbot, history=history, delay=0) + return + + chatbot.append((inputs, "")) + yield from update_ui(chatbot=chatbot, history=history) + genai = GoogleChatInit() + retry = 0 + while True: + try: + stream_response = genai.generate_chat(inputs, llm_kwargs, history, system_prompt) + break + except Exception as e: + retry += 1 + chatbot[-1] = ((chatbot[-1][0], timeout_bot_msg)) + retry_msg = f",正在重试 ({retry}/{MAX_RETRY}) ……" if MAX_RETRY > 0 else "" + yield from update_ui(chatbot=chatbot, history=history, msg="请求超时" + retry_msg) # 刷新界面 + if retry > MAX_RETRY: raise TimeoutError + gpt_replying_buffer = "" + gpt_security_policy = "" + history.extend([inputs, '']) + for response in stream_response: + results = response.decode("utf-8") # 被这个解码给耍了。。 + gpt_security_policy += results + match = re.search(r'"text":\s*"((?:[^"\\]|\\.)*)"', results, flags=re.DOTALL) + error_match = re.search(r'\"message\":\s*\"(.*)\"', results, flags=re.DOTALL) + if match: + try: + paraphrase = json.loads('{"text": "%s"}' % match.group(1)) + except: + raise ValueError(f"解析GEMINI消息出错。") + gpt_replying_buffer += paraphrase['text'] # 使用 json 解析库进行处理 + chatbot[-1] = (inputs, gpt_replying_buffer) + history[-1] = gpt_replying_buffer + yield from update_ui(chatbot=chatbot, history=history) + if error_match: + history = history[-2] # 错误的不纳入对话 + chatbot[-1] = (inputs, gpt_replying_buffer + f"对话错误,请查看message\n\n```\n{error_match.group(1)}\n```") + yield from update_ui(chatbot=chatbot, history=history) + raise RuntimeError('对话错误') + if not gpt_replying_buffer: + history = history[-2] # 错误的不纳入对话 + chatbot[-1] = (inputs, gpt_replying_buffer + f"触发了Google的安全访问策略,没有回答\n\n```\n{gpt_security_policy}\n```") + yield from update_ui(chatbot=chatbot, history=history) + + + +if __name__ == '__main__': + import sys + + llm_kwargs = {'llm_model': 'gemini-pro'} + result = predict('Write long a story about a magic backpack.', llm_kwargs, llm_kwargs, []) + for i in result: + print(i) diff --git a/request_llms/com_google.py b/request_llms/com_google.py new file mode 100644 index 0000000..7981908 --- /dev/null +++ b/request_llms/com_google.py @@ -0,0 +1,198 @@ +# encoding: utf-8 +# @Time : 2023/12/25 +# @Author : Spike +# @Descr : +import json +import os +import re +import requests +from typing import List, Dict, Tuple +from toolbox import get_conf, encode_image + +proxies, TIMEOUT_SECONDS = get_conf('proxies', 'TIMEOUT_SECONDS') + +""" +======================================================================== +第五部分 一些文件处理方法 +files_filter_handler 根据type过滤文件 +input_encode_handler 提取input中的文件,并解析 +file_manifest_filter_html 根据type过滤文件, 并解析为html or md 文本 +link_mtime_to_md 文件增加本地时间参数,避免下载到缓存文件 +html_view_blank 超链接 +html_local_file 本地文件取相对路径 +to_markdown_tabs 文件list 转换为 md tab +""" + + +def files_filter_handler(file_list): + new_list = [] + filter_ = ['png', 'jpg', 'jpeg', 'bmp', 'svg', 'webp', 'ico', 'tif', 'tiff', 'raw', 'eps'] + for file in file_list: + file = str(file).replace('file=', '') + if os.path.exists(file): + if str(os.path.basename(file)).split('.')[-1] in filter_: + new_list.append(file) + return new_list + + +def input_encode_handler(inputs): + md_encode = [] + pattern_md_file = r"(!?\[[^\]]+\]\([^\)]+\))" + matches_path = re.findall(pattern_md_file, inputs) + for md_path in matches_path: + pattern_file = r"\((file=.*)\)" + matches_path = re.findall(pattern_file, md_path) + encode_file = files_filter_handler(file_list=matches_path) + if encode_file: + md_encode.extend([{ + "data": encode_image(i), + "type": os.path.splitext(i)[1].replace('.', '') + } for i in encode_file]) + inputs = inputs.replace(md_path, '') + return inputs, md_encode + + +def file_manifest_filter_html(file_list, filter_: list = None, md_type=False): + new_list = [] + if not filter_: + filter_ = ['png', 'jpg', 'jpeg', 'bmp', 'svg', 'webp', 'ico', 'tif', 'tiff', 'raw', 'eps'] + for file in file_list: + if str(os.path.basename(file)).split('.')[-1] in filter_: + new_list.append(html_local_img(file, md=md_type)) + elif os.path.exists(file): + new_list.append(link_mtime_to_md(file)) + else: + new_list.append(file) + return new_list + + +def link_mtime_to_md(file): + link_local = html_local_file(file) + link_name = os.path.basename(file) + a = f"[{link_name}]({link_local}?{os.path.getmtime(file)})" + return a + + +def html_local_file(file): + base_path = os.path.dirname(__file__) # 项目目录 + if os.path.exists(str(file)): + file = f'file={file.replace(base_path, ".")}' + return file + + +def html_local_img(__file, layout='left', max_width=None, max_height=None, md=True): + style = '' + if max_width is not None: + style += f"max-width: {max_width};" + if max_height is not None: + style += f"max-height: {max_height};" + __file = html_local_file(__file) + a = f'