{"repo": "cdutcmliuxin/gpt", "files": {"toolbox.py": {"6d7f3feab3faee234abcec4580d32bee6e3cdb8d": {"t": 1785768951.0719407, "n": 35632, "h": "bf8d5f8d6ad91289", "c": "import markdown\nimport importlib\nimport time\nimport inspect\nimport re\nimport os\nimport gradio\nfrom latex2mathml.converter import convert as tex2mathml\nfrom functools import wraps, lru_cache\npj = os.path.join\n\n\"\"\"\n========================================================================\n第一部分\n函数插件输入输出接驳区\n - ChatBotWithCookies: 带Cookies的Chatbot类,为实现更多强大的功能做基础\n - ArgsGeneralWrapper: 装饰器函数,用于重组输入参数,改变输入参数的顺序与结构\n - update_ui: 刷新界面用 yield from update_ui(chatbot, history)\n - CatchException: 将插件中出的所有问题显示在界面上\n - HotReload: 实现插件的热更新\n - trimmed_format_exc: 打印traceback,为了安全而隐藏绝对地址\n========================================================================\n\"\"\"\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\n\ndef ArgsGeneralWrapper(f):\n \"\"\"\n 装饰器函数,用于重组输入参数,改变输入参数的顺序与结构。\n \"\"\"\n def decorated(request: gradio.Request, 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 'client_ip': request.client.host,\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 if cookies.get('lock_plugin', None) is None:\n # 正常状态\n yield from f(txt_passon, llm_kwargs, plugin_kwargs, chatbot_with_cookie, history, system_prompt, *args)\n else:\n # 处理个别特殊插件的锁定状态\n module, fn_name = cookies['lock_plugin'].split('->')\n f_hot_reload = getattr(importlib.import_module(module, fn_name), fn_name)\n yield from f_hot_reload(txt_passon, llm_kwargs, plugin_kwargs, chatbot_with_cookie, history, system_prompt, *args)\n return decorated\n\n\ndef update_ui(chatbot, history, msg='正常', **kwargs): # 刷新界面\n \"\"\"\n 刷新用户界面\n \"\"\"\n assert isinstance(chatbot, ChatBotWithCookies), \"在传递chatbot的过程中不要将其丢弃。必要时, 可用clear将其清空, 然后用for+append循环重新赋值。\"\n cookies = chatbot.get_cookies()\n\n # 解决插件锁定时的界面显示问题\n if cookies.get('lock_plugin', None):\n label = cookies.get('llm_model', \"\") + \" | \" + \"正在锁定插件\" + cookies.get('lock_plugin', None)\n chatbot_gr = gradio.update(value=chatbot, label=label)\n if cookies.get('label', \"\") != label: cookies['label'] = label # 记住当前的label\n elif cookies.get('label', None):\n chatbot_gr = gradio.update(value=chatbot, label=cookies.get('llm_model', \"\"))\n cookies['label'] = None # 清空label\n else:\n chatbot_gr = chatbot\n\n yield cookies, chatbot_gr, history, msg\n\ndef update_ui_lastest_msg(lastmsg, chatbot, history, delay=1): # 刷新界面\n \"\"\"\n 刷新用户界面\n \"\"\"\n if len(chatbot) == 0: chatbot.append([\"update_ui_last_msg\", lastmsg])\n chatbot[-1] = list(chatbot[-1])\n chatbot[-1][-1] = lastmsg\n yield from update_ui(chatbot=chatbot, history=history)\n time.sleep(delay)\n\n\ndef trimmed_format_exc():\n import os, traceback\n str = traceback.format_exc()\n current_path = os.getcwd()\n replace_path = \".\"\n return str.replace(current_path, replace_path)\n\ndef CatchException(f):\n \"\"\"\n 装饰器函数,捕捉函数f中的异常并封装到一个生成器中返回,并显示到聊天当中。\n \"\"\"\n\n @wraps(f)\n def decorated(main_input, llm_kwargs, plugin_kwargs, chatbot_with_cookie, history, *args, **kwargs):\n try:\n yield from f(main_input, llm_kwargs, plugin_kwargs, chatbot_with_cookie, history, *args, **kwargs)\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' + trimmed_format_exc() + '```'\n if len(chatbot_with_cookie) == 0:\n chatbot_with_cookie.clear()\n chatbot_with_cookie.append([\"插件调度异常\", \"异常原因\"])\n chatbot_with_cookie[-1] = (chatbot_with_cookie[-1][0],\n f\"[Local Message] 实验性函数调用出错: \\n\\n{tb_str} \\n\\n当前代理可用性: \\n\\n{check_proxy(proxies)}\")\n yield from update_ui(chatbot=chatbot_with_cookie, 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========================================================================\n第二部分\n其他小工具:\n - write_results_to_file: 将结果写入markdown文件中\n - regular_txt_to_markdown: 将普通文本转换为Markdown格式的文本。\n - report_execption: 向chatbot中添加简单的意外错误信息\n - text_divide_paragraph: 将文本按照段落分隔符分割开,生成带有段落标签的HTML代码。\n - markdown_convertion: 用多种方式组合,将markdown转化为好看的html\n - format_io: 接管gradio默认的markdown处理方式\n - on_file_uploaded: 处理文件的上传(自动解压)\n - on_report_generated: 将生成的报告自动投射到文件上传区\n - clip_history: 当历史上下文过长时,自动截断\n - get_conf: 获取设置\n - select_api_key: 根据当前的模型类别,抽取可用的api-key\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\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 = 'GPT-Report-' + gen_time_str() + '.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('# GPT-Academic Report\\n')\n for i, content in enumerate(history):\n try: \n if type(content) != str: content = str(content)\n except:\n continue\n if i % 2 == 0:\n f.write('## ')\n try:\n f.write(content)\n except:\n # remove everything that cannot be handled by utf8\n f.write(content.encode('utf-8', 'ignore').decode())\n f.write('\\n\\n')\n res = '以上材料已经被写入:\\t' + os.path.abspath(f'./gpt_log/{file_name}')\n print(res)\n return res\n\n\ndef write_history_to_file(history, file_basename=None, file_fullname=None):\n \"\"\"\n 将对话记录history以Markdown格式写入文件中。如果没有指定文件名,则使用当前时间生成文件名。\n \"\"\"\n import os\n import time\n if file_fullname is None:\n if file_basename is not None:\n file_fullname = os.path.join(get_log_folder(), file_basename)\n else:\n file_fullname = os.path.join(get_log_folder(), f'GPT-Academic-{gen_time_str()}.md')\n os.makedirs(os.path.dirname(file_fullname), exist_ok=True)\n with open(file_fullname, 'w', encoding='utf8') as f:\n f.write('# GPT-Academic Report\\n')\n for i, content in enumerate(history):\n try: \n if type(content) != str: content = str(content)\n except:\n continue\n if i % 2 == 0:\n f.write('## ')\n try:\n f.write(content)\n except:\n # remove everything that cannot be handled by utf8\n f.write(content.encode('utf-8', 'ignore').decode())\n f.write('\\n\\n')\n res = os.path.abspath(file_fullname)\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 pre = '