1 line
25 KiB
JSON
1 line
25 KiB
JSON
{"repo": "2926811287/2926811287.github.io", "files": {"toolbox.py": {"0b89673ee94b907583470165c9cc7681b54e9c43": {"t": 1785768951.874432, "n": 18622, "h": "d6e672148444e1f7", "c": "import markdown\nimport importlib\nimport traceback\nimport inspect\nimport re\nfrom latex2mathml.converter import convert as tex2mathml\nfrom functools import wraps, lru_cache\n############################### 插件输入输出接驳区 #######################################\nclass ChatBotWithCookies(list):\n def __init__(self, cookie):\n self._cookies = cookie\n\n def write_list(self, list):\n for t in list:\n self.append(t)\n\n def get_list(self):\n return [t for t in self]\n\n def get_cookies(self):\n return self._cookies\n\ndef ArgsGeneralWrapper(f):\n \"\"\"\n 装饰器函数,用于重组输入参数,改变输入参数的顺序与结构。\n \"\"\"\n def decorated(cookies, max_length, llm_model, txt, txt2, top_p, temperature, chatbot, history, system_prompt, plugin_advanced_arg, *args):\n txt_passon = txt\n if txt == \"\" and txt2 != \"\": txt_passon = txt2\n # 引入一个有cookie的chatbot\n cookies.update({\n 'top_p':top_p,\n 'temperature':temperature,\n })\n llm_kwargs = {\n 'api_key': cookies['api_key'],\n 'llm_model': llm_model,\n 'top_p':top_p,\n 'max_length': max_length,\n 'temperature':temperature,\n }\n plugin_kwargs = {\n \"advanced_arg\": plugin_advanced_arg,\n }\n chatbot_with_cookie = ChatBotWithCookies(cookies)\n chatbot_with_cookie.write_list(chatbot)\n yield from f(txt_passon, llm_kwargs, plugin_kwargs, chatbot_with_cookie, history, system_prompt, *args)\n return decorated\n\ndef update_ui(chatbot, history, msg='正常', **kwargs): # 刷新界面\n \"\"\"\n 刷新用户界面\n \"\"\"\n assert isinstance(chatbot, ChatBotWithCookies), \"在传递chatbot的过程中不要将其丢弃。必要时,可用clear将其清空,然后用for+append循环重新赋值。\"\n yield chatbot.get_cookies(), chatbot, history, msg\n\ndef CatchException(f):\n \"\"\"\n 装饰器函数,捕捉函数f中的异常并封装到一个生成器中返回,并显示到聊天当中。\n \"\"\"\n @wraps(f)\n def decorated(txt, top_p, temperature, chatbot, history, systemPromptTxt, WEB_PORT):\n try:\n yield from f(txt, top_p, temperature, chatbot, history, systemPromptTxt, WEB_PORT)\n except Exception as e:\n from check_proxy import check_proxy\n from toolbox import get_conf\n proxies, = get_conf('proxies')\n tb_str = '```\\n' + traceback.format_exc() + '```'\n if chatbot is None or len(chatbot) == 0:\n chatbot = [[\"插件调度异常\", \"异常原因\"]]\n chatbot[-1] = (chatbot[-1][0],\n f\"[Local Message] 实验性函数调用出错: \\n\\n{tb_str} \\n\\n当前代理可用性: \\n\\n{check_proxy(proxies)}\")\n yield from update_ui(chatbot=chatbot, history=history, msg=f'异常 {e}') # 刷新界面\n return decorated\n\n\ndef HotReload(f):\n \"\"\"\n HotReload的装饰器函数,用于实现Python函数插件的热更新。\n 函数热更新是指在不停止程序运行的情况下,更新函数代码,从而达到实时更新功能。\n 在装饰器内部,使用wraps(f)来保留函数的元信息,并定义了一个名为decorated的内部函数。\n 内部函数通过使用importlib模块的reload函数和inspect模块的getmodule函数来重新加载并获取函数模块,\n 然后通过getattr函数获取函数名,并在新模块中重新加载函数。\n 最后,使用yield from语句返回重新加载过的函数,并在被装饰的函数上执行。\n 最终,装饰器函数返回内部函数。这个内部函数可以将函数的原始定义更新为最新版本,并执行函数的新版本。\n \"\"\"\n @wraps(f)\n def decorated(*args, **kwargs):\n fn_name = f.__name__\n f_hot_reload = getattr(importlib.reload(inspect.getmodule(f)), fn_name)\n yield from f_hot_reload(*args, **kwargs)\n return decorated\n\n\n####################################### 其他小工具 #####################################\n\ndef get_reduce_token_percent(text):\n \"\"\"\n * 此函数未来将被弃用\n \"\"\"\n try:\n # text = \"maximum context length is 4097 tokens. However, your messages resulted in 4870 tokens\"\n pattern = r\"(\\d+)\\s+tokens\\b\"\n match = re.findall(pattern, text)\n EXCEED_ALLO = 500 # 稍微留一点余地,否则在回复时会因余量太少出问题\n max_limit = float(match[0]) - EXCEED_ALLO\n current_tokens = float(match[1])\n ratio = max_limit/current_tokens\n assert ratio > 0 and ratio < 1\n return ratio, str(int(current_tokens-max_limit))\n except:\n return 0.5, '不详'\n\n\n\ndef write_results_to_file(history, file_name=None):\n \"\"\"\n 将对话记录history以Markdown格式写入文件中。如果没有指定文件名,则使用当前时间生成文件名。\n \"\"\"\n import os\n import time\n if file_name is None:\n # file_name = time.strftime(\"chatGPT分析报告%Y-%m-%d-%H-%M-%S\", time.localtime()) + '.md'\n file_name = 'chatGPT分析报告' + \\\n time.strftime(\"%Y-%m-%d-%H-%M-%S\", time.localtime()) + '.md'\n os.makedirs('./gpt_log/', exist_ok=True)\n with open(f'./gpt_log/{file_name}', 'w', encoding='utf8') as f:\n f.write('# chatGPT 分析报告\\n')\n for i, content in enumerate(history):\n try: # 这个bug没找到触发条件,暂时先这样顶一下\n if type(content) != str:\n content = str(content)\n except:\n continue\n if i % 2 == 0:\n f.write('## ')\n f.write(content)\n f.write('\\n\\n')\n res = '以上材料已经被写入' + os.path.abspath(f'./gpt_log/{file_name}')\n print(res)\n return res\n\n\ndef regular_txt_to_markdown(text):\n \"\"\"\n 将普通文本转换为Markdown格式的文本。\n \"\"\"\n text = text.replace('\\n', '\\n\\n')\n text = text.replace('\\n\\n\\n', '\\n\\n')\n text = text.replace('\\n\\n\\n', '\\n\\n')\n return text\n\n\n\n\ndef report_execption(chatbot, history, a, b):\n \"\"\"\n 向chatbot中添加错误信息\n \"\"\"\n chatbot.append((a, b))\n history.append(a)\n history.append(b)\n\n\ndef text_divide_paragraph(text):\n \"\"\"\n 将文本按照段落分隔符分割开,生成带有段落标签的HTML代码。\n \"\"\"\n if '```' in text:\n # careful input\n return text\n else:\n # wtf input\n lines = text.split(\"\\n\")\n for i, line in enumerate(lines):\n lines[i] = lines[i].replace(\" \", \" \")\n text = \"</br>\".join(lines)\n return text\n\n\ndef markdown_convertion(txt):\n \"\"\"\n 将Markdown格式的文本转换为HTML格式。如果包含数学公式,则先将公式转换为HTML格式。\n \"\"\"\n pre = '<div class=\"markdown-body\">'\n suf = '</div>'\n markdown_extension_configs = {\n 'mdx_math': {\n 'enable_dollar_delimiter': True,\n 'use_gitlab_delimiters': False,\n },\n }\n find_equation_pattern = r'<script type=\"math/tex(?:.*?)>(.*?)</script>'\n\n def tex2mathml_catch_exception(content, *args, **kwargs):\n try:\n content = tex2mathml(content, *args, **kwargs)\n except:\n content = content\n return content\n\n def replace_math_no_render(match):\n content = match.group(1)\n if 'mode=display' in match.group(0):\n content = content.replace('\\n', '</br>')\n return f\"<font color=\\\"#00FF00\\\">$$</font><font color=\\\"#FF00FF\\\">{content}</font><font color=\\\"#00FF00\\\">$$</font>\"\n else:\n return f\"<font color=\\\"#00FF00\\\">$</font><font color=\\\"#FF00FF\\\">{content}</font><font color=\\\"#00FF00\\\">$</font>\"\n\n def replace_math_render(match):\n content = match.group(1)\n if 'mode=display' in match.group(0):\n if '\\\\begin{aligned}' in content:\n content = content.replace('\\\\begin{aligned}', '\\\\begin{array}')\n content = content.replace('\\\\end{aligned}', '\\\\end{array}')\n content = content.replace('&', ' ')\n content = tex2mathml_catch_exception(content, display=\"block\")\n return content\n else:\n return tex2mathml_catch_exception(content)\n\n def markdown_bug_hunt(content):\n \"\"\"\n 解决一个mdx_math的bug(单$包裹begin命令时多余<script>)\n \"\"\"\n content = content.replace('<script type=\"math/tex\">\\n<script type=\"math/tex; mode=display\">', '<script type=\"math/tex; mode=display\">')\n content = content.replace('</script>\\n</script>', '</script>')\n return content\n\n\n if ('$' in txt) and ('```' not in txt): # 有$标识的公式符号,且没有代码段```的标识\n # convert everything to html format\n split = markdown.markdown(text='---')\n convert_stage_1 = markdown.markdown(text=txt, extensions=['mdx_math', 'fenced_code', 'tables', 'sane_lists'], extension_configs=markdown_extension_configs)\n convert_stage_1 = markdown_bug_hunt(convert_stage_1)\n # re.DOTALL: Make the '.' special character match any character at all, including a newline; without this flag, '.' will match anything except a newline. Corresponds to the inline flag (?s).\n # 1. convert to easy-to-copy tex (do not render math)\n convert_stage_2_1, n = re.subn(find_equation_pattern, replace_math_no_render, convert_stage_1, flags=re.DOTALL)\n # 2. convert to rendered equation\n convert_stage_2_2, n = re.subn(find_equation_pattern, replace_math_render, convert_stage_1, flags=re.DOTALL)\n # cat them together\n return pre + convert_stage_2_1 + f'{split}' + convert_stage_2_2 + suf\n else:\n return pre + markdown.markdown(txt, extensions=['fenced_code', 'codehilite', 'tables', 'sane_lists']) + suf\n\n\ndef close_up_code_segment_during_stream(gpt_reply):\n \"\"\"\n 在gpt输出代码的中途(输出了前面的```,但还没输出完后面的```),补上后面的```\n\n Args:\n gpt_reply (str): GPT模型返回的回复字符串。\n\n Returns:\n str: 返回一个新的字符串,将输出代码片段的“后面的```”补上。\n\n \"\"\"\n if '```' not in gpt_reply:\n return gpt_reply\n if gpt_reply.endswith('```'):\n return gpt_reply\n\n # 排除了以上两个情况,我们\n segments = gpt_reply.split('```')\n n_mark = len(segments) - 1\n if n_mark % 2 == 1:\n # print('输出代码片段中!')\n return gpt_reply+'\\n```'\n else:\n return gpt_reply\n\n\ndef format_io(self, y):\n \"\"\"\n 将输入和输出解析为HTML格式。将y中最后一项的输入部分段落化,并将输出部分的Markdown和数学公式转换为HTML格式。\n \"\"\"\n if y is None or y == []:\n return []\n i_ask, gpt_reply = y[-1]\n i_ask = text_divide_paragraph(i_ask) # 输入部分太自由,预处理一波\n gpt_reply = close_up_code_segment_during_stream(gpt_reply) # 当代码输出半截的时候,试着补上后个```\n y[-1] = (\n None if i_ask is None else markdown.markdown(i_ask, extensions=['fenced_code', 'tables']),\n None if gpt_reply is None else markdown_convertion(gpt_reply)\n )\n return y\n\n\ndef find_free_port():\n \"\"\"\n 返回当前系统中可用的未使用端口。\n \"\"\"\n import socket\n from contextlib import closing\n with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as s:\n s.bind(('', 0))\n s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)\n return s.getsockname()[1]\n\n\ndef extract_archive(file_path, dest_dir):\n import zipfile\n import tarfile\n import os\n # Get the file extension of the input file\n file_extension = os.path.splitext(file_path)[1]\n\n # Extract the archive based on its extension\n if file_extension == '.zip':\n with zipfile.ZipFile(file_path, 'r') as zipobj:\n zipobj.extractall(path=dest_dir)\n print(\"Successfully extracted zip archive to {}\".format(dest_dir))\n\n elif file_extension in ['.tar', '.gz', '.bz2']:\n with tarfile.open(file_path, 'r:*') as tarobj:\n tarobj.extractall(path=dest_dir)\n print(\"Successfully extracted tar archive to {}\".format(dest_dir))\n\n # 第三方库,需要预先pip install rarfile\n # 此外,Windows上还需要安装winrar软件,配置其Path环境变量,如\"C:\\Program Files\\WinRAR\"才可以\n elif file_extension == '.rar':\n try:\n import rarfile\n with rarfile.RarFile(file_path) as rf:\n rf.extractall(path=dest_dir)\n print(\"Successfully extracted rar archive to {}\".format(dest_dir))\n except:\n print(\"Rar format requires additional dependencies to install\")\n return '\\n\\n需要安装pip install rarfile来解压rar文件'\n\n # 第三方库,需要预先pip install py7zr\n elif file_extension == '.7z':\n try:\n import py7zr\n with py7zr.SevenZipFile(file_path, mode='r') as f:\n f.extractall(path=dest_dir)\n print(\"Successfully extracted 7z archive to {}\".format(dest_dir))\n except:\n print(\"7z format requires additional dependencies to install\")\n return '\\n\\n需要安装pip install py7zr来解压7z文件'\n else:\n return ''\n return ''\n\n\ndef find_recent_files(directory):\n \"\"\"\n me: find files that is created with in one minutes under a directory with python, write a function\n gpt: here it is!\n \"\"\"\n import os\n import time\n current_time = time.time()\n one_minute_ago = current_time - 60\n recent_files = []\n\n for filename in os.listdir(directory):\n file_path = os.path.join(directory, filename)\n if file_path.endswith('.log'):\n continue\n created_time = os.path.getmtime(file_path)\n if created_time >= one_minute_ago:\n if os.path.isdir(file_path):\n continue\n recent_files.append(file_path)\n\n return recent_files\n\n\ndef on_file_uploaded(files, chatbot, txt, txt2, checkboxes):\n if len(files) == 0:\n return chatbot, txt\n import shutil\n import os\n import time\n import glob\n from toolbox import extract_archive\n try:\n shutil.rmtree('./private_upload/')\n except:\n pass\n time_tag = time.strftime(\"%Y-%m-%d-%H-%M-%S\", time.localtime())\n os.makedirs(f'private_upload/{time_tag}', exist_ok=True)\n err_msg = ''\n for file in files:\n file_origin_name = os.path.basename(file.orig_name)\n shutil.copy(file.name, f'private_upload/{time_tag}/{file_origin_name}')\n err_msg += extract_archive(f'private_upload/{time_tag}/{file_origin_name}',\n dest_dir=f'private_upload/{time_tag}/{file_origin_name}.extract')\n moved_files = [fp for fp in glob.glob(\n 'private_upload/**/*', recursive=True)]\n if \"底部输入区\" in checkboxes:\n txt = \"\"\n txt2 = f'private_upload/{time_tag}'\n else:\n txt = f'private_upload/{time_tag}'\n txt2 = \"\"\n moved_files_str = '\\t\\n\\n'.join(moved_files)\n chatbot.append(['我上传了文件,请查收',\n f'[Local Message] 收到以下文件: \\n\\n{moved_files_str}' +\n f'\\n\\n调用路径参数已自动修正到: \\n\\n{txt}' +\n f'\\n\\n现在您点击任意“红颜色”标识的函数插件时,以上文件将被作为输入参数'+err_msg])\n return chatbot, txt, txt2\n\n\ndef on_report_generated(files, chatbot):\n from toolbox import find_recent_files\n report_files = find_recent_files('gpt_log')\n if len(report_files) == 0:\n return None, chatbot\n # files.extend(report_files)\n chatbot.append(['汇总报告如何远程获取?', '汇总报告已经添加到右侧“文件上传区”(可能处于折叠状态),请查收。'])\n return report_files, chatbot\n\ndef is_openai_api_key(key):\n API_MATCH = re.match(r\"sk-[a-zA-Z0-9]{48}$\", key)\n return bool(API_MATCH)\n\ndef is_api2d_key(key):\n if key.startswith('fk') and len(key) == 41:\n return True\n else:\n return False\n\ndef is_any_api_key(key):\n if ',' in key:\n keys = key.split(',')\n for k in keys:\n if is_any_api_key(k): return True\n return False\n else:\n return is_openai_api_key(key) or is_api2d_key(key)\n\ndef what_keys(keys):\n avail_key_list = {'OpenAI Key':0, \"API2D Key\":0}\n key_list = keys.split(',')\n\n for k in key_list:\n if is_openai_api_key(k): \n avail_key_list['OpenAI Key'] += 1\n\n for k in key_list:\n if is_api2d_key(k): \n avail_key_list['API2D Key'] += 1\n\n return f\"检测到: OpenAI Key {avail_key_list['OpenAI Key']} 个,API2D Key {avail_key_list['API2D Key']} 个\"\n\ndef select_api_key(keys, llm_model):\n import random\n avail_key_list = []\n key_list = keys.split(',')\n\n if llm_model.startswith('gpt-'):\n for k in key_list:\n if is_openai_api_key(k): avail_key_list.append(k)\n\n if llm_model.startswith('api2d-'):\n for k in key_list:\n if is_api2d_key(k): avail_key_list.append(k)\n\n if len(avail_key_list) == 0:\n raise RuntimeError(f\"您提供的api-key不满足要求,不包含任何可用于{llm_model}的api-key。您可能选择了错误的模型或请求源。\")\n\n api_key = random.choice(avail_key_list) # 随机负载均衡\n return api_key\n\n@lru_cache(maxsize=128)\ndef read_single_conf_with_lru_cache(arg):\n from colorful import print亮红, print亮绿, print亮蓝\n try:\n r = getattr(importlib.import_module('config_private'), arg)\n except:\n r = getattr(importlib.import_module('config'), arg)\n # 在读取API_KEY时,检查一下是不是忘了改config\n if arg == 'API_KEY':\n print亮蓝(f\"[API_KEY] 本项目现已支持OpenAI和API2D的api-key。也支持同时填写多个api-key,如API_KEY=\\\"openai-key1,openai-key2,api2d-key3\\\"\")\n print亮蓝(f\"[API_KEY] 您既可以在config.py中修改api-key(s),也可以在问题输入区输入临时的api-key(s),然后回车键提交后即可生效。\")\n if is_any_api_key(r):\n print亮绿(f\"[API_KEY] 您的 API_KEY 是: {r[:15]}*** API_KEY 导入成功\")\n else:\n print亮红( \"[API_KEY] 正确的 API_KEY 是'sk'开头的51位密钥(OpenAI),或者 'fk'开头的41位密钥,请在config文件中修改API密钥之后再运行。\")\n if arg == 'proxies':\n if r is None:\n print亮红('[PROXY] 网络代理状态:未配置。无代理状态下很可能无法访问OpenAI家族的模型。建议:检查USE_PROXY选项是否修改。')\n else:\n print亮绿('[PROXY] 网络代理状态:已配置。配置信息如下:', r)\n assert isinstance(r, dict), 'proxies格式错误,请注意proxies选项的格式,不要遗漏括号。'\n return r\n\n\ndef get_conf(*args):\n # 建议您复制一个config_private.py放自己的秘密, 如API和代理网址, 避免不小心传github被别人看到\n res = []\n for arg in args:\n r = read_single_conf_with_lru_cache(arg)\n res.append(r)\n return res\n\n\ndef clear_line_break(txt):\n txt = txt.replace('\\n', ' ')\n txt = txt.replace(' ', ' ')\n txt = txt.replace(' ', ' ')\n return txt\n\n\nclass DummyWith():\n \"\"\"\n 这段代码定义了一个名为DummyWith的空上下文管理器,\n 它的作用是……额……没用,即在代码结构不变得情况下取代其他的上下文管理器。\n 上下文管理器是一种Python对象,用于与with语句一起使用,\n 以确保一些资源在代码块执行期间得到正确的初始化和清理。\n 上下文管理器必须实现两个方法,分别为 __enter__()和 __exit__()。\n 在上下文执行开始的情况下,__enter__()方法会在代码块被执行前被调用,\n 而在上下文执行结束时,__exit__()方法则会被调用。\n \"\"\"\n def __enter__(self):\n return self\n\n def __exit__(self, exc_type, exc_value, traceback):\n return\n\ndef run_gradio_in_subpath(demo, auth, port, custom_path):\n def is_path_legal(path: str)->bool:\n '''\n check path for sub url\n path: path to check\n return value: do sub url wrap\n '''\n if path == \"/\": return True\n if len(path) == 0:\n print(\"ilegal custom path: {}\\npath must not be empty\\ndeploy on root url\".format(path))\n return False\n if path[0] == '/':\n if path[1] != '/':\n print(\"deploy on sub-path {}\".format(path))\n return True\n return False\n print(\"ilegal custom path: {}\\npath should begin with \\'/\\'\\ndeploy on root url\".format(path))\n return False\n\n if not is_path_legal(custom_path): raise RuntimeError('Ilegal custom path')\n import uvicorn\n import gradio as gr\n from fastapi import FastAPI\n app = FastAPI()\n if custom_path != \"/\":\n @app.get(\"/\")\n def read_main(): \n return {\"message\": f\"Gradio is running at: {custom_path}\"}\n app = gr.mount_gradio_app(app, demo, path=custom_path)\n uvicorn.run(app, host=\"0.0.0.0\", port=port) # , auth=auth\n"}}, "config.py": {"0b89673ee94b907583470165c9cc7681b54e9c43": {"t": 1785768953.5008025, "n": 2040, "h": "55bae1ce5894311a", "c": "# [step 1]>> 例如: API_KEY = \"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\" (此key无效)\nAPI_KEY = \"sk-此处填API密钥\" # 可同时填写多个API-KEY,用英文逗号分割,例如API_KEY = \"sk-openaikey1,sk-openaikey2,fkxxxx-api2dkey1,fkxxxx-api2dkey2\"\n\n# [step 2]>> 改为True应用代理,如果直接在海外服务器部署,此处不修改\nUSE_PROXY = False\nif USE_PROXY:\n # 填写格式是 [协议]:// [地址] :[端口],填写之前不要忘记把USE_PROXY改成True,如果直接在海外服务器部署,此处不修改\n # 例如 \"socks5h://localhost:11284\"\n # [协议] 常见协议无非socks5h/http; 例如 v2**y 和 ss* 的默认本地协议是socks5h; 而cl**h 的默认本地协议是http\n # [地址] 懂的都懂,不懂就填localhost或者127.0.0.1肯定错不了(localhost意思是代理软件安装在本机上)\n # [端口] 在代理软件的设置里找。虽然不同的代理软件界面不一样,但端口号都应该在最显眼的位置上\n\n # 代理网络的地址,打开你的科学上网软件查看代理的协议(socks5/http)、地址(localhost)和端口(11284)\n proxies = {\n # [协议]:// [地址] :[端口]\n \"http\": \"socks5h://localhost:11284\",\n \"https\": \"socks5h://localhost:11284\",\n }\nelse:\n proxies = None\n\n# [step 3]>> 多线程函数插件中,默认允许多少路线程同时访问OpenAI。Free trial users的限制是每分钟3次,Pay-as-you-go users的限制是每分钟3500次\n# 一言以蔽之:免费用户填3,OpenAI绑了信用卡的用户可以填 16 或者更高。提高限制请查询:https://platform.openai.com/docs/guides/rate-limits/overview\nDEFAULT_WORKER_NUM = 3\n\n\n# [step 4]>> 以下配置可以优化体验,但大部分场合下并不需要修改\n# 对话窗的高度\nCHATBOT_HEIGHT = 1115\n\n# 代码高亮\nCODE_HIGHLIGHT = True\n\n# 窗口布局\nLAYOUT = \"LEFT-RIGHT\" # \"LEFT-RIGHT\"(左右布局) # \"TOP-DOWN\"(上下布局)\n\n# 发送请求到OpenAI后,等待多久判定为超时\nTIMEOUT_SECONDS = 30\n\n# 网页的端口, -1代表随机端口\nWEB_PORT = -1\n\n# 如果OpenAI不响应(网络卡顿、代理失败、KEY失效),重试的次数限制\nMAX_RETRY = 2\n\n# OpenAI模型选择是(gpt4现在只对申请成功的人开放,体验gpt-4可以试试api2d)\nLLM_MODEL = \"gpt-3.5-turbo\" # 可选 ↓↓↓\nAVAIL_LLM_MODELS = [\"gpt-3.5-turbo\", \"api2d-gpt-3.5-turbo\", \"gpt-4\", \"api2d-gpt-4\", \"chatglm\"]\n\n# 本地LLM模型如ChatGLM的执行方式 CPU/GPU\nLOCAL_MODEL_DEVICE = \"cpu\" # 可选 \"cuda\"\n\n# 设置gradio的并行线程数(不需要修改)\nCONCURRENT_COUNT = 100\n\n# 设置用户名和密码(不需要修改)(相关功能不稳定,与gradio版本和网络都相关,如果本地使用不建议加这个)\n# [(\"username\", \"password\"), (\"username2\", \"password2\"), ...]\nAUTHENTICATION = []\n\n# 重新URL重新定向,实现更换API_URL的作用(常规情况下,不要修改!!)\n# 格式 {\"https://api.openai.com/v1/chat/completions\": \"重定向的URL\"}\nAPI_URL_REDIRECT = {}\n\n# 如果需要在二级路径下运行(常规情况下,不要修改!!)(需要配合修改main.py才能生效!)\nCUSTOM_PATH = \"/\"\n"}}}} |