diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml deleted file mode 100644 index 545fb400e12008a93b854ea0264c253578a9ba86..0000000000000000000000000000000000000000 --- a/.pre-commit-config.yaml +++ /dev/null @@ -1,32 +0,0 @@ -default_language_version: - python: python3 -exclude: 'dotnet' -ci: - autofix_prs: true - autoupdate_commit_msg: '[pre-commit.ci] pre-commit suggestions' - autoupdate_schedule: 'quarterly' - -repos: - - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.4.0 - hooks: - - id: check-ast - # - id: check-yaml - - id: check-toml - - id: check-json - - id: check-byte-order-marker - exclude: .gitignore - - id: check-merge-conflict - - id: detect-private-key - - id: trailing-whitespace - - id: end-of-file-fixer - - id: no-commit-to-branch - - repo: https://github.com/psf/black - rev: 23.3.0 - hooks: - - id: black - # - repo: https://github.com/charliermarsh/ruff-pre-commit - # rev: v0.0.261 - # hooks: - # - id: ruff - # args: ["--fix"] diff --git a/Dockerfile b/Dockerfile index 97dba6f114fd0db32bc14d123e699e341ca9c02c..ac47b8e36ea1577c16e2940aaa133dc1774d9348 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,34 +1,34 @@ -# 此Dockerfile适用于“无本地模型”的迷你运行环境构建 -# 如果需要使用chatglm等本地模型或者latex运行依赖,请参考 docker-compose.yml -# - 如何构建: 先修改 `config.py`, 然后 `docker build -t gpt-academic . ` -# - 如何运行(Linux下): `docker run --rm -it --net=host gpt-academic ` -# - 如何运行(其他操作系统,选择任意一个固定端口50923): `docker run --rm -it -e WEB_PORT=50923 -p 50923:50923 gpt-academic ` +# 此Dockerfile适用于“无本地模型”的环境构建,如果需要使用chatglm等本地模型或者latex运行依赖,请参考 docker-compose.yml +# 如何构建: 先修改 `config.py`, 然后 `docker build -t gpt-academic . ` +# 如何运行(Linux下): `docker run --rm -it --net=host gpt-academic ` +# 如何运行(其他操作系统,选择任意一个固定端口50923): `docker run --rm -it -e WEB_PORT=50923 -p 50923:50923 gpt-academic ` FROM python:3.11 -# 非必要步骤,更换pip源 (以下三行,可以删除) +# 非必要步骤,更换pip源 RUN echo '[global]' > /etc/pip.conf && \ echo 'index-url = https://mirrors.aliyun.com/pypi/simple/' >> /etc/pip.conf && \ echo 'trusted-host = mirrors.aliyun.com' >> /etc/pip.conf -# 进入工作路径(必要) +# 进入工作路径 WORKDIR /gpt -# 安装大部分依赖,利用Docker缓存加速以后的构建 (以下三行,可以删除) +# 安装大部分依赖,利用Docker缓存加速以后的构建 COPY requirements.txt ./ +COPY ./docs/gradio-3.32.2-py3-none-any.whl ./docs/gradio-3.32.2-py3-none-any.whl RUN pip3 install -r requirements.txt -# 装载项目文件,安装剩余依赖(必要) +# 装载项目文件,安装剩余依赖 COPY . . RUN pip3 install -r requirements.txt -# 非必要步骤,用于预热模块(可以删除) +# 非必要步骤,用于预热模块 RUN python3 -c 'from check_proxy import warm_up_modules; warm_up_modules()' -# 启动(必要) +# 启动 CMD ["python3", "-u", "main.py"] diff --git a/README.md b/README.md index 49fa0683dd3d1ac2826be4c2d43a879a5aa705f1..873629134d1b83d0d8d6c13652f14c47306b5ff2 100644 --- a/README.md +++ b/README.md @@ -11,96 +11,73 @@ pinned: false # ChatGPT 学术优化 > **Note** -> -> 2023.11.12: 某些依赖包尚不兼容python 3.12,推荐python 3.11。 -> -> 2023.12.26: 安装依赖时,请选择`requirements.txt`中**指定的版本**。 安装命令:`pip install -r requirements.txt`。本项目完全开源免费,您可通过订阅[在线服务](https://github.com/binary-husky/gpt_academic/wiki/online)的方式鼓励本项目的发展。 - -
- -
-

- GPT 学术优化 (GPT Academic) -

- -[![Github][Github-image]][Github-url] -[![License][License-image]][License-url] -[![Releases][Releases-image]][Releases-url] -[![Installation][Installation-image]][Installation-url] -[![Wiki][Wiki-image]][Wiki-url] -[![PR][PRs-image]][PRs-url] - -[Github-image]: https://img.shields.io/badge/github-12100E.svg?style=flat-square -[License-image]: https://img.shields.io/github/license/binary-husky/gpt_academic?label=License&style=flat-square&color=orange -[Releases-image]: https://img.shields.io/github/release/binary-husky/gpt_academic?label=Release&style=flat-square&color=blue -[Installation-image]: https://img.shields.io/badge/dynamic/json?color=blue&url=https://raw.githubusercontent.com/binary-husky/gpt_academic/master/version&query=$.version&label=Installation&style=flat-square -[Wiki-image]: https://img.shields.io/badge/wiki-项目文档-black?style=flat-square -[PRs-image]: https://img.shields.io/badge/PRs-welcome-pink?style=flat-square - -[Github-url]: https://github.com/binary-husky/gpt_academic -[License-url]: https://github.com/binary-husky/gpt_academic/blob/master/LICENSE -[Releases-url]: https://github.com/binary-husky/gpt_academic/releases -[Installation-url]: https://github.com/binary-husky/gpt_academic#installation -[Wiki-url]: https://github.com/binary-husky/gpt_academic/wiki -[PRs-url]: https://github.com/binary-husky/gpt_academic/pulls +> +> 2023.7.8: Gradio, Pydantic依赖调整,已修改 `requirements.txt`。请及时**更新代码**,安装依赖时,请严格选择`requirements.txt`中**指定的版本** +> +> `pip install -r requirements.txt` -
-
+#
GPT 学术优化 (GPT Academic)
-**如果喜欢这个项目,请给它一个Star;如果您发明了好用的快捷键或插件,欢迎发pull requests!** +**如果喜欢这个项目,请给它一个Star;如果您发明了好用的快捷键或函数插件,欢迎发pull requests!** -If you like this project, please give it a Star. -Read this in [English](docs/README.English.md) | [日本語](docs/README.Japanese.md) | [한국어](docs/README.Korean.md) | [Русский](docs/README.Russian.md) | [Français](docs/README.French.md). All translations have been provided by the project itself. To translate this project to arbitrary language with GPT, read and run [`multi_language.py`](multi_language.py) (experimental). -
+If you like this project, please give it a Star. If you've come up with more useful academic shortcuts or functional plugins, feel free to open an issue or pull request. We also have a README in [English|](docs/README_EN.md)[日本語|](docs/README_JP.md)[한국어|](https://github.com/mldljyh/ko_gpt_academic)[Русский|](docs/README_RS.md)[Français](docs/README_FR.md) translated by this project itself. +To translate this project to arbitrary language with GPT, read and run [`multi_language.py`](multi_language.py) (experimental). -> [!NOTE] -> 1.本项目中每个文件的功能都在[自译解报告](https://github.com/binary-husky/gpt_academic/wiki/GPT‐Academic项目自译解报告)`self_analysis.md`详细说明。随着版本的迭代,您也可以随时自行点击相关函数插件,调用GPT重新生成项目的自我解析报告。常见问题请查阅wiki。 -> [![常规安装方法](https://img.shields.io/static/v1?label=&message=常规安装方法&color=gray)](#installation) [![一键安装脚本](https://img.shields.io/static/v1?label=&message=一键安装脚本&color=gray)](https://github.com/binary-husky/gpt_academic/releases) [![配置说明](https://img.shields.io/static/v1?label=&message=配置说明&color=gray)](https://github.com/binary-husky/gpt_academic/wiki/项目配置说明) [![wiki](https://img.shields.io/static/v1?label=&message=wiki&color=gray)]([https://github.com/binary-husky/gpt_academic/wiki/项目配置说明](https://github.com/binary-husky/gpt_academic/wiki)) +> **Note** > -> 2.本项目兼容并鼓励尝试国内中文大语言基座模型如通义千问,智谱GLM等。支持多个api-key共存,可在配置文件中填写如`API_KEY="openai-key1,openai-key2,azure-key3,api2d-key4"`。需要临时更换`API_KEY`时,在输入区输入临时的`API_KEY`然后回车键提交即可生效。 +> 1.请注意只有 **高亮** 标识的函数插件(按钮)才支持读取文件,部分插件位于插件区的**下拉菜单**中。另外我们以**最高优先级**欢迎和处理任何新插件的PR。 +> +> 2.本项目中每个文件的功能都在[自译解报告`self_analysis.md`](https://github.com/binary-husky/gpt_academic/wiki/GPT‐Academic项目自译解报告)详细说明。随着版本的迭代,您也可以随时自行点击相关函数插件,调用GPT重新生成项目的自我解析报告。常见问题[`wiki`](https://github.com/binary-husky/gpt_academic/wiki)。[安装方法](#installation) | [配置说明](https://github.com/binary-husky/gpt_academic/wiki/%E9%A1%B9%E7%9B%AE%E9%85%8D%E7%BD%AE%E8%AF%B4%E6%98%8E)。 +> +> 3.本项目兼容并鼓励尝试国产大语言模型ChatGLM和Moss等等。支持多个api-key共存,可在配置文件中填写如`API_KEY="openai-key1,openai-key2,azure-key3,api2d-key4"`。需要临时更换`API_KEY`时,在输入区输入临时的`API_KEY`然后回车键提交后即可生效。 + -

+
功能(⭐= 近期新增功能) | 描述 --- | --- -⭐[接入新模型](https://github.com/binary-husky/gpt_academic/wiki/%E5%A6%82%E4%BD%95%E5%88%87%E6%8D%A2%E6%A8%A1%E5%9E%8B) | 百度[千帆](https://cloud.baidu.com/doc/WENXINWORKSHOP/s/Nlks5zkzu)与文心一言, 通义千问[Qwen](https://modelscope.cn/models/qwen/Qwen-7B-Chat/summary),上海AI-Lab[书生](https://github.com/InternLM/InternLM),讯飞[星火](https://xinghuo.xfyun.cn/),[LLaMa2](https://huggingface.co/meta-llama/Llama-2-7b-chat-hf),[智谱GLM4](https://open.bigmodel.cn/),DALLE3, [DeepseekCoder](https://coder.deepseek.com/) -⭐支持mermaid图像渲染 | 支持让GPT生成[流程图](https://www.bilibili.com/video/BV18c41147H9/)、状态转移图、甘特图、饼状图、GitGraph等等(3.7版本) -⭐Arxiv论文精细翻译 ([Docker](https://github.com/binary-husky/gpt_academic/pkgs/container/gpt_academic_with_latex)) | [插件] 一键[以超高质量翻译arxiv论文](https://www.bilibili.com/video/BV1dz4y1v77A/),目前最好的论文翻译工具 -⭐[实时语音对话输入](https://github.com/binary-husky/gpt_academic/blob/master/docs/use_audio.md) | [插件] 异步[监听音频](https://www.bilibili.com/video/BV1AV4y187Uy/),自动断句,自动寻找回答时机 -⭐AutoGen多智能体插件 | [插件] 借助微软AutoGen,探索多Agent的智能涌现可能! -⭐虚空终端插件 | [插件] 能够使用自然语言直接调度本项目其他插件 -润色、翻译、代码解释 | 一键润色、翻译、查找论文语法错误、解释代码 +⭐[接入新模型](https://github.com/binary-husky/gpt_academic/wiki/%E5%A6%82%E4%BD%95%E5%88%87%E6%8D%A2%E6%A8%A1%E5%9E%8B)! | 百度[千帆](https://cloud.baidu.com/doc/WENXINWORKSHOP/s/Nlks5zkzu)与文心一言, [通义千问](https://modelscope.cn/models/qwen/Qwen-7B-Chat/summary),上海AI-Lab[书生](https://github.com/InternLM/InternLM),讯飞[星火](https://xinghuo.xfyun.cn/),[LLaMa2](https://huggingface.co/meta-llama/Llama-2-7b-chat-hf) +一键润色 | 支持一键润色、一键查找论文语法错误 +一键中英互译 | 一键中英互译 +一键代码解释 | 显示代码、解释代码、生成代码、给代码加注释 [自定义快捷键](https://www.bilibili.com/video/BV14s4y1E7jN) | 支持自定义快捷键 -模块化设计 | 支持自定义强大的[插件](https://github.com/binary-husky/gpt_academic/tree/master/crazy_functions),插件支持[热更新](https://github.com/binary-husky/gpt_academic/wiki/%E5%87%BD%E6%95%B0%E6%8F%92%E4%BB%B6%E6%8C%87%E5%8D%97) -[程序剖析](https://www.bilibili.com/video/BV1cj411A7VW) | [插件] 一键剖析Python/C/C++/Java/Lua/...项目树 或 [自我剖析](https://www.bilibili.com/video/BV1cj411A7VW) -读论文、[翻译](https://www.bilibili.com/video/BV1KT411x7Wn)论文 | [插件] 一键解读latex/pdf论文全文并生成摘要 -Latex全文[翻译](https://www.bilibili.com/video/BV1nk4y1Y7Js/)、[润色](https://www.bilibili.com/video/BV1FT411H7c5/) | [插件] 一键翻译或润色latex论文 -批量注释生成 | [插件] 一键批量生成函数注释 -Markdown[中英互译](https://www.bilibili.com/video/BV1yo4y157jV/) | [插件] 看到上面5种语言的[README](https://github.com/binary-husky/gpt_academic/blob/master/docs/README_EN.md)了吗?就是出自他的手笔 -[PDF论文全文翻译功能](https://www.bilibili.com/video/BV1KT411x7Wn) | [插件] PDF论文提取题目&摘要+翻译全文(多线程) -[Arxiv小助手](https://www.bilibili.com/video/BV1LM4y1279X) | [插件] 输入arxiv文章url即可一键翻译摘要+下载PDF -Latex论文一键校对 | [插件] 仿Grammarly对Latex文章进行语法、拼写纠错+输出对照PDF -[谷歌学术统合小助手](https://www.bilibili.com/video/BV19L411U7ia) | [插件] 给定任意谷歌学术搜索页面URL,让gpt帮你[写relatedworks](https://www.bilibili.com/video/BV1GP411U7Az/) -互联网信息聚合+GPT | [插件] 一键[让GPT从互联网获取信息](https://www.bilibili.com/video/BV1om4y127ck)回答问题,让信息永不过时 +模块化设计 | 支持自定义强大的[函数插件](https://github.com/binary-husky/gpt_academic/tree/master/crazy_functions),插件支持[热更新](https://github.com/binary-husky/gpt_academic/wiki/%E5%87%BD%E6%95%B0%E6%8F%92%E4%BB%B6%E6%8C%87%E5%8D%97) +[自我程序剖析](https://www.bilibili.com/video/BV1cj411A7VW) | [函数插件] [一键读懂](https://github.com/binary-husky/gpt_academic/wiki/chatgpt-academic%E9%A1%B9%E7%9B%AE%E8%87%AA%E8%AF%91%E8%A7%A3%E6%8A%A5%E5%91%8A)本项目的源代码 +[程序剖析](https://www.bilibili.com/video/BV1cj411A7VW) | [函数插件] 一键可以剖析其他Python/C/C++/Java/Lua/...项目树 +读论文、[翻译](https://www.bilibili.com/video/BV1KT411x7Wn)论文 | [函数插件] 一键解读latex/pdf论文全文并生成摘要 +Latex全文[翻译](https://www.bilibili.com/video/BV1nk4y1Y7Js/)、[润色](https://www.bilibili.com/video/BV1FT411H7c5/) | [函数插件] 一键翻译或润色latex论文 +批量注释生成 | [函数插件] 一键批量生成函数注释 +Markdown[中英互译](https://www.bilibili.com/video/BV1yo4y157jV/) | [函数插件] 看到上面5种语言的[README](https://github.com/binary-husky/gpt_academic/blob/master/docs/README_EN.md)了吗? +chat分析报告生成 | [函数插件] 运行后自动生成总结汇报 +[PDF论文全文翻译功能](https://www.bilibili.com/video/BV1KT411x7Wn) | [函数插件] PDF论文提取题目&摘要+翻译全文(多线程) +[Arxiv小助手](https://www.bilibili.com/video/BV1LM4y1279X) | [函数插件] 输入arxiv文章url即可一键翻译摘要+下载PDF +Latex论文一键校对 | [函数插件] 仿Grammarly对Latex文章进行语法、拼写纠错+输出对照PDF +[谷歌学术统合小助手](https://www.bilibili.com/video/BV19L411U7ia) | [函数插件] 给定任意谷歌学术搜索页面URL,让gpt帮你[写relatedworks](https://www.bilibili.com/video/BV1GP411U7Az/) +互联网信息聚合+GPT | [函数插件] 一键[让GPT从互联网获取信息](https://www.bilibili.com/video/BV1om4y127ck)回答问题,让信息永不过时 +⭐Arxiv论文精细翻译 ([Docker](https://github.com/binary-husky/gpt_academic/pkgs/container/gpt_academic_with_latex)) | [函数插件] 一键[以超高质量翻译arxiv论文](https://www.bilibili.com/video/BV1dz4y1v77A/),目前最好的论文翻译工具 +⭐[实时语音对话输入](https://github.com/binary-husky/gpt_academic/blob/master/docs/use_audio.md) | [函数插件] 异步[监听音频](https://www.bilibili.com/video/BV1AV4y187Uy/),自动断句,自动寻找回答时机 公式/图片/表格显示 | 可以同时显示公式的[tex形式和渲染形式](https://user-images.githubusercontent.com/96192199/230598842-1d7fcddd-815d-40ee-af60-baf488a199df.png),支持公式、代码高亮 +多线程函数插件支持 | 支持多线调用chatgpt,一键处理[海量文本](https://www.bilibili.com/video/BV1FT411H7c5/)或程序 启动暗色[主题](https://github.com/binary-husky/gpt_academic/issues/173) | 在浏览器url后面添加```/?__theme=dark```可以切换dark主题 -[多LLM模型](https://www.bilibili.com/video/BV1wT411p7yf)支持 | 同时被GPT3.5、GPT4、[清华ChatGLM2](https://github.com/THUDM/ChatGLM2-6B)、[复旦MOSS](https://github.com/OpenLMLab/MOSS)伺候的感觉一定会很不错吧? +[多LLM模型](https://www.bilibili.com/video/BV1wT411p7yf)支持 | 同时被GPT3.5、GPT4、[清华ChatGLM2](https://github.com/THUDM/ChatGLM2-6B)、[复旦MOSS](https://github.com/OpenLMLab/MOSS)同时伺候的感觉一定会很不错吧? +⭐ChatGLM2微调模型 | 支持加载ChatGLM2微调模型,提供ChatGLM2微调辅助插件 更多LLM模型接入,支持[huggingface部署](https://huggingface.co/spaces/qingxu98/gpt-academic) | 加入Newbing接口(新必应),引入清华[Jittorllms](https://github.com/Jittor/JittorLLMs)支持[LLaMA](https://github.com/facebookresearch/llama)和[盘古α](https://openi.org.cn/pangu/) ⭐[void-terminal](https://github.com/binary-husky/void-terminal) pip包 | 脱离GUI,在Python中直接调用本项目的所有函数插件(开发中) +⭐虚空终端插件 | [函数插件] 用自然语言,直接调度本项目其他插件 更多新功能展示 (图像生成等) …… | 见本文档结尾处 ……
- 新界面(修改`config.py`中的LAYOUT选项即可实现“左右布局”和“上下布局”的切换)
- +
-- 所有按钮都通过读取functional.py动态生成,可随意加自定义功能,解放剪贴板 +- 所有按钮都通过读取functional.py动态生成,可随意加自定义功能,解放粘贴板
@@ -110,99 +87,66 @@ Latex论文一键校对 | [插件] 仿Grammarly对Latex文章进行语法、拼 -- 如果输出包含公式,会以tex形式和渲染形式同时显示,方便复制和阅读 +- 如果输出包含公式,会同时以tex形式和渲染形式显示,方便复制和阅读
-- 懒得看项目代码?直接把整个工程炫ChatGPT嘴里 +- 懒得看项目代码?整个工程直接给chatgpt炫嘴里
-- 多种大语言模型混合调用(ChatGLM + OpenAI-GPT3.5 + GPT4) +- 多种大语言模型混合调用(ChatGLM + OpenAI-GPT3.5 + [API2D](https://api2d.com/)-GPT4)
-

- # Installation - -```mermaid -flowchart TD - A{"安装方法"} --> W1("I. 🔑直接运行 (Windows, Linux or MacOS)") - W1 --> W11["1. Python pip包管理依赖"] - W1 --> W12["2. Anaconda包管理依赖(推荐⭐)"] - - A --> W2["II. 🐳使用Docker (Windows, Linux or MacOS)"] - - W2 --> k1["1. 部署项目全部能力的大镜像(推荐⭐)"] - W2 --> k2["2. 仅在线模型(GPT, GLM4等)镜像"] - W2 --> k3["3. 在线模型 + Latex的大镜像"] - - A --> W4["IV. 🚀其他部署方法"] - W4 --> C1["1. Windows/MacOS 一键安装运行脚本(推荐⭐)"] - W4 --> C2["2. Huggingface, Sealos远程部署"] - W4 --> C4["3. ... 其他 ..."] -``` - -### 安装方法I:直接运行 (Windows, Linux or MacOS) +### 安装方法I:直接运行 (Windows, Linux or MacOS) 1. 下载项目 +```sh +git clone --depth=1 https://github.com/binary-husky/gpt_academic.git +cd gpt_academic +``` - ```sh - git clone --depth=1 https://github.com/binary-husky/gpt_academic.git - cd gpt_academic - ``` - -2. 配置API_KEY等变量 - - 在`config.py`中,配置API KEY等变量。[特殊网络环境设置方法](https://github.com/binary-husky/gpt_academic/issues/1)、[Wiki-项目配置说明](https://github.com/binary-husky/gpt_academic/wiki/项目配置说明)。 +2. 配置API_KEY - 「 程序会优先检查是否存在名为`config_private.py`的私密配置文件,并用其中的配置覆盖`config.py`的同名配置。如您能理解以上读取逻辑,我们强烈建议您在`config.py`同路径下创建一个名为`config_private.py`的新配置文件,并使用`config_private.py`配置项目,从而确保自动更新时不会丢失配置 」。 +在`config.py`中,配置API KEY等设置,[点击查看特殊网络环境设置方法](https://github.com/binary-husky/gpt_academic/issues/1) 。 - 「 支持通过`环境变量`配置项目,环境变量的书写格式参考`docker-compose.yml`文件或者我们的[Wiki页面](https://github.com/binary-husky/gpt_academic/wiki/项目配置说明)。配置读取优先级: `环境变量` > `config_private.py` > `config.py` 」。 +(P.S. 程序运行时会优先检查是否存在名为`config_private.py`的私密配置文件,并用其中的配置覆盖`config.py`的同名配置。因此,如果您能理解我们的配置读取逻辑,我们强烈建议您在`config.py`旁边创建一个名为`config_private.py`的新配置文件,并把`config.py`中的配置转移(复制)到`config_private.py`中(仅复制您修改过的配置条目即可)。`config_private.py`不受git管控,可以让您的隐私信息更加安全。P.S.项目同样支持通过`环境变量`配置大多数选项,环境变量的书写格式参考`docker-compose`文件。读取优先级: `环境变量` > `config_private.py` > `config.py`) 3. 安装依赖 - ```sh - # (选择I: 如熟悉python, python推荐版本 3.9 ~ 3.11)备注:使用官方pip源或者阿里pip源, 临时换源方法:python -m pip install -r requirements.txt -i https://mirrors.aliyun.com/pypi/simple/ - python -m pip install -r requirements.txt +```sh +# (选择I: 如熟悉python)(python版本3.9以上,越新越好),备注:使用官方pip源或者阿里pip源,临时换源方法:python -m pip install -r requirements.txt -i https://mirrors.aliyun.com/pypi/simple/ +python -m pip install -r requirements.txt - # (选择II: 使用Anaconda)步骤也是类似的 (https://www.bilibili.com/video/BV1rc411W7Dr): - conda create -n gptac_venv python=3.11 # 创建anaconda环境 - conda activate gptac_venv # 激活anaconda环境 - python -m pip install -r requirements.txt # 这个步骤和pip安装一样的步骤 - ``` +# (选择II: 如不熟悉python)使用anaconda,步骤也是类似的 (https://www.bilibili.com/video/BV1rc411W7Dr): +conda create -n gptac_venv python=3.11 # 创建anaconda环境 +conda activate gptac_venv # 激活anaconda环境 +python -m pip install -r requirements.txt # 这个步骤和pip安装一样的步骤 +```
如果需要支持清华ChatGLM2/复旦MOSS/RWKV作为后端,请点击展开此处

-【可选步骤】如果需要支持清华ChatGLM3/复旦MOSS作为后端,需要额外安装更多依赖(前提条件:熟悉Python + 用过Pytorch + 电脑配置够强): - +【可选步骤】如果需要支持清华ChatGLM2/复旦MOSS作为后端,需要额外安装更多依赖(前提条件:熟悉Python + 用过Pytorch + 电脑配置够强): ```sh -# 【可选步骤I】支持清华ChatGLM3。清华ChatGLM备注:如果遇到"Call ChatGLM fail 不能正常加载ChatGLM的参数" 错误,参考如下: 1:以上默认安装的为torch+cpu版,使用cuda需要卸载torch重新安装torch+cuda; 2:如因本机配置不够无法加载模型,可以修改request_llm/bridge_chatglm.py中的模型精度, 将 AutoTokenizer.from_pretrained("THUDM/chatglm-6b", trust_remote_code=True) 都修改为 AutoTokenizer.from_pretrained("THUDM/chatglm-6b-int4", trust_remote_code=True) -python -m pip install -r request_llms/requirements_chatglm.txt +# 【可选步骤I】支持清华ChatGLM2。清华ChatGLM备注:如果遇到"Call ChatGLM fail 不能正常加载ChatGLM的参数" 错误,参考如下: 1:以上默认安装的为torch+cpu版,使用cuda需要卸载torch重新安装torch+cuda; 2:如因本机配置不够无法加载模型,可以修改request_llm/bridge_chatglm.py中的模型精度, 将 AutoTokenizer.from_pretrained("THUDM/chatglm-6b", trust_remote_code=True) 都修改为 AutoTokenizer.from_pretrained("THUDM/chatglm-6b-int4", trust_remote_code=True) +python -m pip install -r request_llm/requirements_chatglm.txt # 【可选步骤II】支持复旦MOSS -python -m pip install -r request_llms/requirements_moss.txt -git clone --depth=1 https://github.com/OpenLMLab/MOSS.git request_llms/moss # 注意执行此行代码时,必须处于项目根路径 +python -m pip install -r request_llm/requirements_moss.txt +git clone --depth=1 https://github.com/OpenLMLab/MOSS.git request_llm/moss # 注意执行此行代码时,必须处于项目根路径 # 【可选步骤III】支持RWKV Runner 参考wiki:https://github.com/binary-husky/gpt_academic/wiki/%E9%80%82%E9%85%8DRWKV-Runner # 【可选步骤IV】确保config.py配置文件的AVAIL_LLM_MODELS包含了期望的模型,目前支持的全部模型如下(jittorllms系列目前仅支持docker方案): -AVAIL_LLM_MODELS = ["gpt-3.5-turbo", "api2d-gpt-3.5-turbo", "gpt-4", "api2d-gpt-4", "chatglm", "moss"] # + ["jittorllms_rwkv", "jittorllms_pangualpha", "jittorllms_llama"] - -# 【可选步骤V】支持本地模型INT8,INT4量化(这里所指的模型本身不是量化版本,目前deepseek-coder支持,后面测试后会加入更多模型量化选择) -pip install bitsandbyte -# windows用户安装bitsandbytes需要使用下面bitsandbytes-windows-webui -python -m pip install bitsandbytes --prefer-binary --extra-index-url=https://jllllll.github.io/bitsandbytes-windows-webui -pip install -U git+https://github.com/huggingface/transformers.git -pip install -U git+https://github.com/huggingface/accelerate.git -pip install peft +AVAIL_LLM_MODELS = ["gpt-3.5-turbo", "api2d-gpt-3.5-turbo", "gpt-4", "api2d-gpt-4", "chatglm", "newbing", "moss"] # + ["jittorllms_rwkv", "jittorllms_pangualpha", "jittorllms_llama"] ```

@@ -211,86 +155,102 @@ pip install peft 4. 运行 - ```sh - python main.py - ``` +```sh +python main.py +``` ### 安装方法II:使用Docker -0. 部署项目的全部能力(这个是包含cuda和latex的大型镜像。但如果您网速慢、硬盘小,则不推荐该方法部署完整项目) -[![fullcapacity](https://github.com/binary-husky/gpt_academic/actions/workflows/build-with-all-capacity.yml/badge.svg?branch=master)](https://github.com/binary-husky/gpt_academic/actions/workflows/build-with-all-capacity.yml) +[![fullcapacity](https://github.com/binary-husky/gpt_academic/actions/workflows/build-with-all-capacity.yml/badge.svg?branch=master)](https://github.com/binary-husky/gpt_academic/actions/workflows/build-with-audio-assistant.yml) - ``` sh - # 修改docker-compose.yml,保留方案0并删除其他方案。然后运行: - docker-compose up - ``` - -1. 仅ChatGPT + GLM4 + 文心一言+spark等在线模型(推荐大多数人选择) +1. 仅ChatGPT(推荐大多数人选择,等价于docker-compose方案1) [![basic](https://github.com/binary-husky/gpt_academic/actions/workflows/build-without-local-llms.yml/badge.svg?branch=master)](https://github.com/binary-husky/gpt_academic/actions/workflows/build-without-local-llms.yml) [![basiclatex](https://github.com/binary-husky/gpt_academic/actions/workflows/build-with-latex.yml/badge.svg?branch=master)](https://github.com/binary-husky/gpt_academic/actions/workflows/build-with-latex.yml) [![basicaudio](https://github.com/binary-husky/gpt_academic/actions/workflows/build-with-audio-assistant.yml/badge.svg?branch=master)](https://github.com/binary-husky/gpt_academic/actions/workflows/build-with-audio-assistant.yml) - ``` sh - # 修改docker-compose.yml,保留方案1并删除其他方案。然后运行: - docker-compose up - ``` -P.S. 如果需要依赖Latex的插件功能,请见Wiki。另外,您也可以直接使用方案4或者方案0获取Latex功能。 +``` sh +git clone --depth=1 https://github.com/binary-husky/gpt_academic.git # 下载项目 +cd gpt_academic # 进入路径 +nano config.py # 用任意文本编辑器编辑config.py, 配置 “Proxy”, “API_KEY” 以及 “WEB_PORT” (例如50923) 等 +docker build -t gpt-academic . # 安装 -2. ChatGPT + GLM3 + MOSS + LLAMA2 + 通义千问(需要熟悉[Nvidia Docker](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/install-guide.html#installing-on-ubuntu-and-debian)运行时) +#(最后一步-Linux操作系统)用`--net=host`更方便快捷 +docker run --rm -it --net=host gpt-academic +#(最后一步-MacOS/Windows操作系统)只能用-p选项将容器上的端口(例如50923)暴露给主机上的端口 +docker run --rm -it -e WEB_PORT=50923 -p 50923:50923 gpt-academic +``` +P.S. 如果需要依赖Latex的插件功能,请见Wiki。另外,您也可以直接使用docker-compose获取Latex功能(修改docker-compose.yml,保留方案4并删除其他方案)。 + +2. ChatGPT + ChatGLM2 + MOSS + LLAMA2 + 通义千问(需要熟悉[Nvidia Docker](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/install-guide.html#installing-on-ubuntu-and-debian)运行时) [![chatglm](https://github.com/binary-husky/gpt_academic/actions/workflows/build-with-chatglm.yml/badge.svg?branch=master)](https://github.com/binary-husky/gpt_academic/actions/workflows/build-with-chatglm.yml) - ``` sh - # 修改docker-compose.yml,保留方案2并删除其他方案。然后运行: - docker-compose up - ``` +``` sh +# 修改docker-compose.yml,保留方案2并删除其他方案。修改docker-compose.yml中方案2的配置,参考其中注释即可 +docker-compose up +``` + +3. ChatGPT + LLAMA + 盘古 + RWKV(需要熟悉[Nvidia Docker](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/install-guide.html#installing-on-ubuntu-and-debian)运行时) +[![jittorllms](https://github.com/binary-husky/gpt_academic/actions/workflows/build-with-jittorllms.yml/badge.svg?branch=master)](https://github.com/binary-husky/gpt_academic/actions/workflows/build-with-jittorllms.yml) +``` sh +# 修改docker-compose.yml,保留方案3并删除其他方案。修改docker-compose.yml中方案3的配置,参考其中注释即可 +docker-compose up +``` + + +### 安装方法III:其他部署姿势 +1. 一键运行脚本。 +完全不熟悉python环境的Windows用户可以下载[Release](https://github.com/binary-husky/gpt_academic/releases)中发布的一键运行脚本安装无本地模型的版本。 +脚本的贡献来源是[oobabooga](https://github.com/oobabooga/one-click-installers)。 + +2. 使用docker-compose运行。 +请阅读docker-compose.yml后,按照其中的提示操作即可 -### 安装方法III:其他部署方法 -1. **Windows一键运行脚本**。 -完全不熟悉python环境的Windows用户可以下载[Release](https://github.com/binary-husky/gpt_academic/releases)中发布的一键运行脚本安装无本地模型的版本。脚本贡献来源:[oobabooga](https://github.com/oobabooga/one-click-installers)。 +3. 如何使用反代URL +按照`config.py`中的说明配置API_URL_REDIRECT即可。 -2. 使用第三方API、Azure等、文心一言、星火等,见[Wiki页面](https://github.com/binary-husky/gpt_academic/wiki/项目配置说明) +4. 微软云AzureAPI +按照`config.py`中的说明配置即可(AZURE_ENDPOINT等四个配置) -3. 云服务器远程部署避坑指南。 -请访问[云服务器远程部署wiki](https://github.com/binary-husky/gpt_academic/wiki/%E4%BA%91%E6%9C%8D%E5%8A%A1%E5%99%A8%E8%BF%9C%E7%A8%8B%E9%83%A8%E7%BD%B2%E6%8C%87%E5%8D%97) +5. 远程云服务器部署(需要云服务器知识与经验)。 +请访问[部署wiki-1](https://github.com/binary-husky/gpt_academic/wiki/%E4%BA%91%E6%9C%8D%E5%8A%A1%E5%99%A8%E8%BF%9C%E7%A8%8B%E9%83%A8%E7%BD%B2%E6%8C%87%E5%8D%97) -4. 在其他平台部署&二级网址部署 - - 使用Sealos[一键部署](https://github.com/binary-husky/gpt_academic/issues/993)。 - - 使用WSL2(Windows Subsystem for Linux 子系统)。请访问[部署wiki-2](https://github.com/binary-husky/gpt_academic/wiki/%E4%BD%BF%E7%94%A8WSL2%EF%BC%88Windows-Subsystem-for-Linux-%E5%AD%90%E7%B3%BB%E7%BB%9F%EF%BC%89%E9%83%A8%E7%BD%B2) - - 如何在二级网址(如`http://localhost/subpath`)下运行。请访问[FastAPI运行说明](docs/WithFastapi.md) +6. 使用Sealos[一键部署](https://github.com/binary-husky/gpt_academic/issues/993)。 + +7. 使用WSL2(Windows Subsystem for Linux 子系统)。 +请访问[部署wiki-2](https://github.com/binary-husky/gpt_academic/wiki/%E4%BD%BF%E7%94%A8WSL2%EF%BC%88Windows-Subsystem-for-Linux-%E5%AD%90%E7%B3%BB%E7%BB%9F%EF%BC%89%E9%83%A8%E7%BD%B2) + +8. 如何在二级网址(如`http://localhost/subpath`)下运行。 +请访问[FastAPI运行说明](docs/WithFastapi.md) -

# Advanced Usage ### I:自定义新的便捷按钮(学术快捷键) - -任意文本编辑器打开`core_functional.py`,添加如下条目,然后重启程序。(如果按钮已存在,那么可以直接修改(前缀、后缀都已支持热修改),无需重启程序即可生效。) +任意文本编辑器打开`core_functional.py`,添加条目如下,然后重启程序即可。(如果按钮已经添加成功并可见,那么前缀、后缀都支持热修改,无需重启程序即可生效。) 例如 - -```python +``` "超级英译中": { # 前缀,会被加在你的输入之前。例如,用来描述你的要求,例如翻译、解释代码、润色等等 - "Prefix": "请翻译把下面一段内容成中文,然后用一个markdown表格逐一解释文中出现的专有名词:\n\n", - + "Prefix": "请翻译把下面一段内容成中文,然后用一个markdown表格逐一解释文中出现的专有名词:\n\n", + # 后缀,会被加在你的输入之后。例如,配合前缀可以把你的输入内容用引号圈起来。 "Suffix": "", }, ``` -
### II:自定义函数插件 + 编写强大的函数插件来执行任何你想得到的和想不到的任务。 本项目的插件编写、调试难度很低,只要您具备一定的python基础知识,就可以仿照我们提供的模板实现自己的插件功能。 详情请参考[函数插件指南](https://github.com/binary-husky/gpt_academic/wiki/%E5%87%BD%E6%95%B0%E6%8F%92%E4%BB%B6%E6%8C%87%E5%8D%97)。 -

-# Updates -### I:动态 +# Latest Update +### I:新功能动态 1. 对话保存功能。在函数插件区调用 `保存当前的对话` 即可将当前对话保存为可读+可复原的html文件, 另外在函数插件区(下拉菜单)调用 `载入对话历史存档` ,即可还原之前的会话。 @@ -331,23 +291,28 @@ Tip:不指定文件直接点击 `载入对话历史存档` 可以查看历史h -7. OpenAI图像生成 +7. 新增MOSS大语言模型支持 +
+ +
+ +8. OpenAI图像生成
-8. 基于mermaid的流图、脑图绘制 +9. OpenAI音频解析与总结
- +
-9. Latex全文校对纠错 +10. Latex全文校对纠错
===>
-10. 语言、主题切换 +11. 语言、主题切换
@@ -355,14 +320,7 @@ Tip:不指定文件直接点击 `载入对话历史存档` 可以查看历史h ### II:版本: -- version 3.80(TODO): 优化AutoGen插件主题并设计一系列衍生插件 -- version 3.70: 引入Mermaid绘图,实现GPT画脑图等功能 -- version 3.60: 引入AutoGen作为新一代插件的基石 -- version 3.57: 支持GLM3,星火v3,文心一言v4,修复本地模型的并发BUG -- version 3.56: 支持动态追加基础功能按钮,新汇报PDF汇总页面 -- version 3.55: 重构前端界面,引入悬浮窗口与菜单栏 -- version 3.54: 新增动态代码解释器(Code Interpreter)(待完善) -- version 3.53: 支持动态选择不同界面主题,提高稳定性&解决多用户冲突问题 +- version 3.60(todo): 优化虚空终端,引入code interpreter和更多插件 - version 3.50: 使用自然语言调用本项目的所有函数插件(虚空终端),支持插件分类,改进UI,设计新主题 - version 3.49: 支持百度千帆平台和文心一言 - version 3.48: 支持阿里达摩院通义千问,上海AI-Lab书生,讯飞星火 @@ -376,58 +334,25 @@ Tip:不指定文件直接点击 `载入对话历史存档` 可以查看历史h - version 3.0: 对chatglm和其他小型llm的支持 - version 2.6: 重构了插件结构,提高了交互性,加入更多插件 - version 2.5: 自更新,解决总结大工程源代码时文本过长、token溢出的问题 -- version 2.4: 新增PDF全文翻译功能; 新增输入区切换位置的功能 +- version 2.4: (1)新增PDF全文翻译功能; (2)新增输入区切换位置的功能; (3)新增垂直布局选项; (4)多线程函数插件优化。 - version 2.3: 增强多线程交互性 - version 2.2: 函数插件支持热重载 - version 2.1: 可折叠式布局 - version 2.0: 引入模块化函数插件 - version 1.0: 基础功能 -GPT Academic开发者QQ群:`610599535` +gpt_academic开发者QQ群-2:610599535 - 已知问题 - 某些浏览器翻译插件干扰此软件前端的运行 - - 官方Gradio目前有很多兼容性问题,请**务必使用`requirement.txt`安装Gradio** - -```mermaid -timeline LR - title GPT-Academic项目发展历程 - section 2.x - 1.0~2.2: 基础功能: 引入模块化函数插件: 可折叠式布局: 函数插件支持热重载 - 2.3~2.5: 增强多线程交互性: 新增PDF全文翻译功能: 新增输入区切换位置的功能: 自更新 - 2.6: 重构了插件结构: 提高了交互性: 加入更多插件 - section 3.x - 3.0~3.1: 对chatglm支持: 对其他小型llm支持: 支持同时问询多个gpt模型: 支持多个apikey负载均衡 - 3.2~3.3: 函数插件支持更多参数接口: 保存对话功能: 解读任意语言代码: 同时询问任意的LLM组合: 互联网信息综合功能 - 3.4: 加入arxiv论文翻译: 加入latex论文批改功能 - 3.44: 正式支持Azure: 优化界面易用性 - 3.46: 自定义ChatGLM2微调模型: 实时语音对话 - 3.49: 支持阿里达摩院通义千问: 上海AI-Lab书生: 讯飞星火: 支持百度千帆平台 & 文心一言 - 3.50: 虚空终端: 支持插件分类: 改进UI: 设计新主题 - 3.53: 动态选择不同界面主题: 提高稳定性: 解决多用户冲突问题 - 3.55: 动态代码解释器: 重构前端界面: 引入悬浮窗口与菜单栏 - 3.56: 动态追加基础功能按钮: 新汇报PDF汇总页面 - 3.57: GLM3, 星火v3: 支持文心一言v4: 修复本地模型的并发BUG - 3.60: 引入AutoGen - 3.70: 引入Mermaid绘图: 实现GPT画脑图等功能 - 3.80(TODO): 优化AutoGen插件主题: 设计衍生插件 - -``` - + - 官方Gradio目前有很多兼容性Bug,请务必使用`requirement.txt`安装Gradio ### III:主题 可以通过修改`THEME`选项(config.py)变更主题 1. `Chuanhu-Small-and-Beautiful` [网址](https://github.com/GaiZhenbiao/ChuanhuChatGPT/) -### IV:本项目的开发分支 - -1. `master` 分支: 主分支,稳定版 -2. `frontier` 分支: 开发分支,测试版 -3. 如何[接入其他大模型](request_llms/README.md) -4. 访问GPT-Academic的[在线服务并支持我们](https://github.com/binary-husky/gpt_academic/wiki/online) - -### V:参考与学习 +### IV:参考与学习 ``` 代码中参考了很多其他优秀项目中的设计,顺序不分先后: diff --git a/app.py b/app.py index b3b5abb3423a4ff5a50a580481ad0b4dfeb68d09..3b96a0977fb5a0bb489c2dbd40d18f6a738b42f0 100644 --- a/app.py +++ b/app.py @@ -1,40 +1,24 @@ import os; os.environ['no_proxy'] = '*' # 避免代理网络产生意外污染 -help_menu_description = \ -"""Github源代码开源和更新[地址🚀](https://github.com/binary-husky/gpt_academic), -感谢热情的[开发者们❤️](https://github.com/binary-husky/gpt_academic/graphs/contributors). -

常见问题请查阅[项目Wiki](https://github.com/binary-husky/gpt_academic/wiki), -如遇到Bug请前往[Bug反馈](https://github.com/binary-husky/gpt_academic/issues). -

普通对话使用说明: 1. 输入问题; 2. 点击提交 -

基础功能区使用说明: 1. 输入文本; 2. 点击任意基础功能区按钮 -

函数插件区使用说明: 1. 输入路径/问题, 或者上传文件; 2. 点击任意函数插件区按钮 -

虚空终端使用说明: 点击虚空终端, 然后根据提示输入指令, 再次点击虚空终端 -

如何保存对话: 点击保存当前的对话按钮 -

如何语音对话: 请阅读Wiki -

如何临时更换API_KEY: 在输入区输入临时API_KEY后提交(网页刷新后失效)""" - def main(): import subprocess, sys - subprocess.check_call([sys.executable, '-m', 'pip', 'install', 'https://public.agent-matrix.com/publish/gradio-3.32.8-py3-none-any.whl']) + subprocess.check_call([sys.executable, '-m', 'pip', 'install', 'gradio-stable-fork']) import gradio as gr - if gr.__version__ not in ['3.32.8']: - raise ModuleNotFoundError("使用项目内置Gradio获取最优体验! 请运行 `pip install -r requirements.txt` 指令安装内置Gradio及其他依赖, 详情信息见requirements.txt.") - from request_llms.bridge_all import predict + from request_llm.bridge_all import predict from toolbox import format_io, find_free_port, on_file_uploaded, on_report_generated, get_conf, ArgsGeneralWrapper, load_chat_cookies, DummyWith - # 建议您复制一个config_private.py放自己的秘密, 如API和代理网址 + # 建议您复制一个config_private.py放自己的秘密, 如API和代理网址, 避免不小心传github被别人看到 proxies, WEB_PORT, LLM_MODEL, CONCURRENT_COUNT, AUTHENTICATION = get_conf('proxies', 'WEB_PORT', 'LLM_MODEL', 'CONCURRENT_COUNT', 'AUTHENTICATION') CHATBOT_HEIGHT, LAYOUT, AVAIL_LLM_MODELS, AUTO_CLEAR_TXT = get_conf('CHATBOT_HEIGHT', 'LAYOUT', 'AVAIL_LLM_MODELS', 'AUTO_CLEAR_TXT') - ENABLE_AUDIO, AUTO_CLEAR_TXT, PATH_LOGGING, AVAIL_THEMES, THEME, ADD_WAIFU = get_conf('ENABLE_AUDIO', 'AUTO_CLEAR_TXT', 'PATH_LOGGING', 'AVAIL_THEMES', 'THEME', 'ADD_WAIFU') - DARK_MODE, NUM_CUSTOM_BASIC_BTN, SSL_KEYFILE, SSL_CERTFILE = get_conf('DARK_MODE', 'NUM_CUSTOM_BASIC_BTN', 'SSL_KEYFILE', 'SSL_CERTFILE') - INIT_SYS_PROMPT = get_conf('INIT_SYS_PROMPT') + ENABLE_AUDIO, AUTO_CLEAR_TXT, PATH_LOGGING = get_conf('ENABLE_AUDIO', 'AUTO_CLEAR_TXT', 'PATH_LOGGING') # 如果WEB_PORT是-1, 则随机选取WEB端口 PORT = find_free_port() if WEB_PORT <= 0 else WEB_PORT from check_proxy import get_current_version - from themes.theme import adjust_theme, advanced_css, theme_declaration, js_code_clear, js_code_reset, js_code_show_or_hide, js_code_show_or_hide_group2 - from themes.theme import js_code_for_css_changing, js_code_for_toggle_darkmode, js_code_for_persistent_cookie_init - from themes.theme import load_dynamic_theme, to_cookie_str, from_cookie_str, init_cookie + from themes.theme import adjust_theme, advanced_css, theme_declaration + initial_prompt = "Serve me as a writing and programming assistant." title_html = f"

GPT 学术优化 {get_current_version()}

{theme_declaration}" + description = "代码开源和更新[地址🚀](https://github.com/binary-husky/gpt_academic)," + description += "感谢热情的[开发者们❤️](https://github.com/binary-husky/gpt_academic/graphs/contributors)" # 问询记录, python 版本建议3.9+(越新越好) import logging, uuid @@ -51,7 +35,7 @@ def main(): # 高级函数插件 from crazy_functional import get_crazy_functions - DEFAULT_FN_GROUPS = get_conf('DEFAULT_FN_GROUPS') + DEFAULT_FN_GROUPS, = get_conf('DEFAULT_FN_GROUPS') plugins = get_crazy_functions() all_plugin_groups = list(set([g for _, plugin in plugins.items() for g in plugin['Group'].split('|')])) match_group = lambda tags, groups: any([g in groups for g in tags.split('|')]) @@ -67,19 +51,16 @@ def main(): proxy_info = check_proxy(proxies) gr_L1 = lambda: gr.Row().style() - gr_L2 = lambda scale, elem_id: gr.Column(scale=scale, elem_id=elem_id, min_width=400) + gr_L2 = lambda scale, elem_id: gr.Column(scale=scale, elem_id=elem_id) if LAYOUT == "TOP-DOWN": gr_L1 = lambda: DummyWith() gr_L2 = lambda scale, elem_id: gr.Row() CHATBOT_HEIGHT /= 2 cancel_handles = [] - customize_btns = {} - predefined_btns = {} with gr.Blocks(title="GPT 学术优化", theme=set_theme, analytics_enabled=False, css=advanced_css) as demo: gr.HTML(title_html) gr.HTML('''
Duplicate Space请您打开此页面后务必点击上方的“复制空间”(Duplicate Space)按钮!使用时,先在输入框填入API-KEY然后回车。
切忌在“复制空间”(Duplicate Space)之前填入API_KEY或进行提问,否则您的API_KEY将极可能被空间所有者攫取!
支持任意数量的OpenAI的密钥和API2D的密钥共存,例如输入"OpenAI密钥1,API2D密钥2",然后提交,即可同时使用两种模型接口。
''') - secret_css, dark_mode, py_pickle_cookie = gr.Textbox(visible=False), gr.Textbox(DARK_MODE, visible=False), gr.Textbox(visible=False) cookies = gr.State(load_chat_cookies()) with gr_L1(): with gr_L2(scale=2, elem_id="gpt-chat"): @@ -89,45 +70,37 @@ def main(): with gr_L2(scale=1, elem_id="gpt-panel"): with gr.Accordion("输入区", open=True, elem_id="input-panel") as area_input_primary: with gr.Row(): - txt = gr.Textbox(show_label=False, lines=2, placeholder="输入问题或API密钥,输入多个密钥时,用英文逗号间隔。支持多个OpenAI密钥共存。").style(container=False) + txt = gr.Textbox(show_label=False, lines=2, placeholder="输入问题或API密钥,输入多个密钥时,用英文逗号间隔。支持OpenAI密钥和API2D密钥共存。").style(container=False) with gr.Row(): - submitBtn = gr.Button("提交", elem_id="elem_submit", variant="primary") + submitBtn = gr.Button("提交", variant="primary") with gr.Row(): - resetBtn = gr.Button("重置", elem_id="elem_reset", variant="secondary"); resetBtn.style(size="sm") - stopBtn = gr.Button("停止", elem_id="elem_stop", variant="secondary"); stopBtn.style(size="sm") - clearBtn = gr.Button("清除", elem_id="elem_clear", variant="secondary", visible=False); clearBtn.style(size="sm") - if ENABLE_AUDIO: + resetBtn = gr.Button("重置", variant="secondary"); resetBtn.style(size="sm") + stopBtn = gr.Button("停止", variant="secondary"); stopBtn.style(size="sm") + clearBtn = gr.Button("清除", variant="secondary", visible=False); clearBtn.style(size="sm") + if ENABLE_AUDIO: with gr.Row(): - audio_mic = gr.Audio(source="microphone", type="numpy", elem_id="elem_audio", streaming=True, show_label=False).style(container=False) + audio_mic = gr.Audio(source="microphone", type="numpy", streaming=True, show_label=False).style(container=False) with gr.Row(): status = gr.Markdown(f"Tip: 按Enter提交, 按Shift+Enter换行。当前模型: {LLM_MODEL} \n {proxy_info}", elem_id="state-panel") - with gr.Accordion("基础功能区", open=True, elem_id="basic-panel") as area_basic_fn: with gr.Row(): - for k in range(NUM_CUSTOM_BASIC_BTN): - customize_btn = gr.Button("自定义按钮" + str(k+1), visible=False, variant="secondary", info_str=f'基础功能区: 自定义按钮') - customize_btn.style(size="sm") - customize_btns.update({"自定义按钮" + str(k+1): customize_btn}) for k in functional: if ("Visible" in functional[k]) and (not functional[k]["Visible"]): continue variant = functional[k]["Color"] if "Color" in functional[k] else "secondary" - functional[k]["Button"] = gr.Button(k, variant=variant, info_str=f'基础功能区: {k}') + functional[k]["Button"] = gr.Button(k, variant=variant) functional[k]["Button"].style(size="sm") - predefined_btns.update({k: functional[k]["Button"]}) with gr.Accordion("函数插件区", open=True, elem_id="plugin-panel") as area_crazy_fn: with gr.Row(): gr.Markdown("插件可读取“输入区”文本/路径作为参数(上传文件自动修正路径)") with gr.Row(elem_id="input-plugin-group"): - plugin_group_sel = gr.Dropdown(choices=all_plugin_groups, label='', show_label=False, value=DEFAULT_FN_GROUPS, + plugin_group_sel = gr.Dropdown(choices=all_plugin_groups, label='', show_label=False, value=DEFAULT_FN_GROUPS, multiselect=True, interactive=True, elem_classes='normal_mut_select').style(container=False) with gr.Row(): for k, plugin in plugins.items(): if not plugin.get("AsButton", True): continue visible = True if match_group(plugin['Group'], DEFAULT_FN_GROUPS) else False variant = plugins[k]["Color"] if "Color" in plugin else "secondary" - info = plugins[k].get("Info", k) - plugin['Button'] = plugins[k]['Button'] = gr.Button(k, variant=variant, - visible=visible, info_str=f'函数插件区: {info}').style(size="sm") + plugin['Button'] = plugins[k]['Button'] = gr.Button(k, variant=variant, visible=visible).style(size="sm") with gr.Row(): with gr.Accordion("更多函数插件", open=True): dropdown_fn_list = [] @@ -138,143 +111,53 @@ def main(): with gr.Row(): dropdown = gr.Dropdown(dropdown_fn_list, value=r"打开插件列表", label="", show_label=False).style(container=False) with gr.Row(): - plugin_advanced_arg = gr.Textbox(show_label=True, label="高级参数输入区", visible=False, + plugin_advanced_arg = gr.Textbox(show_label=True, label="高级参数输入区", visible=False, placeholder="这里是特殊函数插件的高级参数输入区").style(container=False) with gr.Row(): switchy_bt = gr.Button(r"请先从插件列表中选择", variant="secondary").style(size="sm") with gr.Row(): - with gr.Accordion("点击展开“文件下载区”。", open=False) as area_file_up: - file_upload = gr.Files(label="任何文件, 推荐上传压缩文件(zip, tar)", file_count="multiple", elem_id="elem_upload") - - with gr.Floating(init_x="0%", init_y="0%", visible=True, width=None, drag="forbidden", elem_id="tooltip"): - with gr.Row(): - with gr.Tab("上传文件", elem_id="interact-panel"): - gr.Markdown("请上传本地文件/压缩包供“函数插件区”功能调用。请注意: 上传文件后会自动把输入区修改为相应路径。") - file_upload_2 = gr.Files(label="任何文件, 推荐上传压缩文件(zip, tar)", file_count="multiple", elem_id="elem_upload_float") - - with gr.Tab("更换模型", elem_id="interact-panel"): - md_dropdown = gr.Dropdown(AVAIL_LLM_MODELS, value=LLM_MODEL, label="更换LLM模型/请求源").style(container=False) + with gr.Accordion("点击展开“文件上传区”。上传本地文件/压缩包供函数插件调用。", open=False) as area_file_up: + file_upload = gr.Files(label="任何文件, 但推荐上传压缩文件(zip, tar)", file_count="multiple") + with gr.Accordion("更换模型 & SysPrompt & 交互界面布局", open=(LAYOUT == "TOP-DOWN"), elem_id="interact-panel"): + system_prompt = gr.Textbox(show_label=True, placeholder=f"System Prompt", label="System prompt", value=initial_prompt) top_p = gr.Slider(minimum=-0, maximum=1.0, value=1.0, step=0.01,interactive=True, label="Top-p (nucleus sampling)",) temperature = gr.Slider(minimum=-0, maximum=2.0, value=1.0, step=0.01, interactive=True, label="Temperature",) - max_length_sl = gr.Slider(minimum=256, maximum=1024*32, value=4096, step=128, interactive=True, label="Local LLM MaxLength",) - system_prompt = gr.Textbox(show_label=True, lines=2, placeholder=f"System Prompt", label="System prompt", value=INIT_SYS_PROMPT) - - with gr.Tab("界面外观", elem_id="interact-panel"): - theme_dropdown = gr.Dropdown(AVAIL_THEMES, value=THEME, label="更换UI主题").style(container=False) - checkboxes = gr.CheckboxGroup(["基础功能区", "函数插件区", "浮动输入区", "输入清除键", "插件参数区"], value=["基础功能区", "函数插件区"], label="显示/隐藏功能区", elem_id='cbs').style(container=False) - opt = ["自定义菜单"] - value=[] - if ADD_WAIFU: opt += ["添加Live2D形象"]; value += ["添加Live2D形象"] - checkboxes_2 = gr.CheckboxGroup(opt, value=value, label="显示/隐藏自定义菜单", elem_id='cbsc').style(container=False) - dark_mode_btn = gr.Button("切换界面明暗 ☀", variant="secondary").style(size="sm") - dark_mode_btn.click(None, None, None, _js=js_code_for_toggle_darkmode) - with gr.Tab("帮助", elem_id="interact-panel"): - gr.Markdown(help_menu_description) - - with gr.Floating(init_x="20%", init_y="50%", visible=False, width="40%", drag="top") as area_input_secondary: - with gr.Accordion("浮动输入区", open=True, elem_id="input-panel2"): - with gr.Row() as row: - row.style(equal_height=True) - with gr.Column(scale=10): - txt2 = gr.Textbox(show_label=False, placeholder="Input question here.", - elem_id='user_input_float', lines=8, label="输入区2").style(container=False) - with gr.Column(scale=1, min_width=40): - submitBtn2 = gr.Button("提交", variant="primary"); submitBtn2.style(size="sm") + max_length_sl = gr.Slider(minimum=256, maximum=8192, value=4096, step=1, interactive=True, label="Local LLM MaxLength",) + checkboxes = gr.CheckboxGroup(["基础功能区", "函数插件区", "底部输入区", "输入清除键", "插件参数区"], value=["基础功能区", "函数插件区"], label="显示/隐藏功能区") + md_dropdown = gr.Dropdown(AVAIL_LLM_MODELS, value=LLM_MODEL, label="更换LLM模型/请求源").style(container=False) + dark_mode_btn = gr.Button("Toggle Dark Mode ☀", variant="secondary").style(size="sm") + dark_mode_btn.click(None, None, None, _js="""() => { + if (document.querySelectorAll('.dark').length) { + document.querySelectorAll('.dark').forEach(el => el.classList.remove('dark')); + } else { + document.querySelector('body').classList.add('dark'); + } + }""", + ) + gr.Markdown(description) + with gr.Accordion("备选输入区", open=True, visible=False, elem_id="input-panel2") as area_input_secondary: + with gr.Row(): + txt2 = gr.Textbox(show_label=False, placeholder="Input question here.", label="输入区2").style(container=False) + with gr.Row(): + submitBtn2 = gr.Button("提交", variant="primary") + with gr.Row(): resetBtn2 = gr.Button("重置", variant="secondary"); resetBtn2.style(size="sm") stopBtn2 = gr.Button("停止", variant="secondary"); stopBtn2.style(size="sm") - clearBtn2 = gr.Button("清除", elem_id="elem_clear2", variant="secondary", visible=False); clearBtn2.style(size="sm") - - - with gr.Floating(init_x="20%", init_y="50%", visible=False, width="40%", drag="top") as area_customize: - with gr.Accordion("自定义菜单", open=True, elem_id="edit-panel"): - with gr.Row() as row: - with gr.Column(scale=10): - AVAIL_BTN = [btn for btn in customize_btns.keys()] + [k for k in functional] - basic_btn_dropdown = gr.Dropdown(AVAIL_BTN, value="自定义按钮1", label="选择一个需要自定义基础功能区按钮").style(container=False) - basic_fn_title = gr.Textbox(show_label=False, placeholder="输入新按钮名称", lines=1).style(container=False) - basic_fn_prefix = gr.Textbox(show_label=False, placeholder="输入新提示前缀", lines=4).style(container=False) - basic_fn_suffix = gr.Textbox(show_label=False, placeholder="输入新提示后缀", lines=4).style(container=False) - with gr.Column(scale=1, min_width=70): - basic_fn_confirm = gr.Button("确认并保存", variant="primary"); basic_fn_confirm.style(size="sm") - basic_fn_clean = gr.Button("恢复默认", variant="primary"); basic_fn_clean.style(size="sm") - def assign_btn(persistent_cookie_, cookies_, basic_btn_dropdown_, basic_fn_title, basic_fn_prefix, basic_fn_suffix, clean_up=False): - ret = {} - # 读取之前的自定义按钮 - customize_fn_overwrite_ = cookies_['customize_fn_overwrite'] - # 更新新的自定义按钮 - customize_fn_overwrite_.update({ - basic_btn_dropdown_: - { - "Title":basic_fn_title, - "Prefix":basic_fn_prefix, - "Suffix":basic_fn_suffix, - } - } - ) - if clean_up: - customize_fn_overwrite_ = {} - cookies_.update(customize_fn_overwrite_) # 更新cookie - visible = (not clean_up) and (basic_fn_title != "") - if basic_btn_dropdown_ in customize_btns: - # 是自定义按钮,不是预定义按钮 - ret.update({customize_btns[basic_btn_dropdown_]: gr.update(visible=visible, value=basic_fn_title)}) - else: - # 是预定义按钮 - ret.update({predefined_btns[basic_btn_dropdown_]: gr.update(visible=visible, value=basic_fn_title)}) - ret.update({cookies: cookies_}) - try: persistent_cookie_ = from_cookie_str(persistent_cookie_) # persistent cookie to dict - except: persistent_cookie_ = {} - persistent_cookie_["custom_bnt"] = customize_fn_overwrite_ # dict update new value - persistent_cookie_ = to_cookie_str(persistent_cookie_) # persistent cookie to dict - ret.update({py_pickle_cookie: persistent_cookie_}) # write persistent cookie - return ret - - # update btn - h = basic_fn_confirm.click(assign_btn, [py_pickle_cookie, cookies, basic_btn_dropdown, basic_fn_title, basic_fn_prefix, basic_fn_suffix], - [py_pickle_cookie, cookies, *customize_btns.values(), *predefined_btns.values()]) - h.then(None, [py_pickle_cookie], None, _js="""(py_pickle_cookie)=>{setCookie("py_pickle_cookie", py_pickle_cookie, 365);}""") - # clean up btn - h2 = basic_fn_clean.click(assign_btn, [py_pickle_cookie, cookies, basic_btn_dropdown, basic_fn_title, basic_fn_prefix, basic_fn_suffix, gr.State(True)], - [py_pickle_cookie, cookies, *customize_btns.values(), *predefined_btns.values()]) - h2.then(None, [py_pickle_cookie], None, _js="""(py_pickle_cookie)=>{setCookie("py_pickle_cookie", py_pickle_cookie, 365);}""") - - def persistent_cookie_reload(persistent_cookie_, cookies_): - ret = {} - for k in customize_btns: - ret.update({customize_btns[k]: gr.update(visible=False, value="")}) - - try: persistent_cookie_ = from_cookie_str(persistent_cookie_) # persistent cookie to dict - except: return ret - - customize_fn_overwrite_ = persistent_cookie_.get("custom_bnt", {}) - cookies_['customize_fn_overwrite'] = customize_fn_overwrite_ - ret.update({cookies: cookies_}) - - for k,v in persistent_cookie_["custom_bnt"].items(): - if v['Title'] == "": continue - if k in customize_btns: ret.update({customize_btns[k]: gr.update(visible=True, value=v['Title'])}) - else: ret.update({predefined_btns[k]: gr.update(visible=True, value=v['Title'])}) - return ret + clearBtn2 = gr.Button("清除", variant="secondary", visible=False); clearBtn2.style(size="sm") # 功能区显示开关与功能区的互动 def fn_area_visibility(a): ret = {} - ret.update({area_input_primary: gr.update(visible=("浮动输入区" not in a))}) - ret.update({area_input_secondary: gr.update(visible=("浮动输入区" in a))}) + ret.update({area_basic_fn: gr.update(visible=("基础功能区" in a))}) + ret.update({area_crazy_fn: gr.update(visible=("函数插件区" in a))}) + ret.update({area_input_primary: gr.update(visible=("底部输入区" not in a))}) + ret.update({area_input_secondary: gr.update(visible=("底部输入区" in a))}) + ret.update({clearBtn: gr.update(visible=("输入清除键" in a))}) + ret.update({clearBtn2: gr.update(visible=("输入清除键" in a))}) ret.update({plugin_advanced_arg: gr.update(visible=("插件参数区" in a))}) - if "浮动输入区" in a: ret.update({txt: gr.update(value="")}) - return ret - checkboxes.select(fn_area_visibility, [checkboxes], [area_basic_fn, area_crazy_fn, area_input_primary, area_input_secondary, txt, txt2, plugin_advanced_arg] ) - checkboxes.select(None, [checkboxes], None, _js=js_code_show_or_hide) - - # 功能区显示开关与功能区的互动 - def fn_area_visibility_2(a): - ret = {} - ret.update({area_customize: gr.update(visible=("自定义菜单" in a))}) + if "底部输入区" in a: ret.update({txt: gr.update(value="")}) return ret - checkboxes_2.select(fn_area_visibility_2, [checkboxes_2], [area_customize] ) - checkboxes_2.select(None, [checkboxes_2], None, _js=js_code_show_or_hide_group2) - + checkboxes.select(fn_area_visibility, [checkboxes], [area_basic_fn, area_crazy_fn, area_input_primary, area_input_secondary, txt, txt2, clearBtn, clearBtn2, plugin_advanced_arg] ) # 整理反复出现的控件句柄组合 input_combo = [cookies, max_length_sl, md_dropdown, txt, txt2, top_p, temperature, chatbot, history, system_prompt, plugin_advanced_arg] output_combo = [cookies, chatbot, history, status] @@ -284,28 +167,22 @@ def main(): cancel_handles.append(txt2.submit(**predict_args)) cancel_handles.append(submitBtn.click(**predict_args)) cancel_handles.append(submitBtn2.click(**predict_args)) - resetBtn.click(None, None, [chatbot, history, status], _js=js_code_reset) # 先在前端快速清除chatbot&status - resetBtn2.click(None, None, [chatbot, history, status], _js=js_code_reset) # 先在前端快速清除chatbot&status - resetBtn.click(lambda: ([], [], "已重置"), None, [chatbot, history, status]) # 再在后端清除history - resetBtn2.click(lambda: ([], [], "已重置"), None, [chatbot, history, status]) # 再在后端清除history - clearBtn.click(None, None, [txt, txt2], _js=js_code_clear) - clearBtn2.click(None, None, [txt, txt2], _js=js_code_clear) + resetBtn.click(lambda: ([], [], "已重置"), None, [chatbot, history, status]) + resetBtn2.click(lambda: ([], [], "已重置"), None, [chatbot, history, status]) + clearBtn.click(lambda: ("",""), None, [txt, txt2]) + clearBtn2.click(lambda: ("",""), None, [txt, txt2]) if AUTO_CLEAR_TXT: - submitBtn.click(None, None, [txt, txt2], _js=js_code_clear) - submitBtn2.click(None, None, [txt, txt2], _js=js_code_clear) - txt.submit(None, None, [txt, txt2], _js=js_code_clear) - txt2.submit(None, None, [txt, txt2], _js=js_code_clear) + submitBtn.click(lambda: ("",""), None, [txt, txt2]) + submitBtn2.click(lambda: ("",""), None, [txt, txt2]) + txt.submit(lambda: ("",""), None, [txt, txt2]) + txt2.submit(lambda: ("",""), None, [txt, txt2]) # 基础功能区的回调函数注册 for k in functional: if ("Visible" in functional[k]) and (not functional[k]["Visible"]): continue click_handle = functional[k]["Button"].click(fn=ArgsGeneralWrapper(predict), inputs=[*input_combo, gr.State(True), gr.State(k)], outputs=output_combo) cancel_handles.append(click_handle) - for btn in customize_btns.values(): - click_handle = btn.click(fn=ArgsGeneralWrapper(predict), inputs=[*input_combo, gr.State(True), gr.State(btn.value)], outputs=output_combo) - cancel_handles.append(click_handle) # 文件上传区,接收文件后与chatbot的互动 - file_upload.upload(on_file_uploaded, [file_upload, chatbot, txt, txt2, checkboxes, cookies], [chatbot, txt, txt2, cookies]).then(None, None, None, _js=r"()=>{toast_push('上传完毕 ...'); cancel_loading_status();}") - file_upload_2.upload(on_file_uploaded, [file_upload_2, chatbot, txt, txt2, checkboxes, cookies], [chatbot, txt, txt2, cookies]).then(None, None, None, _js=r"()=>{toast_push('上传完毕 ...'); cancel_loading_status();}") + file_upload.upload(on_file_uploaded, [file_upload, chatbot, txt, txt2, checkboxes, cookies], [chatbot, txt, txt2, cookies]) # 函数插件-固定按钮区 for k in plugins: if not plugins[k].get("AsButton", True): continue @@ -315,34 +192,16 @@ def main(): # 函数插件-下拉菜单与随变按钮的互动 def on_dropdown_changed(k): variant = plugins[k]["Color"] if "Color" in plugins[k] else "secondary" - info = plugins[k].get("Info", k) - ret = {switchy_bt: gr.update(value=k, variant=variant, info_str=f'函数插件区: {info}')} + ret = {switchy_bt: gr.update(value=k, variant=variant)} if plugins[k].get("AdvancedArgs", False): # 是否唤起高级插件参数区 ret.update({plugin_advanced_arg: gr.update(visible=True, label=f"插件[{k}]的高级参数说明:" + plugins[k].get("ArgsReminder", [f"没有提供高级参数功能说明"]))}) else: ret.update({plugin_advanced_arg: gr.update(visible=False, label=f"插件[{k}]不需要高级参数。")}) return ret dropdown.select(on_dropdown_changed, [dropdown], [switchy_bt, plugin_advanced_arg] ) - def on_md_dropdown_changed(k): return {chatbot: gr.update(label="当前模型:"+k)} md_dropdown.select(on_md_dropdown_changed, [md_dropdown], [chatbot] ) - - def on_theme_dropdown_changed(theme, secret_css): - adjust_theme, css_part1, _, adjust_dynamic_theme = load_dynamic_theme(theme) - if adjust_dynamic_theme: - css_part2 = adjust_dynamic_theme._get_theme_css() - else: - css_part2 = adjust_theme()._get_theme_css() - return css_part2 + css_part1 - - theme_handle = theme_dropdown.select(on_theme_dropdown_changed, [theme_dropdown, secret_css], [secret_css]) - theme_handle.then( - None, - [secret_css], - None, - _js=js_code_for_css_changing - ) # 随变按钮的回调函数注册 def route(request: gr.Request, k, *args, **kwargs): if k in [r"打开插件列表", r"请先从插件列表中选择"]: return @@ -360,53 +219,52 @@ def main(): if not group_list: # 处理特殊情况:没有选择任何插件组 return [*[plugin['Button'].update(visible=False) for _, plugin in plugins_as_btn.items()], gr.Dropdown.update(choices=[])] for k, plugin in plugins.items(): - if plugin.get("AsButton", True): + if plugin.get("AsButton", True): btn_list.append(plugin['Button'].update(visible=match_group(plugin['Group'], group_list))) # 刷新按钮 if plugin.get('AdvancedArgs', False): dropdown_fn_list.append(k) # 对于需要高级参数的插件,亦在下拉菜单中显示 elif match_group(plugin['Group'], group_list): fns_list.append(k) # 刷新下拉列表 return [*btn_list, gr.Dropdown.update(choices=fns_list)] plugin_group_sel.select(fn=on_group_change, inputs=[plugin_group_sel], outputs=[*[plugin['Button'] for name, plugin in plugins_as_btn.items()], dropdown]) - if ENABLE_AUDIO: + if ENABLE_AUDIO: from crazy_functions.live_audio.audio_io import RealtimeAudioDistribution rad = RealtimeAudioDistribution() def deal_audio(audio, cookies): rad.feed(cookies['uuid'].hex, audio) audio_mic.stream(deal_audio, inputs=[audio_mic, cookies]) - - demo.load(init_cookie, inputs=[cookies], outputs=[cookies]) - demo.load(persistent_cookie_reload, inputs = [py_pickle_cookie, cookies], - outputs = [py_pickle_cookie, cookies, *customize_btns.values(), *predefined_btns.values()], _js=js_code_for_persistent_cookie_init) - demo.load(None, inputs=[dark_mode], outputs=None, _js="""(dark_mode)=>{apply_cookie_for_checkbox(dark_mode);}""") # 配置暗色主题或亮色主题 - demo.load(None, inputs=[gr.Textbox(LAYOUT, visible=False)], outputs=None, _js='(LAYOUT)=>{GptAcademicJavaScriptInit(LAYOUT);}') - + def init_cookie(cookies, chatbot): + # 为每一位访问的用户赋予一个独一无二的uuid编码 + cookies.update({'uuid': uuid.uuid4()}) + return cookies + demo.load(init_cookie, inputs=[cookies, chatbot], outputs=[cookies]) + demo.load(lambda: 0, inputs=None, outputs=None, _js='()=>{ChatBotHeight();}') + # gradio的inbrowser触发不太稳定,回滚代码到原始的浏览器打开函数 - def run_delayed_tasks(): + def auto_opentab_delay(): import threading, webbrowser, time print(f"如果浏览器没有自动打开,请复制并转到以下URL:") - if DARK_MODE: print(f"\t「暗色主题已启用(支持动态切换主题)」: http://localhost:{PORT}") - else: print(f"\t「亮色主题已启用(支持动态切换主题)」: http://localhost:{PORT}") - - def auto_updates(): time.sleep(0); auto_update() - def open_browser(): time.sleep(2); webbrowser.open_new_tab(f"http://localhost:{PORT}") - def warm_up_mods(): time.sleep(6); warm_up_modules() - - threading.Thread(target=auto_updates, name="self-upgrade", daemon=True).start() # 查看自动更新 - threading.Thread(target=open_browser, name="open-browser", daemon=True).start() # 打开浏览器页面 - threading.Thread(target=warm_up_mods, name="warm-up", daemon=True).start() # 预热tiktoken模块 - - run_delayed_tasks() + print(f"\t(亮色主题): http://localhost:{PORT}") + print(f"\t(暗色主题): http://localhost:{PORT}/?__theme=dark") + def open(): + time.sleep(2) # 打开浏览器 + DARK_MODE, = get_conf('DARK_MODE') + if DARK_MODE: webbrowser.open_new_tab(f"http://localhost:{PORT}/?__theme=dark") + else: webbrowser.open_new_tab(f"http://localhost:{PORT}") + threading.Thread(target=open, name="open-browser", daemon=True).start() + threading.Thread(target=auto_update, name="self-upgrade", daemon=True).start() + threading.Thread(target=warm_up_modules, name="warm-up", daemon=True).start() + + auto_opentab_delay() demo.queue(concurrency_count=CONCURRENT_COUNT).launch(server_name="0.0.0.0", share=False, favicon_path="docs/logo.png", blocked_paths=["config.py","config_private.py","docker-compose.yml","Dockerfile"]) - # 如果需要在二级路径下运行 - # CUSTOM_PATH = get_conf('CUSTOM_PATH') - # if CUSTOM_PATH != "/": + # CUSTOM_PATH, = get_conf('CUSTOM_PATH') + # if CUSTOM_PATH != "/": # from toolbox import run_gradio_in_subpath # run_gradio_in_subpath(demo, auth=AUTHENTICATION, port=PORT, custom_path=CUSTOM_PATH) - # else: + # else: # demo.launch(server_name="0.0.0.0", server_port=PORT, auth=AUTHENTICATION, favicon_path="docs/logo.png", - # blocked_paths=["config.py","config_private.py","docker-compose.yml","Dockerfile",f"{PATH_LOGGING}/admin"]) + # blocked_paths=["config.py","config_private.py","docker-compose.yml","Dockerfile"]) if __name__ == "__main__": main() diff --git a/check_proxy.py b/check_proxy.py index 2df818559b16dde2999143bc4824e0aa1f3e97b8..b6fe99f878df4006cb1bc0031f86ce1ef8eba563 100644 --- a/check_proxy.py +++ b/check_proxy.py @@ -5,6 +5,7 @@ def check_proxy(proxies): try: response = requests.get("https://ipapi.co/json/", proxies=proxies, timeout=4) data = response.json() + # print(f'查询代理的地理位置,返回的结果是{data}') if 'country_name' in data: country = data['country_name'] result = f"代理配置 {proxies_https}, 代理所在地:{country}" @@ -45,9 +46,9 @@ def backup_and_download(current_version, remote_version): return new_version_dir os.makedirs(new_version_dir) shutil.copytree('./', backup_dir, ignore=lambda x, y: ['history']) - proxies = get_conf('proxies') - try: r = requests.get('https://github.com/binary-husky/chatgpt_academic/archive/refs/heads/master.zip', proxies=proxies, stream=True) - except: r = requests.get('https://public.gpt-academic.top/publish/master.zip', proxies=proxies, stream=True) + proxies, = get_conf('proxies') + r = requests.get( + 'https://github.com/binary-husky/chatgpt_academic/archive/refs/heads/master.zip', proxies=proxies, stream=True) zip_file_path = backup_dir+'/master.zip' with open(zip_file_path, 'wb+') as f: f.write(r.content) @@ -110,10 +111,11 @@ def auto_update(raise_error=False): try: from toolbox import get_conf import requests + import time import json - proxies = get_conf('proxies') - try: response = requests.get("https://raw.githubusercontent.com/binary-husky/chatgpt_academic/master/version", proxies=proxies, timeout=5) - except: response = requests.get("https://public.gpt-academic.top/publish/version", proxies=proxies, timeout=5) + proxies, = get_conf('proxies') + response = requests.get( + "https://raw.githubusercontent.com/binary-husky/chatgpt_academic/master/version", proxies=proxies, timeout=5) remote_json_data = json.loads(response.text) remote_version = remote_json_data['version'] if remote_json_data["show_feature"]: @@ -125,7 +127,8 @@ def auto_update(raise_error=False): current_version = json.loads(current_version)['version'] if (remote_version - current_version) >= 0.01-1e-5: from colorful import print亮黄 - print亮黄(f'\n新版本可用。新版本:{remote_version},当前版本:{current_version}。{new_feature}') + print亮黄( + f'\n新版本可用。新版本:{remote_version},当前版本:{current_version}。{new_feature}') print('(1)Github更新地址:\nhttps://github.com/binary-husky/chatgpt_academic\n') user_instruction = input('(2)是否一键更新代码(Y+回车=确认,输入其他/无输入+回车=不更新)?') if user_instruction in ['Y', 'y']: @@ -151,26 +154,16 @@ def auto_update(raise_error=False): print(msg) def warm_up_modules(): - print('正在执行一些模块的预热 ...') - from toolbox import ProxyNetworkActivate - from request_llms.bridge_all import model_info - with ProxyNetworkActivate("Warmup_Modules"): - enc = model_info["gpt-3.5-turbo"]['tokenizer'] - enc.encode("模块预热", disallowed_special=()) - enc = model_info["gpt-4"]['tokenizer'] - enc.encode("模块预热", disallowed_special=()) - -def warm_up_vectordb(): - print('正在执行一些模块的预热 ...') - from toolbox import ProxyNetworkActivate - with ProxyNetworkActivate("Warmup_Modules"): - import nltk - with ProxyNetworkActivate("Warmup_Modules"): nltk.download("punkt") + print('正在执行一些模块的预热...') + from request_llm.bridge_all import model_info + enc = model_info["gpt-3.5-turbo"]['tokenizer'] + enc.encode("模块预热", disallowed_special=()) + enc = model_info["gpt-4"]['tokenizer'] + enc.encode("模块预热", disallowed_special=()) - if __name__ == '__main__': import os os.environ['no_proxy'] = '*' # 避免代理网络产生意外污染 from toolbox import get_conf - proxies = get_conf('proxies') + proxies, = get_conf('proxies') check_proxy(proxies) diff --git a/config.py b/config.py index a536a181a31b2d35beb4b38937f77a2087b5bde4..46f8a9887abe6632422211dcc11b31cc7cba3043 100644 --- a/config.py +++ b/config.py @@ -2,8 +2,8 @@ 以下所有配置也都支持利用环境变量覆写,环境变量配置格式见docker-compose.yml。 读取优先级:环境变量 > config_private.py > config.py --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- - All the following configurations also support using environment variables to override, - and the environment variable configuration format can be seen in docker-compose.yml. + All the following configurations also support using environment variables to override, + and the environment variable configuration format can be seen in docker-compose.yml. Configuration reading priority: environment variable > config_private.py > config.py """ @@ -19,13 +19,13 @@ API_KEY = "此处填API密钥" # 可同时填写多个API-KEY,用英文逗 USE_PROXY = False if USE_PROXY: """ - 代理网络的地址,打开你的代理软件查看代理协议(socks5h / http)、地址(localhost)和端口(11284) 填写格式是 [协议]:// [地址] :[端口],填写之前不要忘记把USE_PROXY改成True,如果直接在海外服务器部署,此处不修改 <配置教程&视频教程> https://github.com/binary-husky/gpt_academic/issues/1> [协议] 常见协议无非socks5h/http; 例如 v2**y 和 ss* 的默认本地协议是socks5h; 而cl**h 的默认本地协议是http - [地址] 填localhost或者127.0.0.1(localhost意思是代理软件安装在本机上) + [地址] 懂的都懂,不懂就填localhost或者127.0.0.1肯定错不了(localhost意思是代理软件安装在本机上) [端口] 在代理软件的设置里找。虽然不同的代理软件界面不一样,但端口号都应该在最显眼的位置上 """ + # 代理网络的地址,打开你的*学*网软件查看代理的协议(socks5h / http)、地址(localhost)和端口(11284) proxies = { # [协议]:// [地址] :[端口] "http": "socks5h://localhost:11284", # 再例如 "http": "http://127.0.0.1:7890", @@ -37,7 +37,7 @@ else: # ------------------------------------ 以下配置可以优化体验, 但大部分场合下并不需要修改 ------------------------------------ # 重新URL重新定向,实现更换API_URL的作用(高危设置! 常规情况下不要修改! 通过修改此设置,您将把您的API-KEY和对话隐私完全暴露给您设定的中间人!) -# 格式: API_URL_REDIRECT = {"https://api.openai.com/v1/chat/completions": "在这里填写重定向的api.openai.com的URL"} +# 格式: API_URL_REDIRECT = {"https://api.openai.com/v1/chat/completions": "在这里填写重定向的api.openai.com的URL"} # 举例: API_URL_REDIRECT = {"https://api.openai.com/v1/chat/completions": "https://reverse-proxy-url/v1/chat/completions"} API_URL_REDIRECT = {} @@ -50,11 +50,6 @@ DEFAULT_WORKER_NUM = 3 # 色彩主题, 可选 ["Default", "Chuanhu-Small-and-Beautiful", "High-Contrast"] # 更多主题, 请查阅Gradio主题商店: https://huggingface.co/spaces/gradio/theme-gallery 可选 ["Gstaff/Xkcd", "NoCrypt/Miku", ...] THEME = "Chuanhu-Small-and-Beautiful" -AVAIL_THEMES = ["Default", "Chuanhu-Small-and-Beautiful", "High-Contrast", "Gstaff/Xkcd", "NoCrypt/Miku"] - - -# 默认的系统提示词(system prompt) -INIT_SYS_PROMPT = "Serve me as a writing and programming assistant." # 对话窗的高度 (仅在LAYOUT="TOP-DOWN"时生效) @@ -67,10 +62,7 @@ CODE_HIGHLIGHT = True # 窗口布局 LAYOUT = "LEFT-RIGHT" # "LEFT-RIGHT"(左右布局) # "TOP-DOWN"(上下布局) - - -# 暗色模式 / 亮色模式 -DARK_MODE = False +DARK_MODE = True # 暗色模式 / 亮色模式 # 发送请求到OpenAI后,等待多久判定为超时 @@ -89,41 +81,21 @@ LLM_MODEL = "gpt-3.5-turbo" # 可选 "chatglm" AVAIL_LLM_MODELS = ["gpt-3.5-turbo", "gpt-4", "api2d-gpt-4", "api2d-gpt-3.5-turbo", "spark", "azure-gpt-3.5"] # 插件分类默认选项 -DEFAULT_FN_GROUPS = ['对话', '编程', '学术', '智能体'] +DEFAULT_FN_GROUPS = ['对话', '编程', '学术'] # 模型选择是 (注意: LLM_MODEL是默认选中的模型, 它*必须*被包含在AVAIL_LLM_MODELS列表中 ) -LLM_MODEL = "gpt-3.5-turbo-16k" # 可选 ↓↓↓ -AVAIL_LLM_MODELS = ["gpt-4-1106-preview", "gpt-4-turbo-preview", "gpt-4-vision-preview", - "gpt-3.5-turbo-1106", "gpt-3.5-turbo-16k", "gpt-3.5-turbo", "azure-gpt-3.5", - "gpt-4", "gpt-4-32k", "azure-gpt-4", "glm-4", "glm-3-turbo", - "gemini-pro", "chatglm3", "claude-2"] -# P.S. 其他可用的模型还包括 [ -# "moss", "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" -# ] - - -# 定义界面上“询问多个GPT模型”插件应该使用哪些模型,请从AVAIL_LLM_MODELS中选择,并在不同模型之间用`&`间隔,例如"gpt-3.5-turbo&chatglm3&azure-gpt-4" -MULTI_QUERY_LLM_MODELS = "gpt-3.5-turbo&chatglm3" - - -# 选择本地模型变体(只有当AVAIL_LLM_MODELS包含了对应本地模型时,才会起作用) -# 如果你选择Qwen系列的模型,那么请在下面的QWEN_MODEL_SELECTION中指定具体的模型 -# 也可以是具体的模型路径 -QWEN_LOCAL_MODEL_SELECTION = "Qwen/Qwen-1_8B-Chat-Int8" - - -# 接入通义千问在线大模型 https://dashscope.console.aliyun.com/ -DASHSCOPE_API_KEY = "" # 阿里灵积云API_KEY +LLM_MODEL = "gpt-3.5-turbo" # 可选 ↓↓↓ +AVAIL_LLM_MODELS = ["gpt-3.5-turbo-16k", "gpt-3.5-turbo", "azure-gpt-3.5", "api2d-gpt-3.5-turbo", + "gpt-4", "api2d-gpt-4", "chatglm", "moss", "newbing", "stack-claude"] +# P.S. 其他可用的模型还包括 ["qianfan", "llama2", "qwen", "gpt-3.5-turbo-0613", "gpt-3.5-turbo-16k-0613", +# "spark", "sparkv2", "chatglm_onnx", "claude-1-100k", "claude-2", "internlm", "jittorllms_pangualpha", "jittorllms_llama"] # 百度千帆(LLM_MODEL="qianfan") BAIDU_CLOUD_API_KEY = '' BAIDU_CLOUD_SECRET_KEY = '' -BAIDU_CLOUD_QIANFAN_MODEL = 'ERNIE-Bot' # 可选 "ERNIE-Bot-4"(文心大模型4.0), "ERNIE-Bot"(文心一言), "ERNIE-Bot-turbo", "BLOOMZ-7B", "Llama-2-70B-Chat", "Llama-2-13B-Chat", "Llama-2-7B-Chat" +BAIDU_CLOUD_QIANFAN_MODEL = 'ERNIE-Bot' # 可选 "ERNIE-Bot"(文心一言), "ERNIE-Bot-turbo", "BLOOMZ-7B", "Llama-2-70B-Chat", "Llama-2-13B-Chat", "Llama-2-7B-Chat" # 如果使用ChatGLM2微调模型,请把 LLM_MODEL="chatglmft",并在此处指定模型路径 @@ -134,6 +106,7 @@ CHATGLM_PTUNING_CHECKPOINT = "" # 例如"/home/hmp/ChatGLM2-6B/ptuning/output/6b LOCAL_MODEL_DEVICE = "cpu" # 可选 "cuda" LOCAL_MODEL_QUANT = "FP16" # 默认 "FP16" "INT4" 启用量化INT4版本 "INT8" 启用量化INT8版本 + # 设置gradio的并行线程数(不需要修改) CONCURRENT_COUNT = 100 @@ -143,7 +116,7 @@ AUTO_CLEAR_TXT = False # 加一个live2d装饰 -ADD_WAIFU = True +ADD_WAIFU = False # 设置用户名和密码(不需要修改)(相关功能不稳定,与gradio版本和网络都相关,如果本地使用不建议加这个) @@ -155,31 +128,22 @@ AUTHENTICATION = [] CUSTOM_PATH = "/" -# HTTPS 秘钥和证书(不需要修改) -SSL_KEYFILE = "" -SSL_CERTFILE = "" - - # 极少数情况下,openai的官方KEY需要伴随组织编码(格式如org-xxxxxxxxxxxxxxxxxxxxxxxx)使用 API_ORG = "" -# 如果需要使用Slack Claude,使用教程详情见 request_llms/README.md -SLACK_CLAUDE_BOT_ID = '' +# 如果需要使用Slack Claude,使用教程详情见 request_llm/README.md +SLACK_CLAUDE_BOT_ID = '' SLACK_CLAUDE_USER_TOKEN = '' -# 如果需要使用AZURE(方法一:单个azure模型部署)详情请见额外文档 docs\use_azure.md +# 如果需要使用AZURE 详情请见额外文档 docs\use_azure.md AZURE_ENDPOINT = "https://你亲手写的api名称.openai.azure.com/" AZURE_API_KEY = "填入azure openai api的密钥" # 建议直接在API_KEY处填写,该选项即将被弃用 AZURE_ENGINE = "填入你亲手写的部署名" # 读 docs\use_azure.md -# 如果需要使用AZURE(方法二:多个azure模型部署+动态切换)详情请见额外文档 docs\use_azure.md -AZURE_CFG_ARRAY = {} - - -# 使用Newbing (不推荐使用,未来将删除) +# 使用Newbing NEWBING_STYLE = "creative" # ["creative", "balanced", "precise"] NEWBING_COOKIES = """ put your new bing cookies here @@ -200,79 +164,33 @@ XFYUN_API_SECRET = "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" XFYUN_API_KEY = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" -# 接入智谱大模型 -ZHIPUAI_API_KEY = "" -ZHIPUAI_MODEL = "" # 此选项已废弃,不再需要填写 - - -# # 火山引擎YUNQUE大模型 -# YUNQUE_SECRET_KEY = "" -# YUNQUE_ACCESS_KEY = "" -# YUNQUE_MODEL = "" - - # Claude API KEY ANTHROPIC_API_KEY = "" -# Mathpix 拥有执行PDF的OCR功能,但是需要注册账号 -MATHPIX_APPID = "" -MATHPIX_APPKEY = "" - - # 自定义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 = "" +HUGGINGFACE_ACCESS_TOKEN = "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" # GROBID服务器地址(填写多个可以均衡负载),用于高质量地读取PDF文档 # 获取方法:复制以下空间https://huggingface.co/spaces/qingxu98/grobid,设为public,然后GROBID_URL = "https://(你的hf用户名如qingxu98)-(你的填写的空间名如grobid).hf.space" GROBID_URLS = [ "https://qingxu98-grobid.hf.space","https://qingxu98-grobid2.hf.space","https://qingxu98-grobid3.hf.space", - "https://qingxu98-grobid4.hf.space","https://qingxu98-grobid5.hf.space", "https://qingxu98-grobid6.hf.space", - "https://qingxu98-grobid7.hf.space", "https://qingxu98-grobid8.hf.space", + "https://shaocongma-grobid.hf.space","https://FBR123-grobid.hf.space", "https://yeku-grobid.hf.space", ] # 是否允许通过自然语言描述修改本页的配置,该功能具有一定的危险性,默认关闭 ALLOW_RESET_CONFIG = False - - -# 在使用AutoGen插件时,是否使用Docker容器运行代码 -AUTOGEN_USE_DOCKER = False - - # 临时的上传文件夹位置,请勿修改 PATH_PRIVATE_UPLOAD = "private_upload" - - # 日志文件夹的位置,请勿修改 PATH_LOGGING = "gpt_log" - -# 除了连接OpenAI之外,还有哪些场合允许使用代理,请勿修改 -WHEN_TO_USE_PROXY = ["Download_LLM", "Download_Gradio_Theme", "Connect_Grobid", - "Warmup_Modules", "Nougat_Download", "AutoGen"] - - -# *实验性功能*: 自动检测并屏蔽失效的KEY,请勿使用 -BLOCK_INVALID_APIKEY = False - - -# 启用插件热加载 -PLUGIN_HOT_RELOAD = False - - -# 自定义按钮的最大数量限制 -NUM_CUSTOM_BASIC_BTN = 4 - """ 在线大模型配置关联关系示意图 │ @@ -282,16 +200,13 @@ NUM_CUSTOM_BASIC_BTN = 4 │ ├── API_ORG(不常用) │ └── API_URL_REDIRECT(不常用) │ -├── "azure-gpt-3.5" 等azure模型(单个azure模型,不需要动态切换) +├── "azure-gpt-3.5" 等azure模型 │ ├── API_KEY │ ├── AZURE_ENDPOINT │ ├── AZURE_API_KEY │ ├── AZURE_ENGINE │ └── API_URL_REDIRECT │ -├── "azure-gpt-3.5" 等azure模型(多个azure模型,需要动态切换,高优先级) -│ └── AZURE_CFG_ARRAY -│ ├── "spark" 星火认知大模型 spark & sparkv2 │ ├── XFYUN_APPID │ ├── XFYUN_API_SECRET @@ -309,36 +224,11 @@ NUM_CUSTOM_BASIC_BTN = 4 │ ├── BAIDU_CLOUD_API_KEY │ └── BAIDU_CLOUD_SECRET_KEY │ -├── "glm-4", "glm-3-turbo", "zhipuai" 智谱AI大模型 -│ └── ZHIPUAI_API_KEY -│ -├── "qwen-turbo" 等通义千问大模型 -│ └── DASHSCOPE_API_KEY -│ -├── "Gemini" -│ └── GEMINI_API_KEY -│ -└── "newbing" Newbing接口不再稳定,不推荐使用 +├── "newbing" Newbing接口不再稳定,不推荐使用 ├── NEWBING_STYLE └── NEWBING_COOKIES - -本地大模型示意图 -│ -├── "chatglm3" -├── "chatglm" -├── "chatglm_onnx" -├── "chatglmft" -├── "internlm" -├── "moss" -├── "jittorllms_pangualpha" -├── "jittorllms_llama" -├── "deepseekcoder" -├── "qwen-local" -├── RWKV的支持见Wiki -└── "llama2" - - + 用户图形界面布局依赖关系示意图 │ ├── CHATBOT_HEIGHT 对话窗的高度 @@ -349,7 +239,7 @@ NUM_CUSTOM_BASIC_BTN = 4 ├── THEME 色彩主题 ├── AUTO_CLEAR_TXT 是否在提交时自动清空输入框 ├── ADD_WAIFU 加一个live2d装饰 -└── ALLOW_RESET_CONFIG 是否允许通过自然语言描述修改本页的配置,该功能具有一定的危险性 +├── ALLOW_RESET_CONFIG 是否允许通过自然语言描述修改本页的配置,该功能具有一定的危险性 插件在线服务配置依赖关系示意图 @@ -361,10 +251,7 @@ NUM_CUSTOM_BASIC_BTN = 4 │ ├── ALIYUN_ACCESSKEY │ └── ALIYUN_SECRET │ -└── PDF文档精准解析 - ├── GROBID_URLS - ├── MATHPIX_APPID - └── MATHPIX_APPKEY - +├── PDF文档精准解析 +│ └── GROBID_URLS """ diff --git a/core_functional.py b/core_functional.py index 4074cddb27b4f10c86b803df37005f516bfd8f58..c4519ef8a73e3c01386a48ef3a26bf4560f3a2fc 100644 --- a/core_functional.py +++ b/core_functional.py @@ -3,143 +3,83 @@ # 'stop' 颜色对应 theme.py 中的 color_er import importlib from toolbox import clear_line_break -from toolbox import apply_gpt_academic_string_mask_langbased -from toolbox import build_gpt_academic_masked_string_langbased -from textwrap import dedent + def get_core_functions(): return { - - "学术语料润色": { - # [1*] 前缀字符串,会被加在你的输入之前。例如,用来描述你的要求,例如翻译、解释代码、润色等等。 - # 这里填一个提示词字符串就行了,这里为了区分中英文情景搞复杂了一点 - "Prefix": build_gpt_academic_masked_string_langbased( - text_show_english= - r"Below is a paragraph from an academic paper. Polish the writing to meet the academic style, " - r"improve the spelling, grammar, clarity, concision and overall readability. When necessary, rewrite the whole sentence. " - r"Firstly, you should provide the polished paragraph. " - r"Secondly, you should list all your modification and explain the reasons to do so in markdown table.", - text_show_chinese= - r"作为一名中文学术论文写作改进助理,你的任务是改进所提供文本的拼写、语法、清晰、简洁和整体可读性," - r"同时分解长句,减少重复,并提供改进建议。请先提供文本的更正版本,然后在markdown表格中列出修改的内容,并给出修改的理由:" - ) + "\n\n", - # [2*] 后缀字符串,会被加在你的输入之后。例如,配合前缀可以把你的输入内容用引号圈起来 + "英语学术润色": { + # 前缀,会被加在你的输入之前。例如,用来描述你的要求,例如翻译、解释代码、润色等等 + "Prefix": r"Below is a paragraph from an academic paper. Polish the writing to meet the academic style, " + + r"improve the spelling, grammar, clarity, concision and overall readability. When necessary, rewrite the whole sentence. " + + r"Furthermore, list all modification and explain the reasons to do so in markdown table." + "\n\n", + # 后缀,会被加在你的输入之后。例如,配合前缀可以把你的输入内容用引号圈起来 "Suffix": r"", - # [3] 按钮颜色 (可选参数,默认 secondary) + # 按钮颜色 (默认 secondary) "Color": r"secondary", - # [4] 按钮是否可见 (可选参数,默认 True,即可见) + # 按钮是否可见 (默认 True,即可见) "Visible": True, - # [5] 是否在触发时清除历史 (可选参数,默认 False,即不处理之前的对话历史) - "AutoClearHistory": False, - # [6] 文本预处理 (可选参数,默认 None,举例:写个函数移除所有的换行符) - "PreProcess": None, + # 是否在触发时清除历史 (默认 False,即不处理之前的对话历史) + "AutoClearHistory": False }, - - - "总结绘制脑图": { - # 前缀,会被加在你的输入之前。例如,用来描述你的要求,例如翻译、解释代码、润色等等 - "Prefix": r"", - # 后缀,会被加在你的输入之后。例如,配合前缀可以把你的输入内容用引号圈起来 - "Suffix": - # dedent() 函数用于去除多行字符串的缩进 - dedent("\n"+r''' - ============================== - - 使用mermaid flowchart对以上文本进行总结,概括上述段落的内容以及内在逻辑关系,例如: - - 以下是对以上文本的总结,以mermaid flowchart的形式展示: - ```mermaid - flowchart LR - A["节点名1"] --> B("节点名2") - B --> C{"节点名3"} - C --> D["节点名4"] - C --> |"箭头名1"| E["节点名5"] - C --> |"箭头名2"| F["节点名6"] - ``` - - 警告: - (1)使用中文 - (2)节点名字使用引号包裹,如["Laptop"] - (3)`|` 和 `"`之间不要存在空格 - (4)根据情况选择flowchart LR(从左到右)或者flowchart TD(从上到下) - '''), + "中文学术润色": { + "Prefix": r"作为一名中文学术论文写作改进助理,你的任务是改进所提供文本的拼写、语法、清晰、简洁和整体可读性," + + r"同时分解长句,减少重复,并提供改进建议。请只提供文本的更正版本,避免包括解释。请编辑以下文本" + "\n\n", + "Suffix": r"", }, - - "查找语法错误": { - "Prefix": r"Help me ensure that the grammar and the spelling is correct. " - r"Do not try to polish the text, if no mistake is found, tell me that this paragraph is good. " - r"If you find grammar or spelling mistakes, please list mistakes you find in a two-column markdown table, " - r"put the original text the first column, " - r"put the corrected text in the second column and highlight the key words you fixed. " - r"Finally, please provide the proofreaded text.""\n\n" + "Prefix": r"Can you help me ensure that the grammar and the spelling is correct? " + + r"Do not try to polish the text, if no mistake is found, tell me that this paragraph is good." + + r"If you find grammar or spelling mistakes, please list mistakes you find in a two-column markdown table, " + + r"put the original text the first column, " + + r"put the corrected text in the second column and highlight the key words you fixed.""\n" r"Example:""\n" r"Paragraph: How is you? Do you knows what is it?""\n" r"| Original sentence | Corrected sentence |""\n" r"| :--- | :--- |""\n" r"| How **is** you? | How **are** you? |""\n" - r"| Do you **knows** what **is** **it**? | Do you **know** what **it** **is** ? |""\n\n" + r"| Do you **knows** what **is** **it**? | Do you **know** what **it** **is** ? |""\n" r"Below is a paragraph from an academic paper. " r"You need to report all grammar and spelling mistakes as the example before." + "\n\n", "Suffix": r"", "PreProcess": clear_line_break, # 预处理:清除换行符 }, - - "中译英": { "Prefix": r"Please translate following sentence to English:" + "\n\n", "Suffix": r"", }, - - - "学术英中互译": { - "Prefix": build_gpt_academic_masked_string_langbased( - text_show_chinese= - r"I want you to act as a scientific English-Chinese translator, " - r"I will provide you with some paragraphs in one language " - r"and your task is to accurately and academically translate the paragraphs only into the other language. " - r"Do not repeat the original provided paragraphs after translation. " - r"You should use artificial intelligence tools, " - r"such as natural language processing, and rhetorical knowledge " - r"and experience about effective writing techniques to reply. " - r"I'll give you my paragraphs as follows, tell me what language it is written in, and then translate:", - text_show_english= - r"你是经验丰富的翻译,请把以下学术文章段落翻译成中文," - r"并同时充分考虑中文的语法、清晰、简洁和整体可读性," - r"必要时,你可以修改整个句子的顺序以确保翻译后的段落符合中文的语言习惯。" - r"你需要翻译的文本如下:" - ) + "\n\n", - "Suffix": r"", + "学术中英互译": { + "Prefix": r"I want you to act as a scientific English-Chinese translator, " + + r"I will provide you with some paragraphs in one language " + + r"and your task is to accurately and academically translate the paragraphs only into the other language. " + + r"Do not repeat the original provided paragraphs after translation. " + + r"You should use artificial intelligence tools, " + + r"such as natural language processing, and rhetorical knowledge " + + r"and experience about effective writing techniques to reply. " + + r"I'll give you my paragraphs as follows, tell me what language it is written in, and then translate:" + "\n\n", + "Suffix": "", + "Color": "secondary", }, - - "英译中": { "Prefix": r"翻译成地道的中文:" + "\n\n", "Suffix": r"", - "Visible": False, + "Visible": False, }, - - "找图片": { - "Prefix": r"我需要你找一张网络图片。使用Unsplash API(https://source.unsplash.com/960x640/?<英语关键词>)获取图片URL," + "Prefix": r"我需要你找一张网络图片。使用Unsplash API(https://source.unsplash.com/960x640/?<英语关键词>)获取图片URL," + r"然后请使用Markdown格式封装,并且不要有反斜线,不要用代码块。现在,请按以下描述给我发送图片:" + "\n\n", "Suffix": r"", - "Visible": False, + "Visible": False, }, - - "解释代码": { "Prefix": r"请解释以下代码:" + "\n```\n", "Suffix": "\n```\n", }, - - "参考文献转Bib": { - "Prefix": r"Here are some bibliography items, please transform them into bibtex style." - r"Note that, reference styles maybe more than one kind, you should transform each item correctly." - r"Items need to be transformed:" + "\n\n", - "Visible": False, + "Prefix": r"Here are some bibliography items, please transform them into bibtex style." + + r"Note that, reference styles maybe more than one kind, you should transform each item correctly." + + r"Items need to be transformed:", + "Visible": False, "Suffix": r"", } } @@ -149,25 +89,8 @@ def handle_core_functionality(additional_fn, inputs, history, chatbot): import core_functional importlib.reload(core_functional) # 热更新prompt core_functional = core_functional.get_core_functions() - addition = chatbot._cookies['customize_fn_overwrite'] - if additional_fn in addition: - # 自定义功能 - inputs = addition[additional_fn]["Prefix"] + inputs + addition[additional_fn]["Suffix"] - return inputs, history - else: - # 预制功能 - if "PreProcess" in core_functional[additional_fn]: - if core_functional[additional_fn]["PreProcess"] is not None: - inputs = core_functional[additional_fn]["PreProcess"](inputs) # 获取预处理函数(如果有的话) - # 为字符串加上上面定义的前缀和后缀。 - inputs = apply_gpt_academic_string_mask_langbased( - string = core_functional[additional_fn]["Prefix"] + inputs + core_functional[additional_fn]["Suffix"], - lang_reference = inputs, - ) - if core_functional[additional_fn].get("AutoClearHistory", False): - history = [] - return inputs, history - -if __name__ == "__main__": - t = get_core_functions()["总结绘制脑图"] - print(t["Prefix"] + t["Suffix"]) \ No newline at end of file + if "PreProcess" in core_functional[additional_fn]: inputs = core_functional[additional_fn]["PreProcess"](inputs) # 获取预处理函数(如果有的话) + inputs = core_functional[additional_fn]["Prefix"] + inputs + core_functional[additional_fn]["Suffix"] + if core_functional[additional_fn].get("AutoClearHistory", False): + history = [] + return inputs, history diff --git a/crazy_functional.py b/crazy_functional.py index 3e998e56fce91582ab89d2c7e7b41eb94eabdf8d..4df53f582944d766f46a42372e83477cde46dc41 100644 --- a/crazy_functional.py +++ b/crazy_functional.py @@ -1,5 +1,4 @@ from toolbox import HotReload # HotReload 的意思是热更新,修改函数插件后,不需要重启程序,代码直接生效 -from toolbox import trimmed_format_exc def get_crazy_functions(): @@ -7,7 +6,6 @@ def get_crazy_functions(): from crazy_functions.生成函数注释 import 批量生成函数注释 from crazy_functions.解析项目源代码 import 解析项目本身 from crazy_functions.解析项目源代码 import 解析一个Python项目 - from crazy_functions.解析项目源代码 import 解析一个Matlab项目 from crazy_functions.解析项目源代码 import 解析一个C项目的头文件 from crazy_functions.解析项目源代码 import 解析一个C项目 from crazy_functions.解析项目源代码 import 解析一个Golang项目 @@ -32,122 +30,108 @@ def get_crazy_functions(): from crazy_functions.理解PDF文档内容 import 理解PDF文档内容标准文件输入 from crazy_functions.Latex全文润色 import Latex中文润色 from crazy_functions.Latex全文润色 import Latex英文纠错 + from crazy_functions.Latex全文翻译 import Latex中译英 + from crazy_functions.Latex全文翻译 import Latex英译中 from crazy_functions.批量Markdown翻译 import Markdown中译英 from crazy_functions.虚空终端 import 虚空终端 - from crazy_functions.生成多种Mermaid图表 import 生成多种Mermaid图表 + function_plugins = { "虚空终端": { - "Group": "对话|编程|学术|智能体", + "Group": "对话|编程|学术", "Color": "stop", "AsButton": True, - "Function": HotReload(虚空终端), + "Function": HotReload(虚空终端) }, "解析整个Python项目": { "Group": "编程", "Color": "stop", "AsButton": True, "Info": "解析一个Python项目的所有源文件(.py) | 输入参数为路径", - "Function": HotReload(解析一个Python项目), + "Function": HotReload(解析一个Python项目) }, "载入对话历史存档(先上传存档或输入路径)": { "Group": "对话", "Color": "stop", "AsButton": False, "Info": "载入对话历史存档 | 输入参数为路径", - "Function": HotReload(载入对话历史存档), + "Function": HotReload(载入对话历史存档) }, "删除所有本地对话历史记录(谨慎操作)": { "Group": "对话", "AsButton": False, "Info": "删除所有本地对话历史记录,谨慎操作 | 不需要输入参数", - "Function": HotReload(删除所有本地对话历史记录), + "Function": HotReload(删除所有本地对话历史记录) }, "清除所有缓存文件(谨慎操作)": { "Group": "对话", "Color": "stop", "AsButton": False, # 加入下拉菜单中 "Info": "清除所有缓存文件,谨慎操作 | 不需要输入参数", - "Function": HotReload(清除缓存), - }, - "生成多种Mermaid图表(从当前对话或路径(.pdf/.md/.docx)中生产图表)": { - "Group": "对话", - "Color": "stop", - "AsButton": False, - "Info" : "基于当前对话或文件生成多种Mermaid图表,图表类型由模型判断", - "Function": HotReload(生成多种Mermaid图表), - "AdvancedArgs": True, - "ArgsReminder": "请输入图类型对应的数字,不输入则为模型自行判断:1-流程图,2-序列图,3-类图,4-饼图,5-甘特图,6-状态图,7-实体关系图,8-象限提示图,9-思维导图", + "Function": HotReload(清除缓存) }, "批量总结Word文档": { "Group": "学术", "Color": "stop", "AsButton": True, "Info": "批量总结word文档 | 输入参数为路径", - "Function": HotReload(总结word文档), - }, - "解析整个Matlab项目": { - "Group": "编程", - "Color": "stop", - "AsButton": False, - "Info": "解析一个Matlab项目的所有源文件(.m) | 输入参数为路径", - "Function": HotReload(解析一个Matlab项目), + "Function": HotReload(总结word文档) }, "解析整个C++项目头文件": { "Group": "编程", "Color": "stop", "AsButton": False, # 加入下拉菜单中 "Info": "解析一个C++项目的所有头文件(.h/.hpp) | 输入参数为路径", - "Function": HotReload(解析一个C项目的头文件), + "Function": HotReload(解析一个C项目的头文件) }, "解析整个C++项目(.cpp/.hpp/.c/.h)": { "Group": "编程", "Color": "stop", "AsButton": False, # 加入下拉菜单中 "Info": "解析一个C++项目的所有源文件(.cpp/.hpp/.c/.h)| 输入参数为路径", - "Function": HotReload(解析一个C项目), + "Function": HotReload(解析一个C项目) }, "解析整个Go项目": { "Group": "编程", "Color": "stop", "AsButton": False, # 加入下拉菜单中 "Info": "解析一个Go项目的所有源文件 | 输入参数为路径", - "Function": HotReload(解析一个Golang项目), + "Function": HotReload(解析一个Golang项目) }, "解析整个Rust项目": { "Group": "编程", "Color": "stop", "AsButton": False, # 加入下拉菜单中 "Info": "解析一个Rust项目的所有源文件 | 输入参数为路径", - "Function": HotReload(解析一个Rust项目), + "Function": HotReload(解析一个Rust项目) }, "解析整个Java项目": { "Group": "编程", "Color": "stop", "AsButton": False, # 加入下拉菜单中 "Info": "解析一个Java项目的所有源文件 | 输入参数为路径", - "Function": HotReload(解析一个Java项目), + "Function": HotReload(解析一个Java项目) }, "解析整个前端项目(js,ts,css等)": { "Group": "编程", "Color": "stop", "AsButton": False, # 加入下拉菜单中 "Info": "解析一个前端项目的所有源文件(js,ts,css等) | 输入参数为路径", - "Function": HotReload(解析一个前端项目), + "Function": HotReload(解析一个前端项目) }, "解析整个Lua项目": { "Group": "编程", "Color": "stop", "AsButton": False, # 加入下拉菜单中 "Info": "解析一个Lua项目的所有源文件 | 输入参数为路径", - "Function": HotReload(解析一个Lua项目), + "Function": HotReload(解析一个Lua项目) }, "解析整个CSharp项目": { "Group": "编程", "Color": "stop", "AsButton": False, # 加入下拉菜单中 "Info": "解析一个CSharp项目的所有源文件 | 输入参数为路径", - "Function": HotReload(解析一个CSharp项目), + "Function": HotReload(解析一个CSharp项目) }, "解析Jupyter Notebook文件": { "Group": "编程", @@ -163,530 +147,384 @@ def get_crazy_functions(): "Color": "stop", "AsButton": False, "Info": "读取Tex论文并写摘要 | 输入参数为路径", - "Function": HotReload(读文章写摘要), + "Function": HotReload(读文章写摘要) }, "翻译README或MD": { "Group": "编程", "Color": "stop", "AsButton": True, "Info": "将Markdown翻译为中文 | 输入参数为路径或URL", - "Function": HotReload(Markdown英译中), + "Function": HotReload(Markdown英译中) }, "翻译Markdown或README(支持Github链接)": { "Group": "编程", "Color": "stop", "AsButton": False, "Info": "将Markdown或README翻译为中文 | 输入参数为路径或URL", - "Function": HotReload(Markdown英译中), + "Function": HotReload(Markdown英译中) }, "批量生成函数注释": { "Group": "编程", "Color": "stop", "AsButton": False, # 加入下拉菜单中 "Info": "批量生成函数的注释 | 输入参数为路径", - "Function": HotReload(批量生成函数注释), + "Function": HotReload(批量生成函数注释) }, "保存当前的对话": { "Group": "对话", "AsButton": True, "Info": "保存当前的对话 | 不需要输入参数", - "Function": HotReload(对话历史存档), + "Function": HotReload(对话历史存档) }, "[多线程Demo]解析此项目本身(源码自译解)": { "Group": "对话|编程", "AsButton": False, # 加入下拉菜单中 "Info": "多线程解析并翻译此项目的源码 | 不需要输入参数", - "Function": HotReload(解析项目本身), + "Function": HotReload(解析项目本身) }, - "历史上的今天": { + "[插件demo]历史上的今天": { "Group": "对话", "AsButton": True, - "Info": "查看历史上的今天事件 (这是一个面向开发者的插件Demo) | 不需要输入参数", - "Function": HotReload(高阶功能模板函数), + "Info": "查看历史上的今天事件 | 不需要输入参数", + "Function": HotReload(高阶功能模板函数) }, "精准翻译PDF论文": { "Group": "学术", "Color": "stop", - "AsButton": True, + "AsButton": True, "Info": "精准翻译PDF论文为中文 | 输入参数为路径", - "Function": HotReload(批量翻译PDF文档), + "Function": HotReload(批量翻译PDF文档) }, "询问多个GPT模型": { "Group": "对话", "Color": "stop", "AsButton": True, - "Function": HotReload(同时问询), + "Function": HotReload(同时问询) }, "批量总结PDF文档": { "Group": "学术", "Color": "stop", "AsButton": False, # 加入下拉菜单中 "Info": "批量总结PDF文档的内容 | 输入参数为路径", - "Function": HotReload(批量总结PDF文档), + "Function": HotReload(批量总结PDF文档) }, "谷歌学术检索助手(输入谷歌学术搜索页url)": { "Group": "学术", "Color": "stop", "AsButton": False, # 加入下拉菜单中 "Info": "使用谷歌学术检索助手搜索指定URL的结果 | 输入参数为谷歌学术搜索页的URL", - "Function": HotReload(谷歌检索小助手), + "Function": HotReload(谷歌检索小助手) }, "理解PDF文档内容 (模仿ChatPDF)": { "Group": "学术", "Color": "stop", "AsButton": False, # 加入下拉菜单中 "Info": "理解PDF文档的内容并进行回答 | 输入参数为路径", - "Function": HotReload(理解PDF文档内容标准文件输入), + "Function": HotReload(理解PDF文档内容标准文件输入) }, "英文Latex项目全文润色(输入路径或上传压缩包)": { "Group": "学术", "Color": "stop", "AsButton": False, # 加入下拉菜单中 "Info": "对英文Latex项目全文进行润色处理 | 输入参数为路径或上传压缩包", - "Function": HotReload(Latex英文润色), + "Function": HotReload(Latex英文润色) + }, + "英文Latex项目全文纠错(输入路径或上传压缩包)": { + "Group": "学术", + "Color": "stop", + "AsButton": False, # 加入下拉菜单中 + "Info": "对英文Latex项目全文进行纠错处理 | 输入参数为路径或上传压缩包", + "Function": HotReload(Latex英文纠错) }, - "中文Latex项目全文润色(输入路径或上传压缩包)": { "Group": "学术", "Color": "stop", "AsButton": False, # 加入下拉菜单中 "Info": "对中文Latex项目全文进行润色处理 | 输入参数为路径或上传压缩包", - "Function": HotReload(Latex中文润色), - }, - # 已经被新插件取代 - # "英文Latex项目全文纠错(输入路径或上传压缩包)": { - # "Group": "学术", - # "Color": "stop", - # "AsButton": False, # 加入下拉菜单中 - # "Info": "对英文Latex项目全文进行纠错处理 | 输入参数为路径或上传压缩包", - # "Function": HotReload(Latex英文纠错), - # }, - # 已经被新插件取代 - # "Latex项目全文中译英(输入路径或上传压缩包)": { - # "Group": "学术", - # "Color": "stop", - # "AsButton": False, # 加入下拉菜单中 - # "Info": "对Latex项目全文进行中译英处理 | 输入参数为路径或上传压缩包", - # "Function": HotReload(Latex中译英) - # }, - # 已经被新插件取代 - # "Latex项目全文英译中(输入路径或上传压缩包)": { - # "Group": "学术", - # "Color": "stop", - # "AsButton": False, # 加入下拉菜单中 - # "Info": "对Latex项目全文进行英译中处理 | 输入参数为路径或上传压缩包", - # "Function": HotReload(Latex英译中) - # }, + "Function": HotReload(Latex中文润色) + }, + "Latex项目全文中译英(输入路径或上传压缩包)": { + "Group": "学术", + "Color": "stop", + "AsButton": False, # 加入下拉菜单中 + "Info": "对Latex项目全文进行中译英处理 | 输入参数为路径或上传压缩包", + "Function": HotReload(Latex中译英) + }, + "Latex项目全文英译中(输入路径或上传压缩包)": { + "Group": "学术", + "Color": "stop", + "AsButton": False, # 加入下拉菜单中 + "Info": "对Latex项目全文进行英译中处理 | 输入参数为路径或上传压缩包", + "Function": HotReload(Latex英译中) + }, "批量Markdown中译英(输入路径或上传压缩包)": { "Group": "编程", "Color": "stop", "AsButton": False, # 加入下拉菜单中 "Info": "批量将Markdown文件中文翻译为英文 | 输入参数为路径或上传压缩包", - "Function": HotReload(Markdown中译英), + "Function": HotReload(Markdown中译英) }, } # -=--=- 尚未充分测试的实验性插件 & 需要额外依赖的插件 -=--=- try: from crazy_functions.下载arxiv论文翻译摘要 import 下载arxiv论文并翻译摘要 - - function_plugins.update( - { - "一键下载arxiv论文并翻译摘要(先在input输入编号,如1812.10695)": { - "Group": "学术", - "Color": "stop", - "AsButton": False, # 加入下拉菜单中 - # "Info": "下载arxiv论文并翻译摘要 | 输入参数为arxiv编号如1812.10695", - "Function": HotReload(下载arxiv论文并翻译摘要), - } + function_plugins.update({ + "一键下载arxiv论文并翻译摘要(先在input输入编号,如1812.10695)": { + "Group": "学术", + "Color": "stop", + "AsButton": False, # 加入下拉菜单中 + # "Info": "下载arxiv论文并翻译摘要 | 输入参数为arxiv编号如1812.10695", + "Function": HotReload(下载arxiv论文并翻译摘要) } - ) + }) except: - print(trimmed_format_exc()) - print("Load function plugin failed") + print('Load function plugin failed') try: from crazy_functions.联网的ChatGPT import 连接网络回答问题 - - function_plugins.update( - { - "连接网络回答问题(输入问题后点击该插件,需要访问谷歌)": { - "Group": "对话", - "Color": "stop", - "AsButton": False, # 加入下拉菜单中 - # "Info": "连接网络回答问题(需要访问谷歌)| 输入参数是一个问题", - "Function": HotReload(连接网络回答问题), - } + function_plugins.update({ + "连接网络回答问题(输入问题后点击该插件,需要访问谷歌)": { + "Group": "对话", + "Color": "stop", + "AsButton": False, # 加入下拉菜单中 + # "Info": "连接网络回答问题(需要访问谷歌)| 输入参数是一个问题", + "Function": HotReload(连接网络回答问题) } - ) + }) from crazy_functions.联网的ChatGPT_bing版 import 连接bing搜索回答问题 - - function_plugins.update( - { - "连接网络回答问题(中文Bing版,输入问题后点击该插件)": { - "Group": "对话", - "Color": "stop", - "AsButton": False, # 加入下拉菜单中 - "Info": "连接网络回答问题(需要访问中文Bing)| 输入参数是一个问题", - "Function": HotReload(连接bing搜索回答问题), - } + function_plugins.update({ + "连接网络回答问题(中文Bing版,输入问题后点击该插件)": { + "Group": "对话", + "Color": "stop", + "AsButton": False, # 加入下拉菜单中 + "Info": "连接网络回答问题(需要访问中文Bing)| 输入参数是一个问题", + "Function": HotReload(连接bing搜索回答问题) } - ) + }) except: - print(trimmed_format_exc()) - print("Load function plugin failed") + print('Load function plugin failed') try: from crazy_functions.解析项目源代码 import 解析任意code项目 - - function_plugins.update( - { - "解析项目源代码(手动指定和筛选源代码文件类型)": { - "Group": "编程", - "Color": "stop", - "AsButton": False, - "AdvancedArgs": True, # 调用时,唤起高级参数输入区(默认False) - "ArgsReminder": '输入时用逗号隔开, *代表通配符, 加了^代表不匹配; 不输入代表全部匹配。例如: "*.c, ^*.cpp, config.toml, ^*.toml"', # 高级参数输入区的显示提示 - "Function": HotReload(解析任意code项目), - }, - } - ) + function_plugins.update({ + "解析项目源代码(手动指定和筛选源代码文件类型)": { + "Group": "编程", + "Color": "stop", + "AsButton": False, + "AdvancedArgs": True, # 调用时,唤起高级参数输入区(默认False) + "ArgsReminder": "输入时用逗号隔开, *代表通配符, 加了^代表不匹配; 不输入代表全部匹配。例如: \"*.c, ^*.cpp, config.toml, ^*.toml\"", # 高级参数输入区的显示提示 + "Function": HotReload(解析任意code项目) + }, + }) except: - print(trimmed_format_exc()) - print("Load function plugin failed") + print('Load function plugin failed') try: from crazy_functions.询问多个大语言模型 import 同时问询_指定模型 - - function_plugins.update( - { - "询问多个GPT模型(手动指定询问哪些模型)": { - "Group": "对话", - "Color": "stop", - "AsButton": False, - "AdvancedArgs": True, # 调用时,唤起高级参数输入区(默认False) - "ArgsReminder": "支持任意数量的llm接口,用&符号分隔。例如chatglm&gpt-3.5-turbo&gpt-4", # 高级参数输入区的显示提示 - "Function": HotReload(同时问询_指定模型), - }, - } - ) + function_plugins.update({ + "询问多个GPT模型(手动指定询问哪些模型)": { + "Group": "对话", + "Color": "stop", + "AsButton": False, + "AdvancedArgs": True, # 调用时,唤起高级参数输入区(默认False) + "ArgsReminder": "支持任意数量的llm接口,用&符号分隔。例如chatglm&gpt-3.5-turbo&api2d-gpt-4", # 高级参数输入区的显示提示 + "Function": HotReload(同时问询_指定模型) + }, + }) except: - print(trimmed_format_exc()) - print("Load function plugin failed") + print('Load function plugin failed') try: - from crazy_functions.图片生成 import 图片生成_DALLE2, 图片生成_DALLE3, 图片修改_DALLE2 - - function_plugins.update( - { - "图片生成_DALLE2 (先切换模型到gpt-*)": { - "Group": "对话", - "Color": "stop", - "AsButton": False, - "AdvancedArgs": True, # 调用时,唤起高级参数输入区(默认False) - "ArgsReminder": "在这里输入分辨率, 如1024x1024(默认),支持 256x256, 512x512, 1024x1024", # 高级参数输入区的显示提示 - "Info": "使用DALLE2生成图片 | 输入参数字符串,提供图像的内容", - "Function": HotReload(图片生成_DALLE2), - }, - } - ) - function_plugins.update( - { - "图片生成_DALLE3 (先切换模型到gpt-*)": { - "Group": "对话", - "Color": "stop", - "AsButton": False, - "AdvancedArgs": True, # 调用时,唤起高级参数输入区(默认False) - "ArgsReminder": "在这里输入自定义参数「分辨率-质量(可选)-风格(可选)」, 参数示例「1024x1024-hd-vivid」 || 分辨率支持 「1024x1024」(默认) /「1792x1024」/「1024x1792」 || 质量支持 「-standard」(默认) /「-hd」 || 风格支持 「-vivid」(默认) /「-natural」", # 高级参数输入区的显示提示 - "Info": "使用DALLE3生成图片 | 输入参数字符串,提供图像的内容", - "Function": HotReload(图片生成_DALLE3), - }, - } - ) - function_plugins.update( - { - "图片修改_DALLE2 (先切换模型到gpt-*)": { - "Group": "对话", - "Color": "stop", - "AsButton": False, - "AdvancedArgs": False, # 调用时,唤起高级参数输入区(默认False) - # "Info": "使用DALLE2修改图片 | 输入参数字符串,提供图像的内容", - "Function": HotReload(图片修改_DALLE2), - }, - } - ) + from crazy_functions.图片生成 import 图片生成 + function_plugins.update({ + "图片生成(先切换模型到openai或api2d)": { + "Group": "对话", + "Color": "stop", + "AsButton": False, + "AdvancedArgs": True, # 调用时,唤起高级参数输入区(默认False) + "ArgsReminder": "在这里输入分辨率, 如256x256(默认)", # 高级参数输入区的显示提示 + "Info": "图片生成 | 输入参数字符串,提供图像的内容", + "Function": HotReload(图片生成) + }, + }) except: - print(trimmed_format_exc()) - print("Load function plugin failed") + print('Load function plugin failed') try: from crazy_functions.总结音视频 import 总结音视频 - - function_plugins.update( - { - "批量总结音视频(输入路径或上传压缩包)": { - "Group": "对话", - "Color": "stop", - "AsButton": False, - "AdvancedArgs": True, - "ArgsReminder": "调用openai api 使用whisper-1模型, 目前支持的格式:mp4, m4a, wav, mpga, mpeg, mp3。此处可以输入解析提示,例如:解析为简体中文(默认)。", - "Info": "批量总结音频或视频 | 输入参数为路径", - "Function": HotReload(总结音视频), - } + function_plugins.update({ + "批量总结音视频(输入路径或上传压缩包)": { + "Group": "对话", + "Color": "stop", + "AsButton": False, + "AdvancedArgs": True, + "ArgsReminder": "调用openai api 使用whisper-1模型, 目前支持的格式:mp4, m4a, wav, mpga, mpeg, mp3。此处可以输入解析提示,例如:解析为简体中文(默认)。", + "Info": "批量总结音频或视频 | 输入参数为路径", + "Function": HotReload(总结音视频) } - ) + }) except: - print(trimmed_format_exc()) - print("Load function plugin failed") + print('Load function plugin failed') try: from crazy_functions.数学动画生成manim import 动画生成 - - function_plugins.update( - { - "数学动画生成(Manim)": { - "Group": "对话", - "Color": "stop", - "AsButton": False, - "Info": "按照自然语言描述生成一个动画 | 输入参数是一段话", - "Function": HotReload(动画生成), - } + function_plugins.update({ + "数学动画生成(Manim)": { + "Group": "对话", + "Color": "stop", + "AsButton": False, + "Info": "按照自然语言描述生成一个动画 | 输入参数是一段话", + "Function": HotReload(动画生成) } - ) + }) except: - print(trimmed_format_exc()) - print("Load function plugin failed") + print('Load function plugin failed') try: from crazy_functions.批量Markdown翻译 import Markdown翻译指定语言 - - function_plugins.update( - { - "Markdown翻译(指定翻译成何种语言)": { - "Group": "编程", - "Color": "stop", - "AsButton": False, - "AdvancedArgs": True, - "ArgsReminder": "请输入要翻译成哪种语言,默认为Chinese。", - "Function": HotReload(Markdown翻译指定语言), - } + function_plugins.update({ + "Markdown翻译(手动指定语言)": { + "Group": "编程", + "Color": "stop", + "AsButton": False, + "AdvancedArgs": True, + "ArgsReminder": "请输入要翻译成哪种语言,默认为Chinese。", + "Function": HotReload(Markdown翻译指定语言) } - ) + }) except: - print(trimmed_format_exc()) - print("Load function plugin failed") + print('Load function plugin failed') try: - from crazy_functions.知识库问答 import 知识库文件注入 - - function_plugins.update( - { - "构建知识库(先上传文件素材,再运行此插件)": { - "Group": "对话", - "Color": "stop", - "AsButton": False, - "AdvancedArgs": True, - "ArgsReminder": "此处待注入的知识库名称id, 默认为default。文件进入知识库后可长期保存。可以通过再次调用本插件的方式,向知识库追加更多文档。", - "Function": HotReload(知识库文件注入), - } + from crazy_functions.Langchain知识库 import 知识库问答 + function_plugins.update({ + "构建知识库(先上传文件素材,再运行此插件)": { + "Group": "对话", + "Color": "stop", + "AsButton": False, + "AdvancedArgs": True, + "ArgsReminder": "此处待注入的知识库名称id, 默认为default。文件进入知识库后可长期保存。可以通过再次调用本插件的方式,向知识库追加更多文档。", + "Function": HotReload(知识库问答) } - ) + }) except: - print(trimmed_format_exc()) - print("Load function plugin failed") + print('Load function plugin failed') try: - from crazy_functions.知识库问答 import 读取知识库作答 - - function_plugins.update( - { - "知识库文件注入(构建知识库后,再运行此插件)": { - "Group": "对话", - "Color": "stop", - "AsButton": False, - "AdvancedArgs": True, - "ArgsReminder": "待提取的知识库名称id, 默认为default, 您需要构建知识库后再运行此插件。", - "Function": HotReload(读取知识库作答), - } + from crazy_functions.Langchain知识库 import 读取知识库作答 + function_plugins.update({ + "知识库问答(构建知识库后,再运行此插件)": { + "Group": "对话", + "Color": "stop", + "AsButton": False, + "AdvancedArgs": True, + "ArgsReminder": "待提取的知识库名称id, 默认为default, 您需要构建知识库后再运行此插件。", + "Function": HotReload(读取知识库作答) } - ) + }) except: - print(trimmed_format_exc()) - print("Load function plugin failed") + print('Load function plugin failed') try: from crazy_functions.交互功能函数模板 import 交互功能模板函数 - - function_plugins.update( - { - "交互功能模板Demo函数(查找wallhaven.cc的壁纸)": { - "Group": "对话", - "Color": "stop", - "AsButton": False, - "Function": HotReload(交互功能模板函数), - } + function_plugins.update({ + "交互功能模板函数": { + "Group": "对话", + "Color": "stop", + "AsButton": False, + "Function": HotReload(交互功能模板函数) } - ) + }) except: - print(trimmed_format_exc()) - print("Load function plugin failed") + print('Load function plugin failed') try: - from crazy_functions.Latex输出PDF import Latex英文纠错加PDF对比 - from crazy_functions.Latex输出PDF import Latex翻译中文并重新编译PDF - from crazy_functions.Latex输出PDF import PDF翻译中文并重新编译PDF - - function_plugins.update( - { - "Latex英文纠错+高亮修正位置 [需Latex]": { - "Group": "学术", - "Color": "stop", - "AsButton": False, - "AdvancedArgs": True, - "ArgsReminder": "如果有必要, 请在此处追加更细致的矫错指令(使用英文)。", - "Function": HotReload(Latex英文纠错加PDF对比), - }, - "Arxiv论文精细翻译(输入arxivID)[需Latex]": { - "Group": "学术", - "Color": "stop", - "AsButton": False, - "AdvancedArgs": True, - "ArgsReminder": r"如果有必要, 请在此处给出自定义翻译命令, 解决部分词汇翻译不准确的问题。 " - r"例如当单词'agent'翻译不准确时, 请尝试把以下指令复制到高级参数区: " - r'If the term "agent" is used in this section, it should be translated to "智能体". ', - "Info": "Arixv论文精细翻译 | 输入参数arxiv论文的ID,比如1812.10695", - "Function": HotReload(Latex翻译中文并重新编译PDF), - }, - "本地Latex论文精细翻译(上传Latex项目)[需Latex]": { - "Group": "学术", - "Color": "stop", - "AsButton": False, - "AdvancedArgs": True, - "ArgsReminder": r"如果有必要, 请在此处给出自定义翻译命令, 解决部分词汇翻译不准确的问题。 " - r"例如当单词'agent'翻译不准确时, 请尝试把以下指令复制到高级参数区: " - r'If the term "agent" is used in this section, it should be translated to "智能体". ', - "Info": "本地Latex论文精细翻译 | 输入参数是路径", - "Function": HotReload(Latex翻译中文并重新编译PDF), - }, - "PDF翻译中文并重新编译PDF(上传PDF)[需Latex]": { - "Group": "学术", - "Color": "stop", - "AsButton": False, - "AdvancedArgs": True, - "ArgsReminder": r"如果有必要, 请在此处给出自定义翻译命令, 解决部分词汇翻译不准确的问题。 " - r"例如当单词'agent'翻译不准确时, 请尝试把以下指令复制到高级参数区: " - r'If the term "agent" is used in this section, it should be translated to "智能体". ', - "Info": "PDF翻译中文,并重新编译PDF | 输入参数为路径", - "Function": HotReload(PDF翻译中文并重新编译PDF) - } + from crazy_functions.Latex输出PDF结果 import Latex英文纠错加PDF对比 + function_plugins.update({ + "Latex英文纠错+高亮修正位置 [需Latex]": { + "Group": "学术", + "Color": "stop", + "AsButton": False, + "AdvancedArgs": True, + "ArgsReminder": "如果有必要, 请在此处追加更细致的矫错指令(使用英文)。", + "Function": HotReload(Latex英文纠错加PDF对比) + } + }) + from crazy_functions.Latex输出PDF结果 import Latex翻译中文并重新编译PDF + function_plugins.update({ + "Arixv论文精细翻译(输入arxivID)[需Latex]": { + "Group": "学术", + "Color": "stop", + "AsButton": False, + "AdvancedArgs": True, + "ArgsReminder": + "如果有必要, 请在此处给出自定义翻译命令, 解决部分词汇翻译不准确的问题。 " + + "例如当单词'agent'翻译不准确时, 请尝试把以下指令复制到高级参数区: " + + 'If the term "agent" is used in this section, it should be translated to "智能体". ', + "Info": "Arixv论文精细翻译 | 输入参数arxiv论文的ID,比如1812.10695", + "Function": HotReload(Latex翻译中文并重新编译PDF) } - ) + }) + function_plugins.update({ + "本地Latex论文精细翻译(上传Latex项目)[需Latex]": { + "Group": "学术", + "Color": "stop", + "AsButton": False, + "AdvancedArgs": True, + "ArgsReminder": + "如果有必要, 请在此处给出自定义翻译命令, 解决部分词汇翻译不准确的问题。 " + + "例如当单词'agent'翻译不准确时, 请尝试把以下指令复制到高级参数区: " + + 'If the term "agent" is used in this section, it should be translated to "智能体". ', + "Info": "本地Latex论文精细翻译 | 输入参数是路径", + "Function": HotReload(Latex翻译中文并重新编译PDF) + } + }) except: - print(trimmed_format_exc()) - print("Load function plugin failed") + print('Load function plugin failed') try: from toolbox import get_conf - - ENABLE_AUDIO = get_conf("ENABLE_AUDIO") + ENABLE_AUDIO, = get_conf('ENABLE_AUDIO') if ENABLE_AUDIO: from crazy_functions.语音助手 import 语音助手 - - function_plugins.update( - { - "实时语音对话": { - "Group": "对话", - "Color": "stop", - "AsButton": True, - "Info": "这是一个时刻聆听着的语音对话助手 | 没有输入参数", - "Function": HotReload(语音助手), - } - } - ) - except: - print(trimmed_format_exc()) - print("Load function plugin failed") - - try: - from crazy_functions.批量翻译PDF文档_NOUGAT import 批量翻译PDF文档 - - function_plugins.update( - { - "精准翻译PDF文档(NOUGAT)": { - "Group": "学术", - "Color": "stop", - "AsButton": False, - "Function": HotReload(批量翻译PDF文档), - } - } - ) - except: - print(trimmed_format_exc()) - print("Load function plugin failed") - - try: - from crazy_functions.函数动态生成 import 函数动态生成 - - function_plugins.update( - { - "动态代码解释器(CodeInterpreter)": { - "Group": "智能体", + function_plugins.update({ + "实时音频采集": { + "Group": "对话", "Color": "stop", - "AsButton": False, - "Function": HotReload(函数动态生成), + "AsButton": True, + "Info": "开始语言对话 | 没有输入参数", + "Function": HotReload(语音助手) } - } - ) + }) except: - print(trimmed_format_exc()) - print("Load function plugin failed") + print('Load function plugin failed') try: - from crazy_functions.多智能体 import 多智能体终端 - - function_plugins.update( - { - "AutoGen多智能体终端(仅供测试)": { - "Group": "智能体", - "Color": "stop", - "AsButton": False, - "Function": HotReload(多智能体终端), - } + from crazy_functions.批量翻译PDF文档_NOUGAT import 批量翻译PDF文档 + function_plugins.update({ + "精准翻译PDF文档(NOUGAT)": { + "Group": "学术", + "Color": "stop", + "AsButton": False, + "Function": HotReload(批量翻译PDF文档) } - ) + }) except: - print(trimmed_format_exc()) - print("Load function plugin failed") - - try: - from crazy_functions.互动小游戏 import 随机小游戏 + print('Load function plugin failed') - function_plugins.update( - { - "随机互动小游戏(仅供测试)": { - "Group": "智能体", - "Color": "stop", - "AsButton": False, - "Function": HotReload(随机小游戏), - } - } - ) - except: - print(trimmed_format_exc()) - print("Load function plugin failed") # try: - # from crazy_functions.高级功能函数模板 import 测试图表渲染 + # from crazy_functions.CodeInterpreter import 虚空终端CodeInterpreter # function_plugins.update({ - # "绘制逻辑关系(测试图表渲染)": { - # "Group": "智能体", + # "CodeInterpreter(开发中,仅供测试)": { + # "Group": "编程|对话", # "Color": "stop", - # "AsButton": True, - # "Function": HotReload(测试图表渲染) + # "AsButton": False, + # "Function": HotReload(虚空终端CodeInterpreter) # } # }) # except: - # print(trimmed_format_exc()) # print('Load function plugin failed') # try: @@ -703,6 +541,8 @@ def get_crazy_functions(): # except: # print('Load function plugin failed') + + """ 设置默认值: - 默认 Group = 对话 @@ -712,12 +552,12 @@ def get_crazy_functions(): """ for name, function_meta in function_plugins.items(): if "Group" not in function_meta: - function_plugins[name]["Group"] = "对话" + function_plugins[name]["Group"] = '对话' if "AsButton" not in function_meta: function_plugins[name]["AsButton"] = True if "AdvancedArgs" not in function_meta: function_plugins[name]["AdvancedArgs"] = False if "Color" not in function_meta: - function_plugins[name]["Color"] = "secondary" + function_plugins[name]["Color"] = 'secondary' return function_plugins diff --git "a/crazy_functions/Langchain\347\237\245\350\257\206\345\272\223.py" "b/crazy_functions/Langchain\347\237\245\350\257\206\345\272\223.py" index 8433895f538e826e4294b7d6503583aafc2b34c8..741a3d068472a1fc20629053e6e49fff278473f0 100644 --- "a/crazy_functions/Langchain\347\237\245\350\257\206\345\272\223.py" +++ "b/crazy_functions/Langchain\347\237\245\350\257\206\345\272\223.py" @@ -53,14 +53,14 @@ def 知识库问答(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_pro yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 print('Checking Text2vec ...') from langchain.embeddings.huggingface import HuggingFaceEmbeddings - with ProxyNetworkActivate('Download_LLM'): # 临时地激活代理网络 + with ProxyNetworkActivate(): # 临时地激活代理网络 HuggingFaceEmbeddings(model_name="GanymedeNil/text2vec-large-chinese") # < -------------------构建知识库--------------- > chatbot.append(['
'.join(file_manifest), "正在构建知识库..."]) yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 print('Establishing knowledge archive ...') - with ProxyNetworkActivate('Download_LLM'): # 临时地激活代理网络 + with ProxyNetworkActivate(): # 临时地激活代理网络 kai = knowledge_archive_interface() kai.feed_archive(file_manifest=file_manifest, id=kai_id) kai_files = kai.get_loaded_file() diff --git "a/crazy_functions/Latex\345\205\250\346\226\207\346\266\246\350\211\262.py" "b/crazy_functions/Latex\345\205\250\346\226\207\346\266\246\350\211\262.py" index 3bd0613d4dcf7fd8b535e6a857b14130f85b2df9..462f965758a49cb7283faa0e78e074135fdfbfe2 100644 --- "a/crazy_functions/Latex\345\205\250\346\226\207\346\266\246\350\211\262.py" +++ "b/crazy_functions/Latex\345\205\250\346\226\207\346\266\246\350\211\262.py" @@ -1,5 +1,5 @@ from toolbox import update_ui, trimmed_format_exc, promote_file_to_downloadzone, get_log_folder -from toolbox import CatchException, report_exception, write_history_to_file, zip_folder +from toolbox import CatchException, report_execption, write_history_to_file, zip_folder class PaperFileGroup(): @@ -11,7 +11,7 @@ class PaperFileGroup(): self.sp_file_tag = [] # count_token - from request_llms.bridge_all import model_info + from request_llm.bridge_all import model_info enc = model_info["gpt-3.5-turbo"]['tokenizer'] def get_token_num(txt): return len(enc.encode(txt, disallowed_special=())) self.get_token_num = get_token_num @@ -26,8 +26,8 @@ class PaperFileGroup(): self.sp_file_index.append(index) self.sp_file_tag.append(self.file_paths[index]) else: - from crazy_functions.pdf_fns.breakdown_txt import breakdown_text_to_satisfy_token_limit - segments = breakdown_text_to_satisfy_token_limit(file_content, max_token_limit) + from .crazy_utils import breakdown_txt_to_satisfy_token_limit_for_pdf + segments = breakdown_txt_to_satisfy_token_limit_for_pdf(file_content, self.get_token_num, max_token_limit) for j, segment in enumerate(segments): self.sp_file_contents.append(segment) self.sp_file_index.append(index) @@ -135,18 +135,18 @@ def 多文件润色(file_manifest, project_folder, llm_kwargs, plugin_kwargs, ch @CatchException -def Latex英文润色(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request): +def Latex英文润色(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port): # 基本信息:功能、贡献者 chatbot.append([ "函数插件功能?", - "对整个Latex项目进行润色。函数插件贡献者: Binary-Husky。(注意,此插件不调用Latex,如果有Latex环境,请使用「Latex英文纠错+高亮修正位置(需Latex)插件」"]) + "对整个Latex项目进行润色。函数插件贡献者: Binary-Husky。(注意,此插件不调用Latex,如果有Latex环境,请使用“Latex英文纠错+高亮”插件)"]) yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 # 尝试导入依赖,如果缺少依赖,则给出安装建议 try: import tiktoken except: - report_exception(chatbot, history, + report_execption(chatbot, history, a=f"解析项目: {txt}", b=f"导入软件依赖失败。使用该模块需要额外依赖,安装方法```pip install --upgrade tiktoken```。") yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 @@ -157,12 +157,12 @@ def Latex英文润色(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_p project_folder = txt else: if txt == "": txt = '空空如也的输入栏' - report_exception(chatbot, history, a = f"解析项目: {txt}", b = f"找不到本地项目或无权访问: {txt}") + report_execption(chatbot, history, a = f"解析项目: {txt}", b = f"找不到本地项目或无权访问: {txt}") yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 return file_manifest = [f for f in glob.glob(f'{project_folder}/**/*.tex', recursive=True)] if len(file_manifest) == 0: - report_exception(chatbot, history, a = f"解析项目: {txt}", b = f"找不到任何.tex文件: {txt}") + report_execption(chatbot, history, a = f"解析项目: {txt}", b = f"找不到任何.tex文件: {txt}") yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 return yield from 多文件润色(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, language='en') @@ -173,7 +173,7 @@ def Latex英文润色(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_p @CatchException -def Latex中文润色(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request): +def Latex中文润色(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port): # 基本信息:功能、贡献者 chatbot.append([ "函数插件功能?", @@ -184,7 +184,7 @@ def Latex中文润色(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_p try: import tiktoken except: - report_exception(chatbot, history, + report_execption(chatbot, history, a=f"解析项目: {txt}", b=f"导入软件依赖失败。使用该模块需要额外依赖,安装方法```pip install --upgrade tiktoken```。") yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 @@ -195,12 +195,12 @@ def Latex中文润色(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_p project_folder = txt else: if txt == "": txt = '空空如也的输入栏' - report_exception(chatbot, history, a = f"解析项目: {txt}", b = f"找不到本地项目或无权访问: {txt}") + report_execption(chatbot, history, a = f"解析项目: {txt}", b = f"找不到本地项目或无权访问: {txt}") yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 return file_manifest = [f for f in glob.glob(f'{project_folder}/**/*.tex', recursive=True)] if len(file_manifest) == 0: - report_exception(chatbot, history, a = f"解析项目: {txt}", b = f"找不到任何.tex文件: {txt}") + report_execption(chatbot, history, a = f"解析项目: {txt}", b = f"找不到任何.tex文件: {txt}") yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 return yield from 多文件润色(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, language='zh') @@ -209,7 +209,7 @@ def Latex中文润色(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_p @CatchException -def Latex英文纠错(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request): +def Latex英文纠错(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port): # 基本信息:功能、贡献者 chatbot.append([ "函数插件功能?", @@ -220,7 +220,7 @@ def Latex英文纠错(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_p try: import tiktoken except: - report_exception(chatbot, history, + report_execption(chatbot, history, a=f"解析项目: {txt}", b=f"导入软件依赖失败。使用该模块需要额外依赖,安装方法```pip install --upgrade tiktoken```。") yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 @@ -231,12 +231,12 @@ def Latex英文纠错(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_p project_folder = txt else: if txt == "": txt = '空空如也的输入栏' - report_exception(chatbot, history, a = f"解析项目: {txt}", b = f"找不到本地项目或无权访问: {txt}") + report_execption(chatbot, history, a = f"解析项目: {txt}", b = f"找不到本地项目或无权访问: {txt}") yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 return file_manifest = [f for f in glob.glob(f'{project_folder}/**/*.tex', recursive=True)] if len(file_manifest) == 0: - report_exception(chatbot, history, a = f"解析项目: {txt}", b = f"找不到任何.tex文件: {txt}") + report_execption(chatbot, history, a = f"解析项目: {txt}", b = f"找不到任何.tex文件: {txt}") yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 return yield from 多文件润色(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, language='en', mode='proofread') diff --git "a/crazy_functions/Latex\345\205\250\346\226\207\347\277\273\350\257\221.py" "b/crazy_functions/Latex\345\205\250\346\226\207\347\277\273\350\257\221.py" index d6c3b5edc30085397548128f9de0b55f22d593e2..b5aad71bf9e46dd251cd6b8d19161b8eb6a3222a 100644 --- "a/crazy_functions/Latex\345\205\250\346\226\207\347\277\273\350\257\221.py" +++ "b/crazy_functions/Latex\345\205\250\346\226\207\347\277\273\350\257\221.py" @@ -1,5 +1,5 @@ from toolbox import update_ui, promote_file_to_downloadzone -from toolbox import CatchException, report_exception, write_history_to_file +from toolbox import CatchException, report_execption, write_history_to_file fast_debug = False class PaperFileGroup(): @@ -11,7 +11,7 @@ class PaperFileGroup(): self.sp_file_tag = [] # count_token - from request_llms.bridge_all import model_info + from request_llm.bridge_all import model_info enc = model_info["gpt-3.5-turbo"]['tokenizer'] def get_token_num(txt): return len(enc.encode(txt, disallowed_special=())) self.get_token_num = get_token_num @@ -26,8 +26,8 @@ class PaperFileGroup(): self.sp_file_index.append(index) self.sp_file_tag.append(self.file_paths[index]) else: - from crazy_functions.pdf_fns.breakdown_txt import breakdown_text_to_satisfy_token_limit - segments = breakdown_text_to_satisfy_token_limit(file_content, max_token_limit) + from .crazy_utils import breakdown_txt_to_satisfy_token_limit_for_pdf + segments = breakdown_txt_to_satisfy_token_limit_for_pdf(file_content, self.get_token_num, max_token_limit) for j, segment in enumerate(segments): self.sp_file_contents.append(segment) self.sp_file_index.append(index) @@ -106,7 +106,7 @@ def 多文件翻译(file_manifest, project_folder, llm_kwargs, plugin_kwargs, ch @CatchException -def Latex英译中(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request): +def Latex英译中(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port): # 基本信息:功能、贡献者 chatbot.append([ "函数插件功能?", @@ -117,7 +117,7 @@ def Latex英译中(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prom try: import tiktoken except: - report_exception(chatbot, history, + report_execption(chatbot, history, a=f"解析项目: {txt}", b=f"导入软件依赖失败。使用该模块需要额外依赖,安装方法```pip install --upgrade tiktoken```。") yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 @@ -128,12 +128,12 @@ def Latex英译中(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prom project_folder = txt else: if txt == "": txt = '空空如也的输入栏' - report_exception(chatbot, history, a = f"解析项目: {txt}", b = f"找不到本地项目或无权访问: {txt}") + report_execption(chatbot, history, a = f"解析项目: {txt}", b = f"找不到本地项目或无权访问: {txt}") yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 return file_manifest = [f for f in glob.glob(f'{project_folder}/**/*.tex', recursive=True)] if len(file_manifest) == 0: - report_exception(chatbot, history, a = f"解析项目: {txt}", b = f"找不到任何.tex文件: {txt}") + report_execption(chatbot, history, a = f"解析项目: {txt}", b = f"找不到任何.tex文件: {txt}") yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 return yield from 多文件翻译(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, language='en->zh') @@ -143,7 +143,7 @@ def Latex英译中(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prom @CatchException -def Latex中译英(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request): +def Latex中译英(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port): # 基本信息:功能、贡献者 chatbot.append([ "函数插件功能?", @@ -154,7 +154,7 @@ def Latex中译英(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prom try: import tiktoken except: - report_exception(chatbot, history, + report_execption(chatbot, history, a=f"解析项目: {txt}", b=f"导入软件依赖失败。使用该模块需要额外依赖,安装方法```pip install --upgrade tiktoken```。") yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 @@ -165,12 +165,12 @@ def Latex中译英(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prom project_folder = txt else: if txt == "": txt = '空空如也的输入栏' - report_exception(chatbot, history, a = f"解析项目: {txt}", b = f"找不到本地项目或无权访问: {txt}") + report_execption(chatbot, history, a = f"解析项目: {txt}", b = f"找不到本地项目或无权访问: {txt}") yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 return file_manifest = [f for f in glob.glob(f'{project_folder}/**/*.tex', recursive=True)] if len(file_manifest) == 0: - report_exception(chatbot, history, a = f"解析项目: {txt}", b = f"找不到任何.tex文件: {txt}") + report_execption(chatbot, history, a = f"解析项目: {txt}", b = f"找不到任何.tex文件: {txt}") yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 return yield from 多文件翻译(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, language='zh->en') \ No newline at end of file diff --git "a/crazy_functions/Latex\350\276\223\345\207\272PDF.py" "b/crazy_functions/Latex\350\276\223\345\207\272PDF.py" deleted file mode 100644 index fc878f9ff078bd92e48033e981159aa17a02cf2a..0000000000000000000000000000000000000000 --- "a/crazy_functions/Latex\350\276\223\345\207\272PDF.py" +++ /dev/null @@ -1,484 +0,0 @@ -from toolbox import update_ui, trimmed_format_exc, get_conf, get_log_folder, promote_file_to_downloadzone -from toolbox import CatchException, report_exception, update_ui_lastest_msg, zip_result, gen_time_str -from functools import partial -import glob, os, requests, time, json, tarfile - -pj = os.path.join -ARXIV_CACHE_DIR = os.path.expanduser(f"~/arxiv_cache/") - - -# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 工具函数 =-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -# 专业词汇声明 = 'If the term "agent" is used in this section, it should be translated to "智能体". ' -def switch_prompt(pfg, mode, more_requirement): - """ - Generate prompts and system prompts based on the mode for proofreading or translating. - Args: - - pfg: Proofreader or Translator instance. - - mode: A string specifying the mode, either 'proofread' or 'translate_zh'. - - Returns: - - inputs_array: A list of strings containing prompts for users to respond to. - - sys_prompt_array: A list of strings containing prompts for system prompts. - """ - n_split = len(pfg.sp_file_contents) - if mode == 'proofread_en': - inputs_array = [r"Below is a section from an academic paper, proofread this section." + - r"Do not modify any latex command such as \section, \cite, \begin, \item and equations. " + more_requirement + - r"Answer me only with the revised text:" + - f"\n\n{frag}" for frag in pfg.sp_file_contents] - sys_prompt_array = ["You are a professional academic paper writer." for _ in range(n_split)] - elif mode == 'translate_zh': - inputs_array = [ - r"Below is a section from an English academic paper, translate it into Chinese. " + more_requirement + - r"Do not modify any latex command such as \section, \cite, \begin, \item and equations. " + - r"Answer me only with the translated text:" + - f"\n\n{frag}" for frag in pfg.sp_file_contents] - sys_prompt_array = ["You are a professional translator." for _ in range(n_split)] - else: - assert False, "未知指令" - return inputs_array, sys_prompt_array - - -def desend_to_extracted_folder_if_exist(project_folder): - """ - Descend into the extracted folder if it exists, otherwise return the original folder. - - Args: - - project_folder: A string specifying the folder path. - - Returns: - - A string specifying the path to the extracted folder, or the original folder if there is no extracted folder. - """ - maybe_dir = [f for f in glob.glob(f'{project_folder}/*') if os.path.isdir(f)] - if len(maybe_dir) == 0: return project_folder - if maybe_dir[0].endswith('.extract'): return maybe_dir[0] - return project_folder - - -def move_project(project_folder, arxiv_id=None): - """ - Create a new work folder and copy the project folder to it. - - Args: - - project_folder: A string specifying the folder path of the project. - - Returns: - - A string specifying the path to the new work folder. - """ - import shutil, time - time.sleep(2) # avoid time string conflict - if arxiv_id is not None: - new_workfolder = pj(ARXIV_CACHE_DIR, arxiv_id, 'workfolder') - else: - new_workfolder = f'{get_log_folder()}/{gen_time_str()}' - try: - shutil.rmtree(new_workfolder) - except: - pass - - # align subfolder if there is a folder wrapper - items = glob.glob(pj(project_folder, '*')) - items = [item for item in items if os.path.basename(item) != '__MACOSX'] - if len(glob.glob(pj(project_folder, '*.tex'))) == 0 and len(items) == 1: - if os.path.isdir(items[0]): project_folder = items[0] - - shutil.copytree(src=project_folder, dst=new_workfolder) - return new_workfolder - - -def arxiv_download(chatbot, history, txt, allow_cache=True): - def check_cached_translation_pdf(arxiv_id): - translation_dir = pj(ARXIV_CACHE_DIR, arxiv_id, 'translation') - if not os.path.exists(translation_dir): - os.makedirs(translation_dir) - target_file = pj(translation_dir, 'translate_zh.pdf') - if os.path.exists(target_file): - promote_file_to_downloadzone(target_file, rename_file=None, chatbot=chatbot) - target_file_compare = pj(translation_dir, 'comparison.pdf') - if os.path.exists(target_file_compare): - promote_file_to_downloadzone(target_file_compare, rename_file=None, chatbot=chatbot) - return target_file - return False - - def is_float(s): - try: - float(s) - return True - except ValueError: - return False - - if ('.' in txt) and ('/' not in txt) and is_float(txt): # is arxiv ID - txt = 'https://arxiv.org/abs/' + txt.strip() - if ('.' in txt) and ('/' not in txt) and is_float(txt[:10]): # is arxiv ID - txt = 'https://arxiv.org/abs/' + txt[:10] - - if not txt.startswith('https://arxiv.org'): - return txt, None # 是本地文件,跳过下载 - - # <-------------- inspect format -------------> - chatbot.append([f"检测到arxiv文档连接", '尝试下载 ...']) - yield from update_ui(chatbot=chatbot, history=history) - time.sleep(1) # 刷新界面 - - url_ = txt # https://arxiv.org/abs/1707.06690 - if not txt.startswith('https://arxiv.org/abs/'): - msg = f"解析arxiv网址失败, 期望格式例如: https://arxiv.org/abs/1707.06690。实际得到格式: {url_}。" - yield from update_ui_lastest_msg(msg, chatbot=chatbot, history=history) # 刷新界面 - return msg, None - # <-------------- set format -------------> - arxiv_id = url_.split('/abs/')[-1] - if 'v' in arxiv_id: arxiv_id = arxiv_id[:10] - cached_translation_pdf = check_cached_translation_pdf(arxiv_id) - if cached_translation_pdf and allow_cache: return cached_translation_pdf, arxiv_id - - url_tar = url_.replace('/abs/', '/e-print/') - translation_dir = pj(ARXIV_CACHE_DIR, arxiv_id, 'e-print') - extract_dst = pj(ARXIV_CACHE_DIR, arxiv_id, 'extract') - os.makedirs(translation_dir, exist_ok=True) - - # <-------------- download arxiv source file -------------> - dst = pj(translation_dir, arxiv_id + '.tar') - if os.path.exists(dst): - yield from update_ui_lastest_msg("调用缓存", chatbot=chatbot, history=history) # 刷新界面 - else: - yield from update_ui_lastest_msg("开始下载", chatbot=chatbot, history=history) # 刷新界面 - proxies = get_conf('proxies') - r = requests.get(url_tar, proxies=proxies) - with open(dst, 'wb+') as f: - f.write(r.content) - # <-------------- extract file -------------> - yield from update_ui_lastest_msg("下载完成", chatbot=chatbot, history=history) # 刷新界面 - from toolbox import extract_archive - extract_archive(file_path=dst, dest_dir=extract_dst) - return extract_dst, arxiv_id - - -def pdf2tex_project(pdf_file_path): - # Mathpix API credentials - app_id, app_key = get_conf('MATHPIX_APPID', 'MATHPIX_APPKEY') - headers = {"app_id": app_id, "app_key": app_key} - - # Step 1: Send PDF file for processing - options = { - "conversion_formats": {"tex.zip": True}, - "math_inline_delimiters": ["$", "$"], - "rm_spaces": True - } - - response = requests.post(url="https://api.mathpix.com/v3/pdf", - headers=headers, - data={"options_json": json.dumps(options)}, - files={"file": open(pdf_file_path, "rb")}) - - if response.ok: - pdf_id = response.json()["pdf_id"] - print(f"PDF processing initiated. PDF ID: {pdf_id}") - - # Step 2: Check processing status - while True: - conversion_response = requests.get(f"https://api.mathpix.com/v3/pdf/{pdf_id}", headers=headers) - conversion_data = conversion_response.json() - - if conversion_data["status"] == "completed": - print("PDF processing completed.") - break - elif conversion_data["status"] == "error": - print("Error occurred during processing.") - else: - print(f"Processing status: {conversion_data['status']}") - time.sleep(5) # wait for a few seconds before checking again - - # Step 3: Save results to local files - output_dir = os.path.join(os.path.dirname(pdf_file_path), 'mathpix_output') - if not os.path.exists(output_dir): - os.makedirs(output_dir) - - url = f"https://api.mathpix.com/v3/pdf/{pdf_id}.tex" - response = requests.get(url, headers=headers) - file_name_wo_dot = '_'.join(os.path.basename(pdf_file_path).split('.')[:-1]) - output_name = f"{file_name_wo_dot}.tex.zip" - output_path = os.path.join(output_dir, output_name) - with open(output_path, "wb") as output_file: - output_file.write(response.content) - print(f"tex.zip file saved at: {output_path}") - - import zipfile - unzip_dir = os.path.join(output_dir, file_name_wo_dot) - with zipfile.ZipFile(output_path, 'r') as zip_ref: - zip_ref.extractall(unzip_dir) - - return unzip_dir - - else: - print(f"Error sending PDF for processing. Status code: {response.status_code}") - return None - - -# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 插件主程序1 =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= - - -@CatchException -def Latex英文纠错加PDF对比(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request): - # <-------------- information about this plugin -------------> - chatbot.append(["函数插件功能?", - "对整个Latex项目进行纠错, 用latex编译为PDF对修正处做高亮。函数插件贡献者: Binary-Husky。注意事项: 目前仅支持GPT3.5/GPT4,其他模型转化效果未知。目前对机器学习类文献转化效果最好,其他类型文献转化效果未知。仅在Windows系统进行了测试,其他操作系统表现未知。"]) - yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 - - # <-------------- more requirements -------------> - if ("advanced_arg" in plugin_kwargs) and (plugin_kwargs["advanced_arg"] == ""): plugin_kwargs.pop("advanced_arg") - more_req = plugin_kwargs.get("advanced_arg", "") - _switch_prompt_ = partial(switch_prompt, more_requirement=more_req) - - # <-------------- check deps -------------> - try: - import glob, os, time, subprocess - subprocess.Popen(['pdflatex', '-version']) - from .latex_fns.latex_actions import Latex精细分解与转化, 编译Latex - except Exception as e: - chatbot.append([f"解析项目: {txt}", - f"尝试执行Latex指令失败。Latex没有安装, 或者不在环境变量PATH中。安装方法https://tug.org/texlive/。报错信息\n\n```\n\n{trimmed_format_exc()}\n\n```\n\n"]) - yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 - return - - # <-------------- clear history and read input -------------> - history = [] - if os.path.exists(txt): - project_folder = txt - else: - if txt == "": txt = '空空如也的输入栏' - report_exception(chatbot, history, a=f"解析项目: {txt}", b=f"找不到本地项目或无权访问: {txt}") - yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 - return - file_manifest = [f for f in glob.glob(f'{project_folder}/**/*.tex', recursive=True)] - if len(file_manifest) == 0: - report_exception(chatbot, history, a=f"解析项目: {txt}", b=f"找不到任何.tex文件: {txt}") - yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 - return - - # <-------------- if is a zip/tar file -------------> - project_folder = desend_to_extracted_folder_if_exist(project_folder) - - # <-------------- move latex project away from temp folder -------------> - project_folder = move_project(project_folder, arxiv_id=None) - - # <-------------- if merge_translate_zh is already generated, skip gpt req -------------> - if not os.path.exists(project_folder + '/merge_proofread_en.tex'): - yield from Latex精细分解与转化(file_manifest, project_folder, llm_kwargs, plugin_kwargs, - chatbot, history, system_prompt, mode='proofread_en', - switch_prompt=_switch_prompt_) - - # <-------------- compile PDF -------------> - success = yield from 编译Latex(chatbot, history, main_file_original='merge', - main_file_modified='merge_proofread_en', - work_folder_original=project_folder, work_folder_modified=project_folder, - work_folder=project_folder) - - # <-------------- zip PDF -------------> - zip_res = zip_result(project_folder) - if success: - chatbot.append((f"成功啦", '请查收结果(压缩包)...')) - yield from update_ui(chatbot=chatbot, history=history); - time.sleep(1) # 刷新界面 - promote_file_to_downloadzone(file=zip_res, chatbot=chatbot) - else: - chatbot.append((f"失败了", - '虽然PDF生成失败了, 但请查收结果(压缩包), 内含已经翻译的Tex文档, 也是可读的, 您可以到Github Issue区, 用该压缩包+对话历史存档进行反馈 ...')) - yield from update_ui(chatbot=chatbot, history=history); - time.sleep(1) # 刷新界面 - promote_file_to_downloadzone(file=zip_res, chatbot=chatbot) - - # <-------------- we are done -------------> - return success - - -# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 插件主程序2 =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= - -@CatchException -def Latex翻译中文并重新编译PDF(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request): - # <-------------- information about this plugin -------------> - chatbot.append([ - "函数插件功能?", - "对整个Latex项目进行翻译, 生成中文PDF。函数插件贡献者: Binary-Husky。注意事项: 此插件Windows支持最佳,Linux下必须使用Docker安装,详见项目主README.md。目前仅支持GPT3.5/GPT4,其他模型转化效果未知。目前对机器学习类文献转化效果最好,其他类型文献转化效果未知。"]) - yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 - - # <-------------- more requirements -------------> - if ("advanced_arg" in plugin_kwargs) and (plugin_kwargs["advanced_arg"] == ""): plugin_kwargs.pop("advanced_arg") - more_req = plugin_kwargs.get("advanced_arg", "") - no_cache = more_req.startswith("--no-cache") - if no_cache: more_req.lstrip("--no-cache") - allow_cache = not no_cache - _switch_prompt_ = partial(switch_prompt, more_requirement=more_req) - - # <-------------- check deps -------------> - try: - import glob, os, time, subprocess - subprocess.Popen(['pdflatex', '-version']) - from .latex_fns.latex_actions import Latex精细分解与转化, 编译Latex - except Exception as e: - chatbot.append([f"解析项目: {txt}", - f"尝试执行Latex指令失败。Latex没有安装, 或者不在环境变量PATH中。安装方法https://tug.org/texlive/。报错信息\n\n```\n\n{trimmed_format_exc()}\n\n```\n\n"]) - yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 - return - - # <-------------- clear history and read input -------------> - history = [] - try: - txt, arxiv_id = yield from arxiv_download(chatbot, history, txt, allow_cache) - except tarfile.ReadError as e: - yield from update_ui_lastest_msg( - "无法自动下载该论文的Latex源码,请前往arxiv打开此论文下载页面,点other Formats,然后download source手动下载latex源码包。接下来调用本地Latex翻译插件即可。", - chatbot=chatbot, history=history) - return - - if txt.endswith('.pdf'): - report_exception(chatbot, history, a=f"解析项目: {txt}", b=f"发现已经存在翻译好的PDF文档") - yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 - return - - if os.path.exists(txt): - project_folder = txt - else: - if txt == "": txt = '空空如也的输入栏' - report_exception(chatbot, history, a=f"解析项目: {txt}", b=f"找不到本地项目或无法处理: {txt}") - yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 - return - - file_manifest = [f for f in glob.glob(f'{project_folder}/**/*.tex', recursive=True)] - if len(file_manifest) == 0: - report_exception(chatbot, history, a=f"解析项目: {txt}", b=f"找不到任何.tex文件: {txt}") - yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 - return - - # <-------------- if is a zip/tar file -------------> - project_folder = desend_to_extracted_folder_if_exist(project_folder) - - # <-------------- move latex project away from temp folder -------------> - project_folder = move_project(project_folder, arxiv_id) - - # <-------------- if merge_translate_zh is already generated, skip gpt req -------------> - if not os.path.exists(project_folder + '/merge_translate_zh.tex'): - yield from Latex精细分解与转化(file_manifest, project_folder, llm_kwargs, plugin_kwargs, - chatbot, history, system_prompt, mode='translate_zh', - switch_prompt=_switch_prompt_) - - # <-------------- compile PDF -------------> - success = yield from 编译Latex(chatbot, history, main_file_original='merge', - main_file_modified='merge_translate_zh', mode='translate_zh', - work_folder_original=project_folder, work_folder_modified=project_folder, - work_folder=project_folder) - - # <-------------- zip PDF -------------> - zip_res = zip_result(project_folder) - if success: - chatbot.append((f"成功啦", '请查收结果(压缩包)...')) - yield from update_ui(chatbot=chatbot, history=history); - time.sleep(1) # 刷新界面 - promote_file_to_downloadzone(file=zip_res, chatbot=chatbot) - else: - chatbot.append((f"失败了", - '虽然PDF生成失败了, 但请查收结果(压缩包), 内含已经翻译的Tex文档, 您可以到Github Issue区, 用该压缩包进行反馈。如系统是Linux,请检查系统字体(见Github wiki) ...')) - yield from update_ui(chatbot=chatbot, history=history); - time.sleep(1) # 刷新界面 - promote_file_to_downloadzone(file=zip_res, chatbot=chatbot) - - # <-------------- we are done -------------> - return success - - -# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 插件主程序3 =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= - -@CatchException -def PDF翻译中文并重新编译PDF(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port): - # <-------------- information about this plugin -------------> - chatbot.append([ - "函数插件功能?", - "将PDF转换为Latex项目,翻译为中文后重新编译为PDF。函数插件贡献者: Marroh。注意事项: 此插件Windows支持最佳,Linux下必须使用Docker安装,详见项目主README.md。目前仅支持GPT3.5/GPT4,其他模型转化效果未知。目前对机器学习类文献转化效果最好,其他类型文献转化效果未知。"]) - yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 - - # <-------------- more requirements -------------> - if ("advanced_arg" in plugin_kwargs) and (plugin_kwargs["advanced_arg"] == ""): plugin_kwargs.pop("advanced_arg") - more_req = plugin_kwargs.get("advanced_arg", "") - no_cache = more_req.startswith("--no-cache") - if no_cache: more_req.lstrip("--no-cache") - allow_cache = not no_cache - _switch_prompt_ = partial(switch_prompt, more_requirement=more_req) - - # <-------------- check deps -------------> - try: - import glob, os, time, subprocess - subprocess.Popen(['pdflatex', '-version']) - from .latex_fns.latex_actions import Latex精细分解与转化, 编译Latex - except Exception as e: - chatbot.append([f"解析项目: {txt}", - f"尝试执行Latex指令失败。Latex没有安装, 或者不在环境变量PATH中。安装方法https://tug.org/texlive/。报错信息\n\n```\n\n{trimmed_format_exc()}\n\n```\n\n"]) - yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 - return - - # <-------------- clear history and read input -------------> - if os.path.exists(txt): - project_folder = txt - else: - if txt == "": txt = '空空如也的输入栏' - report_exception(chatbot, history, a=f"解析项目: {txt}", b=f"找不到本地项目或无法处理: {txt}") - yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 - return - - file_manifest = [f for f in glob.glob(f'{project_folder}/**/*.pdf', recursive=True)] - if len(file_manifest) == 0: - report_exception(chatbot, history, a=f"解析项目: {txt}", b=f"找不到任何.pdf文件: {txt}") - yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 - return - if len(file_manifest) != 1: - report_exception(chatbot, history, a=f"解析项目: {txt}", b=f"不支持同时处理多个pdf文件: {txt}") - yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 - return - app_id, app_key = get_conf('MATHPIX_APPID', 'MATHPIX_APPKEY') - if len(app_id) == 0 or len(app_key) == 0: - report_exception(chatbot, history, a="缺失 MATHPIX_APPID 和 MATHPIX_APPKEY。", b=f"请配置 MATHPIX_APPID 和 MATHPIX_APPKEY") - yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 - return - - # <-------------- convert pdf into tex -------------> - project_folder = pdf2tex_project(file_manifest[0]) - - # Translate English Latex to Chinese Latex, and compile it - file_manifest = [f for f in glob.glob(f'{project_folder}/**/*.tex', recursive=True)] - if len(file_manifest) == 0: - report_exception(chatbot, history, a=f"解析项目: {txt}", b=f"找不到任何.tex文件: {txt}") - yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 - return - - # <-------------- if is a zip/tar file -------------> - project_folder = desend_to_extracted_folder_if_exist(project_folder) - - # <-------------- move latex project away from temp folder -------------> - project_folder = move_project(project_folder) - - # <-------------- if merge_translate_zh is already generated, skip gpt req -------------> - if not os.path.exists(project_folder + '/merge_translate_zh.tex'): - yield from Latex精细分解与转化(file_manifest, project_folder, llm_kwargs, plugin_kwargs, - chatbot, history, system_prompt, mode='translate_zh', - switch_prompt=_switch_prompt_) - - # <-------------- compile PDF -------------> - success = yield from 编译Latex(chatbot, history, main_file_original='merge', - main_file_modified='merge_translate_zh', mode='translate_zh', - work_folder_original=project_folder, work_folder_modified=project_folder, - work_folder=project_folder) - - # <-------------- zip PDF -------------> - zip_res = zip_result(project_folder) - if success: - chatbot.append((f"成功啦", '请查收结果(压缩包)...')) - yield from update_ui(chatbot=chatbot, history=history); - time.sleep(1) # 刷新界面 - promote_file_to_downloadzone(file=zip_res, chatbot=chatbot) - else: - chatbot.append((f"失败了", - '虽然PDF生成失败了, 但请查收结果(压缩包), 内含已经翻译的Tex文档, 您可以到Github Issue区, 用该压缩包进行反馈。如系统是Linux,请检查系统字体(见Github wiki) ...')) - yield from update_ui(chatbot=chatbot, history=history); - time.sleep(1) # 刷新界面 - promote_file_to_downloadzone(file=zip_res, chatbot=chatbot) - - # <-------------- we are done -------------> - return success diff --git "a/crazy_functions/Latex\350\276\223\345\207\272PDF\347\273\223\346\236\234.py" "b/crazy_functions/Latex\350\276\223\345\207\272PDF\347\273\223\346\236\234.py" index 36c99e71cf7ad81dcf1b721b1f98f59ef694c7fa..56ca1c6c1f679039b549e6b661a7d450564220f4 100644 --- "a/crazy_functions/Latex\350\276\223\345\207\272PDF\347\273\223\346\236\234.py" +++ "b/crazy_functions/Latex\350\276\223\345\207\272PDF\347\273\223\346\236\234.py" @@ -1,11 +1,11 @@ from toolbox import update_ui, trimmed_format_exc, get_conf, get_log_folder, promote_file_to_downloadzone -from toolbox import CatchException, report_exception, update_ui_lastest_msg, zip_result, gen_time_str +from toolbox import CatchException, report_execption, update_ui_lastest_msg, zip_result, gen_time_str from functools import partial import glob, os, requests, time pj = os.path.join ARXIV_CACHE_DIR = os.path.expanduser(f"~/arxiv_cache/") -# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 工具函数 =-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +# =================================== 工具函数 =============================================== # 专业词汇声明 = 'If the term "agent" is used in this section, it should be translated to "智能体". ' def switch_prompt(pfg, mode, more_requirement): """ @@ -73,14 +73,13 @@ def move_project(project_folder, arxiv_id=None): # align subfolder if there is a folder wrapper items = glob.glob(pj(project_folder,'*')) - items = [item for item in items if os.path.basename(item)!='__MACOSX'] if len(glob.glob(pj(project_folder,'*.tex'))) == 0 and len(items) == 1: if os.path.isdir(items[0]): project_folder = items[0] shutil.copytree(src=project_folder, dst=new_workfolder) return new_workfolder -def arxiv_download(chatbot, history, txt, allow_cache=True): +def arxiv_download(chatbot, history, txt): def check_cached_translation_pdf(arxiv_id): translation_dir = pj(ARXIV_CACHE_DIR, arxiv_id, 'translation') if not os.path.exists(translation_dir): @@ -88,9 +87,6 @@ def arxiv_download(chatbot, history, txt, allow_cache=True): target_file = pj(translation_dir, 'translate_zh.pdf') if os.path.exists(target_file): promote_file_to_downloadzone(target_file, rename_file=None, chatbot=chatbot) - target_file_compare = pj(translation_dir, 'comparison.pdf') - if os.path.exists(target_file_compare): - promote_file_to_downloadzone(target_file_compare, rename_file=None, chatbot=chatbot) return target_file return False def is_float(s): @@ -120,7 +116,7 @@ def arxiv_download(chatbot, history, txt, allow_cache=True): arxiv_id = url_.split('/abs/')[-1] if 'v' in arxiv_id: arxiv_id = arxiv_id[:10] cached_translation_pdf = check_cached_translation_pdf(arxiv_id) - if cached_translation_pdf and allow_cache: return cached_translation_pdf, arxiv_id + if cached_translation_pdf: return cached_translation_pdf, arxiv_id url_tar = url_.replace('/abs/', '/e-print/') translation_dir = pj(ARXIV_CACHE_DIR, arxiv_id, 'e-print') @@ -133,7 +129,7 @@ def arxiv_download(chatbot, history, txt, allow_cache=True): yield from update_ui_lastest_msg("调用缓存", chatbot=chatbot, history=history) # 刷新界面 else: yield from update_ui_lastest_msg("开始下载", chatbot=chatbot, history=history) # 刷新界面 - proxies = get_conf('proxies') + proxies, = get_conf('proxies') r = requests.get(url_tar, proxies=proxies) with open(dst, 'wb+') as f: f.write(r.content) @@ -142,7 +138,7 @@ def arxiv_download(chatbot, history, txt, allow_cache=True): from toolbox import extract_archive extract_archive(file_path=dst, dest_dir=extract_dst) return extract_dst, arxiv_id -# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 插件主程序1 =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +# ========================================= 插件主程序1 ===================================================== @CatchException @@ -175,12 +171,12 @@ def Latex英文纠错加PDF对比(txt, llm_kwargs, plugin_kwargs, chatbot, histo project_folder = txt else: if txt == "": txt = '空空如也的输入栏' - report_exception(chatbot, history, a = f"解析项目: {txt}", b = f"找不到本地项目或无权访问: {txt}") + report_execption(chatbot, history, a = f"解析项目: {txt}", b = f"找不到本地项目或无权访问: {txt}") yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 return file_manifest = [f for f in glob.glob(f'{project_folder}/**/*.tex', recursive=True)] if len(file_manifest) == 0: - report_exception(chatbot, history, a = f"解析项目: {txt}", b = f"找不到任何.tex文件: {txt}") + report_execption(chatbot, history, a = f"解析项目: {txt}", b = f"找不到任何.tex文件: {txt}") yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 return @@ -218,7 +214,8 @@ def Latex英文纠错加PDF对比(txt, llm_kwargs, plugin_kwargs, chatbot, histo # <-------------- we are done -------------> return success -# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 插件主程序2 =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= + +# ========================================= 插件主程序2 ===================================================== @CatchException def Latex翻译中文并重新编译PDF(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port): @@ -231,9 +228,6 @@ def Latex翻译中文并重新编译PDF(txt, llm_kwargs, plugin_kwargs, chatbot, # <-------------- more requirements -------------> if ("advanced_arg" in plugin_kwargs) and (plugin_kwargs["advanced_arg"] == ""): plugin_kwargs.pop("advanced_arg") more_req = plugin_kwargs.get("advanced_arg", "") - no_cache = more_req.startswith("--no-cache") - if no_cache: more_req.lstrip("--no-cache") - allow_cache = not no_cache _switch_prompt_ = partial(switch_prompt, more_requirement=more_req) # <-------------- check deps -------------> @@ -250,9 +244,9 @@ def Latex翻译中文并重新编译PDF(txt, llm_kwargs, plugin_kwargs, chatbot, # <-------------- clear history and read input -------------> history = [] - txt, arxiv_id = yield from arxiv_download(chatbot, history, txt, allow_cache) + txt, arxiv_id = yield from arxiv_download(chatbot, history, txt) if txt.endswith('.pdf'): - report_exception(chatbot, history, a = f"解析项目: {txt}", b = f"发现已经存在翻译好的PDF文档") + report_execption(chatbot, history, a = f"解析项目: {txt}", b = f"发现已经存在翻译好的PDF文档") yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 return @@ -261,13 +255,13 @@ def Latex翻译中文并重新编译PDF(txt, llm_kwargs, plugin_kwargs, chatbot, project_folder = txt else: if txt == "": txt = '空空如也的输入栏' - report_exception(chatbot, history, a = f"解析项目: {txt}", b = f"找不到本地项目或无法处理: {txt}") + report_execption(chatbot, history, a = f"解析项目: {txt}", b = f"找不到本地项目或无法处理: {txt}") yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 return file_manifest = [f for f in glob.glob(f'{project_folder}/**/*.tex', recursive=True)] if len(file_manifest) == 0: - report_exception(chatbot, history, a = f"解析项目: {txt}", b = f"找不到任何.tex文件: {txt}") + report_execption(chatbot, history, a = f"解析项目: {txt}", b = f"找不到任何.tex文件: {txt}") yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 return diff --git a/crazy_functions/agent_fns/auto_agent.py b/crazy_functions/agent_fns/auto_agent.py deleted file mode 100644 index 4f8fda9d5872db9c178321d43415b24dbea024bb..0000000000000000000000000000000000000000 --- a/crazy_functions/agent_fns/auto_agent.py +++ /dev/null @@ -1,23 +0,0 @@ -from toolbox import CatchException, update_ui, gen_time_str, trimmed_format_exc, ProxyNetworkActivate -from toolbox import report_exception, get_log_folder, update_ui_lastest_msg, Singleton -from crazy_functions.agent_fns.pipe import PluginMultiprocessManager, PipeCom -from crazy_functions.agent_fns.general import AutoGenGeneral - - - -class AutoGenMath(AutoGenGeneral): - - def define_agents(self): - from autogen import AssistantAgent, UserProxyAgent - return [ - { - "name": "assistant", # name of the agent. - "cls": AssistantAgent, # class of the agent. - }, - { - "name": "user_proxy", # name of the agent. - "cls": UserProxyAgent, # class of the agent. - "human_input_mode": "ALWAYS", # always ask for human input. - "llm_config": False, # disables llm-based auto reply. - }, - ] \ No newline at end of file diff --git a/crazy_functions/agent_fns/echo_agent.py b/crazy_functions/agent_fns/echo_agent.py deleted file mode 100644 index 52bf72debc7a56a89b277ced80078ea6b985e1fa..0000000000000000000000000000000000000000 --- a/crazy_functions/agent_fns/echo_agent.py +++ /dev/null @@ -1,19 +0,0 @@ -from crazy_functions.agent_fns.pipe import PluginMultiprocessManager, PipeCom - -class EchoDemo(PluginMultiprocessManager): - def subprocess_worker(self, child_conn): - # ⭐⭐ 子进程 - self.child_conn = child_conn - while True: - msg = self.child_conn.recv() # PipeCom - if msg.cmd == "user_input": - # wait futher user input - self.child_conn.send(PipeCom("show", msg.content)) - wait_success = self.subprocess_worker_wait_user_feedback(wait_msg="我准备好处理下一个问题了.") - if not wait_success: - # wait timeout, terminate this subprocess_worker - break - elif msg.cmd == "terminate": - self.child_conn.send(PipeCom("done", "")) - break - print('[debug] subprocess_worker terminated') \ No newline at end of file diff --git a/crazy_functions/agent_fns/general.py b/crazy_functions/agent_fns/general.py deleted file mode 100644 index 327a613b36b456220ac85d42a6a536f4fce42ea6..0000000000000000000000000000000000000000 --- a/crazy_functions/agent_fns/general.py +++ /dev/null @@ -1,138 +0,0 @@ -from toolbox import trimmed_format_exc, get_conf, ProxyNetworkActivate -from crazy_functions.agent_fns.pipe import PluginMultiprocessManager, PipeCom -from request_llms.bridge_all import predict_no_ui_long_connection -import time - -def gpt_academic_generate_oai_reply( - self, - messages, - sender, - config, -): - llm_config = self.llm_config if config is None else config - if llm_config is False: - return False, None - if messages is None: - messages = self._oai_messages[sender] - - inputs = messages[-1]['content'] - history = [] - for message in messages[:-1]: - history.append(message['content']) - context=messages[-1].pop("context", None) - assert context is None, "预留参数 context 未实现" - - reply = predict_no_ui_long_connection( - inputs=inputs, - llm_kwargs=llm_config, - history=history, - sys_prompt=self._oai_system_message[0]['content'], - console_slience=True - ) - assumed_done = reply.endswith('\nTERMINATE') - return True, reply - -class AutoGenGeneral(PluginMultiprocessManager): - def gpt_academic_print_override(self, user_proxy, message, sender): - # ⭐⭐ run in subprocess - try: - print_msg = sender.name + "\n\n---\n\n" + message["content"] - except: - print_msg = sender.name + "\n\n---\n\n" + message - self.child_conn.send(PipeCom("show", print_msg)) - - def gpt_academic_get_human_input(self, user_proxy, message): - # ⭐⭐ run in subprocess - patience = 300 - begin_waiting_time = time.time() - self.child_conn.send(PipeCom("interact", message)) - while True: - time.sleep(0.5) - if self.child_conn.poll(): - wait_success = True - break - if time.time() - begin_waiting_time > patience: - self.child_conn.send(PipeCom("done", "")) - wait_success = False - break - if wait_success: - return self.child_conn.recv().content - else: - raise TimeoutError("等待用户输入超时") - - def define_agents(self): - raise NotImplementedError - - def exe_autogen(self, input): - # ⭐⭐ run in subprocess - input = input.content - code_execution_config = {"work_dir": self.autogen_work_dir, "use_docker": self.use_docker} - agents = self.define_agents() - user_proxy = None - assistant = None - for agent_kwargs in agents: - agent_cls = agent_kwargs.pop('cls') - kwargs = { - 'llm_config':self.llm_kwargs, - 'code_execution_config':code_execution_config - } - kwargs.update(agent_kwargs) - agent_handle = agent_cls(**kwargs) - agent_handle._print_received_message = lambda a,b: self.gpt_academic_print_override(agent_kwargs, a, b) - for d in agent_handle._reply_func_list: - if hasattr(d['reply_func'],'__name__') and d['reply_func'].__name__ == 'generate_oai_reply': - d['reply_func'] = gpt_academic_generate_oai_reply - if agent_kwargs['name'] == 'user_proxy': - agent_handle.get_human_input = lambda a: self.gpt_academic_get_human_input(user_proxy, a) - user_proxy = agent_handle - if agent_kwargs['name'] == 'assistant': assistant = agent_handle - try: - if user_proxy is None or assistant is None: raise Exception("用户代理或助理代理未定义") - with ProxyNetworkActivate("AutoGen"): - user_proxy.initiate_chat(assistant, message=input) - except Exception as e: - tb_str = '```\n' + trimmed_format_exc() + '```' - self.child_conn.send(PipeCom("done", "AutoGen 执行失败: \n\n" + tb_str)) - - def subprocess_worker(self, child_conn): - # ⭐⭐ run in subprocess - self.child_conn = child_conn - while True: - msg = self.child_conn.recv() # PipeCom - self.exe_autogen(msg) - - -class AutoGenGroupChat(AutoGenGeneral): - def exe_autogen(self, input): - # ⭐⭐ run in subprocess - import autogen - - input = input.content - with ProxyNetworkActivate("AutoGen"): - code_execution_config = {"work_dir": self.autogen_work_dir, "use_docker": self.use_docker} - agents = self.define_agents() - agents_instances = [] - for agent_kwargs in agents: - agent_cls = agent_kwargs.pop("cls") - kwargs = {"code_execution_config": code_execution_config} - kwargs.update(agent_kwargs) - agent_handle = agent_cls(**kwargs) - agent_handle._print_received_message = lambda a, b: self.gpt_academic_print_override(agent_kwargs, a, b) - agents_instances.append(agent_handle) - if agent_kwargs["name"] == "user_proxy": - user_proxy = agent_handle - user_proxy.get_human_input = lambda a: self.gpt_academic_get_human_input(user_proxy, a) - try: - groupchat = autogen.GroupChat(agents=agents_instances, messages=[], max_round=50) - manager = autogen.GroupChatManager(groupchat=groupchat, **self.define_group_chat_manager_config()) - manager._print_received_message = lambda a, b: self.gpt_academic_print_override(agent_kwargs, a, b) - manager.get_human_input = lambda a: self.gpt_academic_get_human_input(manager, a) - if user_proxy is None: - raise Exception("user_proxy is not defined") - user_proxy.initiate_chat(manager, message=input) - except Exception: - tb_str = "```\n" + trimmed_format_exc() + "```" - self.child_conn.send(PipeCom("done", "AutoGen exe failed: \n\n" + tb_str)) - - def define_group_chat_manager_config(self): - raise NotImplementedError diff --git a/crazy_functions/agent_fns/persistent.py b/crazy_functions/agent_fns/persistent.py deleted file mode 100644 index 82c869cb18ceba5c56e05d3d8b18bb968cf3b35e..0000000000000000000000000000000000000000 --- a/crazy_functions/agent_fns/persistent.py +++ /dev/null @@ -1,16 +0,0 @@ -from toolbox import Singleton -@Singleton -class GradioMultiuserManagerForPersistentClasses(): - def __init__(self): - self.mapping = {} - - def already_alive(self, key): - return (key in self.mapping) and (self.mapping[key].is_alive()) - - def set(self, key, x): - self.mapping[key] = x - return self.mapping[key] - - def get(self, key): - return self.mapping[key] - diff --git a/crazy_functions/agent_fns/pipe.py b/crazy_functions/agent_fns/pipe.py deleted file mode 100644 index a292af810ef23992b036cc0697785268bc8a6250..0000000000000000000000000000000000000000 --- a/crazy_functions/agent_fns/pipe.py +++ /dev/null @@ -1,194 +0,0 @@ -from toolbox import get_log_folder, update_ui, gen_time_str, get_conf, promote_file_to_downloadzone -from crazy_functions.agent_fns.watchdog import WatchDog -import time, os - -class PipeCom: - def __init__(self, cmd, content) -> None: - self.cmd = cmd - self.content = content - - -class PluginMultiprocessManager: - def __init__(self, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request): - # ⭐ run in main process - self.autogen_work_dir = os.path.join(get_log_folder("autogen"), gen_time_str()) - self.previous_work_dir_files = {} - self.llm_kwargs = llm_kwargs - self.plugin_kwargs = plugin_kwargs - self.chatbot = chatbot - self.history = history - self.system_prompt = system_prompt - # self.user_request = user_request - self.alive = True - self.use_docker = get_conf("AUTOGEN_USE_DOCKER") - self.last_user_input = "" - # create a thread to monitor self.heartbeat, terminate the instance if no heartbeat for a long time - timeout_seconds = 5 * 60 - self.heartbeat_watchdog = WatchDog(timeout=timeout_seconds, bark_fn=self.terminate, interval=5) - self.heartbeat_watchdog.begin_watch() - - def feed_heartbeat_watchdog(self): - # feed this `dog`, so the dog will not `bark` (bark_fn will terminate the instance) - self.heartbeat_watchdog.feed() - - def is_alive(self): - return self.alive - - def launch_subprocess_with_pipe(self): - # ⭐ run in main process - from multiprocessing import Process, Pipe - - parent_conn, child_conn = Pipe() - self.p = Process(target=self.subprocess_worker, args=(child_conn,)) - self.p.daemon = True - self.p.start() - return parent_conn - - def terminate(self): - self.p.terminate() - self.alive = False - print("[debug] instance terminated") - - def subprocess_worker(self, child_conn): - # ⭐⭐ run in subprocess - raise NotImplementedError - - def send_command(self, cmd): - # ⭐ run in main process - repeated = False - if cmd == self.last_user_input: - repeated = True - cmd = "" - else: - self.last_user_input = cmd - self.parent_conn.send(PipeCom("user_input", cmd)) - return repeated, cmd - - def immediate_showoff_when_possible(self, fp): - # ⭐ 主进程 - # 获取fp的拓展名 - file_type = fp.split('.')[-1] - # 如果是文本文件, 则直接显示文本内容 - if file_type.lower() in ['png', 'jpg']: - image_path = os.path.abspath(fp) - self.chatbot.append([ - '检测到新生图像:', - f'本地文件预览:
' - ]) - yield from update_ui(chatbot=self.chatbot, history=self.history) - - def overwatch_workdir_file_change(self): - # ⭐ 主进程 Docker 外挂文件夹监控 - path_to_overwatch = self.autogen_work_dir - change_list = [] - # 扫描路径下的所有文件, 并与self.previous_work_dir_files中所记录的文件进行对比, - # 如果有新文件出现,或者文件的修改时间发生变化,则更新self.previous_work_dir_files中 - # 把新文件和发生变化的文件的路径记录到 change_list 中 - for root, dirs, files in os.walk(path_to_overwatch): - for file in files: - file_path = os.path.join(root, file) - if file_path not in self.previous_work_dir_files.keys(): - last_modified_time = os.stat(file_path).st_mtime - self.previous_work_dir_files.update({file_path: last_modified_time}) - change_list.append(file_path) - else: - last_modified_time = os.stat(file_path).st_mtime - if last_modified_time != self.previous_work_dir_files[file_path]: - self.previous_work_dir_files[file_path] = last_modified_time - change_list.append(file_path) - if len(change_list) > 0: - file_links = "" - for f in change_list: - res = promote_file_to_downloadzone(f) - file_links += f'
{res}' - yield from self.immediate_showoff_when_possible(f) - - self.chatbot.append(['检测到新生文档.', f'文档清单如下: {file_links}']) - yield from update_ui(chatbot=self.chatbot, history=self.history) - return change_list - - - def main_process_ui_control(self, txt, create_or_resume) -> str: - # ⭐ 主进程 - if create_or_resume == 'create': - self.cnt = 1 - self.parent_conn = self.launch_subprocess_with_pipe() # ⭐⭐⭐ - repeated, cmd_to_autogen = self.send_command(txt) - if txt == 'exit': - self.chatbot.append([f"结束", "结束信号已明确,终止AutoGen程序。"]) - yield from update_ui(chatbot=self.chatbot, history=self.history) - self.terminate() - return "terminate" - - # patience = 10 - - while True: - time.sleep(0.5) - if not self.alive: - # the heartbeat watchdog might have it killed - self.terminate() - return "terminate" - if self.parent_conn.poll(): - self.feed_heartbeat_watchdog() - if "[GPT-Academic] 等待中" in self.chatbot[-1][-1]: - self.chatbot.pop(-1) # remove the last line - if "等待您的进一步指令" in self.chatbot[-1][-1]: - self.chatbot.pop(-1) # remove the last line - if '[GPT-Academic] 等待中' in self.chatbot[-1][-1]: - self.chatbot.pop(-1) # remove the last line - msg = self.parent_conn.recv() # PipeCom - if msg.cmd == "done": - self.chatbot.append([f"结束", msg.content]) - self.cnt += 1 - yield from update_ui(chatbot=self.chatbot, history=self.history) - self.terminate() - break - if msg.cmd == "show": - yield from self.overwatch_workdir_file_change() - notice = "" - if repeated: notice = "(自动忽略重复的输入)" - self.chatbot.append([f"运行阶段-{self.cnt}(上次用户反馈输入为: 「{cmd_to_autogen}」{notice}", msg.content]) - self.cnt += 1 - yield from update_ui(chatbot=self.chatbot, history=self.history) - if msg.cmd == "interact": - yield from self.overwatch_workdir_file_change() - self.chatbot.append([f"程序抵达用户反馈节点.", msg.content + - "\n\n等待您的进一步指令." + - "\n\n(1) 一般情况下您不需要说什么, 清空输入区, 然后直接点击“提交”以继续. " + - "\n\n(2) 如果您需要补充些什么, 输入要反馈的内容, 直接点击“提交”以继续. " + - "\n\n(3) 如果您想终止程序, 输入exit, 直接点击“提交”以终止AutoGen并解锁. " - ]) - yield from update_ui(chatbot=self.chatbot, history=self.history) - # do not terminate here, leave the subprocess_worker instance alive - return "wait_feedback" - else: - self.feed_heartbeat_watchdog() - if '[GPT-Academic] 等待中' not in self.chatbot[-1][-1]: - # begin_waiting_time = time.time() - self.chatbot.append(["[GPT-Academic] 等待AutoGen执行结果 ...", "[GPT-Academic] 等待中"]) - self.chatbot[-1] = [self.chatbot[-1][0], self.chatbot[-1][1].replace("[GPT-Academic] 等待中", "[GPT-Academic] 等待中.")] - yield from update_ui(chatbot=self.chatbot, history=self.history) - # if time.time() - begin_waiting_time > patience: - # self.chatbot.append([f"结束", "等待超时, 终止AutoGen程序。"]) - # yield from update_ui(chatbot=self.chatbot, history=self.history) - # self.terminate() - # return "terminate" - - self.terminate() - return "terminate" - - def subprocess_worker_wait_user_feedback(self, wait_msg="wait user feedback"): - # ⭐⭐ run in subprocess - patience = 5 * 60 - begin_waiting_time = time.time() - self.child_conn.send(PipeCom("interact", wait_msg)) - while True: - time.sleep(0.5) - if self.child_conn.poll(): - wait_success = True - break - if time.time() - begin_waiting_time > patience: - self.child_conn.send(PipeCom("done", "")) - wait_success = False - break - return wait_success diff --git a/crazy_functions/agent_fns/watchdog.py b/crazy_functions/agent_fns/watchdog.py deleted file mode 100644 index 2a2bdfab95097d6c4ad36329ab1fa02dd2ebe868..0000000000000000000000000000000000000000 --- a/crazy_functions/agent_fns/watchdog.py +++ /dev/null @@ -1,28 +0,0 @@ -import threading, time - -class WatchDog(): - def __init__(self, timeout, bark_fn, interval=3, msg="") -> None: - self.last_feed = None - self.timeout = timeout - self.bark_fn = bark_fn - self.interval = interval - self.msg = msg - self.kill_dog = False - - def watch(self): - while True: - if self.kill_dog: break - if time.time() - self.last_feed > self.timeout: - if len(self.msg) > 0: print(self.msg) - self.bark_fn() - break - time.sleep(self.interval) - - def begin_watch(self): - self.last_feed = time.time() - th = threading.Thread(target=self.watch) - th.daemon = True - th.start() - - def feed(self): - self.last_feed = time.time() diff --git "a/crazy_functions/chatglm\345\276\256\350\260\203\345\267\245\345\205\267.py" "b/crazy_functions/chatglm\345\276\256\350\260\203\345\267\245\345\205\267.py" index 1b28228290f9ee7873787b420ed3fa742df427fa..336d7cfc85ac159841758123fa057bd20a0bbbec 100644 --- "a/crazy_functions/chatglm\345\276\256\350\260\203\345\267\245\345\205\267.py" +++ "b/crazy_functions/chatglm\345\276\256\350\260\203\345\267\245\345\205\267.py" @@ -32,7 +32,7 @@ def string_to_options(arguments): return args @CatchException -def 微调数据集生成(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request): +def 微调数据集生成(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port): """ txt 输入栏用户输入的文本,例如需要翻译的一段话,再例如一个包含了待处理文件的路径 llm_kwargs gpt模型参数,如温度和top_p等,一般原样传递下去就行 @@ -40,7 +40,7 @@ def 微调数据集生成(txt, llm_kwargs, plugin_kwargs, chatbot, history, syst chatbot 聊天显示框的句柄,用于显示给用户 history 聊天历史,前情提要 system_prompt 给gpt的静默提醒 - user_request 当前用户的请求信息(IP地址等) + web_port 当前软件运行的端口号 """ history = [] # 清空历史,以免输入溢出 chatbot.append(("这是什么功能?", "[Local Message] 微调数据集生成")) @@ -80,7 +80,7 @@ def 微调数据集生成(txt, llm_kwargs, plugin_kwargs, chatbot, history, syst @CatchException -def 启动微调(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request): +def 启动微调(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port): """ txt 输入栏用户输入的文本,例如需要翻译的一段话,再例如一个包含了待处理文件的路径 llm_kwargs gpt模型参数,如温度和top_p等,一般原样传递下去就行 @@ -88,7 +88,7 @@ def 启动微调(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt chatbot 聊天显示框的句柄,用于显示给用户 history 聊天历史,前情提要 system_prompt 给gpt的静默提醒 - user_request 当前用户的请求信息(IP地址等) + web_port 当前软件运行的端口号 """ import subprocess history = [] # 清空历史,以免输入溢出 diff --git a/crazy_functions/crazy_utils.py b/crazy_functions/crazy_utils.py index 9c8aeccb65f567aca3ce3c2bfda066bafd9c5cba..ee1ab9074add3ebcefa071e17c42e07c17f5be31 100644 --- a/crazy_functions/crazy_utils.py +++ b/crazy_functions/crazy_utils.py @@ -1,18 +1,18 @@ -from toolbox import update_ui, get_conf, trimmed_format_exc, get_max_token, Singleton +from toolbox import update_ui, get_conf, trimmed_format_exc, get_log_folder import threading import os import logging def input_clipping(inputs, history, max_token_limit): import numpy as np - from request_llms.bridge_all import model_info + from request_llm.bridge_all import model_info enc = model_info["gpt-3.5-turbo"]['tokenizer'] def get_token_num(txt): return len(enc.encode(txt, disallowed_special=())) mode = 'input-and-history' # 当 输入部分的token占比 小于 全文的一半时,只裁剪历史 input_token_num = get_token_num(inputs) - if input_token_num < max_token_limit//2: + if input_token_num < max_token_limit//2: mode = 'only-history' max_token_limit = max_token_limit - input_token_num @@ -21,7 +21,7 @@ def input_clipping(inputs, history, max_token_limit): n_token = get_token_num('\n'.join(everything)) everything_token = [get_token_num(e) for e in everything] delta = max(everything_token) // 16 # 截断时的颗粒度 - + while n_token > max_token_limit: where = np.argmax(everything_token) encoded = enc.encode(everything[where], disallowed_special=()) @@ -38,9 +38,9 @@ def input_clipping(inputs, history, max_token_limit): return inputs, history def request_gpt_model_in_new_thread_with_ui_alive( - inputs, inputs_show_user, llm_kwargs, + inputs, inputs_show_user, llm_kwargs, chatbot, history, sys_prompt, refresh_interval=0.2, - handle_token_exceed=True, + handle_token_exceed=True, retry_times_at_unknown_error=2, ): """ @@ -63,21 +63,18 @@ def request_gpt_model_in_new_thread_with_ui_alive( """ import time from concurrent.futures import ThreadPoolExecutor - from request_llms.bridge_all import predict_no_ui_long_connection + from request_llm.bridge_all import predict_no_ui_long_connection # 用户反馈 chatbot.append([inputs_show_user, ""]) yield from update_ui(chatbot=chatbot, history=[]) # 刷新界面 executor = ThreadPoolExecutor(max_workers=16) mutable = ["", time.time(), ""] - # 看门狗耐心 - watch_dog_patience = 5 - # 请求任务 def _req_gpt(inputs, history, sys_prompt): retry_op = retry_times_at_unknown_error exceeded_cnt = 0 while True: # watchdog error - if len(mutable) >= 2 and (time.time()-mutable[1]) > watch_dog_patience: + if len(mutable) >= 2 and (time.time()-mutable[1]) > 5: raise RuntimeError("检测到程序终止。") try: # 【第一种情况】:顺利完成 @@ -92,7 +89,7 @@ def request_gpt_model_in_new_thread_with_ui_alive( # 【选择处理】 尝试计算比例,尽可能多地保留文本 from toolbox import get_reduce_token_percent p_ratio, n_exceed = get_reduce_token_percent(str(token_exceeded_error)) - MAX_TOKEN = get_max_token(llm_kwargs) + MAX_TOKEN = 4096 EXCEED_ALLO = 512 + 512 * exceeded_cnt inputs, history = input_clipping(inputs, history, max_token_limit=MAX_TOKEN-EXCEED_ALLO) mutable[0] += f'[Local Message] 警告,文本过长将进行截断,Token溢出数:{n_exceed}。\n\n' @@ -139,13 +136,11 @@ def can_multi_process(llm): if llm.startswith('gpt-'): return True if llm.startswith('api2d-'): return True if llm.startswith('azure-'): return True - if llm.startswith('spark'): return True - if llm.startswith('zhipuai') or llm.startswith('glm-'): return True return False def request_gpt_model_multi_threads_with_very_awesome_ui_and_high_efficiency( - inputs_array, inputs_show_user_array, llm_kwargs, - chatbot, history_array, sys_prompt_array, + inputs_array, inputs_show_user_array, llm_kwargs, + chatbot, history_array, sys_prompt_array, refresh_interval=0.2, max_workers=-1, scroller_max_len=30, handle_token_exceed=True, show_user_at_complete=False, retry_times_at_unknown_error=2, @@ -179,17 +174,17 @@ def request_gpt_model_multi_threads_with_very_awesome_ui_and_high_efficiency( """ import time, random from concurrent.futures import ThreadPoolExecutor - from request_llms.bridge_all import predict_no_ui_long_connection + from request_llm.bridge_all import predict_no_ui_long_connection assert len(inputs_array) == len(history_array) assert len(inputs_array) == len(sys_prompt_array) if max_workers == -1: # 读取配置文件 - try: max_workers = get_conf('DEFAULT_WORKER_NUM') + try: max_workers, = get_conf('DEFAULT_WORKER_NUM') except: max_workers = 8 if max_workers <= 0: max_workers = 3 # 屏蔽掉 chatglm的多线程,可能会导致严重卡顿 if not can_multi_process(llm_kwargs['llm_model']): max_workers = 1 - + executor = ThreadPoolExecutor(max_workers=max_workers) n_frag = len(inputs_array) # 用户反馈 @@ -198,35 +193,33 @@ def request_gpt_model_multi_threads_with_very_awesome_ui_and_high_efficiency( # 跨线程传递 mutable = [["", time.time(), "等待中"] for _ in range(n_frag)] - # 看门狗耐心 - watch_dog_patience = 5 - # 子线程任务 def _req_gpt(index, inputs, history, sys_prompt): gpt_say = "" retry_op = retry_times_at_unknown_error exceeded_cnt = 0 mutable[index][2] = "执行中" - detect_timeout = lambda: len(mutable[index]) >= 2 and (time.time()-mutable[index][1]) > watch_dog_patience while True: # watchdog error - if detect_timeout(): raise RuntimeError("检测到程序终止。") + if len(mutable[index]) >= 2 and (time.time()-mutable[index][1]) > 5: + raise RuntimeError("检测到程序终止。") try: # 【第一种情况】:顺利完成 + # time.sleep(10); raise RuntimeError("测试") gpt_say = predict_no_ui_long_connection( - inputs=inputs, llm_kwargs=llm_kwargs, history=history, + inputs=inputs, llm_kwargs=llm_kwargs, history=history, sys_prompt=sys_prompt, observe_window=mutable[index], console_slience=True ) mutable[index][2] = "已成功" return gpt_say except ConnectionAbortedError as token_exceeded_error: - # 【第二种情况】:Token溢出 + # 【第二种情况】:Token溢出, if handle_token_exceed: exceeded_cnt += 1 # 【选择处理】 尝试计算比例,尽可能多地保留文本 from toolbox import get_reduce_token_percent p_ratio, n_exceed = get_reduce_token_percent(str(token_exceeded_error)) - MAX_TOKEN = get_max_token(llm_kwargs) + MAX_TOKEN = 4096 EXCEED_ALLO = 512 + 512 * exceeded_cnt inputs, history = input_clipping(inputs, history, max_token_limit=MAX_TOKEN-EXCEED_ALLO) gpt_say += f'[Local Message] 警告,文本过长将进行截断,Token溢出数:{n_exceed}。\n\n' @@ -241,12 +234,11 @@ def request_gpt_model_multi_threads_with_very_awesome_ui_and_high_efficiency( return gpt_say # 放弃 except: # 【第三种情况】:其他错误 - if detect_timeout(): raise RuntimeError("检测到程序终止。") tb_str = '```\n' + trimmed_format_exc() + '```' print(tb_str) gpt_say += f"[Local Message] 警告,线程{index}在执行过程中遭遇问题, Traceback:\n\n{tb_str}\n\n" if len(mutable[index][0]) > 0: gpt_say += "此线程失败前收到的回答:\n\n" + mutable[index][0] - if retry_op > 0: + if retry_op > 0: retry_op -= 1 wait = random.randint(5, 20) if ("Rate limit reached" in tb_str) or ("Too Many Requests" in tb_str): @@ -258,7 +250,6 @@ def request_gpt_model_multi_threads_with_very_awesome_ui_and_high_efficiency( for i in range(wait): mutable[index][2] = f"{fail_info}等待重试 {wait-i}"; time.sleep(1) # 开始重试 - if detect_timeout(): raise RuntimeError("检测到程序终止。") mutable[index][2] = f"重试中 {retry_times_at_unknown_error-retry_op}/{retry_times_at_unknown_error}" continue # 返回重试 else: @@ -284,11 +275,12 @@ def request_gpt_model_multi_threads_with_very_awesome_ui_and_high_efficiency( # 在前端打印些好玩的东西 for thread_index, _ in enumerate(worker_done): print_something_really_funny = "[ ...`"+mutable[thread_index][0][-scroller_max_len:].\ - replace('\n', '').replace('`', '.').replace(' ', '.').replace('
', '.....').replace('$', '.')+"`... ]" + replace('\n', '').replace('```', '...').replace( + ' ', '.').replace('
', '.....').replace('$', '.')+"`... ]" observe_win.append(print_something_really_funny) # 在前端打印些好玩的东西 - stat_str = ''.join([f'`{mutable[thread_index][2]}`: {obs}\n\n' - if not done else f'`{mutable[thread_index][2]}`\n\n' + stat_str = ''.join([f'`{mutable[thread_index][2]}`: {obs}\n\n' + if not done else f'`{mutable[thread_index][2]}`\n\n' for thread_index, done, obs in zip(range(len(worker_done)), worker_done, observe_win)]) # 在前端打印些好玩的东西 chatbot[-1] = [chatbot[-1][0], f'多线程操作已经开始,完成情况: \n\n{stat_str}' + ''.join(['.']*(cnt % 10+1))] @@ -302,17 +294,106 @@ def request_gpt_model_multi_threads_with_very_awesome_ui_and_high_efficiency( for inputs_show_user, f in zip(inputs_show_user_array, futures): gpt_res = f.result() gpt_response_collection.extend([inputs_show_user, gpt_res]) - + # 是否在结束时,在界面上显示结果 if show_user_at_complete: for inputs_show_user, f in zip(inputs_show_user_array, futures): gpt_res = f.result() chatbot.append([inputs_show_user, gpt_res]) yield from update_ui(chatbot=chatbot, history=[]) # 刷新界面 - time.sleep(0.5) + time.sleep(0.3) return gpt_response_collection +def breakdown_txt_to_satisfy_token_limit(txt, get_token_fn, limit): + def cut(txt_tocut, must_break_at_empty_line): # 递归 + if get_token_fn(txt_tocut) <= limit: + return [txt_tocut] + else: + lines = txt_tocut.split('\n') + estimated_line_cut = limit / get_token_fn(txt_tocut) * len(lines) + estimated_line_cut = int(estimated_line_cut) + for cnt in reversed(range(estimated_line_cut)): + if must_break_at_empty_line: + if lines[cnt] != "": + continue + print(cnt) + prev = "\n".join(lines[:cnt]) + post = "\n".join(lines[cnt:]) + if get_token_fn(prev) < limit: + break + if cnt == 0: + raise RuntimeError("存在一行极长的文本!") + # print(len(post)) + # 列表递归接龙 + result = [prev] + result.extend(cut(post, must_break_at_empty_line)) + return result + try: + return cut(txt, must_break_at_empty_line=True) + except RuntimeError: + return cut(txt, must_break_at_empty_line=False) + + +def force_breakdown(txt, limit, get_token_fn): + """ + 当无法用标点、空行分割时,我们用最暴力的方法切割 + """ + for i in reversed(range(len(txt))): + if get_token_fn(txt[:i]) < limit: + return txt[:i], txt[i:] + return "Tiktoken未知错误", "Tiktoken未知错误" + +def breakdown_txt_to_satisfy_token_limit_for_pdf(txt, get_token_fn, limit): + # 递归 + def cut(txt_tocut, must_break_at_empty_line, break_anyway=False): + if get_token_fn(txt_tocut) <= limit: + return [txt_tocut] + else: + lines = txt_tocut.split('\n') + estimated_line_cut = limit / get_token_fn(txt_tocut) * len(lines) + estimated_line_cut = int(estimated_line_cut) + cnt = 0 + for cnt in reversed(range(estimated_line_cut)): + if must_break_at_empty_line: + if lines[cnt] != "": + continue + prev = "\n".join(lines[:cnt]) + post = "\n".join(lines[cnt:]) + if get_token_fn(prev) < limit: + break + if cnt == 0: + if break_anyway: + prev, post = force_breakdown(txt_tocut, limit, get_token_fn) + else: + raise RuntimeError(f"存在一行极长的文本!{txt_tocut}") + # print(len(post)) + # 列表递归接龙 + result = [prev] + result.extend(cut(post, must_break_at_empty_line, break_anyway=break_anyway)) + return result + try: + # 第1次尝试,将双空行(\n\n)作为切分点 + return cut(txt, must_break_at_empty_line=True) + except RuntimeError: + try: + # 第2次尝试,将单空行(\n)作为切分点 + return cut(txt, must_break_at_empty_line=False) + except RuntimeError: + try: + # 第3次尝试,将英文句号(.)作为切分点 + res = cut(txt.replace('.', '。\n'), must_break_at_empty_line=False) # 这个中文的句号是故意的,作为一个标识而存在 + return [r.replace('。\n', '.') for r in res] + except RuntimeError as e: + try: + # 第4次尝试,将中文句号(。)作为切分点 + res = cut(txt.replace('。', '。。\n'), must_break_at_empty_line=False) + return [r.replace('。。\n', '。') for r in res] + except RuntimeError as e: + # 第5次尝试,没办法了,随便切一下敷衍吧 + return cut(txt, must_break_at_empty_line=False, break_anyway=True) + + def read_and_clean_pdf_text(fp): """ @@ -352,7 +433,7 @@ def read_and_clean_pdf_text(fp): if wtf['size'] not in fsize_statiscs: fsize_statiscs[wtf['size']] = 0 fsize_statiscs[wtf['size']] += len(wtf['text']) return max(fsize_statiscs, key=fsize_statiscs.get) - + def ffsize_same(a,b): """ 提取字体大小是否近似相等 @@ -388,7 +469,7 @@ def read_and_clean_pdf_text(fp): if index == 0: page_one_meta = [" ".join(["".join([wtf['text'] for wtf in l['spans']]) for l in t['lines']]).replace( '- ', '') for t in text_areas['blocks'] if 'lines' in t] - + ############################## <第 2 步,获取正文主字体> ################################## try: fsize_statiscs = {} @@ -404,7 +485,7 @@ def read_and_clean_pdf_text(fp): mega_sec = [] sec = [] for index, line in enumerate(meta_line): - if index == 0: + if index == 0: sec.append(line[fc]) continue if REMOVE_FOOT_NOTE: @@ -465,9 +546,6 @@ def read_and_clean_pdf_text(fp): return True else: return False - # 对于某些PDF会有第一个段落就以小写字母开头,为了避免索引错误将其更改为大写 - if starts_with_lowercase_word(meta_txt[0]): - meta_txt[0] = meta_txt[0].capitalize() for _ in range(100): for index, block_txt in enumerate(meta_txt): if starts_with_lowercase_word(block_txt): @@ -501,12 +579,12 @@ def get_files_from_everything(txt, type): # type='.md' """ 这个函数是用来获取指定目录下所有指定类型(如.md)的文件,并且对于网络上的文件,也可以获取它。 下面是对每个参数和返回值的说明: - 参数 - - txt: 路径或网址,表示要搜索的文件或者文件夹路径或网络上的文件。 + 参数 + - txt: 路径或网址,表示要搜索的文件或者文件夹路径或网络上的文件。 - type: 字符串,表示要搜索的文件类型。默认是.md。 - 返回值 - - success: 布尔值,表示函数是否成功执行。 - - file_manifest: 文件路径列表,里面包含以指定类型为后缀名的所有文件的绝对路径。 + 返回值 + - success: 布尔值,表示函数是否成功执行。 + - file_manifest: 文件路径列表,里面包含以指定类型为后缀名的所有文件的绝对路径。 - project_folder: 字符串,表示文件所在的文件夹路径。如果是网络上的文件,就是临时文件夹的路径。 该函数详细注释已添加,请确认是否满足您的需要。 """ @@ -518,7 +596,7 @@ def get_files_from_everything(txt, type): # type='.md' import requests from toolbox import get_conf from toolbox import get_log_folder, gen_time_str - proxies = get_conf('proxies') + proxies, = get_conf('proxies') try: r = requests.get(txt, proxies=proxies) except: @@ -546,6 +624,90 @@ def get_files_from_everything(txt, type): # type='.md' + +def Singleton(cls): + _instance = {} + + def _singleton(*args, **kargs): + if cls not in _instance: + _instance[cls] = cls(*args, **kargs) + return _instance[cls] + + return _singleton + + +@Singleton +class knowledge_archive_interface(): + def __init__(self) -> None: + self.threadLock = threading.Lock() + self.current_id = "" + self.kai_path = None + self.qa_handle = None + self.text2vec_large_chinese = None + + def get_chinese_text2vec(self): + if self.text2vec_large_chinese is None: + # < -------------------预热文本向量化模组--------------- > + from toolbox import ProxyNetworkActivate + print('Checking Text2vec ...') + from langchain.embeddings.huggingface import HuggingFaceEmbeddings + with ProxyNetworkActivate(): # 临时地激活代理网络 + self.text2vec_large_chinese = HuggingFaceEmbeddings(model_name="GanymedeNil/text2vec-large-chinese") + + return self.text2vec_large_chinese + + + def feed_archive(self, file_manifest, id="default"): + self.threadLock.acquire() + # import uuid + self.current_id = id + from zh_langchain import construct_vector_store + self.qa_handle, self.kai_path = construct_vector_store( + vs_id=self.current_id, + files=file_manifest, + sentence_size=100, + history=[], + one_conent="", + one_content_segmentation="", + text2vec = self.get_chinese_text2vec(), + ) + self.threadLock.release() + + def get_current_archive_id(self): + return self.current_id + + def get_loaded_file(self): + return self.qa_handle.get_loaded_file() + + def answer_with_archive_by_id(self, txt, id): + self.threadLock.acquire() + if not self.current_id == id: + self.current_id = id + from zh_langchain import construct_vector_store + self.qa_handle, self.kai_path = construct_vector_store( + vs_id=self.current_id, + files=[], + sentence_size=100, + history=[], + one_conent="", + one_content_segmentation="", + text2vec = self.get_chinese_text2vec(), + ) + VECTOR_SEARCH_SCORE_THRESHOLD = 0 + VECTOR_SEARCH_TOP_K = 4 + CHUNK_SIZE = 512 + resp, prompt = self.qa_handle.get_knowledge_based_conent_test( + query = txt, + vs_path = self.kai_path, + score_threshold=VECTOR_SEARCH_SCORE_THRESHOLD, + vector_search_top_k=VECTOR_SEARCH_TOP_K, + chunk_conent=True, + chunk_size=CHUNK_SIZE, + text2vec = self.get_chinese_text2vec(), + ) + self.threadLock.release() + return resp, prompt + @Singleton class nougat_interface(): def __init__(self): @@ -553,10 +715,8 @@ class nougat_interface(): def nougat_with_timeout(self, command, cwd, timeout=3600): import subprocess - from toolbox import ProxyNetworkActivate logging.info(f'正在执行命令 {command}') - with ProxyNetworkActivate("Nougat_Download"): - process = subprocess.Popen(command, shell=True, cwd=cwd, env=os.environ) + process = subprocess.Popen(command, shell=True, cwd=cwd) try: stdout, stderr = process.communicate(timeout=timeout) except subprocess.TimeoutExpired: @@ -570,7 +730,7 @@ class nougat_interface(): def NOUGAT_parse_pdf(self, fp, chatbot, history): from toolbox import update_ui_lastest_msg - yield from update_ui_lastest_msg("正在解析论文, 请稍候。进度:正在排队, 等待线程锁...", + yield from update_ui_lastest_msg("正在解析论文, 请稍候。进度:正在排队, 等待线程锁...", chatbot=chatbot, history=history, delay=0) self.threadLock.acquire() import glob, threading, os @@ -578,7 +738,7 @@ class nougat_interface(): dst = os.path.join(get_log_folder(plugin_name='nougat'), gen_time_str()) os.makedirs(dst) - yield from update_ui_lastest_msg("正在解析论文, 请稍候。进度:正在加载NOUGAT... (提示:首次运行需要花费较长时间下载NOUGAT参数)", + yield from update_ui_lastest_msg("正在解析论文, 请稍候。进度:正在加载NOUGAT... (提示:首次运行需要花费较长时间下载NOUGAT参数)", chatbot=chatbot, history=history, delay=0) self.nougat_with_timeout(f'nougat --out "{os.path.abspath(dst)}" "{os.path.abspath(fp)}"', os.getcwd(), timeout=3600) res = glob.glob(os.path.join(dst,'*.mmd')) @@ -601,8 +761,49 @@ def try_install_deps(deps, reload_m=[]): importlib.reload(__import__(m)) -def get_plugin_arg(plugin_kwargs, key, default): - # 如果参数是空的 - if (key in plugin_kwargs) and (plugin_kwargs[key] == ""): plugin_kwargs.pop(key) - # 正常情况 - return plugin_kwargs.get(key, default) +HTML_CSS = """ +.row { + display: flex; + flex-wrap: wrap; +} +.column { + flex: 1; + padding: 10px; +} +.table-header { + font-weight: bold; + border-bottom: 1px solid black; +} +.table-row { + border-bottom: 1px solid lightgray; +} +.table-cell { + padding: 5px; +} +""" + +TABLE_CSS = """ +
+
REPLACE_A
+
REPLACE_B
+
+""" + +class construct_html(): + def __init__(self) -> None: + self.css = HTML_CSS + self.html_string = f'翻译结果' + + + def add_row(self, a, b): + tmp = TABLE_CSS + from toolbox import markdown_convertion + tmp = tmp.replace('REPLACE_A', markdown_convertion(a)) + tmp = tmp.replace('REPLACE_B', markdown_convertion(b)) + self.html_string += tmp + + + def save_file(self, file_name): + with open(os.path.join(get_log_folder(), file_name), 'w', encoding='utf8') as f: + f.write(self.html_string.encode('utf-8', 'ignore').decode()) + return os.path.join(get_log_folder(), file_name) diff --git a/crazy_functions/diagram_fns/file_tree.py b/crazy_functions/diagram_fns/file_tree.py deleted file mode 100644 index fa7e2e4c4bf56329b0d6c8beb8c5de2cbdbce8b0..0000000000000000000000000000000000000000 --- a/crazy_functions/diagram_fns/file_tree.py +++ /dev/null @@ -1,122 +0,0 @@ -import os -from textwrap import indent - -class FileNode: - def __init__(self, name): - self.name = name - self.children = [] - self.is_leaf = False - self.level = 0 - self.parenting_ship = [] - self.comment = "" - self.comment_maxlen_show = 50 - - @staticmethod - def add_linebreaks_at_spaces(string, interval=10): - return '\n'.join(string[i:i+interval] for i in range(0, len(string), interval)) - - def sanitize_comment(self, comment): - if len(comment) > self.comment_maxlen_show: suf = '...' - else: suf = '' - comment = comment[:self.comment_maxlen_show] - comment = comment.replace('\"', '').replace('`', '').replace('\n', '').replace('`', '').replace('$', '') - comment = self.add_linebreaks_at_spaces(comment, 10) - return '`' + comment + suf + '`' - - def add_file(self, file_path, file_comment): - directory_names, file_name = os.path.split(file_path) - current_node = self - level = 1 - if directory_names == "": - new_node = FileNode(file_name) - current_node.children.append(new_node) - new_node.is_leaf = True - new_node.comment = self.sanitize_comment(file_comment) - new_node.level = level - current_node = new_node - else: - dnamesplit = directory_names.split(os.sep) - for i, directory_name in enumerate(dnamesplit): - found_child = False - level += 1 - for child in current_node.children: - if child.name == directory_name: - current_node = child - found_child = True - break - if not found_child: - new_node = FileNode(directory_name) - current_node.children.append(new_node) - new_node.level = level - 1 - current_node = new_node - term = FileNode(file_name) - term.level = level - term.comment = self.sanitize_comment(file_comment) - term.is_leaf = True - current_node.children.append(term) - - def print_files_recursively(self, level=0, code="R0"): - print(' '*level + self.name + ' ' + str(self.is_leaf) + ' ' + str(self.level)) - for j, child in enumerate(self.children): - child.print_files_recursively(level=level+1, code=code+str(j)) - self.parenting_ship.extend(child.parenting_ship) - p1 = f"""{code}[\"🗎{self.name}\"]""" if self.is_leaf else f"""{code}[[\"📁{self.name}\"]]""" - p2 = """ --> """ - p3 = f"""{code+str(j)}[\"🗎{child.name}\"]""" if child.is_leaf else f"""{code+str(j)}[[\"📁{child.name}\"]]""" - edge_code = p1 + p2 + p3 - if edge_code in self.parenting_ship: - continue - self.parenting_ship.append(edge_code) - if self.comment != "": - pc1 = f"""{code}[\"🗎{self.name}\"]""" if self.is_leaf else f"""{code}[[\"📁{self.name}\"]]""" - pc2 = f""" -.-x """ - pc3 = f"""C{code}[\"{self.comment}\"]:::Comment""" - edge_code = pc1 + pc2 + pc3 - self.parenting_ship.append(edge_code) - - -MERMAID_TEMPLATE = r""" -```mermaid -flowchart LR - %% 一个特殊标记,用于在生成mermaid图表时隐藏代码块 - classDef Comment stroke-dasharray: 5 5 - subgraph {graph_name} -{relationship} - end -``` -""" - -def build_file_tree_mermaid_diagram(file_manifest, file_comments, graph_name): - # Create the root node - file_tree_struct = FileNode("root") - # Build the tree structure - for file_path, file_comment in zip(file_manifest, file_comments): - file_tree_struct.add_file(file_path, file_comment) - file_tree_struct.print_files_recursively() - cc = "\n".join(file_tree_struct.parenting_ship) - ccc = indent(cc, prefix=" "*8) - return MERMAID_TEMPLATE.format(graph_name=graph_name, relationship=ccc) - -if __name__ == "__main__": - # File manifest - file_manifest = [ - "cradle_void_terminal.ipynb", - "tests/test_utils.py", - "tests/test_plugins.py", - "tests/test_llms.py", - "config.py", - "build/ChatGLM-6b-onnx-u8s8/chatglm-6b-int8-onnx-merged/model_weights_0.bin", - "crazy_functions/latex_fns/latex_actions.py", - "crazy_functions/latex_fns/latex_toolbox.py" - ] - file_comments = [ - "根据位置和名称,可能是一个模块的初始化文件根据位置和名称,可能是一个模块的初始化文件根据位置和名称,可能是一个模块的初始化文件", - "包含一些用于文本处理和模型微调的函数和装饰器包含一些用于文本处理和模型微调的函数和装饰器包含一些用于文本处理和模型微调的函数和装饰器", - "用于构建HTML报告的类和方法用于构建HTML报告的类和方法用于构建HTML报告的类和方法", - "包含了用于文本切分的函数,以及处理PDF文件的示例代码包含了用于文本切分的函数,以及处理PDF文件的示例代码包含了用于文本切分的函数,以及处理PDF文件的示例代码", - "用于解析和翻译PDF文件的功能和相关辅助函数用于解析和翻译PDF文件的功能和相关辅助函数用于解析和翻译PDF文件的功能和相关辅助函数", - "是一个包的初始化文件,用于初始化包的属性和导入模块是一个包的初始化文件,用于初始化包的属性和导入模块是一个包的初始化文件,用于初始化包的属性和导入模块", - "用于加载和分割文件中的文本的通用文件加载器用于加载和分割文件中的文本的通用文件加载器用于加载和分割文件中的文本的通用文件加载器", - "包含了用于构建和管理向量数据库的函数和类包含了用于构建和管理向量数据库的函数和类包含了用于构建和管理向量数据库的函数和类", - ] - print(build_file_tree_mermaid_diagram(file_manifest, file_comments, "项目文件树")) \ No newline at end of file diff --git a/crazy_functions/game_fns/game_ascii_art.py b/crazy_functions/game_fns/game_ascii_art.py deleted file mode 100644 index e0b700877415f04437413ac1765fa90fe1b0844f..0000000000000000000000000000000000000000 --- a/crazy_functions/game_fns/game_ascii_art.py +++ /dev/null @@ -1,42 +0,0 @@ -from toolbox import CatchException, update_ui, update_ui_lastest_msg -from crazy_functions.multi_stage.multi_stage_utils import GptAcademicGameBaseState -from crazy_functions.crazy_utils import request_gpt_model_in_new_thread_with_ui_alive -from request_llms.bridge_all import predict_no_ui_long_connection -from crazy_functions.game_fns.game_utils import get_code_block, is_same_thing -import random - - -class MiniGame_ASCII_Art(GptAcademicGameBaseState): - def step(self, prompt, chatbot, history): - if self.step_cnt == 0: - chatbot.append(["我画你猜(动物)", "请稍等..."]) - else: - if prompt.strip() == 'exit': - self.delete_game = True - yield from update_ui_lastest_msg(lastmsg=f"谜底是{self.obj},游戏结束。", chatbot=chatbot, history=history, delay=0.) - return - chatbot.append([prompt, ""]) - yield from update_ui(chatbot=chatbot, history=history) - - if self.step_cnt == 0: - self.lock_plugin(chatbot) - self.cur_task = 'draw' - - if self.cur_task == 'draw': - avail_obj = ["狗","猫","鸟","鱼","老鼠","蛇"] - self.obj = random.choice(avail_obj) - inputs = "I want to play a game called Guess the ASCII art. You can draw the ASCII art and I will try to guess it. " + \ - f"This time you draw a {self.obj}. Note that you must not indicate what you have draw in the text, and you should only produce the ASCII art wrapped by ```. " - raw_res = predict_no_ui_long_connection(inputs=inputs, llm_kwargs=self.llm_kwargs, history=[], sys_prompt="") - self.cur_task = 'identify user guess' - res = get_code_block(raw_res) - history += ['', f'the answer is {self.obj}', inputs, res] - yield from update_ui_lastest_msg(lastmsg=res, chatbot=chatbot, history=history, delay=0.) - - elif self.cur_task == 'identify user guess': - if is_same_thing(self.obj, prompt, self.llm_kwargs): - self.delete_game = True - yield from update_ui_lastest_msg(lastmsg="你猜对了!", chatbot=chatbot, history=history, delay=0.) - else: - self.cur_task = 'identify user guess' - yield from update_ui_lastest_msg(lastmsg="猜错了,再试试,输入“exit”获取答案。", chatbot=chatbot, history=history, delay=0.) \ No newline at end of file diff --git a/crazy_functions/game_fns/game_interactive_story.py b/crazy_functions/game_fns/game_interactive_story.py deleted file mode 100644 index 5c25f4a350409006ca7a4cd03f010d6b47eb044f..0000000000000000000000000000000000000000 --- a/crazy_functions/game_fns/game_interactive_story.py +++ /dev/null @@ -1,212 +0,0 @@ -prompts_hs = """ 请以“{headstart}”为开头,编写一个小说的第一幕。 - -- 尽量短,不要包含太多情节,因为你接下来将会与用户互动续写下面的情节,要留出足够的互动空间。 -- 出现人物时,给出人物的名字。 -- 积极地运用环境描写、人物描写等手法,让读者能够感受到你的故事世界。 -- 积极地运用修辞手法,比如比喻、拟人、排比、对偶、夸张等等。 -- 字数要求:第一幕的字数少于300字,且少于2个段落。 -""" - -prompts_interact = """ 小说的前文回顾: -「 -{previously_on_story} -」 - -你是一个作家,根据以上的情节,给出4种不同的后续剧情发展方向,每个发展方向都精明扼要地用一句话说明。稍后,我将在这4个选择中,挑选一种剧情发展。 - -输出格式例如: -1. 后续剧情发展1 -2. 后续剧情发展2 -3. 后续剧情发展3 -4. 后续剧情发展4 -""" - - -prompts_resume = """小说的前文回顾: -「 -{previously_on_story} -」 - -你是一个作家,我们正在互相讨论,确定后续剧情的发展。 -在以下的剧情发展中, -「 -{choice} -」 -我认为更合理的是:{user_choice}。 -请在前文的基础上(不要重复前文),围绕我选定的剧情情节,编写小说的下一幕。 - -- 禁止杜撰不符合我选择的剧情。 -- 尽量短,不要包含太多情节,因为你接下来将会与用户互动续写下面的情节,要留出足够的互动空间。 -- 不要重复前文。 -- 出现人物时,给出人物的名字。 -- 积极地运用环境描写、人物描写等手法,让读者能够感受到你的故事世界。 -- 积极地运用修辞手法,比如比喻、拟人、排比、对偶、夸张等等。 -- 小说的下一幕字数少于300字,且少于2个段落。 -""" - - -prompts_terminate = """小说的前文回顾: -「 -{previously_on_story} -」 - -你是一个作家,我们正在互相讨论,确定后续剧情的发展。 -现在,故事该结束了,我认为最合理的故事结局是:{user_choice}。 - -请在前文的基础上(不要重复前文),编写小说的最后一幕。 - -- 不要重复前文。 -- 出现人物时,给出人物的名字。 -- 积极地运用环境描写、人物描写等手法,让读者能够感受到你的故事世界。 -- 积极地运用修辞手法,比如比喻、拟人、排比、对偶、夸张等等。 -- 字数要求:最后一幕的字数少于1000字。 -""" - - -from toolbox import CatchException, update_ui, update_ui_lastest_msg -from crazy_functions.multi_stage.multi_stage_utils import GptAcademicGameBaseState -from crazy_functions.crazy_utils import request_gpt_model_in_new_thread_with_ui_alive -from request_llms.bridge_all import predict_no_ui_long_connection -from crazy_functions.game_fns.game_utils import get_code_block, is_same_thing -import random - - -class MiniGame_ResumeStory(GptAcademicGameBaseState): - story_headstart = [ - '先行者知道,他现在是全宇宙中唯一的一个人了。', - '深夜,一个年轻人穿过天安门广场向纪念堂走去。在二十二世纪编年史中,计算机把他的代号定为M102。', - '他知道,这最后一课要提前讲了。又一阵剧痛从肝部袭来,几乎使他晕厥过去。', - '在距地球五万光年的远方,在银河系的中心,一场延续了两万年的星际战争已接近尾声。那里的太空中渐渐隐现出一个方形区域,仿佛灿烂的群星的背景被剪出一个方口。', - '伊依一行三人乘坐一艘游艇在南太平洋上做吟诗航行,他们的目的地是南极,如果几天后能顺利到达那里,他们将钻出地壳去看诗云。', - '很多人生来就会莫名其妙地迷上一样东西,仿佛他的出生就是要和这东西约会似的,正是这样,圆圆迷上了肥皂泡。' - ] - - - def begin_game_step_0(self, prompt, chatbot, history): - # init game at step 0 - self.headstart = random.choice(self.story_headstart) - self.story = [] - chatbot.append(["互动写故事", f"这次的故事开头是:{self.headstart}"]) - self.sys_prompt_ = '你是一个想象力丰富的杰出作家。正在与你的朋友互动,一起写故事,因此你每次写的故事段落应少于300字(结局除外)。' - - - def generate_story_image(self, story_paragraph): - try: - from crazy_functions.图片生成 import gen_image - prompt_ = predict_no_ui_long_connection(inputs=story_paragraph, llm_kwargs=self.llm_kwargs, history=[], sys_prompt='你需要根据用户给出的小说段落,进行简短的环境描写。要求:80字以内。') - image_url, image_path = gen_image(self.llm_kwargs, prompt_, '512x512', model="dall-e-2", quality='standard', style='natural') - return f'
' - except: - return '' - - def step(self, prompt, chatbot, history): - - """ - 首先,处理游戏初始化等特殊情况 - """ - if self.step_cnt == 0: - self.begin_game_step_0(prompt, chatbot, history) - self.lock_plugin(chatbot) - self.cur_task = 'head_start' - else: - if prompt.strip() == 'exit' or prompt.strip() == '结束剧情': - # should we terminate game here? - self.delete_game = True - yield from update_ui_lastest_msg(lastmsg=f"游戏结束。", chatbot=chatbot, history=history, delay=0.) - return - if '剧情收尾' in prompt: - self.cur_task = 'story_terminate' - # # well, game resumes - # chatbot.append([prompt, ""]) - # update ui, don't keep the user waiting - yield from update_ui(chatbot=chatbot, history=history) - - - """ - 处理游戏的主体逻辑 - """ - if self.cur_task == 'head_start': - """ - 这是游戏的第一步 - """ - inputs_ = prompts_hs.format(headstart=self.headstart) - history_ = [] - story_paragraph = yield from request_gpt_model_in_new_thread_with_ui_alive( - inputs_, '故事开头', self.llm_kwargs, - chatbot, history_, self.sys_prompt_ - ) - self.story.append(story_paragraph) - # # 配图 - yield from update_ui_lastest_msg(lastmsg=story_paragraph + '
正在生成插图中 ...', chatbot=chatbot, history=history, delay=0.) - yield from update_ui_lastest_msg(lastmsg=story_paragraph + '
'+ self.generate_story_image(story_paragraph), chatbot=chatbot, history=history, delay=0.) - - # # 构建后续剧情引导 - previously_on_story = "" - for s in self.story: - previously_on_story += s + '\n' - inputs_ = prompts_interact.format(previously_on_story=previously_on_story) - history_ = [] - self.next_choices = yield from request_gpt_model_in_new_thread_with_ui_alive( - inputs_, '请在以下几种故事走向中,选择一种(当然,您也可以选择给出其他故事走向):', self.llm_kwargs, - chatbot, - history_, - self.sys_prompt_ - ) - self.cur_task = 'user_choice' - - - elif self.cur_task == 'user_choice': - """ - 根据用户的提示,确定故事的下一步 - """ - if '请在以下几种故事走向中,选择一种' in chatbot[-1][0]: chatbot.pop(-1) - previously_on_story = "" - for s in self.story: - previously_on_story += s + '\n' - inputs_ = prompts_resume.format(previously_on_story=previously_on_story, choice=self.next_choices, user_choice=prompt) - history_ = [] - story_paragraph = yield from request_gpt_model_in_new_thread_with_ui_alive( - inputs_, f'下一段故事(您的选择是:{prompt})。', self.llm_kwargs, - chatbot, history_, self.sys_prompt_ - ) - self.story.append(story_paragraph) - # # 配图 - yield from update_ui_lastest_msg(lastmsg=story_paragraph + '
正在生成插图中 ...', chatbot=chatbot, history=history, delay=0.) - yield from update_ui_lastest_msg(lastmsg=story_paragraph + '
'+ self.generate_story_image(story_paragraph), chatbot=chatbot, history=history, delay=0.) - - # # 构建后续剧情引导 - previously_on_story = "" - for s in self.story: - previously_on_story += s + '\n' - inputs_ = prompts_interact.format(previously_on_story=previously_on_story) - history_ = [] - self.next_choices = yield from request_gpt_model_in_new_thread_with_ui_alive( - inputs_, - '请在以下几种故事走向中,选择一种。当然,您也可以给出您心中的其他故事走向。另外,如果您希望剧情立即收尾,请输入剧情走向,并以“剧情收尾”四个字提示程序。', self.llm_kwargs, - chatbot, - history_, - self.sys_prompt_ - ) - self.cur_task = 'user_choice' - - - elif self.cur_task == 'story_terminate': - """ - 根据用户的提示,确定故事的结局 - """ - previously_on_story = "" - for s in self.story: - previously_on_story += s + '\n' - inputs_ = prompts_terminate.format(previously_on_story=previously_on_story, user_choice=prompt) - history_ = [] - story_paragraph = yield from request_gpt_model_in_new_thread_with_ui_alive( - inputs_, f'故事收尾(您的选择是:{prompt})。', self.llm_kwargs, - chatbot, history_, self.sys_prompt_ - ) - # # 配图 - yield from update_ui_lastest_msg(lastmsg=story_paragraph + '
正在生成插图中 ...', chatbot=chatbot, history=history, delay=0.) - yield from update_ui_lastest_msg(lastmsg=story_paragraph + '
'+ self.generate_story_image(story_paragraph), chatbot=chatbot, history=history, delay=0.) - - # terminate game - self.delete_game = True - return diff --git a/crazy_functions/game_fns/game_utils.py b/crazy_functions/game_fns/game_utils.py deleted file mode 100644 index 09b6f7a935f3e1f254c4cd0f3b74f78e4c2af298..0000000000000000000000000000000000000000 --- a/crazy_functions/game_fns/game_utils.py +++ /dev/null @@ -1,35 +0,0 @@ - -from crazy_functions.json_fns.pydantic_io import GptJsonIO, JsonStringError -from request_llms.bridge_all import predict_no_ui_long_connection -def get_code_block(reply): - import re - pattern = r"```([\s\S]*?)```" # regex pattern to match code blocks - matches = re.findall(pattern, reply) # find all code blocks in text - if len(matches) == 1: - return "```" + matches[0] + "```" # code block - raise RuntimeError("GPT is not generating proper code.") - -def is_same_thing(a, b, llm_kwargs): - from pydantic import BaseModel, Field - class IsSameThing(BaseModel): - is_same_thing: bool = Field(description="determine whether two objects are same thing.", default=False) - - def run_gpt_fn(inputs, sys_prompt, history=[]): - return predict_no_ui_long_connection( - inputs=inputs, llm_kwargs=llm_kwargs, - history=history, sys_prompt=sys_prompt, observe_window=[] - ) - - gpt_json_io = GptJsonIO(IsSameThing) - inputs_01 = "Identity whether the user input and the target is the same thing: \n target object: {a} \n user input object: {b} \n\n\n".format(a=a, b=b) - inputs_01 += "\n\n\n Note that the user may describe the target object with a different language, e.g. cat and 猫 are the same thing." - analyze_res_cot_01 = run_gpt_fn(inputs_01, "", []) - - inputs_02 = inputs_01 + gpt_json_io.format_instructions - analyze_res = run_gpt_fn(inputs_02, "", [inputs_01, analyze_res_cot_01]) - - try: - res = gpt_json_io.generate_output_auto_repair(analyze_res, run_gpt_fn) - return res.is_same_thing - except JsonStringError as e: - return False \ No newline at end of file diff --git a/crazy_functions/gen_fns/gen_fns_shared.py b/crazy_functions/gen_fns/gen_fns_shared.py deleted file mode 100644 index 8e73794e84437e861d3468d4f0ab799deae6d98c..0000000000000000000000000000000000000000 --- a/crazy_functions/gen_fns/gen_fns_shared.py +++ /dev/null @@ -1,70 +0,0 @@ -import time -import importlib -from toolbox import trimmed_format_exc, gen_time_str, get_log_folder -from toolbox import CatchException, update_ui, gen_time_str, trimmed_format_exc, is_the_upload_folder -from toolbox import promote_file_to_downloadzone, get_log_folder, update_ui_lastest_msg -import multiprocessing - -def get_class_name(class_string): - import re - # Use regex to extract the class name - class_name = re.search(r'class (\w+)\(', class_string).group(1) - return class_name - -def try_make_module(code, chatbot): - module_file = 'gpt_fn_' + gen_time_str().replace('-','_') - fn_path = f'{get_log_folder(plugin_name="gen_plugin_verify")}/{module_file}.py' - with open(fn_path, 'w', encoding='utf8') as f: f.write(code) - promote_file_to_downloadzone(fn_path, chatbot=chatbot) - class_name = get_class_name(code) - manager = multiprocessing.Manager() - return_dict = manager.dict() - p = multiprocessing.Process(target=is_function_successfully_generated, args=(fn_path, class_name, return_dict)) - # only has 10 seconds to run - p.start(); p.join(timeout=10) - if p.is_alive(): p.terminate(); p.join() - p.close() - return return_dict["success"], return_dict['traceback'] - -# check is_function_successfully_generated -def is_function_successfully_generated(fn_path, class_name, return_dict): - return_dict['success'] = False - return_dict['traceback'] = "" - try: - # Create a spec for the module - module_spec = importlib.util.spec_from_file_location('example_module', fn_path) - # Load the module - example_module = importlib.util.module_from_spec(module_spec) - module_spec.loader.exec_module(example_module) - # Now you can use the module - some_class = getattr(example_module, class_name) - # Now you can create an instance of the class - instance = some_class() - return_dict['success'] = True - return - except: - return_dict['traceback'] = trimmed_format_exc() - return - -def subprocess_worker(code, file_path, return_dict): - return_dict['result'] = None - return_dict['success'] = False - return_dict['traceback'] = "" - try: - module_file = 'gpt_fn_' + gen_time_str().replace('-','_') - fn_path = f'{get_log_folder(plugin_name="gen_plugin_run")}/{module_file}.py' - with open(fn_path, 'w', encoding='utf8') as f: f.write(code) - class_name = get_class_name(code) - # Create a spec for the module - module_spec = importlib.util.spec_from_file_location('example_module', fn_path) - # Load the module - example_module = importlib.util.module_from_spec(module_spec) - module_spec.loader.exec_module(example_module) - # Now you can use the module - some_class = getattr(example_module, class_name) - # Now you can create an instance of the class - instance = some_class() - return_dict['result'] = instance.run(file_path) - return_dict['success'] = True - except: - return_dict['traceback'] = trimmed_format_exc() diff --git a/crazy_functions/ipc_fns/mp.py b/crazy_functions/ipc_fns/mp.py deleted file mode 100644 index 575d47ccecbb775205193085c58c06a114d3bfc2..0000000000000000000000000000000000000000 --- a/crazy_functions/ipc_fns/mp.py +++ /dev/null @@ -1,37 +0,0 @@ -import platform -import pickle -import multiprocessing - -def run_in_subprocess_wrapper_func(v_args): - func, args, kwargs, return_dict, exception_dict = pickle.loads(v_args) - import sys - try: - result = func(*args, **kwargs) - return_dict['result'] = result - except Exception as e: - exc_info = sys.exc_info() - exception_dict['exception'] = exc_info - -def run_in_subprocess_with_timeout(func, timeout=60): - if platform.system() == 'Linux': - def wrapper(*args, **kwargs): - return_dict = multiprocessing.Manager().dict() - exception_dict = multiprocessing.Manager().dict() - v_args = pickle.dumps((func, args, kwargs, return_dict, exception_dict)) - process = multiprocessing.Process(target=run_in_subprocess_wrapper_func, args=(v_args,)) - process.start() - process.join(timeout) - if process.is_alive(): - process.terminate() - raise TimeoutError(f'功能单元{str(func)}未能在规定时间内完成任务') - process.close() - if 'exception' in exception_dict: - # ooops, the subprocess ran into an exception - exc_info = exception_dict['exception'] - raise exc_info[1].with_traceback(exc_info[2]) - if 'result' in return_dict.keys(): - # If the subprocess ran successfully, return the result - return return_dict['result'] - return wrapper - else: - return func \ No newline at end of file diff --git a/crazy_functions/latex_fns/latex_actions.py b/crazy_functions/latex_fns/latex_actions.py index 8772f5e1fb530d72be282deaef2eb18ed9ffa1d2..dcde0e994e7a8890e0f4dd5c9006a96e2071d5c9 100644 --- a/crazy_functions/latex_fns/latex_actions.py +++ b/crazy_functions/latex_fns/latex_actions.py @@ -1,10 +1,9 @@ from toolbox import update_ui, update_ui_lastest_msg, get_log_folder -from toolbox import get_conf, objdump, objload, promote_file_to_downloadzone +from toolbox import zip_folder, objdump, objload, promote_file_to_downloadzone from .latex_toolbox import PRESERVE, TRANSFORM from .latex_toolbox import set_forbidden_text, set_forbidden_text_begin_end, set_forbidden_text_careful_brace from .latex_toolbox import reverse_forbidden_text_careful_brace, reverse_forbidden_text, convert_to_linklist, post_process from .latex_toolbox import fix_content, find_main_tex_file, merge_tex_files, compile_latex_with_timeout -from .latex_toolbox import find_title_and_abs import os, shutil import re @@ -91,18 +90,7 @@ class LatexPaperSplit(): "项目Github地址 \\url{https://github.com/binary-husky/gpt_academic/}。" # 请您不要删除或修改这行警告,除非您是论文的原作者(如果您是论文原作者,欢迎加REAME中的QQ联系开发者) self.msg_declare = "为了防止大语言模型的意外谬误产生扩散影响,禁止移除或修改此警告。}}\\\\" - self.title = "unknown" - self.abstract = "unknown" - - def read_title_and_abstract(self, txt): - try: - title, abstract = find_title_and_abs(txt) - if title is not None: - self.title = title.replace('\n', ' ').replace('\\\\', ' ').replace(' ', '').replace(' ', '') - if abstract is not None: - self.abstract = abstract.replace('\n', ' ').replace('\\\\', ' ').replace(' ', '').replace(' ', '') - except: - pass + def merge_result(self, arr, mode, msg, buggy_lines=[], buggy_line_surgery_n_lines=10): """ @@ -175,8 +163,9 @@ class LatexPaperFileGroup(): self.sp_file_contents = [] self.sp_file_index = [] self.sp_file_tag = [] + # count_token - from request_llms.bridge_all import model_info + from request_llm.bridge_all import model_info enc = model_info["gpt-3.5-turbo"]['tokenizer'] def get_token_num(txt): return len(enc.encode(txt, disallowed_special=())) self.get_token_num = get_token_num @@ -191,12 +180,13 @@ class LatexPaperFileGroup(): self.sp_file_index.append(index) self.sp_file_tag.append(self.file_paths[index]) else: - from crazy_functions.pdf_fns.breakdown_txt import breakdown_text_to_satisfy_token_limit - segments = breakdown_text_to_satisfy_token_limit(file_content, max_token_limit) + from ..crazy_utils import breakdown_txt_to_satisfy_token_limit_for_pdf + segments = breakdown_txt_to_satisfy_token_limit_for_pdf(file_content, self.get_token_num, max_token_limit) for j, segment in enumerate(segments): self.sp_file_contents.append(segment) self.sp_file_index.append(index) self.sp_file_tag.append(self.file_paths[index] + f".part-{j}.tex") + print('Segmentation: done') def merge_result(self): self.file_result = ["" for _ in range(len(self.file_paths))] @@ -244,8 +234,8 @@ def Latex精细分解与转化(file_manifest, project_folder, llm_kwargs, plugin chatbot.append((f"Latex文件融合完成", f'[Local Message] 正在精细切分latex文件,这需要一段时间计算,文档越长耗时越长,请耐心等待。')) yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 lps = LatexPaperSplit() - lps.read_title_and_abstract(merged_content) res = lps.split(merged_content, project_folder, opts) # 消耗时间的函数 + # <-------- 拆分过长的latex片段 ----------> pfg = LatexPaperFileGroup() for index, r in enumerate(res): @@ -266,19 +256,12 @@ def Latex精细分解与转化(file_manifest, project_folder, llm_kwargs, plugin else: # <-------- gpt 多线程请求 ----------> - history_array = [[""] for _ in range(n_split)] - # LATEX_EXPERIMENTAL, = get_conf('LATEX_EXPERIMENTAL') - # if LATEX_EXPERIMENTAL: - # paper_meta = f"The paper you processing is `{lps.title}`, a part of the abstraction is `{lps.abstract}`" - # paper_meta_max_len = 888 - # history_array = [[ paper_meta[:paper_meta_max_len] + '...', "Understand, what should I do?"] for _ in range(n_split)] - gpt_response_collection = yield from request_gpt_model_multi_threads_with_very_awesome_ui_and_high_efficiency( inputs_array=inputs_array, inputs_show_user_array=inputs_show_user_array, llm_kwargs=llm_kwargs, chatbot=chatbot, - history_array=history_array, + history_array=[[""] for _ in range(n_split)], sys_prompt_array=sys_prompt_array, # max_workers=5, # 并行任务数量限制, 最多同时执行5个, 其他的排队等待 scroller_max_len = 40 @@ -402,7 +385,7 @@ def 编译Latex(chatbot, history, main_file_original, main_file_modified, work_f result_pdf = pj(work_folder_modified, f'merge_diff.pdf') # get pdf path promote_file_to_downloadzone(result_pdf, rename_file=None, chatbot=chatbot) # promote file to web UI if modified_pdf_success: - yield from update_ui_lastest_msg(f'转化PDF编译已经成功, 正在尝试生成对比PDF, 请稍候 ...', chatbot, history) # 刷新Gradio前端界面 + yield from update_ui_lastest_msg(f'转化PDF编译已经成功, 即将退出 ...', chatbot, history) # 刷新Gradio前端界面 result_pdf = pj(work_folder_modified, f'{main_file_modified}.pdf') # get pdf path origin_pdf = pj(work_folder_original, f'{main_file_original}.pdf') # get pdf path if os.path.exists(pj(work_folder, '..', 'translation')): @@ -414,11 +397,8 @@ def 编译Latex(chatbot, history, main_file_original, main_file_modified, work_f from .latex_toolbox import merge_pdfs concat_pdf = pj(work_folder_modified, f'comparison.pdf') merge_pdfs(origin_pdf, result_pdf, concat_pdf) - if os.path.exists(pj(work_folder, '..', 'translation')): - shutil.copyfile(concat_pdf, pj(work_folder, '..', 'translation', 'comparison.pdf')) promote_file_to_downloadzone(concat_pdf, rename_file=None, chatbot=chatbot) # promote file to web UI except Exception as e: - print(e) pass return True # 成功啦 else: @@ -443,7 +423,7 @@ def write_html(sp_file_contents, sp_file_result, chatbot, project_folder): # write html try: import shutil - from crazy_functions.pdf_fns.report_gen_html import construct_html + from ..crazy_utils import construct_html from toolbox import gen_time_str ch = construct_html() orig = "" diff --git a/crazy_functions/latex_fns/latex_toolbox.py b/crazy_functions/latex_fns/latex_toolbox.py index bbd1bb3c6b85a9731912388f187b248a626ffd52..c733c81887e19b130f2dbd4817359c9287a007c3 100644 --- a/crazy_functions/latex_fns/latex_toolbox.py +++ b/crazy_functions/latex_fns/latex_toolbox.py @@ -1,18 +1,15 @@ import os, shutil import re import numpy as np - PRESERVE = 0 TRANSFORM = 1 pj = os.path.join - -class LinkedListNode: +class LinkedListNode(): """ Linked List Node """ - def __init__(self, string, preserve=True) -> None: self.string = string self.preserve = preserve @@ -21,47 +18,41 @@ class LinkedListNode: # self.begin_line = 0 # self.begin_char = 0 - def convert_to_linklist(text, mask): root = LinkedListNode("", preserve=True) current_node = root for c, m, i in zip(text, mask, range(len(text))): - if (m == PRESERVE and current_node.preserve) or ( - m == TRANSFORM and not current_node.preserve - ): + if (m==PRESERVE and current_node.preserve) \ + or (m==TRANSFORM and not current_node.preserve): # add current_node.string += c else: - current_node.next = LinkedListNode(c, preserve=(m == PRESERVE)) + current_node.next = LinkedListNode(c, preserve=(m==PRESERVE)) current_node = current_node.next return root - def post_process(root): # 修复括号 node = root while True: string = node.string - if node.preserve: + if node.preserve: node = node.next - if node is None: - break + if node is None: break continue - def break_check(string): - str_stack = [""] # (lv, index) + str_stack = [""] # (lv, index) for i, c in enumerate(string): - if c == "{": - str_stack.append("{") - elif c == "}": + if c == '{': + str_stack.append('{') + elif c == '}': if len(str_stack) == 1: - print("stack fix") + print('stack fix') return i str_stack.pop(-1) else: str_stack[-1] += c return -1 - bp = break_check(string) if bp == -1: @@ -78,66 +69,51 @@ def post_process(root): node.next = q node = node.next - if node is None: - break + if node is None: break # 屏蔽空行和太短的句子 node = root while True: - if len(node.string.strip("\n").strip("")) == 0: - node.preserve = True - if len(node.string.strip("\n").strip("")) < 42: - node.preserve = True + if len(node.string.strip('\n').strip(''))==0: node.preserve = True + if len(node.string.strip('\n').strip(''))<42: node.preserve = True node = node.next - if node is None: - break + if node is None: break node = root while True: if node.next and node.preserve and node.next.preserve: node.string += node.next.string node.next = node.next.next node = node.next - if node is None: - break + if node is None: break # 将前后断行符脱离 node = root prev_node = None while True: if not node.preserve: - lstriped_ = node.string.lstrip().lstrip("\n") - if ( - (prev_node is not None) - and (prev_node.preserve) - and (len(lstriped_) != len(node.string)) - ): - prev_node.string += node.string[: -len(lstriped_)] + lstriped_ = node.string.lstrip().lstrip('\n') + if (prev_node is not None) and (prev_node.preserve) and (len(lstriped_)!=len(node.string)): + prev_node.string += node.string[:-len(lstriped_)] node.string = lstriped_ - rstriped_ = node.string.rstrip().rstrip("\n") - if ( - (node.next is not None) - and (node.next.preserve) - and (len(rstriped_) != len(node.string)) - ): - node.next.string = node.string[len(rstriped_) :] + node.next.string + rstriped_ = node.string.rstrip().rstrip('\n') + if (node.next is not None) and (node.next.preserve) and (len(rstriped_)!=len(node.string)): + node.next.string = node.string[len(rstriped_):] + node.next.string node.string = rstriped_ - # =-=-= + # ===== prev_node = node node = node.next - if node is None: - break + if node is None: break # 标注节点的行数范围 node = root n_line = 0 expansion = 2 while True: - n_l = node.string.count("\n") - node.range = [n_line - expansion, n_line + n_l + expansion] # 失败时,扭转的范围 - n_line = n_line + n_l + n_l = node.string.count('\n') + node.range = [n_line-expansion, n_line+n_l+expansion] # 失败时,扭转的范围 + n_line = n_line+n_l node = node.next - if node is None: - break + if node is None: break return root @@ -152,125 +128,97 @@ def set_forbidden_text(text, mask, pattern, flags=0): """ Add a preserve text area in this paper e.g. with pattern = r"\\begin\{algorithm\}(.*?)\\end\{algorithm\}" - you can mask out (mask = PRESERVE so that text become untouchable for GPT) + you can mask out (mask = PRESERVE so that text become untouchable for GPT) everything between "\begin{equation}" and "\end{equation}" """ - if isinstance(pattern, list): - pattern = "|".join(pattern) + if isinstance(pattern, list): pattern = '|'.join(pattern) pattern_compile = re.compile(pattern, flags) for res in pattern_compile.finditer(text): - mask[res.span()[0] : res.span()[1]] = PRESERVE + mask[res.span()[0]:res.span()[1]] = PRESERVE return text, mask - def reverse_forbidden_text(text, mask, pattern, flags=0, forbid_wrapper=True): """ Move area out of preserve area (make text editable for GPT) - count the number of the braces so as to catch compelete text area. + count the number of the braces so as to catch compelete text area. e.g. - \begin{abstract} blablablablablabla. \end{abstract} + \begin{abstract} blablablablablabla. \end{abstract} """ - if isinstance(pattern, list): - pattern = "|".join(pattern) + if isinstance(pattern, list): pattern = '|'.join(pattern) pattern_compile = re.compile(pattern, flags) for res in pattern_compile.finditer(text): if not forbid_wrapper: - mask[res.span()[0] : res.span()[1]] = TRANSFORM + mask[res.span()[0]:res.span()[1]] = TRANSFORM else: - mask[res.regs[0][0] : res.regs[1][0]] = PRESERVE # '\\begin{abstract}' - mask[res.regs[1][0] : res.regs[1][1]] = TRANSFORM # abstract - mask[res.regs[1][1] : res.regs[0][1]] = PRESERVE # abstract + mask[res.regs[0][0]: res.regs[1][0]] = PRESERVE # '\\begin{abstract}' + mask[res.regs[1][0]: res.regs[1][1]] = TRANSFORM # abstract + mask[res.regs[1][1]: res.regs[0][1]] = PRESERVE # abstract return text, mask - def set_forbidden_text_careful_brace(text, mask, pattern, flags=0): """ Add a preserve text area in this paper (text become untouchable for GPT). - count the number of the braces so as to catch compelete text area. + count the number of the braces so as to catch compelete text area. e.g. - \caption{blablablablabla\texbf{blablabla}blablabla.} + \caption{blablablablabla\texbf{blablabla}blablabla.} """ pattern_compile = re.compile(pattern, flags) for res in pattern_compile.finditer(text): brace_level = -1 p = begin = end = res.regs[0][0] - for _ in range(1024 * 16): - if text[p] == "}" and brace_level == 0: - break - elif text[p] == "}": - brace_level -= 1 - elif text[p] == "{": - brace_level += 1 + for _ in range(1024*16): + if text[p] == '}' and brace_level == 0: break + elif text[p] == '}': brace_level -= 1 + elif text[p] == '{': brace_level += 1 p += 1 - end = p + 1 + end = p+1 mask[begin:end] = PRESERVE return text, mask - -def reverse_forbidden_text_careful_brace( - text, mask, pattern, flags=0, forbid_wrapper=True -): +def reverse_forbidden_text_careful_brace(text, mask, pattern, flags=0, forbid_wrapper=True): """ Move area out of preserve area (make text editable for GPT) - count the number of the braces so as to catch compelete text area. + count the number of the braces so as to catch compelete text area. e.g. - \caption{blablablablabla\texbf{blablabla}blablabla.} + \caption{blablablablabla\texbf{blablabla}blablabla.} """ pattern_compile = re.compile(pattern, flags) for res in pattern_compile.finditer(text): brace_level = 0 p = begin = end = res.regs[1][0] - for _ in range(1024 * 16): - if text[p] == "}" and brace_level == 0: - break - elif text[p] == "}": - brace_level -= 1 - elif text[p] == "{": - brace_level += 1 + for _ in range(1024*16): + if text[p] == '}' and brace_level == 0: break + elif text[p] == '}': brace_level -= 1 + elif text[p] == '{': brace_level += 1 p += 1 end = p mask[begin:end] = TRANSFORM if forbid_wrapper: - mask[res.regs[0][0] : begin] = PRESERVE - mask[end : res.regs[0][1]] = PRESERVE + mask[res.regs[0][0]:begin] = PRESERVE + mask[end:res.regs[0][1]] = PRESERVE return text, mask - def set_forbidden_text_begin_end(text, mask, pattern, flags=0, limit_n_lines=42): """ Find all \begin{} ... \end{} text block that with less than limit_n_lines lines. Add it to preserve area """ pattern_compile = re.compile(pattern, flags) - def search_with_line_limit(text, mask): for res in pattern_compile.finditer(text): cmd = res.group(1) # begin{what} - this = res.group(2) # content between begin and end - this_mask = mask[res.regs[2][0] : res.regs[2][1]] - white_list = [ - "document", - "abstract", - "lemma", - "definition", - "sproof", - "em", - "emph", - "textit", - "textbf", - "itemize", - "enumerate", - ] - if (cmd in white_list) or this.count( - "\n" - ) >= limit_n_lines: # use a magical number 42 + this = res.group(2) # content between begin and end + this_mask = mask[res.regs[2][0]:res.regs[2][1]] + white_list = ['document', 'abstract', 'lemma', 'definition', 'sproof', + 'em', 'emph', 'textit', 'textbf', 'itemize', 'enumerate'] + if (cmd in white_list) or this.count('\n') >= limit_n_lines: # use a magical number 42 this, this_mask = search_with_line_limit(this, this_mask) - mask[res.regs[2][0] : res.regs[2][1]] = this_mask + mask[res.regs[2][0]:res.regs[2][1]] = this_mask else: - mask[res.regs[0][0] : res.regs[0][1]] = PRESERVE + mask[res.regs[0][0]:res.regs[0][1]] = PRESERVE return text, mask + return search_with_line_limit(text, mask) - return search_with_line_limit(text, mask) """ @@ -279,7 +227,6 @@ Latex Merge File =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= """ - def find_main_tex_file(file_manifest, mode): """ 在多Tex文档中,寻找主文件,必须包含documentclass,返回找到的第一个。 @@ -287,36 +234,27 @@ def find_main_tex_file(file_manifest, mode): """ canidates = [] for texf in file_manifest: - if os.path.basename(texf).startswith("merge"): + if os.path.basename(texf).startswith('merge'): continue - with open(texf, "r", encoding="utf8", errors="ignore") as f: + with open(texf, 'r', encoding='utf8', errors='ignore') as f: file_content = f.read() - if r"\documentclass" in file_content: + if r'\documentclass' in file_content: canidates.append(texf) else: continue if len(canidates) == 0: - raise RuntimeError("无法找到一个主Tex文件(包含documentclass关键字)") + raise RuntimeError('无法找到一个主Tex文件(包含documentclass关键字)') elif len(canidates) == 1: return canidates[0] - else: # if len(canidates) >= 2 通过一些Latex模板中常见(但通常不会出现在正文)的单词,对不同latex源文件扣分,取评分最高者返回 + else: # if len(canidates) >= 2 通过一些Latex模板中常见(但通常不会出现在正文)的单词,对不同latex源文件扣分,取评分最高者返回 canidates_score = [] # 给出一些判定模板文档的词作为扣分项 - unexpected_words = [ - "\\LaTeX", - "manuscript", - "Guidelines", - "font", - "citations", - "rejected", - "blind review", - "reviewers", - ] - expected_words = ["\\input", "\\ref", "\\cite"] + unexpected_words = ['\LaTeX', 'manuscript', 'Guidelines', 'font', 'citations', 'rejected', 'blind review', 'reviewers'] + expected_words = ['\input', '\ref', '\cite'] for texf in canidates: canidates_score.append(0) - with open(texf, "r", encoding="utf8", errors="ignore") as f: + with open(texf, 'r', encoding='utf8', errors='ignore') as f: file_content = f.read() file_content = rm_comments(file_content) for uw in unexpected_words: @@ -325,10 +263,9 @@ def find_main_tex_file(file_manifest, mode): for uw in expected_words: if uw in file_content: canidates_score[-1] += 1 - select = np.argmax(canidates_score) # 取评分最高者返回 + select = np.argmax(canidates_score) # 取评分最高者返回 return canidates[select] - - + def rm_comments(main_file): new_file_remove_comment_lines = [] for l in main_file.splitlines(): @@ -337,39 +274,30 @@ def rm_comments(main_file): pass else: new_file_remove_comment_lines.append(l) - main_file = "\n".join(new_file_remove_comment_lines) + main_file = '\n'.join(new_file_remove_comment_lines) # main_file = re.sub(r"\\include{(.*?)}", r"\\input{\1}", main_file) # 将 \include 命令转换为 \input 命令 - main_file = re.sub(r"(? 0 and node_string.count("\_") > final_tex.count("\_"): + final_tex = node_string # 出问题了,还原原文 + if node_string.count('\\begin') != final_tex.count('\\begin'): + final_tex = node_string # 出问题了,还原原文 + if node_string.count('\_') > 0 and node_string.count('\_') > final_tex.count('\_'): # walk and replace any _ without \ final_tex = re.sub(r"(? 0xFFFFFFFF: - raise ValueError("Data exceeds wave file size limit") - if add_header: - fid.write(header_data) - # data chunk - fid.write(b'data') - fid.write(struct.pack('' or (data.dtype.byteorder == '=' and - sys.byteorder == 'big'): - data = data.byteswap() - _array_tofile(fid, data) - - if add_header: - # Determine file size and place it in correct - # position at start of the file. - size = fid.tell() - fid.seek(4) - fid.write(struct.pack(' 16000 - write_numpy_to_wave(temp_file, NEW_SAMPLERATE, dsdata) + io.wavfile.write(temp_file, NEW_SAMPLERATE, dsdata) # read pcm binary with open(temp_file, "rb") as f: data = f.read() - is_speaking, info = is_speaker_speaking(vad, data, NEW_SAMPLERATE) - - if is_speaking or echo_cnt > 0: - # 如果话筒激活 / 如果处于回声收尾阶段 - echo_cnt -= 1 - if not is_previous_frame_transmitted: # 上一帧没有人声,但是我们把上一帧同样加上 - if previous_frame_data is not None: data = previous_frame_data + data - if is_speaking: - echo_cnt = echo_cnt_max - slices = zip(*(iter(data),) * 640) # 640个字节为一组 - for i in slices: sr.send_audio(bytes(i)) - keep_alive_last_send_time = time.time() - is_previous_frame_transmitted = True - else: - is_previous_frame_transmitted = False - echo_cnt = 0 - # 保持链接激活,即使没有声音,也根据时间间隔,发送一些音频片段给服务器 - if time.time() - keep_alive_last_send_time > timeout_limit_second/2: - slices = zip(*(iter(data),) * 640) # 640个字节为一组 - for i in slices: sr.send_audio(bytes(i)) - keep_alive_last_send_time = time.time() - is_previous_frame_transmitted = True - self.audio_shape = info + # print('audio len:', len(audio), '\t ds len:', len(dsdata), '\t need n send:', len(data)//640) + slices = zip(*(iter(data),) * 640) # 640个字节为一组 + for i in slices: sr.send_audio(bytes(i)) else: time.sleep(0.1) diff --git a/crazy_functions/live_audio/audio_io.py b/crazy_functions/live_audio/audio_io.py index 00fd3f2d846ccf20eb300b796bb91842315e3482..3ff83a66e8d9f0bb15250f1c3c2b5ea36745ff55 100644 --- a/crazy_functions/live_audio/audio_io.py +++ b/crazy_functions/live_audio/audio_io.py @@ -35,7 +35,7 @@ class RealtimeAudioDistribution(): def read(self, uuid): if uuid in self.data: res = self.data.pop(uuid) - # print('\r read-', len(res), '-', max(res), end='', flush=True) + print('\r read-', len(res), '-', max(res), end='', flush=True) else: res = None return res diff --git a/crazy_functions/multi_stage/multi_stage_utils.py b/crazy_functions/multi_stage/multi_stage_utils.py deleted file mode 100644 index 1395e79ff132de3622d2dd3b3867f3916399e061..0000000000000000000000000000000000000000 --- a/crazy_functions/multi_stage/multi_stage_utils.py +++ /dev/null @@ -1,93 +0,0 @@ -from pydantic import BaseModel, Field -from typing import List -from toolbox import update_ui_lastest_msg, disable_auto_promotion -from toolbox import CatchException, update_ui, get_conf, select_api_key, get_log_folder -from request_llms.bridge_all import predict_no_ui_long_connection -from crazy_functions.json_fns.pydantic_io import GptJsonIO, JsonStringError -import time -import pickle - -def have_any_recent_upload_files(chatbot): - _5min = 5 * 60 - if not chatbot: return False # chatbot is None - most_recent_uploaded = chatbot._cookies.get("most_recent_uploaded", None) - if not most_recent_uploaded: return False # most_recent_uploaded is None - if time.time() - most_recent_uploaded["time"] < _5min: return True # most_recent_uploaded is new - else: return False # most_recent_uploaded is too old - -class GptAcademicState(): - def __init__(self): - self.reset() - - def reset(self): - pass - - def dump_state(self, chatbot): - chatbot._cookies['plugin_state'] = pickle.dumps(self) - - def set_state(self, chatbot, key, value): - setattr(self, key, value) - chatbot._cookies['plugin_state'] = pickle.dumps(self) - - def get_state(chatbot, cls=None): - state = chatbot._cookies.get('plugin_state', None) - if state is not None: state = pickle.loads(state) - elif cls is not None: state = cls() - else: state = GptAcademicState() - state.chatbot = chatbot - return state - - -class GptAcademicGameBaseState(): - """ - 1. first init: __init__ -> - """ - def init_game(self, chatbot, lock_plugin): - self.plugin_name = None - self.callback_fn = None - self.delete_game = False - self.step_cnt = 0 - - def lock_plugin(self, chatbot): - if self.callback_fn is None: - raise ValueError("callback_fn is None") - chatbot._cookies['lock_plugin'] = self.callback_fn - self.dump_state(chatbot) - - def get_plugin_name(self): - if self.plugin_name is None: - raise ValueError("plugin_name is None") - return self.plugin_name - - def dump_state(self, chatbot): - chatbot._cookies[f'plugin_state/{self.get_plugin_name()}'] = pickle.dumps(self) - - def set_state(self, chatbot, key, value): - setattr(self, key, value) - chatbot._cookies[f'plugin_state/{self.get_plugin_name()}'] = pickle.dumps(self) - - @staticmethod - def sync_state(chatbot, llm_kwargs, cls, plugin_name, callback_fn, lock_plugin=True): - state = chatbot._cookies.get(f'plugin_state/{plugin_name}', None) - if state is not None: - state = pickle.loads(state) - else: - state = cls() - state.init_game(chatbot, lock_plugin) - state.plugin_name = plugin_name - state.llm_kwargs = llm_kwargs - state.chatbot = chatbot - state.callback_fn = callback_fn - return state - - def continue_game(self, prompt, chatbot, history): - # 游戏主体 - yield from self.step(prompt, chatbot, history) - self.step_cnt += 1 - # 保存状态,收尾 - self.dump_state(chatbot) - # 如果游戏结束,清理 - if self.delete_game: - chatbot._cookies['lock_plugin'] = None - chatbot._cookies[f'plugin_state/{self.get_plugin_name()}'] = None - yield from update_ui(chatbot=chatbot, history=history) diff --git a/crazy_functions/pdf_fns/breakdown_txt.py b/crazy_functions/pdf_fns/breakdown_txt.py deleted file mode 100644 index e7c767361f946e664b4a0e258fa9698529225300..0000000000000000000000000000000000000000 --- a/crazy_functions/pdf_fns/breakdown_txt.py +++ /dev/null @@ -1,125 +0,0 @@ -from crazy_functions.ipc_fns.mp import run_in_subprocess_with_timeout - -def force_breakdown(txt, limit, get_token_fn): - """ 当无法用标点、空行分割时,我们用最暴力的方法切割 - """ - for i in reversed(range(len(txt))): - if get_token_fn(txt[:i]) < limit: - return txt[:i], txt[i:] - return "Tiktoken未知错误", "Tiktoken未知错误" - - -def maintain_storage(remain_txt_to_cut, remain_txt_to_cut_storage): - """ 为了加速计算,我们采样一个特殊的手段。当 remain_txt_to_cut > `_max` 时, 我们把 _max 后的文字转存至 remain_txt_to_cut_storage - 当 remain_txt_to_cut < `_min` 时,我们再把 remain_txt_to_cut_storage 中的部分文字取出 - """ - _min = int(5e4) - _max = int(1e5) - # print(len(remain_txt_to_cut), len(remain_txt_to_cut_storage)) - if len(remain_txt_to_cut) < _min and len(remain_txt_to_cut_storage) > 0: - remain_txt_to_cut = remain_txt_to_cut + remain_txt_to_cut_storage - remain_txt_to_cut_storage = "" - if len(remain_txt_to_cut) > _max: - remain_txt_to_cut_storage = remain_txt_to_cut[_max:] + remain_txt_to_cut_storage - remain_txt_to_cut = remain_txt_to_cut[:_max] - return remain_txt_to_cut, remain_txt_to_cut_storage - - -def cut(limit, get_token_fn, txt_tocut, must_break_at_empty_line, break_anyway=False): - """ 文本切分 - """ - res = [] - total_len = len(txt_tocut) - fin_len = 0 - remain_txt_to_cut = txt_tocut - remain_txt_to_cut_storage = "" - # 为了加速计算,我们采样一个特殊的手段。当 remain_txt_to_cut > `_max` 时, 我们把 _max 后的文字转存至 remain_txt_to_cut_storage - remain_txt_to_cut, remain_txt_to_cut_storage = maintain_storage(remain_txt_to_cut, remain_txt_to_cut_storage) - - while True: - if get_token_fn(remain_txt_to_cut) <= limit: - # 如果剩余文本的token数小于限制,那么就不用切了 - res.append(remain_txt_to_cut); fin_len+=len(remain_txt_to_cut) - break - else: - # 如果剩余文本的token数大于限制,那么就切 - lines = remain_txt_to_cut.split('\n') - - # 估计一个切分点 - estimated_line_cut = limit / get_token_fn(remain_txt_to_cut) * len(lines) - estimated_line_cut = int(estimated_line_cut) - - # 开始查找合适切分点的偏移(cnt) - cnt = 0 - for cnt in reversed(range(estimated_line_cut)): - if must_break_at_empty_line: - # 首先尝试用双空行(\n\n)作为切分点 - if lines[cnt] != "": - continue - prev = "\n".join(lines[:cnt]) - post = "\n".join(lines[cnt:]) - if get_token_fn(prev) < limit: - break - - if cnt == 0: - # 如果没有找到合适的切分点 - if break_anyway: - # 是否允许暴力切分 - prev, post = force_breakdown(remain_txt_to_cut, limit, get_token_fn) - else: - # 不允许直接报错 - raise RuntimeError(f"存在一行极长的文本!{remain_txt_to_cut}") - - # 追加列表 - res.append(prev); fin_len+=len(prev) - # 准备下一次迭代 - remain_txt_to_cut = post - remain_txt_to_cut, remain_txt_to_cut_storage = maintain_storage(remain_txt_to_cut, remain_txt_to_cut_storage) - process = fin_len/total_len - print(f'正在文本切分 {int(process*100)}%') - if len(remain_txt_to_cut.strip()) == 0: - break - return res - - -def breakdown_text_to_satisfy_token_limit_(txt, limit, llm_model="gpt-3.5-turbo"): - """ 使用多种方式尝试切分文本,以满足 token 限制 - """ - from request_llms.bridge_all import model_info - enc = model_info[llm_model]['tokenizer'] - def get_token_fn(txt): return len(enc.encode(txt, disallowed_special=())) - try: - # 第1次尝试,将双空行(\n\n)作为切分点 - return cut(limit, get_token_fn, txt, must_break_at_empty_line=True) - except RuntimeError: - try: - # 第2次尝试,将单空行(\n)作为切分点 - return cut(limit, get_token_fn, txt, must_break_at_empty_line=False) - except RuntimeError: - try: - # 第3次尝试,将英文句号(.)作为切分点 - res = cut(limit, get_token_fn, txt.replace('.', '。\n'), must_break_at_empty_line=False) # 这个中文的句号是故意的,作为一个标识而存在 - return [r.replace('。\n', '.') for r in res] - except RuntimeError as e: - try: - # 第4次尝试,将中文句号(。)作为切分点 - res = cut(limit, get_token_fn, txt.replace('。', '。。\n'), must_break_at_empty_line=False) - return [r.replace('。。\n', '。') for r in res] - except RuntimeError as e: - # 第5次尝试,没办法了,随便切一下吧 - return cut(limit, get_token_fn, txt, must_break_at_empty_line=False, break_anyway=True) - -breakdown_text_to_satisfy_token_limit = run_in_subprocess_with_timeout(breakdown_text_to_satisfy_token_limit_, timeout=60) - -if __name__ == '__main__': - from crazy_functions.crazy_utils import read_and_clean_pdf_text - file_content, page_one = read_and_clean_pdf_text("build/assets/at.pdf") - - from request_llms.bridge_all import model_info - for i in range(5): - file_content += file_content - - print(len(file_content)) - TOKEN_LIMIT_PER_FRAGMENT = 2500 - res = breakdown_text_to_satisfy_token_limit(file_content, TOKEN_LIMIT_PER_FRAGMENT) - diff --git a/crazy_functions/pdf_fns/parse_pdf.py b/crazy_functions/pdf_fns/parse_pdf.py index fa27de516feb735c0ac92ffa02be97164343d8cf..8a7117adb61a1fb67c911e04d8968ac803885dd1 100644 --- a/crazy_functions/pdf_fns/parse_pdf.py +++ b/crazy_functions/pdf_fns/parse_pdf.py @@ -1,26 +1,16 @@ -from functools import lru_cache -from toolbox import gen_time_str -from toolbox import promote_file_to_downloadzone -from toolbox import write_history_to_file, promote_file_to_downloadzone -from toolbox import get_conf -from toolbox import ProxyNetworkActivate -from colorful import * import requests import random -import copy -import os -import math - +from functools import lru_cache class GROBID_OFFLINE_EXCEPTION(Exception): pass def get_avail_grobid_url(): - GROBID_URLS = get_conf('GROBID_URLS') + from toolbox import get_conf + GROBID_URLS, = get_conf('GROBID_URLS') if len(GROBID_URLS) == 0: return None try: _grobid_url = random.choice(GROBID_URLS) # 随机负载均衡 if _grobid_url.endswith('/'): _grobid_url = _grobid_url.rstrip('/') - with ProxyNetworkActivate('Connect_Grobid'): - res = requests.get(_grobid_url+'/api/isalive') + res = requests.get(_grobid_url+'/api/isalive') if res.text=='true': return _grobid_url else: return None except: @@ -31,141 +21,10 @@ def parse_pdf(pdf_path, grobid_url): import scipdf # pip install scipdf_parser if grobid_url.endswith('/'): grobid_url = grobid_url.rstrip('/') try: - with ProxyNetworkActivate('Connect_Grobid'): - article_dict = scipdf.parse_pdf_to_dict(pdf_path, grobid_url=grobid_url) + article_dict = scipdf.parse_pdf_to_dict(pdf_path, grobid_url=grobid_url) except GROBID_OFFLINE_EXCEPTION: raise GROBID_OFFLINE_EXCEPTION("GROBID服务不可用,请修改config中的GROBID_URL,可修改成本地GROBID服务。") except: raise RuntimeError("解析PDF失败,请检查PDF是否损坏。") return article_dict - -def produce_report_markdown(gpt_response_collection, meta, paper_meta_info, chatbot, fp, generated_conclusion_files): - # -=-=-=-=-=-=-=-= 写出第1个文件:翻译前后混合 -=-=-=-=-=-=-=-= - res_path = write_history_to_file(meta + ["# Meta Translation" , paper_meta_info] + gpt_response_collection, file_basename=f"{gen_time_str()}translated_and_original.md", file_fullname=None) - promote_file_to_downloadzone(res_path, rename_file=os.path.basename(res_path)+'.md', chatbot=chatbot) - generated_conclusion_files.append(res_path) - - # -=-=-=-=-=-=-=-= 写出第2个文件:仅翻译后的文本 -=-=-=-=-=-=-=-= - translated_res_array = [] - # 记录当前的大章节标题: - last_section_name = "" - for index, value in enumerate(gpt_response_collection): - # 先挑选偶数序列号: - if index % 2 != 0: - # 先提取当前英文标题: - cur_section_name = gpt_response_collection[index-1].split('\n')[0].split(" Part")[0] - # 如果index是1的话,则直接使用first section name: - if cur_section_name != last_section_name: - cur_value = cur_section_name + '\n' - last_section_name = copy.deepcopy(cur_section_name) - else: - cur_value = "" - # 再做一个小修改:重新修改当前part的标题,默认用英文的 - cur_value += value - translated_res_array.append(cur_value) - res_path = write_history_to_file(meta + ["# Meta Translation" , paper_meta_info] + translated_res_array, - file_basename = f"{gen_time_str()}-translated_only.md", - file_fullname = None, - auto_caption = False) - promote_file_to_downloadzone(res_path, rename_file=os.path.basename(res_path)+'.md', chatbot=chatbot) - generated_conclusion_files.append(res_path) - return res_path - -def translate_pdf(article_dict, llm_kwargs, chatbot, fp, generated_conclusion_files, TOKEN_LIMIT_PER_FRAGMENT, DST_LANG): - from crazy_functions.pdf_fns.report_gen_html import construct_html - from crazy_functions.pdf_fns.breakdown_txt import breakdown_text_to_satisfy_token_limit - from crazy_functions.crazy_utils import request_gpt_model_in_new_thread_with_ui_alive - from crazy_functions.crazy_utils import request_gpt_model_multi_threads_with_very_awesome_ui_and_high_efficiency - - prompt = "以下是一篇学术论文的基本信息:\n" - # title - title = article_dict.get('title', '无法获取 title'); prompt += f'title:{title}\n\n' - # authors - authors = article_dict.get('authors', '无法获取 authors')[:100]; prompt += f'authors:{authors}\n\n' - # abstract - abstract = article_dict.get('abstract', '无法获取 abstract'); prompt += f'abstract:{abstract}\n\n' - # command - prompt += f"请将题目和摘要翻译为{DST_LANG}。" - meta = [f'# Title:\n\n', title, f'# Abstract:\n\n', abstract ] - - # 单线,获取文章meta信息 - paper_meta_info = yield from request_gpt_model_in_new_thread_with_ui_alive( - inputs=prompt, - inputs_show_user=prompt, - llm_kwargs=llm_kwargs, - chatbot=chatbot, history=[], - sys_prompt="You are an academic paper reader。", - ) - - # 多线,翻译 - inputs_array = [] - inputs_show_user_array = [] - - # get_token_num - from request_llms.bridge_all import model_info - enc = model_info[llm_kwargs['llm_model']]['tokenizer'] - def get_token_num(txt): return len(enc.encode(txt, disallowed_special=())) - - def break_down(txt): - raw_token_num = get_token_num(txt) - if raw_token_num <= TOKEN_LIMIT_PER_FRAGMENT: - return [txt] - else: - # raw_token_num > TOKEN_LIMIT_PER_FRAGMENT - # find a smooth token limit to achieve even seperation - count = int(math.ceil(raw_token_num / TOKEN_LIMIT_PER_FRAGMENT)) - token_limit_smooth = raw_token_num // count + count - return breakdown_text_to_satisfy_token_limit(txt, limit=token_limit_smooth, llm_model=llm_kwargs['llm_model']) - - for section in article_dict.get('sections'): - if len(section['text']) == 0: continue - section_frags = break_down(section['text']) - for i, fragment in enumerate(section_frags): - heading = section['heading'] - if len(section_frags) > 1: heading += f' Part-{i+1}' - inputs_array.append( - f"你需要翻译{heading}章节,内容如下: \n\n{fragment}" - ) - inputs_show_user_array.append( - f"# {heading}\n\n{fragment}" - ) - - gpt_response_collection = yield from request_gpt_model_multi_threads_with_very_awesome_ui_and_high_efficiency( - inputs_array=inputs_array, - inputs_show_user_array=inputs_show_user_array, - llm_kwargs=llm_kwargs, - chatbot=chatbot, - history_array=[meta for _ in inputs_array], - sys_prompt_array=[ - "请你作为一个学术翻译,负责把学术论文准确翻译成中文。注意文章中的每一句话都要翻译。" for _ in inputs_array], - ) - # -=-=-=-=-=-=-=-= 写出Markdown文件 -=-=-=-=-=-=-=-= - produce_report_markdown(gpt_response_collection, meta, paper_meta_info, chatbot, fp, generated_conclusion_files) - - # -=-=-=-=-=-=-=-= 写出HTML文件 -=-=-=-=-=-=-=-= - ch = construct_html() - orig = "" - trans = "" - gpt_response_collection_html = copy.deepcopy(gpt_response_collection) - for i,k in enumerate(gpt_response_collection_html): - if i%2==0: - gpt_response_collection_html[i] = inputs_show_user_array[i//2] - else: - # 先提取当前英文标题: - cur_section_name = gpt_response_collection[i-1].split('\n')[0].split(" Part")[0] - cur_value = cur_section_name + "\n" + gpt_response_collection_html[i] - gpt_response_collection_html[i] = cur_value - - final = ["", "", "一、论文概况", "", "Abstract", paper_meta_info, "二、论文翻译", ""] - final.extend(gpt_response_collection_html) - for i, k in enumerate(final): - if i%2==0: - orig = k - if i%2==1: - trans = k - ch.add_row(a=orig, b=trans) - create_report_file_name = f"{os.path.basename(fp)}.trans.html" - html_file = ch.save_file(create_report_file_name) - generated_conclusion_files.append(html_file) - promote_file_to_downloadzone(html_file, rename_file=os.path.basename(html_file), chatbot=chatbot) diff --git a/crazy_functions/pdf_fns/parse_word.py b/crazy_functions/pdf_fns/parse_word.py deleted file mode 100644 index 64d07dcd48156162eea40b8b9fd3c105ccbf1af2..0000000000000000000000000000000000000000 --- a/crazy_functions/pdf_fns/parse_word.py +++ /dev/null @@ -1,85 +0,0 @@ -from crazy_functions.crazy_utils import read_and_clean_pdf_text, get_files_from_everything -import os -import re -def extract_text_from_files(txt, chatbot, history): - """ - 查找pdf/md/word并获取文本内容并返回状态以及文本 - - 输入参数 Args: - chatbot: chatbot inputs and outputs (用户界面对话窗口句柄,用于数据流可视化) - history (list): List of chat history (历史,对话历史列表) - - 输出 Returns: - 文件是否存在(bool) - final_result(list):文本内容 - page_one(list):第一页内容/摘要 - file_manifest(list):文件路径 - excption(string):需要用户手动处理的信息,如没出错则保持为空 - """ - - final_result = [] - page_one = [] - file_manifest = [] - excption = "" - - if txt == "": - final_result.append(txt) - return False, final_result, page_one, file_manifest, excption #如输入区内容不是文件则直接返回输入区内容 - - #查找输入区内容中的文件 - file_pdf,pdf_manifest,folder_pdf = get_files_from_everything(txt, '.pdf') - file_md,md_manifest,folder_md = get_files_from_everything(txt, '.md') - file_word,word_manifest,folder_word = get_files_from_everything(txt, '.docx') - file_doc,doc_manifest,folder_doc = get_files_from_everything(txt, '.doc') - - if file_doc: - excption = "word" - return False, final_result, page_one, file_manifest, excption - - file_num = len(pdf_manifest) + len(md_manifest) + len(word_manifest) - if file_num == 0: - final_result.append(txt) - return False, final_result, page_one, file_manifest, excption #如输入区内容不是文件则直接返回输入区内容 - - if file_pdf: - try: # 尝试导入依赖,如果缺少依赖,则给出安装建议 - import fitz - except: - excption = "pdf" - return False, final_result, page_one, file_manifest, excption - for index, fp in enumerate(pdf_manifest): - file_content, pdf_one = read_and_clean_pdf_text(fp) # (尝试)按照章节切割PDF - file_content = file_content.encode('utf-8', 'ignore').decode() # avoid reading non-utf8 chars - pdf_one = str(pdf_one).encode('utf-8', 'ignore').decode() # avoid reading non-utf8 chars - final_result.append(file_content) - page_one.append(pdf_one) - file_manifest.append(os.path.relpath(fp, folder_pdf)) - - if file_md: - for index, fp in enumerate(md_manifest): - with open(fp, 'r', encoding='utf-8', errors='replace') as f: - file_content = f.read() - file_content = file_content.encode('utf-8', 'ignore').decode() - headers = re.findall(r'^#\s(.*)$', file_content, re.MULTILINE) #接下来提取md中的一级/二级标题作为摘要 - if len(headers) > 0: - page_one.append("\n".join(headers)) #合并所有的标题,以换行符分割 - else: - page_one.append("") - final_result.append(file_content) - file_manifest.append(os.path.relpath(fp, folder_md)) - - if file_word: - try: # 尝试导入依赖,如果缺少依赖,则给出安装建议 - from docx import Document - except: - excption = "word_pip" - return False, final_result, page_one, file_manifest, excption - for index, fp in enumerate(word_manifest): - doc = Document(fp) - file_content = '\n'.join([p.text for p in doc.paragraphs]) - file_content = file_content.encode('utf-8', 'ignore').decode() - page_one.append(file_content[:200]) - final_result.append(file_content) - file_manifest.append(os.path.relpath(fp, folder_word)) - - return True, final_result, page_one, file_manifest, excption \ No newline at end of file diff --git a/crazy_functions/pdf_fns/report_gen_html.py b/crazy_functions/pdf_fns/report_gen_html.py deleted file mode 100644 index 21829212ff13a2dfd1492f05ac9abc73907dce7b..0000000000000000000000000000000000000000 --- a/crazy_functions/pdf_fns/report_gen_html.py +++ /dev/null @@ -1,58 +0,0 @@ -from toolbox import update_ui, get_conf, trimmed_format_exc, get_log_folder -import os - - - - -class construct_html(): - def __init__(self) -> None: - self.html_string = "" - - def add_row(self, a, b): - from toolbox import markdown_convertion - template = """ - { - primary_col: { - header: String.raw`__PRIMARY_HEADER__`, - msg: String.raw`__PRIMARY_MSG__`, - }, - secondary_rol: { - header: String.raw`__SECONDARY_HEADER__`, - msg: String.raw`__SECONDARY_MSG__`, - } - }, - """ - def std(str): - str = str.replace(r'`',r'`') - if str.endswith("\\"): str += ' ' - if str.endswith("}"): str += ' ' - if str.endswith("$"): str += ' ' - return str - - template_ = template - a_lines = a.split('\n') - b_lines = b.split('\n') - - if len(a_lines) == 1 or len(a_lines[0]) > 50: - template_ = template_.replace("__PRIMARY_HEADER__", std(a[:20])) - template_ = template_.replace("__PRIMARY_MSG__", std(markdown_convertion(a))) - else: - template_ = template_.replace("__PRIMARY_HEADER__", std(a_lines[0])) - template_ = template_.replace("__PRIMARY_MSG__", std(markdown_convertion('\n'.join(a_lines[1:])))) - - if len(b_lines) == 1 or len(b_lines[0]) > 50: - template_ = template_.replace("__SECONDARY_HEADER__", std(b[:20])) - template_ = template_.replace("__SECONDARY_MSG__", std(markdown_convertion(b))) - else: - template_ = template_.replace("__SECONDARY_HEADER__", std(b_lines[0])) - template_ = template_.replace("__SECONDARY_MSG__", std(markdown_convertion('\n'.join(b_lines[1:])))) - self.html_string += template_ - - def save_file(self, file_name): - from toolbox import get_log_folder - with open('crazy_functions/pdf_fns/report_template.html', 'r', encoding='utf8') as f: - html_template = f.read() - html_template = html_template.replace("__TF_ARR__", self.html_string) - with open(os.path.join(get_log_folder(), file_name), 'w', encoding='utf8') as f: - f.write(html_template.encode('utf-8', 'ignore').decode()) - return os.path.join(get_log_folder(), file_name) diff --git a/crazy_functions/pdf_fns/report_template.html b/crazy_functions/pdf_fns/report_template.html deleted file mode 100644 index 39a1e7ce482949978ff90c4738a9adb8803660e6..0000000000000000000000000000000000000000 --- a/crazy_functions/pdf_fns/report_template.html +++ /dev/null @@ -1,104 +0,0 @@ - - - - - - __TITLE__ - - - - - -
-

文章目录

- -
- - - diff --git a/crazy_functions/vector_fns/__init__.py b/crazy_functions/vector_fns/__init__.py deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/crazy_functions/vector_fns/general_file_loader.py b/crazy_functions/vector_fns/general_file_loader.py deleted file mode 100644 index a512c483c8d1048fbb9e517fac7bcc0f83bfdb88..0000000000000000000000000000000000000000 --- a/crazy_functions/vector_fns/general_file_loader.py +++ /dev/null @@ -1,70 +0,0 @@ -# From project chatglm-langchain - - -from langchain.document_loaders import UnstructuredFileLoader -from langchain.text_splitter import CharacterTextSplitter -import re -from typing import List - -class ChineseTextSplitter(CharacterTextSplitter): - def __init__(self, pdf: bool = False, sentence_size: int = None, **kwargs): - super().__init__(**kwargs) - self.pdf = pdf - self.sentence_size = sentence_size - - def split_text1(self, text: str) -> List[str]: - if self.pdf: - text = re.sub(r"\n{3,}", "\n", text) - text = re.sub('\s', ' ', text) - text = text.replace("\n\n", "") - sent_sep_pattern = re.compile('([﹒﹔﹖﹗.。!?]["’”」』]{0,2}|(?=["‘“「『]{1,2}|$))') # del :; - sent_list = [] - for ele in sent_sep_pattern.split(text): - if sent_sep_pattern.match(ele) and sent_list: - sent_list[-1] += ele - elif ele: - sent_list.append(ele) - return sent_list - - def split_text(self, text: str) -> List[str]: ##此处需要进一步优化逻辑 - if self.pdf: - text = re.sub(r"\n{3,}", r"\n", text) - text = re.sub('\s', " ", text) - text = re.sub("\n\n", "", text) - - text = re.sub(r'([;;.!?。!?\?])([^”’])', r"\1\n\2", text) # 单字符断句符 - text = re.sub(r'(\.{6})([^"’”」』])', r"\1\n\2", text) # 英文省略号 - text = re.sub(r'(\…{2})([^"’”」』])', r"\1\n\2", text) # 中文省略号 - text = re.sub(r'([;;!?。!?\?]["’”」』]{0,2})([^;;!?,。!?\?])', r'\1\n\2', text) - # 如果双引号前有终止符,那么双引号才是句子的终点,把分句符\n放到双引号后,注意前面的几句都小心保留了双引号 - text = text.rstrip() # 段尾如果有多余的\n就去掉它 - # 很多规则中会考虑分号;,但是这里我把它忽略不计,破折号、英文双引号等同样忽略,需要的再做些简单调整即可。 - ls = [i for i in text.split("\n") if i] - for ele in ls: - if len(ele) > self.sentence_size: - ele1 = re.sub(r'([,,.]["’”」』]{0,2})([^,,.])', r'\1\n\2', ele) - ele1_ls = ele1.split("\n") - for ele_ele1 in ele1_ls: - if len(ele_ele1) > self.sentence_size: - ele_ele2 = re.sub(r'([\n]{1,}| {2,}["’”」』]{0,2})([^\s])', r'\1\n\2', ele_ele1) - ele2_ls = ele_ele2.split("\n") - for ele_ele2 in ele2_ls: - if len(ele_ele2) > self.sentence_size: - ele_ele3 = re.sub('( ["’”」』]{0,2})([^ ])', r'\1\n\2', ele_ele2) - ele2_id = ele2_ls.index(ele_ele2) - ele2_ls = ele2_ls[:ele2_id] + [i for i in ele_ele3.split("\n") if i] + ele2_ls[ - ele2_id + 1:] - ele_id = ele1_ls.index(ele_ele1) - ele1_ls = ele1_ls[:ele_id] + [i for i in ele2_ls if i] + ele1_ls[ele_id + 1:] - - id = ls.index(ele) - ls = ls[:id] + [i for i in ele1_ls if i] + ls[id + 1:] - return ls - -def load_file(filepath, sentence_size): - loader = UnstructuredFileLoader(filepath, mode="elements") - textsplitter = ChineseTextSplitter(pdf=False, sentence_size=sentence_size) - docs = loader.load_and_split(text_splitter=textsplitter) - # write_check_file(filepath, docs) - return docs - diff --git a/crazy_functions/vector_fns/vector_database.py b/crazy_functions/vector_fns/vector_database.py deleted file mode 100644 index cffa22cfeff3ccf9d3071b5cf534f5b6be22870f..0000000000000000000000000000000000000000 --- a/crazy_functions/vector_fns/vector_database.py +++ /dev/null @@ -1,338 +0,0 @@ -# From project chatglm-langchain - -import threading -from toolbox import Singleton -import os -import shutil -import os -import uuid -import tqdm -from langchain.vectorstores import FAISS -from langchain.docstore.document import Document -from typing import List, Tuple -import numpy as np -from crazy_functions.vector_fns.general_file_loader import load_file - -embedding_model_dict = { - "ernie-tiny": "nghuyong/ernie-3.0-nano-zh", - "ernie-base": "nghuyong/ernie-3.0-base-zh", - "text2vec-base": "shibing624/text2vec-base-chinese", - "text2vec": "GanymedeNil/text2vec-large-chinese", -} - -# Embedding model name -EMBEDDING_MODEL = "text2vec" - -# Embedding running device -EMBEDDING_DEVICE = "cpu" - -# 基于上下文的prompt模版,请务必保留"{question}"和"{context}" -PROMPT_TEMPLATE = """已知信息: -{context} - -根据上述已知信息,简洁和专业的来回答用户的问题。如果无法从中得到答案,请说 “根据已知信息无法回答该问题” 或 “没有提供足够的相关信息”,不允许在答案中添加编造成分,答案请使用中文。 问题是:{question}""" - -# 文本分句长度 -SENTENCE_SIZE = 100 - -# 匹配后单段上下文长度 -CHUNK_SIZE = 250 - -# LLM input history length -LLM_HISTORY_LEN = 3 - -# return top-k text chunk from vector store -VECTOR_SEARCH_TOP_K = 5 - -# 知识检索内容相关度 Score, 数值范围约为0-1100,如果为0,则不生效,经测试设置为小于500时,匹配结果更精准 -VECTOR_SEARCH_SCORE_THRESHOLD = 0 - -NLTK_DATA_PATH = os.path.join(os.path.dirname(os.path.dirname(__file__)), "nltk_data") - -FLAG_USER_NAME = uuid.uuid4().hex - -# 是否开启跨域,默认为False,如果需要开启,请设置为True -# is open cross domain -OPEN_CROSS_DOMAIN = False - -def similarity_search_with_score_by_vector( - self, embedding: List[float], k: int = 4 -) -> List[Tuple[Document, float]]: - - def seperate_list(ls: List[int]) -> List[List[int]]: - lists = [] - ls1 = [ls[0]] - for i in range(1, len(ls)): - if ls[i - 1] + 1 == ls[i]: - ls1.append(ls[i]) - else: - lists.append(ls1) - ls1 = [ls[i]] - lists.append(ls1) - return lists - - scores, indices = self.index.search(np.array([embedding], dtype=np.float32), k) - docs = [] - id_set = set() - store_len = len(self.index_to_docstore_id) - for j, i in enumerate(indices[0]): - if i == -1 or 0 < self.score_threshold < scores[0][j]: - # This happens when not enough docs are returned. - continue - _id = self.index_to_docstore_id[i] - doc = self.docstore.search(_id) - if not self.chunk_conent: - if not isinstance(doc, Document): - raise ValueError(f"Could not find document for id {_id}, got {doc}") - doc.metadata["score"] = int(scores[0][j]) - docs.append(doc) - continue - id_set.add(i) - docs_len = len(doc.page_content) - for k in range(1, max(i, store_len - i)): - break_flag = False - for l in [i + k, i - k]: - if 0 <= l < len(self.index_to_docstore_id): - _id0 = self.index_to_docstore_id[l] - doc0 = self.docstore.search(_id0) - if docs_len + len(doc0.page_content) > self.chunk_size: - break_flag = True - break - elif doc0.metadata["source"] == doc.metadata["source"]: - docs_len += len(doc0.page_content) - id_set.add(l) - if break_flag: - break - if not self.chunk_conent: - return docs - if len(id_set) == 0 and self.score_threshold > 0: - return [] - id_list = sorted(list(id_set)) - id_lists = seperate_list(id_list) - for id_seq in id_lists: - for id in id_seq: - if id == id_seq[0]: - _id = self.index_to_docstore_id[id] - doc = self.docstore.search(_id) - else: - _id0 = self.index_to_docstore_id[id] - doc0 = self.docstore.search(_id0) - doc.page_content += " " + doc0.page_content - if not isinstance(doc, Document): - raise ValueError(f"Could not find document for id {_id}, got {doc}") - doc_score = min([scores[0][id] for id in [indices[0].tolist().index(i) for i in id_seq if i in indices[0]]]) - doc.metadata["score"] = int(doc_score) - docs.append(doc) - return docs - - -class LocalDocQA: - llm: object = None - embeddings: object = None - top_k: int = VECTOR_SEARCH_TOP_K - chunk_size: int = CHUNK_SIZE - chunk_conent: bool = True - score_threshold: int = VECTOR_SEARCH_SCORE_THRESHOLD - - def init_cfg(self, - top_k=VECTOR_SEARCH_TOP_K, - ): - - self.llm = None - self.top_k = top_k - - def init_knowledge_vector_store(self, - filepath, - vs_path: str or os.PathLike = None, - sentence_size=SENTENCE_SIZE, - text2vec=None): - loaded_files = [] - failed_files = [] - if isinstance(filepath, str): - if not os.path.exists(filepath): - print("路径不存在") - return None - elif os.path.isfile(filepath): - file = os.path.split(filepath)[-1] - try: - docs = load_file(filepath, SENTENCE_SIZE) - print(f"{file} 已成功加载") - loaded_files.append(filepath) - except Exception as e: - print(e) - print(f"{file} 未能成功加载") - return None - elif os.path.isdir(filepath): - docs = [] - for file in tqdm(os.listdir(filepath), desc="加载文件"): - fullfilepath = os.path.join(filepath, file) - try: - docs += load_file(fullfilepath, SENTENCE_SIZE) - loaded_files.append(fullfilepath) - except Exception as e: - print(e) - failed_files.append(file) - - if len(failed_files) > 0: - print("以下文件未能成功加载:") - for file in failed_files: - print(f"{file}\n") - - else: - docs = [] - for file in filepath: - docs += load_file(file, SENTENCE_SIZE) - print(f"{file} 已成功加载") - loaded_files.append(file) - - if len(docs) > 0: - print("文件加载完毕,正在生成向量库") - if vs_path and os.path.isdir(vs_path): - try: - self.vector_store = FAISS.load_local(vs_path, text2vec) - self.vector_store.add_documents(docs) - except: - self.vector_store = FAISS.from_documents(docs, text2vec) - else: - self.vector_store = FAISS.from_documents(docs, text2vec) # docs 为Document列表 - - self.vector_store.save_local(vs_path) - return vs_path, loaded_files - else: - raise RuntimeError("文件加载失败,请检查文件格式是否正确") - - def get_loaded_file(self, vs_path): - ds = self.vector_store.docstore - return set([ds._dict[k].metadata['source'].split(vs_path)[-1] for k in ds._dict]) - - - # query 查询内容 - # vs_path 知识库路径 - # chunk_conent 是否启用上下文关联 - # score_threshold 搜索匹配score阈值 - # vector_search_top_k 搜索知识库内容条数,默认搜索5条结果 - # chunk_sizes 匹配单段内容的连接上下文长度 - def get_knowledge_based_conent_test(self, query, vs_path, chunk_conent, - score_threshold=VECTOR_SEARCH_SCORE_THRESHOLD, - vector_search_top_k=VECTOR_SEARCH_TOP_K, chunk_size=CHUNK_SIZE, - text2vec=None): - self.vector_store = FAISS.load_local(vs_path, text2vec) - self.vector_store.chunk_conent = chunk_conent - self.vector_store.score_threshold = score_threshold - self.vector_store.chunk_size = chunk_size - - embedding = self.vector_store.embedding_function.embed_query(query) - related_docs_with_score = similarity_search_with_score_by_vector(self.vector_store, embedding, k=vector_search_top_k) - - if not related_docs_with_score: - response = {"query": query, - "source_documents": []} - return response, "" - # prompt = f"{query}. You should answer this question using information from following documents: \n\n" - prompt = f"{query}. 你必须利用以下文档中包含的信息回答这个问题: \n\n---\n\n" - prompt += "\n\n".join([f"({k}): " + doc.page_content for k, doc in enumerate(related_docs_with_score)]) - prompt += "\n\n---\n\n" - prompt = prompt.encode('utf-8', 'ignore').decode() # avoid reading non-utf8 chars - # print(prompt) - response = {"query": query, "source_documents": related_docs_with_score} - return response, prompt - - - - -def construct_vector_store(vs_id, vs_path, files, sentence_size, history, one_conent, one_content_segmentation, text2vec): - for file in files: - assert os.path.exists(file), "输入文件不存在:" + file - import nltk - if NLTK_DATA_PATH not in nltk.data.path: nltk.data.path = [NLTK_DATA_PATH] + nltk.data.path - local_doc_qa = LocalDocQA() - local_doc_qa.init_cfg() - filelist = [] - if not os.path.exists(os.path.join(vs_path, vs_id)): - os.makedirs(os.path.join(vs_path, vs_id)) - for file in files: - file_name = file.name if not isinstance(file, str) else file - filename = os.path.split(file_name)[-1] - shutil.copyfile(file_name, os.path.join(vs_path, vs_id, filename)) - filelist.append(os.path.join(vs_path, vs_id, filename)) - vs_path, loaded_files = local_doc_qa.init_knowledge_vector_store(filelist, os.path.join(vs_path, vs_id), sentence_size, text2vec) - - if len(loaded_files): - file_status = f"已添加 {'、'.join([os.path.split(i)[-1] for i in loaded_files if i])} 内容至知识库,并已加载知识库,请开始提问" - else: - pass - # file_status = "文件未成功加载,请重新上传文件" - # print(file_status) - return local_doc_qa, vs_path - -@Singleton -class knowledge_archive_interface(): - def __init__(self) -> None: - self.threadLock = threading.Lock() - self.current_id = "" - self.kai_path = None - self.qa_handle = None - self.text2vec_large_chinese = None - - def get_chinese_text2vec(self): - if self.text2vec_large_chinese is None: - # < -------------------预热文本向量化模组--------------- > - from toolbox import ProxyNetworkActivate - print('Checking Text2vec ...') - from langchain.embeddings.huggingface import HuggingFaceEmbeddings - with ProxyNetworkActivate('Download_LLM'): # 临时地激活代理网络 - self.text2vec_large_chinese = HuggingFaceEmbeddings(model_name="GanymedeNil/text2vec-large-chinese") - - return self.text2vec_large_chinese - - - def feed_archive(self, file_manifest, vs_path, id="default"): - self.threadLock.acquire() - # import uuid - self.current_id = id - self.qa_handle, self.kai_path = construct_vector_store( - vs_id=self.current_id, - vs_path=vs_path, - files=file_manifest, - sentence_size=100, - history=[], - one_conent="", - one_content_segmentation="", - text2vec = self.get_chinese_text2vec(), - ) - self.threadLock.release() - - def get_current_archive_id(self): - return self.current_id - - def get_loaded_file(self, vs_path): - return self.qa_handle.get_loaded_file(vs_path) - - def answer_with_archive_by_id(self, txt, id, vs_path): - self.threadLock.acquire() - if not self.current_id == id: - self.current_id = id - self.qa_handle, self.kai_path = construct_vector_store( - vs_id=self.current_id, - vs_path=vs_path, - files=[], - sentence_size=100, - history=[], - one_conent="", - one_content_segmentation="", - text2vec = self.get_chinese_text2vec(), - ) - VECTOR_SEARCH_SCORE_THRESHOLD = 0 - VECTOR_SEARCH_TOP_K = 4 - CHUNK_SIZE = 512 - resp, prompt = self.qa_handle.get_knowledge_based_conent_test( - query = txt, - vs_path = self.kai_path, - score_threshold=VECTOR_SEARCH_SCORE_THRESHOLD, - vector_search_top_k=VECTOR_SEARCH_TOP_K, - chunk_conent=True, - chunk_size=CHUNK_SIZE, - text2vec = self.get_chinese_text2vec(), - ) - self.threadLock.release() - return resp, prompt \ No newline at end of file diff --git a/crazy_functions/vt_fns/vt_call_plugin.py b/crazy_functions/vt_fns/vt_call_plugin.py index f33644d9ad61c29c6809198a4b0d7466a9d98e48..455ac88bc0d7861441301c37490181181243a59a 100644 --- a/crazy_functions/vt_fns/vt_call_plugin.py +++ b/crazy_functions/vt_fns/vt_call_plugin.py @@ -1,7 +1,7 @@ from pydantic import BaseModel, Field from typing import List from toolbox import update_ui_lastest_msg, disable_auto_promotion -from request_llms.bridge_all import predict_no_ui_long_connection +from request_llm.bridge_all import predict_no_ui_long_connection from crazy_functions.json_fns.pydantic_io import GptJsonIO, JsonStringError import copy, json, pickle, os, sys, time diff --git a/crazy_functions/vt_fns/vt_modify_config.py b/crazy_functions/vt_fns/vt_modify_config.py index 58a8531e8ef8fff970ecc002ae2a0c71ec313a1d..e7fd745c3dc2ee1cf260ac2ac97a053b2985d4c8 100644 --- a/crazy_functions/vt_fns/vt_modify_config.py +++ b/crazy_functions/vt_fns/vt_modify_config.py @@ -1,13 +1,13 @@ from pydantic import BaseModel, Field from typing import List from toolbox import update_ui_lastest_msg, get_conf -from request_llms.bridge_all import predict_no_ui_long_connection +from request_llm.bridge_all import predict_no_ui_long_connection from crazy_functions.json_fns.pydantic_io import GptJsonIO import copy, json, pickle, os, sys def modify_configuration_hot(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_intention): - ALLOW_RESET_CONFIG = get_conf('ALLOW_RESET_CONFIG') + ALLOW_RESET_CONFIG, = get_conf('ALLOW_RESET_CONFIG') if not ALLOW_RESET_CONFIG: yield from update_ui_lastest_msg( lastmsg=f"当前配置不允许被修改!如需激活本功能,请在config.py中设置ALLOW_RESET_CONFIG=True后重启软件。", @@ -66,7 +66,7 @@ def modify_configuration_hot(txt, llm_kwargs, plugin_kwargs, chatbot, history, s ) def modify_configuration_reboot(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_intention): - ALLOW_RESET_CONFIG = get_conf('ALLOW_RESET_CONFIG') + ALLOW_RESET_CONFIG, = get_conf('ALLOW_RESET_CONFIG') if not ALLOW_RESET_CONFIG: yield from update_ui_lastest_msg( lastmsg=f"当前配置不允许被修改!如需激活本功能,请在config.py中设置ALLOW_RESET_CONFIG=True后重启软件。", diff --git "a/crazy_functions/\344\270\213\350\275\275arxiv\350\256\272\346\226\207\347\277\273\350\257\221\346\221\230\350\246\201.py" "b/crazy_functions/\344\270\213\350\275\275arxiv\350\256\272\346\226\207\347\277\273\350\257\221\346\221\230\350\246\201.py" index c368b7d66bced9c4ffde805f1f87d367d4c301ee..8b4a5037a21d326ddcdcc7ee5dd6082d949c5a55 100644 --- "a/crazy_functions/\344\270\213\350\275\275arxiv\350\256\272\346\226\207\347\277\273\350\257\221\346\221\230\350\246\201.py" +++ "b/crazy_functions/\344\270\213\350\275\275arxiv\350\256\272\346\226\207\347\277\273\350\257\221\346\221\230\350\246\201.py" @@ -1,6 +1,6 @@ from toolbox import update_ui, get_log_folder from toolbox import write_history_to_file, promote_file_to_downloadzone -from toolbox import CatchException, report_exception, get_conf +from toolbox import CatchException, report_execption, get_conf import re, requests, unicodedata, os from .crazy_utils import request_gpt_model_in_new_thread_with_ui_alive def download_arxiv_(url_pdf): @@ -43,7 +43,7 @@ def download_arxiv_(url_pdf): file_path = download_dir+title_str print('下载中') - proxies = get_conf('proxies') + proxies, = get_conf('proxies') r = requests.get(requests_pdf_url, proxies=proxies) with open(file_path, 'wb+') as f: f.write(r.content) @@ -77,7 +77,7 @@ def get_name(_url_): # print('在缓存中') # return arxiv_recall[_url_] - proxies = get_conf('proxies') + proxies, = get_conf('proxies') res = requests.get(_url_, proxies=proxies) bs = BeautifulSoup(res.text, 'html.parser') @@ -130,7 +130,7 @@ def get_name(_url_): @CatchException -def 下载arxiv论文并翻译摘要(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request): +def 下载arxiv论文并翻译摘要(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port): CRAZY_FUNCTION_INFO = "下载arxiv论文并翻译摘要,函数插件作者[binary-husky]。正在提取摘要并下载PDF文档……" import glob @@ -144,7 +144,7 @@ def 下载arxiv论文并翻译摘要(txt, llm_kwargs, plugin_kwargs, chatbot, hi try: import bs4 except: - report_exception(chatbot, history, + report_execption(chatbot, history, a = f"解析项目: {txt}", b = f"导入软件依赖失败。使用该模块需要额外依赖,安装方法```pip install --upgrade beautifulsoup4```。") yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 @@ -157,7 +157,7 @@ def 下载arxiv论文并翻译摘要(txt, llm_kwargs, plugin_kwargs, chatbot, hi try: pdf_path, info = download_arxiv_(txt) except: - report_exception(chatbot, history, + report_execption(chatbot, history, a = f"解析项目: {txt}", b = f"下载pdf文件未成功") yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 diff --git "a/crazy_functions/\344\272\222\345\212\250\345\260\217\346\270\270\346\210\217.py" "b/crazy_functions/\344\272\222\345\212\250\345\260\217\346\270\270\346\210\217.py" deleted file mode 100644 index 131e9c91954d164f96b1826869eac6477fe4de5f..0000000000000000000000000000000000000000 --- "a/crazy_functions/\344\272\222\345\212\250\345\260\217\346\270\270\346\210\217.py" +++ /dev/null @@ -1,40 +0,0 @@ -from toolbox import CatchException, update_ui, update_ui_lastest_msg -from crazy_functions.multi_stage.multi_stage_utils import GptAcademicGameBaseState -from crazy_functions.crazy_utils import request_gpt_model_in_new_thread_with_ui_alive -from request_llms.bridge_all import predict_no_ui_long_connection -from crazy_functions.game_fns.game_utils import get_code_block, is_same_thing - -@CatchException -def 随机小游戏(prompt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request): - from crazy_functions.game_fns.game_interactive_story import MiniGame_ResumeStory - # 清空历史 - history = [] - # 选择游戏 - cls = MiniGame_ResumeStory - # 如果之前已经初始化了游戏实例,则继续该实例;否则重新初始化 - state = cls.sync_state(chatbot, - llm_kwargs, - cls, - plugin_name='MiniGame_ResumeStory', - callback_fn='crazy_functions.互动小游戏->随机小游戏', - lock_plugin=True - ) - yield from state.continue_game(prompt, chatbot, history) - - -@CatchException -def 随机小游戏1(prompt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request): - from crazy_functions.game_fns.game_ascii_art import MiniGame_ASCII_Art - # 清空历史 - history = [] - # 选择游戏 - cls = MiniGame_ASCII_Art - # 如果之前已经初始化了游戏实例,则继续该实例;否则重新初始化 - state = cls.sync_state(chatbot, - llm_kwargs, - cls, - plugin_name='MiniGame_ASCII_Art', - callback_fn='crazy_functions.互动小游戏->随机小游戏1', - lock_plugin=True - ) - yield from state.continue_game(prompt, chatbot, history) diff --git "a/crazy_functions/\344\272\244\344\272\222\345\212\237\350\203\275\345\207\275\346\225\260\346\250\241\346\235\277.py" "b/crazy_functions/\344\272\244\344\272\222\345\212\237\350\203\275\345\207\275\346\225\260\346\250\241\346\235\277.py" index 811267a321e34896257b612f6797f095625bf962..d57fc2b0f0fb604be1dc19f789815eb7833bef7f 100644 --- "a/crazy_functions/\344\272\244\344\272\222\345\212\237\350\203\275\345\207\275\346\225\260\346\250\241\346\235\277.py" +++ "b/crazy_functions/\344\272\244\344\272\222\345\212\237\350\203\275\345\207\275\346\225\260\346\250\241\346\235\277.py" @@ -3,7 +3,7 @@ from .crazy_utils import request_gpt_model_in_new_thread_with_ui_alive @CatchException -def 交互功能模板函数(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request): +def 交互功能模板函数(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port): """ txt 输入栏用户输入的文本,例如需要翻译的一段话,再例如一个包含了待处理文件的路径 llm_kwargs gpt模型参数, 如温度和top_p等, 一般原样传递下去就行 @@ -11,7 +11,7 @@ def 交互功能模板函数(txt, llm_kwargs, plugin_kwargs, chatbot, history, s chatbot 聊天显示框的句柄,用于显示给用户 history 聊天历史,前情提要 system_prompt 给gpt的静默提醒 - user_request 当前用户的请求信息(IP地址等) + web_port 当前软件运行的端口号 """ history = [] # 清空历史,以免输入溢出 chatbot.append(("这是什么功能?", "交互功能函数模板。在执行完成之后, 可以将自身的状态存储到cookie中, 等待用户的再次调用。")) diff --git "a/crazy_functions/\345\207\275\346\225\260\345\212\250\346\200\201\347\224\237\346\210\220.py" "b/crazy_functions/\345\207\275\346\225\260\345\212\250\346\200\201\347\224\237\346\210\220.py" deleted file mode 100644 index d20d0cf579d2357306e040570f708d4f26a8912a..0000000000000000000000000000000000000000 --- "a/crazy_functions/\345\207\275\346\225\260\345\212\250\346\200\201\347\224\237\346\210\220.py" +++ /dev/null @@ -1,252 +0,0 @@ -# 本源代码中, ⭐ = 关键步骤 -""" -测试: - - 裁剪图像,保留下半部分 - - 交换图像的蓝色通道和红色通道 - - 将图像转为灰度图像 - - 将csv文件转excel表格 - -Testing: - - Crop the image, keeping the bottom half. - - Swap the blue channel and red channel of the image. - - Convert the image to grayscale. - - Convert the CSV file to an Excel spreadsheet. -""" - - -from toolbox import CatchException, update_ui, gen_time_str, trimmed_format_exc, is_the_upload_folder -from toolbox import promote_file_to_downloadzone, get_log_folder, update_ui_lastest_msg -from .crazy_utils import request_gpt_model_in_new_thread_with_ui_alive, get_plugin_arg -from .crazy_utils import input_clipping, try_install_deps -from crazy_functions.gen_fns.gen_fns_shared import is_function_successfully_generated -from crazy_functions.gen_fns.gen_fns_shared import get_class_name -from crazy_functions.gen_fns.gen_fns_shared import subprocess_worker -from crazy_functions.gen_fns.gen_fns_shared import try_make_module -import os -import time -import glob -import multiprocessing - -templete = """ -```python -import ... # Put dependencies here, e.g. import numpy as np. - -class TerminalFunction(object): # Do not change the name of the class, The name of the class must be `TerminalFunction` - - def run(self, path): # The name of the function must be `run`, it takes only a positional argument. - # rewrite the function you have just written here - ... - return generated_file_path -``` -""" - -def inspect_dependency(chatbot, history): - yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 - return True - -def get_code_block(reply): - import re - pattern = r"```([\s\S]*?)```" # regex pattern to match code blocks - matches = re.findall(pattern, reply) # find all code blocks in text - if len(matches) == 1: - return matches[0].strip('python') # code block - for match in matches: - if 'class TerminalFunction' in match: - return match.strip('python') # code block - raise RuntimeError("GPT is not generating proper code.") - -def gpt_interact_multi_step(txt, file_type, llm_kwargs, chatbot, history): - # 输入 - prompt_compose = [ - f'Your job:\n' - f'1. write a single Python function, which takes a path of a `{file_type}` file as the only argument and returns a `string` containing the result of analysis or the path of generated files. \n', - f"2. You should write this function to perform following task: " + txt + "\n", - f"3. Wrap the output python function with markdown codeblock." - ] - i_say = "".join(prompt_compose) - demo = [] - - # 第一步 - gpt_say = yield from request_gpt_model_in_new_thread_with_ui_alive( - inputs=i_say, inputs_show_user=i_say, - llm_kwargs=llm_kwargs, chatbot=chatbot, history=demo, - sys_prompt= r"You are a world-class programmer." - ) - history.extend([i_say, gpt_say]) - yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 # 界面更新 - - # 第二步 - prompt_compose = [ - "If previous stage is successful, rewrite the function you have just written to satisfy following templete: \n", - templete - ] - i_say = "".join(prompt_compose); inputs_show_user = "If previous stage is successful, rewrite the function you have just written to satisfy executable templete. " - gpt_say = yield from request_gpt_model_in_new_thread_with_ui_alive( - inputs=i_say, inputs_show_user=inputs_show_user, - llm_kwargs=llm_kwargs, chatbot=chatbot, history=history, - sys_prompt= r"You are a programmer. You need to replace `...` with valid packages, do not give `...` in your answer!" - ) - code_to_return = gpt_say - history.extend([i_say, gpt_say]) - yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 # 界面更新 - - # # 第三步 - # i_say = "Please list to packages to install to run the code above. Then show me how to use `try_install_deps` function to install them." - # i_say += 'For instance. `try_install_deps(["opencv-python", "scipy", "numpy"])`' - # installation_advance = yield from request_gpt_model_in_new_thread_with_ui_alive( - # inputs=i_say, inputs_show_user=inputs_show_user, - # llm_kwargs=llm_kwargs, chatbot=chatbot, history=history, - # sys_prompt= r"You are a programmer." - # ) - - # # # 第三步 - # i_say = "Show me how to use `pip` to install packages to run the code above. " - # i_say += 'For instance. `pip install -r opencv-python scipy numpy`' - # installation_advance = yield from request_gpt_model_in_new_thread_with_ui_alive( - # inputs=i_say, inputs_show_user=i_say, - # llm_kwargs=llm_kwargs, chatbot=chatbot, history=history, - # sys_prompt= r"You are a programmer." - # ) - installation_advance = "" - - return code_to_return, installation_advance, txt, file_type, llm_kwargs, chatbot, history - - - - -def for_immediate_show_off_when_possible(file_type, fp, chatbot): - if file_type in ['png', 'jpg']: - image_path = os.path.abspath(fp) - chatbot.append(['这是一张图片, 展示如下:', - f'本地文件地址:
`{image_path}`
'+ - f'本地文件预览:
' - ]) - return chatbot - - - -def have_any_recent_upload_files(chatbot): - _5min = 5 * 60 - if not chatbot: return False # chatbot is None - most_recent_uploaded = chatbot._cookies.get("most_recent_uploaded", None) - if not most_recent_uploaded: return False # most_recent_uploaded is None - if time.time() - most_recent_uploaded["time"] < _5min: return True # most_recent_uploaded is new - else: return False # most_recent_uploaded is too old - -def get_recent_file_prompt_support(chatbot): - most_recent_uploaded = chatbot._cookies.get("most_recent_uploaded", None) - path = most_recent_uploaded['path'] - return path - -@CatchException -def 函数动态生成(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request): - """ - txt 输入栏用户输入的文本,例如需要翻译的一段话,再例如一个包含了待处理文件的路径 - llm_kwargs gpt模型参数,如温度和top_p等,一般原样传递下去就行 - plugin_kwargs 插件模型的参数,暂时没有用武之地 - chatbot 聊天显示框的句柄,用于显示给用户 - history 聊天历史,前情提要 - system_prompt 给gpt的静默提醒 - user_request 当前用户的请求信息(IP地址等) - """ - - # 清空历史 - history = [] - - # 基本信息:功能、贡献者 - chatbot.append(["正在启动: 插件动态生成插件", "插件动态生成, 执行开始, 作者Binary-Husky."]) - yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 - - # ⭐ 文件上传区是否有东西 - # 1. 如果有文件: 作为函数参数 - # 2. 如果没有文件:需要用GPT提取参数 (太懒了,以后再写,虚空终端已经实现了类似的代码) - file_list = [] - if get_plugin_arg(plugin_kwargs, key="file_path_arg", default=False): - file_path = get_plugin_arg(plugin_kwargs, key="file_path_arg", default=None) - file_list.append(file_path) - yield from update_ui_lastest_msg(f"当前文件: {file_path}", chatbot, history, 1) - elif have_any_recent_upload_files(chatbot): - file_dir = get_recent_file_prompt_support(chatbot) - file_list = glob.glob(os.path.join(file_dir, '**/*'), recursive=True) - yield from update_ui_lastest_msg(f"当前文件处理列表: {file_list}", chatbot, history, 1) - else: - chatbot.append(["文件检索", "没有发现任何近期上传的文件。"]) - yield from update_ui_lastest_msg("没有发现任何近期上传的文件。", chatbot, history, 1) - return # 2. 如果没有文件 - if len(file_list) == 0: - chatbot.append(["文件检索", "没有发现任何近期上传的文件。"]) - yield from update_ui_lastest_msg("没有发现任何近期上传的文件。", chatbot, history, 1) - return # 2. 如果没有文件 - - # 读取文件 - file_type = file_list[0].split('.')[-1] - - # 粗心检查 - if is_the_upload_folder(txt): - yield from update_ui_lastest_msg(f"请在输入框内填写需求, 然后再次点击该插件! 至于您的文件,不用担心, 文件路径 {txt} 已经被记忆. ", chatbot, history, 1) - return - - # 开始干正事 - MAX_TRY = 3 - for j in range(MAX_TRY): # 最多重试5次 - traceback = "" - try: - # ⭐ 开始啦 ! - code, installation_advance, txt, file_type, llm_kwargs, chatbot, history = \ - yield from gpt_interact_multi_step(txt, file_type, llm_kwargs, chatbot, history) - chatbot.append(["代码生成阶段结束", ""]) - yield from update_ui_lastest_msg(f"正在验证上述代码的有效性 ...", chatbot, history, 1) - # ⭐ 分离代码块 - code = get_code_block(code) - # ⭐ 检查模块 - ok, traceback = try_make_module(code, chatbot) - # 搞定代码生成 - if ok: break - except Exception as e: - if not traceback: traceback = trimmed_format_exc() - # 处理异常 - if not traceback: traceback = trimmed_format_exc() - yield from update_ui_lastest_msg(f"第 {j+1}/{MAX_TRY} 次代码生成尝试, 失败了~ 别担心, 我们5秒后再试一次... \n\n此次我们的错误追踪是\n```\n{traceback}\n```\n", chatbot, history, 5) - - # 代码生成结束, 开始执行 - TIME_LIMIT = 15 - yield from update_ui_lastest_msg(f"开始创建新进程并执行代码! 时间限制 {TIME_LIMIT} 秒. 请等待任务完成... ", chatbot, history, 1) - manager = multiprocessing.Manager() - return_dict = manager.dict() - - # ⭐ 到最后一步了,开始逐个文件进行处理 - for file_path in file_list: - if os.path.exists(file_path): - chatbot.append([f"正在处理文件: {file_path}", f"请稍等..."]) - chatbot = for_immediate_show_off_when_possible(file_type, file_path, chatbot) - yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 # 界面更新 - else: - continue - - # ⭐⭐⭐ subprocess_worker ⭐⭐⭐ - p = multiprocessing.Process(target=subprocess_worker, args=(code, file_path, return_dict)) - # ⭐ 开始执行,时间限制TIME_LIMIT - p.start(); p.join(timeout=TIME_LIMIT) - if p.is_alive(): p.terminate(); p.join() - p.close() - res = return_dict['result'] - success = return_dict['success'] - traceback = return_dict['traceback'] - if not success: - if not traceback: traceback = trimmed_format_exc() - chatbot.append(["执行失败了", f"错误追踪\n```\n{trimmed_format_exc()}\n```\n"]) - # chatbot.append(["如果是缺乏依赖,请参考以下建议", installation_advance]) - yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 - return - - # 顺利完成,收尾 - res = str(res) - if os.path.exists(res): - chatbot.append(["执行成功了,结果是一个有效文件", "结果:" + res]) - new_file_path = promote_file_to_downloadzone(res, chatbot=chatbot) - chatbot = for_immediate_show_off_when_possible(file_type, new_file_path, chatbot) - yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 # 界面更新 - else: - chatbot.append(["执行成功了,结果是一个字符串", "结果:" + res]) - yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 # 界面更新 - diff --git "a/crazy_functions/\345\221\275\344\273\244\350\241\214\345\212\251\346\211\213.py" "b/crazy_functions/\345\221\275\344\273\244\350\241\214\345\212\251\346\211\213.py" index 286952445a1f4f262e47fec82a3f61243f85b5e5..4cbc08471822f51e2b4bc01c8ebfad25c1032f49 100644 --- "a/crazy_functions/\345\221\275\344\273\244\350\241\214\345\212\251\346\211\213.py" +++ "b/crazy_functions/\345\221\275\344\273\244\350\241\214\345\212\251\346\211\213.py" @@ -4,7 +4,7 @@ from .crazy_utils import input_clipping import copy, json @CatchException -def 命令行助手(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request): +def 命令行助手(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port): """ txt 输入栏用户输入的文本, 例如需要翻译的一段话, 再例如一个包含了待处理文件的路径 llm_kwargs gpt模型参数, 如温度和top_p等, 一般原样传递下去就行 @@ -12,7 +12,7 @@ def 命令行助手(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_pro chatbot 聊天显示框的句柄, 用于显示给用户 history 聊天历史, 前情提要 system_prompt 给gpt的静默提醒 - user_request 当前用户的请求信息(IP地址等) + web_port 当前软件运行的端口号 """ # 清空历史, 以免输入溢出 history = [] diff --git "a/crazy_functions/\345\233\276\347\211\207\347\224\237\346\210\220.py" "b/crazy_functions/\345\233\276\347\211\207\347\224\237\346\210\220.py" index 62f36626143c29a6c31f20a0067e2775ad870ce6..51a1baff54281c395e63a008581eabc04565ce2f 100644 --- "a/crazy_functions/\345\233\276\347\211\207\347\224\237\346\210\220.py" +++ "b/crazy_functions/\345\233\276\347\211\207\347\224\237\346\210\220.py" @@ -1,12 +1,13 @@ from toolbox import CatchException, update_ui, get_conf, select_api_key, get_log_folder -from crazy_functions.multi_stage.multi_stage_utils import GptAcademicState +from .crazy_utils import request_gpt_model_in_new_thread_with_ui_alive +import datetime -def gen_image(llm_kwargs, prompt, resolution="1024x1024", model="dall-e-2", quality=None, style=None): +def gen_image(llm_kwargs, prompt, resolution="256x256"): import requests, json, time, os - from request_llms.bridge_all import model_info + from request_llm.bridge_all import model_info - proxies = get_conf('proxies') + proxies, = get_conf('proxies') # Set up OpenAI API key and model api_key = select_api_key(llm_kwargs['api_key'], llm_kwargs['llm_model']) chat_endpoint = model_info[llm_kwargs['llm_model']]['endpoint'] @@ -22,13 +23,8 @@ def gen_image(llm_kwargs, prompt, resolution="1024x1024", model="dall-e-2", qual 'prompt': prompt, 'n': 1, 'size': resolution, - 'model': model, 'response_format': 'url' } - if quality is not None: - data['quality'] = quality - if style is not None: - data['style'] = style response = requests.post(url, headers=headers, json=data, proxies=proxies) print(response.content) try: @@ -46,72 +42,23 @@ def gen_image(llm_kwargs, prompt, resolution="1024x1024", model="dall-e-2", qual return image_url, file_path+file_name -def edit_image(llm_kwargs, prompt, image_path, resolution="1024x1024", model="dall-e-2"): - import requests, json, time, os - from request_llms.bridge_all import model_info - - proxies = get_conf('proxies') - api_key = select_api_key(llm_kwargs['api_key'], llm_kwargs['llm_model']) - chat_endpoint = model_info[llm_kwargs['llm_model']]['endpoint'] - # 'https://api.openai.com/v1/chat/completions' - img_endpoint = chat_endpoint.replace('chat/completions','images/edits') - # # Generate the image - url = img_endpoint - n = 1 - headers = { - 'Authorization': f"Bearer {api_key}", - } - make_transparent(image_path, image_path+'.tsp.png') - make_square_image(image_path+'.tsp.png', image_path+'.tspsq.png') - resize_image(image_path+'.tspsq.png', image_path+'.ready.png', max_size=1024) - image_path = image_path+'.ready.png' - with open(image_path, 'rb') as f: - file_content = f.read() - files = { - 'image': (os.path.basename(image_path), file_content), - # 'mask': ('mask.png', open('mask.png', 'rb')) - 'prompt': (None, prompt), - "n": (None, str(n)), - 'size': (None, resolution), - } - - response = requests.post(url, headers=headers, files=files, proxies=proxies) - print(response.content) - try: - image_url = json.loads(response.content.decode('utf8'))['data'][0]['url'] - except: - raise RuntimeError(response.content.decode()) - # 文件保存到本地 - r = requests.get(image_url, proxies=proxies) - file_path = f'{get_log_folder()}/image_gen/' - os.makedirs(file_path, exist_ok=True) - file_name = 'Image' + time.strftime("%Y-%m-%d-%H-%M-%S", time.localtime()) + '.png' - with open(file_path+file_name, 'wb+') as f: f.write(r.content) - - - return image_url, file_path+file_name - @CatchException -def 图片生成_DALLE2(prompt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request): +def 图片生成(prompt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port): """ - txt 输入栏用户输入的文本,例如需要翻译的一段话,再例如一个包含了待处理文件的路径 - llm_kwargs gpt模型参数,如温度和top_p等,一般原样传递下去就行 - plugin_kwargs 插件模型的参数,暂时没有用武之地 - chatbot 聊天显示框的句柄,用于显示给用户 - history 聊天历史,前情提要 + txt 输入栏用户输入的文本,例如需要翻译的一段话,再例如一个包含了待处理文件的路径 + llm_kwargs gpt模型参数,如温度和top_p等,一般原样传递下去就行 + plugin_kwargs 插件模型的参数,暂时没有用武之地 + chatbot 聊天显示框的句柄,用于显示给用户 + history 聊天历史,前情提要 system_prompt 给gpt的静默提醒 - user_request 当前用户的请求信息(IP地址等) + web_port 当前软件运行的端口号 """ - history = [] # 清空历史,以免输入溢出 - if prompt.strip() == "": - chatbot.append((prompt, "[Local Message] 图像生成提示为空白,请在“输入区”输入图像生成提示。")) - yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 界面更新 - return - chatbot.append(("您正在调用“图像生成”插件。", "[Local Message] 生成图像, 请先把模型切换至gpt-*。如果中文Prompt效果不理想, 请尝试英文Prompt。正在处理中 .....")) - yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 由于请求gpt需要一段时间,我们先及时地做一次界面更新 + history = [] # 清空历史,以免输入溢出 + chatbot.append(("这是什么功能?", "[Local Message] 生成图像, 请先把模型切换至gpt-*或者api2d-*。如果中文效果不理想, 请尝试英文Prompt。正在处理中 .....")) + yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 # 由于请求gpt需要一段时间,我们先及时地做一次界面更新 if ("advanced_arg" in plugin_kwargs) and (plugin_kwargs["advanced_arg"] == ""): plugin_kwargs.pop("advanced_arg") - resolution = plugin_kwargs.get("advanced_arg", '1024x1024') + resolution = plugin_kwargs.get("advanced_arg", '256x256') image_url, image_path = gen_image(llm_kwargs, prompt, resolution) chatbot.append([prompt, f'图像中转网址:
`{image_url}`
'+ @@ -119,158 +66,4 @@ def 图片生成_DALLE2(prompt, llm_kwargs, plugin_kwargs, chatbot, history, sys f'本地文件地址:
`{image_path}`
'+ f'本地文件预览:
' ]) - yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 界面更新 - - -@CatchException -def 图片生成_DALLE3(prompt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request): - history = [] # 清空历史,以免输入溢出 - if prompt.strip() == "": - chatbot.append((prompt, "[Local Message] 图像生成提示为空白,请在“输入区”输入图像生成提示。")) - yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 界面更新 - return - chatbot.append(("您正在调用“图像生成”插件。", "[Local Message] 生成图像, 请先把模型切换至gpt-*。如果中文Prompt效果不理想, 请尝试英文Prompt。正在处理中 .....")) - yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 由于请求gpt需要一段时间,我们先及时地做一次界面更新 - if ("advanced_arg" in plugin_kwargs) and (plugin_kwargs["advanced_arg"] == ""): plugin_kwargs.pop("advanced_arg") - resolution_arg = plugin_kwargs.get("advanced_arg", '1024x1024-standard-vivid').lower() - parts = resolution_arg.split('-') - resolution = parts[0] # 解析分辨率 - quality = 'standard' # 质量与风格默认值 - style = 'vivid' - # 遍历检查是否有额外参数 - for part in parts[1:]: - if part in ['hd', 'standard']: - quality = part - elif part in ['vivid', 'natural']: - style = part - image_url, image_path = gen_image(llm_kwargs, prompt, resolution, model="dall-e-3", quality=quality, style=style) - chatbot.append([prompt, - f'图像中转网址:
`{image_url}`
'+ - f'中转网址预览:
' - f'本地文件地址:
`{image_path}`
'+ - f'本地文件预览:
' - ]) - yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 界面更新 - - -class ImageEditState(GptAcademicState): - # 尚未完成 - def get_image_file(self, x): - import os, glob - if len(x) == 0: return False, None - if not os.path.exists(x): return False, None - if x.endswith('.png'): return True, x - file_manifest = [f for f in glob.glob(f'{x}/**/*.png', recursive=True)] - confirm = (len(file_manifest) >= 1 and file_manifest[0].endswith('.png') and os.path.exists(file_manifest[0])) - file = None if not confirm else file_manifest[0] - return confirm, file - - def lock_plugin(self, chatbot): - chatbot._cookies['lock_plugin'] = 'crazy_functions.图片生成->图片修改_DALLE2' - self.dump_state(chatbot) - - def unlock_plugin(self, chatbot): - self.reset() - chatbot._cookies['lock_plugin'] = None - self.dump_state(chatbot) - - def get_resolution(self, x): - return (x in ['256x256', '512x512', '1024x1024']), x - - def get_prompt(self, x): - confirm = (len(x)>=5) and (not self.get_resolution(x)[0]) and (not self.get_image_file(x)[0]) - return confirm, x - - def reset(self): - self.req = [ - {'value':None, 'description': '请先上传图像(必须是.png格式), 然后再次点击本插件', 'verify_fn': self.get_image_file}, - {'value':None, 'description': '请输入分辨率,可选:256x256, 512x512 或 1024x1024, 然后再次点击本插件', 'verify_fn': self.get_resolution}, - {'value':None, 'description': '请输入修改需求,建议您使用英文提示词, 然后再次点击本插件', 'verify_fn': self.get_prompt}, - ] - self.info = "" - - def feed(self, prompt, chatbot): - for r in self.req: - if r['value'] is None: - confirm, res = r['verify_fn'](prompt) - if confirm: - r['value'] = res - self.dump_state(chatbot) - break - return self - - def next_req(self): - for r in self.req: - if r['value'] is None: - return r['description'] - return "已经收集到所有信息" - - def already_obtained_all_materials(self): - return all([x['value'] is not None for x in self.req]) - -@CatchException -def 图片修改_DALLE2(prompt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request): - # 尚未完成 - history = [] # 清空历史 - state = ImageEditState.get_state(chatbot, ImageEditState) - state = state.feed(prompt, chatbot) - state.lock_plugin(chatbot) - if not state.already_obtained_all_materials(): - chatbot.append(["图片修改\n\n1. 上传图片(图片中需要修改的位置用橡皮擦擦除为纯白色,即RGB=255,255,255)\n2. 输入分辨率 \n3. 输入修改需求", state.next_req()]) - yield from update_ui(chatbot=chatbot, history=history) - return - - image_path = state.req[0]['value'] - resolution = state.req[1]['value'] - prompt = state.req[2]['value'] - chatbot.append(["图片修改, 执行中", f"图片:`{image_path}`
分辨率:`{resolution}`
修改需求:`{prompt}`"]) - yield from update_ui(chatbot=chatbot, history=history) - image_url, image_path = edit_image(llm_kwargs, prompt, image_path, resolution) - chatbot.append([prompt, - f'图像中转网址:
`{image_url}`
'+ - f'中转网址预览:
' - f'本地文件地址:
`{image_path}`
'+ - f'本地文件预览:
' - ]) - yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 界面更新 - state.unlock_plugin(chatbot) - -def make_transparent(input_image_path, output_image_path): - from PIL import Image - image = Image.open(input_image_path) - image = image.convert("RGBA") - data = image.getdata() - new_data = [] - for item in data: - if item[0] == 255 and item[1] == 255 and item[2] == 255: - new_data.append((255, 255, 255, 0)) - else: - new_data.append(item) - image.putdata(new_data) - image.save(output_image_path, "PNG") - -def resize_image(input_path, output_path, max_size=1024): - from PIL import Image - with Image.open(input_path) as img: - width, height = img.size - if width > max_size or height > max_size: - if width >= height: - new_width = max_size - new_height = int((max_size / width) * height) - else: - new_height = max_size - new_width = int((max_size / height) * width) - - resized_img = img.resize(size=(new_width, new_height)) - resized_img.save(output_path) - else: - img.save(output_path) - -def make_square_image(input_path, output_path): - from PIL import Image - with Image.open(input_path) as img: - width, height = img.size - size = max(width, height) - new_img = Image.new("RGBA", (size, size), color="black") - new_img.paste(img, ((size - width) // 2, (size - height) // 2)) - new_img.save(output_path) + yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 # 界面更新 diff --git "a/crazy_functions/\345\244\232\346\231\272\350\203\275\344\275\223.py" "b/crazy_functions/\345\244\232\346\231\272\350\203\275\344\275\223.py" deleted file mode 100644 index 4b16b8846d46c9589a001c159ef70d5dc475c8ad..0000000000000000000000000000000000000000 --- "a/crazy_functions/\345\244\232\346\231\272\350\203\275\344\275\223.py" +++ /dev/null @@ -1,101 +0,0 @@ -# 本源代码中, ⭐ = 关键步骤 -""" -测试: - - show me the solution of $x^2=cos(x)$, solve this problem with figure, and plot and save image to t.jpg - -""" - - -from toolbox import CatchException, update_ui, gen_time_str, trimmed_format_exc, ProxyNetworkActivate -from toolbox import get_conf, select_api_key, update_ui_lastest_msg, Singleton -from crazy_functions.crazy_utils import request_gpt_model_in_new_thread_with_ui_alive, get_plugin_arg -from crazy_functions.crazy_utils import input_clipping, try_install_deps -from crazy_functions.agent_fns.persistent import GradioMultiuserManagerForPersistentClasses -from crazy_functions.agent_fns.auto_agent import AutoGenMath -import time - -def remove_model_prefix(llm): - if llm.startswith('api2d-'): llm = llm.replace('api2d-', '') - if llm.startswith('azure-'): llm = llm.replace('azure-', '') - return llm - - -@CatchException -def 多智能体终端(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request): - """ - txt 输入栏用户输入的文本,例如需要翻译的一段话,再例如一个包含了待处理文件的路径 - llm_kwargs gpt模型参数,如温度和top_p等,一般原样传递下去就行 - plugin_kwargs 插件模型的参数 - chatbot 聊天显示框的句柄,用于显示给用户 - history 聊天历史,前情提要 - system_prompt 给gpt的静默提醒 - user_request 当前用户的请求信息(IP地址等) - """ - # 检查当前的模型是否符合要求 - supported_llms = [ - "gpt-3.5-turbo-16k", - 'gpt-3.5-turbo-1106', - "gpt-4", - "gpt-4-32k", - 'gpt-4-1106-preview', - "azure-gpt-3.5-turbo-16k", - "azure-gpt-3.5-16k", - "azure-gpt-4", - "azure-gpt-4-32k", - ] - from request_llms.bridge_all import model_info - if model_info[llm_kwargs['llm_model']]["max_token"] < 8000: # 至少是8k上下文的模型 - chatbot.append([f"处理任务: {txt}", f"当前插件只支持{str(supported_llms)}, 当前模型{llm_kwargs['llm_model']}的最大上下文长度太短, 不能支撑AutoGen运行。"]) - yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 - return - if model_info[llm_kwargs['llm_model']]["endpoint"] is not None: # 如果不是本地模型,加载API_KEY - llm_kwargs['api_key'] = select_api_key(llm_kwargs['api_key'], llm_kwargs['llm_model']) - - # 尝试导入依赖,如果缺少依赖,则给出安装建议 - try: - import autogen - if get_conf("AUTOGEN_USE_DOCKER"): - import docker - except: - chatbot.append([ f"处理任务: {txt}", - f"导入软件依赖失败。使用该模块需要额外依赖,安装方法```pip install --upgrade pyautogen docker```。"]) - yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 - return - - # 尝试导入依赖,如果缺少依赖,则给出安装建议 - try: - import autogen - import glob, os, time, subprocess - if get_conf("AUTOGEN_USE_DOCKER"): - subprocess.Popen(["docker", "--version"]) - except: - chatbot.append([f"处理任务: {txt}", f"缺少docker运行环境!"]) - yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 - return - - # 解锁插件 - chatbot.get_cookies()['lock_plugin'] = None - persistent_class_multi_user_manager = GradioMultiuserManagerForPersistentClasses() - user_uuid = chatbot.get_cookies().get('uuid') - persistent_key = f"{user_uuid}->多智能体终端" - if persistent_class_multi_user_manager.already_alive(persistent_key): - # 当已经存在一个正在运行的多智能体终端时,直接将用户输入传递给它,而不是再次启动一个新的多智能体终端 - print('[debug] feed new user input') - executor = persistent_class_multi_user_manager.get(persistent_key) - exit_reason = yield from executor.main_process_ui_control(txt, create_or_resume="resume") - else: - # 运行多智能体终端 (首次) - print('[debug] create new executor instance') - history = [] - chatbot.append(["正在启动: 多智能体终端", "插件动态生成, 执行开始, 作者 Microsoft & Binary-Husky."]) - yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 - executor = AutoGenMath(llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request) - persistent_class_multi_user_manager.set(persistent_key, executor) - exit_reason = yield from executor.main_process_ui_control(txt, create_or_resume="create") - - if exit_reason == "wait_feedback": - # 当用户点击了“等待反馈”按钮时,将executor存储到cookie中,等待用户的再次调用 - executor.chatbot.get_cookies()['lock_plugin'] = 'crazy_functions.多智能体->多智能体终端' - else: - executor.chatbot.get_cookies()['lock_plugin'] = None - yield from update_ui(chatbot=executor.chatbot, history=executor.history) # 更新状态 diff --git "a/crazy_functions/\345\257\271\350\257\235\345\216\206\345\217\262\345\255\230\346\241\243.py" "b/crazy_functions/\345\257\271\350\257\235\345\216\206\345\217\262\345\255\230\346\241\243.py" index 6ffc072f634e7c786238963929011229c352d46b..f89faeda27786afad2c246148601d3148dd44ea5 100644 --- "a/crazy_functions/\345\257\271\350\257\235\345\216\206\345\217\262\345\255\230\346\241\243.py" +++ "b/crazy_functions/\345\257\271\350\257\235\345\216\206\345\217\262\345\255\230\346\241\243.py" @@ -1,8 +1,7 @@ -from toolbox import CatchException, update_ui, promote_file_to_downloadzone, get_log_folder, get_user +from toolbox import CatchException, update_ui, promote_file_to_downloadzone, get_log_folder +from .crazy_utils import request_gpt_model_in_new_thread_with_ui_alive import re -f_prefix = 'GPT-Academic对话存档' - def write_chat_to_file(chatbot, history=None, file_name=None): """ 将对话记录history以Markdown格式写入文件中。如果没有指定文件名,则使用当前时间生成文件名。 @@ -10,8 +9,8 @@ def write_chat_to_file(chatbot, history=None, file_name=None): import os import time if file_name is None: - file_name = f_prefix + time.strftime("%Y-%m-%d-%H-%M-%S", time.localtime()) + '.html' - fp = os.path.join(get_log_folder(get_user(chatbot), plugin_name='chat_history'), file_name) + file_name = 'chatGPT对话历史' + time.strftime("%Y-%m-%d-%H-%M-%S", time.localtime()) + '.html' + fp = os.path.join(get_log_folder(), file_name) with open(fp, 'w', encoding='utf8') as f: from themes.theme import advanced_css f.write(f'对话历史') @@ -69,7 +68,7 @@ def read_file_to_chat(chatbot, history, file_name): return chatbot, history @CatchException -def 对话历史存档(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request): +def 对话历史存档(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port): """ txt 输入栏用户输入的文本,例如需要翻译的一段话,再例如一个包含了待处理文件的路径 llm_kwargs gpt模型参数,如温度和top_p等,一般原样传递下去就行 @@ -77,11 +76,11 @@ def 对话历史存档(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_ chatbot 聊天显示框的句柄,用于显示给用户 history 聊天历史,前情提要 system_prompt 给gpt的静默提醒 - user_request 当前用户的请求信息(IP地址等) + web_port 当前软件运行的端口号 """ chatbot.append(("保存当前对话", - f"[Local Message] {write_chat_to_file(chatbot, history)},您可以调用下拉菜单中的“载入对话历史存档”还原当下的对话。")) + f"[Local Message] {write_chat_to_file(chatbot, history)},您可以调用“载入对话历史存档”还原当下的对话。\n警告!被保存的对话历史可以被使用该系统的任何人查阅。")) yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 # 由于请求gpt需要一段时间,我们先及时地做一次界面更新 def hide_cwd(str): @@ -91,7 +90,7 @@ def hide_cwd(str): return str.replace(current_path, replace_path) @CatchException -def 载入对话历史存档(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request): +def 载入对话历史存档(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port): """ txt 输入栏用户输入的文本,例如需要翻译的一段话,再例如一个包含了待处理文件的路径 llm_kwargs gpt模型参数,如温度和top_p等,一般原样传递下去就行 @@ -99,7 +98,7 @@ def 载入对话历史存档(txt, llm_kwargs, plugin_kwargs, chatbot, history, s chatbot 聊天显示框的句柄,用于显示给用户 history 聊天历史,前情提要 system_prompt 给gpt的静默提醒 - user_request 当前用户的请求信息(IP地址等) + web_port 当前软件运行的端口号 """ from .crazy_utils import get_files_from_everything success, file_manifest, _ = get_files_from_everything(txt, type='.html') @@ -107,12 +106,7 @@ def 载入对话历史存档(txt, llm_kwargs, plugin_kwargs, chatbot, history, s if not success: if txt == "": txt = '空空如也的输入栏' import glob - local_history = "
".join([ - "`"+hide_cwd(f)+f" ({gen_file_preview(f)})"+"`" - for f in glob.glob( - f'{get_log_folder(get_user(chatbot), plugin_name="chat_history")}/**/{f_prefix}*.html', - recursive=True - )]) + local_history = "
".join(["`"+hide_cwd(f)+f" ({gen_file_preview(f)})"+"`" for f in glob.glob(f'{get_log_folder()}/**/chatGPT对话历史*.html', recursive=True)]) chatbot.append([f"正在查找对话历史文件(html格式): {txt}", f"找不到任何html文件: {txt}。但本地存储了以下历史文件,您可以将任意一个文件路径粘贴到输入区,然后重试:
{local_history}"]) yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 return @@ -126,7 +120,7 @@ def 载入对话历史存档(txt, llm_kwargs, plugin_kwargs, chatbot, history, s return @CatchException -def 删除所有本地对话历史记录(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request): +def 删除所有本地对话历史记录(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port): """ txt 输入栏用户输入的文本,例如需要翻译的一段话,再例如一个包含了待处理文件的路径 llm_kwargs gpt模型参数,如温度和top_p等,一般原样传递下去就行 @@ -134,16 +128,12 @@ def 删除所有本地对话历史记录(txt, llm_kwargs, plugin_kwargs, chatbot chatbot 聊天显示框的句柄,用于显示给用户 history 聊天历史,前情提要 system_prompt 给gpt的静默提醒 - user_request 当前用户的请求信息(IP地址等) + web_port 当前软件运行的端口号 """ import glob, os - local_history = "
".join([ - "`"+hide_cwd(f)+"`" - for f in glob.glob( - f'{get_log_folder(get_user(chatbot), plugin_name="chat_history")}/**/{f_prefix}*.html', recursive=True - )]) - for f in glob.glob(f'{get_log_folder(get_user(chatbot), plugin_name="chat_history")}/**/{f_prefix}*.html', recursive=True): + local_history = "
".join(["`"+hide_cwd(f)+"`" for f in glob.glob(f'{get_log_folder()}/**/chatGPT对话历史*.html', recursive=True)]) + for f in glob.glob(f'{get_log_folder()}/**/chatGPT对话历史*.html', recursive=True): os.remove(f) chatbot.append([f"删除所有历史对话文件", f"已删除
{local_history}"]) yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 diff --git "a/crazy_functions/\346\200\273\347\273\223word\346\226\207\346\241\243.py" "b/crazy_functions/\346\200\273\347\273\223word\346\226\207\346\241\243.py" index 8793ea4490c07c36688fed0ae95bbbfcbb6f073b..4ea753cbdf7149c77910c1cf217be9eb5bfa3e56 100644 --- "a/crazy_functions/\346\200\273\347\273\223word\346\226\207\346\241\243.py" +++ "b/crazy_functions/\346\200\273\347\273\223word\346\226\207\346\241\243.py" @@ -1,5 +1,5 @@ from toolbox import update_ui -from toolbox import CatchException, report_exception +from toolbox import CatchException, report_execption from toolbox import write_history_to_file, promote_file_to_downloadzone from .crazy_utils import request_gpt_model_in_new_thread_with_ui_alive fast_debug = False @@ -29,12 +29,17 @@ def 解析docx(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot except: raise RuntimeError('请先将.doc文档转换为.docx文档。') + print(file_content) # private_upload里面的文件名在解压zip后容易出现乱码(rar和7z格式正常),故可以只分析文章内容,不输入文件名 - from crazy_functions.pdf_fns.breakdown_txt import breakdown_text_to_satisfy_token_limit - from request_llms.bridge_all import model_info + from .crazy_utils import breakdown_txt_to_satisfy_token_limit_for_pdf + from request_llm.bridge_all import model_info max_token = model_info[llm_kwargs['llm_model']]['max_token'] TOKEN_LIMIT_PER_FRAGMENT = max_token * 3 // 4 - paper_fragments = breakdown_text_to_satisfy_token_limit(txt=file_content, limit=TOKEN_LIMIT_PER_FRAGMENT, llm_model=llm_kwargs['llm_model']) + paper_fragments = breakdown_txt_to_satisfy_token_limit_for_pdf( + txt=file_content, + get_token_fn=model_info[llm_kwargs['llm_model']]['token_cnt'], + limit=TOKEN_LIMIT_PER_FRAGMENT + ) this_paper_history = [] for i, paper_frag in enumerate(paper_fragments): i_say = f'请对下面的文章片段用中文做概述,文件名是{os.path.relpath(fp, project_folder)},文章内容是 ```{paper_frag}```' @@ -79,7 +84,7 @@ def 解析docx(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot @CatchException -def 总结word文档(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request): +def 总结word文档(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port): import glob, os # 基本信息:功能、贡献者 @@ -92,7 +97,7 @@ def 总结word文档(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_pr try: from docx import Document except: - report_exception(chatbot, history, + report_execption(chatbot, history, a=f"解析项目: {txt}", b=f"导入软件依赖失败。使用该模块需要额外依赖,安装方法```pip install --upgrade python-docx pywin32```。") yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 @@ -106,7 +111,7 @@ def 总结word文档(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_pr project_folder = txt else: if txt == "": txt = '空空如也的输入栏' - report_exception(chatbot, history, a=f"解析项目: {txt}", b=f"找不到本地项目或无权访问: {txt}") + report_execption(chatbot, history, a=f"解析项目: {txt}", b=f"找不到本地项目或无权访问: {txt}") yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 return @@ -119,7 +124,7 @@ def 总结word文档(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_pr # 如果没找到任何文件 if len(file_manifest) == 0: - report_exception(chatbot, history, a=f"解析项目: {txt}", b=f"找不到任何.docx或doc文件: {txt}") + report_execption(chatbot, history, a=f"解析项目: {txt}", b=f"找不到任何.docx或doc文件: {txt}") yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 return diff --git "a/crazy_functions/\346\200\273\347\273\223\351\237\263\350\247\206\351\242\221.py" "b/crazy_functions/\346\200\273\347\273\223\351\237\263\350\247\206\351\242\221.py" index b27bcce06c4c83d491dd5bae445be957436204f9..7c113f476adbecdeb0d9c78e28547a095d020b2e 100644 --- "a/crazy_functions/\346\200\273\347\273\223\351\237\263\350\247\206\351\242\221.py" +++ "b/crazy_functions/\346\200\273\347\273\223\351\237\263\350\247\206\351\242\221.py" @@ -1,4 +1,4 @@ -from toolbox import CatchException, report_exception, select_api_key, update_ui, get_conf +from toolbox import CatchException, report_execption, select_api_key, update_ui, get_conf from .crazy_utils import request_gpt_model_in_new_thread_with_ui_alive from toolbox import write_history_to_file, promote_file_to_downloadzone, get_log_folder @@ -41,7 +41,7 @@ def split_audio_file(filename, split_duration=1000): def AnalyAudio(parse_prompt, file_manifest, llm_kwargs, chatbot, history): import os, requests from moviepy.editor import AudioFileClip - from request_llms.bridge_all import model_info + from request_llm.bridge_all import model_info # 设置OpenAI密钥和模型 api_key = select_api_key(llm_kwargs['api_key'], llm_kwargs['llm_model']) @@ -79,7 +79,7 @@ def AnalyAudio(parse_prompt, file_manifest, llm_kwargs, chatbot, history): chatbot.append([f"将 {i} 发送到openai音频解析终端 (whisper),当前参数:{parse_prompt}", "正在处理 ..."]) yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 - proxies = get_conf('proxies') + proxies, = get_conf('proxies') response = requests.post(url, headers=headers, files=files, data=data, proxies=proxies).text chatbot.append(["音频解析结果", response]) @@ -144,7 +144,7 @@ def 总结音视频(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_pro try: from moviepy.editor import AudioFileClip except: - report_exception(chatbot, history, + report_execption(chatbot, history, a=f"解析项目: {txt}", b=f"导入软件依赖失败。使用该模块需要额外依赖,安装方法```pip install --upgrade moviepy```。") yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 @@ -158,7 +158,7 @@ def 总结音视频(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_pro project_folder = txt else: if txt == "": txt = '空空如也的输入栏' - report_exception(chatbot, history, a=f"解析项目: {txt}", b=f"找不到本地项目或无权访问: {txt}") + report_execption(chatbot, history, a=f"解析项目: {txt}", b=f"找不到本地项目或无权访问: {txt}") yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 return @@ -174,7 +174,7 @@ def 总结音视频(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_pro # 如果没找到任何文件 if len(file_manifest) == 0: - report_exception(chatbot, history, a=f"解析项目: {txt}", b=f"找不到任何音频或视频文件: {txt}") + report_execption(chatbot, history, a=f"解析项目: {txt}", b=f"找不到任何音频或视频文件: {txt}") yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 return diff --git "a/crazy_functions/\346\211\271\351\207\217Markdown\347\277\273\350\257\221.py" "b/crazy_functions/\346\211\271\351\207\217Markdown\347\277\273\350\257\221.py" index 1d876d080a7272cc1a9108416d619afd1af11d86..9485b1ec187e9ab73b30f3450cd7bb96c46a659d 100644 --- "a/crazy_functions/\346\211\271\351\207\217Markdown\347\277\273\350\257\221.py" +++ "b/crazy_functions/\346\211\271\351\207\217Markdown\347\277\273\350\257\221.py" @@ -1,6 +1,6 @@ import glob, time, os, re, logging from toolbox import update_ui, trimmed_format_exc, gen_time_str, disable_auto_promotion -from toolbox import CatchException, report_exception, get_log_folder +from toolbox import CatchException, report_execption, get_log_folder from toolbox import write_history_to_file, promote_file_to_downloadzone fast_debug = False @@ -13,7 +13,7 @@ class PaperFileGroup(): self.sp_file_tag = [] # count_token - from request_llms.bridge_all import model_info + from request_llm.bridge_all import model_info enc = model_info["gpt-3.5-turbo"]['tokenizer'] def get_token_num(txt): return len(enc.encode(txt, disallowed_special=())) self.get_token_num = get_token_num @@ -28,8 +28,8 @@ class PaperFileGroup(): self.sp_file_index.append(index) self.sp_file_tag.append(self.file_paths[index]) else: - from crazy_functions.pdf_fns.breakdown_txt import breakdown_text_to_satisfy_token_limit - segments = breakdown_text_to_satisfy_token_limit(file_content, max_token_limit) + from .crazy_utils import breakdown_txt_to_satisfy_token_limit_for_pdf + segments = breakdown_txt_to_satisfy_token_limit_for_pdf(file_content, self.get_token_num, max_token_limit) for j, segment in enumerate(segments): self.sp_file_contents.append(segment) self.sp_file_index.append(index) @@ -118,7 +118,7 @@ def get_files_from_everything(txt, preference=''): if txt.startswith('http'): import requests from toolbox import get_conf - proxies = get_conf('proxies') + proxies, = get_conf('proxies') # 网络的远程文件 if preference == 'Github': logging.info('正在从github下载资源 ...') @@ -153,7 +153,7 @@ def get_files_from_everything(txt, preference=''): @CatchException -def Markdown英译中(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request): +def Markdown英译中(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port): # 基本信息:功能、贡献者 chatbot.append([ "函数插件功能?", @@ -165,7 +165,7 @@ def Markdown英译中(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_p try: import tiktoken except: - report_exception(chatbot, history, + report_execption(chatbot, history, a=f"解析项目: {txt}", b=f"导入软件依赖失败。使用该模块需要额外依赖,安装方法```pip install --upgrade tiktoken```。") yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 @@ -177,12 +177,12 @@ def Markdown英译中(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_p if not success: # 什么都没有 if txt == "": txt = '空空如也的输入栏' - report_exception(chatbot, history, a = f"解析项目: {txt}", b = f"找不到本地项目或无权访问: {txt}") + report_execption(chatbot, history, a = f"解析项目: {txt}", b = f"找不到本地项目或无权访问: {txt}") yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 return if len(file_manifest) == 0: - report_exception(chatbot, history, a = f"解析项目: {txt}", b = f"找不到任何.md文件: {txt}") + report_execption(chatbot, history, a = f"解析项目: {txt}", b = f"找不到任何.md文件: {txt}") yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 return @@ -193,7 +193,7 @@ def Markdown英译中(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_p @CatchException -def Markdown中译英(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request): +def Markdown中译英(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port): # 基本信息:功能、贡献者 chatbot.append([ "函数插件功能?", @@ -205,7 +205,7 @@ def Markdown中译英(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_p try: import tiktoken except: - report_exception(chatbot, history, + report_execption(chatbot, history, a=f"解析项目: {txt}", b=f"导入软件依赖失败。使用该模块需要额外依赖,安装方法```pip install --upgrade tiktoken```。") yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 @@ -215,18 +215,18 @@ def Markdown中译英(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_p if not success: # 什么都没有 if txt == "": txt = '空空如也的输入栏' - report_exception(chatbot, history, a = f"解析项目: {txt}", b = f"找不到本地项目或无权访问: {txt}") + report_execption(chatbot, history, a = f"解析项目: {txt}", b = f"找不到本地项目或无权访问: {txt}") yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 return if len(file_manifest) == 0: - report_exception(chatbot, history, a = f"解析项目: {txt}", b = f"找不到任何.md文件: {txt}") + report_execption(chatbot, history, a = f"解析项目: {txt}", b = f"找不到任何.md文件: {txt}") yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 return yield from 多文件翻译(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, language='zh->en') @CatchException -def Markdown翻译指定语言(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request): +def Markdown翻译指定语言(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port): # 基本信息:功能、贡献者 chatbot.append([ "函数插件功能?", @@ -238,7 +238,7 @@ def Markdown翻译指定语言(txt, llm_kwargs, plugin_kwargs, chatbot, history, try: import tiktoken except: - report_exception(chatbot, history, + report_execption(chatbot, history, a=f"解析项目: {txt}", b=f"导入软件依赖失败。使用该模块需要额外依赖,安装方法```pip install --upgrade tiktoken```。") yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 @@ -248,11 +248,11 @@ def Markdown翻译指定语言(txt, llm_kwargs, plugin_kwargs, chatbot, history, if not success: # 什么都没有 if txt == "": txt = '空空如也的输入栏' - report_exception(chatbot, history, a = f"解析项目: {txt}", b = f"找不到本地项目或无权访问: {txt}") + report_execption(chatbot, history, a = f"解析项目: {txt}", b = f"找不到本地项目或无权访问: {txt}") yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 return if len(file_manifest) == 0: - report_exception(chatbot, history, a = f"解析项目: {txt}", b = f"找不到任何.md文件: {txt}") + report_execption(chatbot, history, a = f"解析项目: {txt}", b = f"找不到任何.md文件: {txt}") yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 return diff --git "a/crazy_functions/\346\211\271\351\207\217\346\200\273\347\273\223PDF\346\226\207\346\241\243.py" "b/crazy_functions/\346\211\271\351\207\217\346\200\273\347\273\223PDF\346\226\207\346\241\243.py" index 54270ab982b55d59e5b8f7cb1e0f27209cc6c83d..b87d482585aee762331973ba26e50c60d14cfb44 100644 --- "a/crazy_functions/\346\211\271\351\207\217\346\200\273\347\273\223PDF\346\226\207\346\241\243.py" +++ "b/crazy_functions/\346\211\271\351\207\217\346\200\273\347\273\223PDF\346\226\207\346\241\243.py" @@ -1,5 +1,5 @@ from toolbox import update_ui, promote_file_to_downloadzone, gen_time_str -from toolbox import CatchException, report_exception +from toolbox import CatchException, report_execption from toolbox import write_history_to_file, promote_file_to_downloadzone from .crazy_utils import request_gpt_model_in_new_thread_with_ui_alive from .crazy_utils import read_and_clean_pdf_text @@ -20,9 +20,14 @@ def 解析PDF(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot, TOKEN_LIMIT_PER_FRAGMENT = 2500 - from crazy_functions.pdf_fns.breakdown_txt import breakdown_text_to_satisfy_token_limit - paper_fragments = breakdown_text_to_satisfy_token_limit(txt=file_content, limit=TOKEN_LIMIT_PER_FRAGMENT, llm_model=llm_kwargs['llm_model']) - page_one_fragments = breakdown_text_to_satisfy_token_limit(txt=str(page_one), limit=TOKEN_LIMIT_PER_FRAGMENT//4, llm_model=llm_kwargs['llm_model']) + from .crazy_utils import breakdown_txt_to_satisfy_token_limit_for_pdf + from request_llm.bridge_all import model_info + enc = model_info["gpt-3.5-turbo"]['tokenizer'] + def get_token_num(txt): return len(enc.encode(txt, disallowed_special=())) + paper_fragments = breakdown_txt_to_satisfy_token_limit_for_pdf( + txt=file_content, get_token_fn=get_token_num, limit=TOKEN_LIMIT_PER_FRAGMENT) + page_one_fragments = breakdown_txt_to_satisfy_token_limit_for_pdf( + txt=str(page_one), get_token_fn=get_token_num, limit=TOKEN_LIMIT_PER_FRAGMENT//4) # 为了更好的效果,我们剥离Introduction之后的部分(如果有) paper_meta = page_one_fragments[0].split('introduction')[0].split('Introduction')[0].split('INTRODUCTION')[0] @@ -101,7 +106,7 @@ do not have too much repetitive information, numerical values using the original @CatchException -def 批量总结PDF文档(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request): +def 批量总结PDF文档(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port): import glob, os # 基本信息:功能、贡献者 @@ -114,7 +119,7 @@ def 批量总结PDF文档(txt, llm_kwargs, plugin_kwargs, chatbot, history, syst try: import fitz except: - report_exception(chatbot, history, + report_execption(chatbot, history, a = f"解析项目: {txt}", b = f"导入软件依赖失败。使用该模块需要额外依赖,安装方法```pip install --upgrade pymupdf```。") yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 @@ -128,7 +133,7 @@ def 批量总结PDF文档(txt, llm_kwargs, plugin_kwargs, chatbot, history, syst project_folder = txt else: if txt == "": txt = '空空如也的输入栏' - report_exception(chatbot, history, a = f"解析项目: {txt}", b = f"找不到本地项目或无权访问: {txt}") + report_execption(chatbot, history, a = f"解析项目: {txt}", b = f"找不到本地项目或无权访问: {txt}") yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 return @@ -137,7 +142,7 @@ def 批量总结PDF文档(txt, llm_kwargs, plugin_kwargs, chatbot, history, syst # 如果没找到任何文件 if len(file_manifest) == 0: - report_exception(chatbot, history, a = f"解析项目: {txt}", b = f"找不到任何.tex或.pdf文件: {txt}") + report_execption(chatbot, history, a = f"解析项目: {txt}", b = f"找不到任何.tex或.pdf文件: {txt}") yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 return diff --git "a/crazy_functions/\346\211\271\351\207\217\346\200\273\347\273\223PDF\346\226\207\346\241\243pdfminer.py" "b/crazy_functions/\346\211\271\351\207\217\346\200\273\347\273\223PDF\346\226\207\346\241\243pdfminer.py" index 181d51ce1b40ae0f25429fa71a056160202296c9..213d8bb26446683fdb87e06e20004dc3861eb087 100644 --- "a/crazy_functions/\346\211\271\351\207\217\346\200\273\347\273\223PDF\346\226\207\346\241\243pdfminer.py" +++ "b/crazy_functions/\346\211\271\351\207\217\346\200\273\347\273\223PDF\346\226\207\346\241\243pdfminer.py" @@ -1,5 +1,5 @@ from toolbox import update_ui -from toolbox import CatchException, report_exception +from toolbox import CatchException, report_execption from .crazy_utils import request_gpt_model_in_new_thread_with_ui_alive from toolbox import write_history_to_file, promote_file_to_downloadzone @@ -124,7 +124,7 @@ def 解析Paper(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbo @CatchException -def 批量总结PDF文档pdfminer(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request): +def 批量总结PDF文档pdfminer(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port): history = [] # 清空历史,以免输入溢出 import glob, os @@ -138,7 +138,7 @@ def 批量总结PDF文档pdfminer(txt, llm_kwargs, plugin_kwargs, chatbot, histo try: import pdfminer, bs4 except: - report_exception(chatbot, history, + report_execption(chatbot, history, a = f"解析项目: {txt}", b = f"导入软件依赖失败。使用该模块需要额外依赖,安装方法```pip install --upgrade pdfminer beautifulsoup4```。") yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 @@ -147,7 +147,7 @@ def 批量总结PDF文档pdfminer(txt, llm_kwargs, plugin_kwargs, chatbot, histo project_folder = txt else: if txt == "": txt = '空空如也的输入栏' - report_exception(chatbot, history, a = f"解析项目: {txt}", b = f"找不到本地项目或无权访问: {txt}") + report_execption(chatbot, history, a = f"解析项目: {txt}", b = f"找不到本地项目或无权访问: {txt}") yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 return file_manifest = [f for f in glob.glob(f'{project_folder}/**/*.tex', recursive=True)] + \ @@ -155,7 +155,7 @@ def 批量总结PDF文档pdfminer(txt, llm_kwargs, plugin_kwargs, chatbot, histo # [f for f in glob.glob(f'{project_folder}/**/*.cpp', recursive=True)] + \ # [f for f in glob.glob(f'{project_folder}/**/*.c', recursive=True)] if len(file_manifest) == 0: - report_exception(chatbot, history, a = f"解析项目: {txt}", b = f"找不到任何.tex或pdf文件: {txt}") + report_execption(chatbot, history, a = f"解析项目: {txt}", b = f"找不到任何.tex或pdf文件: {txt}") yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 return yield from 解析Paper(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt) diff --git "a/crazy_functions/\346\211\271\351\207\217\347\277\273\350\257\221PDF\346\226\207\346\241\243_NOUGAT.py" "b/crazy_functions/\346\211\271\351\207\217\347\277\273\350\257\221PDF\346\226\207\346\241\243_NOUGAT.py" index 7a18277778df2c1044eeeb5524ee6f3dff78f982..2dc15f79088fd9df01f9cc85760a495da14b2eb2 100644 --- "a/crazy_functions/\346\211\271\351\207\217\347\277\273\350\257\221PDF\346\226\207\346\241\243_NOUGAT.py" +++ "b/crazy_functions/\346\211\271\351\207\217\347\277\273\350\257\221PDF\346\226\207\346\241\243_NOUGAT.py" @@ -1,12 +1,11 @@ -from toolbox import CatchException, report_exception, get_log_folder, gen_time_str +from toolbox import CatchException, report_execption, gen_time_str from toolbox import update_ui, promote_file_to_downloadzone, update_ui_lastest_msg, disable_auto_promotion -from toolbox import write_history_to_file, promote_file_to_downloadzone +from toolbox import write_history_to_file, get_log_folder from .crazy_utils import request_gpt_model_in_new_thread_with_ui_alive from .crazy_utils import request_gpt_model_multi_threads_with_very_awesome_ui_and_high_efficiency from .crazy_utils import read_and_clean_pdf_text -from .pdf_fns.parse_pdf import parse_pdf, get_avail_grobid_url, translate_pdf +from .pdf_fns.parse_pdf import parse_pdf, get_avail_grobid_url from colorful import * -import copy import os import math import logging @@ -48,7 +47,7 @@ def markdown_to_dict(article_content): @CatchException -def 批量翻译PDF文档(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request): +def 批量翻译PDF文档(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port): disable_auto_promotion(chatbot) # 基本信息:功能、贡献者 @@ -57,35 +56,30 @@ def 批量翻译PDF文档(txt, llm_kwargs, plugin_kwargs, chatbot, history, syst "批量翻译PDF文档。函数插件贡献者: Binary-Husky"]) yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 + # 尝试导入依赖,如果缺少依赖,则给出安装建议 + try: + import nougat + import tiktoken + except: + report_execption(chatbot, history, + a=f"解析项目: {txt}", + b=f"导入软件依赖失败。使用该模块需要额外依赖,安装方法```pip install --upgrade nougat-ocr tiktoken```。") + yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 + return + # 清空历史,以免输入溢出 history = [] from .crazy_utils import get_files_from_everything success, file_manifest, project_folder = get_files_from_everything(txt, type='.pdf') - if len(file_manifest) > 0: - # 尝试导入依赖,如果缺少依赖,则给出安装建议 - try: - import nougat - import tiktoken - except: - report_exception(chatbot, history, - a=f"解析项目: {txt}", - b=f"导入软件依赖失败。使用该模块需要额外依赖,安装方法```pip install --upgrade nougat-ocr tiktoken```。") - yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 - return - success_mmd, file_manifest_mmd, _ = get_files_from_everything(txt, type='.mmd') - success = success or success_mmd - file_manifest += file_manifest_mmd - chatbot.append(["文件列表:", ", ".join([e.split('/')[-1] for e in file_manifest])]); - yield from update_ui( chatbot=chatbot, history=history) # 检测输入参数,如没有给定输入参数,直接退出 if not success: if txt == "": txt = '空空如也的输入栏' # 如果没找到任何文件 if len(file_manifest) == 0: - report_exception(chatbot, history, - a=f"解析项目: {txt}", b=f"找不到任何.pdf拓展名的文件: {txt}") + report_execption(chatbot, history, + a=f"解析项目: {txt}", b=f"找不到任何.tex或.pdf文件: {txt}") yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 return @@ -98,26 +92,110 @@ def 批量翻译PDF文档(txt, llm_kwargs, plugin_kwargs, chatbot, history, syst def 解析PDF_基于NOUGAT(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt): import copy import tiktoken - TOKEN_LIMIT_PER_FRAGMENT = 1024 + TOKEN_LIMIT_PER_FRAGMENT = 1280 generated_conclusion_files = [] generated_html_files = [] DST_LANG = "中文" - from crazy_functions.crazy_utils import nougat_interface - from crazy_functions.pdf_fns.report_gen_html import construct_html + from crazy_functions.crazy_utils import nougat_interface, construct_html nougat_handle = nougat_interface() for index, fp in enumerate(file_manifest): - if fp.endswith('pdf'): - chatbot.append(["当前进度:", f"正在解析论文,请稍候。(第一次运行时,需要花费较长时间下载NOUGAT参数)"]); yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 - fpp = yield from nougat_handle.NOUGAT_parse_pdf(fp, chatbot, history) - promote_file_to_downloadzone(fpp, rename_file=os.path.basename(fpp)+'.nougat.mmd', chatbot=chatbot) - else: - chatbot.append(["当前论文无需解析:", fp]); yield from update_ui( chatbot=chatbot, history=history) - fpp = fp + chatbot.append(["当前进度:", f"正在解析论文,请稍候。(第一次运行时,需要花费较长时间下载NOUGAT参数)"]); yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 + fpp = yield from nougat_handle.NOUGAT_parse_pdf(fp, chatbot, history) + with open(fpp, 'r', encoding='utf8') as f: article_content = f.readlines() article_dict = markdown_to_dict(article_content) logging.info(article_dict) - yield from translate_pdf(article_dict, llm_kwargs, chatbot, fp, generated_conclusion_files, TOKEN_LIMIT_PER_FRAGMENT, DST_LANG) + + prompt = "以下是一篇学术论文的基本信息:\n" + # title + title = article_dict.get('title', '无法获取 title'); prompt += f'title:{title}\n\n' + # authors + authors = article_dict.get('authors', '无法获取 authors'); prompt += f'authors:{authors}\n\n' + # abstract + abstract = article_dict.get('abstract', '无法获取 abstract'); prompt += f'abstract:{abstract}\n\n' + # command + prompt += f"请将题目和摘要翻译为{DST_LANG}。" + meta = [f'# Title:\n\n', title, f'# Abstract:\n\n', abstract ] + + # 单线,获取文章meta信息 + paper_meta_info = yield from request_gpt_model_in_new_thread_with_ui_alive( + inputs=prompt, + inputs_show_user=prompt, + llm_kwargs=llm_kwargs, + chatbot=chatbot, history=[], + sys_prompt="You are an academic paper reader。", + ) + + # 多线,翻译 + inputs_array = [] + inputs_show_user_array = [] + + # get_token_num + from request_llm.bridge_all import model_info + enc = model_info[llm_kwargs['llm_model']]['tokenizer'] + def get_token_num(txt): return len(enc.encode(txt, disallowed_special=())) + from .crazy_utils import breakdown_txt_to_satisfy_token_limit_for_pdf + + def break_down(txt): + raw_token_num = get_token_num(txt) + if raw_token_num <= TOKEN_LIMIT_PER_FRAGMENT: + return [txt] + else: + # raw_token_num > TOKEN_LIMIT_PER_FRAGMENT + # find a smooth token limit to achieve even seperation + count = int(math.ceil(raw_token_num / TOKEN_LIMIT_PER_FRAGMENT)) + token_limit_smooth = raw_token_num // count + count + return breakdown_txt_to_satisfy_token_limit_for_pdf(txt, get_token_fn=get_token_num, limit=token_limit_smooth) + + for section in article_dict.get('sections'): + if len(section['text']) == 0: continue + section_frags = break_down(section['text']) + for i, fragment in enumerate(section_frags): + heading = section['heading'] + if len(section_frags) > 1: heading += f' Part-{i+1}' + inputs_array.append( + f"你需要翻译{heading}章节,内容如下: \n\n{fragment}" + ) + inputs_show_user_array.append( + f"# {heading}\n\n{fragment}" + ) + + gpt_response_collection = yield from request_gpt_model_multi_threads_with_very_awesome_ui_and_high_efficiency( + inputs_array=inputs_array, + inputs_show_user_array=inputs_show_user_array, + llm_kwargs=llm_kwargs, + chatbot=chatbot, + history_array=[meta for _ in inputs_array], + sys_prompt_array=[ + "请你作为一个学术翻译,负责把学术论文准确翻译成中文。注意文章中的每一句话都要翻译。" for _ in inputs_array], + ) + res_path = write_history_to_file(meta + ["# Meta Translation" , paper_meta_info] + gpt_response_collection, file_basename=None, file_fullname=None) + promote_file_to_downloadzone(res_path, rename_file=os.path.basename(fp)+'.md', chatbot=chatbot) + generated_conclusion_files.append(res_path) + + ch = construct_html() + orig = "" + trans = "" + gpt_response_collection_html = copy.deepcopy(gpt_response_collection) + for i,k in enumerate(gpt_response_collection_html): + if i%2==0: + gpt_response_collection_html[i] = inputs_show_user_array[i//2] + else: + gpt_response_collection_html[i] = gpt_response_collection_html[i] + + final = ["", "", "一、论文概况", "", "Abstract", paper_meta_info, "二、论文翻译", ""] + final.extend(gpt_response_collection_html) + for i, k in enumerate(final): + if i%2==0: + orig = k + if i%2==1: + trans = k + ch.add_row(a=orig, b=trans) + create_report_file_name = f"{os.path.basename(fp)}.trans.html" + html_file = ch.save_file(create_report_file_name) + generated_html_files.append(html_file) + promote_file_to_downloadzone(html_file, rename_file=os.path.basename(html_file), chatbot=chatbot) chatbot.append(("给出输出文件清单", str(generated_conclusion_files + generated_html_files))) yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 diff --git "a/crazy_functions/\346\211\271\351\207\217\347\277\273\350\257\221PDF\346\226\207\346\241\243_\345\244\232\347\272\277\347\250\213.py" "b/crazy_functions/\346\211\271\351\207\217\347\277\273\350\257\221PDF\346\226\207\346\241\243_\345\244\232\347\272\277\347\250\213.py" index 3d111629ae58ba1f1d8887e3dabbe18c45d746c4..d620715bfbe4de451bcf29a03a449e07ecea4efc 100644 --- "a/crazy_functions/\346\211\271\351\207\217\347\277\273\350\257\221PDF\346\226\207\346\241\243_\345\244\232\347\272\277\347\250\213.py" +++ "b/crazy_functions/\346\211\271\351\207\217\347\277\273\350\257\221PDF\346\226\207\346\241\243_\345\244\232\347\272\277\347\250\213.py" @@ -1,16 +1,17 @@ -from toolbox import CatchException, report_exception, get_log_folder, gen_time_str, check_packages +from toolbox import CatchException, report_execption, get_log_folder from toolbox import update_ui, promote_file_to_downloadzone, update_ui_lastest_msg, disable_auto_promotion from toolbox import write_history_to_file, promote_file_to_downloadzone from .crazy_utils import request_gpt_model_in_new_thread_with_ui_alive from .crazy_utils import request_gpt_model_multi_threads_with_very_awesome_ui_and_high_efficiency from .crazy_utils import read_and_clean_pdf_text -from .pdf_fns.parse_pdf import parse_pdf, get_avail_grobid_url, translate_pdf +from .pdf_fns.parse_pdf import parse_pdf, get_avail_grobid_url from colorful import * +import glob import os - +import math @CatchException -def 批量翻译PDF文档(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request): +def 批量翻译PDF文档(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port): disable_auto_promotion(chatbot) # 基本信息:功能、贡献者 @@ -21,9 +22,11 @@ def 批量翻译PDF文档(txt, llm_kwargs, plugin_kwargs, chatbot, history, syst # 尝试导入依赖,如果缺少依赖,则给出安装建议 try: - check_packages(["fitz", "tiktoken", "scipdf"]) + import fitz + import tiktoken + import scipdf except: - report_exception(chatbot, history, + report_execption(chatbot, history, a=f"解析项目: {txt}", b=f"导入软件依赖失败。使用该模块需要额外依赖,安装方法```pip install --upgrade pymupdf tiktoken scipdf_parser```。") yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 @@ -40,8 +43,8 @@ def 批量翻译PDF文档(txt, llm_kwargs, plugin_kwargs, chatbot, history, syst # 如果没找到任何文件 if len(file_manifest) == 0: - report_exception(chatbot, history, - a=f"解析项目: {txt}", b=f"找不到任何.pdf拓展名的文件: {txt}") + report_execption(chatbot, history, + a=f"解析项目: {txt}", b=f"找不到任何.tex或.pdf文件: {txt}") yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 return @@ -55,35 +58,116 @@ def 批量翻译PDF文档(txt, llm_kwargs, plugin_kwargs, chatbot, history, syst def 解析PDF_基于GROBID(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, grobid_url): - import copy, json - TOKEN_LIMIT_PER_FRAGMENT = 1024 + import copy + TOKEN_LIMIT_PER_FRAGMENT = 1280 generated_conclusion_files = [] generated_html_files = [] DST_LANG = "中文" - from crazy_functions.pdf_fns.report_gen_html import construct_html + from crazy_functions.crazy_utils import construct_html for index, fp in enumerate(file_manifest): chatbot.append(["当前进度:", f"正在连接GROBID服务,请稍候: {grobid_url}\n如果等待时间过长,请修改config中的GROBID_URL,可修改成本地GROBID服务。"]); yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 article_dict = parse_pdf(fp, grobid_url) - grobid_json_res = os.path.join(get_log_folder(), gen_time_str() + "grobid.json") - with open(grobid_json_res, 'w+', encoding='utf8') as f: - f.write(json.dumps(article_dict, indent=4, ensure_ascii=False)) - promote_file_to_downloadzone(grobid_json_res, chatbot=chatbot) - if article_dict is None: raise RuntimeError("解析PDF失败,请检查PDF是否损坏。") - yield from translate_pdf(article_dict, llm_kwargs, chatbot, fp, generated_conclusion_files, TOKEN_LIMIT_PER_FRAGMENT, DST_LANG) + prompt = "以下是一篇学术论文的基本信息:\n" + # title + title = article_dict.get('title', '无法获取 title'); prompt += f'title:{title}\n\n' + # authors + authors = article_dict.get('authors', '无法获取 authors'); prompt += f'authors:{authors}\n\n' + # abstract + abstract = article_dict.get('abstract', '无法获取 abstract'); prompt += f'abstract:{abstract}\n\n' + # command + prompt += f"请将题目和摘要翻译为{DST_LANG}。" + meta = [f'# Title:\n\n', title, f'# Abstract:\n\n', abstract ] + + # 单线,获取文章meta信息 + paper_meta_info = yield from request_gpt_model_in_new_thread_with_ui_alive( + inputs=prompt, + inputs_show_user=prompt, + llm_kwargs=llm_kwargs, + chatbot=chatbot, history=[], + sys_prompt="You are an academic paper reader。", + ) + + # 多线,翻译 + inputs_array = [] + inputs_show_user_array = [] + + # get_token_num + from request_llm.bridge_all import model_info + enc = model_info[llm_kwargs['llm_model']]['tokenizer'] + def get_token_num(txt): return len(enc.encode(txt, disallowed_special=())) + from .crazy_utils import breakdown_txt_to_satisfy_token_limit_for_pdf + + def break_down(txt): + raw_token_num = get_token_num(txt) + if raw_token_num <= TOKEN_LIMIT_PER_FRAGMENT: + return [txt] + else: + # raw_token_num > TOKEN_LIMIT_PER_FRAGMENT + # find a smooth token limit to achieve even seperation + count = int(math.ceil(raw_token_num / TOKEN_LIMIT_PER_FRAGMENT)) + token_limit_smooth = raw_token_num // count + count + return breakdown_txt_to_satisfy_token_limit_for_pdf(txt, get_token_fn=get_token_num, limit=token_limit_smooth) + + for section in article_dict.get('sections'): + if len(section['text']) == 0: continue + section_frags = break_down(section['text']) + for i, fragment in enumerate(section_frags): + heading = section['heading'] + if len(section_frags) > 1: heading += f' Part-{i+1}' + inputs_array.append( + f"你需要翻译{heading}章节,内容如下: \n\n{fragment}" + ) + inputs_show_user_array.append( + f"# {heading}\n\n{fragment}" + ) + + gpt_response_collection = yield from request_gpt_model_multi_threads_with_very_awesome_ui_and_high_efficiency( + inputs_array=inputs_array, + inputs_show_user_array=inputs_show_user_array, + llm_kwargs=llm_kwargs, + chatbot=chatbot, + history_array=[meta for _ in inputs_array], + sys_prompt_array=[ + "请你作为一个学术翻译,负责把学术论文准确翻译成中文。注意文章中的每一句话都要翻译。" for _ in inputs_array], + ) + res_path = write_history_to_file(meta + ["# Meta Translation" , paper_meta_info] + gpt_response_collection, file_basename=None, file_fullname=None) + promote_file_to_downloadzone(res_path, rename_file=os.path.basename(fp)+'.md', chatbot=chatbot) + generated_conclusion_files.append(res_path) + + ch = construct_html() + orig = "" + trans = "" + gpt_response_collection_html = copy.deepcopy(gpt_response_collection) + for i,k in enumerate(gpt_response_collection_html): + if i%2==0: + gpt_response_collection_html[i] = inputs_show_user_array[i//2] + else: + gpt_response_collection_html[i] = gpt_response_collection_html[i] + + final = ["", "", "一、论文概况", "", "Abstract", paper_meta_info, "二、论文翻译", ""] + final.extend(gpt_response_collection_html) + for i, k in enumerate(final): + if i%2==0: + orig = k + if i%2==1: + trans = k + ch.add_row(a=orig, b=trans) + create_report_file_name = f"{os.path.basename(fp)}.trans.html" + html_file = ch.save_file(create_report_file_name) + generated_html_files.append(html_file) + promote_file_to_downloadzone(html_file, rename_file=os.path.basename(html_file), chatbot=chatbot) + chatbot.append(("给出输出文件清单", str(generated_conclusion_files + generated_html_files))) yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 def 解析PDF(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt): - """ - 此函数已经弃用 - """ import copy - TOKEN_LIMIT_PER_FRAGMENT = 1024 + TOKEN_LIMIT_PER_FRAGMENT = 1280 generated_conclusion_files = [] generated_html_files = [] - from crazy_functions.pdf_fns.report_gen_html import construct_html + from crazy_functions.crazy_utils import construct_html for index, fp in enumerate(file_manifest): # 读取PDF文件 file_content, page_one = read_and_clean_pdf_text(fp) @@ -91,9 +175,14 @@ def 解析PDF(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot, page_one = str(page_one).encode('utf-8', 'ignore').decode() # avoid reading non-utf8 chars # 递归地切割PDF文件 - from crazy_functions.pdf_fns.breakdown_txt import breakdown_text_to_satisfy_token_limit - paper_fragments = breakdown_text_to_satisfy_token_limit(txt=file_content, limit=TOKEN_LIMIT_PER_FRAGMENT, llm_model=llm_kwargs['llm_model']) - page_one_fragments = breakdown_text_to_satisfy_token_limit(txt=page_one, limit=TOKEN_LIMIT_PER_FRAGMENT//4, llm_model=llm_kwargs['llm_model']) + from .crazy_utils import breakdown_txt_to_satisfy_token_limit_for_pdf + from request_llm.bridge_all import model_info + enc = model_info["gpt-3.5-turbo"]['tokenizer'] + def get_token_num(txt): return len(enc.encode(txt, disallowed_special=())) + paper_fragments = breakdown_txt_to_satisfy_token_limit_for_pdf( + txt=file_content, get_token_fn=get_token_num, limit=TOKEN_LIMIT_PER_FRAGMENT) + page_one_fragments = breakdown_txt_to_satisfy_token_limit_for_pdf( + txt=page_one, get_token_fn=get_token_num, limit=TOKEN_LIMIT_PER_FRAGMENT//4) # 为了更好的效果,我们剥离Introduction之后的部分(如果有) paper_meta = page_one_fragments[0].split('introduction')[0].split('Introduction')[0].split('INTRODUCTION')[0] diff --git "a/crazy_functions/\346\225\260\345\255\246\345\212\250\347\224\273\347\224\237\346\210\220manim.py" "b/crazy_functions/\346\225\260\345\255\246\345\212\250\347\224\273\347\224\237\346\210\220manim.py" index 9465cccd10580fb551e0866867262143ab1b2d4e..26e61b1b3032c180b4cb59625eba00d5f7b7c441 100644 --- "a/crazy_functions/\346\225\260\345\255\246\345\212\250\347\224\273\347\224\237\346\210\220manim.py" +++ "b/crazy_functions/\346\225\260\345\255\246\345\212\250\347\224\273\347\224\237\346\210\220manim.py" @@ -1,7 +1,6 @@ -import os -from toolbox import CatchException, update_ui, gen_time_str, promote_file_to_downloadzone -from crazy_functions.crazy_utils import request_gpt_model_in_new_thread_with_ui_alive -from crazy_functions.crazy_utils import input_clipping +from toolbox import CatchException, update_ui, gen_time_str +from .crazy_utils import request_gpt_model_in_new_thread_with_ui_alive +from .crazy_utils import input_clipping def inspect_dependency(chatbot, history): # 尝试导入依赖,如果缺少依赖,则给出安装建议 @@ -28,10 +27,9 @@ def eval_manim(code): class_name = get_class_name(code) try: - time_str = gen_time_str() subprocess.check_output([sys.executable, '-c', f"from gpt_log.MyAnimation import {class_name}; {class_name}().render()"]) - shutil.move(f'media/videos/1080p60/{class_name}.mp4', f'gpt_log/{class_name}-{time_str}.mp4') - return f'gpt_log/{time_str}.mp4' + shutil.move('media/videos/1080p60/{class_name}.mp4', f'gpt_log/{class_name}-{gen_time_str()}.mp4') + return f'gpt_log/{gen_time_str()}.mp4' except subprocess.CalledProcessError as e: output = e.output.decode() print(f"Command returned non-zero exit status {e.returncode}: {output}.") @@ -50,7 +48,7 @@ def get_code_block(reply): return matches[0].strip('python') # code block @CatchException -def 动画生成(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request): +def 动画生成(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port): """ txt 输入栏用户输入的文本,例如需要翻译的一段话,再例如一个包含了待处理文件的路径 llm_kwargs gpt模型参数,如温度和top_p等,一般原样传递下去就行 @@ -58,7 +56,7 @@ def 动画生成(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt chatbot 聊天显示框的句柄,用于显示给用户 history 聊天历史,前情提要 system_prompt 给gpt的静默提醒 - user_request 当前用户的请求信息(IP地址等) + web_port 当前软件运行的端口号 """ # 清空历史,以免输入溢出 history = [] @@ -96,8 +94,6 @@ def 动画生成(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt res = eval_manim(code) chatbot.append(("生成的视频文件路径", res)) - if os.path.exists(res): - promote_file_to_downloadzone(res, chatbot=chatbot) yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 # 界面更新 # 在这里放一些网上搜集的demo,辅助gpt生成代码 diff --git "a/crazy_functions/\347\220\206\350\247\243PDF\346\226\207\346\241\243\345\206\205\345\256\271.py" "b/crazy_functions/\347\220\206\350\247\243PDF\346\226\207\346\241\243\345\206\205\345\256\271.py" index 732c82c08db5f33b43452a33d26347814e4be5db..f1a89a7ec94f30a00b58ad85661a876efc0ac4d2 100644 --- "a/crazy_functions/\347\220\206\350\247\243PDF\346\226\207\346\241\243\345\206\205\345\256\271.py" +++ "b/crazy_functions/\347\220\206\350\247\243PDF\346\226\207\346\241\243\345\206\205\345\256\271.py" @@ -1,5 +1,5 @@ from toolbox import update_ui -from toolbox import CatchException, report_exception +from toolbox import CatchException, report_execption from .crazy_utils import read_and_clean_pdf_text from .crazy_utils import request_gpt_model_in_new_thread_with_ui_alive fast_debug = False @@ -18,9 +18,14 @@ def 解析PDF(file_name, llm_kwargs, plugin_kwargs, chatbot, history, system_pro TOKEN_LIMIT_PER_FRAGMENT = 2500 - from crazy_functions.pdf_fns.breakdown_txt import breakdown_text_to_satisfy_token_limit - paper_fragments = breakdown_text_to_satisfy_token_limit(txt=file_content, limit=TOKEN_LIMIT_PER_FRAGMENT, llm_model=llm_kwargs['llm_model']) - page_one_fragments = breakdown_text_to_satisfy_token_limit(txt=str(page_one), limit=TOKEN_LIMIT_PER_FRAGMENT//4, llm_model=llm_kwargs['llm_model']) + from .crazy_utils import breakdown_txt_to_satisfy_token_limit_for_pdf + from request_llm.bridge_all import model_info + enc = model_info["gpt-3.5-turbo"]['tokenizer'] + def get_token_num(txt): return len(enc.encode(txt, disallowed_special=())) + paper_fragments = breakdown_txt_to_satisfy_token_limit_for_pdf( + txt=file_content, get_token_fn=get_token_num, limit=TOKEN_LIMIT_PER_FRAGMENT) + page_one_fragments = breakdown_txt_to_satisfy_token_limit_for_pdf( + txt=str(page_one), get_token_fn=get_token_num, limit=TOKEN_LIMIT_PER_FRAGMENT//4) # 为了更好的效果,我们剥离Introduction之后的部分(如果有) paper_meta = page_one_fragments[0].split('introduction')[0].split('Introduction')[0].split('INTRODUCTION')[0] @@ -40,11 +45,11 @@ def 解析PDF(file_name, llm_kwargs, plugin_kwargs, chatbot, history, system_pro for i in range(n_fragment): NUM_OF_WORD = MAX_WORD_TOTAL // n_fragment i_say = f"Read this section, recapitulate the content of this section with less than {NUM_OF_WORD} words: {paper_fragments[i]}" - i_say_show_user = f"[{i+1}/{n_fragment}] Read this section, recapitulate the content of this section with less than {NUM_OF_WORD} words: {paper_fragments[i][:200]} ...." + i_say_show_user = f"[{i+1}/{n_fragment}] Read this section, recapitulate the content of this section with less than {NUM_OF_WORD} words: {paper_fragments[i][:200]}" gpt_say = yield from request_gpt_model_in_new_thread_with_ui_alive(i_say, i_say_show_user, # i_say=真正给chatgpt的提问, i_say_show_user=给用户看的提问 llm_kwargs, chatbot, history=["The main idea of the previous section is?", last_iteration_result], # 迭代上一次的结果 - sys_prompt="Extract the main idea of this section, answer me with Chinese." # 提示 + sys_prompt="Extract the main idea of this section." # 提示 ) iteration_results.append(gpt_say) last_iteration_result = gpt_say @@ -63,7 +68,7 @@ def 解析PDF(file_name, llm_kwargs, plugin_kwargs, chatbot, history, system_pro @CatchException -def 理解PDF文档内容标准文件输入(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request): +def 理解PDF文档内容标准文件输入(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port): import glob, os # 基本信息:功能、贡献者 @@ -76,7 +81,7 @@ def 理解PDF文档内容标准文件输入(txt, llm_kwargs, plugin_kwargs, chat try: import fitz except: - report_exception(chatbot, history, + report_execption(chatbot, history, a = f"解析项目: {txt}", b = f"导入软件依赖失败。使用该模块需要额外依赖,安装方法```pip install --upgrade pymupdf```。") yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 @@ -91,7 +96,7 @@ def 理解PDF文档内容标准文件输入(txt, llm_kwargs, plugin_kwargs, chat else: if txt == "": txt = '空空如也的输入栏' - report_exception(chatbot, history, + report_execption(chatbot, history, a=f"解析项目: {txt}", b=f"找不到本地项目或无权访问: {txt}") yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 return @@ -100,7 +105,7 @@ def 理解PDF文档内容标准文件输入(txt, llm_kwargs, plugin_kwargs, chat file_manifest = [f for f in glob.glob(f'{project_folder}/**/*.pdf', recursive=True)] # 如果没找到任何文件 if len(file_manifest) == 0: - report_exception(chatbot, history, + report_execption(chatbot, history, a=f"解析项目: {txt}", b=f"找不到任何.tex或.pdf文件: {txt}") yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 return diff --git "a/crazy_functions/\347\224\237\346\210\220\345\207\275\346\225\260\346\263\250\351\207\212.py" "b/crazy_functions/\347\224\237\346\210\220\345\207\275\346\225\260\346\263\250\351\207\212.py" index 78aa45355616c2f51570a71f719ede0eff18b549..bf3da6a4b973b311a19757d4b5e6cc4127542e8b 100644 --- "a/crazy_functions/\347\224\237\346\210\220\345\207\275\346\225\260\346\263\250\351\207\212.py" +++ "b/crazy_functions/\347\224\237\346\210\220\345\207\275\346\225\260\346\263\250\351\207\212.py" @@ -1,5 +1,5 @@ from toolbox import update_ui -from toolbox import CatchException, report_exception +from toolbox import CatchException, report_execption from toolbox import write_history_to_file, promote_file_to_downloadzone from .crazy_utils import request_gpt_model_in_new_thread_with_ui_alive fast_debug = False @@ -36,21 +36,21 @@ def 生成函数注释(file_manifest, project_folder, llm_kwargs, plugin_kwargs, @CatchException -def 批量生成函数注释(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request): +def 批量生成函数注释(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port): history = [] # 清空历史,以免输入溢出 import glob, os if os.path.exists(txt): project_folder = txt else: if txt == "": txt = '空空如也的输入栏' - report_exception(chatbot, history, a = f"解析项目: {txt}", b = f"找不到本地项目或无权访问: {txt}") + report_execption(chatbot, history, a = f"解析项目: {txt}", b = f"找不到本地项目或无权访问: {txt}") yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 return file_manifest = [f for f in glob.glob(f'{project_folder}/**/*.py', recursive=True)] + \ [f for f in glob.glob(f'{project_folder}/**/*.cpp', recursive=True)] if len(file_manifest) == 0: - report_exception(chatbot, history, a = f"解析项目: {txt}", b = f"找不到任何.tex文件: {txt}") + report_execption(chatbot, history, a = f"解析项目: {txt}", b = f"找不到任何.tex文件: {txt}") yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 return yield from 生成函数注释(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt) diff --git "a/crazy_functions/\347\224\237\346\210\220\345\244\232\347\247\215Mermaid\345\233\276\350\241\250.py" "b/crazy_functions/\347\224\237\346\210\220\345\244\232\347\247\215Mermaid\345\233\276\350\241\250.py" deleted file mode 100644 index dc01e9405343f39ee2e19648a0045b230a73f163..0000000000000000000000000000000000000000 --- "a/crazy_functions/\347\224\237\346\210\220\345\244\232\347\247\215Mermaid\345\233\276\350\241\250.py" +++ /dev/null @@ -1,296 +0,0 @@ -from toolbox import CatchException, update_ui, report_exception -from .crazy_utils import request_gpt_model_in_new_thread_with_ui_alive -import datetime - -#以下是每类图表的PROMPT -SELECT_PROMPT = """ -“{subject}” -============= -以上是从文章中提取的摘要,将会使用这些摘要绘制图表。请你选择一个合适的图表类型: -1 流程图 -2 序列图 -3 类图 -4 饼图 -5 甘特图 -6 状态图 -7 实体关系图 -8 象限提示图 -不需要解释原因,仅需要输出单个不带任何标点符号的数字。 -""" -#没有思维导图!!!测试发现模型始终会优先选择思维导图 -#流程图 -PROMPT_1 = """ -请你给出围绕“{subject}”的逻辑关系图,使用mermaid语法,mermaid语法举例: -```mermaid -graph TD - P(编程) --> L1(Python) - P(编程) --> L2(C) - P(编程) --> L3(C++) - P(编程) --> L4(Javascipt) - P(编程) --> L5(PHP) -``` -""" -#序列图 -PROMPT_2 = """ -请你给出围绕“{subject}”的序列图,使用mermaid语法,mermaid语法举例: -```mermaid -sequenceDiagram - participant A as 用户 - participant B as 系统 - A->>B: 登录请求 - B->>A: 登录成功 - A->>B: 获取数据 - B->>A: 返回数据 -``` -""" -#类图 -PROMPT_3 = """ -请你给出围绕“{subject}”的类图,使用mermaid语法,mermaid语法举例: -```mermaid -classDiagram - Class01 <|-- AveryLongClass : Cool - Class03 *-- Class04 - Class05 o-- Class06 - Class07 .. Class08 - Class09 --> C2 : Where am i? - Class09 --* C3 - Class09 --|> Class07 - Class07 : equals() - Class07 : Object[] elementData - Class01 : size() - Class01 : int chimp - Class01 : int gorilla - Class08 <--> C2: Cool label -``` -""" -#饼图 -PROMPT_4 = """ -请你给出围绕“{subject}”的饼图,使用mermaid语法,mermaid语法举例: -```mermaid -pie title Pets adopted by volunteers - "狗" : 386 - "猫" : 85 - "兔子" : 15 -``` -""" -#甘特图 -PROMPT_5 = """ -请你给出围绕“{subject}”的甘特图,使用mermaid语法,mermaid语法举例: -```mermaid -gantt - title 项目开发流程 - dateFormat YYYY-MM-DD - section 设计 - 需求分析 :done, des1, 2024-01-06,2024-01-08 - 原型设计 :active, des2, 2024-01-09, 3d - UI设计 : des3, after des2, 5d - section 开发 - 前端开发 :2024-01-20, 10d - 后端开发 :2024-01-20, 10d -``` -""" -#状态图 -PROMPT_6 = """ -请你给出围绕“{subject}”的状态图,使用mermaid语法,mermaid语法举例: -```mermaid -stateDiagram-v2 - [*] --> Still - Still --> [*] - Still --> Moving - Moving --> Still - Moving --> Crash - Crash --> [*] -``` -""" -#实体关系图 -PROMPT_7 = """ -请你给出围绕“{subject}”的实体关系图,使用mermaid语法,mermaid语法举例: -```mermaid -erDiagram - CUSTOMER ||--o{ ORDER : places - ORDER ||--|{ LINE-ITEM : contains - CUSTOMER { - string name - string id - } - ORDER { - string orderNumber - date orderDate - string customerID - } - LINE-ITEM { - number quantity - string productID - } -``` -""" -#象限提示图 -PROMPT_8 = """ -请你给出围绕“{subject}”的象限图,使用mermaid语法,mermaid语法举例: -```mermaid -graph LR - A[Hard skill] --> B(Programming) - A[Hard skill] --> C(Design) - D[Soft skill] --> E(Coordination) - D[Soft skill] --> F(Communication) -``` -""" -#思维导图 -PROMPT_9 = """ -{subject} -========== -请给出上方内容的思维导图,充分考虑其之间的逻辑,使用mermaid语法,mermaid语法举例: -```mermaid -mindmap - root((mindmap)) - Origins - Long history - ::icon(fa fa-book) - Popularisation - British popular psychology author Tony Buzan - Research - On effectiveness
and features - On Automatic creation - Uses - Creative techniques - Strategic planning - Argument mapping - Tools - Pen and paper - Mermaid -``` -""" - -def 解析历史输入(history,llm_kwargs,file_manifest,chatbot,plugin_kwargs): - ############################## <第 0 步,切割输入> ################################## - # 借用PDF切割中的函数对文本进行切割 - TOKEN_LIMIT_PER_FRAGMENT = 2500 - txt = str(history).encode('utf-8', 'ignore').decode() # avoid reading non-utf8 chars - from crazy_functions.pdf_fns.breakdown_txt import breakdown_text_to_satisfy_token_limit - txt = breakdown_text_to_satisfy_token_limit(txt=txt, limit=TOKEN_LIMIT_PER_FRAGMENT, llm_model=llm_kwargs['llm_model']) - ############################## <第 1 步,迭代地历遍整个文章,提取精炼信息> ################################## - results = [] - MAX_WORD_TOTAL = 4096 - n_txt = len(txt) - last_iteration_result = "从以下文本中提取摘要。" - if n_txt >= 20: print('文章极长,不能达到预期效果') - for i in range(n_txt): - NUM_OF_WORD = MAX_WORD_TOTAL // n_txt - i_say = f"Read this section, recapitulate the content of this section with less than {NUM_OF_WORD} words in Chinese: {txt[i]}" - i_say_show_user = f"[{i+1}/{n_txt}] Read this section, recapitulate the content of this section with less than {NUM_OF_WORD} words: {txt[i][:200]} ...." - gpt_say = yield from request_gpt_model_in_new_thread_with_ui_alive(i_say, i_say_show_user, # i_say=真正给chatgpt的提问, i_say_show_user=给用户看的提问 - llm_kwargs, chatbot, - history=["The main content of the previous section is?", last_iteration_result], # 迭代上一次的结果 - sys_prompt="Extracts the main content from the text section where it is located for graphing purposes, answer me with Chinese." # 提示 - ) - results.append(gpt_say) - last_iteration_result = gpt_say - ############################## <第 2 步,根据整理的摘要选择图表类型> ################################## - if ("advanced_arg" in plugin_kwargs) and (plugin_kwargs["advanced_arg"] == ""): plugin_kwargs.pop("advanced_arg") - gpt_say = plugin_kwargs.get("advanced_arg", "") #将图表类型参数赋值为插件参数 - results_txt = '\n'.join(results) #合并摘要 - if gpt_say not in ['1','2','3','4','5','6','7','8','9']: #如插件参数不正确则使用对话模型判断 - i_say_show_user = f'接下来将判断适合的图表类型,如连续3次判断失败将会使用流程图进行绘制'; gpt_say = "[Local Message] 收到。" # 用户提示 - chatbot.append([i_say_show_user, gpt_say]); yield from update_ui(chatbot=chatbot, history=[]) # 更新UI - i_say = SELECT_PROMPT.format(subject=results_txt) - i_say_show_user = f'请判断适合使用的流程图类型,其中数字对应关系为:1-流程图,2-序列图,3-类图,4-饼图,5-甘特图,6-状态图,7-实体关系图,8-象限提示图。由于不管提供文本是什么,模型大概率认为"思维导图"最合适,因此思维导图仅能通过参数调用。' - for i in range(3): - gpt_say = yield from request_gpt_model_in_new_thread_with_ui_alive( - inputs=i_say, - inputs_show_user=i_say_show_user, - llm_kwargs=llm_kwargs, chatbot=chatbot, history=[], - sys_prompt="" - ) - if gpt_say in ['1','2','3','4','5','6','7','8','9']: #判断返回是否正确 - break - if gpt_say not in ['1','2','3','4','5','6','7','8','9']: - gpt_say = '1' - ############################## <第 3 步,根据选择的图表类型绘制图表> ################################## - if gpt_say == '1': - i_say = PROMPT_1.format(subject=results_txt) - elif gpt_say == '2': - i_say = PROMPT_2.format(subject=results_txt) - elif gpt_say == '3': - i_say = PROMPT_3.format(subject=results_txt) - elif gpt_say == '4': - i_say = PROMPT_4.format(subject=results_txt) - elif gpt_say == '5': - i_say = PROMPT_5.format(subject=results_txt) - elif gpt_say == '6': - i_say = PROMPT_6.format(subject=results_txt) - elif gpt_say == '7': - i_say = PROMPT_7.replace("{subject}", results_txt) #由于实体关系图用到了{}符号 - elif gpt_say == '8': - i_say = PROMPT_8.format(subject=results_txt) - elif gpt_say == '9': - i_say = PROMPT_9.format(subject=results_txt) - i_say_show_user = f'请根据判断结果绘制相应的图表。如需绘制思维导图请使用参数调用,同时过大的图表可能需要复制到在线编辑器中进行渲染。' - gpt_say = yield from request_gpt_model_in_new_thread_with_ui_alive( - inputs=i_say, - inputs_show_user=i_say_show_user, - llm_kwargs=llm_kwargs, chatbot=chatbot, history=[], - sys_prompt="" - ) - history.append(gpt_say) - yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 # 界面更新 - -@CatchException -def 生成多种Mermaid图表(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port): - """ - txt 输入栏用户输入的文本,例如需要翻译的一段话,再例如一个包含了待处理文件的路径 - llm_kwargs gpt模型参数,如温度和top_p等,一般原样传递下去就行 - plugin_kwargs 插件模型的参数,用于灵活调整复杂功能的各种参数 - chatbot 聊天显示框的句柄,用于显示给用户 - history 聊天历史,前情提要 - system_prompt 给gpt的静默提醒 - web_port 当前软件运行的端口号 - """ - import os - - # 基本信息:功能、贡献者 - chatbot.append([ - "函数插件功能?", - "根据当前聊天历史或指定的路径文件(文件内容优先)绘制多种mermaid图表,将会由对话模型首先判断适合的图表类型,随后绘制图表。\ - \n您也可以使用插件参数指定绘制的图表类型,函数插件贡献者: Menghuan1918"]) - yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 - - if os.path.exists(txt): #如输入区无内容则直接解析历史记录 - from crazy_functions.pdf_fns.parse_word import extract_text_from_files - file_exist, final_result, page_one, file_manifest, excption = extract_text_from_files(txt, chatbot, history) - else: - file_exist = False - excption = "" - file_manifest = [] - - if excption != "": - if excption == "word": - report_exception(chatbot, history, - a = f"解析项目: {txt}", - b = f"找到了.doc文件,但是该文件格式不被支持,请先转化为.docx格式。") - - elif excption == "pdf": - report_exception(chatbot, history, - a = f"解析项目: {txt}", - b = f"导入软件依赖失败。使用该模块需要额外依赖,安装方法```pip install --upgrade pymupdf```。") - - elif excption == "word_pip": - report_exception(chatbot, history, - a=f"解析项目: {txt}", - b=f"导入软件依赖失败。使用该模块需要额外依赖,安装方法```pip install --upgrade python-docx pywin32```。") - - yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 - - else: - if not file_exist: - history.append(txt) #如输入区不是文件则将输入区内容加入历史记录 - i_say_show_user = f'首先你从历史记录中提取摘要。'; gpt_say = "[Local Message] 收到。" # 用户提示 - chatbot.append([i_say_show_user, gpt_say]); yield from update_ui(chatbot=chatbot, history=history) # 更新UI - yield from 解析历史输入(history,llm_kwargs,file_manifest,chatbot,plugin_kwargs) - else: - file_num = len(file_manifest) - for i in range(file_num): #依次处理文件 - i_say_show_user = f"[{i+1}/{file_num}]处理文件{file_manifest[i]}"; gpt_say = "[Local Message] 收到。" # 用户提示 - chatbot.append([i_say_show_user, gpt_say]); yield from update_ui(chatbot=chatbot, history=history) # 更新UI - history = [] #如输入区内容为文件则清空历史记录 - history.append(final_result[i]) - yield from 解析历史输入(history,llm_kwargs,file_manifest,chatbot,plugin_kwargs) \ No newline at end of file diff --git "a/crazy_functions/\347\237\245\350\257\206\345\272\223\351\227\256\347\255\224.py" "b/crazy_functions/\347\237\245\350\257\206\345\272\223\351\227\256\347\255\224.py" deleted file mode 100644 index f3c7c9e3fc95305bc470d122c89a12f1786c94ee..0000000000000000000000000000000000000000 --- "a/crazy_functions/\347\237\245\350\257\206\345\272\223\351\227\256\347\255\224.py" +++ /dev/null @@ -1,117 +0,0 @@ -from toolbox import CatchException, update_ui, ProxyNetworkActivate, update_ui_lastest_msg, get_log_folder, get_user -from .crazy_utils import request_gpt_model_in_new_thread_with_ui_alive, get_files_from_everything - -install_msg =""" - -1. python -m pip install torch --index-url https://download.pytorch.org/whl/cpu - -2. python -m pip install transformers protobuf langchain sentence-transformers faiss-cpu nltk beautifulsoup4 bitsandbytes tabulate icetk --upgrade - -3. python -m pip install unstructured[all-docs] --upgrade - -4. python -c 'import nltk; nltk.download("punkt")' -""" - -@CatchException -def 知识库文件注入(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request): - """ - txt 输入栏用户输入的文本,例如需要翻译的一段话,再例如一个包含了待处理文件的路径 - llm_kwargs gpt模型参数, 如温度和top_p等, 一般原样传递下去就行 - plugin_kwargs 插件模型的参数,暂时没有用武之地 - chatbot 聊天显示框的句柄,用于显示给用户 - history 聊天历史,前情提要 - system_prompt 给gpt的静默提醒 - user_request 当前用户的请求信息(IP地址等) - """ - history = [] # 清空历史,以免输入溢出 - - # < --------------------读取参数--------------- > - if ("advanced_arg" in plugin_kwargs) and (plugin_kwargs["advanced_arg"] == ""): plugin_kwargs.pop("advanced_arg") - kai_id = plugin_kwargs.get("advanced_arg", 'default') - - chatbot.append((f"向`{kai_id}`知识库中添加文件。", "[Local Message] 从一批文件(txt, md, tex)中读取数据构建知识库, 然后进行问答。")) - yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 - - # resolve deps - try: - # from zh_langchain import construct_vector_store - # from langchain.embeddings.huggingface import HuggingFaceEmbeddings - from crazy_functions.vector_fns.vector_database import knowledge_archive_interface - except Exception as e: - chatbot.append(["依赖不足", f"{str(e)}\n\n导入依赖失败。请用以下命令安装" + install_msg]) - yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 - # from .crazy_utils import try_install_deps - # try_install_deps(['zh_langchain==0.2.1', 'pypinyin'], reload_m=['pypinyin', 'zh_langchain']) - # yield from update_ui_lastest_msg("安装完成,您可以再次重试。", chatbot, history) - return - - # < --------------------读取文件--------------- > - file_manifest = [] - spl = ["txt", "doc", "docx", "email", "epub", "html", "json", "md", "msg", "pdf", "ppt", "pptx", "rtf"] - for sp in spl: - _, file_manifest_tmp, _ = get_files_from_everything(txt, type=f'.{sp}') - file_manifest += file_manifest_tmp - - if len(file_manifest) == 0: - chatbot.append(["没有找到任何可读取文件", "当前支持的格式包括: txt, md, docx, pptx, pdf, json等"]) - yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 - return - - # < -------------------预热文本向量化模组--------------- > - chatbot.append(['
'.join(file_manifest), "正在预热文本向量化模组, 如果是第一次运行, 将消耗较长时间下载中文向量化模型..."]) - yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 - print('Checking Text2vec ...') - from langchain.embeddings.huggingface import HuggingFaceEmbeddings - with ProxyNetworkActivate('Download_LLM'): # 临时地激活代理网络 - HuggingFaceEmbeddings(model_name="GanymedeNil/text2vec-large-chinese") - - # < -------------------构建知识库--------------- > - chatbot.append(['
'.join(file_manifest), "正在构建知识库..."]) - yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 - print('Establishing knowledge archive ...') - with ProxyNetworkActivate('Download_LLM'): # 临时地激活代理网络 - kai = knowledge_archive_interface() - vs_path = get_log_folder(user=get_user(chatbot), plugin_name='vec_store') - kai.feed_archive(file_manifest=file_manifest, vs_path=vs_path, id=kai_id) - kai_files = kai.get_loaded_file(vs_path=vs_path) - kai_files = '
'.join(kai_files) - # chatbot.append(['知识库构建成功', "正在将知识库存储至cookie中"]) - # yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 - # chatbot._cookies['langchain_plugin_embedding'] = kai.get_current_archive_id() - # chatbot._cookies['lock_plugin'] = 'crazy_functions.知识库文件注入->读取知识库作答' - # chatbot.append(['完成', "“根据知识库作答”函数插件已经接管问答系统, 提问吧! 但注意, 您接下来不能再使用其他插件了,刷新页面即可以退出知识库问答模式。"]) - chatbot.append(['构建完成', f"当前知识库内的有效文件:\n\n---\n\n{kai_files}\n\n---\n\n请切换至“知识库问答”插件进行知识库访问, 或者使用此插件继续上传更多文件。"]) - yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 # 由于请求gpt需要一段时间,我们先及时地做一次界面更新 - -@CatchException -def 读取知识库作答(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request=-1): - # resolve deps - try: - # from zh_langchain import construct_vector_store - # from langchain.embeddings.huggingface import HuggingFaceEmbeddings - from crazy_functions.vector_fns.vector_database import knowledge_archive_interface - except Exception as e: - chatbot.append(["依赖不足", f"{str(e)}\n\n导入依赖失败。请用以下命令安装" + install_msg]) - yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 - # from .crazy_utils import try_install_deps - # try_install_deps(['zh_langchain==0.2.1', 'pypinyin'], reload_m=['pypinyin', 'zh_langchain']) - # yield from update_ui_lastest_msg("安装完成,您可以再次重试。", chatbot, history) - return - - # < ------------------- --------------- > - kai = knowledge_archive_interface() - - if ("advanced_arg" in plugin_kwargs) and (plugin_kwargs["advanced_arg"] == ""): plugin_kwargs.pop("advanced_arg") - kai_id = plugin_kwargs.get("advanced_arg", 'default') - vs_path = get_log_folder(user=get_user(chatbot), plugin_name='vec_store') - resp, prompt = kai.answer_with_archive_by_id(txt, kai_id, vs_path) - - chatbot.append((txt, f'[知识库 {kai_id}] ' + prompt)) - yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 # 由于请求gpt需要一段时间,我们先及时地做一次界面更新 - gpt_say = yield from request_gpt_model_in_new_thread_with_ui_alive( - inputs=prompt, inputs_show_user=txt, - llm_kwargs=llm_kwargs, chatbot=chatbot, history=[], - sys_prompt=system_prompt - ) - history.extend((prompt, gpt_say)) - yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 # 由于请求gpt需要一段时间,我们先及时地做一次界面更新 diff --git "a/crazy_functions/\350\201\224\347\275\221\347\232\204ChatGPT.py" "b/crazy_functions/\350\201\224\347\275\221\347\232\204ChatGPT.py" index 346492dbf5e07669856898b09b241f9c247c0cc6..4ed9aebf97834418d145ab1dd5b22ca7f4f9b214 100644 --- "a/crazy_functions/\350\201\224\347\275\221\347\232\204ChatGPT.py" +++ "b/crazy_functions/\350\201\224\347\275\221\347\232\204ChatGPT.py" @@ -2,7 +2,7 @@ from toolbox import CatchException, update_ui from .crazy_utils import request_gpt_model_in_new_thread_with_ui_alive, input_clipping import requests from bs4 import BeautifulSoup -from request_llms.bridge_all import model_info +from request_llm.bridge_all import model_info def google(query, proxies): query = query # 在此处替换您要搜索的关键词 @@ -55,7 +55,7 @@ def scrape_text(url, proxies) -> str: return text @CatchException -def 连接网络回答问题(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request): +def 连接网络回答问题(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port): """ txt 输入栏用户输入的文本,例如需要翻译的一段话,再例如一个包含了待处理文件的路径 llm_kwargs gpt模型参数,如温度和top_p等,一般原样传递下去就行 @@ -63,7 +63,7 @@ def 连接网络回答问题(txt, llm_kwargs, plugin_kwargs, chatbot, history, s chatbot 聊天显示框的句柄,用于显示给用户 history 聊天历史,前情提要 system_prompt 给gpt的静默提醒 - user_request 当前用户的请求信息(IP地址等) + web_port 当前软件运行的端口号 """ history = [] # 清空历史,以免输入溢出 chatbot.append((f"请结合互联网信息回答以下问题:{txt}", @@ -72,7 +72,7 @@ def 连接网络回答问题(txt, llm_kwargs, plugin_kwargs, chatbot, history, s # ------------- < 第1步:爬取搜索引擎的结果 > ------------- from toolbox import get_conf - proxies = get_conf('proxies') + proxies, = get_conf('proxies') urls = google(txt, proxies) history = [] if len(urls) == 0: diff --git "a/crazy_functions/\350\201\224\347\275\221\347\232\204ChatGPT_bing\347\211\210.py" "b/crazy_functions/\350\201\224\347\275\221\347\232\204ChatGPT_bing\347\211\210.py" index eff6f8f9a97cd24abf504ba994c62d03b51c3346..db5adb7992f765db3e5b0e7ecea7e71e44dbe855 100644 --- "a/crazy_functions/\350\201\224\347\275\221\347\232\204ChatGPT_bing\347\211\210.py" +++ "b/crazy_functions/\350\201\224\347\275\221\347\232\204ChatGPT_bing\347\211\210.py" @@ -2,7 +2,7 @@ from toolbox import CatchException, update_ui from .crazy_utils import request_gpt_model_in_new_thread_with_ui_alive, input_clipping import requests from bs4 import BeautifulSoup -from request_llms.bridge_all import model_info +from request_llm.bridge_all import model_info def bing_search(query, proxies=None): @@ -55,7 +55,7 @@ def scrape_text(url, proxies) -> str: return text @CatchException -def 连接bing搜索回答问题(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request): +def 连接bing搜索回答问题(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port): """ txt 输入栏用户输入的文本,例如需要翻译的一段话,再例如一个包含了待处理文件的路径 llm_kwargs gpt模型参数,如温度和top_p等,一般原样传递下去就行 @@ -63,7 +63,7 @@ def 连接bing搜索回答问题(txt, llm_kwargs, plugin_kwargs, chatbot, histor chatbot 聊天显示框的句柄,用于显示给用户 history 聊天历史,前情提要 system_prompt 给gpt的静默提醒 - user_request 当前用户的请求信息(IP地址等) + web_port 当前软件运行的端口号 """ history = [] # 清空历史,以免输入溢出 chatbot.append((f"请结合互联网信息回答以下问题:{txt}", @@ -72,7 +72,7 @@ def 连接bing搜索回答问题(txt, llm_kwargs, plugin_kwargs, chatbot, histor # ------------- < 第1步:爬取搜索引擎的结果 > ------------- from toolbox import get_conf - proxies = get_conf('proxies') + proxies, = get_conf('proxies') urls = bing_search(txt, proxies) history = [] if len(urls) == 0: diff --git "a/crazy_functions/\350\231\232\347\251\272\347\273\210\347\253\257.py" "b/crazy_functions/\350\231\232\347\251\272\347\273\210\347\253\257.py" index 27f449969d7b6aee345040a25c60656356102d74..5f33249e3e77d8fc92ce09f692d34f1e9ea3e559 100644 --- "a/crazy_functions/\350\231\232\347\251\272\347\273\210\347\253\257.py" +++ "b/crazy_functions/\350\231\232\347\251\272\347\273\210\347\253\257.py" @@ -48,7 +48,7 @@ from pydantic import BaseModel, Field from typing import List from toolbox import CatchException, update_ui, is_the_upload_folder from toolbox import update_ui_lastest_msg, disable_auto_promotion -from request_llms.bridge_all import predict_no_ui_long_connection +from request_llm.bridge_all import predict_no_ui_long_connection from crazy_functions.crazy_utils import request_gpt_model_in_new_thread_with_ui_alive from crazy_functions.crazy_utils import input_clipping from crazy_functions.json_fns.pydantic_io import GptJsonIO, JsonStringError @@ -104,7 +104,7 @@ def analyze_intention_with_simple_rules(txt): @CatchException -def 虚空终端(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request): +def 虚空终端(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port): disable_auto_promotion(chatbot=chatbot) # 获取当前虚空终端状态 state = VoidTerminalState.get_state(chatbot) @@ -121,7 +121,7 @@ def 虚空终端(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt state.set_state(chatbot=chatbot, key='has_provided_explaination', value=True) state.unlock_plugin(chatbot=chatbot) yield from update_ui(chatbot=chatbot, history=history) - yield from 虚空终端主路由(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request) + yield from 虚空终端主路由(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port) return else: # 如果意图模糊,提示 @@ -133,7 +133,7 @@ def 虚空终端(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt -def 虚空终端主路由(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request): +def 虚空终端主路由(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port): history = [] chatbot.append(("虚空终端状态: ", f"正在执行任务: {txt}")) yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 diff --git "a/crazy_functions/\350\247\243\346\236\220JupyterNotebook.py" "b/crazy_functions/\350\247\243\346\236\220JupyterNotebook.py" index 2f2c088378822284c50487ea17473bde47214f58..d4a3b49e69ea16235375371a4f51f87af1103a21 100644 --- "a/crazy_functions/\350\247\243\346\236\220JupyterNotebook.py" +++ "b/crazy_functions/\350\247\243\346\236\220JupyterNotebook.py" @@ -1,5 +1,5 @@ from toolbox import update_ui -from toolbox import CatchException, report_exception +from toolbox import CatchException, report_execption from toolbox import write_history_to_file, promote_file_to_downloadzone fast_debug = True @@ -13,9 +13,10 @@ class PaperFileGroup(): self.sp_file_tag = [] # count_token - from request_llms.bridge_all import model_info + from request_llm.bridge_all import model_info enc = model_info["gpt-3.5-turbo"]['tokenizer'] - def get_token_num(txt): return len(enc.encode(txt, disallowed_special=())) + def get_token_num(txt): return len( + enc.encode(txt, disallowed_special=())) self.get_token_num = get_token_num def run_file_split(self, max_token_limit=1900): @@ -28,8 +29,9 @@ class PaperFileGroup(): self.sp_file_index.append(index) self.sp_file_tag.append(self.file_paths[index]) else: - from crazy_functions.pdf_fns.breakdown_txt import breakdown_text_to_satisfy_token_limit - segments = breakdown_text_to_satisfy_token_limit(file_content, max_token_limit) + from .crazy_utils import breakdown_txt_to_satisfy_token_limit_for_pdf + segments = breakdown_txt_to_satisfy_token_limit_for_pdf( + file_content, self.get_token_num, max_token_limit) for j, segment in enumerate(segments): self.sp_file_contents.append(segment) self.sp_file_index.append(index) @@ -60,7 +62,7 @@ def parseNotebook(filename, enable_markdown=1): Code += f"This is {idx+1}th code block: \n" Code += code+"\n" - return Code + return Code def ipynb解释(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt): @@ -115,7 +117,7 @@ def ipynb解释(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbo yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 @CatchException -def 解析ipynb文件(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request): +def 解析ipynb文件(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port): chatbot.append([ "函数插件功能?", "对IPynb文件进行解析。Contributor: codycjy."]) @@ -129,7 +131,7 @@ def 解析ipynb文件(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_p else: if txt == "": txt = '空空如也的输入栏' - report_exception(chatbot, history, + report_execption(chatbot, history, a=f"解析项目: {txt}", b=f"找不到本地项目或无权访问: {txt}") yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 return @@ -139,7 +141,7 @@ def 解析ipynb文件(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_p file_manifest = [f for f in glob.glob( f'{project_folder}/**/*.ipynb', recursive=True)] if len(file_manifest) == 0: - report_exception(chatbot, history, + report_execption(chatbot, history, a=f"解析项目: {txt}", b=f"找不到任何.ipynb文件: {txt}") yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 return diff --git "a/crazy_functions/\350\247\243\346\236\220\351\241\271\347\233\256\346\272\220\344\273\243\347\240\201.py" "b/crazy_functions/\350\247\243\346\236\220\351\241\271\347\233\256\346\272\220\344\273\243\347\240\201.py" index dfd0de0ef5c1d613cc57a5fe80efd5d594991d41..103336295a590a065aaff3333f4a7e014597b3fd 100644 --- "a/crazy_functions/\350\247\243\346\236\220\351\241\271\347\233\256\346\272\220\344\273\243\347\240\201.py" +++ "b/crazy_functions/\350\247\243\346\236\220\351\241\271\347\233\256\346\272\220\344\273\243\347\240\201.py" @@ -1,5 +1,5 @@ from toolbox import update_ui, promote_file_to_downloadzone, disable_auto_promotion -from toolbox import CatchException, report_exception, write_history_to_file +from toolbox import CatchException, report_execption, write_history_to_file from .crazy_utils import input_clipping def 解析源代码新(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt): @@ -83,8 +83,7 @@ def 解析源代码新(file_manifest, project_folder, llm_kwargs, plugin_kwargs, history=this_iteration_history_feed, # 迭代之前的分析 sys_prompt="你是一个程序架构分析师,正在分析一个项目的源代码。" + sys_prompt_additional) - diagram_code = make_diagram(this_iteration_files, result, this_iteration_history_feed) - summary = "请用一句话概括这些文件的整体功能。\n\n" + diagram_code + summary = "请用一句话概括这些文件的整体功能" summary_result = yield from request_gpt_model_in_new_thread_with_ui_alive( inputs=summary, inputs_show_user=summary, @@ -105,88 +104,68 @@ def 解析源代码新(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot.append(("完成了吗?", res)) yield from update_ui(chatbot=chatbot, history=history_to_return) # 刷新界面 -def make_diagram(this_iteration_files, result, this_iteration_history_feed): - from crazy_functions.diagram_fns.file_tree import build_file_tree_mermaid_diagram - return build_file_tree_mermaid_diagram(this_iteration_history_feed[0::2], this_iteration_history_feed[1::2], "项目示意图") @CatchException -def 解析项目本身(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request): +def 解析项目本身(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port): history = [] # 清空历史,以免输入溢出 import glob file_manifest = [f for f in glob.glob('./*.py')] + \ [f for f in glob.glob('./*/*.py')] project_folder = './' if len(file_manifest) == 0: - report_exception(chatbot, history, a = f"解析项目: {txt}", b = f"找不到任何python文件: {txt}") + report_execption(chatbot, history, a = f"解析项目: {txt}", b = f"找不到任何python文件: {txt}") yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 return yield from 解析源代码新(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt) @CatchException -def 解析一个Python项目(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request): +def 解析一个Python项目(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port): history = [] # 清空历史,以免输入溢出 import glob, os if os.path.exists(txt): project_folder = txt else: if txt == "": txt = '空空如也的输入栏' - report_exception(chatbot, history, a = f"解析项目: {txt}", b = f"找不到本地项目或无权访问: {txt}") + report_execption(chatbot, history, a = f"解析项目: {txt}", b = f"找不到本地项目或无权访问: {txt}") yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 return file_manifest = [f for f in glob.glob(f'{project_folder}/**/*.py', recursive=True)] if len(file_manifest) == 0: - report_exception(chatbot, history, a = f"解析项目: {txt}", b = f"找不到任何python文件: {txt}") + report_execption(chatbot, history, a = f"解析项目: {txt}", b = f"找不到任何python文件: {txt}") yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 return yield from 解析源代码新(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt) -@CatchException -def 解析一个Matlab项目(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request): - history = [] # 清空历史,以免输入溢出 - import glob, os - if os.path.exists(txt): - project_folder = txt - else: - if txt == "": txt = '空空如也的输入栏' - report_exception(chatbot, history, a = f"解析Matlab项目: {txt}", b = f"找不到本地项目或无权访问: {txt}") - yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 - return - file_manifest = [f for f in glob.glob(f'{project_folder}/**/*.m', recursive=True)] - if len(file_manifest) == 0: - report_exception(chatbot, history, a = f"解析Matlab项目: {txt}", b = f"找不到任何`.m`源文件: {txt}") - yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 - return - yield from 解析源代码新(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt) @CatchException -def 解析一个C项目的头文件(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request): +def 解析一个C项目的头文件(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port): history = [] # 清空历史,以免输入溢出 import glob, os if os.path.exists(txt): project_folder = txt else: if txt == "": txt = '空空如也的输入栏' - report_exception(chatbot, history, a = f"解析项目: {txt}", b = f"找不到本地项目或无权访问: {txt}") + report_execption(chatbot, history, a = f"解析项目: {txt}", b = f"找不到本地项目或无权访问: {txt}") yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 return file_manifest = [f for f in glob.glob(f'{project_folder}/**/*.h', recursive=True)] + \ [f for f in glob.glob(f'{project_folder}/**/*.hpp', recursive=True)] #+ \ # [f for f in glob.glob(f'{project_folder}/**/*.c', recursive=True)] if len(file_manifest) == 0: - report_exception(chatbot, history, a = f"解析项目: {txt}", b = f"找不到任何.h头文件: {txt}") + report_execption(chatbot, history, a = f"解析项目: {txt}", b = f"找不到任何.h头文件: {txt}") yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 return yield from 解析源代码新(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt) @CatchException -def 解析一个C项目(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request): +def 解析一个C项目(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port): history = [] # 清空历史,以免输入溢出 import glob, os if os.path.exists(txt): project_folder = txt else: if txt == "": txt = '空空如也的输入栏' - report_exception(chatbot, history, a = f"解析项目: {txt}", b = f"找不到本地项目或无权访问: {txt}") + report_execption(chatbot, history, a = f"解析项目: {txt}", b = f"找不到本地项目或无权访问: {txt}") yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 return file_manifest = [f for f in glob.glob(f'{project_folder}/**/*.h', recursive=True)] + \ @@ -194,21 +173,21 @@ def 解析一个C项目(txt, llm_kwargs, plugin_kwargs, chatbot, history, system [f for f in glob.glob(f'{project_folder}/**/*.hpp', recursive=True)] + \ [f for f in glob.glob(f'{project_folder}/**/*.c', recursive=True)] if len(file_manifest) == 0: - report_exception(chatbot, history, a = f"解析项目: {txt}", b = f"找不到任何.h头文件: {txt}") + report_execption(chatbot, history, a = f"解析项目: {txt}", b = f"找不到任何.h头文件: {txt}") yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 return yield from 解析源代码新(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt) @CatchException -def 解析一个Java项目(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request): +def 解析一个Java项目(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port): history = [] # 清空历史,以免输入溢出 import glob, os if os.path.exists(txt): project_folder = txt else: if txt == "": txt = '空空如也的输入栏' - report_exception(chatbot, history, a=f"解析项目: {txt}", b=f"找不到本地项目或无权访问: {txt}") + report_execption(chatbot, history, a=f"解析项目: {txt}", b=f"找不到本地项目或无权访问: {txt}") yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 return file_manifest = [f for f in glob.glob(f'{project_folder}/**/*.java', recursive=True)] + \ @@ -216,21 +195,21 @@ def 解析一个Java项目(txt, llm_kwargs, plugin_kwargs, chatbot, history, sys [f for f in glob.glob(f'{project_folder}/**/*.xml', recursive=True)] + \ [f for f in glob.glob(f'{project_folder}/**/*.sh', recursive=True)] if len(file_manifest) == 0: - report_exception(chatbot, history, a=f"解析项目: {txt}", b=f"找不到任何java文件: {txt}") + report_execption(chatbot, history, a=f"解析项目: {txt}", b=f"找不到任何java文件: {txt}") yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 return yield from 解析源代码新(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt) @CatchException -def 解析一个前端项目(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request): +def 解析一个前端项目(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port): history = [] # 清空历史,以免输入溢出 import glob, os if os.path.exists(txt): project_folder = txt else: if txt == "": txt = '空空如也的输入栏' - report_exception(chatbot, history, a=f"解析项目: {txt}", b=f"找不到本地项目或无权访问: {txt}") + report_execption(chatbot, history, a=f"解析项目: {txt}", b=f"找不到本地项目或无权访问: {txt}") yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 return file_manifest = [f for f in glob.glob(f'{project_folder}/**/*.ts', recursive=True)] + \ @@ -245,21 +224,21 @@ def 解析一个前端项目(txt, llm_kwargs, plugin_kwargs, chatbot, history, s [f for f in glob.glob(f'{project_folder}/**/*.css', recursive=True)] + \ [f for f in glob.glob(f'{project_folder}/**/*.jsx', recursive=True)] if len(file_manifest) == 0: - report_exception(chatbot, history, a=f"解析项目: {txt}", b=f"找不到任何前端相关文件: {txt}") + report_execption(chatbot, history, a=f"解析项目: {txt}", b=f"找不到任何前端相关文件: {txt}") yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 return yield from 解析源代码新(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt) @CatchException -def 解析一个Golang项目(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request): +def 解析一个Golang项目(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port): history = [] # 清空历史,以免输入溢出 import glob, os if os.path.exists(txt): project_folder = txt else: if txt == "": txt = '空空如也的输入栏' - report_exception(chatbot, history, a=f"解析项目: {txt}", b=f"找不到本地项目或无权访问: {txt}") + report_execption(chatbot, history, a=f"解析项目: {txt}", b=f"找不到本地项目或无权访问: {txt}") yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 return file_manifest = [f for f in glob.glob(f'{project_folder}/**/*.go', recursive=True)] + \ @@ -267,40 +246,40 @@ def 解析一个Golang项目(txt, llm_kwargs, plugin_kwargs, chatbot, history, s [f for f in glob.glob(f'{project_folder}/**/go.sum', recursive=True)] + \ [f for f in glob.glob(f'{project_folder}/**/go.work', recursive=True)] if len(file_manifest) == 0: - report_exception(chatbot, history, a=f"解析项目: {txt}", b=f"找不到任何golang文件: {txt}") + report_execption(chatbot, history, a=f"解析项目: {txt}", b=f"找不到任何golang文件: {txt}") yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 return yield from 解析源代码新(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt) @CatchException -def 解析一个Rust项目(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request): +def 解析一个Rust项目(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port): history = [] # 清空历史,以免输入溢出 import glob, os if os.path.exists(txt): project_folder = txt else: if txt == "": txt = '空空如也的输入栏' - report_exception(chatbot, history, a=f"解析项目: {txt}", b=f"找不到本地项目或无权访问: {txt}") + report_execption(chatbot, history, a=f"解析项目: {txt}", b=f"找不到本地项目或无权访问: {txt}") yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 return file_manifest = [f for f in glob.glob(f'{project_folder}/**/*.rs', recursive=True)] + \ [f for f in glob.glob(f'{project_folder}/**/*.toml', recursive=True)] + \ [f for f in glob.glob(f'{project_folder}/**/*.lock', recursive=True)] if len(file_manifest) == 0: - report_exception(chatbot, history, a=f"解析项目: {txt}", b=f"找不到任何golang文件: {txt}") + report_execption(chatbot, history, a=f"解析项目: {txt}", b=f"找不到任何golang文件: {txt}") yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 return yield from 解析源代码新(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt) @CatchException -def 解析一个Lua项目(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request): +def 解析一个Lua项目(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port): history = [] # 清空历史,以免输入溢出 import glob, os if os.path.exists(txt): project_folder = txt else: if txt == "": txt = '空空如也的输入栏' - report_exception(chatbot, history, a = f"解析项目: {txt}", b = f"找不到本地项目或无权访问: {txt}") + report_execption(chatbot, history, a = f"解析项目: {txt}", b = f"找不到本地项目或无权访问: {txt}") yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 return file_manifest = [f for f in glob.glob(f'{project_folder}/**/*.lua', recursive=True)] + \ @@ -308,34 +287,34 @@ def 解析一个Lua项目(txt, llm_kwargs, plugin_kwargs, chatbot, history, syst [f for f in glob.glob(f'{project_folder}/**/*.json', recursive=True)] + \ [f for f in glob.glob(f'{project_folder}/**/*.toml', recursive=True)] if len(file_manifest) == 0: - report_exception(chatbot, history, a = f"解析项目: {txt}", b = f"找不到任何lua文件: {txt}") + report_execption(chatbot, history, a = f"解析项目: {txt}", b = f"找不到任何lua文件: {txt}") yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 return yield from 解析源代码新(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt) @CatchException -def 解析一个CSharp项目(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request): +def 解析一个CSharp项目(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port): history = [] # 清空历史,以免输入溢出 import glob, os if os.path.exists(txt): project_folder = txt else: if txt == "": txt = '空空如也的输入栏' - report_exception(chatbot, history, a = f"解析项目: {txt}", b = f"找不到本地项目或无权访问: {txt}") + report_execption(chatbot, history, a = f"解析项目: {txt}", b = f"找不到本地项目或无权访问: {txt}") yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 return file_manifest = [f for f in glob.glob(f'{project_folder}/**/*.cs', recursive=True)] + \ [f for f in glob.glob(f'{project_folder}/**/*.csproj', recursive=True)] if len(file_manifest) == 0: - report_exception(chatbot, history, a = f"解析项目: {txt}", b = f"找不到任何CSharp文件: {txt}") + report_execption(chatbot, history, a = f"解析项目: {txt}", b = f"找不到任何CSharp文件: {txt}") yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 return yield from 解析源代码新(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt) @CatchException -def 解析任意code项目(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request): +def 解析任意code项目(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port): txt_pattern = plugin_kwargs.get("advanced_arg") txt_pattern = txt_pattern.replace(",", ",") # 将要匹配的模式(例如: *.c, *.cpp, *.py, config.toml) @@ -356,7 +335,7 @@ def 解析任意code项目(txt, llm_kwargs, plugin_kwargs, chatbot, history, sys project_folder = txt else: if txt == "": txt = '空空如也的输入栏' - report_exception(chatbot, history, a = f"解析项目: {txt}", b = f"找不到本地项目或无权访问: {txt}") + report_execption(chatbot, history, a = f"解析项目: {txt}", b = f"找不到本地项目或无权访问: {txt}") yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 return # 若上传压缩文件, 先寻找到解压的文件夹路径, 从而避免解析压缩文件 @@ -369,7 +348,7 @@ def 解析任意code项目(txt, llm_kwargs, plugin_kwargs, chatbot, history, sys file_manifest = [f for pattern in pattern_include for f in glob.glob(f'{extract_folder_path}/**/{pattern}', recursive=True) if "" != extract_folder_path and \ os.path.isfile(f) and (not re.search(pattern_except, f) or pattern.endswith('.' + re.search(pattern_except, f).group().split('.')[-1]))] if len(file_manifest) == 0: - report_exception(chatbot, history, a = f"解析项目: {txt}", b = f"找不到任何文件: {txt}") + report_execption(chatbot, history, a = f"解析项目: {txt}", b = f"找不到任何文件: {txt}") yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 return yield from 解析源代码新(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt) \ No newline at end of file diff --git "a/crazy_functions/\350\257\242\351\227\256\345\244\232\344\270\252\345\244\247\350\257\255\350\250\200\346\250\241\345\236\213.py" "b/crazy_functions/\350\257\242\351\227\256\345\244\232\344\270\252\345\244\247\350\257\255\350\250\200\346\250\241\345\236\213.py" index 069d4407fb575216a5b640da9467cba616f3963f..8fdf5915d303a54cc7859e9df77ac9acf5311ced 100644 --- "a/crazy_functions/\350\257\242\351\227\256\345\244\232\344\270\252\345\244\247\350\257\255\350\250\200\346\250\241\345\236\213.py" +++ "b/crazy_functions/\350\257\242\351\227\256\345\244\232\344\270\252\345\244\247\350\257\255\350\250\200\346\250\241\345\236\213.py" @@ -1,8 +1,8 @@ -from toolbox import CatchException, update_ui, get_conf +from toolbox import CatchException, update_ui from .crazy_utils import request_gpt_model_in_new_thread_with_ui_alive import datetime @CatchException -def 同时问询(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request): +def 同时问询(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port): """ txt 输入栏用户输入的文本,例如需要翻译的一段话,再例如一个包含了待处理文件的路径 llm_kwargs gpt模型参数,如温度和top_p等,一般原样传递下去就行 @@ -10,15 +10,14 @@ def 同时问询(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt chatbot 聊天显示框的句柄,用于显示给用户 history 聊天历史,前情提要 system_prompt 给gpt的静默提醒 - user_request 当前用户的请求信息(IP地址等) + web_port 当前软件运行的端口号 """ history = [] # 清空历史,以免输入溢出 - MULTI_QUERY_LLM_MODELS = get_conf('MULTI_QUERY_LLM_MODELS') - chatbot.append((txt, "正在同时咨询" + MULTI_QUERY_LLM_MODELS)) + chatbot.append((txt, "正在同时咨询gpt-3.5和gpt-4……")) yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 # 由于请求gpt需要一段时间,我们先及时地做一次界面更新 # llm_kwargs['llm_model'] = 'chatglm&gpt-3.5-turbo&api2d-gpt-3.5-turbo' # 支持任意数量的llm接口,用&符号分隔 - llm_kwargs['llm_model'] = MULTI_QUERY_LLM_MODELS # 支持任意数量的llm接口,用&符号分隔 + llm_kwargs['llm_model'] = 'gpt-3.5-turbo&gpt-4' # 支持任意数量的llm接口,用&符号分隔 gpt_say = yield from request_gpt_model_in_new_thread_with_ui_alive( inputs=txt, inputs_show_user=txt, llm_kwargs=llm_kwargs, chatbot=chatbot, history=history, @@ -32,7 +31,7 @@ def 同时问询(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt @CatchException -def 同时问询_指定模型(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request): +def 同时问询_指定模型(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port): """ txt 输入栏用户输入的文本,例如需要翻译的一段话,再例如一个包含了待处理文件的路径 llm_kwargs gpt模型参数,如温度和top_p等,一般原样传递下去就行 @@ -40,7 +39,7 @@ def 同时问询_指定模型(txt, llm_kwargs, plugin_kwargs, chatbot, history, chatbot 聊天显示框的句柄,用于显示给用户 history 聊天历史,前情提要 system_prompt 给gpt的静默提醒 - user_request 当前用户的请求信息(IP地址等) + web_port 当前软件运行的端口号 """ history = [] # 清空历史,以免输入溢出 diff --git "a/crazy_functions/\350\257\255\351\237\263\345\212\251\346\211\213.py" "b/crazy_functions/\350\257\255\351\237\263\345\212\251\346\211\213.py" index 8af0fd999966bb44a79c68525a3192422233a3e5..b1c8c41e63f3cedc97affb66d5ea124f9c5d4837 100644 --- "a/crazy_functions/\350\257\255\351\237\263\345\212\251\346\211\213.py" +++ "b/crazy_functions/\350\257\255\351\237\263\345\212\251\346\211\213.py" @@ -1,35 +1,47 @@ from toolbox import update_ui from toolbox import CatchException, get_conf, markdown_convertion from crazy_functions.crazy_utils import input_clipping -from crazy_functions.agent_fns.watchdog import WatchDog -from request_llms.bridge_all import predict_no_ui_long_connection +from request_llm.bridge_all import predict_no_ui_long_connection import threading, time import numpy as np from .live_audio.aliyunASR import AliyunASR import json -import re +class WatchDog(): + def __init__(self, timeout, bark_fn, interval=3, msg="") -> None: + self.last_feed = None + self.timeout = timeout + self.bark_fn = bark_fn + self.interval = interval + self.msg = msg + self.kill_dog = False + + def watch(self): + while True: + if self.kill_dog: break + if time.time() - self.last_feed > self.timeout: + if len(self.msg) > 0: print(self.msg) + self.bark_fn() + break + time.sleep(self.interval) + + def begin_watch(self): + self.last_feed = time.time() + th = threading.Thread(target=self.watch) + th.daemon = True + th.start() + + def feed(self): + self.last_feed = time.time() def chatbot2history(chatbot): history = [] for c in chatbot: for q in c: - if q in ["[ 请讲话 ]", "[ 等待GPT响应 ]", "[ 正在等您说完问题 ]"]: - continue - elif q.startswith("[ 正在等您说完问题 ]"): - continue - else: + if q not in ["[请讲话]", "[等待GPT响应]", "[正在等您说完问题]"]: history.append(q.strip('
').strip('
').strip('

').strip('

')) return history -def visualize_audio(chatbot, audio_shape): - if len(chatbot) == 0: chatbot.append(["[ 请讲话 ]", "[ 正在等您说完问题 ]"]) - chatbot[-1] = list(chatbot[-1]) - p1 = '「' - p2 = '」' - chatbot[-1][-1] = re.sub(p1+r'(.*)'+p2, '', chatbot[-1][-1]) - chatbot[-1][-1] += (p1+f"`{audio_shape}`"+p2) - class AsyncGptTask(): def __init__(self) -> None: self.observe_future = [] @@ -69,9 +81,8 @@ class InterviewAssistant(AliyunASR): self.capture_interval = 0.5 # second self.stop = False self.parsed_text = "" # 下个句子中已经说完的部分, 由 test_on_result_chg() 写入 - self.parsed_sentence = "" # 某段话的整个句子, 由 test_on_sentence_end() 写入 + self.parsed_sentence = "" # 某段话的整个句子,由 test_on_sentence_end() 写入 self.buffered_sentence = "" # - self.audio_shape = "" # 音频的可视化表现, 由 audio_convertion_thread() 写入 self.event_on_result_chg = threading.Event() self.event_on_entence_end = threading.Event() self.event_on_commit_question = threading.Event() @@ -106,7 +117,7 @@ class InterviewAssistant(AliyunASR): def begin(self, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt): # main plugin function self.init(chatbot) - chatbot.append(["[ 请讲话 ]", "[ 正在等您说完问题 ]"]) + chatbot.append(["[请讲话]", "[正在等您说完问题]"]) yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 self.plugin_wd.begin_watch() self.agt = AsyncGptTask() @@ -146,18 +157,14 @@ class InterviewAssistant(AliyunASR): self.commit_wd.begin_watch() chatbot[-1] = list(chatbot[-1]) - chatbot[-1] = [self.buffered_sentence, "[ 等待GPT响应 ]"] + chatbot[-1] = [self.buffered_sentence, "[等待GPT响应]"] yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 # add gpt task 创建子线程请求gpt,避免线程阻塞 history = chatbot2history(chatbot) self.agt.add_async_gpt_task(self.buffered_sentence, len(chatbot)-1, llm_kwargs, history, system_prompt) self.buffered_sentence = "" - chatbot.append(["[ 请讲话 ]", "[ 正在等您说完问题 ]"]) - yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 - - if not self.event_on_result_chg.is_set() and not self.event_on_entence_end.is_set() and not self.event_on_commit_question.is_set(): - visualize_audio(chatbot, self.audio_shape) + chatbot.append(["[请讲话]", "[正在等您说完问题]"]) yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 if len(self.stop_msg) != 0: @@ -166,7 +173,7 @@ class InterviewAssistant(AliyunASR): @CatchException -def 语音助手(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request): +def 语音助手(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port): # pip install -U openai-whisper chatbot.append(["对话助手函数插件:使用时,双手离开鼠标键盘吧", "音频助手, 正在听您讲话(点击“停止”键可终止程序)..."]) yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 @@ -176,7 +183,7 @@ def 语音助手(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt import nls from scipy import io except: - chatbot.append(["导入依赖失败", "使用该模块需要额外依赖, 安装方法:```pip install --upgrade aliyun-python-sdk-core==2.13.3 pyOpenSSL webrtcvad scipy git+https://github.com/aliyun/alibabacloud-nls-python-sdk.git```"]) + chatbot.append(["导入依赖失败", "使用该模块需要额外依赖, 安装方法:```pip install --upgrade aliyun-python-sdk-core==2.13.3 pyOpenSSL scipy git+https://github.com/aliyun/alibabacloud-nls-python-sdk.git```"]) yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 return diff --git "a/crazy_functions/\350\257\273\346\226\207\347\253\240\345\206\231\346\221\230\350\246\201.py" "b/crazy_functions/\350\257\273\346\226\207\347\253\240\345\206\231\346\221\230\350\246\201.py" index 48222a6ddd9719cb4375972d4353286bcb43fbd4..acdf632c3ba44d0a20424d29e6c9718c999f20f2 100644 --- "a/crazy_functions/\350\257\273\346\226\207\347\253\240\345\206\231\346\221\230\350\246\201.py" +++ "b/crazy_functions/\350\257\273\346\226\207\347\253\240\345\206\231\346\221\230\350\246\201.py" @@ -1,5 +1,5 @@ from toolbox import update_ui -from toolbox import CatchException, report_exception +from toolbox import CatchException, report_execption from toolbox import write_history_to_file, promote_file_to_downloadzone from .crazy_utils import request_gpt_model_in_new_thread_with_ui_alive @@ -44,21 +44,21 @@ def 解析Paper(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbo @CatchException -def 读文章写摘要(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request): +def 读文章写摘要(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port): history = [] # 清空历史,以免输入溢出 import glob, os if os.path.exists(txt): project_folder = txt else: if txt == "": txt = '空空如也的输入栏' - report_exception(chatbot, history, a = f"解析项目: {txt}", b = f"找不到本地项目或无权访问: {txt}") + report_execption(chatbot, history, a = f"解析项目: {txt}", b = f"找不到本地项目或无权访问: {txt}") yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 return file_manifest = [f for f in glob.glob(f'{project_folder}/**/*.tex', recursive=True)] # + \ # [f for f in glob.glob(f'{project_folder}/**/*.cpp', recursive=True)] + \ # [f for f in glob.glob(f'{project_folder}/**/*.c', recursive=True)] if len(file_manifest) == 0: - report_exception(chatbot, history, a = f"解析项目: {txt}", b = f"找不到任何.tex文件: {txt}") + report_execption(chatbot, history, a = f"解析项目: {txt}", b = f"找不到任何.tex文件: {txt}") yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 return yield from 解析Paper(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt) diff --git "a/crazy_functions/\350\260\267\346\255\214\346\243\200\347\264\242\345\260\217\345\212\251\346\211\213.py" "b/crazy_functions/\350\260\267\346\255\214\346\243\200\347\264\242\345\260\217\345\212\251\346\211\213.py" index 8b7ea3ffce15e0ca6f0017987a974a3e4d183810..05e80d2c8432cd3db46b8ca5a30b045ca9f5c7ca 100644 --- "a/crazy_functions/\350\260\267\346\255\214\346\243\200\347\264\242\345\260\217\345\212\251\346\211\213.py" +++ "b/crazy_functions/\350\260\267\346\255\214\346\243\200\347\264\242\345\260\217\345\212\251\346\211\213.py" @@ -1,5 +1,5 @@ from .crazy_utils import request_gpt_model_in_new_thread_with_ui_alive -from toolbox import CatchException, report_exception, promote_file_to_downloadzone +from toolbox import CatchException, report_execption, promote_file_to_downloadzone from toolbox import update_ui, update_ui_lastest_msg, disable_auto_promotion, write_history_to_file import logging import requests @@ -17,7 +17,7 @@ def get_meta_information(url, chatbot, history): from urllib.parse import urlparse session = requests.session() - proxies = get_conf('proxies') + proxies, = get_conf('proxies') headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36', 'Accept-Encoding': 'gzip, deflate, br', @@ -26,13 +26,7 @@ def get_meta_information(url, chatbot, history): 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7', 'Connection': 'keep-alive' } - try: - session.proxies.update(proxies) - except: - report_exception(chatbot, history, - a=f"获取代理失败 无代理状态下很可能无法访问OpenAI家族的模型及谷歌学术 建议:检查USE_PROXY选项是否修改。", - b=f"尝试直接连接") - yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 + session.proxies.update(proxies) session.headers.update(headers) response = session.get(url) @@ -132,7 +126,7 @@ def get_meta_information(url, chatbot, history): return profile @CatchException -def 谷歌检索小助手(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request): +def 谷歌检索小助手(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port): disable_auto_promotion(chatbot=chatbot) # 基本信息:功能、贡献者 chatbot.append([ @@ -146,7 +140,7 @@ def 谷歌检索小助手(txt, llm_kwargs, plugin_kwargs, chatbot, history, syst import math from bs4 import BeautifulSoup except: - report_exception(chatbot, history, + report_execption(chatbot, history, a = f"解析项目: {txt}", b = f"导入软件依赖失败。使用该模块需要额外依赖,安装方法```pip install --upgrade beautifulsoup4 arxiv```。") yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 diff --git "a/crazy_functions/\350\276\205\345\212\251\345\212\237\350\203\275.py" "b/crazy_functions/\350\276\205\345\212\251\345\212\237\350\203\275.py" index 10f71ed6f1b82af08ba47e975195db7142b90942..16854e087eec27f4990aaafcf1b2e9f8ee9e1e30 100644 --- "a/crazy_functions/\350\276\205\345\212\251\345\212\237\350\203\275.py" +++ "b/crazy_functions/\350\276\205\345\212\251\345\212\237\350\203\275.py" @@ -2,16 +2,13 @@ # @Time : 2023/4/19 # @Author : Spike # @Descr : -from toolbox import update_ui, get_conf, get_user +from toolbox import update_ui, get_conf from toolbox import CatchException -from toolbox import default_user_name from crazy_functions.crazy_utils import request_gpt_model_in_new_thread_with_ui_alive -import shutil -import os @CatchException -def 猜你想问(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request): +def 猜你想问(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port): if txt: show_say = txt prompt = txt+'\n回答完问题后,再列出用户可能提出的三个问题。' @@ -32,23 +29,14 @@ def 猜你想问(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt @CatchException -def 清除缓存(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request): +def 清除缓存(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port): chatbot.append(['清除本地缓存数据', '执行中. 删除数据']) yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 - def _get_log_folder(user=default_user_name): - PATH_LOGGING = get_conf('PATH_LOGGING') - _dir = os.path.join(PATH_LOGGING, user) - if not os.path.exists(_dir): os.makedirs(_dir) - return _dir - - def _get_upload_folder(user=default_user_name): - PATH_PRIVATE_UPLOAD = get_conf('PATH_PRIVATE_UPLOAD') - _dir = os.path.join(PATH_PRIVATE_UPLOAD, user) - return _dir - - shutil.rmtree(_get_log_folder(get_user(chatbot)), ignore_errors=True) - shutil.rmtree(_get_upload_folder(get_user(chatbot)), ignore_errors=True) + import shutil, os + PATH_PRIVATE_UPLOAD, PATH_LOGGING = get_conf('PATH_PRIVATE_UPLOAD', 'PATH_LOGGING') + shutil.rmtree(PATH_LOGGING, ignore_errors=True) + shutil.rmtree(PATH_PRIVATE_UPLOAD, ignore_errors=True) chatbot.append(['清除本地缓存数据', '执行完成']) yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 \ No newline at end of file diff --git "a/crazy_functions/\351\253\230\347\272\247\345\212\237\350\203\275\345\207\275\346\225\260\346\250\241\346\235\277.py" "b/crazy_functions/\351\253\230\347\272\247\345\212\237\350\203\275\345\207\275\346\225\260\346\250\241\346\235\277.py" index d22a67411a2c94a06c342d041627c9f0afc031e7..abcbbc6631fa4abdd0577c5a06bd12c5c2504b09 100644 --- "a/crazy_functions/\351\253\230\347\272\247\345\212\237\350\203\275\345\207\275\346\225\260\346\250\241\346\235\277.py" +++ "b/crazy_functions/\351\253\230\347\272\247\345\212\237\350\203\275\345\207\275\346\225\260\346\250\241\346\235\277.py" @@ -1,47 +1,19 @@ from toolbox import CatchException, update_ui -from crazy_functions.crazy_utils import request_gpt_model_in_new_thread_with_ui_alive +from .crazy_utils import request_gpt_model_in_new_thread_with_ui_alive import datetime - -高阶功能模板函数示意图 = f""" -```mermaid -flowchart TD - %% 一个特殊标记,用于在生成mermaid图表时隐藏代码块 - subgraph 函数调用["函数调用过程"] - AA["输入栏用户输入的文本(txt)"] --> BB["gpt模型参数(llm_kwargs)"] - BB --> CC["插件模型参数(plugin_kwargs)"] - CC --> DD["对话显示框的句柄(chatbot)"] - DD --> EE["对话历史(history)"] - EE --> FF["系统提示词(system_prompt)"] - FF --> GG["当前用户信息(web_port)"] - - A["开始(查询5天历史事件)"] - A --> B["获取当前月份和日期"] - B --> C["生成历史事件查询提示词"] - C --> D["调用大模型"] - D --> E["更新界面"] - E --> F["记录历史"] - F --> |"下一天"| B - end -``` -""" - @CatchException -def 高阶功能模板函数(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request): +def 高阶功能模板函数(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port): """ - # 高阶功能模板函数示意图:https://mermaid.live/edit#pako:eNptk1tvEkEYhv8KmattQpvlvOyFCcdeeaVXuoYssBwie8gyhCIlqVoLhrbbtAWNUpEGUkyMEDW2Fmn_DDOL_8LZHdOwxrnamX3f7_3mmZk6yKhZCfAgV1KrmYKoQ9fDuKC4yChX0nld1Aou1JzjznQ5fWmejh8LYHW6vG2a47YAnlCLNSIRolnenKBXI_zRIBrcuqRT890u7jZx7zMDt-AaMbnW1--5olGiz2sQjwfoQxsZL0hxplSSU0-rop4vrzmKR6O2JxYjHmwcL2Y_HDatVMkXlf86YzHbGY9bO5j8XE7O8Nsbc3iNB3ukL2SMcH-XIQBgWoVOZzxuOxOJOyc63EPGV6ZQLENVrznViYStTiaJ2vw2M2d9bByRnOXkgCnXylCSU5quyto_IcmkbdvctELmJ-j1ASW3uB3g5xOmKqVTmqr_Na3AtuS_dtBFm8H90XJyHkDDT7S9xXWb4HGmRChx64AOL5HRpUm411rM5uh4H78Z4V7fCZzytjZz2seto9XaNPFue07clLaVZF8UNLygJ-VES8lah_n-O-5Ozc7-77NzJ0-K0yr0ZYrmHdqAk50t2RbA4qq9uNohBASw7YpSgaRkLWCCAtxAlnRZLGbJba9bPwUAC5IsCYAnn1kpJ1ZKUACC0iBSsQLVBzUlA3ioVyQ3qGhZEUrxokiehAz4nFgqk1VNVABfB1uAD_g2_AGPl-W8nMcbCvsDblADfNCz4feyobDPy3rYEMtxwYYbPFNVUoHdCPmDHBv2cP4AMfrCbiBli-Q-3afv0X6WdsIjW2-10fgDy1SAig - txt 输入栏用户输入的文本,例如需要翻译的一段话,再例如一个包含了待处理文件的路径 llm_kwargs gpt模型参数,如温度和top_p等,一般原样传递下去就行 plugin_kwargs 插件模型的参数,用于灵活调整复杂功能的各种参数 chatbot 聊天显示框的句柄,用于显示给用户 history 聊天历史,前情提要 system_prompt 给gpt的静默提醒 - user_request 当前用户的请求信息(IP地址等) + web_port 当前软件运行的端口号 """ history = [] # 清空历史,以免输入溢出 - chatbot.append(( - "您正在调用插件:历史上的今天", - "[Local Message] 请注意,您正在调用一个[函数插件]的模板,该函数面向希望实现更多有趣功能的开发者,它可以作为创建新功能函数的模板(该函数只有20多行代码)。此外我们也提供可同步处理大量文件的多线程Demo供您参考。您若希望分享新的功能模组,请不吝PR!" + 高阶功能模板函数示意图)) + chatbot.append(("这是什么功能?", "[Local Message] 请注意,您正在调用一个[函数插件]的模板,该函数面向希望实现更多有趣功能的开发者,它可以作为创建新功能函数的模板(该函数只有20多行代码)。此外我们也提供可同步处理大量文件的多线程Demo供您参考。您若希望分享新的功能模组,请不吝PR!")) yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 # 由于请求gpt需要一段时间,我们先及时地做一次界面更新 for i in range(5): currentMonth = (datetime.date.today() + datetime.timedelta(days=i)).month @@ -54,46 +26,4 @@ def 高阶功能模板函数(txt, llm_kwargs, plugin_kwargs, chatbot, history, s ) chatbot[-1] = (i_say, gpt_say) history.append(i_say);history.append(gpt_say) - yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 # 界面更新 - - - - -PROMPT = """ -请你给出围绕“{subject}”的逻辑关系图,使用mermaid语法,mermaid语法举例: -```mermaid -graph TD - P(编程) --> L1(Python) - P(编程) --> L2(C) - P(编程) --> L3(C++) - P(编程) --> L4(Javascipt) - P(编程) --> L5(PHP) -``` -""" -@CatchException -def 测试图表渲染(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request): - """ - txt 输入栏用户输入的文本,例如需要翻译的一段话,再例如一个包含了待处理文件的路径 - llm_kwargs gpt模型参数,如温度和top_p等,一般原样传递下去就行 - plugin_kwargs 插件模型的参数,用于灵活调整复杂功能的各种参数 - chatbot 聊天显示框的句柄,用于显示给用户 - history 聊天历史,前情提要 - system_prompt 给gpt的静默提醒 - user_request 当前用户的请求信息(IP地址等) - """ - history = [] # 清空历史,以免输入溢出 - chatbot.append(("这是什么功能?", "一个测试mermaid绘制图表的功能,您可以在输入框中输入一些关键词,然后使用mermaid+llm绘制图表。")) - yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 # 由于请求gpt需要一段时间,我们先及时地做一次界面更新 - - if txt == "": txt = "空白的输入栏" # 调皮一下 - - i_say_show_user = f'请绘制有关“{txt}”的逻辑关系图。' - i_say = PROMPT.format(subject=txt) - gpt_say = yield from request_gpt_model_in_new_thread_with_ui_alive( - inputs=i_say, - inputs_show_user=i_say_show_user, - llm_kwargs=llm_kwargs, chatbot=chatbot, history=[], - sys_prompt="" - ) - history.append(i_say); history.append(gpt_say) - yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 # 界面更新 \ No newline at end of file + yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 # 界面更新 \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index 2090c5aa90f728e16d1d0254feb03cddefff12a1..2387527fce707643a03c763aa177826108d5cfbc 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,81 +1,4 @@ -## =================================================== -# docker-compose.yml -## =================================================== -# 1. 请在以下方案中选择任意一种,然后删除其他的方案 -# 2. 修改你选择的方案中的environment环境变量,详情请见github wiki或者config.py -# 3. 选择一种暴露服务端口的方法,并对相应的配置做出修改: - # 【方法1: 适用于Linux,很方便,可惜windows不支持】与宿主的网络融合为一体,这个是默认配置 - # network_mode: "host" - # 【方法2: 适用于所有系统包括Windows和MacOS】端口映射,把容器的端口映射到宿主的端口(注意您需要先删除network_mode: "host",再追加以下内容) - # ports: - # - "12345:12345" # 注意!12345必须与WEB_PORT环境变量相互对应 -# 4. 最后`docker-compose up`运行 -# 5. 如果希望使用显卡,请关注 LOCAL_MODEL_DEVICE 和 英伟达显卡运行时 选项 -## =================================================== -# 1. Please choose one of the following options and delete the others. -# 2. Modify the environment variables in the selected option, see GitHub wiki or config.py for more details. -# 3. Choose a method to expose the server port and make the corresponding configuration changes: - # [Method 1: Suitable for Linux, convenient, but not supported for Windows] Fusion with the host network, this is the default configuration - # network_mode: "host" - # [Method 2: Suitable for all systems including Windows and MacOS] Port mapping, mapping the container port to the host port (note that you need to delete network_mode: "host" first, and then add the following content) - # ports: - # - "12345: 12345" # Note! 12345 must correspond to the WEB_PORT environment variable. -# 4. Finally, run `docker-compose up`. -# 5. If you want to use a graphics card, pay attention to the LOCAL_MODEL_DEVICE and Nvidia GPU runtime options. -## =================================================== - -## =================================================== -## 【方案零】 部署项目的全部能力(这个是包含cuda和latex的大型镜像。如果您网速慢、硬盘小或没有显卡,则不推荐使用这个) -## =================================================== -version: '3' -services: - gpt_academic_full_capability: - image: ghcr.io/binary-husky/gpt_academic_with_all_capacity:master - environment: - # 请查阅 `config.py`或者 github wiki 以查看所有的配置信息 - API_KEY: ' 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 ' - # USE_PROXY: ' True ' - # proxies: ' { "http": "http://localhost:10881", "https": "http://localhost:10881", } ' - LLM_MODEL: ' gpt-3.5-turbo ' - AVAIL_LLM_MODELS: ' ["gpt-3.5-turbo", "gpt-4", "qianfan", "sparkv2", "spark", "chatglm"] ' - BAIDU_CLOUD_API_KEY : ' bTUtwEAveBrQipEowUvDwYWq ' - BAIDU_CLOUD_SECRET_KEY : ' jqXtLvXiVw6UNdjliATTS61rllG8Iuni ' - XFYUN_APPID: ' 53a8d816 ' - XFYUN_API_SECRET: ' MjMxNDQ4NDE4MzM0OSNlNjQ2NTlhMTkx ' - XFYUN_API_KEY: ' 95ccdec285364869d17b33e75ee96447 ' - ENABLE_AUDIO: ' False ' - DEFAULT_WORKER_NUM: ' 20 ' - WEB_PORT: ' 12345 ' - ADD_WAIFU: ' False ' - ALIYUN_APPKEY: ' RxPlZrM88DnAFkZK ' - THEME: ' Chuanhu-Small-and-Beautiful ' - ALIYUN_ACCESSKEY: ' LTAI5t6BrFUzxRXVGUWnekh1 ' - ALIYUN_SECRET: ' eHmI20SVWIwQZxCiTD2bGQVspP9i68 ' - # LOCAL_MODEL_DEVICE: ' cuda ' - - # 加载英伟达显卡运行时 - # runtime: nvidia - # deploy: - # resources: - # reservations: - # devices: - # - driver: nvidia - # count: 1 - # capabilities: [gpu] - - # 【WEB_PORT暴露方法1: 适用于Linux】与宿主的网络融合 - network_mode: "host" - - # 【WEB_PORT暴露方法2: 适用于所有系统】端口映射 - # ports: - # - "12345:12345" # 12345必须与WEB_PORT相互对应 - - # 启动容器后,运行main.py主程序 - command: > - bash -c "python3 -u main.py" - - - +#【请修改完参数后,删除此行】请在以下方案中选择一种,然后删除其他的方案,最后docker-compose up运行 | Please choose from one of these options below, delete other options as well as This Line ## =================================================== ## 【方案一】 如果不需要运行本地模型(仅 chatgpt, azure, 星火, 千帆, claude 等在线大模型服务) @@ -129,7 +52,7 @@ services: runtime: nvidia devices: - /dev/nvidia0:/dev/nvidia0 - + # 与宿主的网络融合 network_mode: "host" command: > @@ -137,7 +60,7 @@ services: # P.S. 通过对 command 进行微调,可以便捷地安装额外的依赖 # command: > - # bash -c "pip install -r request_llms/requirements_qwen.txt && python3 -u main.py" + # bash -c "pip install -r request_llm/requirements_qwen.txt && python3 -u main.py" ### =================================================== ### 【方案三】 如果需要运行ChatGPT + LLAMA + 盘古 + RWKV本地模型 @@ -163,7 +86,7 @@ services: runtime: nvidia devices: - /dev/nvidia0:/dev/nvidia0 - + # 与宿主的网络融合 network_mode: "host" @@ -229,3 +152,4 @@ services: # 不使用代理网络拉取最新代码 command: > bash -c "python3 -u main.py" + diff --git a/docs/Dockerfile+ChatGLM b/docs/Dockerfile+ChatGLM index 7777bf26716e9206de62a51da2d47eadaff0ed15..f0d7c7586f14f3a77557684d62609dba8d5a83a5 100644 --- a/docs/Dockerfile+ChatGLM +++ b/docs/Dockerfile+ChatGLM @@ -1 +1,2 @@ # 此Dockerfile不再维护,请前往docs/GithubAction+ChatGLM+Moss + diff --git a/docs/Dockerfile+JittorLLM b/docs/Dockerfile+JittorLLM index b10be8075b3212c6231e6574af29932de6d35aa6..2bd1237b9386545ed681a9540af968872bddd140 100644 --- a/docs/Dockerfile+JittorLLM +++ b/docs/Dockerfile+JittorLLM @@ -1 +1 @@ -# 此Dockerfile不再维护,请前往docs/GithubAction+JittorLLMs +# 此Dockerfile不再维护,请前往docs/GithubAction+JittorLLMs \ No newline at end of file diff --git a/docs/GithubAction+AllCapacity b/docs/GithubAction+AllCapacity index 4ba0e31a9e1e7858059e179e97ff2648dd898c58..2ed9f4c9e97a0a53ec8fb1681a126c7aa9cb06a1 100644 --- a/docs/GithubAction+AllCapacity +++ b/docs/GithubAction+AllCapacity @@ -13,20 +13,21 @@ RUN python3 -m pip install openai numpy arxiv rich RUN python3 -m pip install colorama Markdown pygments pymupdf RUN python3 -m pip install python-docx moviepy pdfminer RUN python3 -m pip install zh_langchain==0.2.1 pypinyin +RUN python3 -m pip install nougat-ocr RUN python3 -m pip install rarfile py7zr -RUN python3 -m pip install aliyun-python-sdk-core==2.13.3 pyOpenSSL webrtcvad scipy git+https://github.com/aliyun/alibabacloud-nls-python-sdk.git +RUN python3 -m pip install aliyun-python-sdk-core==2.13.3 pyOpenSSL scipy git+https://github.com/aliyun/alibabacloud-nls-python-sdk.git # 下载分支 WORKDIR /gpt RUN git clone --depth=1 https://github.com/binary-husky/gpt_academic.git WORKDIR /gpt/gpt_academic -RUN git clone --depth=1 https://github.com/OpenLMLab/MOSS.git request_llms/moss +RUN git clone https://github.com/OpenLMLab/MOSS.git request_llm/moss RUN python3 -m pip install -r requirements.txt -RUN python3 -m pip install -r request_llms/requirements_moss.txt -RUN python3 -m pip install -r request_llms/requirements_qwen.txt -RUN python3 -m pip install -r request_llms/requirements_chatglm.txt -RUN python3 -m pip install -r request_llms/requirements_newbing.txt -RUN python3 -m pip install nougat-ocr +RUN python3 -m pip install -r request_llm/requirements_moss.txt +RUN python3 -m pip install -r request_llm/requirements_qwen.txt +RUN python3 -m pip install -r request_llm/requirements_chatglm.txt +RUN python3 -m pip install -r request_llm/requirements_newbing.txt + # 预热Tiktoken模块 diff --git a/docs/GithubAction+AllCapacityBeta b/docs/GithubAction+AllCapacityBeta deleted file mode 100644 index d3a06ee19860f49e76c836add5c6ff65aa0517ff..0000000000000000000000000000000000000000 --- a/docs/GithubAction+AllCapacityBeta +++ /dev/null @@ -1,53 +0,0 @@ -# docker build -t gpt-academic-all-capacity -f docs/GithubAction+AllCapacity --network=host --build-arg http_proxy=http://localhost:10881 --build-arg https_proxy=http://localhost:10881 . -# docker build -t gpt-academic-all-capacity -f docs/GithubAction+AllCapacityBeta --network=host . -# docker run -it --net=host gpt-academic-all-capacity bash - -# 从NVIDIA源,从而支持显卡(检查宿主的nvidia-smi中的cuda版本必须>=11.3) -FROM fuqingxu/11.3.1-runtime-ubuntu20.04-with-texlive:latest - -# use python3 as the system default python -WORKDIR /gpt -RUN curl -sS https://bootstrap.pypa.io/get-pip.py | python3.8 - -# # 非必要步骤,更换pip源 (以下三行,可以删除) -# RUN echo '[global]' > /etc/pip.conf && \ -# echo 'index-url = https://mirrors.aliyun.com/pypi/simple/' >> /etc/pip.conf && \ -# echo 'trusted-host = mirrors.aliyun.com' >> /etc/pip.conf - -# 下载pytorch -RUN python3 -m pip install torch torchvision --extra-index-url https://download.pytorch.org/whl/cu113 -# 准备pip依赖 -RUN python3 -m pip install openai numpy arxiv rich -RUN python3 -m pip install colorama Markdown pygments pymupdf -RUN python3 -m pip install python-docx moviepy pdfminer -RUN python3 -m pip install zh_langchain==0.2.1 pypinyin -RUN python3 -m pip install rarfile py7zr -RUN python3 -m pip install aliyun-python-sdk-core==2.13.3 pyOpenSSL webrtcvad scipy git+https://github.com/aliyun/alibabacloud-nls-python-sdk.git -# 下载分支 -WORKDIR /gpt -RUN git clone --depth=1 https://github.com/binary-husky/gpt_academic.git -WORKDIR /gpt/gpt_academic -RUN git clone --depth=1 https://github.com/OpenLMLab/MOSS.git request_llms/moss - -RUN python3 -m pip install -r requirements.txt -RUN python3 -m pip install -r request_llms/requirements_moss.txt -RUN python3 -m pip install -r request_llms/requirements_qwen.txt -RUN python3 -m pip install -r request_llms/requirements_chatglm.txt -RUN python3 -m pip install -r request_llms/requirements_newbing.txt -RUN python3 -m pip install nougat-ocr - -# 预热Tiktoken模块 -RUN python3 -c 'from check_proxy import warm_up_modules; warm_up_modules()' - -# 安装知识库插件的额外依赖 -RUN apt-get update && apt-get install libgl1 -y -RUN pip3 install transformers protobuf langchain sentence-transformers faiss-cpu nltk beautifulsoup4 bitsandbytes tabulate icetk --upgrade -RUN pip3 install unstructured[all-docs] --upgrade -RUN python3 -c 'from check_proxy import warm_up_vectordb; warm_up_vectordb()' -RUN rm -rf /usr/local/lib/python3.8/dist-packages/tests - - -# COPY .cache /root/.cache -# COPY config_private.py config_private.py -# 启动 -CMD ["python3", "-u", "main.py"] diff --git a/docs/GithubAction+ChatGLM+Moss b/docs/GithubAction+ChatGLM+Moss index 3212dc2f4d17425696e0a67a35e90cb81b6a99e5..3087d5513c646759c33f08d29d62ed68602eaa93 100644 --- a/docs/GithubAction+ChatGLM+Moss +++ b/docs/GithubAction+ChatGLM+Moss @@ -14,12 +14,12 @@ RUN python3 -m pip install torch --extra-index-url https://download.pytorch.org/ WORKDIR /gpt RUN git clone --depth=1 https://github.com/binary-husky/gpt_academic.git WORKDIR /gpt/gpt_academic -RUN git clone https://github.com/OpenLMLab/MOSS.git request_llms/moss +RUN git clone https://github.com/OpenLMLab/MOSS.git request_llm/moss RUN python3 -m pip install -r requirements.txt -RUN python3 -m pip install -r request_llms/requirements_moss.txt -RUN python3 -m pip install -r request_llms/requirements_qwen.txt -RUN python3 -m pip install -r request_llms/requirements_chatglm.txt -RUN python3 -m pip install -r request_llms/requirements_newbing.txt +RUN python3 -m pip install -r request_llm/requirements_moss.txt +RUN python3 -m pip install -r request_llm/requirements_qwen.txt +RUN python3 -m pip install -r request_llm/requirements_chatglm.txt +RUN python3 -m pip install -r request_llm/requirements_newbing.txt diff --git a/docs/GithubAction+JittorLLMs b/docs/GithubAction+JittorLLMs index 189eb24431e4778367e08d359949a260e9426194..dc883bcfcc393dcafed8010e15894e53f4b6cfc2 100644 --- a/docs/GithubAction+JittorLLMs +++ b/docs/GithubAction+JittorLLMs @@ -16,12 +16,12 @@ WORKDIR /gpt RUN git clone --depth=1 https://github.com/binary-husky/gpt_academic.git WORKDIR /gpt/gpt_academic RUN python3 -m pip install -r requirements.txt -RUN python3 -m pip install -r request_llms/requirements_chatglm.txt -RUN python3 -m pip install -r request_llms/requirements_newbing.txt -RUN python3 -m pip install -r request_llms/requirements_jittorllms.txt -i https://pypi.jittor.org/simple -I +RUN python3 -m pip install -r request_llm/requirements_chatglm.txt +RUN python3 -m pip install -r request_llm/requirements_newbing.txt +RUN python3 -m pip install -r request_llm/requirements_jittorllms.txt -i https://pypi.jittor.org/simple -I # 下载JittorLLMs -RUN git clone https://github.com/binary-husky/JittorLLMs.git --depth 1 request_llms/jittorllms +RUN git clone https://github.com/binary-husky/JittorLLMs.git --depth 1 request_llm/jittorllms # 禁用缓存,确保更新代码 ADD "https://www.random.org/cgi-bin/randbyte?nbytes=10&format=h" skipcache diff --git a/docs/GithubAction+NoLocal+AudioAssistant b/docs/GithubAction+NoLocal+AudioAssistant index 6d6dab0a5bfce8b62ce8c292924a6303229d425d..9ea1ea54636d698a452be7de98d5413551ee39af 100644 --- a/docs/GithubAction+NoLocal+AudioAssistant +++ b/docs/GithubAction+NoLocal+AudioAssistant @@ -13,7 +13,7 @@ COPY . . RUN pip3 install -r requirements.txt # 安装语音插件的额外依赖 -RUN pip3 install aliyun-python-sdk-core==2.13.3 pyOpenSSL webrtcvad scipy git+https://github.com/aliyun/alibabacloud-nls-python-sdk.git +RUN pip3 install pyOpenSSL scipy git+https://github.com/aliyun/alibabacloud-nls-python-sdk.git # 可选步骤,用于预热模块 RUN python3 -c 'from check_proxy import warm_up_modules; warm_up_modules()' diff --git a/docs/GithubAction+NoLocal+Latex b/docs/GithubAction+NoLocal+Latex index 95dd4b82729da1cc611c1c245c9ed2c54ba0cde3..2f2608ccb77eb01e162b0176baf8f39dc3391019 100644 --- a/docs/GithubAction+NoLocal+Latex +++ b/docs/GithubAction+NoLocal+Latex @@ -4,22 +4,16 @@ # - 3 运行 docker run -v /home/fuqingxu/arxiv_cache:/root/arxiv_cache --rm -it --net=host gpt-academic-nolocal-latex FROM fuqingxu/python311_texlive_ctex:latest -ENV PATH "$PATH:/usr/local/texlive/2022/bin/x86_64-linux" -ENV PATH "$PATH:/usr/local/texlive/2023/bin/x86_64-linux" -ENV PATH "$PATH:/usr/local/texlive/2024/bin/x86_64-linux" -ENV PATH "$PATH:/usr/local/texlive/2025/bin/x86_64-linux" -ENV PATH "$PATH:/usr/local/texlive/2026/bin/x86_64-linux" - -# 删除文档文件以节约空间 -RUN rm -rf /usr/local/texlive/2023/texmf-dist/doc # 指定路径 WORKDIR /gpt -RUN pip3 install openai numpy arxiv rich +RUN pip3 install gradio openai numpy arxiv rich RUN pip3 install colorama Markdown pygments pymupdf -RUN pip3 install python-docx pdfminer +RUN pip3 install python-docx moviepy pdfminer +RUN pip3 install zh_langchain==0.2.1 RUN pip3 install nougat-ocr +RUN pip3 install aliyun-python-sdk-core==2.13.3 pyOpenSSL scipy git+https://github.com/aliyun/alibabacloud-nls-python-sdk.git # 装载项目文件 COPY . . diff --git a/docs/GithubAction+NoLocal+Vectordb b/docs/GithubAction+NoLocal+Vectordb deleted file mode 100644 index 45074d935d664fa2754230dcdc0c056f5ace047a..0000000000000000000000000000000000000000 --- a/docs/GithubAction+NoLocal+Vectordb +++ /dev/null @@ -1,26 +0,0 @@ -# 此Dockerfile适用于“无本地模型”的环境构建,如果需要使用chatglm等本地模型,请参考 docs/Dockerfile+ChatGLM -# 如何构建: 先修改 `config.py`, 然后 docker build -t gpt-academic-nolocal-vs -f docs/GithubAction+NoLocal+Vectordb . -# 如何运行: docker run --rm -it --net=host gpt-academic-nolocal-vs -FROM python:3.11 - -# 指定路径 -WORKDIR /gpt - -# 装载项目文件 -COPY . . - -# 安装依赖 -RUN pip3 install -r requirements.txt - -# 安装知识库插件的额外依赖 -RUN apt-get update && apt-get install libgl1 -y -RUN pip3 install torch torchvision --index-url https://download.pytorch.org/whl/cpu -RUN pip3 install transformers protobuf langchain sentence-transformers faiss-cpu nltk beautifulsoup4 bitsandbytes tabulate icetk --upgrade -RUN pip3 install unstructured[all-docs] --upgrade -RUN python3 -c 'from check_proxy import warm_up_vectordb; warm_up_vectordb()' - -# 可选步骤,用于预热模块 -RUN python3 -c 'from check_proxy import warm_up_modules; warm_up_modules()' - -# 启动 -CMD ["python3", "-u", "main.py"] diff --git a/docs/README.Arabic.md b/docs/README.Arabic.md deleted file mode 100644 index 5d8bf3cc31d118fab8d8523bebffce77593abb5c..0000000000000000000000000000000000000000 --- a/docs/README.Arabic.md +++ /dev/null @@ -1,343 +0,0 @@ - - - -> **ملحوظة** -> -> تمت ترجمة هذا الملف README باستخدام GPT (بواسطة المكون الإضافي لهذا المشروع) وقد لا تكون الترجمة 100٪ موثوقة، يُرجى التمييز بعناية بنتائج الترجمة. -> -> 2023.11.7: عند تثبيت التبعيات، يُرجى اختيار الإصدار المُحدد في `requirements.txt`. الأمر للتثبيت: `pip install -r requirements.txt`. - -#
GPT الأكاديمي
- -**إذا كنت تحب هذا المشروع، فيُرجى إعطاؤه Star. لترجمة هذا المشروع إلى لغة عشوائية باستخدام GPT، قم بقراءة وتشغيل [`multi_language.py`](multi_language.py) (تجريبي). - -> **ملحوظة** -> -> 1. يُرجى ملاحظة أنها الإضافات (الأزرار) المميزة فقط التي تدعم قراءة الملفات، وبعض الإضافات توجد في قائمة منسدلة في منطقة الإضافات. بالإضافة إلى ذلك، نرحب بأي Pull Request جديد بأعلى أولوية لأي إضافة جديدة. -> -> 2. تُوضّح كل من الملفات في هذا المشروع وظيفتها بالتفصيل في [تقرير الفهم الذاتي `self_analysis.md`](https://github.com/binary-husky/gpt_academic/wiki/GPT‐Academic项目自译解报告). يمكنك في أي وقت أن تنقر على إضافة وظيفة ذات صلة لاستدعاء GPT وإعادة إنشاء تقرير الفهم الذاتي للمشروع. للأسئلة الشائعة [`الويكي`](https://github.com/binary-husky/gpt_academic/wiki). [طرق التثبيت العادية](#installation) | [نصب بنقرة واحدة](https://github.com/binary-husky/gpt_academic/releases) | [تعليمات التكوين](https://github.com/binary-husky/gpt_academic/wiki/项目配置说明). -> -> 3. يتم توافق هذا المشروع مع ودعم توصيات اللغة البيجائية الأكبر شمولًا وشجاعة لمثل ChatGLM. يمكنك توفير العديد من مفاتيح Api المشتركة في تكوين الملف، مثل `API_KEY="openai-key1,openai-key2,azure-key3,api2d-key4"`. عند تبديل مؤقت لـ `API_KEY`، قم بإدخال `API_KEY` المؤقت في منطقة الإدخال ثم اضغط على زر "إدخال" لجعله ساري المفعول. - - - -
- -الوظائف (⭐= وظائف مُضافة حديثًا) | الوصف ---- | --- -⭐[التوصل لنموذج جديد](https://github.com/binary-husky/gpt_academic/wiki/%E5%A6%82%E4%BD%95%E5%88%87%E6%8D%A2%E6%A8%A1%E5%9E%8B)! | بحث بيدو[تشيان فان](https://cloud.baidu.com/doc/WENXINWORKSHOP/s/Nlks5zkzu) ووينسين[جينرال](https://modelscope.cn/models/qwen/Qwen-7B-Chat/summary)، مختبرات شنغهاي للذكاء الصناعي[شو شينغ](https://github.com/InternLM/InternLM)، إكسنفلام[زينغهو]https://xinghuo.xfyun.cn/)، [LLaMa2](https://huggingface.co/meta-llama/Llama-2-7b-chat-hf)، واجهة بيانية ذكية و3 خدمات إضافية [DALLE3] -الجودة الفائقة، الترجمة، شرح الكود | الإصلاح الفوري للاخطاء النحوية في الأبحاث وترجمة وتحسين التصريف اللغوي للأكواد -[اختصارات مخصصة](https://www.bilibili.com/video/BV14s4y1E7jN) | دعم الاختصارات المخصصة -تصميم قابل للتوسيع | دعم الإضافات القوية المخصصة (الوظائف)، الإضافات قابلة للتحديث بشكل فوري -[تحليل البرنامج](https://www.bilibili.com/video/BV1cj411A7VW) | [وظائف] التحليل الشجري بناءً على البرنامج من Python/C/C++/Java/Lua/..., أو [التحليل الذاتي](https://www.bilibili.com/video/BV1cj411A7VW) -قراءة وترجمة الأبحاث | [وظائف] فك تشفير كامل لأوراق البحث بتنسيق LaTeX/PDF وإنشاء مستخلص -ترجمة وتحسين أوراق اللاتكس | [وظائف] ترجمة أو تحسين الأوراق المكتوبة بلاتكس -إنشاء تعليقات الدوال دفعة واحدة | [وظائف] إنشاء تعليقات الدوال بدفعة واحدة -ترجمة Markdown بين اللغتين العربية والإنجليزية | [وظائف] هل رأيت الـ 5 لغات المستخدمة في منشور [README](https://github.com/binary-husky/gpt_academic/blob/master/docs/README_EN.md) ؟ -إنشاء تقرير تحليل الدردشة | [وظائف] إنشاء تقرير ملخص بعد تشغيله -ترجمة كاملة لأوراق PDF | [وظائف] تحليل الأوراق بتنسيق PDF لتحديد العنوان وملخصها وترجمتها (متعدد الخيوط) -مساعدة Arxiv | [وظائف] قم بإدخال رابط مقال Arxiv لترجمة الملخص وتحميل ملف PDF -تصحيح لاتكس بضغطة زر واحدة | [وظائف] إكمال تصحيح لاتكس بناءً على التركيبة النحوية، إخراج همز المقابل للمقارنة PDF -مساعد بحث Google بنسخة محلية | [وظائف] قم بتقديم رابط لصفحة بحث Google Scholar العشوائي حتى يساعدك GPT في كتابة [الأبحاث المتعلقة](https://www.bilibili.com/video/BV1GP411U7Az/) -تجميع معلومات الويب + GPT | [وظائف] جمع المعلومات من الويب بشكل سهل للرد على الأسئلة لجعل المعلومات محدثة باستمرار -⭐ترجمة دقيقة لأوراق Arxiv ([Docker](https://github.com/binary-husky/gpt_academic/pkgs/container/gpt_academic_with_latex)) | [وظائف] ترجمة مقالات Arxiv عالية الجودة بنقرة واحدة، أفضل أداة حاليا للترجمة -⭐[إدخال الصوت الفوري](https://github.com/binary-husky/gpt_academic/blob/master/docs/use_audio.md) | [وظائف] (غير متزامن) استماع الصوت وقطعه تلقائيًا وتحديد وقت الإجابة تلقائيًا -عرض الصيغ/الصور/الجداول | يمكن عرض الصيغ بشكل [TEX](https://user-images.githubusercontent.com/96192199/230598842-1d7fcddd-815d-40ee-af60-baf488a199df.png) وأيضًا بتنسيق رسومي، يدعم عرض الصيغ وإبراز الكود -⭐إضغط على وكيل "شارلوت الذكي" | [وظائف] استكمال الذكاء للكأس الأول للذكاء المكتسب من مايكروسوفت، اكتشاف وتطوير عالمي العميل -تبديل الواجهة المُظلمة | يمكنك التبديل إلى الواجهة المظلمة بإضافة ```/?__theme=dark``` إلى نهاية عنوان URL في المتصفح -دعم المزيد من نماذج LLM | دعم لجميع GPT3.5 وGPT4 و[ChatGLM2 في جامعة ثوه في لين](https://github.com/THUDM/ChatGLM2-6B) و[MOSS في جامعة فودان](https://github.com/OpenLMLab/MOSS) -⭐تحوي انطباعة "ChatGLM2" | يدعم استيراد "ChatGLM2" ويوفر إضافة المساعدة في تعديله -دعم المزيد من نماذج "LLM"، دعم [نشر الحديس](https://huggingface.co/spaces/qingxu98/gpt-academic) | انضم إلى واجهة "Newbing" (Bing الجديدة)،نقدم نماذج Jittorllms الجديدة تؤيدهم [LLaMA](https://github.com/facebookresearch/llama) و [盘古α](https://openi.org.cn/pangu/) -⭐حزمة "void-terminal" للشبكة (pip) | قم بطلب كافة وظائف إضافة هذا المشروع في python بدون واجهة رسومية (قيد التطوير) -⭐PCI-Express لإعلام (PCI) | [وظائف] باللغة الطبيعية، قم بتنفيذ المِهام الأخرى في المشروع -المزيد من العروض (إنشاء الصور وغيرها)……| شاهد أكثر في نهاية هذا المستند ... -
- - -- شكل جديد (عن طريق تعديل الخيار LAYOUT في `config.py` لقانون التوزيع "اليمين أو اليسار" أو "الأعلى أو الأسفل") -
- -
- - -- جميع الأزرار يتم إنشاؤها ديناميكيًا من خلال قراءة functional.py ويمكن إضافة وظائف مخصصة بحرية وتحرير الحافظة -
- -
- -- التجميل / التحوير -
- -
- - - -- إذا تضمّن الإخراج معادلات، فسيتم عرضها بشكلٍ يمكّن من النسخ والقراءة على النحوين: TEX ورسومية. -
- -
- -- هل تشعر بالكسل من قراءة كود المشروع؟ قم بمدها مباشرةً إلى ChatGPT -
- -
- -- دمج نماذج اللغات الكبيرة المختلفة (ChatGLM + OpenAI-GPT3.5 + [API2D](https://api2d.com/)-GPT4) -
- -
- -# Installation -### طريقة التثبيت الأولى: التشغيل المباشر (Windows، Linux أو MacOS) - -1. قم بتنزيل المشروع -```sh -git clone --depth=1 https://github.com/binary-husky/gpt_academic.git -cd gpt_academic -``` - -2. قم بتكوين لغة البرمجة Python - -في ملف `config.py`، قم بتكوين مفتاح الواجهة API والإعدادات الأخرى، [انقر هنا للاطلاع على طريقة تكوين الإعدادات في بيئة شبكة خاصة](https://github.com/binary-husky/gpt_academic/issues/1). [انقر هنا لزيارة صفحة الويكي](https://github.com/binary-husky/gpt_academic/wiki/توضيحات-تكوين-المشروع). - -" ستقوم البرنامج بفحص وجود ملف تكوين خاص يسمى `config_private.py` بأولوية، وسيستخدم التكوينات الموجودة فيه لتجاوز التكوينات ذات الأسماء المطابقة في `config.py`. إذا كنت تفهم هذه الطريقة ونظام القراءة، فإننا نوصي بشدة بإنشاء ملف تكوين جديد يسمى `config_private.py` بجوار `config.py` ونقل (نسخ) التكوينات الموجودة في `config.py` إلى `config_private.py` (يجب نسخ العناصر التي قمت بتعديلها فقط). " - -" يدعم المشروع التكوين من خلال `المتغيرات المحيطية`، ويمكن تحديد تنسيق كتابة المتغيرات المحيطية من خلال ملف `docker-compose.yml` أو صفحة الويكي الخاصة بنا. تعتمد أولوية القراءة على التكوينات على التالي: `المتغيرات المحيطية` > `config_private.py` > `config.py`. " - -3. قم بتثبيت التبعيات -```sh -# (الخيار الأول: إذا كنت تعرف Python، python>=3.9) الملحوظة: استخدم مستودع pip الرسمي أو مستودع pip آلي بباي، يمكن تغيير المستودع المؤقت بواسطة الأمر: python -m pip install -r requirements.txt -i https://mirrors.aliyun.com/pypi/simple/ -python -m pip install -r requirements.txt - -# (الخيار الثاني: باستخدام Anaconda) الخطوات مشابهة (https://www.bilibili.com/video/BV1rc411W7Dr): -conda create -n gptac_venv python=3.11 # إنشاء بيئة Anaconda -conda activate gptac_venv # تنشيط بيئة Anaconda -python -m pip install -r requirements.txt # هذه الخطوة مطابقة لخطوة تثبيت pip -``` - - -
إذا كنت بحاجة إلى دعم ChatGLM2 من الجامعة الصينية للاقتصاد وإدارة الأعمال وموس من جامعة فودان كخادم وجودة عالية لطرح الأسئلة، انقر هنا للعرض -

- -【خطوات اختيارية】إذا كنت بحاجة إلى دعم جودة عالية لتشات جامعة تسينهوا (ChatGLM2) الصينية وجامعة فودان (MOSS)، يتعين عليك تثبيت تبعيات إضافية (شرط مسبق: التعامل مع Python واستخدام Pytorch وتوفر الحاسوب الشخصي بمواصفات قوية): -```sh -# 【خطوات اختيارية 1】دعم جودة عالية لتشات جامعة تسينهوا (ChatGLM2) -python -m pip install -r request_llms/requirements_chatglm.txt - -# 【خطوات اختيارية 2】دعم جودة عالية لتشات جامعة فودان (MOSS) -python -m pip install -r request_llms/requirements_moss.txt -git clone --depth=1 https://github.com/OpenLMLab/MOSS.git request_llms/moss # عند تنفيذ هذا الأمر، يجب أن تكون في مسار المشروع الرئيسي - -# 【خطوات اختيارية 3】دعم RWKV Runner -راجع الويكي: https://github.com/binary-husky/gpt_academic/wiki/دليل-تكوين-RWKV - -# 【خطوات اختيارية 4】تأكد من أن ملف التكوين config.py يحتوي على النماذج المرجوة، وهناك النماذج المدعومة حاليًا التالية (توجد خطط لتشغيل "jittorllms" في docker فقط): -AVAIL_LLM_MODELS = ["gpt-3.5-turbo", "api2d-gpt-3.5-turbo", "gpt-4", "api2d-gpt-4", "chatglm", "moss"] # + ["jittorllms_rwkv", "jittorllms_pangualpha", "jittorllms_llama"] -``` - -

-
- - -4. تشغيل البرنامج -```sh -python main.py -``` - -### طريقة التثبيت الثانية: استخدام Docker - -0. نصب القدرات الكاملة للمشروع (هذا هو الصورة الكبيرة التي تحتوي على CUDA و LaTeX. ولكن إذا كانت سرعة الإنترنت بطيئة أو القرص الصلب صغير، فإننا لا نوصي باستخدام هذا الخيار) -[![fullcapacity](https://github.com/binary-husky/gpt_academic/actions/workflows/build-with-all-capacity.yml/badge.svg?branch=master)](https://github.com/binary-husky/gpt_academic/actions/workflows/build-with-all-capacity.yml) - -``` sh -# قم بتعديل ملف docker-compose.yml للحفاظ على الخطة رقم 0 وحذف الخطط الأخرى. ثم أشغل: -docker-compose up -``` - -1. تشغيل نموذج ChatGPT فقط + 文心一言 (Wenxin YIYan) + Spark عبر الإنترنت (يُوصى بهذا الخيار للمعظم) - -[![basic](https://github.com/binary-husky/gpt_academic/actions/workflows/build-without-local-llms.yml/badge.svg?branch=master)](https://github.com/binary-husky/gpt_academic/actions/workflows/build-without-local-llms.yml) -[![basiclatex](https://github.com/binary-husky/gpt_academic/actions/workflows/build-with-latex.yml/badge.svg?branch=master)](https://github.com/binary-husky/gpt_academic/actions/workflows/build-with-latex.yml) -[![basicaudio](https://github.com/binary-husky/gpt_academic/actions/workflows/build-with-audio-assistant.yml/badge.svg?branch=master)](https://github.com/binary-husky/gpt_academic/actions/workflows/build-with-audio-assistant.yml) - -``` sh -# قم بتعديل ملف docker-compose.yml للحفاظ على الخطة رقم 1 وحذف الخطط الأخرى. ثم أشغل: -docker-compose up -``` - -P.S. للاستفادة من إمكانية اللافتكس الإضافية، يرجى الرجوع إلى الويكي. بالإضافة إلى ذلك، يمكنك استخدام الخطة 4 أو الخطة 0 مباشرة للحصول على إمكانية اللافتكس. - -2. تشغيل نموذج ChatGPT + نموذج ChatGLM2 + نموذج MOSS + نموذج LLAMA2 + تون يي تشين ون (QiChaYiWen) (يتطلب معرفة بتشغيل نيفيديا دوكر (Nvidia Docker)) - -[![chatglm](https://github.com/binary-husky/gpt_academic/actions/workflows/build-with-chatglm.yml/badge.svg?branch=master)](https://github.com/binary-husky/gpt_academic/actions/workflows/build-with-chatglm.yml) - -``` sh -# قم بتعديل ملف docker-compose.yml للحفاظ على الخطة رقم 2 وحذف الخطط الأخرى. ثم أشغل: -docker-compose up -``` - -### طريقة التثبيت الثالثة: طرائق نشر أخرى -1. **نصوص بنقرة واحدة لأنظمة Windows**. -يمكن لمستخدمي Windows الذين لا يعرفون بيئة Python تنزيل سكربت التشغيل بنقرة واحدة من [الإصدارات](https://github.com/binary-husky/gpt_academic/releases) المنشورة لتثبيت الإصدار الذي لا يحتوي على نماذج محلية. -المساهمة في السكربت تعود لـ[oobabooga](https://github.com/oobabooga/one-click-installers). - -2. استخدام واجهة برمجة تطبيقات (API) مطراف ثالثة، Microsoft Azure، ونشوة النص، وغيرها، يرجى الرجوع إلى [صفحة الويكي](https://github.com/binary-husky/gpt_academic/wiki/إعدادات-التكوين-للمشروع) الخاصة بنا - -3. دليل تجنب المشاكل عند نشر المشروع في خوادم السحابة. -يرجى زيارة صفحة [دليل نشر خوادم السحابة في المحيط](https://github.com/binary-husky/gpt_academic/wiki/دليل-نشر-خوادم-السحابة) - -4. طرائق نشر المشروع بأحدث الأساليب - - استخدام Sealos للنشر السريع [بنقرة واحدة](https://github.com/binary-husky/gpt_academic/issues/993). - - استخدم WSL2 (Windows Subsystem for Linux). يُرجى زيارة صفحة الويكي [لدليل التثبيت-2](https://github.com/binary-husky/gpt_academic/wiki/دليل-تشغيل-WSL2-(Windows-Subsystem-for-Linux) - - كيفية تشغيل البرنامج تحت عنوان فرعي (على سبيل المثال: `http://localhost/subpath`). يُرجى زيارة [إرشادات FastAPI](docs/WithFastapi.md) - - - -# الاستخدام المتقدم -### I: إنشاء أزرار مخصصة (اختصارات أكاديمية) -افتح أي محرر نصوص وافتح `core_functional.py` وأضف الإدخالات التالية ثم أعد تشغيل البرنامج. (إذا كانت الأزرار موجودة بالفعل، بإمكانك تعديل البادئة واللاحقة حراريًا دون الحاجة لإعادة تشغيل البرنامج) -على سبيل المثال: -``` -"ترجمة سوبر الإنجليزية إلى العربية": { - # البادئة، ستتم إضافتها قبل إدخالاتك. مثلاً، لوصف ما تريده مثل ترجمة أو شرح كود أو تلوين وهلم جرا - "بادئة": "يرجى ترجمة النص التالي إلى العربية ثم استخدم جدول Markdown لشرح المصطلحات المختصة المذكورة في النص:\n\n", - - # اللاحقة، سيتم إضافتها بعد إدخالاتك. يمكن استخدامها لوضع علامات اقتباس حول إدخالك. - "لاحقة": "", -}, -``` -
- -
- -### II: إنشاء مكونات وظيفية مخصصة -قم بكتابة مكونات وظيفية قوية لتنفيذ أي مهمة ترغب في الحصول عليها وحتى تلك التي لم تخطر لك على بال. -إن إنشاء وتصحيح المكونات في هذا المشروع سهل للغاية، فما عليك سوى أن تمتلك بعض المعرفة الأساسية في لغة البرمجة بايثون وتستند على القالب الذي نقدمه. -للمزيد من التفاصيل، يُرجى الاطلاع على [دليل المكونات الوظيفية](https://github.com/binary-husky/gpt_academic/wiki/%E5%87%BD%E6%95%B0%E6%8F%92%E4%BB%B6%E6%8C%87%E5%8D%97). - - -# التحديثات -### I: تحديثات - -1. ميزة حفظ الدردشة: يمكن حفظ الدردشة الحالية كملف HTML قابل للقراءة والاسترداد ببساطة عند استدعاء الوظيفة في منطقة المكونات `حفظ الدردشة الحالية` ، ويمكن استرجاع المحادثة السابقة ببساطة عند استدعاء الوظيفة في منطقة المكونات (القائمة المنسدلة) `تحميل سجل الدردشة` . -نصيحة: يمكنك النقر المباشر على `تحميل سجل الدردشة` بدون تحديد ملف لعرض ذاكرة التخزين المؤقت لسجلات HTML. -
- -
- -2. ميزة ترجمة المقالات العلمية بواسطة Latex/Arxiv -
- ===> - -
- -3. محطة فراغ (فهم نغمة المستخدم من داخل اللغة الطبيعية واستدعاء وظائف أخرى تلقائيًا) - -- الخطوة 1: اكتب "بالرجاء استدعاء وظيفة ترجمة المقالة الأكاديمية من PDF وعنوان المقال هو https://openreview.net/pdf?id=rJl0r3R9KX". -- الخطوة 2: انقر فوق "محطة الفراغ". - -
- -
- -4. تصميم الوظائف المتعددة القادرة على توفير وظائف قوية بواجهات بسيطة -
- - -
- -5. ترجمة وإلغاء ترجمة المشاريع الأخرى مفتوحة المصدر -
- - -
- -6. ميزة تزيين [live2d](https://github.com/fghrsh/live2d_demo) (مغلقة بشكل افتراضي، يتطلب تعديل `config.py`) -
- -
- -7. إنتاج الصور من OpenAI -
- -
- -8. تحليل وإجماع الصوت من OpenAI -
- -
- -9. إصلاح أخطاء اللغة الطبيعة في Latex -
- ===> - -
- -10. تغيير اللغة والموضوع -
- -
- - - -### II: الإصدارات: -- الإصدار 3.70 (قريبًا): تحسينات لوظائف AutoGen وتصميم سلسلة من المكونات المشتقة -- الإصدار 3.60: إدخال AutoGen كأساس لوظائف الجيل الجديد -- الإصدار 3.57: دعم GLM3، نار النجوم v3، وشجرة الكلمات v4، وإصلاح خطأ الازدحام في النماذج المحلية -- الإصدار 3.56: الدعم لإضافة مزامنة الأزرار الأساسية حسب الطلب، وصفحة تجميع تقارير البيانات في ملف PDF -- الإصدار 3.55: إعادة هيكلة واجهة المستخدم الأمامية، وإضافة نافذة عائمة وشريط قائمة -- الإصدار 3.54: إضافة مترجم الكود المباشر (Code Interpreter) (قيد الانجاز) -- الإصدار 3.53: دعم اختيار موضوعات واجهة مختلفة، وزيادة الاستقرار وحل مشاكل التعارض بين المستخدمين المتعدد -- الإصدار 3.50: استخدام اللغة الطبيعية لاستدعاء جميع وظائف المشروع هذا (محطة فراغ)، ودعم تصنيف الوظائف وتحسين واجهة المستخدم وتصميم مواضيع جديدة -- الإصدار 3.49: دعم المنصات البحثية في بيدو كونفان وشجرة الكلمات -- الإصدار 3.48: دعم علي بابا, بوكما رش حتكيا, إكسونامبلومانت النار -- الإصدار 3.46: دعم محادثة نصية في الوقت الحقيقي غير مراقبة -- الإصدار 3.45: دعم تخصيص LatexChatglm النموذج التعديل -- الإصدار 3.44: دعم Azure رسميًا، وتحسين سهولة الاستخدام للواجهات الأمامية -- الإصدار 3.4: +ترجمة النصوص الكاملة للمقالات من خلال ملف PDF، +اختيار موضع المنطقة النصية، +خيار التخطيط الرأسي، +تحسينات في وظائف التداخل العديدة -- الإصدار 3.3: +وظائف متكاملة للمعلومات عبر الإنترنت -- الإصدار 3.2: دعم وظائف المكونات التي تحتوي معلمات أكثر (حفظ النص، فهم أي لغة برمجة، طلب أي تركيبة LLM في وقت واحد) -- الإصدار 3.1: دعم السؤال نحو نماذج GPT المتعددة! دعم واجهة api2d، دعم توازن الأحمال بين المفاتيح الخاصة المتعددة -- الإصدار 3.0: دعم لنماذج جات، واحدة منها لشتلس الصغيرة -- الإصدار 2.6: إعادة تصميم بنية الوظائف، وتحسين التفاعل وإضافة مزيد من الوظائف -- الإصدار 2.5: التحديث التلقائي، وحل مشكلة النص الطويل عند ملخص المشاريع الضخمة وتجاوز النصوص. -- الإصدار 2.4: (١) إضافة ميزة ترجمة المقالات الدورية. (٢) إضافة ميزة لتحويل مكان منطقة الإدخال. (٣) إضافة خيار التخطيط العمودي (vertical layout). (٤) تحسين وظائف المكونات متعددة الخيوط. -- الإصدار 2.3: تحسين التفاعل مع مواضيع متعددة -- الإصدار 2.2: دعم إعادة تحميل الوظائف المكونة حراريًا -- الإصدار 2.1: تصميم قابل للطي -- الإصدار 2.0: إدخال وحدات الوظائف المكونة -- الإصدار 1.0: الوظائف الأساسية - -مجموعة المطورين GPT Academic QQ: `610599535` - -- مشكلات معروفة - - بعض ملحقات متصفح الترجمة تتداخل مع تشغيل الواجهة الأمامية لهذا البرنامج - - يحتوي Gradio الرسمي حاليًا على عدد كبير من مشاكل التوافق. يُرجى استخدام `requirement.txt` لتثبيت Gradio. - -### III: الأنساق -يمكن تغيير الأنساق بتعديل خيار `THEME` (config.py) -1. `Chuanhu-Small-and-Beautiful` [الرابط](https://github.com/GaiZhenbiao/ChuanhuChatGPT/) - - -### IV: فروع تطوير هذا المشروع - -1. الفرع `master`: الفرع الرئيسي، إصدار مستقر -2. الفرع `frontier`: الفرع التطويري، إصدار تجريبي - - -### V: المراجع والفروض التعليمية - -``` -استخدمت العديد من التصاميم الموجودة في مشاريع ممتازة أخرى في الأكواد التالية، للمراجع عشوائية: - -# ViewGradio: -https://github.com/THUD - - - -# مُثبّت بضغطة واحدة Oobabooga: -https://github.com/oobabooga/one-click-installers - -# المزيد: -https://github.com/gradio-app/gradio -https://github.com/fghrsh/live2d_demo diff --git a/docs/README.English.md b/docs/README.English.md deleted file mode 100644 index 48afdf4549f8f1a83927da857cd535a18e3e6f97..0000000000000000000000000000000000000000 --- a/docs/README.English.md +++ /dev/null @@ -1,357 +0,0 @@ - - - -> **Note** -> -> This README was translated by GPT (implemented by the plugin of this project) and may not be 100% reliable. Please carefully check the translation results. -> -> 2023.11.7: When installing dependencies, please select the **specified versions** in the `requirements.txt` file. Installation command: `pip install -r requirements.txt`. - - -#
GPT Academic Optimization
- -**If you like this project, please give it a Star.** -To translate this project to arbitrary language with GPT, read and run [`multi_language.py`](multi_language.py) (experimental). - -> **Note** -> -> 1.Please note that only plugins (buttons) highlighted in **bold** support reading files, and some plugins are located in the **dropdown menu** in the plugin area. Additionally, we welcome and process any new plugins with the **highest priority** through PRs. -> -> 2.The functionalities of each file in this project are described in detail in the [self-analysis report `self_analysis.md`](https://github.com/binary-husky/gpt_academic/wiki/GPT‐Academic项目自译解报告). As the version iterates, you can also click on the relevant function plugin at any time to call GPT to regenerate the project's self-analysis report. Common questions are in the [`wiki`](https://github.com/binary-husky/gpt_academic/wiki). [Regular installation method](#installation) | [One-click installation script](https://github.com/binary-husky/gpt_academic/releases) | [Configuration instructions](https://github.com/binary-husky/gpt_academic/wiki/项目配置说明). -> -> 3.This project is compatible with and encourages the use of domestic large-scale language models such as ChatGLM. Multiple api-keys can be used together. You can fill in the configuration file with `API_KEY="openai-key1,openai-key2,azure-key3,api2d-key4"` to temporarily switch `API_KEY` during input, enter the temporary `API_KEY`, and then press enter to apply it. - - - - -
- -Feature (⭐ = Recently Added) | Description ---- | --- -⭐[Integrate New Models](https://github.com/binary-husky/gpt_academic/wiki/%E5%A6%82%E4%BD%95%E5%88%87%E6%8D%A2%E6%A8%A1%E5%9E%8B) | Baidu [Qianfan](https://cloud.baidu.com/doc/WENXINWORKSHOP/s/Nlks5zkzu) and Wenxin Yiyu, [Tongyi Qianwen](https://modelscope.cn/models/qwen/Qwen-7B-Chat/summary), Shanghai AI-Lab [Shusheng](https://github.com/InternLM/InternLM), Xunfei [Xinghuo](https://xinghuo.xfyun.cn/), [LLaMa2](https://huggingface.co/meta-llama/Llama-2-7b-chat-hf), Zhifu API, DALLE3 -Proofreading, Translation, Code Explanation | One-click proofreading, translation, searching for grammar errors in papers, explaining code -[Custom Shortcuts](https://www.bilibili.com/video/BV14s4y1E7jN) | Support for custom shortcuts -Modular Design | Support for powerful [plugins](https://github.com/binary-husky/gpt_academic/tree/master/crazy_functions), plugins support [hot updates](https://github.com/binary-husky/gpt_academic/wiki/%E5%87%BD%E6%95%B0%E6%8F%92%E4%BB%B6%E6%8C%87%E5%8D%97) -[Program Profiling](https://www.bilibili.com/video/BV1cj411A7VW) | [Plugin] One-click to profile Python/C/C++/Java/Lua/... project trees or [self-profiling](https://www.bilibili.com/video/BV1cj411A7VW) -Read Papers, [Translate](https://www.bilibili.com/video/BV1KT411x7Wn) Papers | [Plugin] One-click to interpret full-text latex/pdf papers and generate abstracts -Full-text Latex [Translation](https://www.bilibili.com/video/BV1nk4y1Y7Js/), [Proofreading](https://www.bilibili.com/video/BV1FT411H7c5/) | [Plugin] One-click translation or proofreading of latex papers -Batch Comment Generation | [Plugin] One-click batch generation of function comments -Markdown [Translation](https://www.bilibili.com/video/BV1yo4y157jV/) | [Plugin] Did you see the [README](https://github.com/binary-husky/gpt_academic/blob/master/docs/README_EN.md) in the top five languages? -Chat Analysis Report Generation | [Plugin] Automatically generates summary reports after running -[PDF Paper Full-text Translation](https://www.bilibili.com/video/BV1KT411x7Wn) | [Plugin] Extract title & abstract of PDF papers + translate full-text (multi-threaded) -[Arxiv Helper](https://www.bilibili.com/video/BV1LM4y1279X) | [Plugin] Enter the arxiv article URL to translate the abstract + download PDF with one click -One-click Proofreading of Latex Papers | [Plugin] Syntax and spelling correction of Latex papers similar to Grammarly + output side-by-side PDF -[Google Scholar Integration Helper](https://www.bilibili.com/video/BV19L411U7ia) | [Plugin] Given any Google Scholar search page URL, let GPT help you [write related works](https://www.bilibili.com/video/BV1GP411U7Az/) -Internet Information Aggregation + GPT | [Plugin] One-click to let GPT retrieve information from the Internet to answer questions and keep the information up to date -⭐Arxiv Paper Fine Translation ([Docker](https://github.com/binary-husky/gpt_academic/pkgs/container/gpt_academic_with_latex)) | [Plugin] One-click [high-quality translation of arxiv papers](https://www.bilibili.com/video/BV1dz4y1v77A/), the best paper translation tool at present -⭐[Real-time Speech Input](https://github.com/binary-husky/gpt_academic/blob/master/docs/use_audio.md) | [Plugin] Asynchronously [listen to audio](https://www.bilibili.com/video/BV1AV4y187Uy/), automatically segment sentences, and automatically find the best time to answer -Formula/Image/Table Display | Can simultaneously display formulas in [TeX form and rendered form](https://user-images.githubusercontent.com/96192199/230598842-1d7fcddd-815d-40ee-af60-baf488a199df.png), support formula and code highlighting -⭐AutoGen Multi-Agent Plugin | [Plugin] Explore the emergence of multi-agent intelligence with Microsoft AutoGen! -Start Dark [Theme](https://github.com/binary-husky/gpt_academic/issues/173) | Add ```/?__theme=dark``` to the end of the browser URL to switch to the dark theme -[More LLM Model Support](https://www.bilibili.com/video/BV1wT411p7yf) | It must be great to be served by GPT3.5, GPT4, [THU ChatGLM2](https://github.com/THUDM/ChatGLM2-6B), and [Fudan MOSS](https://github.com/OpenLMLab/MOSS) at the same time, right? -⭐ChatGLM2 Fine-tuning Model | Support for loading ChatGLM2 fine-tuning models and providing ChatGLM2 fine-tuning assistant plugins -More LLM Model Access, support for [huggingface deployment](https://huggingface.co/spaces/qingxu98/gpt-academic) | Join NewBing interface (New Bing), introduce Tsinghua [JittorLLMs](https://github.com/Jittor/JittorLLMs) to support [LLaMA](https://github.com/facebookresearch/llama) and [Pangu](https://openi.org.cn/pangu/) -⭐[void-terminal](https://github.com/binary-husky/void-terminal) pip package | Use this project's all function plugins directly in Python without GUI (under development) -⭐Void Terminal Plugin | [Plugin] Schedule other plugins of this project directly in natural language -More New Feature Demonstrations (Image Generation, etc.)...... | See the end of this document ........ -
- - -- New interface (modify the LAYOUT option in `config.py` to switch between "left-right layout" and "top-bottom layout") -
- -
- - -- All buttons are dynamically generated by reading `functional.py` and can be added with custom functions to free up the clipboard -
- -
- -- Proofreading/Correction -
- -
- - - -- If the output contains formulas, they will be displayed in both tex format and rendered format for easy copying and reading. -
- -
- -- Too lazy to look at the project code? Show off the whole project directly in chatgpt's mouth -
- -
- -- Multiple large language models mixed calling (ChatGLM + OpenAI-GPT3.5 + [API2D](https://api2d.com/)-GPT4) -
- -
- -# Installation -### Installation Method I: Run directly (Windows, Linux or MacOS) - -1. Download the project -```sh -git clone --depth=1 https://github.com/binary-husky/gpt_academic.git -cd gpt_academic -``` - -2. Configure API_KEY - -In `config.py`, configure API KEY and other settings, [click here to see special network environment configuration methods](https://github.com/binary-husky/gpt_academic/issues/1). [Wiki page](https://github.com/binary-husky/gpt_academic/wiki/项目配置说明)。 - -「 The program will first check if a secret configuration file named `config_private.py` exists and use the configurations from that file to override the ones in `config.py` with the same names. If you understand this logic, we strongly recommend that you create a new configuration file named `config_private.py` next to `config.py` and move (copy) the configurations from `config.py` to `config_private.py` (only copy the configuration items you have modified). 」 - -「 Project configuration can be done via `environment variables`. The format of the environment variables can be found in the `docker-compose.yml` file or our [Wiki page](https://github.com/binary-husky/gpt_academic/wiki/项目配置说明). Configuration priority: `environment variables` > `config_private.py` > `config.py`. 」 - - -3. Install dependencies -```sh -# (Option I: If you are familiar with python, python>=3.9) Note: Use the official pip source or the Aliyun pip source. Temporary method for switching the source: python -m pip install -r requirements.txt -i https://mirrors.aliyun.com/pypi/simple/ -python -m pip install -r requirements.txt - -# (Option II: Using Anaconda) The steps are similar (https://www.bilibili.com/video/BV1rc411W7Dr): -conda create -n gptac_venv python=3.11 # Create the anaconda environment -conda activate gptac_venv # Activate the anaconda environment -python -m pip install -r requirements.txt # This step is the same as the pip installation process -``` - - -
If you need to support THU ChatGLM2, Fudan MOSS, or RWKV Runner as backends, click here to expand -

- -【Optional Step】If you need to support THU ChatGLM2 or Fudan MOSS as backends, you need to install additional dependencies (Prerequisites: Familiar with Python + Familiar with Pytorch + Sufficient computer configuration): -```sh -# 【Optional Step I】Support THU ChatGLM2. Note: If you encounter the "Call ChatGLM fail unable to load ChatGLM parameters" error, refer to the following: 1. The default installation above is for torch+cpu version. To use cuda, uninstall torch and reinstall torch+cuda; 2. If the model cannot be loaded due to insufficient local configuration, you can modify the model accuracy in request_llm/bridge_chatglm.py. Change AutoTokenizer.from_pretrained("THUDM/chatglm-6b", trust_remote_code=True) to AutoTokenizer.from_pretrained("THUDM/chatglm-6b-int4", trust_remote_code=True) -python -m pip install -r request_llms/requirements_chatglm.txt - -# 【Optional Step II】Support Fudan MOSS -python -m pip install -r request_llms/requirements_moss.txt -git clone --depth=1 https://github.com/OpenLMLab/MOSS.git request_llms/moss # When executing this line of code, make sure you are in the root directory of the project - -# 【Optional Step III】Support RWKV Runner -Refer to wiki: https://github.com/binary-husky/gpt_academic/wiki/%E9%80%82%E9%85%8DRWKV-Runner - -# 【Optional Step IV】Make sure that the AVAIL_LLM_MODELS in the config.py configuration file includes the expected models. The currently supported models are as follows (jittorllms series currently only supports the docker solution): -AVAIL_LLM_MODELS = ["gpt-3.5-turbo", "api2d-gpt-3.5-turbo", "gpt-4", "api2d-gpt-4", "chatglm", "moss"] # + ["jittorllms_rwkv", "jittorllms_pangualpha", "jittorllms_llama"] -``` - -

-
- - - -4. Run -```sh -python main.py -``` - -### Installation Method II: Use Docker - -0. Deploy all capabilities of the project (this is a large image that includes cuda and latex. Not recommended if you have slow internet speed or small hard drive) -[![fullcapacity](https://github.com/binary-husky/gpt_academic/actions/workflows/build-with-all-capacity.yml/badge.svg?branch=master)](https://github.com/binary-husky/gpt_academic/actions/workflows/build-with-all-capacity.yml) - -``` sh -# Modify docker-compose.yml, keep scheme 0 and delete other schemes. Then run: -docker-compose up -``` - -1. ChatGPT + Wenxin + Spark online models only (recommended for most people) -[![basic](https://github.com/binary-husky/gpt_academic/actions/workflows/build-without-local-llms.yml/badge.svg?branch=master)](https://github.com/binary-husky/gpt_academic/actions/workflows/build-without-local-llms.yml) -[![basiclatex](https://github.com/binary-husky/gpt_academic/actions/workflows/build-with-latex.yml/badge.svg?branch=master)](https://github.com/binary-husky/gpt_academic/actions/workflows/build-with-latex.yml) -[![basicaudio](https://github.com/binary-husky/gpt_academic/actions/workflows/build-with-audio-assistant.yml/badge.svg?branch=master)](https://github.com/binary-husky/gpt_academic/actions/workflows/build-with-audio-assistant.yml) - -``` sh -# Modify docker-compose.yml, keep scheme 1 and delete other schemes. Then run: -docker-compose up -``` - -P.S. If you need the latex plugin functionality, please see the Wiki. Also, you can directly use scheme 4 or scheme 0 to get the Latex functionality. - -2. ChatGPT + ChatGLM2 + MOSS + LLAMA2 + Intelligent Questions (requires familiarity with [Nvidia Docker](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/install-guide.html#installing-on-ubuntu-and-debian) runtime) -[![chatglm](https://github.com/binary-husky/gpt_academic/actions/workflows/build-with-chatglm.yml/badge.svg?branch=master)](https://github.com/binary-husky/gpt_academic/actions/workflows/build-with-chatglm.yml) - -``` sh -# Modify docker-compose.yml, keep scheme 2 and delete other schemes. Then run: -docker-compose up -``` - - -### Installation Method III: Other deployment methods -1. **Windows one-click running script**. -Windows users who are completely unfamiliar with the python environment can download the one-click running script from the [Release](https://github.com/binary-husky/gpt_academic/releases) to install the version without local models. -The script is contributed by [oobabooga](https://github.com/oobabooga/one-click-installers). - -2. Use third-party APIs, Azure, Wenxin, Xinghuo, etc., see [Wiki page](https://github.com/binary-husky/gpt_academic/wiki/项目配置说明) - -3. Pitfall guide for deploying on cloud servers. -Please visit [Cloud Server Remote Deployment Wiki](https://github.com/binary-husky/gpt_academic/wiki/%E4%BA%91%E6%9C%8D%E5%8A%A1%E5%99%A8%E8%BF%9C%E7%A8%8B%E9%83%A8%E7%BD%B2%E6%8C%87%E5%8D%97) - -4. Some new deployment platforms or methods - - Use Sealos [to deploy with one click](https://github.com/binary-husky/gpt_academic/issues/993). - - Use WSL2 (Windows Subsystem for Linux). Please refer to [Deployment Wiki-2](https://github.com/binary-husky/gpt_academic/wiki/%E4%BD%BF%E7%94%A8WSL2%EF%BC%88Windows-Subsystem-for-Linux-%E5%AD%90%E7%B3%BB%E7%BB%9F%EF%BC%89%E9%83%A8%E7%BD%B2) - - How to run under a subpath (such as `http://localhost/subpath`). Please visit [FastAPI Run Instructions](docs/WithFastapi.md) - - - -# Advanced Usage -### I: Customizing new convenient buttons (academic shortcuts) -Open `core_functional.py` with any text editor, add the following entry, and then restart the program. (If the button already exists, both the prefix and suffix can be modified on-the-fly without restarting the program.) -For example: -``` -"Super Translation": { - # Prefix: will be added before your input. For example, used to describe your request, such as translation, code explanation, proofreading, etc. - "Prefix": "Please translate the following paragraph into Chinese and then explain each proprietary term in the text using a markdown table:\n\n", - - # Suffix: will be added after your input. For example, used to wrap your input in quotation marks along with the prefix. - "Suffix": "", -}, -``` -
- -
- -### II: Custom function plugins -Write powerful function plugins to perform any task you desire and can't imagine. -The difficulty of writing and debugging plugins in this project is very low. As long as you have a certain knowledge of Python, you can implement your own plugin functionality by following the template we provide. -For more details, please refer to the [Function Plugin Guide](https://github.com/binary-husky/gpt_academic/wiki/%E5%87%BD%E6%95%B0%E6%8F%92%E4%BB%B6%E6%8C%87%E5%8D%97). - -# Updates -### I: Dynamics - -1. Conversation-saving feature. Call `Save the current conversation` in the function plugin area to save the current conversation as a readable and restorable HTML file. Additionally, call `Load conversation history archive` in the function plugin area (drop-down menu) to restore previous sessions. -Tip: Clicking `Load conversation history archive` without specifying a file allows you to view the cached historical HTML archive. -
- -
- -2. ⭐Latex/Arxiv paper translation feature⭐ -
- ===> - -
- -3. Void Terminal (understanding user intent from natural language input and automatically calling other plugins) - -- Step 1: Enter " Please call the plugin to translate the PDF paper, the address is https://openreview.net/pdf?id=rJl0r3R9KX" -- Step 2: Click "Void Terminal" - -
- -
- -4. Modular function design, simple interface supporting powerful functionality -
- - -
- -5. Translate and interpret other open-source projects -
- - -
- -6. Added small features that decorate [live2d](https://github.com/fghrsh/live2d_demo) (disabled by default, needs modification in `config.py`) -
- -
- -7. OpenAI image generation -
- -
- -8. OpenAI audio parsing and summarization -
- -
- -9. Latex full-text proofreading and correction -
- ===> - -
- -10. Language and theme switching -
- -
- - - -### II: Versions: -- version 3.70 (todo): Optimize the AutoGen plugin theme and design a series of derivative plugins -- version 3.60: Introduce AutoGen as the cornerstone of the new generation of plugins -- version 3.57: Support GLM3, Spark v3, Wenxin Quote v4, and fix concurrency bugs in local models -- version 3.56: Support dynamically adding basic functional buttons and a new summary PDF page -- version 3.55: Refactor the frontend interface and introduce floating windows and a menu bar -- version 3.54: Add a dynamic code interpreter (Code Interpreter) (to be improved) -- version 3.53: Support dynamically choosing different interface themes, improve stability, and resolve conflicts between multiple users -- version 3.50: Use natural language to call all function plugins of this project (Void Terminal), support plugin classification, improve UI, and design new themes -- version 3.49: Support Baidu Qianfan Platform and Wenxin Quote -- version 3.48: Support Ali Dharma Academy Tongyi Qianwen, Shanghai AI-Lab Shusheng, and Xunfei Spark -- version 3.46: Support fully hands-off real-time voice conversation -- version 3.45: Support customizing ChatGLM2 fine-tuned models -- version 3.44: Officially support Azure, optimize interface usability -- version 3.4: + Arxiv paper translation, latex paper correction functionality -- version 3.3: + Internet information integration functionality -- version 3.2: Function plugins support more parameter interfaces (conversation saving functionality, interpreting any code language + asking any combination of LLMs simultaneously) -- version 3.1: Support querying multiple GPT models simultaneously! Support API2D, support load balancing for multiple API keys -- version 3.0: Support chatglm and other small-scale LLMs -- version 2.6: Refactored plugin structure, improved interactivity, added more plugins -- version 2.5: Self-updating, fix the problem of text being too long and token overflowing when summarizing large code projects -- version 2.4: (1) Add PDF full-text translation functionality; (2) Add functionality to switch the position of the input area; (3) Add vertical layout option; (4) Optimize multi-threaded function plugins. -- version 2.3: Enhance multi-threaded interactivity -- version 2.2: Function plugin hot-reloading support -- version 2.1: Collapsible layout -- version 2.0: Introduce modular function plugins -- version 1.0: Basic functionality - -GPT Academic Developer QQ Group: `610599535` - -- Known Issues - - Some browser translation plugins interfere with the frontend operation of this software - - Official Gradio currently has many compatibility bugs, please make sure to install Gradio using `requirement.txt` - -### III: Themes -You can change the theme by modifying the `THEME` option (config.py). -1. `Chuanhu-Small-and-Beautiful` [Website](https://github.com/GaiZhenbiao/ChuanhuChatGPT/) - -### IV: Development Branches of This Project - -1. `master` branch: Main branch, stable version -2. `frontier` branch: Development branch, test version - -*** - -### V: References and Learning - - -The code references the designs of many other excellent projects, in no particular order: - -[THU ChatGLM2-6B](https://github.com/THUDM/ChatGLM2-6B) - - -[THU JittorLLMs](https://github.com/Jittor/JittorLLMs) - - -[ChatPaper](https://github.com/kaixindelele/ChatPaper) - - -[Edge-GPT](https://github.com/acheong08/EdgeGPT) - - -[ChuanhuChatGPT](https://github.com/GaiZhenbiao/ChuanhuChatGPT) - - - -# Oobabooga one-click installer: -https://github.com/oobabooga/one-click-installers - -# More: -https://github.com/gradio-app/gradio -https://github.com/fghrsh/live2d_demo diff --git a/docs/README.French.md b/docs/README.French.md deleted file mode 100644 index bf136e59dc42f88b7303efc2cd98c12f55e4bced..0000000000000000000000000000000000000000 --- a/docs/README.French.md +++ /dev/null @@ -1,356 +0,0 @@ - - - -> **Remarque** -> -> Ce README a été traduit par GPT (implémenté par le plugin de ce projet) et n'est pas fiable à 100 %. Veuillez examiner attentivement les résultats de la traduction. -> -> 7 novembre 2023 : Lors de l'installation des dépendances, veuillez choisir les versions **spécifiées** dans le fichier `requirements.txt`. Commande d'installation : `pip install -r requirements.txt`. - - -#
Optimisation académique GPT (GPT Academic)
- -**Si vous aimez ce projet, merci de lui donner une étoile ; si vous avez inventé des raccourcis ou des plugins utiles, n'hésitez pas à envoyer des demandes d'extraction !** - -Si vous aimez ce projet, veuillez lui donner une étoile. -Pour traduire ce projet dans une langue arbitraire avec GPT, lisez et exécutez [`multi_language.py`](multi_language.py) (expérimental). - -> **Remarque** -> -> 1. Veuillez noter que seuls les plugins (boutons) marqués en **surbrillance** prennent en charge la lecture de fichiers, et certains plugins se trouvent dans le **menu déroulant** de la zone des plugins. De plus, nous accueillons avec la plus haute priorité les nouvelles demandes d'extraction de plugins. -> -> 2. Les fonctionnalités de chaque fichier de ce projet sont spécifiées en détail dans [le rapport d'auto-analyse `self_analysis.md`](https://github.com/binary-husky/gpt_academic/wiki/GPT‐Academic个项目自译解报告). Vous pouvez également cliquer à tout moment sur les plugins de fonctions correspondants pour appeler GPT et générer un rapport d'auto-analyse du projet. Questions fréquemment posées [wiki](https://github.com/binary-husky/gpt_academic/wiki). [Méthode d'installation standard](#installation) | [Script d'installation en un clic](https://github.com/binary-husky/gpt_academic/releases) | [Instructions de configuration](https://github.com/binary-husky/gpt_academic/wiki/项目配置说明).. -> -> 3. Ce projet est compatible avec et recommande l'expérimentation de grands modèles de langage chinois tels que ChatGLM, etc. Prend en charge plusieurs clés API, vous pouvez les remplir dans le fichier de configuration comme `API_KEY="openai-key1,openai-key2,azure-key3,api2d-key4"`. Pour changer temporairement la clé API, entrez la clé API temporaire dans la zone de saisie, puis appuyez sur Entrée pour soumettre et activer celle-ci. - - -
- -Fonctionnalités (⭐ = fonctionnalité récemment ajoutée) | Description ---- | --- -⭐[Modèles acquis](https://github.com/binary-husky/gpt_academic/wiki/如何切换模型)! | Baidu [Qianfan](https://cloud.baidu.com/doc/WENXINWORKSHOP/s/Nlks5zkzu) et Wenxin Yiyuan, [Tongyi Qianwen](https://modelscope.cn/models/qwen/Qwen-7B-Chat/summary), Shanghai AI-Lab [Shusheng](https://github.com/InternLM/InternLM), Xunfei [Xinghuo](https://xinghuo.xfyun.cn/), [LLaMa2](https://huggingface.co/meta-llama/Llama-2-7b-chat-hf), Zhifu API, DALLE3 -Amélioration, traduction, explication du code | Correction, traduction, recherche d'erreurs de syntaxe dans les articles, explication du code -[Raccourcis personnalisés](https://www.bilibili.com/video/BV14s4y1E7jN) | Prise en charge de raccourcis personnalisés -Conception modulaire | Prise en charge de plugins puissants personnalisables, prise en charge de la [mise à jour à chaud](https://github.com/binary-husky/gpt_academic/wiki/函数插件指南) des plugins -[Analyse de programme](https://www.bilibili.com/video/BV1cj411A7VW) | [Plugin] Analyse en profondeur d'un arbre de projets Python/C/C++/Java/Lua/... d'un simple clic ou [auto-analyse](https://www.bilibili.com/video/BV1cj411A7VW) -Lecture d'articles, traduction d'articles | [Plugin] Lecture automatique des articles LaTeX/PDF et génération du résumé -Traduction complète de [LaTeX](https://www.bilibili.com/video/BV1nk4y1Y7Js/) ou amélioration de leur qualité | [Plugin] Traduction ou amélioration rapide des articles LaTeX -Génération de commentaires en masse | [Plugin] Génération facile de commentaires de fonctions -Traduction [chinois-anglais](https://www.bilibili.com/video/BV1yo4y157jV/) du Markdown | [Plugin] Avez-vous vu le [README](https://github.com/binary-husky/gpt_academic/blob/master/docs/README_EN.md) dans les cinq langues ci-dessus ? -Génération de rapports d'analyse du chat | [Plugin] Génération automatique d'un rapport récapitulatif après l'exécution du chat -[Fonction de traduction complète des articles PDF](https://www.bilibili.com/video/BV1KT411x7Wn) | [Plugin] Extraction du titre et du résumé d'un article PDF, ainsi que traduction intégrale (multithreading) -Assistant Arxiv | [Plugin] Saisissez l'URL d'un article Arxiv pour traduire automatiquement le résumé et télécharger le PDF -Correction automatique d'articles LaTeX | [Plugin] Correction de la grammaire, de l'orthographe et comparaison avec le PDF correspondant, à la manière de Grammarly -Assistant Google Scholar | [Plugin] Donner l'URL d'une page de recherche Google Scholar pour obtenir de l'aide sur l'écriture des références -Agrégation d'informations sur Internet + GPT | [Plugin] Obtenez les informations de l'Internet pour répondre aux questions à l'aide de GPT, afin que les informations ne soient jamais obsolètes -⭐Traduction détaillée des articles Arxiv ([Docker](https://github.com/binary-husky/gpt_academic/pkgs/container/gpt_academic_with_latex)) | [Plugin] Traduction de haute qualité d'articles Arxiv en un clic, le meilleur outil de traduction d'articles à ce jour -⭐[Saisie orale en temps réel](https://github.com/binary-husky/gpt_academic/blob/master/docs/use_audio.md) | [Plugin] Écoute asynchrone de l'audio, découpage automatique et recherche automatique du meilleur moment pour répondre -Affichage des formules, images, tableaux | Affichage simultané de la forme [TeX et rendue](https://user-images.githubusercontent.com/96192199/230598842-1d7fcddd-815d-40ee-af60-baf488a199df.png) des formules, prise en charge de la mise en évidence des formules et du code -⭐Plugin AutoGen multi-agents | [Plugin] Explorez les émergences intelligentes à plusieurs agents avec Microsoft AutoGen ! -Activation du [thème sombre](https://github.com/binary-husky/gpt_academic/issues/173) | Ajouter ```/?__theme=dark``` à l'URL du navigateur pour basculer vers le thème sombre -Prise en charge de plusieurs modèles LLM | Expérimentez avec GPT 3.5, GPT4, [ChatGLM2 de Tsinghua](https://github.com/THUDM/ChatGLM2-6B), [MOSS de Fudan](https://github.com/OpenLMLab/MOSS) simultanément ! -⭐Modèle ChatGLM2 fine-tuned | Chargez et utilisez un modèle fine-tuned de ChatGLM2, disponible avec un plugin d'assistance -Prise en charge de plus de modèles LLM, déploiement sur [Huggingface](https://huggingface.co/spaces/qingxu98/gpt-academic) | Ajout de l'interface de connaissance-API, support de [LLaMA](https://github.com/facebookresearch/llama) et [PanGuα](https://openi.org.cn/pangu/) -⭐Paquet pip [void-terminal](https://github.com/binary-husky/void-terminal) | Accédez à toutes les fonctions et plugins de ce projet directement depuis Python (en cours de développement) -⭐Plugin terminal du vide | [Plugin] Utilisez un langage naturel pour interagir avec les autres plugins du projet -Affichage de nouvelles fonctionnalités (génération d'images, etc.) …… | Voir à la fin de ce document …… -
- - -- Nouvelle interface (modifiez l'option LAYOUT dans `config.py` pour basculer entre la disposition "gauche-droite" et "haut-bas") -
- -
- - -- Tous les boutons sont générés dynamiquement en lisant `functional.py`, vous pouvez donc ajouter de nouvelles fonctionnalités personnalisées et libérer le presse-papiers. -
- -
- -- Retouche/correction -
- -
- - - -- If the output contains formulas, they will be displayed in both tex and rendered forms for easy copying and reading. - -
- -
- -- Don't feel like looking at the project code? Just give it to ChatGPT to show off. - -
- -
- -- Multiple large language models are mixed and used together (ChatGLM + OpenAI-GPT3.5 + [API2D](https://api2d.com/)-GPT4). - -
- -
- -# Installation -### Method I: Run directly (Windows, Linux, or MacOS) - -1. Download the project -```sh -git clone --depth=1 https://github.com/binary-husky/gpt_academic.git -cd gpt_academic -``` - -2. Configure API_KEY - -In `config.py`, configure the API KEY and other settings. [Click here to see methods for special network environment configurations](https://github.com/binary-husky/gpt_academic/issues/1). [Wiki page](https://github.com/binary-husky/gpt_academic/wiki/项目配置说明). - -「 The program will first check if there is a confidential configuration file named `config_private.py`, and use the configurations in that file to override the corresponding configurations in `config.py`. If you understand this logic, we strongly recommend creating a new configuration file named `config_private.py` right next to `config.py`, and move (copy) the configurations from `config.py` to `config_private.py` (only copy the configurations that you have modified). 」 - -「 You can also configure the project using `environment variables`. The format of the environment variables can be found in the `docker-compose.yml` file or on our [Wiki page](https://github.com/binary-husky/gpt_academic/wiki/项目配置说明). The priority of configuration reading is: `environment variables` > `config_private.py` > `config.py`. 」 - -3. Install dependencies -```sh -# (Option I: If you are familiar with Python, python>=3.9) Note: Use the official pip source or the Ali pip source. Temporary change of source method: python -m pip install -r requirements.txt -i https://mirrors.aliyun.com/pypi/simple/ -python -m pip install -r requirements.txt - -# (Option II: Use Anaconda) The steps are similar (https://www.bilibili.com/video/BV1rc411W7Dr): -conda create -n gptac_venv python=3.11 # Create an anaconda environment -conda activate gptac_venv # Activate the anaconda environment -python -m pip install -r requirements.txt # This step is the same as the pip installation step -``` - - -
If you need to support Tsinghua ChatGLM2/Fudan MOSS/RWKV as backends, click here to expand -

- -[Optional Steps] If you need to support Tsinghua ChatGLM2/Fudan MOSS as backends, you need to install additional dependencies (Prerequisites: Familiar with Python + Have used PyTorch + Sufficient computer configuration): -```sh -# [Optional Step I] Support Tsinghua ChatGLM2. Comment on this note: If you encounter the error "Call ChatGLM generated an error and cannot load the parameters of ChatGLM", refer to the following: 1: The default installation is the torch+cpu version. To use cuda, you need to uninstall torch and reinstall torch+cuda; 2: If the model cannot be loaded due to insufficient computer configuration, you can modify the model precision in request_llm/bridge_chatglm.py. Change AutoTokenizer.from_pretrained("THUDM/chatglm-6b", trust_remote_code=True) to AutoTokenizer.from_pretrained("THUDM/chatglm-6b-int4", trust_remote_code=True). -python -m pip install -r request_llms/requirements_chatglm.txt - -# [Optional Step II] Support Fudan MOSS -python -m pip install -r request_llms/requirements_moss.txt -git clone --depth=1 https://github.com/OpenLMLab/MOSS.git request_llms/moss # Note: You need to be at the root directory of the project when executing this line of code - -# [Optional Step III] Support RWKV Runner -Refer to the wiki: https://github.com/binary-husky/gpt_academic/wiki/%E9%80%82%E9%85%8DRWKV-Runner - -# [Optional Step IV] Make sure that the AVAIL_LLM_MODELS in the config.py configuration file contains the expected models. The currently supported models are as follows (jittorllms series currently only support the docker solution): -AVAIL_LLM_MODELS = ["gpt-3.5-turbo", "api2d-gpt-3.5-turbo", "gpt-4", "api2d-gpt-4", "chatglm", "moss"] # + ["jittorllms_rwkv", "jittorllms_pangualpha", "jittorllms_llama"] -``` - -

-
- - -4. Run -```sh -python main.py -``` - -### Method II: Use Docker - -0. Deploy all capabilities of the project (this is a large image that includes cuda and latex. But if you have a slow internet speed or a small hard drive, it is not recommended to use this) - -``` sh -# Modify the docker-compose.yml file, keep scheme 0 and delete the other schemes. Then run: -docker-compose up -``` - -1. ChatGPT + Wenxin Yiyu + Spark and other online models (recommended for most people) - -``` sh -# Modify the docker-compose.yml file, keep scheme 1 and delete the other schemes. Then run: -docker-compose up -``` - -NOTE: If you need Latex plugin functionality, please refer to the Wiki. Additionally, you can also use scheme 4 or scheme 0 directly to obtain Latex functionality. - -2. ChatGPT + ChatGLM2 + MOSS + LLAMA2 + Tongyi Qianwen (requires familiarity with [Nvidia Docker](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/install-guide.html#installing-on-ubuntu-and-debian) runtime) - -``` sh -# Modify the docker-compose.yml file, keep scheme 2 and delete the other schemes. Then run: -docker-compose up -``` - - -### Method III: Other deployment methods -1. **One-click run script for Windows**. -Windows users who are completely unfamiliar with the Python environment can download the one-click run script without local models from the [Release](https://github.com/binary-husky/gpt_academic/releases) section. -The script was contributed by [oobabooga](https://github.com/oobabooga/one-click-installers). - -2. Use third-party APIs, Azure, Wenxin Yiyu, Xinghuo, etc., see the [Wiki page](https://github.com/binary-husky/gpt_academic/wiki/项目配置说明). - -3. Pitfall guide for deploying on cloud servers. -Please visit the [cloud server remote deployment wiki](https://github.com/binary-husky/gpt_academic/wiki/%E4%BA%91%E6%9C%8D%E5%8A%A1%E5%99%A8%E8%BF%9C%E7%A8%8B%E9%83%A8%E7%BD%B2%E6%8C%87%E5%8D%97). - -4. Some new deployment platforms or methods - - Use Sealos [one-click deployment](https://github.com/binary-husky/gpt_academic/issues/993). - - Use WSL2 (Windows Subsystem for Linux). Please visit the [deployment wiki-2](https://github.com/binary-husky/gpt_academic/wiki/%E4%BD%BF%E7%94%A8WSL2%EF%BC%88Windows-Subsystem-for-Linux-%E5%AD%90%E7%B3%BB%E7%BB%9F%EF%BC%89%E9%83%A8%E7%BD%B2) - - How to run under a subpath (such as `http://localhost/subpath`). Please see [FastAPI running instructions](docs/WithFastapi.md) - - - -# Utilisation avancée -### I: Personnalisation des nouveaux boutons d'accès rapide (raccourcis académiques) -Ouvrez `core_functional.py` avec n'importe quel éditeur de texte, ajoutez les entrées suivantes, puis redémarrez le programme. (Si le bouton existe déjà, le préfixe et le suffixe peuvent être modifiés à chaud sans redémarrer le programme). -Par exemple: -``` -"Traduction avancée de l'anglais vers le français": { - # Préfixe, ajouté avant votre saisie. Par exemple, utilisez-le pour décrire votre demande, telle que la traduction, l'explication du code, l'amélioration, etc. - "Prefix": "Veuillez traduire le contenu suivant en français, puis expliquer chaque terme propre à la langue anglaise utilisé dans le texte à l'aide d'un tableau markdown : \n\n", - - # Suffixe, ajouté après votre saisie. Par exemple, en utilisant le préfixe, vous pouvez entourer votre contenu par des guillemets. - "Suffix": "", -}, -``` -
- -
- -### II: Personnalisation des plugins de fonction -Écrivez de puissants plugins de fonction pour accomplir toutes les tâches que vous souhaitez ou ne pouvez pas imaginer. -Le développement et le débogage de ces plugins dans ce projet sont très faciles. Tant que vous avez des connaissances de base en python, vous pouvez implémenter vos propres fonctionnalités grâce à notre modèle fourni. -Veuillez consulter le [Guide des plugins de fonction](https://github.com/binary-husky/gpt_academic/wiki/%E5%87%BD%E6%95%B0%E6%8F%92%E4%BB%B6%E6%8C%87%E5%8D%97) pour plus de détails. - - -# Mises à jour -### I: Dynamique - -1. Fonction de sauvegarde de conversation. Appelez `Enregistrer la conversation en cours` dans la zone des plugins fonctionnels pour enregistrer la conversation en cours sous la forme d'un fichier HTML lisible et récupérable. En outre, appelez `Charger les archives de conversation` dans la zone des plugins fonctionnels (menu déroulant) pour restaurer les conversations précédentes. -Astuce: Si aucun fichier n'est spécifié, cliquez directement sur `Charger les archives de conversation` pour afficher le cache des archives HTML. -
- -
- -2. ⭐ Fonction de traduction des articles Latex/Arxiv ⭐ -
- ===> - -
- -3. Terminal du néant (comprendre l'intention de l'utilisateur à partir de la saisie en langage naturel et appeler automatiquement d'autres plugins) - -- Étape 1: Saisissez "Veuillez appeler le plugin de traduction pour le document PDF, l'URL est https://openreview.net/pdf?id=rJl0r3R9KX". -- Étape 2 : Cliquez sur "Terminal du néant". - -
- -
- -4. Conception de fonctionnalités modulaires, une interface simple peut prendre en charge des fonctionnalités puissantes -
- - -
- -5. Traduction et interprétation d'autres projets open-source -
- - -
- -6. Fonctionnalités supplémentaires intégrant [live2d](https://github.com/fghrsh/live2d_demo) (désactivé par défaut, nécessite des modifications dans `config.py`) -
- -
- -7. Génération d'images par OpenAI -
- -
- -8. Analyse et résumé audio par OpenAI -
- -
- -9. Vérification et correction orthographique complète du document en Latex -
- ===> - -
- -10. Changement de langue et de thème -
- -
- - - -### II: Versions: -- version 3.70(tâche à accomplir) : Optimisation de la fonction AutoGen et création d'une série de plugins dérivés -- version 3.60 : Introduction d'AutoGen comme base des nouveaux plugins -- version 3.57 : Prise en charge de GLM3, Starlight v3, Zen v4 et correction de l'incompatibilité des modèles locaux -- version 3.56 : Possibilité d'ajouter dynamiquement des boutons de fonction de base et nouvelle page de synthèse des PDF -- version 3.55: Refonte de l'interface utilisateur avec fenêtres flottantes et barre de menu -- version 3.54 : Nouvel interpréteur de code dynamique (Code Interpreter) (à améliorer) -- version 3.53 : Possibilité de choisir dynamiquement différents thèmes d'interface, amélioration de la stabilité et résolution des problèmes de conflit entre utilisateurs multiples -- version 3.50 : Utiliser le langage naturel pour appeler toutes les fonctions du projet (Terminal du néant), prise en charge de la classification des plugins, amélioration de l'interface utilisateur, conception de nouveaux thèmes -- version 3.49 : Prise en charge de Baidu Qianfan et Xiaomi-Wenyiyan -- version 3.48 : Prise en charge d'Ali-DA, Shanghai AI-Lab-Shusheng et Xunfei Xinghuo -- version 3.46 : Prise en charge de la conversation audio temps réel sans intervention -- version 3.45 : Prise en charge de la personnalisation du modèle ChatGLM2 -- version 3.44 : Prise en charge officielle d'Azure, amélioration de l'utilisabilité de l'interface -- version 3.4 : +traduction complète des articles Arxiv, +correction des articles Latex -- version 3.3 : +fonction d'intégration d'informations Internet -- version 3.2 : Les plugins de fonction prennent en charge plus de paramètres (fonction d'enregistrement de conversation, débogage de code de n'importe quel langage + demandes d'LLM arbitraires) -- version 3.1 : Prise en charge de l'interrogation simultanée de plusieurs modèles gpt ! Prise en charge de l'API2D, répartition de charge entre plusieurs clés API -- version 3.0 : Prise en charge de chatglm et d'autres petits llm -- version 2.6 : Refonte de la structure des plugins, amélioration de l'interactivité, ajout de nouveaux plugins -- version 2.5 : Auto-mise à jour, résolution des problèmes de dépassement de longueur de texte et de jeton pendant la consolidation de grands projets de codes sources -- version 2.4 : (1) Nouvelle fonctionnalité de traduction complète des documents PDF ; (2) Nouvelle fonctionnalité de changement de position de la zone de saisie ; (3) Nouvelle option de disposition verticale ; (4) Optimisation des plugins de fonction multithreads. -- version 2.3 : Amélioration de l'interactivité multi-threads -- version 2.2 : Prise en charge du rechargement à chaud des plugins de fonction -- version 2.1 : Mise en page pliable -- version 2.0 : Introduction de plugins de fonction modulaires -- version 1.0: Fonctionnalités de base - -Groupe QQ des développeurs de GPT Academic: `610599535` - -- Problèmes connus - - Certains plugins de traduction de navigateurs peuvent nuire au fonctionnement de l'interface utilisateur de ce logiciel. - - Gradio officiel a actuellement de nombreux bugs de compatibilité. Veuillez utiliser `requirement.txt` pour installer Gradio. - -### III: Thèmes -Vous pouvez modifier le thème en modifiant l'option `THEME` (config.py). - -1. `Chuanhu-Small-and-Beautiful` [Lien](https://github.com/GaiZhenbiao/ChuanhuChatGPT/) - - -### IV: Branches de développement de ce projet - -1. Branche `master` : Branche principale, version stable -2. Branche `frontier` : Branche de développement, version de test - - -### V: Références et apprentissage - -``` -De nombreux designs de codes de projets exceptionnels ont été référencés dans le développement de ce projet, sans ordre spécifique : - -# ChatGLM2-6B de l'Université Tsinghua: -https://github.com/THUDM/ChatGLM2-6B - -# JittorLLMs de l'Université Tsinghua: -https://github.com/Jittor/JittorLLMs - -# ChatPaper : -https://github.com/kaixindelele/ChatPaper - -# Edge-GPT : -https://github.com/acheong08/EdgeGPT - -# ChuanhuChatGPT : -https://github.com/GaiZhenbiao/ChuanhuChatGPT - - - -# Oobabooga installeur en un clic : -https://github.com/oobabooga/one-click-installers - -# Plus: -https://github.com/gradio-app/gradio -https://github.com/fghrsh/live2d_demo diff --git a/docs/README.German.md b/docs/README.German.md deleted file mode 100644 index 87f7db5903d3bccabae8dbee97bfe274a1864946..0000000000000000000000000000000000000000 --- a/docs/README.German.md +++ /dev/null @@ -1,363 +0,0 @@ - - - -> **Hinweis** -> -> Dieses README wurde mithilfe der GPT-Übersetzung (durch das Plugin dieses Projekts) erstellt und ist nicht zu 100 % zuverlässig. Bitte überprüfen Sie die Übersetzungsergebnisse sorgfältig. -> -> 7. November 2023: Beim Installieren der Abhängigkeiten bitte nur die in der `requirements.txt` **angegebenen Versionen** auswählen. Installationsbefehl: `pip install -r requirements.txt`. - - -#
GPT Academic (GPT Akademisch)
- -**Wenn Ihnen dieses Projekt gefällt, geben Sie ihm bitte einen Star. Wenn Sie praktische Tastenkombinationen oder Plugins entwickelt haben, sind Pull-Anfragen willkommen!** - -Wenn Ihnen dieses Projekt gefällt, geben Sie ihm bitte einen Star. -Um dieses Projekt mit GPT in eine beliebige Sprache zu übersetzen, lesen Sie [`multi_language.py`](multi_language.py) (experimentell). - -> **Hinweis** -> -> 1. Beachten Sie bitte, dass nur die mit **hervorgehobenen** Plugins (Schaltflächen) Dateien lesen können. Einige Plugins befinden sich im **Drop-down-Menü** des Plugin-Bereichs. Außerdem freuen wir uns über jede neue Plugin-PR mit **höchster Priorität**. -> -> 2. Die Funktionen jeder Datei in diesem Projekt sind im [Selbstanalysebericht `self_analysis.md`](https://github.com/binary-husky/gpt_academic/wiki/GPT-Academic-Selbstanalysebericht) ausführlich erläutert. Sie können jederzeit auf die relevanten Funktions-Plugins klicken und GPT aufrufen, um den Selbstanalysebericht des Projekts neu zu generieren. Häufig gestellte Fragen finden Sie im [`Wiki`](https://github.com/binary-husky/gpt_academic/wiki). [Standardinstallationsmethode](#installation) | [Ein-Klick-Installationsskript](https://github.com/binary-husky/gpt_academic/releases) | [Konfigurationsanleitung](https://github.com/binary-husky/gpt_academic/wiki/Projekt-Konfigurationsanleitung). -> -> 3. Dieses Projekt ist kompatibel mit und unterstützt auch die Verwendung von inländischen Sprachmodellen wie ChatGLM. Die gleichzeitige Verwendung mehrerer API-Schlüssel ist möglich, indem Sie sie in der Konfigurationsdatei wie folgt angeben: `API_KEY="openai-key1,openai-key2,azure-key3,api2d-key4"`. Wenn Sie den `API_KEY` vorübergehend ändern möchten, geben Sie vorübergehend den temporären `API_KEY` im Eingabebereich ein und drücken Sie die Eingabetaste, um die Änderung wirksam werden zu lassen. - - - - -
- -Funktionen (⭐= Kürzlich hinzugefügte Funktion) | Beschreibung ---- | --- -⭐[Neues Modell integrieren](https://github.com/binary-husky/gpt_academic/wiki/%E5%A6%82%E4%BD%95%E5%88%87%E6%8D%A2%E6%A8%A1%E5%9E%8B)! | Baidu [Qianfan](https://cloud.baidu.com/doc/WENXINWORKSHOP/s/Nlks5zkzu) und Wenxin Yanyi, [Tongyi Qianwen](https://modelscope.cn/models/qwen/Qwen-7B-Chat/summary), Shanghai AI-Lab [Shusheng](https://github.com/InternLM/InternLM), Xunfei [Xinghuo](https://xinghuo.xfyun.cn/), [LLaMa2](https://huggingface.co/meta-llama/Llama-2-7b-chat-hf), Cognitive Graph API, DALLE3 -Verfeinern, Übersetzen, Codierung erläutern | Ein-Klick-Verfeinerung, Übersetzung, Suche nach grammatikalischen Fehlern in wissenschaftlichen Arbeiten, Erklärung von Code -[Eigene Tastenkombinationen](https://www.bilibili.com/video/BV14s4y1E7jN) definieren | Eigene Tastenkombinationen definieren -Modulare Gestaltung | Ermöglicht die Verwendung benutzerdefinierter leistungsstarker [Plugins](https://github.com/binary-husky/gpt_academic/tree/master/crazy_functions), Plugins unterstützen [Hot-Reload](https://github.com/binary-husky/gpt_academic/wiki/%E5%87%BD%E6%95%B0%E6%8F%92%E4%BB%B6%E6%8C%87%E5%8D%97) -[Programmanalyse](https://www.bilibili.com/video/BV1cj411A7VW) | [Plugin] Ermöglicht die Erstellung einer Projekthierarchie für Python/C/C++/Java/Lua/... mit nur einem Klick oder [Selbstanalyse](https://www.bilibili.com/video/BV1cj411A7VW) -Lesen von Forschungsarbeiten, Übersetzen von Forschungsarbeiten | [Plugin] Ermöglicht eine Umwandlung des gesamten Latex-/PDF-Forschungspapiers mit nur einem Klick und generiert eine Zusammenfassung -Latex-Übersetzung des vollständigen Textes, Ausbesserung | [Plugin] Ermöglicht eine Übersetzung oder Verbesserung der Latex-Forschungsarbeit mit nur einem Klick -Erzeugen von Batch-Anmerkungen | [Plugin] Erzeugt Funktionserläuterungen in Stapeln -Markdown- [En-De-Übersetzung](https://www.bilibili.com/video/BV1yo4y157jV/) | [Plugin] Haben Sie die [README](https://github.com/binary-husky/gpt_academic/blob/master/docs/README_EN.md) in den oben genannten 5 Sprachen gesehen? -Erzeugen eines Chat-Analyseberichts | [Plugin] Generiert einen zusammenfassenden Bericht nach der Ausführung -PDF-Textübersetzungsmerkmal | [Plugin] Extrahiert Titel und Zusammenfassung des PDF-Dokuments und übersetzt den vollständigen Text (mehrfädig) -Arxiv-Assistent | [Plugin] Geben Sie die URL eines Arxiv-Artikels ein, um eine Zusammenfassung zu übersetzen und die PDF-Datei herunterzuladen -Automatische Überprüfung von Latex-Artikeln | [Plugin] Überprüft die Grammatik und Rechtschreibung von Latex-Artikeln nach dem Vorbild von Grammarly und generiert eine PDF-Vergleichsdatei -Google Scholar Integration Assistant | [Plugin] Geben Sie eine beliebige URL der Google Scholar-Suchseite ein und lassen Sie GPT Ihre [Verwandten Arbeiten](https://www.bilibili.com/video/BV1GP411U7Az/) schreiben -Internetinformationsaggregation + GPT | [Plugin] Ermöglicht es GPT, Fragen durch das Durchsuchen des Internets zu beantworten und Informationen immer auf dem neuesten Stand zu halten -⭐Feine Übersetzung von Arxiv-Artikeln ([Docker](https://github.com/binary-husky/gpt_academic/pkgs/container/gpt_academic_with_latex)) | [Plugin] Übersetzt Arxiv-Artikel [mit hoher Qualität](https://www.bilibili.com/video/BV1dz4y1v77A/) mit einem Klick - das beste Übersetzungstool für wissenschaftliche Artikel -⭐[Echtzeit-Spracheingabe](https://github.com/binary-husky/gpt_academic/blob/master/docs/use_audio.md) | [Plugin] [Asynchrones Lauschen auf Audio-Eingabe](https://www.bilibili.com/video/BV1AV4y187Uy/), automatisches Zerschneiden des Textes, automatische Suche nach dem richtigen Zeitpunkt zur Beantwortung -Darstellen von Formeln/Bildern/Tabellen | Zeigt Formeln sowohl in [TEX-](https://user-images.githubusercontent.com/96192199/230598842-1d7fcddd-815d-40ee-af60-baf488a199df.png)- als auch in gerenderten Formen an, unterstützt Formeln und Code-Hervorhebung -⭐AutoGen Multi-Agent Plugin | [Plugin] Erforscht die Möglichkeiten des emergenten Verhaltens von Multi-Agent-Systemen mit Microsoft AutoGen! -Start im Dark-Theme | Um das Dark-Theme zu aktivieren, fügen Sie ```/?__theme=dark``` am Ende der URL im Browser hinzu -[Mehrsprachige LLM-Modelle](https://www.bilibili.com/video/BV1wT411p7yf) unterstützt | Es ist sicherlich beeindruckend, von GPT3.5, GPT4, [ChatGLM2 der Tsinghua University](https://github.com/THUDM/ChatGLM2-6B), [MOSS der Fudan University](https://github.com/OpenLMLab/MOSS) bedient zu werden, oder? -⭐ChatGLM2 Feinabstimmungsmodell | Unterstützt das Laden von ChatGLM2-Feinabstimmungsmodellen und bietet Unterstützung für ChatGLM2-Feinabstimmungsassistenten -Integration weiterer LLM-Modelle, Unterstützung von [Huggingface-Deployment](https://huggingface.co/spaces/qingxu98/gpt-academic) | Hinzufügen der Newbing-Schnittstelle (neues Bing), Einführung der [Jittorllms der Tsinghua University](https://github.com/Jittor/JittorLLMs) zur Unterstützung von LLaMA und PanGu Alpha -⭐[void-terminal](https://github.com/binary-husky/void-terminal) Pip-Paket | Verwenden Sie das Projekt in Python direkt, indem Sie das gesamte Funktionsplugin verwenden (in Entwicklung) -⭐Void-Terminal-Plugin | [Plugin] Verwenden Sie natürliche Sprache, um andere Funktionen dieses Projekts direkt zu steuern -Weitere Funktionen anzeigen (z. B. Bildgenerierung) …… | Siehe das Ende dieses Dokuments …… -
- - -- Neues Interface (Ändern Sie die LAYOUT-Option in der `config.py`, um zwischen "Links-Rechts-Layout" und "Oben-Unten-Layout" zu wechseln) -
- -
- - -- Alle Schaltflächen werden dynamisch aus der `functional.py` generiert und ermöglichen das beliebige Hinzufügen benutzerdefinierter Funktionen zur Befreiung der Zwischenablage. -
- -
- -- Überarbeiten/Korrigieren -
- -
- - - -- If the output contains formulas, they will be displayed in both tex format and rendering format for easy copying and reading. -
- -
- -- Don't want to look at the project code? Show off the whole project directly in chatgpt's mouth. -
- -
- -- Multiple large language models mixed calling (ChatGLM + OpenAI-GPT3.5 + [API2D](https://api2d.com/)-GPT4) -
- -
- -# Installation -### Installation Method I: Run directly (Windows, Linux or MacOS) - -1. Download the project -```sh -git clone --depth=1 https://github.com/binary-husky/gpt_academic.git -cd gpt_academic -``` - -2. Configure API_KEY - -In `config.py`, configure API KEY and other settings, [click to view special network environment configuration methods](https://github.com/binary-husky/gpt_academic/issues/1). [Wiki page](https://github.com/binary-husky/gpt_academic/wiki/Project-Configuration-Instructions). - -「 The program will first check if there is a confidential configuration file named `config_private.py` and use its configuration to override the configuration with the same name in `config.py`. If you understand this reading logic, we strongly recommend that you create a new configuration file named `config_private.py` next to `config.py` and move (copy) the configuration in `config.py` to `config_private.py` (only copy the configuration items that you have modified). 」 - -「 You can configure the project through `environment variables`. The format of environment variables can refer to the `docker-compose.yml` file or our [Wiki page](https://github.com/binary-husky/gpt_academic/wiki/Project-Configuration-Instructions). The priority of configuration reading is: `environment variables` > `config_private.py` > `config.py`. 」 - - -3. Install dependencies -```sh -# (Option I: if you are familiar with python, python>=3.9) Note: Use the official pip source or Ali pip source, temporary method to change the source: python -m pip install -r requirements.txt -i https://mirrors.aliyun.com/pypi/simple/ -python -m pip install -r requirements.txt - -# (Option II: Using Anaconda) The steps are similar (https://www.bilibili.com/video/BV1rc411W7Dr): -conda create -n gptac_venv python=3.11 # Create an anaconda environment -conda activate gptac_venv # Activate the anaconda environment -python -m pip install -r requirements.txt # This step is the same as installing with pip -``` - - -
If you need support for Tsinghua ChatGLM2/Fudan MOSS/RWKV as backend, please click to expand. -

- -[Optional] If you need to support Tsinghua ChatGLM2/Fudan MOSS as the backend, you need to install additional dependencies (Prerequisites: Familiar with Python + Have used PyTorch + Strong computer configuration): -```sh -# [Optional Step I] Support Tsinghua ChatGLM2. Tsinghua ChatGLM note: If you encounter the error "Call ChatGLM fail cannot load ChatGLM parameters normally", refer to the following: 1: The default installation above is torch+cpu version. To use cuda, you need to uninstall torch and reinstall torch+cuda; 2: If you cannot load the model due to insufficient computer configuration, you can modify the model accuracy in request_llm/bridge_chatglm.py. Change AutoTokenizer.from_pretrained("THUDM/chatglm-6b", trust_remote_code=True) to AutoTokenizer.from_pretrained("THUDM/chatglm-6b-int4", trust_remote_code=True) -python -m pip install -r request_llms/requirements_chatglm.txt - -# [Optional Step II] Support Fudan MOSS -python -m pip install -r request_llms/requirements_moss.txt -git clone --depth=1 https://github.com/OpenLMLab/MOSS.git request_llms/moss # When executing this line of code, you must be in the root path of the project - -# [Optional Step III] Support RWKV Runner -Refer to the wiki: https://github.com/binary-husky/gpt_academic/wiki/Support-RWKV-Runner - -# [Optional Step IV] Make sure the AVAIL_LLM_MODELS in config.py includes the expected models. The currently supported models are as follows (the jittorllms series only supports the docker solution at present): -AVAIL_LLM_MODELS = ["gpt-3.5-turbo", "api2d-gpt-3.5-turbo", "gpt-4", "api2d-gpt-4", "chatglm", "moss"] # + ["jittorllms_rwkv", "jittorllms_pangualpha", "jittorllms_llama"] -``` - -

-
- - - -4. Run -```sh -python main.py -``` - -### Installation Method II: Use Docker - -0. Deploy all capabilities of the project (this is a large image that includes cuda and latex. But if you have a slow internet speed or a small hard drive, it is not recommended to use this) -[![fullcapacity](https://github.com/binary-husky/gpt_academic/actions/workflows/build-with-all-capacity.yml/badge.svg?branch=master)](https://github.com/binary-husky/gpt_academic/actions/workflows/build-with-all-capacity.yml) - -``` sh -# Modify docker-compose.yml, keep solution 0 and delete other solutions. Then run: -docker-compose up -``` - -1. ChatGPT + Wenxin's words + spark and other online models (recommended for most people) -[![basic](https://github.com/binary-husky/gpt_academic/actions/workflows/build-without-local-llms.yml/badge.svg?branch=master)](https://github.com/binary-husky/gpt_academic/actions/workflows/build-without-local-llms.yml) -[![basiclatex](https://github.com/binary-husky/gpt_academic/actions/workflows/build-with-latex.yml/badge.svg?branch=master)](https://github.com/binary-husky/gpt_academic/actions/workflows/build-with-latex.yml) -[![basicaudio](https://github.com/binary-husky/gpt_academic/actions/workflows/build-with-audio-assistant.yml/badge.svg?branch=master)](https://github.com/binary-husky/gpt_academic/actions/workflows/build-with-audio-assistant.yml) - -``` sh -# Modify docker-compose.yml, keep solution 1 and delete other solutions. Then run: -docker-compose up -``` - -P.S. If you need the Latex plugin functionality, please refer to the Wiki. Also, you can directly use solution 4 or 0 to get the Latex functionality. - -2. ChatGPT + ChatGLM2 + MOSS + LLAMA2 + Thousand Questions (Requires familiarity with [Nvidia Docker](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/install-guide.html#installing-on-ubuntu-and-debian) runtime) -[![chatglm](https://github.com/binary-husky/gpt_academic/actions/workflows/build-with-chatglm.yml/badge.svg?branch=master)](https://github.com/binary-husky/gpt_academic/actions/workflows/build-with-chatglm.yml) - -``` sh -# Modify docker-compose.yml, keep solution 2 and delete other solutions. Then run: -docker-compose up -``` - - -### Installation Method III: Other Deployment Methods -1. **Windows One-Click Script**. -Windows users who are completely unfamiliar with the python environment can download the one-click script for installation without local models in the published [Release](https://github.com/binary-husky/gpt_academic/releases). -The script is contributed by [oobabooga](https://github.com/oobabooga/one-click-installers). - -2. Use third-party APIs, Azure, Wenxin's words, Spark, etc., see [Wiki page](https://github.com/binary-husky/gpt_academic/wiki/Project-Configuration-Instructions) - -3. Pit avoidance guide for cloud server remote deployment. -Please visit the [Cloud Server Remote Deployment Wiki](https://github.com/binary-husky/gpt_academic/wiki/Cloud-Server-Remote-Deployment-Guide) - -4. Some new deployment platforms or methods - - Use Sealos [one-click deployment](https://github.com/binary-husky/gpt_academic/issues/993). - - Use WSL2 (Windows Subsystem for Linux). Please visit the [deployment wiki-2](https://github.com/binary-husky/gpt_academic/wiki/Deploy-on-Windows-Subsystem-for-Linux-WSL2) - - How to run under a subpath (such as `http://localhost/subpath`). Please visit [FastAPI Running Instructions](docs/WithFastapi.md) - - - -# Fortgeschrittene Nutzung -### I: Benutzerdefinierte Tasten hinzufügen (akademische Hotkeys) -Öffnen Sie die Datei `core_functional.py` mit einem beliebigen Texteditor und fügen Sie folgenden Eintrag hinzu. Starten Sie dann das Programm neu. (Wenn die Schaltfläche bereits vorhanden ist, können sowohl das Präfix als auch das Suffix schnell geändert werden, ohne dass das Programm neu gestartet werden muss.) - -Beispiel: -``` -"Übersetzung von Englisch nach Chinesisch": { - # Präfix, wird vor Ihrer Eingabe hinzugefügt. Zum Beispiel, um Ihre Anforderungen zu beschreiben, z.B. Übersetzen, Code erklären, verbessern usw. - "Präfix": "Bitte übersetzen Sie den folgenden Abschnitt ins Chinesische und erklären Sie dann jedes Fachwort in einer Markdown-Tabelle:\n\n", - - # Suffix, wird nach Ihrer Eingabe hinzugefügt. Zum Beispiel, um Ihre Eingabe in Anführungszeichen zu setzen. - "Suffix": "", -}, -``` -
- -
- -### II: Benutzerdefinierte Funktionsplugins -Schreiben Sie leistungsstarke Funktionsplugins, um beliebige Aufgaben zu erledigen, die Sie wünschen oder nicht erwartet haben. -Das Erstellen und Debuggen von Plugins in diesem Projekt ist einfach und erfordert nur Grundkenntnisse in Python. Sie können unser bereitgestelltes Template verwenden, um Ihre eigene Plugin-Funktion zu implementieren. -Weitere Informationen finden Sie in der [Plugin-Anleitung](https://github.com/binary-husky/gpt_academic/wiki/%E5%87%BD%E6%95%B0%E6%8F%92%E4%BB%B6%E6%8C%87%E5%8D%97). - - -# Aktualisierungen -### I: Neuigkeiten - -1. Dialogspeicherungsfunktion. Rufen Sie im Funktionspluginbereich "Aktuellen Dialog speichern" auf, um den aktuellen Dialog als lesbare und wiederherstellbare HTML-Datei zu speichern. -Darüber hinaus können Sie im Funktionspluginbereich (Dropdown-Menü) "Dialoghistorie laden" aufrufen, um frühere Sitzungen wiederherzustellen. -Tipp: Wenn kein Dateiname angegeben ist, können Sie direkt auf "Dialoghistorie laden" klicken, um den Verlauf des HTML-Archivs anzuzeigen. -
- -
- -2. ⭐ Latex/Arxiv-Papierübersetzungsfunktion ⭐ -
- ===> - -
- -3. Leere Terminaloberfläche (Verständnis der Benutzerabsicht und automatischer Aufruf anderer Plugins aus natürlicher Spracheingabe) - -- Schritt 1: Geben Sie "Bitte Plugin aufrufen, um das PDF-Papier zu übersetzen, dessen Adresse https://openreview.net/pdf?id=rJl0r3R9KX ist" ein. -- Schritt 2: Klicken Sie auf "Leere Terminaloberfläche". - -
- -
- -4. Modulare Funktionsgestaltung mit einfacher Schnittstelle für leistungsstarke Funktionen -
- - -
- -5. Übersetzung und Lösung anderer Open-Source-Projekte -
- - -
- -6. Funktionen zur Dekoration von [live2d](https://github.com/fghrsh/live2d_demo) (standardmäßig deaktiviert, config.py muss geändert werden) -
- -
- -7. OpenAI-Bildgenerierung -
- -
- -8. OpenAI-Audioanalyse und Zusammenfassung -
- -
- -9. Latex-Volltextkorrektur -
- ===> - -
- -10. Sprach- und Themenwechsel -
- -
- - - -### II: Versionen: -- Version 3.70 (ausstehend): Optimierung des AutoGen-Plugin-Themas und Entwicklung einer Reihe von abgeleiteten Plugins -- Version 3.60: Einführung von AutoGen als Grundlage für neue Plugin-Generation -- Version 3.57: Unterstützung von GLM3, SparkV3, WenxinYiyanV4, Behebung von Problemen bei gleichzeitiger Verwendung von lokalen Modellen -- Version 3.56: Dynamische Hinzufügung von Basisfunktionsbuttons, neue Übersichtsseite für PDFs -- Version 3.55: Überarbeitung der Benutzeroberfläche, Hinzufügung von Schwebefenstern und Menüleiste -- Version 3.54: Neuer dynamischer Code interpretier (Code Interpreter) (unfertig) -- Version 3.53: Unterstützung für dynamische Auswahl verschiedener Oberflächenthemen, Verbesserung der Stabilität und Behebung von Mehrbenutzerkonflikten -- Version 3.50: Verwenden Sie natürliche Sprache, um alle Funktionen dieses Projekts aufzurufen (leeres Terminal), Unterstützung für Plugin-Kategorien, verbesserte Benutzeroberfläche, neue Themen -- Version 3.49: Unterstützung für Baidu Qianfan Platform und WenxinYiyan -- Version 3.48: Unterstützung für Alibaba Damo Academy Tongyi Qianwen, Shanghai AI-Lab Shusheng, Xunfei Spark -- Version 3.46: Vollständig automatisierter Echtzeit-Sprachdialog -- Version 3.45: Anpassbare ChatGLM2-Feinjustierung -- Version 3.44: Offizielle Unterstützung für Azure, Verbesserung der Benutzerfreundlichkeit der Benutzeroberfläche -- Version 3.4: Hinzufügen von Arxiv-Papierübersetzung, LaTeX-Papierkorrektur -- Version 3.3: Hinzufügen von Internet-Informationen -- Version 3.2: Funktionsplugins unterstützen weitere Parameter (Dialog speichern, beliebigen Code analysieren und nach beliebigen LLM-Kombinationen fragen) -- Version 3.1: Unterstützung für die gleichzeitige Abfrage mehrerer GPT-Modelle! Unterstützung für API-Schlüssel-Lastenausgleich -- Version 3.0: Unterstützung von ChatGLM und anderen kleinen LLMs -- Version 2.6: Neugestaltung der Plugin-Struktur, Verbesserung der Interaktivität, Hinzufügen weiterer Plugins -- Version 2.5: Auto-Update zur Lösung von Problemen mit zu langem Text oder Tokenüberschuss beim Zusammenfassen von Code -- Version 2.4: (1) Hinzufügen der Funktion zur Übersetzung des vollständigen PDF-Texts; (2) Neues Feature zum Wechseln der Position des Eingabebereichs; (3) Hinzufügen der Option für eine vertikale Ausrichtung; (4) Verbesserung der Multithreading-Funktionen von Plugins. -- Version 2.3: Verbesserte Multithreading-Interaktivität -- Version 2.2: Funktionsplugins können heiß neu geladen werden -- Version 2.1: Faltbare Layouts -- Version 2.0: Einführung modularer Funktionsplugins -- Version 1.0: Grundfunktionen - -Entwickler-QQ-Gruppe von GPT Academic: `610599535` - -- Bekannte Probleme - - Einige Browserübersetzungsplugins beeinflussen die Frontend-Ausführung dieser Software - - Die offizielle Version von Gradio hat derzeit viele Kompatibilitätsprobleme. Installieren Sie Gradio daher unbedingt über `requirement.txt`. - -### III: Themen -Sie können das Theme ändern, indem Sie die Option `THEME` (config.py) ändern. -1. `Chuanhu-Small-and-Beautiful` [Link](https://github.com/GaiZhenbiao/ChuanhuChatGPT/) - - -### IV: Entwicklungszweige dieses Projekts - -1. `master` Branch: Hauptzweig, stabile Version -2. `frontier` Branch: Entwicklungsbranch, Testversion - - -### V: Referenzen und Lernen - -``` -Der Code basiert auf dem Design anderer herausragender Projekte. Die Reihenfolge ist beliebig: - -# ChatGLM2-6B von Tsinghua: -https://github.com/THUDM/ChatGLM2-6B - -# JittorLLMs von Tsinghua: -https://github.com/Jittor/JittorLLMs - -# ChatPaper: -https://github.com/kaixindelele/ChatPaper - -# Edge-GPT: -https://github.com/acheong08/EdgeGPT - -# ChuanhuChatGPT: -https://github.com/GaiZhenbiao/ChuanhuChatGPT - - - -# Oobabooga One-Click-Installations: -https://github.com/oobabooga/one-click-installers - -# Weitere: -https://github.com/gradio-app/gradio -https://github.com/fghrsh/live2d_demo diff --git a/docs/README.Italian.md b/docs/README.Italian.md deleted file mode 100644 index f231e49ff792cd9510a3115f2a9415b9400efd5d..0000000000000000000000000000000000000000 --- a/docs/README.Italian.md +++ /dev/null @@ -1,360 +0,0 @@ - - - -> **Nota** -> -> Questo README è stato tradotto da GPT (implementato da un plugin di questo progetto) e non è al 100% affidabile, per favore valuta attentamente i risultati della traduzione. -> -> 2023.11.7: Quando installi le dipendenze, seleziona le versioni **specificate** nel file `requirements.txt`. Comando di installazione: `pip install -r requirements.txt`. - - -#
GPT Ottimizzazione Accademica (GPT Academic)
- -**Se ti piace questo progetto, per favore dagli una stella; se hai idee o plugin utili, fai una pull request!** - -Se ti piace questo progetto, dagli una stella. -Per tradurre questo progetto in qualsiasi lingua con GPT, leggi ed esegui [`multi_language.py`](multi_language.py) (sperimentale). - -> **Nota** -> -> 1. Fai attenzione che solo i plugin (pulsanti) **evidenziati** supportano la lettura dei file, alcuni plugin si trovano nel **menu a tendina** nell'area dei plugin. Inoltre, accogliamo e gestiamo con **massima priorità** qualsiasi nuovo plugin attraverso pull request. -> -> 2. Le funzioni di ogni file in questo progetto sono descritte in dettaglio nel [rapporto di traduzione automatica del progetto `self_analysis.md`](https://github.com/binary-husky/gpt_academic/wiki/GPT‐Academic项目自译解报告). Con l'iterazione della versione, puoi anche fare clic sui plugin delle funzioni rilevanti in qualsiasi momento per richiamare GPT e rigenerare il rapporto di auto-analisi del progetto. Domande frequenti [`wiki`](https://github.com/binary-husky/gpt_academic/wiki) | [Metodo di installazione standard](#installazione) | [Script di installazione one-click](https://github.com/binary-husky/gpt_academic/releases) | [Configurazione](https://github.com/binary-husky/gpt_academic/wiki/项目配置说明)。 -> -> 3. Questo progetto è compatibile e incoraggia l'uso di modelli di linguaggio di grandi dimensioni nazionali, come ChatGLM. Supporto per la coesistenza di più chiavi API, puoi compilare nel file di configurazione come `API_KEY="openai-key1,openai-key2,azure-key3,api2d-key4"`. Quando è necessario sostituire temporaneamente `API_KEY`, inserisci temporaneamente `API_KEY` nell'area di input e premi Invio per confermare. - - - - -
- -Funzionalità (⭐ = Nuove funzionalità recenti) | Descrizione ---- | --- -⭐[Integrazione di nuovi modelli](https://github.com/binary-husky/gpt_academic/wiki/%E5%A6%82%E4%BD%95%E5%88%87%E6%8D%A2%E6%A8%A1%E5%9E%8B)! | Baidu [Qianfan](https://cloud.baidu.com/doc/WENXINWORKSHOP/s/Nlks5zkzu) e [Wenxin](https://cloud.baidu.com/doc/GUIDE/5268.9) Intelligence, [Tongyi Qianwen](https://modelscope.cn/models/qwen/Qwen-7B-Chat/summary), Shanghai AI-Lab [bookbrain](https://github.com/InternLM/InternLM), Xunfei [Xinghuo](https://xinghuo.xfyun.cn/), [LLaMa2](https://huggingface.co/meta-llama/Llama-2-7b-chat-hf), Zhipu API, DALLE3 -Revisione, traduzione, spiegazione del codice | Revisione, traduzione, ricerca errori grammaticali nei documenti e spiegazione del codice con un clic -[Tasti di scelta rapida personalizzati](https://www.bilibili.com/video/BV14s4y1E7jN) | Supporta tasti di scelta rapida personalizzati -Design modulare | Supporto per plugin personalizzati potenti, i plugin supportano l'[aggiornamento in tempo reale](https://github.com/binary-husky/gpt_academic/wiki/%E5%87%BD%E6%95%B0%E6%8F%92%E4%BB%B6%E6%8C%87%E5%8D%97) -[Analisi del codice](https://www.bilibili.com/video/BV1cj411A7VW) | [Plugin] Un clic per analizzare alberi di progetti Python/C/C++/Java/Lua/... o [autoanalisi](https://www.bilibili.com/video/BV1cj411A7VW) -Lettura di documenti, traduzione di documenti | [Plugin] Un clic per interpretare documenti completi in latex/pdf e generare un riassunto -Traduzione completa di testi in Latex, revisione completa di testi in Latex | [Plugin] Un clic per tradurre o correggere documenti in latex -Generazione automatica di commenti in batch | [Plugin] Un clic per generare commenti di funzione in batch -Traduzione [cinese-inglese](https://www.bilibili.com/video/BV1yo4y157jV/) in Markdown | [Plugin] Hai visto sopra i README in 5 lingue diverse ([Inglese](https://github.com/binary-husky/gpt_academic/blob/master/docs/README_EN.md))? -Generazione di rapporti di analisi chat | [Plugin] Genera automaticamente un rapporto di sintesi dopo l'esecuzione -Funzionalità di traduzione di testo completo in PDF | [Plugin] Estrai il titolo e il riassunto dei documenti PDF e traduci tutto il testo (multithreading) -Aiutante per Arxiv | [Plugin] Inserisci l'URL dell'articolo Arxiv per tradurre riassunto e scaricare PDF in un clic -Controllo completo dei documenti in Latex | [Plugin] Rileva errori grammaticali e ortografici nei documenti in Latex simile a Grammarly + Scarica un PDF per il confronto -Assistente per Google Scholar | [Plugin] Dato qualsiasi URL della pagina di ricerca di Google Scholar, fai scrivere da GPT gli *articoli correlati* per te -Concentrazione delle informazioni di Internet + GPT | [Plugin] [Recupera informazioni da Internet](https://www.bilibili.com/video/BV1om4y127ck) utilizzando GPT per rispondere alle domande e rendi le informazioni sempre aggiornate -⭐Traduzione accurata di articoli Arxiv ([Docker](https://github.com/binary-husky/gpt_academic/pkgs/container/gpt_academic_with_latex)) | [Plugin] [Traduci articoli Arxiv ad alta qualità](https://www.bilibili.com/video/BV1dz4y1v77A/) con un clic, lo strumento di traduzione degli articoli migliore al mondo al momento -⭐[Inserimento della conversazione vocale in tempo reale](https://github.com/binary-husky/gpt_academic/blob/master/docs/use_audio.md) | [Plugin] [Ascolta l'audio](https://www.bilibili.com/video/BV1AV4y187Uy/) in modo asincrono, taglia automaticamente le frasi e trova automaticamente il momento giusto per rispondere -Visualizzazione di formule, immagini, tabelle | Mostra contemporaneamente formule in formato tex e renderizzato, supporta formule e evidenziazione del codice -⭐Plugin multi-agente AutoGen | [Plugin] Esplora le possibilità dell'emergenza intelligence multi-agente con l'aiuto di Microsoft AutoGen! -Attiva il tema scuro [qui](https://github.com/binary-husky/gpt_academic/issues/173) | Aggiungi ```/?__theme=dark``` alla fine dell'URL del browser per passare al tema scuro -Supporto di più modelli LLM | Essere servito contemporaneamente da GPT3.5, GPT4, [ChatGLM2 di Tsinghua](https://github.com/THUDM/ChatGLM2-6B), [MOSS di Fudan](https://github.com/OpenLMLab/MOSS) -⭐Modello di fine-tuning ChatGLM2 | Supporto per l'importazione del modello di fine-tuning di ChatGLM2, fornendo plug-in di assistenza per il fine tuning di ChatGLM2 -Più supporto per modelli LLM, supporto del [deploy di Huggingface](https://huggingface.co/spaces/qingxu98/gpt-academic) | Aggiungi interfaccia Newbing (Bing Translator), introduce il supporto di [JittorLLMs](https://github.com/Jittor/JittorLLMs) di Tsinghua, supporto per [LLaMA](https://github.com/facebookresearch/llama) e [Panguα](https://openi.org.cn/pangu/) -⭐Pacchetto pip [void-terminal](https://github.com/binary-husky/void-terminal) | Fornisce funzionalità di tutti i plugin di questo progetto direttamente in Python senza GUI (in sviluppo) -⭐Plugin terminale virtuale | [Plugin] Richiama altri plugin di questo progetto utilizzando linguaggio naturale -Altre nuove funzionalità (come la generazione di immagini) ... | Vedi alla fine di questo documento ... - -
- - -- Nuovo layout (modifica l'opzione LAYOUT in `config.py` per passare tra "layout sinistra / destra" e "layout sopra / sotto") -
- -
- - -- Tutti i pulsanti vengono generati dinamicamente leggendo `functional.py`, puoi aggiungere liberamente funzionalità personalizzate, liberando la clipboard -
- -
- -- Revisione / correzione -
- -
- - - -- Se l'output contiene formule, saranno visualizzate sia in formato tex che in formato renderizzato per facilitarne la copia e la lettura. -
- -
- -- Non hai voglia di guardare il codice del progetto? Mostralo direttamente al chatgpt in bocca. -
- -
- -- Chiamate miste di modelli di grandi dimensioni (ChatGLM + OpenAI-GPT3.5 + [API2D](https://api2d.com/)-GPT4) -
- -
- -# Installazione -### Metodo di installazione I: Esegui direttamente (Windows, Linux o MacOS) - -1. Scarica il progetto -```sh -git clone --depth=1 https://github.com/binary-husky/gpt_academic.git -cd gpt_academic -``` - -2. Configura l'API_KEY - -Nel file `config.py`, configura l'API KEY e altre impostazioni, [clicca qui per vedere come configurare l'API in ambienti di rete speciali](https://github.com/binary-husky/gpt_academic/issues/1) . [Pagina Wiki](https://github.com/binary-husky/gpt_academic/wiki/项目配置说明). - -「 Il programma controllerà prima se esiste un file di configurazione privata chiamato `config_private.py` e utilizzerà le configurazioni in esso contenute per sovrascrivere le configurazioni con lo stesso nome in `config.py`. Se comprendi questa logica di lettura, ti consigliamo vivamente di creare un nuovo file di configurazione chiamato `config_private.py` accanto a `config.py` e spostare (copiare) le configurazioni da `config.py` a `config_private.py` (basta copiare le voci di configurazione che hai modificato). 」 - -「 Supporta la configurazione del progetto tramite `variabili d'ambiente`, il formato di scrittura delle variabili d'ambiente è descritto nel file `docker-compose.yml` o nella nostra [pagina Wiki](https://github.com/binary-husky/gpt_academic/wiki/项目配置说明) priorità di lettura della configurazione: `variabili d'ambiente` > `config_private.py` > `config.py`. 」 - -3. Installa le dipendenze -```sh -# (Scelta I: Se familiarizzato con python, python>=3.9) Nota: Usa il repository delle fonti ufficiale di pip o Ali pip per temporaneamente cambiare la fonte: python -m pip install -r requirements.txt -i https://mirrors.aliyun.com/pypi/simple/ -python -m pip install -r requirements.txt - -# (Scelta II: Usa Anaconda) Anche in questo caso, i passaggi sono simili (https://www.bilibili.com/video/BV1rc411W7Dr): -conda create -n gptac_venv python=3.11 # Crea l'ambiente anaconda -conda activate gptac_venv # Attiva l'ambiente anaconda -python -m pip install -r requirements.txt # Questo passaggio è identico alla procedura di installazione con pip -``` - - -
Se desideri utilizzare il backend di ChatGLM2 di Tsinghua/Fudan MOSS/RWKV, fai clic per espandere -

- -[Optional] Se desideri utilizzare ChatGLM2 di Tsinghua/Fudan MOSS come backend, è necessario installare ulteriori dipendenze (Requisiti: conoscenza di Python + esperienza con Pytorch + hardware potente): -```sh -# [Optional Step I] Supporto per ChatGLM2 di Tsinghua. Note di ChatGLM di Tsinghua: Se si verifica l'errore "Call ChatGLM fail non può caricare i parametri di ChatGLM", fare riferimento a quanto segue: 1: L'installazione predefinita è la versione torch+cpu, per usare cuda è necessario disinstallare torch ed installare nuovamente la versione con torch+cuda; 2: Se il modello non può essere caricato a causa di una configurazione insufficiente, è possibile modificare la precisione del modello in request_llm/bridge_chatglm.py, sostituendo AutoTokenizer.from_pretrained("THUDM/chatglm-6b", trust_remote_code=True) con AutoTokenizer.from_pretrained("THUDM/chatglm-6b-int4", trust_remote_code=True) -python -m pip install -r request_llms/requirements_chatglm.txt - -# [Optional Step II] Supporto per Fudan MOSS -python -m pip install -r request_llms/requirements_moss.txt -git clone --depth=1 https://github.com/OpenLMLab/MOSS.git request_llms/moss # Attenzione: eseguire questo comando nella directory principale del progetto - -# [Optional Step III] Supporto per RWKV Runner -Consulta il Wiki: https://github.com/binary-husky/gpt_academic/wiki/%E9%80%82%E9%85%8DRWKV-Runner - -# [Optional Step IV] Assicurati che il file di configurazione config.py includa i modelli desiderati. Di seguito sono elencati i modelli attualmente supportati (gli llm di jittorllms supportano solo la soluzione Docker): -AVAIL_LLM_MODELS = ["gpt-3.5-turbo", "api2d-gpt-3.5-turbo", "gpt-4", "api2d-gpt-4", "chatglm", "moss", "jittorllms_rwkv", "jittorllms_pangualpha", "jittorllms_llama"] -``` - -

-
- - - -4. Esegui -```sh -python main.py -``` - -### Metodo di installazione II: Utilizzo di Docker - -0. Installa tutte le funzionalità del progetto (Questo è un'immagine di grandi dimensioni che include cuda e latex. Potrebbe non essere adatta se hai una connessione lenta o uno spazio su disco limitato) -[![fullcapacity](https://github.com/binary-husky/gpt_academic/actions/workflows/build-with-all-capacity.yml/badge.svg?branch=master)](https://github.com/binary-husky/gpt_academic/actions/workflows/build-with-all-capacity.yml) - -``` sh -# Modifica il file docker-compose.yml: mantieni solo la configurazione 0 e rimuovi le altre configurazioni. Avvia il seguente comando: -docker-compose up -``` - -1. ChatGPT + Wenxin Yiyu (Poem) + Spark, solo modelli online (Consigliato per la maggior parte delle persone) -[![basic](https://github.com/binary-husky/gpt_academic/actions/workflows/build-without-local-llms.yml/badge.svg?branch=master)](https://github.com/binary-husky/gpt_academic/actions/workflows/build-without-local-llms.yml) -[![basiclatex](https://github.com/binary-husky/gpt_academic/actions/workflows/build-with-latex.yml/badge.svg?branch=master)](https://github.com/binary-husky/gpt_academic/actions/workflows/build-with-latex.yml) -[![basicaudio](https://github.com/binary-husky/gpt_academic/actions/workflows/build-with-audio-assistant.yml/badge.svg?branch=master)](https://github.com/binary-husky/gpt_academic/actions/workflows/build-with-audio-assistant.yml) - -``` sh -# Modifica il file docker-compose.yml: mantieni solo la configurazione 1 e rimuovi le altre configurazioni. Avvia il seguente comando: -docker-compose up -``` - -P.S. Se hai bisogno del plugin LaTeX, consulta la pagina Wiki. In alternativa, puoi utilizzare le configurazioni 4 o 0 direttamente per ottenere questa funzionalità. - -2. ChatGPT + ChatGLM2 + MOSS + LLAMA2 + Tongyi Q&W (Richiede conoscenze su Nvidia Docker) -[![chatglm](https://github.com/binary-husky/gpt_academic/actions/workflows/build-with-chatglm.yml/badge.svg?branch=master)](https://github.com/binary-husky/gpt_academic/actions/workflows/build-with-chatglm.yml) - -``` sh -# Modifica il file docker-compose.yml: mantieni solo la configurazione 2 e rimuovi le altre configurazioni. Avvia il seguente comando: -docker-compose up -``` - - -### Metodo di installazione III: Altre opzioni di distribuzione -1. **Script di esecuzione con un clic per Windows**. -Se non conosci affatto l'ambiente python in Windows, puoi scaricare uno script di esecuzione con un clic dalla sezione [Release](https://github.com/binary-husky/gpt_academic/releases) per installare la versione che non richiede modelli locali. -Lo script è stato fornito da [oobabooga](https://github.com/oobabooga/one-click-installers). - -2. Utilizzo di API di terze parti, Azure, Wenxin Yiyu (Poem), Xinghuo, ecc. vedi [pagina Wiki](https://github.com/binary-husky/gpt_academic/wiki/项目配置说明) - -3. Guida all'installazione del server cloud remoto. -Visita la [pagina Wiki sull'installazione del server cloud remoto](https://github.com/binary-husky/gpt_academic/wiki/云服务器远程部署指南). - -4. Altre nuove piattaforme o metodi di distribuzione: - - Uso di Sealos per il [deployment con un clic](https://github.com/binary-husky/gpt_academic/issues/993). - - Uso di WSL2 (Windows Subsystem for Linux). Vedi [Guida all'installazione](https://github.com/binary-husky/gpt_academic/wiki/使用WSL2(Windows-Subsystem-for-Linux-子系统)部署) per maggiori informazioni. - - Funzionamento su un sotto-percorso URL (`http://localhost/subpath`). Vedi [istruzioni FastAPI](docs/WithFastapi.md) per maggiori dettagli. - - - -# Utilizzo avanzato -### I: Personalizzare nuovi pulsanti rapidi (tasti di scelta rapida accademici) -Apri `core_functional.py` con qualsiasi editor di testo e aggiungi le seguenti voci, quindi riavvia il programma. (Se il pulsante esiste già, sia il prefisso che il suffisso possono essere modificati a caldo senza la necessità di riavviare il programma.) -Ad esempio, -``` -"Traduzione avanzata Cinese-Inglese": { - # Prefisso, sarà aggiunto prima del tuo input. Ad esempio, utilizzato per descrivere la tua richiesta, come traduzione, spiegazione del codice, rifinitura, ecc. - "Prefisso": "Si prega di tradurre il seguente testo in cinese e fornire spiegazione per i termini tecnici utilizzati, utilizzando una tabella in markdown uno per uno:\n\n", - - # Suffisso, sarà aggiunto dopo il tuo input. Ad esempio, in combinazione con il prefisso, puoi circondare il tuo input con virgolette. - "Suffisso": "", -}, -``` -
- -
- -### II: Plugin di funzioni personalizzate -Scrivi potentissimi plugin di funzioni per eseguire qualsiasi compito che desideri, sia che tu lo pensi o meno. -La scrittura di plugin per questo progetto è facile e richiede solo conoscenze di base di Python. Puoi seguire il [Guida ai Plugin di Funzione](https://github.com/binary-husky/gpt_academic/wiki/%E5%87%BD%E6%95%B0%E6%8F%92%E4%BB%B6%E6%8C%87%E5%8D%97) per maggiori dettagli. - - -# Aggiornamenti -### I: Aggiornamenti - -1. Funzionalità di salvataggio della conversazione. Chiamare `Salva la conversazione corrente` nell'area del plugin per salvare la conversazione corrente come un file html leggibile e ripristinabile. -Inoltre, nella stessa area del plugin (menu a tendina) chiamare `Carica la cronologia della conversazione` per ripristinare una conversazione precedente. -Suggerimento: fare clic su `Carica la cronologia della conversazione` senza specificare un file per visualizzare la tua cronologia di archiviazione HTML. -
- -
- -2. ⭐ Funzionalità di traduzione articoli Latex/Arxiv ⭐ -
- ===> - -
- -3. Terminale vuoto (Comprensione dell'intento dell'utente dai testi liberi + Chiamata automatica di altri plugin) - -- Passaggio 1: Digitare "Chiamare il plugin per tradurre un documento PDF, l'indirizzo è https://openreview.net/pdf?id=rJl0r3R9KX" -- Passaggio 2: Fare clic su "Terminale vuoto" - -
- -
- -4. Design modulare, interfacce semplici che supportano funzionalità potenti -
- - -
- -5. Traduzione e interpretazione di altri progetti open source -
- - -
- -6. Funzionalità leggera per [live2d](https://github.com/fghrsh/live2d_demo) (disabilitata per impostazione predefinita, richiede modifica di `config.py`) -
- -
- -7. Generazione di immagini di OpenAI -
- -
- -8. Elaborazione e riepilogo audio di OpenAI -
- -
- -9. Correzione totale del testo di Latex -
- ===> - -
- -10. Cambio linguaggio e tema -
- -
- - -### II: Versioni: -- versione 3.70 (todo): Ottimizzazione della visualizzazione del tema AutoGen e sviluppo di una serie di plugin correlati. -- versione 3.60: Introduzione di AutoGen come fondamento per i plugin della nuova generazione. -- versione 3.57: Supporto per GLM3, StarFirev3, Wenxin-yiyanv4 e correzione di bug sulla concorrenza dell'uso di modelli locali. -- versione 3.56: Possibilità di aggiungere dinamicamente pulsanti per funzionalità di base e nuova pagina di riepilogo del PDF. -- versione 3.55: Ristrutturazione dell'interfaccia utente, introduzione di finestre fluttuanti e barre dei menu. -- versione 3.54: Nuovo interprete di codice dinamico (Code Interpreter) (da perfezionare). -- versione 3.53: Possibilità di selezionare dinamicamente diversi temi dell'interfaccia utente, miglioramento della stabilità e risoluzione dei conflitti tra utenti multipli. -- versione 3.50: Utilizzo del linguaggio naturale per chiamare tutte le funzioni dei plugin di questo progetto (Terminale vuoto), supporto per la classificazione dei plugin, miglioramento dell'interfaccia utente e design di nuovi temi. -- versione 3.49: Supporto per la piattaforma Baidu Qianfan e Wenxin-yiyan. -- versione 3.48: Supporto per Alibaba DAXI 所见即所答, Shanghai AI-Lab Shusheng, Xunfei StarFire. -- versione 3.46: Supporto per la chat vocale in tempo reale completamente automatica. -- versione 3.45: Supporto personalizzato per il micro-aggiustamento del modello ChatGLM2. -- versione 3.44: Supporto ufficiale per Azure, miglioramento dell'usabilità dell'interfaccia. -- versione 3.4: + Funzionalità di traduzione di documenti arXiv e correzione di documenti LaTeX. -- versione 3.3: + Funzionalità di sintesi delle informazioni su Internet. -- versione 3.2: Il plugin di funzione supporta più interfacce dei parametri (funzionalità di salvataggio della conversazione, interpretazione di codici in qualsiasi linguaggio contemporaneamente, interrogare qualsiasi combinazione di LLM). -- versione 3.1: Supporto per l'interrogazione simultanea di più modelli GPT! Supporto per api2d, equilibrio del carico con più apikey. -- versione 3.0: Supporto per chatglm e altri piccoli llm. -- versione 2.6: Rielaborazione della struttura del plugin, miglioramento dell'interattività, aggiunta di ulteriori plugin. -- versione 2.5: Aggiornamento automatico, risoluzione del problema della lunghezza eccessiva del testo durante il riepilogo di grandi blocchi di codice che supera i token. -- versione 2.4: (1) Nuova funzionalità di traduzione di documenti PDF; (2) Nuova funzionalità di scambio delle posizioni tra l'area di input (input area); (3) Nuova opzione di layout verticale; (4) Ottimizzazione del plugin a threading multiplo. -- versione 2.3: Miglioramento dell'interattività con threading multiplo. -- versione 2.2: Supporto per il plugin con ricarica a caldo. -- versione 2.1: Layout pieghevole. -- versione 2.0: Introduzione di plugin modulari. -- versione 1.0: Funzioni di base - -GPT Academic Developer QQ Group: `610599535` - -- Problemi noti - - Alcuni plug-in di traduzione del browser possono interferire con il funzionamento del frontend di questo software - - L'app Gradio ufficiale ha molti bug di compatibilità, si consiglia di installare Gradio tramite `requirement.txt` - -### III: Temi -Il tema può essere modificato modificando l'opzione `THEME` (config.py) -1. `Chuanhu-Small-and-Beautiful` [Website](https://github.com/GaiZhenbiao/ChuanhuChatGPT/) - - -### IV: Branch di Sviluppo di questo progetto - -1. `master` branch: branch principale, versione stabile -2. `frontier` branch: branch di sviluppo, versione di test - - -### V: Riferimenti e Risorse di Apprendimento - -``` -Nel codice sono state utilizzate diverse idee dagli altri progetti, senza un ordine specifico: - -# ChatGLM2-6B di Tsinghua: -https://github.com/THUDM/ChatGLM2-6B - -# JittorLLMs di Tsinghua: -https://github.com/Jittor/JittorLLMs - -# ChatPaper: -https://github.com/kaixindelele/ChatPaper - -# Edge-GPT: -https://github.com/acheong08/EdgeGPT - -# ChuanhuChatGPT: -https://github.com/GaiZhenbiao/ChuanhuChatGPT - - - -# Installazione con un solo clic di Oobabooga: -https://github.com/oobabooga/one-click-installers - -# Altre risorse: -https://github.com/gradio-app/gradio -https://github.com/fghrsh/live2d_demo diff --git a/docs/README.Japanese.md b/docs/README.Japanese.md deleted file mode 100644 index 13cbdede24b3c716a0961b72331259ed081aab2b..0000000000000000000000000000000000000000 --- a/docs/README.Japanese.md +++ /dev/null @@ -1,344 +0,0 @@ - - - -> **注意** -> -> 此READMEはGPTによる翻訳で生成されました(このプロジェクトのプラグインによって実装されています)、翻訳結果は100%正確ではないため、注意してください。 -> -> 2023年11月7日: 依存関係をインストールする際は、`requirements.txt`で**指定されたバージョン**を選択してください。 インストールコマンド: `pip install -r requirements.txt`。 - - -#
GPT 学術最適化 (GPT Academic)
- -**このプロジェクトが気に入った場合は、Starを付けてください。また、便利なショートカットキーまたはプラグインを作成した場合は、プルリクエストを歓迎します!** -GPTを使用してこのプロジェクトを任意の言語に翻訳するには、[`multi_language.py`](multi_language.py)を読み込んで実行します(実験的な機能)。 - -> **注意** -> -> 1. **強調された** プラグイン(ボタン)のみがファイルを読み込むことができることに注意してください。一部のプラグインは、プラグインエリアのドロップダウンメニューにあります。また、新しいプラグインのPRを歓迎し、最優先で対応します。 -> -> 2. このプロジェクトの各ファイルの機能は、[自己分析レポート`self_analysis.md`](https://github.com/binary-husky/gpt_academic/wiki/GPT‐Academic%E9%A1%B9%E7%9B%AE%E8%87%AA%E8%AF%91%E8%A7%A3%E5%A0%82)で詳しく説明されています。バージョンが進化するにつれて、関連する関数プラグインをクリックして、プロジェクトの自己分析レポートをGPTで再生成することもできます。よくある質問については、[`wiki`](https://github.com/binary-husky/gpt_academic/wiki)をご覧ください。[標準的なインストール方法](#installation) | [ワンクリックインストールスクリプト](https://github.com/binary-husky/gpt_academic/releases) | [構成の説明](https://github.com/binary-husky/gpt_academic/wiki/Project-Configuration-Explain)。 -> -> 3. このプロジェクトは、[ChatGLM](https://www.chatglm.dev/)などの中国製の大規模言語モデルも互換性があり、試してみることを推奨しています。複数のAPIキーを共存させることができ、設定ファイルに`API_KEY="openai-key1,openai-key2,azure-key3,api2d-key4"`のように記入できます。`API_KEY`を一時的に変更する必要がある場合は、入力エリアに一時的な`API_KEY`を入力し、Enterキーを押して提出すると有効になります。 - - - - -
- -機能(⭐= 最近追加された機能) | 説明 ---- | --- -⭐[新しいモデルの追加](https://github.com/binary-husky/gpt_academic/wiki/%E5%A6%82%E4%BD%95%E5%88%87%E6%8D%A2%E6%A8%A1%E5%9E%8B)! | Baidu [Qianfan](https://cloud.baidu.com/doc/WENXINWORKSHOP/s/Nlks5zkzu)とWenxin Yiyu, [Tongyi Qianwen](https://modelscope.cn/models/qwen/Qwen-7B-Chat/summary), Shanghai AI-Lab [Shusheng](https://github.com/InternLM/InternLM), Xunfei [Xinghuo](https://xinghuo.xfyun.cn/), [LLaMa2](https://huggingface.co/meta-llama/Llama-2-7b-chat-hf), Zhantu API, DALLE3 -校正、翻訳、コード解説 | 一括校正、翻訳、論文の文法エラーの検索、コードの解説 -[カスタムショートカットキー](https://www.bilibili.com/video/BV14s4y1E7jN) | カスタムショートカットキーのサポート -モジュール化された設計 | カスタムでパワフルな[プラグイン](https://github.com/binary-husky/gpt_academic/tree/master/crazy_functions)のサポート、プラグインの[ホットリロード](https://github.com/binary-husky/gpt_academic/wiki/%E5%87%BD%E6%95%B0%E6%8F%92%E4%BB%B6%E6%8C%87%E5%8D%97) -[プログラム解析](https://www.bilibili.com/video/BV1cj411A7VW) | [プラグイン] Python/C/C++/Java/Lua/...のプロジェクトツリーを簡単に解析するか、[自己解析](https://www.bilibili.com/video/BV1cj411A7VW) -論文の読み込み、[翻訳](https://www.bilibili.com/video/BV1KT411x7Wn) | [プラグイン] LaTeX/PDFの論文全文を翻訳して要約を作成する -LaTeX全文の[翻訳](https://www.bilibili.com/video/BV1nk4y1Y7Js/)、[校正](https://www.bilibili.com/video/BV1FT411H7c5/) | [プラグイン] LaTeX論文を翻訳や校正する -一括コメント生成 | [プラグイン] 関数コメントを一括生成する -Markdownの[日英翻訳](https://www.bilibili.com/video/BV1yo4y157jV/) | [プラグイン] 5つの言語([英語](https://github.com/binary-husky/gpt_academic/blob/master/docs/README_EN.md)など)のREADMEをご覧になりましたか? -チャット分析レポートの生成 | [プラグイン] 実行後にサマリーレポートを自動生成する -[PDF論文全文の翻訳機能](https://www.bilibili.com/video/BV1KT411x7Wn) | [プラグイン] PDF論文のタイトルと要約を抽出し、全文を翻訳する(マルチスレッド) -[Arxivアシスタント](https://www.bilibili.com/video/BV1LM4y1279X) | [プラグイン] arxiv論文のURLを入力すると、要約を翻訳してPDFをダウンロードできます -LaTeX論文の一括校正 | [プラグイン] Grammarlyのように、LaTeX論文の文法とスペルを修正して対照PDFを出力する -[Google Scholar統合アシスタント](https://www.bilibili.com/video/BV19L411U7ia) | [プラグイン] 任意のGoogle Scholar検索ページのURLを指定して、関連資料をGPTに書かせることができます -インターネット情報の集約+GPT | [プラグイン] インターネットから情報を取得して質問に答え、情報が常に最新になるようにします -⭐Arxiv論文の詳細な翻訳 ([Docker](https://github.com/binary-husky/gpt_academic/pkgs/container/gpt_academic_with_latex)) | [プラグイン] arxiv論文を超高品質で翻訳します。最高の論文翻訳ツールです -⭐[リアルタイム音声入力](https://github.com/binary-husky/gpt_academic/blob/master/docs/use_audio.md) | [プラグイン] 非同期[音声をリッスン(https://www.bilibili.com/video/BV1AV4y187Uy/)し、自動で文章を区切り、回答のタイミングを自動で探します -公式/画像/表の表示 | 公式の[tex形式とレンダリング形式](https://user-images.githubusercontent.com/96192199/230598842-1d7fcddd-815d-40ee-af60-baf488a199df.png)を同時に表示し、公式とコードのハイライトをサポートします -⭐AutoGenマルチエージェントプラグイン | [プラグイン] Microsoft AutoGenを利用して、マルチエージェントのインテリジェントなエマージェンスを探索します -ダーク[テーマ](https://github.com/binary-husky/gpt_academic/issues/173)を起動 | ブラウザのURLに```/?__theme=dark```を追加すると、ダークテーマに切り替えられます -[複数のLLMモデル](https://www.bilibili.com/video/BV1wT411p7yf)のサポート | GPT3.5、GPT4、[Tsinghua ChatGLM2](https://github.com/THUDM/ChatGLM2-6B)、[Fudan MOSS](https://github.com/OpenLMLab/MOSS)などを同時に使えるのは最高の感じですよね? -⭐ChatGLM2ファインチューニングモデル | ChatGLM2ファインチューニングモデルをロードして使用することができ、ChatGLM2ファインチューニングの補助プラグインが用意されています -さらなるLLMモデルの導入、[HuggingFaceデプロイのサポート](https://huggingface.co/spaces/qingxu98/gpt-academic) | Newbingインターフェース(新しいBing)の追加、Tsinghua [Jittorllms](https://github.com/Jittor/JittorLLMs)の導入、[LLaMA](https://github.com/facebookresearch/llama)および[盤古α](https://openi.org.cn/pangu/)のサポート -⭐[void-terminal](https://github.com/binary-husky/void-terminal) pipパッケージ | GUIから独立して、Pythonから直接このプロジェクトのすべての関数プラグインを呼び出せます(開発中) -⭐Void Terminalプラグイン | [プラグイン] 自然言語で、このプロジェクトの他のプラグインを直接実行します -その他の新機能の紹介(画像生成など)...... | 末尾をご覧ください ...... -
- - - -- もし出力に数式が含まれている場合、TeX形式とレンダリング形式の両方で表示されます。これにより、コピーと読み取りが容易になります。 - -
- -
- -- プロジェクトのコードを見るのがめんどくさい?プロジェクト全体を`chatgpt`に広報口頭発表してもらえるよ - -
- -
- -- 異なる言語モデルの組み合わせ呼び出し(ChatGLM + OpenAI-GPT3.5 + [API2D](https://api2d.com/)-GPT4) - -
- -
- -# インストール -### 方法I:直接実行(Windows、Linux、またはMacOS) - -1. プロジェクトをダウンロード -```sh -git clone --depth=1 https://github.com/binary-husky/gpt_academic.git -cd gpt_academic -``` - -2. APIキーを設定する - -`config.py`でAPIキーやその他の設定を設定します。特殊なネットワーク環境の設定方法については、[こちらをクリックして確認してください](https://github.com/binary-husky/gpt_academic/issues/1)。[Wikiページ](https://github.com/binary-husky/gpt_academic/wiki/Getting-Started)も参照してください。 - -「プログラムは、`config.py`と同じ場所にある`config_private.py`という名前のプライベート設定ファイルが存在するかどうかを優先的にチェックし、同じ名前の設定をコピーします。この読み込みロジックを理解できる場合、`config.py`の横に`config_private.py`という名前の新しい設定ファイルを作成し、`config.py`の設定を転送(コピー)することを強くお勧めします(変更した設定項目だけをコピーします)。」 - -「プロジェクトを環境変数で設定することもサポートしています。環境変数の書式は、`docker-compose.yml`ファイルや[Wikiページ](https://github.com/binary-husky/gpt_academic/wiki/Getting-Started)を参考にしてください。設定の優先度は、`環境変数` > `config_private.py` > `config.py`の順です。」 - -3. 依存関係をインストールする -```sh -# (オプションI:Pythonに詳しい場合、Python 3.9以上)注:公式のpipソースまたは阿里pipソースを使用し、一時的なソースの変更方法は、python -m pip install -r requirements.txt -i https://mirrors.aliyun.com/pypi/simple/です。 -python -m pip install -r requirements.txt - -# (オプションII:Anacondaを使用する場合)手順は同様です (https://www.bilibili.com/video/BV1rc411W7Dr): -conda create -n gptac_venv python=3.11 # Anaconda環境を作成 -conda activate gptac_venv # Anaconda環境をアクティベート -python -m pip install -r requirements.txt # この手順はpipのインストール手順と同じです -``` - -
清華ChatGLM2/復旦MOSS/RWKVがバックエンドとしてサポートされている場合、ここをクリックして展開してください -

- -【オプションステップ】 清華ChatGLM2/復旦MOSSをバックエンドとしてサポートする場合は、さらに追加の依存関係をインストールする必要があります(前提条件:Pythonに精通していて、PytorchとNVIDIA GPUを使用したことがあり、十分なコンピュータの構成を持っていること): - -```sh -# 【オプションステップI】 清華ChatGLM2のサポートを追加する。 清華ChatGLM2に関する注意点: "Call ChatGLM fail 不能正常加载ChatGLM的参数" のエラーが発生した場合、次の手順を参照してください。 1: デフォルトでインストールされているのはtorch+cpu版です。CUDAを使用するにはtorchをアンインストールしてtorch+cuda版を再インストールする必要があります。 2: モデルをロードできない場合は、request_llm/bridge_chatglm.pyのモデル精度を変更できます。AutoTokenizer.from_pretrained("THUDM/chatglm-6b", trust_remote_code=True)をAutoTokenizer.from_pretrained("THUDM/chatglm-6b-int4", trust_remote_code=True)に変更します。 -python -m pip install -r request_llms/requirements_chatglm.txt - -# 【オプションステップII】 復旦MOSSのサポートを追加する -python -m pip install -r request_llms/requirements_moss.txt -git clone --depth=1 https://github.com/OpenLMLab/MOSS.git request_llms/moss # このコマンドを実行するときは、プロジェクトのルートパスである必要があります。 - -# 【オプションステップIII】 RWKV Runnerのサポートを追加する -Wikiを参照してください: https://github.com/binary-husky/gpt_academic/wiki/%E9%80%82%E9%85%8DRWKV-Runner - -# 【オプションステップIV】 config.py設定ファイルに、以下のすべてのモデルが含まれていることを確認します。以下のモデルがすべてサポートされています(jittorllmsはDockerのみサポートされています): -AVAIL_LLM_MODELS = ["gpt-3.5-turbo", "api2d-gpt-3.5-turbo", "gpt-4", "api2d-gpt-4", "chatglm", "moss"] # + ["jittorllms_rwkv", "jittorllms_pangualpha", "jittorllms_llama"] -``` - -

-
- -4. 実行する -```sh -python main.py -``` - -### 方法II:Dockerを使用する - -0. プロジェクトのフルスケールデプロイ(これは、CUDAとLaTeXを含む大規模なイメージですが、ネットワーク速度が遅いまたはディスク容量が小さい場合はおすすめしません) -[![fullcapacity](https://github.com/binary-husky/gpt_academic/actions/workflows/build-with-all-capacity.yml/badge.svg?branch=master)](https://github.com/binary-husky/gpt_academic/actions/workflows/build-with-all-capacity.yml) - -```sh -# docker-compose.ymlを編集し、スキーム0を残し、その他を削除してから実行する: -docker-compose up -``` - -1. ChatGPT + 文心一言 + sparkなどのオンラインモデルのみを含む(ほとんどの人におすすめ) -[![basic](https://github.com/binary-husky/gpt_academic/actions/workflows/build-without-local-llms.yml/badge.svg?branch=master)](https://github.com/binary-husky/gpt_academic/actions/workflows/build-without-local-llms.yml) -[![basiclatex](https://github.com/binary-husky/gpt_academic/actions/workflows/build-with-latex.yml/badge.svg?branch=master)](https://github.com/binary-husky/gpt_academic/actions/workflows/build-with-latex.yml) -[![basicaudio](https://github.com/binary-husky/gpt_academic/actions/workflows/build-with-audio-assistant.yml/badge.svg?branch=master)](https://github.com/binary-husky/gpt_academic/actions/workflows/build-with-audio-assistant.yml) - -```sh -# docker-compose.ymlを編集し、スキーム1を残し、その他を削除してから実行する: -docker-compose up -``` - -P.S. LaTeXプラグインの機能を使用する場合は、Wikiを参照してください。また、LaTeX機能を使用するためには、スキーム4またはスキーム0を直接使用することもできます。 - -2. ChatGPT + ChatGLM2 + MOSS + LLAMA2 + 通慧千問(Nvidia Dockerに精通している場合) -[![chatglm](https://github.com/binary-husky/gpt_academic/actions/workflows/build-with-chatglm.yml/badge.svg?branch=master)](https://github.com/binary-husky/gpt_academic/actions/workflows/build-with-chatglm.yml) - -```sh -# docker-compose.ymlを編集し、スキーム2を残し、その他を削除してから実行する: -docker-compose up -``` - - -### 方法III:その他のデプロイメントオプション - -1. **Windowsのワンクリック実行スクリプト**。 -Python環境に詳しくないWindowsユーザーは、[リリース](https://github.com/binary-husky/gpt_academic/releases)からワンクリック実行スクリプトをダウンロードして、ローカルモデルのないバージョンをインストールできます。 -スクリプトの貢献者は[oobabooga](https://github.com/oobabooga/one-click-installers)です。 - -2. 第三者のAPI、Azureなど、文心一言、星火などを使用するには、[Wikiページ](https://github.com/binary-husky/gpt_academic/wiki/Getting-Started)を参照してください。 - -3. クラウドサーバーでのリモートデプロイの回避策ガイドを参照してください。 -[クラウドサーバーでのリモートデプロイの回避策ガイドwiki](https://github.com/binary-husky/gpt_academic/wiki/Getting-Started#%E4%BA%91%E3%82%B5%E3%83%BC%E3%83%90%E3%83%BC%E3%83%AA%E3%82%BC%E3%83%A0%E3%82%B5%E3%83%BC%E3%83%90%E3%81%AE%E3%83%AA%E3%83%A2%E3%83%BC%E3%83%88%E3%83%87%E3%83%97%E3%83%AD%E3%82%A4%E6%8C%87%E5%8D%97) - -4. その他の新しいデプロイプラットフォームや方法 - - Sealosを使用した[ワンクリックデプロイ](https://github.com/binary-husky/gpt_academic/issues/993) - - WSL2(Windows Subsystem for Linux)の使用方法については、[デプロイwiki-2](https://github.com/binary-husky/gpt_academic/wiki/Getting-Started)を参照してください。 - - サブパス(例:`http://localhost/subpath`)でFastAPIを実行する方法については、[FastAPIの実行方法](docs/WithFastapi.md)を参照してください。 - - - -# 高度な使用法 -### I:カスタムショートカットボタンの作成(学術的なショートカットキー) -テキストエディタで`core_functional.py`を開き、次の項目を追加し、プログラムを再起動します。(ボタンが存在する場合、プレフィックスとサフィックスはホット変更に対応しており、プログラムを再起動せずに有効にすることができます。) -例: -``` -"超级英译中": { - # プレフィックス、入力の前に追加されます。例えば、要求を記述するために使用されます。翻訳、コードの解説、校正など - "プレフィックス": "下記の内容を中国語に翻訳し、専門用語を一つずつマークダウンテーブルで解説してください:\n\n"、 - - # サフィックス、入力の後に追加されます。プレフィックスと一緒に使用して、入力内容を引用符で囲むことができます。 - "サフィックス": ""、 -}、 -``` -
- -
- -### II:関数プラグインのカスタマイズ -自分の望む任意のタスクを実行するために、強力な関数プラグインを作成できます。 -このプロジェクトのプラグインの作成とデバッグの難易度は非常に低く、一定のPythonの基礎知識があれば、提供されたテンプレートを参考に自分自身のプラグイン機能を実装することができます。 -詳細については、[関数プラグインガイド](https://github.com/binary-husky/gpt_academic/wiki/%E5%87%BD%E6%95%B0%E6%8F%92%E4%BB%B6%E6%8C%87%E5%8D%97)を参照してください。 - - -# 更新 -### I:ダイナミック - -1. 会話の保存機能。プラグインエリアで `Save Current Conversation` を呼び出すだけで、現在の会話を読み取り可能で復旧可能なhtmlファイルとして保存できます。 -また、プラグインエリア(ドロップダウンメニュー)で `Load Conversation History Archive` を呼び出すことで、以前の会話を復元できます。 -ヒント:ファイルを指定せずに `Load Conversation History Archive` をクリックすると、履歴のhtmlアーカイブのキャッシュを表示することができます。 -
- -
- -2. ⭐Latex/Arxiv論文の翻訳機能⭐ -
- ===> - -
- -3. ゼロのターミナル(自然言語入力からユーザの意図を理解+他のプラグインを自動的に呼び出す) - -- ステップ1:「プラグインのPDF論文の翻訳を呼び出してください、アドレスはhttps://openreview.net/pdf?id=rJl0r3R9KX」と入力します。 -- ステップ2:「Zero Terminal」をクリックします。 - -
- -
- -4. モジュール化された機能設計、シンプルなインターフェイスで強力な機能をサポートする -
- - -
- -5. 他のオープンソースプロジェクトの翻訳 -
- - -
- -6. [live2d](https://github.com/fghrsh/live2d_demo)のデコレーション機能(デフォルトでは無効で、`config.py`を変更する必要があります) -
- -
- -7. OpenAI画像生成 -
- -
- -8. OpenAIオーディオ解析と要約 -
- -
- -9. Latex全体の校正と修正 -
- ===> - -
- -10. 言語、テーマの切り替え -
- -
- - - -### II:バージョン: -- version 3.70(todo): AutoGenプラグインのテーマを最適化し、一連の派生プラグインを設計する -- version 3.60: AutoGenを次世代プラグインの基盤として導入 -- version 3.57: GLM3、星火v3、文心一言v4をサポート、ローカルモデルの並行バグを修正 -- version 3.56: 基本機能ボタンを動的に追加、新しい報告書PDF集約ページ -- version 3.55: フロントエンドのデザインを再構築し、浮動ウィンドウとメニューバーを導入 -- version 3.54: 新しい動的コードインタプリタ(Code Interpreter)の追加(未完成) -- version 3.53: 異なるテーマを動的に選択できるように、安定性の向上と複数ユーザの競合問題の解決 -- version 3.50: 自然言語でこのプロジェクトのすべての関数プラグインを呼び出すことができるようになりました(ゼロのターミナル)プラグインの分類をサポートし、UIを改善し、新しいテーマを設計 -- version 3.49: Baidu Qianfanプラットフォームと文心一言をサポート -- version 3.48: Alibaba DAMO Academy Tongyi Qianwen、Shanghai AI-Lab Shusheng、Xunfei Xinghuoをサポート -- version 3.46: 完全なオートモードのリアルタイム音声対話をサポート -- version 3.45: カスタムChatGLM2ファインチューニングモデルをサポート -- version 3.44: 公式にAzureをサポート、UIの使いやすさを最適化 -- version 3.4: +arxiv論文の翻訳、latex論文の校閲機能 -- version 3.3: +インターネット情報の総合機能 -- version 3.2: 関数プラグインがさらに多くのパラメータインターフェースをサポート(会話の保存機能、任意の言語のコードの解釈、同時に任意のLLMの組み合わせを尋ねる) -- version 3.1: 複数のgptモデルに同時に質問できるようにサポートされました! api2dをサポートし、複数のapikeyの負荷分散をサポートしました -- version 3.0: chatglmと他の小さなllmのサポート -- version 2.6: プラグインの構造を再構築し、対話性を高め、より多くのプラグインを追加しました -- version 2.5: 自己更新、ソースコード全体の要約時のテキストの長さ、トークンのオーバーフローの問題を解決しました -- version 2.4: (1)新しいPDF全文翻訳機能を追加しました。(2)入力エリアの位置を切り替えるための新しい機能を追加しました。(3)垂直レイアウトオプションを追加しました。(4)マルチスレッド関数プラグインを最適化しました。 -- version 2.3: マルチスレッドの対話を強化しました -- version 2.2: 関数プラグインのホットリロードをサポート -- version 2.1: 折りたたみ式のレイアウト -- version 2.0: モジュール化された関数プラグインの導入 -- version 1.0: 基本機能 - -GPT Academic開発者QQグループ:`610599535` - --既知の問題 - - 一部のブラウザ翻訳プラグインがこのソフトウェアのフロントエンドの実行を妨げる - - 公式Gradioには互換性の問題があり、必ず`requirement.txt`を使用してGradioをインストールしてください - -### III:テーマ -`THEME`オプション(`config.py`)を変更することで、テーマを変更できます -1. `Chuanhu-Small-and-Beautiful` [リンク](https://github.com/GaiZhenbiao/ChuanhuChatGPT/) - - -### IV:本プロジェクトの開発ブランチ - -1. `master`ブランチ:メインブランチ、安定版 -2. `frontier`ブランチ:開発ブランチ、テスト版 - - -### V:参考と学習 - -``` -コードの中には、他の優れたプロジェクトのデザインを参考にしたものが多く含まれています。順序は問いません: - -# 清華ChatGLM2-6B: -https://github.com/THUDM/ChatGLM2-6B - -# 清華JittorLLMs: -https://github.com/Jittor/JittorLLMs - -# ChatPaper: -https://github.com/kaixindelele/ChatPaper - -# Edge-GPT: -https://github.com/acheong08/EdgeGPT - -# ChuanhuChatGPT: -https://github.com/GaiZhenbiao/ChuanhuChatGPT - - - -# Oobaboogaワンクリックインストーラー: -https://github.com/oobabooga/one-click-installers - -# その他: -https://github.com/gradio-app/gradio -https://github.com/fghrsh/live2d_demo diff --git a/docs/README.Korean.md b/docs/README.Korean.md deleted file mode 100644 index 2bd1f577cfa10888016873a9befc64d63a23b287..0000000000000000000000000000000000000000 --- a/docs/README.Korean.md +++ /dev/null @@ -1,363 +0,0 @@ - - - -> **참고** -> -> 이 README는 GPT 번역으로 생성되었습니다 (이 프로젝트의 플러그인에 의해 구현됨) . 100% 신뢰할 수 없으므로 번역 결과를 주의 깊게 검토하십시오. -> -> 2023.11.7: 종속성을 설치할 때, `requirements.txt`에 **지정된 버전**을 선택하십시오. 설치 명령어: `pip install -r requirements.txt`. - - - - -#
GPT 학술 최적화 (GPT Academic)
- -**이 프로젝트가 마음에 드신다면, Star를 부탁드립니다. 편리한 단축키나 플러그인을 발견하셨다면 Pull Request를 환영합니다!** -GPT를 사용하여 이 프로젝트를 임의의 언어로 번역하려면 [`multi_language.py`](multi_language.py)를 읽고 실행하십시오 (실험적). - - -> **참고** -> -> 1. **강조 표시**된 플러그인 (버튼)만 파일을 읽을 수 있습니다. 일부 플러그인은 플러그인 영역의 **드롭다운 메뉴**에 있습니다. 또한 새로운 플러그인에 대한 모든 PR을 환영하며, 이를 **가장 우선적**으로 처리합니다. -> -> 2. 이 프로젝트의 각 파일의 기능은 [자체 분석 보고서 `self_analysis.md`](https://github.com/binary-husky/gpt_academic/wiki/GPT‐Academic%EC%A0%9C%ED%94%84%EB%AA%85%EC%84%B1%EB%B0%A9%EC%8B%9D%EC%9D%98_%EA%B2%B0%EA%B3%BC)에서 자세히 설명되어 있습니다. 버전이 반복됨에 따라, 관련 기능 플러그인을 언제든지 클릭하여 GPT를 호출하여 프로젝트의 자체 분석 보고서를 다시 생성할 수 있습니다. 자주 묻는 질문은 [`위키`](https://github.com/binary-husky/gpt_academic/wiki)를 참조하십시오. [일반적인 설치 방법](#installation) | [원클릭 설치 스크립트](https://github.com/binary-husky/gpt_academic/releases) | [설정 설명서](https://github.com/binary-husky/gpt_academic/wiki/%EC%84%A4%EC%A0%95%EC%82%AC%EB%AA%85_%EA%B0%84%EB%8B%A8_%EC%84%B8%ED%8A%B8%EB%B2%84_%EC%B6%94%EA%B0%80) - - -> 3. 이 프로젝트는 ChatGLM 등 대형 언어 모델 (ChatGLM 등) 실행을 지원하고 권장합니다. 여러 개의 API 키를 동시에 사용할 수 있으며, 구성 파일에 `API_KEY="openai-key1,openai-key2,azure-key3,api2d-key4"`와 같이 입력할 수 있습니다. `API_KEY`를 일시적으로 변경해야 하는 경우, 입력 영역에 임시 `API_KEY`를 입력한 다음 Enter 키를 누르면 적용됩니다. - - - - - -
- -기능 (⭐= 최근 추가 기능) | 설명 ---- | --- -⭐[새 모델 추가](https://github.com/binary-husky/gpt_academic/wiki/%E5%A6%82%E4%BD%95%E5%88%87%E6%8D%A2%E6%A8%A1%E5%9E%8B)! | Baidu [Qianfan](https://cloud.baidu.com/doc/WENXINWORKSHOP/s/Nlks5zkzu)와 Wenxin Yiyan, [Tongyi Qianwen](https://modelscope.cn/models/qwen/Qwen-7B-Chat/summary), Shanghai AI-Lab [Shusheng](https://github.com/InternLM/InternLM), Xunfei [Star](https://xinghuo.xfyun.cn/), [LLaMa2](https://huggingface.co/meta-llama/Llama-2-7b-chat-hf), Zhipu API, DALLE3 -문체 개선, 번역, 코드 설명 | 일괄적인 문체 개선, 번역, 논문 문법 오류 탐색, 코드 설명 -[사용자 정의 단축키](https://www.bilibili.com/video/BV14s4y1E7jN) | 사용자 정의 단축키 지원 -모듈화 설계 | 사용자 정의 가능한 강력한 [플러그인](https://github.com/binary-husky/gpt_academic/tree/master/crazy_functions) 지원, 플러그인 지원 [핫 업데이트](https://github.com/binary-husky/gpt_academic/wiki/%E5%87%BD%E6%95%B0%E6%8F%92%E4%BB%B6%E6%8C%87%E5%8D%97) -[프로그램 분석](https://www.bilibili.com/video/BV1cj411A7VW) | [플러그인] 한 번에 Python/C/C++/Java/Lua/... 프로젝트 트리를 분석하거나 [자체 분석](https://www.bilibili.com/video/BV1cj411A7VW) -논문 읽기, 논문 [번역](https://www.bilibili.com/video/BV1KT411x7Wn) | [플러그인] LaTeX/PDF 논문 전문을 읽고 요약 생성 -LaTeX 전체 [번역](https://www.bilibili.com/video/BV1nk4y1Y7Js/), [개선](https://www.bilibili.com/video/BV1FT411H7c5/) | [플러그인] LaTeX 논문 번역 또는 개선 -일괄 주석 생성 | [플러그인] 함수 주석 일괄 생성 -Markdown [한 / 영 번역](https://www.bilibili.com/video/BV1yo4y157jV/) | 위의 5개 언어로 작성된 [README](https://github.com/binary-husky/gpt_academic/blob/master/docs/README_EN.md)를 살펴보셨나요? -채팅 분석 보고서 생성 | [플러그인] 실행 후 요약 보고서 자동 생성 -[PDF 논문 전체 번역](https://www.bilibili.com/video/BV1KT411x7Wn) 기능 | [플러그인] PDF 논문 제목 및 요약 추출 + 전체 번역 (멀티 스레드) -[Arxiv 도우미](https://www.bilibili.com/video/BV1LM4y1279X) | [플러그인] arxiv 논문 url 입력시 요약 번역 + PDF 다운로드 -LaTeX 논문 일괄 교정 | [플러그인] Grammarly를 모사하여 LaTeX 논문에 대한 문법 및 맞춤법 오류 교정 + 대조 PDF 출력 -[Google 학술 통합 도우미](https://www.bilibili.com/video/BV19L411U7ia) | 임의의 Google 학술 검색 페이지 URL을 지정하여 gpt가 [related works를 작성](https://www.bilibili.com/video/BV1GP411U7Az/)하게 해주세요. -인터넷 정보 집계 + GPT | [플러그인] [인터넷에서 정보를 가져와서](https://www.bilibili.com/video/BV1om4y127ck) 질문에 대답하도록 GPT를 자동화하세요. 정보가 절대로 오래되지 않도록 해줍니다. -⭐Arxiv 논문 세심한 번역 ([Docker](https://github.com/binary-husky/gpt_academic/pkgs/container/gpt_academic_with_latex)) | [플러그인] [arxiv 논문을 고품질 번역으로](https://www.bilibili.com/video/BV1dz4y1v77A/) 번역하는 최고의 도구 -⭐[실시간 음성 대화 입력](https://github.com/binary-husky/gpt_academic/blob/master/docs/use_audio.md) | [플러그인] 비동기적으로 [오디오를 모니터링](https://www.bilibili.com/video/BV1AV4y187Uy/)하여 문장을 자동으로 분절하고 대답 시기를 자동으로 찾습니다. -수식/이미지/표 표시 | [tex 형식 및 렌더링 형식](https://user-images.githubusercontent.com/96192199/230598842-1d7fcddd-815d-40ee-af60-baf488a199df.png)의 수식을 동시에 표시하며, 수식 및 코드 하이라이트 지원 -⭐AutoGen multi-agent 플러그인 | [플러그인] Microsoft AutoGen을 활용하여 여러 개의 에이전트가 지능적으로 발생하는 가능성을 탐색하세요! -다크 모드 주제 지원 | 브라우저의 URL 뒤에 ```/?__theme=dark```를 추가하여 다크 모드로 전환하세요. -[다양한 LLM 모델](https://www.bilibili.com/video/BV1wT411p7yf) 지원 | GPT3.5, GPT4, [Tsinghua ChatGLM2](https://github.com/THUDM/ChatGLM2-6B), [Fudan MOSS](https://github.com/OpenLMLab/MOSS)을 함께 사용하는 느낌은 좋을 것입니다, 그렇지 않습니까? -⭐ChatGLM2 fine-tuned 모델 | ChatGLM2 fine-tuned 모델 로드를 지원하며, ChatGLM2 fine-tuned 보조 플러그인 제공 -더 많은 LLM 모델 연결, [huggingface 배포](https://huggingface.co/spaces/qingxu98/gpt-academic) 지원 | Newbing 인터페이스(신 밍), Tsinghua [Jittorllms](https://github.com/Jittor/JittorLLMs) 도입, [LLaMA](https://github.com/facebookresearch/llama)와 [Pangu-alpha](https://openi.org.cn/pangu/)를 지원합니다. -⭐[void-terminal](https://github.com/binary-husky/void-terminal) 패키지 | GUI에서 독립, Python에서 이 프로젝트의 모든 함수 플러그인을 직접 호출 (개발 중) -⭐Void 터미널 플러그인 | [플러그인] 자연어로 이 프로젝트의 다른 플러그인을 직접 영속합니다. -기타 새로운 기능 소개 (이미지 생성 등) …… | 본 문서 맨 끝 참조 …… -
- - -- 새로운 인터페이스(`config.py`의 LAYOUT 옵션 수정으로 "왼쪽-오른쪽 레이아웃"과 "위-아래 레이아웃"을 전환할 수 있음) -
- -
- - -- 모든 버튼은 functional.py를 동적으로 읽어 생성되므로 원하는대로 사용자 정의 기능을 추가할 수 있으며 클립 보드를 해제할 수 있습니다. -
- -
- -- 문체 개선/오류 수정 -
- -
- - - -- If the output contains equations, they will be displayed in both tex format and rendered format for easy copying and reading. -
- -
- -- Don't feel like looking at the project code? Just give it to ChatGPT and let it dazzle you. -
- -
- -- Mix and match multiple powerful language models (ChatGLM + OpenAI-GPT3.5 + [API2D](https://api2d.com/)-GPT4) -
- -
- -# Installation -### Installation Method I: Run Directly (Windows, Linux or MacOS) - -1. Download the project -```sh -git clone --depth=1 https://github.com/binary-husky/gpt_academic.git -cd gpt_academic -``` - -2. Configure API_KEY - -In `config.py`, configure the API KEY and other settings, [click here to view special network environment configuration methods](https://github.com/binary-husky/gpt_academic/issues/1). [Wiki page](https://github.com/binary-husky/gpt_academic/wiki/项目配置说明)。 - -" The program will first check if there is a confidential configuration file named `config_private.py` and use its configuration to override the configuration with the same name in `config.py`. If you can understand this reading logic, we strongly recommend that you create a new configuration file named `config_private.py` next to `config.py` and move (copy) the configuration from `config.py` to `config_private.py` (only copy the modified configuration items). " - -" You can configure the project through `environment variables`. The format of the environment variables can be found in the `docker-compose.yml` file or our [Wiki page](https://github.com/binary-husky/gpt_academic/wiki/项目配置说明). The priority of the configuration reading is: `environment variables` > `config_private.py` > `config.py`. " - -3. Install dependencies -```sh -# (Option I: if familiar with python, python>=3.9) Note: Use the official pip source or Aliyun pip source. Temporary switching source method: python -m pip install -r requirements.txt -i https://mirrors.aliyun.com/pypi/simple/ -python -m pip install -r requirements.txt - -# (Option II: using Anaconda) The steps are similar (https://www.bilibili.com/video/BV1rc411W7Dr): -conda create -n gptac_venv python=3.11 # Create an Anaconda environment -conda activate gptac_venv # Activate the Anaconda environment -python -m pip install -r requirements.txt # This step is the same as the pip installation step -``` - - -
Click here to expand if you need support for Tsinghua ChatGLM2/Fudan MOSS/RWKV backend -

- -[Optional Step] If you need support for Tsinghua ChatGLM2/Fudan MOSS as the backend, you need to install additional dependencies (Prerequisites: Familiar with Python + Have used Pytorch + Sufficient computer configuration): -```sh -# [Optional Step I] Support for Tsinghua ChatGLM2. Note for Tsinghua ChatGLM: If you encounter the error "Call ChatGLM fail cannot load ChatGLM parameters", refer to the following: 1: The default installation above is torch+cpu version. To use cuda, uninstall torch and reinstall torch+cuda; 2: If you cannot load the model due to insufficient computer configuration, you can modify the model precision in request_llm/bridge_chatglm.py, change AutoTokenizer.from_pretrained("THUDM/chatglm-6b", trust_remote_code=True) to AutoTokenizer.from_pretrained("THUDM/chatglm-6b-int4", trust_remote_code=True) -python -m pip install -r request_llms/requirements_chatglm.txt - -# [Optional Step II] Support for Fudan MOSS -python -m pip install -r request_llms/requirements_moss.txt -git clone --depth=1 https://github.com/OpenLMLab/MOSS.git request_llms/moss # When executing this line of code, make sure you are in the project root path - -# [Optional Step III] Support for RWKV Runner -Refer to the wiki: https://github.com/binary-husky/gpt_academic/wiki/%E9%80%82%E9%85%8DRWKV-Runner - -# [Optional Step IV] Make sure that the AVAIL_LLM_MODELS in the config.py configuration file includes the expected models. The currently supported models are as follows (the jittorllms series only supports the docker solution): -AVAIL_LLM_MODELS = ["gpt-3.5-turbo", "api2d-gpt-3.5-turbo", "gpt-4", "api2d-gpt-4", "chatglm", "moss"] # + ["jittorllms_rwkv", "jittorllms_pangualpha", "jittorllms_llama"] -``` - -

-
- - - -4. Run -```sh -python main.py -``` - -### Installation Method II: Use Docker - -0. Deploy all the capabilities of the project (this is a large image that includes cuda and latex. However, it is not recommended if your internet speed is slow or your hard disk is small) -[![fullcapacity](https://github.com/binary-husky/gpt_academic/actions/workflows/build-with-all-capacity.yml/badge.svg?branch=master)](https://github.com/binary-husky/gpt_academic/actions/workflows/build-with-all-capacity.yml) - -``` sh -# Modify docker-compose.yml, keep scheme 0 and delete the others. Then run: -docker-compose up -``` - -1. ChatGPT+Random Quotes+Wikipedia Summary+Spark and other online models (recommended for most people) -[![basic](https://github.com/binary-husky/gpt_academic/actions/workflows/build-without-local-llms.yml/badge.svg?branch=master)](https://github.com/binary-husky/gpt_academic/actions/workflows/build-without-local-llms.yml) -[![basiclatex](https://github.com/binary-husky/gpt_academic/actions/workflows/build-with-latex.yml/badge.svg?branch=master)](https://github.com/binary-husky/gpt_academic/actions/workflows/build-with-latex.yml) -[![basicaudio](https://github.com/binary-husky/gpt_academic/actions/workflows/build-with-audio-assistant.yml/badge.svg?branch=master)](https://github.com/binary-husky/gpt_academic/actions/workflows/build-with-audio-assistant.yml) - -``` sh -# Modify docker-compose.yml, keep scheme 1 and delete the others. Then run: -docker-compose up -``` - -P.S. If you need the Latex plugin feature, please refer to the Wiki. Additionally, you can also use scheme 4 or scheme 0 directly to get the Latex feature. - -2. ChatGPT + ChatGLM2 + MOSS + LLAMA2 + Thousand Questions (Requires familiarity with [Nvidia Docker](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/install-guide.html#installing-on-ubuntu-and-debian) runtime) -[![chatglm](https://github.com/binary-husky/gpt_academic/actions/workflows/build-with-chatglm.yml/badge.svg?branch=master)](https://github.com/binary-husky/gpt_academic/actions/workflows/build-with-chatglm.yml) - -``` sh -# Modify docker-compose.yml, keep scheme 2 and delete the others. Then run: -docker-compose up -``` - - -### Installation Method III: Other Deployment Methods -1. **One-click run script for Windows**. -Windows users who are completely unfamiliar with the Python environment can download the one-click run script without local models from the [Release](https://github.com/binary-husky/gpt_academic/releases) section. -The script contribution comes from [oobabooga](https://github.com/oobabooga/one-click-installers). - -2. Use third-party APIs, Azure, etc., Random Quotes, Spark, etc., see the [Wiki page](https://github.com/binary-husky/gpt_academic/wiki/项目配置说明). - -3. Pitfall guide for remote deployment on cloud servers. -Please visit the [cloud server remote deployment wiki](https://github.com/binary-husky/gpt_academic/wiki/%E4%BA%91%E6%9C%8D%E5%8A%A1%E5%99%A8%E8%BF%9C%E7%A8%8B%E9%83%A8%E7%BD%B2%E6%8C%87%E5%8D%97) - -4. Some new deployment platforms or methods - - Use Sealos for [one-click deployment](https://github.com/binary-husky/gpt_academic/issues/993). - - Use WSL2 (Windows Subsystem for Linux). Please visit [deployment wiki-2](https://github.com/binary-husky/gpt_academic/wiki/%E4%BD%BF%E7%94%A8WSL2%EF%BC%88Windows-Subsystem-for-Linux-%E5%AD%90%E7%B3%BB%E7%BB%9F%EF%BC%89%E9%83%A8%E7%BD%B2) - - How to run in a subpath (such as `http://localhost/subpath`). Please refer to [FastAPI running instructions](docs/WithFastapi.md) - - - -# 고급 사용법 -### I: 사용자 정의 바로 가기 버튼 추가 (학술 단축키) -임의의 텍스트 편집기로 `core_functional.py` 파일을 열고 다음과 같은 항목을 추가한 다음 프로그램을 다시 시작하십시오. (이미 버튼이 있는 경우에는 접두사와 접미사를 실시간으로 수정할 수 있으므로 프로그램을 다시 시작할 필요가 없습니다.) -예시: -``` -"초급영문 번역": { - # 접두사, 입력 내용 앞에 추가됩니다. 예를 들어 요구 사항을 설명하는 데 사용됩니다. 예를 들어 번역, 코드 설명, 교정 등 - "Prefix": "다음 내용을 한국어로 번역하고 전문 용어에 대한 설명을 적용한 마크다운 표를 사용하세요:\n\n", - - # 접미사, 입력 내용 뒤에 추가됩니다. 예를 들어 접두사와 함께 입력 내용을 따옴표로 감쌀 수 있습니다. - "Suffix": "", -}, -``` -
- -
- -### II: 사용자 정의 함수 플러그인 -원하는 작업을 수행하기 위해 능력있는 함수 플러그인을 작성하세요. -이 프로젝트의 플러그인 작성 및 디버깅은 난이도가 낮으며, 일정한 Python 기본 지식만 있으면 우리가 제공하는 템플릿을 본따서 고유한 플러그인 기능을 구현할 수 있습니다. -자세한 내용은 [함수 플러그인 가이드](https://github.com/binary-husky/gpt_academic/wiki/%E5%87%BD%E6%95%B0%E6%8F%92%E4%BB%B6%E6%8C%87%E5%8D%97)를 참조하세요. - - -# 업데이트 -### I: 다이나믹 - -1. 대화 저장 기능. 플러그인 영역에서 '현재 대화 저장'을 호출하여 현재 대화를 볼 수 있고, html 파일을 복구할 수 있습니다. -또한 플러그인 영역에서 '대화 기록 불러오기'를 호출하여 이전 대화를 복원할 수 있습니다. -팁: 파일을 지정하지 않고 '대화 기록 불러오기'를 바로 클릭하면 이전 html 기록 캐시를 볼 수 있습니다. -
- -
- -2. ⭐Latex/Arxiv 논문 번역 기능⭐ -
- ===> - -
- -3. 빈 터미널 (자연어 입력에서 사용자 의도 이해 + 자동 플러그인 호출) - -- 단계 1: "플러그인을 사용하여 PDF 논문을 번역하십시오. 주소는 https://openreview.net/pdf?id=rJl0r3R9KX입니다." 입력 -- 단계 2: "빈 터미널" 클릭 - -
- -
- -4. 모듈화된 기능 디자인, 간단한 인터페이스로 강력한 기능 제공 -
- - -
- -5. 다른 오픈 소스 프로젝트 번역 -
- - -
- -6. [live2d](https://github.com/fghrsh/live2d_demo)의 작은 기능 추가 (기본 설정은 닫혀 있으며, `config.py`를 수정해야 합니다.) -
- -
- -7. OpenAI 이미지 생성 -
- -
- -8. OpenAI 오디오 분석 및 요약 -
- -
- -9. Latex 전체 교정 오류 -
- ===> - -
- -10. 언어, 테마 변경 -
- -
- - - -### II: 버전: -- 버전 3.70 (예정): AutoGen 플러그인 테마 개선 및 다른 테마 플러그인 디자인 -- 버전 3.60: AutoGen을 새로운 세대 플러그인의 기반으로 도입 -- 버전 3.57: GLM3, Starfire v3, 文心一言 v4 지원, 로컬 모델의 동시성 버그 수정 -- 버전 3.56: 동적으로 기본 기능 버튼 추가, 새로운 보고서 PDF 요약 페이지 -- 버전 3.55: 프론트 엔드 인터페이스 리팩토링, 화면 따라다니는 윈도우 및 메뉴 바 도입 -- 버전 3.54: 새로운 동적 코드 해석기 (Code Interpreter) 추가 (완벽하게 완성되지 않음) -- 버전 3.53: 다른 인터페이스 테마 동적 선택 기능 추가, 안정성 향상 및 다중 사용자 충돌 문제 해결 -- 버전 3.50: 자연어로 이 프로젝트의 모든 함수 플러그인을 호출하는 기능 (빈 터미널) 추가, 플러그인 분류 지원, UI 개선, 새로운 테마 설계 -- 버전 3.49: Baidu Qianfan 플랫폼 및 문심일언 지원 -- 버전 3.48: Ali DameiYuan Sematic Query, Shanghai AI-Lab Shusheng, Xunfei Starfire 지원 -- 버전 3.46: 완전 자동 운전 가능한 실시간 음성 대화 지원 -- 버전 3.45: 사용자 정의 ChatGLM2 fine-tuning 모델 지원 -- 버전 3.44: Azure 정식 지원, 인터페이스의 사용 편의성 개선 -- 버전 3.4: +arxiv 논문 번역, latex 논문 교정 기능 추가 -- 버전 3.3: +인터넷 정보 종합 기능 -- 버전 3.2: 함수 플러그인이 더 많은 매개변수 인터페이스를 지원합니다 (대화 저장 기능, 임의의 언어 코드 해석 + 임의의 LLM 조합을 동시에 요청) -- 버전 3.1: 여러 GPT 모델에 동시에 질문할 수 있는 기능 추가! api2d 지원, 여러 개의 apikey 부하 균형 조정 지원 -- 버전 3.0: chatglm 및 기타 소규모 llm 지원 -- 버전 2.6: 플러그인 구조를 재구성하여 상호 작용성 향상, 더 많은 플러그인 추가 -- 버전 2.5: 자동 업데이트, 소스 코드 요약 중 텍스트가 너무 길고 토큰이 오버플로되는 문제 해결 -- 버전 2.4: (1)PDF 전체 번역 기능 추가; (2)입력 영역 위치 전환 기능 추가; (3)수직 레이아웃 옵션 추가; (4)멀티 스레드 함수 플러그인 최적화 -- 버전 2.3: 멀티 스레드 상호 작용성 강화 -- 버전 2.2: 함수 플러그인의 핫 리로드 지원 -- 버전 2.1: 접을 수 있는 레이아웃 -- 버전 2.0: 모듈화 함수 플러그인 도입 -- 버전 1.0: 기본 기능 - -GPT Academic 개발자 QQ 그룹: `610599535` -- 알려진 문제 - - 특정 웹 브라우저 번역 플러그인이 이 소프트웨어의 프론트엔드 실행에 방해가 되는 경우가 있습니다. - - 공식 Gradio에는 호환성 문제가 많기 때문에 `requirement.txt`를 사용하여 Gradio를 설치하십시오. - -### III: 테마 -`THEME` 옵션 (`config.py`)을 수정하여 테마를 변경할 수 있습니다. -1. `Chuanhu-Small-and-Beautiful` [URL](https://github.com/GaiZhenbiao/ChuanhuChatGPT/) - - -### IV: 이 프로젝트의 개발 브랜치 - -1. `master` 브랜치: 메인 브랜치, 안정 버전 -2. `frontier` 브랜치: 개발 브랜치, 테스트 버전 - - -### V: 참고 및 학습 - -``` -코드에서는 다른 우수한 프로젝트의 디자인을 많이 참고했습니다. 순서는 문제 없이 나열됩니다: - -# 清华ChatGLM2-6B: -https://github.com/THUDM/ChatGLM2-6B - -# 清华JittorLLMs: -https://github.com/Jittor/JittorLLMs - -# ChatPaper: -https://github.com/kaixindelele/ChatPaper - -# Edge-GPT: -https://github.com/acheong08/EdgeGPT - -# ChuanhuChatGPT: -https://github.com/GaiZhenbiao/ChuanhuChatGPT - - - -# Oobabooga 원 클릭 설치 프로그램: -https://github.com/oobabooga/one-click-installers - -# 더보기: -https://github.com/gradio-app/gradio -https://github.com/fghrsh/live2d_demo diff --git a/docs/README.Portuguese.md b/docs/README.Portuguese.md deleted file mode 100644 index 4cc02c19ebbb900c4424d60d680d654d4bc3fe8d..0000000000000000000000000000000000000000 --- a/docs/README.Portuguese.md +++ /dev/null @@ -1,357 +0,0 @@ - - - -> **Nota** -> -> Este README foi traduzido pelo GPT (implementado por um plugin deste projeto) e não é 100% confiável. Por favor, verifique cuidadosamente o resultado da tradução. -> -> 7 de novembro de 2023: Ao instalar as dependências, favor selecionar as **versões especificadas** no `requirements.txt`. Comando de instalação: `pip install -r requirements.txt`. - -#
GPT Acadêmico
- -**Se você gosta deste projeto, por favor, dê uma estrela nele. Se você inventou atalhos de teclado ou plugins úteis, fique à vontade para criar pull requests!** -Para traduzir este projeto para qualquer idioma utilizando o GPT, leia e execute [`multi_language.py`](multi_language.py) (experimental). - -> **Nota** -> -> 1. Observe que apenas os plugins (botões) marcados em **destaque** são capazes de ler arquivos, alguns plugins estão localizados no **menu suspenso** do plugin area. Também damos boas-vindas e prioridade máxima a qualquer novo plugin via PR. -> -> 2. As funcionalidades de cada arquivo deste projeto estão detalhadamente explicadas em [autoanálise `self_analysis.md`](https://github.com/binary-husky/gpt_academic/wiki/GPT‐Academic项目自译解报告). Com a iteração das versões, você também pode clicar nos plugins de funções relevantes a qualquer momento para chamar o GPT para regerar o relatório de autonálise do projeto. Perguntas frequentes [`wiki`](https://github.com/binary-husky/gpt_academic/wiki) | [Método de instalação convencional](#installation) | [Script de instalação em um clique](https://github.com/binary-husky/gpt_academic/releases) | [Explicação de configuração](https://github.com/binary-husky/gpt_academic/wiki/项目配置说明)。 -> -> 3. Este projeto é compatível e encoraja o uso de modelos de linguagem chineses, como ChatGLM. Vários api-keys podem ser usados simultaneamente, podendo ser especificados no arquivo de configuração como `API_KEY="openai-key1,openai-key2,azure-key3,api2d-key4"`. Quando precisar alterar temporariamente o `API_KEY`, insira o `API_KEY` temporário na área de entrada e pressione Enter para que ele seja efetivo. - - -
- -Funcionalidades (⭐= funcionalidade recentemente adicionada) | Descrição ---- | --- -⭐[Integração com novos modelos](https://github.com/binary-husky/gpt_academic/wiki/%E5%A6%82%E4%BD%95%E5%88%87%E6%8D%A2%E6%A8%A1%E5%9E%8B)! | [Qianfan](https://cloud.baidu.com/doc/WENXINWORKSHOP/s/Nlks5zkzu) da Baidu, Wenxin e [Tongyi Qianwen](https://modelscope.cn/models/qwen/Qwen-7B-Chat/summary), [Shusheng](https://github.com/InternLM/InternLM) da Shanghai AI-Lab, [Xinghuo](https://xinghuo.xfyun.cn/) da Iflytek, [LLaMa2](https://huggingface.co/meta-llama/Llama-2-7b-chat-hf), Zhipu API, DALLE3 -Aprimoramento, tradução, explicação de códigos | Aprimoramento com um clique, tradução, busca de erros gramaticais em artigos e explicação de códigos -[Atalhos de teclado personalizados](https://www.bilibili.com/video/BV14s4y1E7jN) | Suporte para atalhos de teclado personalizados -Design modular | Suporte a plugins poderosos e personalizáveis, plugins com suporte a [atualização a quente](https://github.com/binary-husky/gpt_academic/wiki/%E5%87%BD%E6%95%B0%E6%8F%92%E4%BB%B6%E6%8C%87%E5%8D%97) -[Análise de código](https://www.bilibili.com/video/BV1cj411A7VW) | [Plugin] Análise instantânea da estrutura de projetos em Python/C/C++/Java/Lua/... ou [autoanálise](https://www.bilibili.com/video/BV1cj411A7VW) -Leitura de artigos, [tradução](https://www.bilibili.com/video/BV1KT411x7Wn) de artigos | [Plugin] Interpretação instantânea de artigos completos em latex/pdf e geração de resumos -Tradução completa de artigos em latex [PDF](https://www.bilibili.com/video/BV1nk4y1Y7Js/), [aprimoramento](https://www.bilibili.com/video/BV1FT411H7c5/) | [Plugin] Tradução completa ou aprimoramento de artigos em latex com um clique -Geração em lote de comentários | [Plugin] Geração em lote de comentários de funções com um clique -Tradução (inglês-chinês) de Markdown | [Plugin] Você já viu o [README](https://github.com/binary-husky/gpt_academic/blob/master/docs/README_EN.md) nas 5 línguas acima? -Criação de relatório de análise de bate-papo | [Plugin] Geração automática de relatório de resumo após a execução -Tradução [completa de artigos em PDF](https://www.bilibili.com/video/BV1KT411x7Wn) | [Plugin] Extração de título e resumo de artigos em PDF + tradução completa (multithreading) -Auxiliar Arxiv | [Plugin] Insira o URL de um artigo Arxiv para traduzir o resumo + baixar o PDF com um clique -Correção automática de artigos em latex | [Plugin] Correções gramaticais e ortográficas de artigos em latex semelhante ao Grammarly + saída PDF comparativo -Auxiliar Google Scholar | [Plugin] Insira qualquer URL da busca do Google Acadêmico e deixe o GPT [escrever trabalhos relacionados](https://www.bilibili.com/video/BV1GP411U7Az/) para você -Agregação de informações da Internet + GPT | [Plugin] Capturar informações da Internet e obter respostas de perguntas com o GPT em um clique, para que as informações nunca fiquem desatualizadas -⭐Tradução refinada de artigos do Arxiv ([Docker](https://github.com/binary-husky/gpt_academic/pkgs/container/gpt_academic_with_latex)) | [Plugin] Tradução de alta qualidade de artigos do Arxiv com um clique, a melhor ferramenta de tradução de artigos atualmente -⭐Entrada de conversa de voz em tempo real | [Plugin] Monitoramento de áudio [assíncrono](https://www.bilibili.com/video/BV1AV4y187Uy/), segmentação automática de frases, detecção automática de momentos de resposta -Exibição de fórmulas, imagens e tabelas | Exibição de fórmulas em formato tex e renderizadas simultaneamente, suporte a fórmulas e destaque de código -⭐Plugin AutoGen para vários agentes | [Plugin] Explore a emergência de múltiplos agentes com o AutoGen da Microsoft! -Ativar o tema escuro | Adicione ```/?__theme=dark``` ao final da URL para alternar para o tema escuro -Suporte a múltiplos modelos LLM | Ser atendido simultaneamente pelo GPT3.5, GPT4, [ChatGLM2](https://github.com/THUDM/ChatGLM2-6B) do Tsinghua University e [MOSS](https://github.com/OpenLMLab/MOSS) da Fudan University se sente incrível, não é mesmo? -⭐Modelo de ajuste fino ChatGLM2 | Suporte para carregar o modelo ChatGLM2 ajustado e fornecer plugins de assistência ao ajuste fino do ChatGLM2 -Mais modelos LLM e suporte para [implantação pela HuggingFace](https://huggingface.co/spaces/qingxu98/gpt-academic) | Integração com a interface Newbing (Bing novo), introdução do [Jittorllms](https://github.com/Jittor/JittorLLMs) da Tsinghua University com suporte a [LLaMA](https://github.com/facebookresearch/llama) e [Panguα](https://openi.org.cn/pangu/) -⭐Pacote pip [void-terminal](https://github.com/binary-husky/void-terminal) | Chame todas as funções plugins deste projeto diretamente em Python, sem a GUI (em desenvolvimento) -⭐Plugin Terminal do Vácuo | [Plugin] Chame outros plugins deste projeto diretamente usando linguagem natural -Apresentação de mais novas funcionalidades (geração de imagens, etc.) ... | Veja no final deste documento ... - -
- - -- Nova interface (altere a opção LAYOUT em `config.py` para alternar entre os "Layouts de lado a lado" e "Layout de cima para baixo") -
- -
- - -- Todos os botões são gerados dinamicamente através da leitura do `functional.py`, você pode adicionar funcionalidades personalizadas à vontade, liberando sua área de transferência -
- -
- -- Aprimoramento/Correção -
- -
- - - -- Se a saída contiver fórmulas, elas serão exibidas tanto em formato tex quanto renderizado para facilitar a cópia e a leitura. -
- -
- -- Não tem vontade de ver o código do projeto? O projeto inteiro está diretamente na boca do chatgpt. -
- -
- -- Combinação de vários modelos de linguagem (ChatGLM + OpenAI-GPT3.5 + [API2D](https://api2d.com/)-GPT4) -
- -
- -# Instalação -### Método de instalação I: Executar diretamente (Windows, Linux ou MacOS) - -1. Baixe o projeto -```sh -git clone --depth=1 https://github.com/binary-husky/gpt_academic.git -cd gpt_academic -``` - -2. Configure a API_KEY - -No arquivo `config.py`, configure a API KEY e outras configurações. [Clique aqui para ver o método de configuração em redes especiais](https://github.com/binary-husky/gpt_academic/issues/1). [Página Wiki](https://github.com/binary-husky/gpt_academic/wiki/项目配置说明). - -「 O programa verificará primeiro se existe um arquivo de configuração privada chamado `config_private.py` e substituirá as configurações correspondentes no arquivo `config.py`. Se você entender essa lógica de leitura, é altamente recomendável criar um novo arquivo de configuração chamado `config_private.py` ao lado do `config.py` e copiar as configurações do `config.py` para o `config_private.py` (copiando apenas os itens de configuração que você modificou). 」 - -「 Suporte para configurar o projeto por meio de `variáveis de ambiente`, o formato de gravação das variáveis de ambiente pode ser encontrado no arquivo `docker-compose.yml` ou em nossa [página Wiki](https://github.com/binary-husky/gpt_academic/wiki/项目配置说明). A prioridade de leitura das configurações é: `variáveis de ambiente` > `config_private.py` > `config.py`. 」 - - -3. Instale as dependências -```sh -# (Opção I: Se você está familiarizado com o Python, Python>=3.9) Observação: Use o pip oficial ou o pip da Aliyun. Método temporário para alternar fontes: python -m pip install -r requirements.txt -i https://mirrors.aliyun.com/pypi/simple/ -python -m pip install -r requirements.txt - -# (Opção II: Use o Anaconda) Os passos também são semelhantes (https://www.bilibili.com/video/BV1rc411W7Dr): -conda create -n gptac_venv python=3.11 # Crie um ambiente do Anaconda -conda activate gptac_venv # Ative o ambiente do Anaconda -python -m pip install -r requirements.txt # Este passo é igual ao da instalação do pip -``` - - -
Se você quiser suporte para o ChatGLM2 do THU/ MOSS do Fudan/RWKV como backend, clique para expandir -

- -[Opcional] Se você quiser suporte para o ChatGLM2 do THU/ MOSS do Fudan, precisará instalar dependências extras (pré-requisitos: familiarizado com o Python + já usou o PyTorch + o computador tem configuração suficiente): -```sh -# [Opcional Passo I] Suporte para ChatGLM2 do THU. Observações sobre o ChatGLM2 do THU: Se você encontrar o erro "Call ChatGLM fail 不能正常加载ChatGLM的参数" (Falha ao chamar o ChatGLM, não é possível carregar os parâmetros do ChatGLM), consulte o seguinte: 1: A versão instalada por padrão é a versão torch+cpu. Se você quiser usar a versão cuda, desinstale o torch e reinstale uma versão com torch+cuda; 2: Se a sua configuração não for suficiente para carregar o modelo, você pode modificar a precisão do modelo em request_llm/bridge_chatglm.py, alterando todas as ocorrências de AutoTokenizer.from_pretrained("THUDM/chatglm-6b", trust_remote_code=True) para AutoTokenizer.from_pretrained("THUDM/chatglm-6b-int4", trust_remote_code=True) -python -m pip install -r request_llms/requirements_chatglm.txt - -# [Opcional Passo II] Suporte para MOSS do Fudan -python -m pip install -r request_llms/requirements_moss.txt -git clone --depth=1 https://github.com/OpenLMLab/MOSS.git request_llms/moss # Observe que você deve estar no diretório raiz do projeto ao executar este comando - -# [Opcional Passo III] Suporte para RWKV Runner -Consulte a página Wiki: https://github.com/binary-husky/gpt_academic/wiki/%E9%80%82%E9%85%8DRWKV-Runner - -# [Opcional Passo IV] Verifique se o arquivo de configuração config.py contém os modelos desejados, os modelos compatíveis são os seguintes (a série jittorllms suporta apenas a solução Docker): -AVAIL_LLM_MODELS = ["gpt-3.5-turbo", "api2d-gpt-3.5-turbo", "gpt-4", "api2d-gpt-4", "chatglm", "moss"] # + ["jittorllms_rwkv", "jittorllms_pangualpha", "jittorllms_llama"] -``` - -

-
- - - -4. Execute -```sh -python main.py -``` - -### Método de instalação II: Usando o Docker - -0. Implante todas as capacidades do projeto (este é um contêiner grande que inclui CUDA e LaTeX. Não recomendado se você tiver uma conexão lenta com a internet ou pouco espaço em disco) -[![fullcapacity](https://github.com/binary-husky/gpt_academic/actions/workflows/build-with-all-capacity.yml/badge.svg?branch=master)](https://github.com/binary-husky/gpt_academic/actions/workflows/build-with-all-capacity.yml) - -``` sh -# Modifique o arquivo docker-compose.yml para incluir apenas a seção 0 e excluir as outras seções. Em seguida, execute: -docker-compose up -``` - -1. ChatGPT + 文心一言 + spark + outros modelos online (recomendado para a maioria dos usuários) -[![basic](https://github.com/binary-husky/gpt_academic/actions/workflows/build-without-local-llms.yml/badge.svg?branch=master)](https://github.com/binary-husky/gpt_academic/actions/workflows/build-without-local-llms.yml) -[![basiclatex](https://github.com/binary-husky/gpt_academic/actions/workflows/build-with-latex.yml/badge.svg?branch=master)](https://github.com/binary-husky/gpt_academic/actions/workflows/build-with-latex.yml) -[![basicaudio](https://github.com/binary-husky/gpt_academic/actions/workflows/build-with-audio-assistant.yml/badge.svg?branch=master)](https://github.com/binary-husky/gpt_academic/actions/workflows/build-with-audio-assistant.yml) - -``` sh -# Modifique o arquivo docker-compose.yml para incluir apenas a seção 1 e excluir as outras seções. Em seguida, execute: -docker-compose up -``` - -Obs.: Se você precisar do plugin Latex, consulte a Wiki. Além disso, você também pode usar a seção 4 ou 0 para obter a funcionalidade do LaTeX. - -2. ChatGPT + ChatGLM2 + MOSS + LLAMA2 + 通义千问 (você precisa estar familiarizado com o [Nvidia Docker](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/install-guide.html#installing-on-ubuntu-and-debian) para executar este modo) -[![chatglm](https://github.com/binary-husky/gpt_academic/actions/workflows/build-with-chatglm.yml/badge.svg?branch=master)](https://github.com/binary-husky/gpt_academic/actions/workflows/build-with-chatglm.yml) - -``` sh -# Modifique o arquivo docker-compose.yml para incluir apenas a seção 2 e excluir as outras seções. Em seguida, execute: -docker-compose up -``` - - -### Método de instalação III: Outros métodos de implantação -1. **Script de execução com um clique para Windows**. -Usuários do Windows que não estão familiarizados com o ambiente Python podem baixar o script de execução com um clique da [Release](https://github.com/binary-husky/gpt_academic/releases) para instalar a versão sem modelos locais. -A contribuição do script vem de [oobabooga](https://github.com/oobabooga/one-click-installers). - -2. Usar APIs de terceiros, Azure, etc., 文心一言, 星火, consulte a [página Wiki](https://github.com/binary-husky/gpt_academic/wiki/项目配置说明). - -3. Guia para evitar armadilhas na implantação em servidor em nuvem. -Consulte o [wiki de implantação em servidor em nuvem](https://github.com/binary-husky/gpt_academic/wiki/%E4%BA%91%E6%9C%8D%E5%8A%A1%E5%99%A8%E8%BF%9C%E7%A8%8B%E9%83%A8%E7%BD%B2%E6%8C%87%E5%8D%97). - -4. Algumas novas plataformas ou métodos de implantação - - Use Sealos [implantação com um clique](https://github.com/binary-husky/gpt_academic/issues/993). - - Use o WSL2 (Subsistema do Windows para Linux). Consulte [wiki de implantação](https://github.com/binary-husky/gpt_academic/wiki/%E4%BD%BF%E7%94%A8WSL2%EF%BC%88Windows-Subsystem-for-Linux-%E5%AD%90%E7%B3%BB%E7%BB%9F%EF%BC%89%E9%83%A8%E7%BD%B2). - - Como executar em um subdiretório da URL (como `http://localhost/subpath`). Consulte [instruções de execução com o FastAPI](docs/WithFastapi.md) - - - -# Uso Avançado -### I: Personalização de Novos Botões de Atalho (Atalhos Acadêmicos) -Abra o arquivo `core_functional.py` em qualquer editor de texto, adicione o seguinte item e reinicie o programa. (Se o botão já existir, o prefixo e o sufixo podem ser modificados a qualquer momento sem reiniciar o programa). -Por exemplo: -``` -"超级英译中": { - # Prefixo, adicionado antes do seu input. Por exemplo, usado para descrever sua solicitação, como traduzir, explicar o código, revisar, etc. - "Prefix": "Por favor, traduza o parágrafo abaixo para o chinês e explique cada termo técnico dentro de uma tabela markdown:\n\n", - - # Sufixo, adicionado após o seu input. Por exemplo, em conjunto com o prefixo, pode-se colocar seu input entre aspas. - "Suffix": "", -}, -``` -
- -
- -### II: Personalização de Funções Plugins -Crie poderosos plugins de função para executar tarefas que você pode e não pode imaginar. -Criar plugins neste projeto é fácil, basta seguir o modelo fornecido, desde que você tenha conhecimento básico de Python. -Consulte o [Guia dos Plugins de Função](https://github.com/binary-husky/gpt_academic/wiki/%E5%87%BD%E6%95%B0%E6%8F%92%E4%BB%B6%E6%8C%87%E5%8D%97) para mais detalhes. - - -# Atualizações -### I: Dinâmico - -1. Função de salvar conversas. Chame a função "Salvar a conversa atual" na área de plugins para salvar a conversa atual em um arquivo HTML legível e recuperável. Além disso, chame a função "Carregar histórico de conversas" na área de plugins (menu suspenso) para restaurar conversas anteriores. -Dica: Se você clicar diretamente em "Carregar histórico de conversas" sem especificar o arquivo, poderá visualizar o cache do histórico do arquivo HTML. -
- -
- -2. ⭐Tradução de artigos Latex/Arxiv⭐ -
- ===> - -
- -3. Terminal vazio (entendendo a intenção do usuário a partir do texto em linguagem natural e chamando automaticamente outros plugins) - -- Passo 1: Digite "Por favor, chame o plugin 'Traduzir artigo PDF' e forneça o link https://openreview.net/pdf?id=rJl0r3R9KX" -- Passo 2: Clique em "Terminal vazio" - -
- -
- -4. Design de recursos modular, interface simples com suporte a recursos poderosos -
- - -
- -5. Tradução e interpretação de outros projetos de código aberto -
- - -
- -6. Recursos adicionais para [live2d](https://github.com/fghrsh/live2d_demo) (desativados por padrão, requer modificação no arquivo `config.py`) -
- -
- -7. Geração de imagens pela OpenAI -
- -
- -8. Análise e resumo de áudio pela OpenAI -
- -
- -9. Correção de erros em texto e código LaTeX -
- ===> - -
- -10. Alternância de idioma e tema -
- -
- - - -### II: Versões: -- Versão 3.70 (a fazer): Melhorar o plugin AutoGen e projetar uma série de plugins relacionados. -- Versão 3.60: Introdução do AutoGen como base para a próxima geração de plugins. -- Versão 3.57: Suporte para GLM3, Starfire v3, Wenxin Yiyan v4, correção de bugs relacionados a modelos locais executados simultaneamente. -- Versão 3.56: Suporte para adicionar dinamicamente botões de função básicos e nova página de resumo em PDF. -- Versão 3.55: Reformulação da interface do usuário, introdução de janelas flutuantes e menus. -- Versão 3.54: Novo interpretador de código dinâmico (Code Interpreter) (em desenvolvimento) -- Versão 3.53: Suporte para alterar dinamicamente o tema da interface, melhorias de estabilidade e correção de conflitos entre vários usuários. -- Versão 3.50: Chamada de todas as funções de plugins deste projeto usando linguagem natural (Terminal vazio), suporte a categorização de plugins, melhorias na interface do usuário e design de novos temas. -- Versão 3.49: Suporte para Baidu Qianfan Platform e Wenxin Yiyan. -- Versão 3.48: Suporte para Alibaba DAMO Academy Tongyi Qianwen, Shanghai AI-Lab Shusheng e Xunfei Xinghuo. -- Versão 3.46: Suporte para diálogos em tempo real totalmente automáticos. -- Versão 3.45: Suporte para personalização do modelo ChatGLM2. -- Versão 3.44: Suporte oficial ao Azure, aprimoramentos na usabilidade da interface. -- Versão 3.4: Tradução completa de artigos Arxiv/Latex, correção de artigos Latex. -- Versão 3.3: Funcionalidade de consulta a informações na internet. -- Versão 3.2: Maior suporte para parâmetros de função de plugins (função de salvar conversas, interpretação de código em qualquer linguagem + perguntas sobre combinações LLM arbitrariamente). -- Versão 3.1: Suporte para fazer perguntas a modelos GPT múltiplos! Suporte para API2D, balanceamento de carga em vários APIKeys. -- Versão 3.0: Suporte para chatglm e outros pequenos modelos LLM. -- Versão 2.6: Refatoração da estrutura de plugins, melhoria na interação, adição de mais plugins. -- Versão 2.5: Auto-atualizável, resolve problemas de texto muito longo ou estouro de tokens ao resumir grandes projetos de código. -- Versão 2.4: (1) Novo recurso de tradução completa de PDF; (2) Nova função para alternar a posição da área de input; (3) Nova opção de layout vertical; (4) Melhoria dos plugins de função em várias threads. -- Versão 2.3: Melhorias na interação em várias threads. -- Versão 2.2: Suporte para recarregar plugins sem reiniciar o programa. -- Versão 2.1: Layout dobrável. -- Versão 2.0: Introdução de plugins de função modular. -- Versão 1.0: Funcionalidades básicas. - -GPT Academic QQ Group: `610599535` - -- Problemas conhecidos - - Alguns plugins de tradução de navegadores podem interferir na execução deste software. - - A biblioteca Gradio possui alguns bugs de compatibilidade conhecidos. Certifique-se de instalar o Gradio usando o arquivo `requirement.txt`. - -### III: Temas -Você pode alterar o tema atualizando a opção `THEME` (config.py). -1. `Chuanhu-Small-and-Beautiful` [Link](https://github.com/GaiZhenbiao/ChuanhuChatGPT/) - - -### IV: Branches de Desenvolvimento deste Projeto - -1. Branch `master`: Branch principal, versão estável. -2. Branch `frontier`: Branch de desenvolvimento, versão de teste. - - -### V: Referências para Aprendizado - -``` -O código referenciou muitos projetos excelentes, em ordem aleatória: - -# Tsinghua ChatGLM2-6B: -https://github.com/THUDM/ChatGLM2-6B - -# Tsinghua JittorLLMs: -https://github.com/Jittor/JittorLLMs - -# ChatPaper: -https://github.com/kaixindelele/ChatPaper - -# Edge-GPT: -https://github.com/acheong08/EdgeGPT - -# ChuanhuChatGPT: -https://github.com/GaiZhenbiao/ChuanhuChatGPT - - - -# Oobabooga instalador com um clique: -https://github.com/oobabooga/instaladores-de-um-clique - -# Mais: -https://github.com/gradio-app/gradio -https://github.com/fghrsh/live2d_demo diff --git a/docs/README.Russian.md b/docs/README.Russian.md deleted file mode 100644 index 471f17449884c06a63bcd20905fd263c574bf869..0000000000000000000000000000000000000000 --- a/docs/README.Russian.md +++ /dev/null @@ -1,360 +0,0 @@ - - - -> **Примечание** -> -> Этот README был переведен с помощью GPT (реализовано с помощью плагина этого проекта) и не может быть полностью надежным, пожалуйста, внимательно проверьте результаты перевода. -> -> 7 ноября 2023 года: При установке зависимостей, пожалуйста, выберите **указанные версии** из `requirements.txt`. Команда установки: `pip install -r requirements.txt`. - - -#
GPT Academic (GPT Академический)
- -**Если вам нравится этот проект, пожалуйста, поставьте звезду; если у вас есть удобные горячие клавиши или плагины, приветствуются pull requests!** -Чтобы перевести этот проект на произвольный язык с помощью GPT, прочтите и выполните [`multi_language.py`](multi_language.py) (экспериментально). - -> **Примечание** -> -> 1. Пожалуйста, обратите внимание, что только плагины (кнопки), выделенные **жирным шрифтом**, поддерживают чтение файлов, некоторые плагины находятся в выпадающем меню **плагинов**. Кроме того, мы с радостью приветствуем и обрабатываем PR для любых новых плагинов с **наивысшим приоритетом**. -> -> 2. Функции каждого файла в этом проекте подробно описаны в [отчете о самостоятельном анализе проекта `self_analysis.md`](https://github.com/binary-husky/gpt_academic/wiki/GPT‐Academic项目自译解报告). С каждым новым релизом вы также можете в любое время нажать на соответствующий функциональный плагин, вызвать GPT для повторной генерации сводного отчета о самоанализе проекта. Часто задаваемые вопросы [`wiki`](https://github.com/binary-husky/gpt_academic/wiki) | [обычные методы установки](#installation) | [скрипт одношаговой установки](https://github.com/binary-husky/gpt_academic/releases) | [инструкции по настройке](https://github.com/binary-husky/gpt_academic/wiki/项目配置说明). -> -> 3. Этот проект совместим и настоятельно рекомендуется использование китайской NLP-модели ChatGLM и других моделей больших языков производства Китая. Поддерживает одновременное использование нескольких ключей API, которые можно указать в конфигурационном файле, например, `API_KEY="openai-key1,openai-key2,azure-key3,api2d-key4"`. Если нужно временно заменить `API_KEY`, введите временный `API_KEY` в окне ввода и нажмите Enter для его подтверждения. - - - - -
- -Функции (⭐= Недавно добавленные функции) | Описание ---- | --- -⭐[Подключение новой модели](https://github.com/binary-husky/gpt_academic/wiki/%E5%A6%82%E4%BD%95%E5%88%87%E6%8D%A2%E6%A8%A1%E5%9E%8B)! | Baidu [QianFan](https://cloud.baidu.com/doc/WENXINWORKSHOP/s/Nlks5zkzu) и WenxinYiYan, [TongYiQianWen](https://modelscope.cn/models/qwen/Qwen-7B-Chat/summary), Shanghai AI-Lab [ShuSheng](https://github.com/InternLM/InternLM), Xunfei [XingHuo](https://xinghuo.xfyun.cn/), [LLaMa2](https://huggingface.co/meta-llama/Llama-2-7b-chat-hf), ZhiPu API, DALLE3 -Улучшение, перевод, объяснение кода | Одним нажатием выполнить поиск синтаксических ошибок в научных статьях, переводить, объяснять код -[Настройка горячих клавиш](https://www.bilibili.com/video/BV14s4y1E7jN) | Поддержка настройки горячих клавиш -Модульный дизайн | Поддержка настраиваемых мощных [плагинов](https://github.com/binary-husky/gpt_academic/tree/master/crazy_functions), плагины поддерживают [горячую замену](https://github.com/binary-husky/gpt_academic/wiki/%E5%87%BD%E6%95%B0%E6%8F%92%E4%BB%B6%E6%8C%87%E5%8D%97) -[Профилирование кода](https://www.bilibili.com/video/BV1cj411A7VW) | [Плагин] Одним нажатием можно профилировать дерево проекта Python/C/C++/Java/Lua/... или [проанализировать самого себя](https://www.bilibili.com/video/BV1cj411A7VW) -Просмотр статей, перевод статей | [Плагин] Одним нажатием прочитать полный текст статьи в формате LaTeX/PDF и сгенерировать аннотацию -Перевод LaTeX статей, [улучшение](https://www.bilibili.com/video/BV1FT411H7c5/)| [Плагин] Одним нажатием перевести или улучшить статьи в формате LaTeX -Генерация пакетного комментария | [Плагин] Одним нажатием сгенерировать многострочный комментарий к функции -Перевод Markdown на английский и китайский | [Плагин] Вы видели документацию на сверху на пяти языках? [README](https://github.com/binary-husky/gpt_academic/blob/master/docs/README_EN.md)` -Анализ и создание отчета в формате чата | [Плагин] Автоматически генерируйте сводный отчет после выполнения -Функция перевода полноценной PDF статьи | [Плагин] Изъять название и аннотацию статьи из PDF + переводить полный текст (многопоточно) -[Arxiv помощник](https://www.bilibili.com/video/BV1LM4y1279X) | [Плагин] Просто введите URL статьи на arXiv, чтобы одним нажатием выполнить перевод аннотации + загрузить PDF -Одним кликом проверить статью на LaTeX | [Плагин] Проверка грамматики и правописания статьи LaTeX, добавление PDF в качестве справки -[Помощник Google Scholar](https://www.bilibili.com/video/BV19L411U7ia) | [Плагин] Создайте "related works" с помощью Google Scholar URL по вашему выбору. -Агрегирование интернет-информации + GPT | [Плагин] [GPT получает информацию из интернета](https://www.bilibili.com/video/BV1om4y127ck) и отвечает на вопросы, чтобы информация никогда не устаревала -⭐Точный перевод статей Arxiv ([Docker](https://github.com/binary-husky/gpt_academic/pkgs/container/gpt_academic_with_latex)) | [Плагин] [Переводите статьи Arxiv наивысшего качества](https://www.bilibili.com/video/BV1dz4y1v77A/) всего одним нажатием. Сейчас это лучший инструмент для перевода научных статей -⭐[Реальное время ввода голосом](https://github.com/binary-husky/gpt_academic/blob/master/docs/use_audio.md) | [Плагин] Асинхронно [слушать аудио](https://www.bilibili.com/video/BV1AV4y187Uy/), автоматически разбивать на предложения, автоматически находить момент для ответа -Отображение формул/изображений/таблиц | Поддержка отображения формул в форме [tex и рендеринга](https://user-images.githubusercontent.com/96192199/230598842-1d7fcddd-815d-40ee-af60-baf488a199df.png), поддержка подсветки синтаксиса формул и кода -⭐Плагин AutoGen для множества интеллектуальных агентов | [Плагин] Используйте Microsoft AutoGen для исследования возможностей интеллектуального всплытия нескольких агентов! -Запуск [темной темы](https://github.com/binary-husky/gpt_academic/issues/173) | Добавьте `/?__theme=dark` в конец URL в браузере, чтобы переключиться на темную тему -[Поддержка нескольких моделей LLM](https://www.bilibili.com/video/BV1wT411p7yf) | Быть обслуживаемым GPT3.5, GPT4, [ChatGLM2 из Цинхуа](https://github.com/THUDM/ChatGLM2-6B), [MOSS из Фуданя](https://github.com/OpenLMLab/MOSS) одновременно должно быть очень приятно, не так ли? -⭐Модель ChatGLM2 Fine-tune | Поддержка загрузки модели ChatGLM2 Fine-tune, предоставляет вспомогательный плагин ChatGLM2 Fine-tune -Больше моделей LLM, поддержка [развертывания huggingface](https://huggingface.co/spaces/qingxu98/gpt-academic) | Включение интерфейса Newbing (новый Bing), введение поддержки китайских [Jittorllms](https://github.com/Jittor/JittorLLMs) для поддержки [LLaMA](https://github.com/facebookresearch/llama) и [Panguα](https://openi.org.cn/pangu/) -⭐Пакет pip [void-terminal](https://github.com/binary-husky/void-terminal) | Без GUI вызывайте все функциональные плагины этого проекта прямо из Python (разрабатывается) -⭐Плагин пустого терминала | [Плагин] Используя естественный язык, напрямую распоряжайтесь другими плагинами этого проекта -Больше новых функций (генерация изображений и т. д.) ... | Смотрите в конце этого документа ... -
- - -- Новый интерфейс (изменение опции LAYOUT в `config.py` позволяет переключиться между "расположением слева и справа" и "расположением сверху и снизу") -
- -
- - -- Все кнопки генерируются динамически на основе `functional.py` и могут быть свободно дополнены, освобождая буфер обмена -
- -
- -- Улучшение/исправление -
- -
- - - -- Если вывод содержит формулы, они отображаются одновременно в виде tex и отрендеренного вида для удобства копирования и чтения -
- -
- -- Не хочешь смотреть код проекта? Весь проект сразу в уста ChatGPT -
- -
- -- Смешанное использование нескольких больших языковых моделей (ChatGLM + OpenAI-GPT3.5 + [API2D](https://api2d.com/)-GPT4) -
- -
- -# Установка -### Метод установки I: Прямой запуск (Windows, Linux или MacOS) - -1. Скачайте проект -```sh -git clone --depth=1 https://github.com/binary-husky/gpt_academic.git -cd gpt_academic -``` - -2. Настройте API_KEY - -В файле `config.py` настройте API KEY и другие настройки, [нажмите здесь, чтобы узнать способы настройки в специальных сетевых средах](https://github.com/binary-husky/gpt_academic/issues/1). [Инструкции по настройке проекта](https://github.com/binary-husky/gpt_academic/wiki/Сonfig-Instructions). - -「 Программа будет в первую очередь проверять наличие файла config_private.py с приватными настройками и заменять соответствующие настройки в файле config.py на те, которые указаны в файле config_private.py. Если вы понимаете эту логику, мы настоятельно рекомендуем вам создать новый файл настроек config_private.py рядом с файлом config.py и скопировать туда настройки из config.py (только те, которые вы изменяли). 」 - -「 Поддерживается настроить проект с помощью `переменных среды`. Пример настройки переменных среды можно найти в файле docker-compose.yml или на нашей [странице вики](https://github.com/binary-husky/gpt_academic/wiki/Сonfig-Instructions). Приоритет настроек: `переменные среды` > `config_private.py` > `config.py`. 」 - - -3. Установите зависимости -```sh -# (Выбор I: Если знакомы с Python, python>=3.9). Примечание: используйте официальный pip-репозиторий или пакетный репозиторий Alibaba, временный способ изменить источник: python -m pip install -r requirements.txt -i https://mirrors.aliyun.com/pypi/simple/ -python -m pip install -r requirements.txt - -# (Выбор II: Используйте Anaconda). Шаги аналогичны (https://www.bilibili.com/video/BV1rc411W7Dr): -conda create -n gptac_venv python=3.11 # Создание среды Anaconda -conda activate gptac_venv # Активация среды Anaconda -python -m pip install -r requirements.txt # Здесь все тоже самое, что и с установкой для pip -``` - - -
Если вам нужна поддержка ChatGLM2 от Цинхуа/MOSS от Фуданя/Раннера RWKV как бэкенда, нажмите, чтобы развернуть -

- -【Опциональный шаг】Если вам нужна поддержка ChatGLM2 от Цинхуа/Сервиса MOSS от Фуданя, вам понадобится дополнительно установить дополнительные зависимости (предполагается, что вы знакомы с Python + PyTorch + у вас достаточно мощный компьютер): -```sh -# 【Опциональный шаг I】Поддержка ChatGLM2 от Цинхуа. Примечание к ChatGLM от Цинхуа: Если вы столкнулись с ошибкой "Call ChatGLM fail 不能正常加载ChatGLM的参数", обратите внимание на следующее: 1: По умолчанию установлена версия torch+cpu, для использования cuda необходимо удалить torch и установить версию torch+cuda; 2: Если вы не можете загрузить модель из-за недостаточной мощности компьютера, вы можете изменить точность модели в файле request_llm/bridge_chatglm.py, заменив AutoTokenizer.from_pretrained("THUDM/chatglm-6b", trust_remote_code=True) на AutoTokenizer.from_pretrained("THUDM/chatglm-6b-int4", trust_remote_code=True) -python -m pip install -r request_llms/requirements_chatglm.txt - -# 【Опциональный шаг II】Поддержка MOSS от Фуданя -python -m pip install -r request_llms/requirements_moss.txt -git clone --depth=1 https://github.com/OpenLMLab/MOSS.git request_llms/moss # Обратите внимание, что когда вы запускаете эту команду, вы должны находиться в корневой папке проекта - -# 【Опциональный шаг III】Поддержка RWKV Runner -Смотрите вики: https://github.com/binary-husky/gpt_academic/wiki/Поддержка-RWKV-Runner - -# 【Опциональный шаг IV】Убедитесь, что config.py содержит все нужные вам модели. Пример: -AVAIL_LLM_MODELS = ["gpt-3.5-turbo", "api2d-gpt-3.5-turbo", "gpt-4", "api2d-gpt-4", "chatglm", "moss"] # + ["jittorllms_rwkv", "jittorllms_pangualpha", "jittorllms_llama"] -``` - -

-
- - - -4. Запустите программу -```sh -python main.py -``` - -### Метод установки II: Используйте Docker - -0. Установка всех возможностей проекта (это большой образ с поддержкой cuda и LaTeX; но если у вас медленный интернет или маленький жесткий диск, мы не рекомендуем использовать этот метод). -[![fullcapacity](https://github.com/binary-husky/gpt_academic/actions/workflows/build-with-all-capacity.yml/badge.svg?branch=master)](https://github.com/binary-husky/gpt_academic/actions/workflows/build-with-all-capacity.yml) - -``` sh -# Измените файл docker-compose.yml, сохраните метод 0 и удалите другие методы. Затем запустите: -docker-compose up -``` - -1. Чат GPT + 文心一言 + Spark и другие онлайн-модели (рекомендуется для большинства пользователей) -[![basic](https://github.com/binary-husky/gpt_academic/actions/workflows/build-without-local-llms.yml/badge.svg?branch=master)](https://github.com/binary-husky/gpt_academic/actions/workflows/build-without-local-llms.yml) -[![basiclatex](https://github.com/binary-husky/gpt_academic/actions/workflows/build-with-latex.yml/badge.svg?branch=master)](https://github.com/binary-husky/gpt_academic/actions/workflows/build-with-latex.yml) -[![basicaudio](https://github.com/binary-husky/gpt_academic/actions/workflows/build-with-audio-assistant.yml/badge.svg?branch=master)](https://github.com/binary-husky/gpt_academic/actions/workflows/build-with-audio-assistant.yml) - -``` sh -# Измените файл docker-compose.yml, сохраните метод 1 и удалите другие методы. Затем запустите: -docker-compose up -``` - -P.S. Если вам нужен функционал, связанный с LaTeX, обратитесь к разделу Wiki. Кроме того, вы также можете использовать схему 4 или схему 0 для доступа к функционалу LaTeX. - -2. Чат GPT + ChatGLM2 + MOSS + LLAMA2 + TakyiQ & Другие попытки ввести в обиход -[![chatglm](https://github.com/binary-husky/gpt_academic/actions/workflows/build-with-chatglm.yml/badge.svg?branch=master)](https://github.com/binary-husky/gpt_academic/actions/workflows/build-with-chatglm.yml) - -``` sh -# Измените файл docker-compose.yml, сохраните метод 2 и удалите другие методы. Затем запустите: -docker-compose up -``` - - -### Метод установки III: Другие способы развертывания -1. **Скрипты запуска одним нажатием для Windows**. -Пользователи Windows, не знакомые с окружением Python, могут загрузить одну из версий в разделе [Релизы](https://github.com/binary-husky/gpt_academic/releases) для установки версии без локальных моделей. -Скрипты взяты из вкладки [oobabooga](https://github.com/oobabooga/one-click-installers). - -2. Использование сторонних API, Azure и т. д., см. страницу [вики](https://github.com/binary-husky/gpt_academic/wiki/Сonfig-Instructions) - -3. Руководство по развертыванию на удаленном сервере. -Пожалуйста, посетите [вики-страницу развертывания на облачном сервере](https://github.com/binary-husky/gpt_academic/wiki/Руководство-по-развертыванию-на-облаке). - -4. Некоторые новые платформы или методы развертывания - - Использование Sealos [для однократного развертывания](https://github.com/binary-husky/gpt_academic/issues/993) - - Использование WSL2 (Windows Subsystem for Linux). См. [Руководство развертывания-2](https://github.com/binary-husky/gpt_academic/wiki/Using-WSL2-for-deployment) - - Как запустить на вложенном URL-адресе (например, `http://localhost/subpath`). См. [Инструкции по работе с FastAPI](docs/WithFastapi.md) - - - -# Расширенное использование -### I: Пользовательские удобные кнопки (академические сочетания клавиш) -Откройте файл `core_functional.py` в любом текстовом редакторе и добавьте следующие записи, затем перезапустите программу. (Если кнопка уже существует, то префикс и суффикс поддерживают горячую замену без перезапуска программы.) -Например, -``` -"Супер-англо-русский перевод": { - # Префикс, который будет добавлен перед вашим вводом. Например, используется для описания вашего запроса, например, перевода, объяснения кода, редактирования и т.д. - "Префикс": "Пожалуйста, переведите следующий абзац на русский язык, а затем покажите каждый термин на экране с помощью таблицы Markdown:\n\n", - - # Суффикс, который будет добавлен после вашего ввода. Например, можно использовать с префиксом, чтобы заключить ваш ввод в кавычки. - "Суффикс": "", -}, -``` -
- -
- -### II: Пользовательские функциональные плагины -Создавайте мощные функциональные плагины для выполнения любых задач, которые вам нужны и которых вы и не можете себе представить. -Создание плагина для этого проекта и его отладка являются простыми задачами, и если у вас есть базовые знания Python, вы можете реализовать свой собственный функциональный плагин, используя наши предоставленные шаблоны. -Дополнительную информацию см. в [Руководстве по функциональным плагинам](https://github.com/binary-husky/gpt_academic/wiki/%E5%87%BD%E6%95%B0%E6%8F%92%E4%BB%B6%E6%8C%87%E5%8D%97). - - -# Обновления -### I: Динамические - -1. Функция сохранения диалога. Вызовите "Сохранить текущий диалог" в области функциональных плагинов, чтобы сохранить текущий диалог в виде читаемого и восстанавливаемого html-файла. -Кроме того, можно использовать "Загрузить архивный файл диалога" в области функциональных плагинов (выпадающее меню), чтобы восстановить предыдущий разговор. -Подсказка: если не указывать файл и просто щелкнуть "Загрузить архивный файл диалога", можно просмотреть кэш сохраненных html-архивов. -
- -
- -2. ⭐Перевод Latex/Arxiv статей⭐ -
- ===> - -
- -3. Void Terminal (понимание пользовательских намерений из естественного языка и автоматическое вызов других плагинов) - -- Шаг 1: Введите "Пожалуйста, вызовите плагин для перевода PDF-статьи, адрес которой https://openreview.net/pdf?id=rJl0r3R9KX". -- Шаг 2: Нажмите "Void Terminal". - -
- -
- -4. Модульный дизайн функционала, позволяющий реализовать мощные функции с помощью простых интерфейсов -
- - -
- -5. Перевод и анализ других открытых проектов -
- - -
- -6. Функциональность для украшения[meme](https://github.com/fghrsh/live2d_demo) (по умолчанию отключена, требуется изменение файла `config.py`) -
- -
- -7. Генерация изображений с помощью OpenAI -
- -
- -8. Анализ и обобщение аудио с помощью OpenAI -
- -
- -9. Проверка и исправление ошибок во всем тексте LaTeX -
- ===> - -
- -10. Изменение языка и темы -
- -
- - - -### II: Версии: -- Версия 3.70 (в планах): Оптимизация темы AutoGen и разработка ряда дополнительных плагинов -- Версия 3.60: Внедрение AutoGen в качестве фундамента нового поколения плагинов -- Версия 3.57: Поддержка GLM3, Starfire v3, Wenxin One Word v4, исправление ошибок при совместном использовании локальной модели -- Версия 3.56: Поддержка добавления дополнительных функциональных кнопок в реальном времени, новая страница отчетов в формате PDF -- Версия 3.55: Переработка пользовательского интерфейса, внедрение плавающего окна и панели меню -- Версия 3.54: Добавлен интерпретатор кода (Code Interpreter) (в разработке) -- Версия 3.53: Динамический выбор различных тем интерфейса, повышение стабильности и решение проблемы конфликтов между несколькими пользователями -- Версия 3.50: Использование естественного языка для вызова всех функциональных плагинов проекта (Void Terminal), поддержка категоризации плагинов, улучшение пользовательского интерфейса, разработка новых тем -- Версия 3.49: Поддержка платформы Baidu Qianfan и Wenxin One Word -- Версия 3.48: Поддержка Ali Dharma Institute, Shanghai AI-Lab Scholar, Xunfei Starfire -- Версия 3.46: Поддержка реального голосового диалога с полной автоматизацией -- Версия 3.45: Поддержка настраиваемой модели ChatGLM2 -- Версия 3.44: Официальная поддержка Azure, улучшение удобства пользовательского интерфейса -- Версия 3.4: +Перевод полных текстов PDF, +корректировка латексных документов -- Версия 3.3: +Интернет-информационные функции -- Версия 3.2: Поддержка дополнительных параметров в функциональных плагинах (функция сохранения диалога, интерпретация кода на любом языке + одновременный вопрос о любом комбинированном LLM) -- Версия 3.1: Поддержка одновременного обращения к нескольким моделям gpt! Поддержка API2D, поддержка равномерной нагрузки нескольких api-ключей -- Версия 3.0: Поддержка chatglm и других небольших моделей llm -- Версия 2.6: Переработка структуры плагинов для повышения интерактивности, добавление дополнительных плагинов -- Версия 2.5: Автоматическое обновление, решение проблемы с длиной текста и переполнением токенов при обработке текста -- Версия 2.4: (1) Добавление функции полного перевода PDF; (2) Добавление функции изменения позиции объекта ввода; (3) Добавление функции вертикального размещения; (4) Оптимизация многопоточных функциональных плагинов. -- Версия 2.3: Улучшение интерактивности многопоточности -- Версия 2.2: Поддержка живой перезагрузки функциональных плагинов -- Версия 2.1: Складываемый макет -- Версия 2.0: Введение модульных функциональных плагинов -- Версия 1.0: Базовые функции - -GPT Academic Группа QQ разработчиков: `610599535` - -- Известные проблемы - - Некоторые расширения для браузера могут мешать работе пользовательского интерфейса этого программного обеспечения - - У официального Gradio есть много проблем совместимости, поэтому обязательно установите Gradio с помощью `requirement.txt` - -### III: Темы -Вы можете изменить тему путем изменения опции `THEME` (config.py) -1. `Chuanhu-Small-and-Beautiful` [ссылка](https://github.com/GaiZhenbiao/ChuanhuChatGPT/) - - -### IV: Ветви разработки этого проекта - -1. Ветка `master`: Основная ветка, стабильная версия -2. Ветвь `frontier`: Ветвь разработки, версия для тестирования - - -### V: Справочники и обучение - -``` -В коде использовались многие функции, представленные в других отличных проектах, поэтому их порядок не имеет значения: - -# ChatGLM2-6B от Тиньхуа: -https://github.com/THUDM/ChatGLM2-6B - -# Линейные модели с ограниченной памятью от Тиньхуа: -https://github.com/Jittor/JittorLLMs - -# ChatPaper: -https://github.com/kaixindelele/ChatPaper - -# Edge-GPT: -https://github.com/acheong08/EdgeGPT - -# ChuanhuChatGPT: -https://github.com/GaiZhenbiao/ChuanhuChatGPT - - - -# Установщик с одним щелчком Oobabooga: -https://github.com/oobabooga/one-click-installers - -# Больше: -https://github.com/gradio-app/gradio -https://github.com/fghrsh/live2d_demo diff --git a/docs/WithFastapi.md b/docs/WithFastapi.md index 270375076a6d0cdae568180c48a619a40f3c0ccd..188b52716485f15e528772c6454ee7839ced4406 100644 --- a/docs/WithFastapi.md +++ b/docs/WithFastapi.md @@ -16,19 +16,19 @@ nano config.py + demo.queue(concurrency_count=CONCURRENT_COUNT) - # 如果需要在二级路径下运行 - - # CUSTOM_PATH = get_conf('CUSTOM_PATH') - - # if CUSTOM_PATH != "/": + - # CUSTOM_PATH, = get_conf('CUSTOM_PATH') + - # if CUSTOM_PATH != "/": - # from toolbox import run_gradio_in_subpath - # run_gradio_in_subpath(demo, auth=AUTHENTICATION, port=PORT, custom_path=CUSTOM_PATH) - - # else: + - # else: - # demo.launch(server_name="0.0.0.0", server_port=PORT, auth=AUTHENTICATION, favicon_path="docs/logo.png") + 如果需要在二级路径下运行 - + CUSTOM_PATH = get_conf('CUSTOM_PATH') - + if CUSTOM_PATH != "/": + + CUSTOM_PATH, = get_conf('CUSTOM_PATH') + + if CUSTOM_PATH != "/": + from toolbox import run_gradio_in_subpath + run_gradio_in_subpath(demo, auth=AUTHENTICATION, port=PORT, custom_path=CUSTOM_PATH) - + else: + + else: + demo.launch(server_name="0.0.0.0", server_port=PORT, auth=AUTHENTICATION, favicon_path="docs/logo.png") if __name__ == "__main__": diff --git a/docs/self_analysis.md b/docs/self_analysis.md index e34b905d7bb93ee6af9c730aef23052323c0489e..ebc2337194974bf210794df7d858889010fecf08 100644 --- a/docs/self_analysis.md +++ b/docs/self_analysis.md @@ -38,20 +38,20 @@ | crazy_functions\读文章写摘要.py | 对论文进行解析和全文摘要生成 | | crazy_functions\谷歌检索小助手.py | 提供谷歌学术搜索页面中相关文章的元数据信息。 | | crazy_functions\高级功能函数模板.py | 使用Unsplash API发送相关图片以回复用户的输入。 | -| request_llms\bridge_all.py | 基于不同LLM模型进行对话。 | -| request_llms\bridge_chatglm.py | 使用ChatGLM模型生成回复,支持单线程和多线程方式。 | -| request_llms\bridge_chatgpt.py | 基于GPT模型完成对话。 | -| request_llms\bridge_jittorllms_llama.py | 使用JittorLLMs模型完成对话,支持单线程和多线程方式。 | -| request_llms\bridge_jittorllms_pangualpha.py | 使用JittorLLMs模型完成对话,基于多进程和多线程方式。 | -| request_llms\bridge_jittorllms_rwkv.py | 使用JittorLLMs模型完成聊天功能,提供包括历史信息、参数调节等在内的多个功能选项。 | -| request_llms\bridge_moss.py | 加载Moss模型完成对话功能。 | -| request_llms\bridge_newbing.py | 使用Newbing聊天机器人进行对话,支持单线程和多线程方式。 | -| request_llms\bridge_newbingfree.py | 基于Bing chatbot API实现聊天机器人的文本生成功能。 | -| request_llms\bridge_stackclaude.py | 基于Slack API实现Claude与用户的交互。 | -| request_llms\bridge_tgui.py | 通过websocket实现聊天机器人与UI界面交互。 | -| request_llms\edge_gpt.py | 调用Bing chatbot API提供聊天机器人服务。 | -| request_llms\edge_gpt_free.py | 实现聊天机器人API,采用aiohttp和httpx工具库。 | -| request_llms\test_llms.py | 对llm模型进行单元测试。 | +| request_llm\bridge_all.py | 基于不同LLM模型进行对话。 | +| request_llm\bridge_chatglm.py | 使用ChatGLM模型生成回复,支持单线程和多线程方式。 | +| request_llm\bridge_chatgpt.py | 基于GPT模型完成对话。 | +| request_llm\bridge_jittorllms_llama.py | 使用JittorLLMs模型完成对话,支持单线程和多线程方式。 | +| request_llm\bridge_jittorllms_pangualpha.py | 使用JittorLLMs模型完成对话,基于多进程和多线程方式。 | +| request_llm\bridge_jittorllms_rwkv.py | 使用JittorLLMs模型完成聊天功能,提供包括历史信息、参数调节等在内的多个功能选项。 | +| request_llm\bridge_moss.py | 加载Moss模型完成对话功能。 | +| request_llm\bridge_newbing.py | 使用Newbing聊天机器人进行对话,支持单线程和多线程方式。 | +| request_llm\bridge_newbingfree.py | 基于Bing chatbot API实现聊天机器人的文本生成功能。 | +| request_llm\bridge_stackclaude.py | 基于Slack API实现Claude与用户的交互。 | +| request_llm\bridge_tgui.py | 通过websocket实现聊天机器人与UI界面交互。 | +| request_llm\edge_gpt.py | 调用Bing chatbot API提供聊天机器人服务。 | +| request_llm\edge_gpt_free.py | 实现聊天机器人API,采用aiohttp和httpx工具库。 | +| request_llm\test_llms.py | 对llm模型进行单元测试。 | ## 接下来请你逐文件分析下面的工程[0/48] 请对下面的程序文件做一个概述: check_proxy.py @@ -129,7 +129,7 @@ toolbox.py是一个工具类库,其中主要包含了一些函数装饰器和 1. `input_clipping`: 该函数用于裁剪输入文本长度,使其不超过一定的限制。 2. `request_gpt_model_in_new_thread_with_ui_alive`: 该函数用于请求 GPT 模型并保持用户界面的响应,支持多线程和实时更新用户界面。 -这两个函数都依赖于从 `toolbox` 和 `request_llms` 中导入的一些工具函数。函数的输入和输出有详细的描述文档。 +这两个函数都依赖于从 `toolbox` 和 `request_llm` 中导入的一些工具函数。函数的输入和输出有详细的描述文档。 ## [12/48] 请对下面的程序文件做一个概述: crazy_functions\Latex全文润色.py @@ -137,7 +137,7 @@ toolbox.py是一个工具类库,其中主要包含了一些函数装饰器和 ## [13/48] 请对下面的程序文件做一个概述: crazy_functions\Latex全文翻译.py -这个文件包含两个函数 `Latex英译中` 和 `Latex中译英`,它们都会对整个Latex项目进行翻译。这个文件还包含一个类 `PaperFileGroup`,它拥有一个方法 `run_file_split`,用于把长文本文件分成多个短文件。其中使用了工具库 `toolbox` 中的一些函数和从 `request_llms` 中导入了 `model_info`。接下来的函数把文件读取进来,把它们的注释删除,进行分割,并进行翻译。这个文件还包括了一些异常处理和界面更新的操作。 +这个文件包含两个函数 `Latex英译中` 和 `Latex中译英`,它们都会对整个Latex项目进行翻译。这个文件还包含一个类 `PaperFileGroup`,它拥有一个方法 `run_file_split`,用于把长文本文件分成多个短文件。其中使用了工具库 `toolbox` 中的一些函数和从 `request_llm` 中导入了 `model_info`。接下来的函数把文件读取进来,把它们的注释删除,进行分割,并进行翻译。这个文件还包括了一些异常处理和界面更新的操作。 ## [14/48] 请对下面的程序文件做一个概述: crazy_functions\__init__.py @@ -165,7 +165,7 @@ toolbox.py是一个工具类库,其中主要包含了一些函数装饰器和 3. read_file_to_chat(chatbot, history, file_name):从传入的文件中读取内容,解析出对话历史记录并更新聊天显示框。 -4. 对话历史存档(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request):一个主要函数,用于保存当前对话记录并提醒用户。如果用户希望加载历史记录,则调用read_file_to_chat()来更新聊天显示框。如果用户希望删除历史记录,调用删除所有本地对话历史记录()函数完成删除操作。 +4. 对话历史存档(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port):一个主要函数,用于保存当前对话记录并提醒用户。如果用户希望加载历史记录,则调用read_file_to_chat()来更新聊天显示框。如果用户希望删除历史记录,调用删除所有本地对话历史记录()函数完成删除操作。 ## [19/48] 请对下面的程序文件做一个概述: crazy_functions\总结word文档.py @@ -217,7 +217,7 @@ toolbox.py是一个工具类库,其中主要包含了一些函数装饰器和 ## [31/48] 请对下面的程序文件做一个概述: crazy_functions\读文章写摘要.py -这个程序文件是一个Python模块,文件名为crazy_functions\读文章写摘要.py。该模块包含了两个函数,其中主要函数是"读文章写摘要"函数,其实现了解析给定文件夹中的tex文件,对其中每个文件的内容进行摘要生成,并根据各论文片段的摘要,最终生成全文摘要。第二个函数是"解析Paper"函数,用于解析单篇论文文件。其中用到了一些工具函数和库,如update_ui、CatchException、report_exception、write_results_to_file等。 +这个程序文件是一个Python模块,文件名为crazy_functions\读文章写摘要.py。该模块包含了两个函数,其中主要函数是"读文章写摘要"函数,其实现了解析给定文件夹中的tex文件,对其中每个文件的内容进行摘要生成,并根据各论文片段的摘要,最终生成全文摘要。第二个函数是"解析Paper"函数,用于解析单篇论文文件。其中用到了一些工具函数和库,如update_ui、CatchException、report_execption、write_results_to_file等。 ## [32/48] 请对下面的程序文件做一个概述: crazy_functions\谷歌检索小助手.py @@ -227,19 +227,19 @@ toolbox.py是一个工具类库,其中主要包含了一些函数装饰器和 该程序文件定义了一个名为高阶功能模板函数的函数,该函数接受多个参数,包括输入的文本、gpt模型参数、插件模型参数、聊天显示框的句柄、聊天历史等,并利用送出请求,使用 Unsplash API 发送相关图片。其中,为了避免输入溢出,函数会在开始时清空历史。函数也有一些 UI 更新的语句。该程序文件还依赖于其他两个模块:CatchException 和 update_ui,以及一个名为 request_gpt_model_in_new_thread_with_ui_alive 的来自 crazy_utils 模块(应该是自定义的工具包)的函数。 -## [34/48] 请对下面的程序文件做一个概述: request_llms\bridge_all.py +## [34/48] 请对下面的程序文件做一个概述: request_llm\bridge_all.py 该文件包含两个函数:predict和predict_no_ui_long_connection,用于基于不同的LLM模型进行对话。该文件还包含一个lazyloadTiktoken类和一个LLM_CATCH_EXCEPTION修饰器函数。其中lazyloadTiktoken类用于懒加载模型的tokenizer,LLM_CATCH_EXCEPTION用于错误处理。整个文件还定义了一些全局变量和模型信息字典,用于引用和配置LLM模型。 -## [35/48] 请对下面的程序文件做一个概述: request_llms\bridge_chatglm.py +## [35/48] 请对下面的程序文件做一个概述: request_llm\bridge_chatglm.py 这是一个Python程序文件,名为`bridge_chatglm.py`,其中定义了一个名为`GetGLMHandle`的类和三个方法:`predict_no_ui_long_connection`、 `predict`和 `stream_chat`。该文件依赖于多个Python库,如`transformers`和`sentencepiece`。该文件实现了一个聊天机器人,使用ChatGLM模型来生成回复,支持单线程和多线程方式。程序启动时需要加载ChatGLM的模型和tokenizer,需要一段时间。在配置文件`config.py`中设置参数会影响模型的内存和显存使用,因此程序可能会导致低配计算机卡死。 -## [36/48] 请对下面的程序文件做一个概述: request_llms\bridge_chatgpt.py +## [36/48] 请对下面的程序文件做一个概述: request_llm\bridge_chatgpt.py -该文件为 Python 代码文件,文件名为 request_llms\bridge_chatgpt.py。该代码文件主要提供三个函数:predict、predict_no_ui和 predict_no_ui_long_connection,用于发送至 chatGPT 并等待回复,获取输出。该代码文件还包含一些辅助函数,用于处理连接异常、生成 HTTP 请求等。该文件的代码架构清晰,使用了多个自定义函数和模块。 +该文件为 Python 代码文件,文件名为 request_llm\bridge_chatgpt.py。该代码文件主要提供三个函数:predict、predict_no_ui和 predict_no_ui_long_connection,用于发送至 chatGPT 并等待回复,获取输出。该代码文件还包含一些辅助函数,用于处理连接异常、生成 HTTP 请求等。该文件的代码架构清晰,使用了多个自定义函数和模块。 -## [37/48] 请对下面的程序文件做一个概述: request_llms\bridge_jittorllms_llama.py +## [37/48] 请对下面的程序文件做一个概述: request_llm\bridge_jittorllms_llama.py 该代码文件实现了一个聊天机器人,其中使用了 JittorLLMs 模型。主要包括以下几个部分: 1. GetGLMHandle 类:一个进程类,用于加载 JittorLLMs 模型并接收并处理请求。 @@ -248,17 +248,17 @@ toolbox.py是一个工具类库,其中主要包含了一些函数装饰器和 这个文件中还有一些辅助函数和全局变量,例如 importlib、time、threading 等。 -## [38/48] 请对下面的程序文件做一个概述: request_llms\bridge_jittorllms_pangualpha.py +## [38/48] 请对下面的程序文件做一个概述: request_llm\bridge_jittorllms_pangualpha.py 这个文件是为了实现使用jittorllms(一种机器学习模型)来进行聊天功能的代码。其中包括了模型加载、模型的参数加载、消息的收发等相关操作。其中使用了多进程和多线程来提高性能和效率。代码中还包括了处理依赖关系的函数和预处理函数等。 -## [39/48] 请对下面的程序文件做一个概述: request_llms\bridge_jittorllms_rwkv.py +## [39/48] 请对下面的程序文件做一个概述: request_llm\bridge_jittorllms_rwkv.py 这个文件是一个Python程序,文件名为request_llm\bridge_jittorllms_rwkv.py。它依赖transformers、time、threading、importlib、multiprocessing等库。在文件中,通过定义GetGLMHandle类加载jittorllms模型参数和定义stream_chat方法来实现与jittorllms模型的交互。同时,该文件还定义了predict_no_ui_long_connection和predict方法来处理历史信息、调用jittorllms模型、接收回复信息并输出结果。 -## [40/48] 请对下面的程序文件做一个概述: request_llms\bridge_moss.py +## [40/48] 请对下面的程序文件做一个概述: request_llm\bridge_moss.py -该文件为一个Python源代码文件,文件名为 request_llms\bridge_moss.py。代码定义了一个 GetGLMHandle 类和两个函数 predict_no_ui_long_connection 和 predict。 +该文件为一个Python源代码文件,文件名为 request_llm\bridge_moss.py。代码定义了一个 GetGLMHandle 类和两个函数 predict_no_ui_long_connection 和 predict。 GetGLMHandle 类继承自Process类(多进程),主要功能是启动一个子进程并加载 MOSS 模型参数,通过 Pipe 进行主子进程的通信。该类还定义了 check_dependency、moss_init、run 和 stream_chat 等方法,其中 check_dependency 和 moss_init 是子进程的初始化方法,run 是子进程运行方法,stream_chat 实现了主进程和子进程的交互过程。 @@ -266,7 +266,7 @@ GetGLMHandle 类继承自Process类(多进程),主要功能是启动一个 函数 predict 是单线程方法,通过调用 update_ui 将交互过程中 MOSS 的回复实时更新到UI(User Interface)中,并执行一个 named function(additional_fn)指定的函数对输入进行预处理。 -## [41/48] 请对下面的程序文件做一个概述: request_llms\bridge_newbing.py +## [41/48] 请对下面的程序文件做一个概述: request_llm\bridge_newbing.py 这是一个名为`bridge_newbing.py`的程序文件,包含三个部分: @@ -276,11 +276,11 @@ GetGLMHandle 类继承自Process类(多进程),主要功能是启动一个 第三部分定义了一个名为`newbing_handle`的全局变量,并导出了`predict_no_ui_long_connection`和`predict`这两个方法,以供其他程序可以调用。 -## [42/48] 请对下面的程序文件做一个概述: request_llms\bridge_newbingfree.py +## [42/48] 请对下面的程序文件做一个概述: request_llm\bridge_newbingfree.py 这个Python文件包含了三部分内容。第一部分是来自edge_gpt_free.py文件的聊天机器人程序。第二部分是子进程Worker,用于调用主体。第三部分提供了两个函数:predict_no_ui_long_connection和predict用于调用NewBing聊天机器人和返回响应。其中predict函数还提供了一些参数用于控制聊天机器人的回复和更新UI界面。 -## [43/48] 请对下面的程序文件做一个概述: request_llms\bridge_stackclaude.py +## [43/48] 请对下面的程序文件做一个概述: request_llm\bridge_stackclaude.py 这是一个Python源代码文件,文件名为request_llm\bridge_stackclaude.py。代码分为三个主要部分: @@ -290,21 +290,21 @@ GetGLMHandle 类继承自Process类(多进程),主要功能是启动一个 第三部分定义了predict_no_ui_long_connection和predict两个函数,主要用于通过调用ClaudeHandle对象的stream_chat方法来获取Claude的回复,并更新ui以显示相关信息。其中predict函数采用单线程方法,而predict_no_ui_long_connection函数使用多线程方法。 -## [44/48] 请对下面的程序文件做一个概述: request_llms\bridge_tgui.py +## [44/48] 请对下面的程序文件做一个概述: request_llm\bridge_tgui.py 该文件是一个Python代码文件,名为request_llm\bridge_tgui.py。它包含了一些函数用于与chatbot UI交互,并通过WebSocket协议与远程LLM模型通信完成文本生成任务,其中最重要的函数是predict()和predict_no_ui_long_connection()。这个程序还有其他的辅助函数,如random_hash()。整个代码文件在协作的基础上完成了一次修改。 -## [45/48] 请对下面的程序文件做一个概述: request_llms\edge_gpt.py +## [45/48] 请对下面的程序文件做一个概述: request_llm\edge_gpt.py 该文件是一个用于调用Bing chatbot API的Python程序,它由多个类和辅助函数构成,可以根据给定的对话连接在对话中提出问题,使用websocket与远程服务通信。程序实现了一个聊天机器人,可以为用户提供人工智能聊天。 -## [46/48] 请对下面的程序文件做一个概述: request_llms\edge_gpt_free.py +## [46/48] 请对下面的程序文件做一个概述: request_llm\edge_gpt_free.py 该代码文件为一个会话API,可通过Chathub发送消息以返回响应。其中使用了 aiohttp 和 httpx 库进行网络请求并发送。代码中包含了一些函数和常量,多数用于生成请求数据或是请求头信息等。同时该代码文件还包含了一个 Conversation 类,调用该类可实现对话交互。 -## [47/48] 请对下面的程序文件做一个概述: request_llms\test_llms.py +## [47/48] 请对下面的程序文件做一个概述: request_llm\test_llms.py -这个文件是用于对llm模型进行单元测试的Python程序。程序导入一个名为"request_llms.bridge_newbingfree"的模块,然后三次使用该模块中的predict_no_ui_long_connection()函数进行预测,并输出结果。此外,还有一些注释掉的代码段,这些代码段也是关于模型预测的。 +这个文件是用于对llm模型进行单元测试的Python程序。程序导入一个名为"request_llm.bridge_newbingfree"的模块,然后三次使用该模块中的predict_no_ui_long_connection()函数进行预测,并输出结果。此外,还有一些注释掉的代码段,这些代码段也是关于模型预测的。 ## 用一张Markdown表格简要描述以下文件的功能: check_proxy.py, colorful.py, config.py, config_private.py, core_functional.py, crazy_functional.py, main.py, multi_language.py, theme.py, toolbox.py, crazy_functions\crazy_functions_test.py, crazy_functions\crazy_utils.py, crazy_functions\Latex全文润色.py, crazy_functions\Latex全文翻译.py, crazy_functions\__init__.py, crazy_functions\下载arxiv论文翻译摘要.py。根据以上分析,用一句话概括程序的整体功能。 @@ -355,24 +355,24 @@ crazy_functions\代码重写为全英文_多线程.py, crazy_functions\图片生 概括程序的整体功能:提供了一系列处理文本、文件和代码的功能,使用了各类语言模型、多线程、网络请求和数据解析技术来提高效率和精度。 ## 用一张Markdown表格简要描述以下文件的功能: -crazy_functions\谷歌检索小助手.py, crazy_functions\高级功能函数模板.py, request_llms\bridge_all.py, request_llms\bridge_chatglm.py, request_llms\bridge_chatgpt.py, request_llms\bridge_jittorllms_llama.py, request_llms\bridge_jittorllms_pangualpha.py, request_llms\bridge_jittorllms_rwkv.py, request_llms\bridge_moss.py, request_llms\bridge_newbing.py, request_llms\bridge_newbingfree.py, request_llms\bridge_stackclaude.py, request_llms\bridge_tgui.py, request_llms\edge_gpt.py, request_llms\edge_gpt_free.py, request_llms\test_llms.py。根据以上分析,用一句话概括程序的整体功能。 +crazy_functions\谷歌检索小助手.py, crazy_functions\高级功能函数模板.py, request_llm\bridge_all.py, request_llm\bridge_chatglm.py, request_llm\bridge_chatgpt.py, request_llm\bridge_jittorllms_llama.py, request_llm\bridge_jittorllms_pangualpha.py, request_llm\bridge_jittorllms_rwkv.py, request_llm\bridge_moss.py, request_llm\bridge_newbing.py, request_llm\bridge_newbingfree.py, request_llm\bridge_stackclaude.py, request_llm\bridge_tgui.py, request_llm\edge_gpt.py, request_llm\edge_gpt_free.py, request_llm\test_llms.py。根据以上分析,用一句话概括程序的整体功能。 | 文件名 | 功能描述 | | --- | --- | | crazy_functions\谷歌检索小助手.py | 提供谷歌学术搜索页面中相关文章的元数据信息。 | | crazy_functions\高级功能函数模板.py | 使用Unsplash API发送相关图片以回复用户的输入。 | -| request_llms\bridge_all.py | 基于不同LLM模型进行对话。 | -| request_llms\bridge_chatglm.py | 使用ChatGLM模型生成回复,支持单线程和多线程方式。 | -| request_llms\bridge_chatgpt.py | 基于GPT模型完成对话。 | -| request_llms\bridge_jittorllms_llama.py | 使用JittorLLMs模型完成对话,支持单线程和多线程方式。 | -| request_llms\bridge_jittorllms_pangualpha.py | 使用JittorLLMs模型完成对话,基于多进程和多线程方式。 | -| request_llms\bridge_jittorllms_rwkv.py | 使用JittorLLMs模型完成聊天功能,提供包括历史信息、参数调节等在内的多个功能选项。 | -| request_llms\bridge_moss.py | 加载Moss模型完成对话功能。 | -| request_llms\bridge_newbing.py | 使用Newbing聊天机器人进行对话,支持单线程和多线程方式。 | -| request_llms\bridge_newbingfree.py | 基于Bing chatbot API实现聊天机器人的文本生成功能。 | -| request_llms\bridge_stackclaude.py | 基于Slack API实现Claude与用户的交互。 | -| request_llms\bridge_tgui.py | 通过websocket实现聊天机器人与UI界面交互。 | -| request_llms\edge_gpt.py | 调用Bing chatbot API提供聊天机器人服务。 | -| request_llms\edge_gpt_free.py | 实现聊天机器人API,采用aiohttp和httpx工具库。 | -| request_llms\test_llms.py | 对llm模型进行单元测试。 | +| request_llm\bridge_all.py | 基于不同LLM模型进行对话。 | +| request_llm\bridge_chatglm.py | 使用ChatGLM模型生成回复,支持单线程和多线程方式。 | +| request_llm\bridge_chatgpt.py | 基于GPT模型完成对话。 | +| request_llm\bridge_jittorllms_llama.py | 使用JittorLLMs模型完成对话,支持单线程和多线程方式。 | +| request_llm\bridge_jittorllms_pangualpha.py | 使用JittorLLMs模型完成对话,基于多进程和多线程方式。 | +| request_llm\bridge_jittorllms_rwkv.py | 使用JittorLLMs模型完成聊天功能,提供包括历史信息、参数调节等在内的多个功能选项。 | +| request_llm\bridge_moss.py | 加载Moss模型完成对话功能。 | +| request_llm\bridge_newbing.py | 使用Newbing聊天机器人进行对话,支持单线程和多线程方式。 | +| request_llm\bridge_newbingfree.py | 基于Bing chatbot API实现聊天机器人的文本生成功能。 | +| request_llm\bridge_stackclaude.py | 基于Slack API实现Claude与用户的交互。 | +| request_llm\bridge_tgui.py | 通过websocket实现聊天机器人与UI界面交互。 | +| request_llm\edge_gpt.py | 调用Bing chatbot API提供聊天机器人服务。 | +| request_llm\edge_gpt_free.py | 实现聊天机器人API,采用aiohttp和httpx工具库。 | +| request_llm\test_llms.py | 对llm模型进行单元测试。 | | 程序整体功能 | 实现不同种类的聊天机器人,可以根据输入进行文本生成。 | diff --git a/docs/test_markdown_format.py b/docs/test_markdown_format.py index 8255478474a379fafd43a40278e6a8e802aae4f0..896f6f130c69f8a94d6f49feadf7091f0f23c2c9 100644 --- a/docs/test_markdown_format.py +++ b/docs/test_markdown_format.py @@ -7,27 +7,13 @@ sample = """ """ import re - def preprocess_newbing_out(s): - pattern = r"\^(\d+)\^" # 匹配^数字^ - pattern2 = r"\[(\d+)\]" # 匹配^数字^ - - def sub(m): - return "\\[" + m.group(1) + "\\]" # 将匹配到的数字作为替换值 - - result = re.sub(pattern, sub, s) # 替换操作 - if "[1]" in result: - result += ( - '


' - + "
".join( - [ - re.sub(pattern2, sub, r) - for r in result.split("\n") - if r.startswith("[") - ] - ) - + "
" - ) + pattern = r'\^(\d+)\^' # 匹配^数字^ + pattern2 = r'\[(\d+)\]' # 匹配^数字^ + sub = lambda m: '\['+m.group(1)+'\]' # 将匹配到的数字作为替换值 + result = re.sub(pattern, sub, s) # 替换操作 + if '[1]' in result: + result += '


' + "
".join([re.sub(pattern2, sub, r) for r in result.split('\n') if r.startswith('[')]) + '
' return result @@ -42,39 +28,37 @@ def close_up_code_segment_during_stream(gpt_reply): str: 返回一个新的字符串,将输出代码片段的“后面的```”补上。 """ - if "```" not in gpt_reply: + if '```' not in gpt_reply: return gpt_reply - if gpt_reply.endswith("```"): + if gpt_reply.endswith('```'): return gpt_reply # 排除了以上两个情况,我们 - segments = gpt_reply.split("```") + segments = gpt_reply.split('```') n_mark = len(segments) - 1 if n_mark % 2 == 1: # print('输出代码片段中!') - return gpt_reply + "\n```" + return gpt_reply+'\n```' else: return gpt_reply - - + import markdown from latex2mathml.converter import convert as tex2mathml - - +from functools import wraps, lru_cache def markdown_convertion(txt): """ 将Markdown格式的文本转换为HTML格式。如果包含数学公式,则先将公式转换为HTML格式。 """ pre = '
' - suf = "
" + suf = '' if txt.startswith(pre) and txt.endswith(suf): # print('警告,输入了已经经过转化的字符串,二次转化可能出问题') - return txt # 已经被转化过,不需要再次转化 - + return txt # 已经被转化过,不需要再次转化 + markdown_extension_configs = { - "mdx_math": { - "enable_dollar_delimiter": True, - "use_gitlab_delimiters": False, + 'mdx_math': { + 'enable_dollar_delimiter': True, + 'use_gitlab_delimiters': False, }, } find_equation_pattern = r'\n", "") + content = content.replace('\n', '') return content - if ("$" in txt) and ("```" not in txt): # 有$标识的公式符号,且没有代码段```的标识 + + if ('$' in txt) and ('```' not in txt): # 有$标识的公式符号,且没有代码段```的标识 # convert everything to html format - split = markdown.markdown(text="---") - convert_stage_1 = markdown.markdown( - text=txt, - extensions=["mdx_math", "fenced_code", "tables", "sane_lists"], - extension_configs=markdown_extension_configs, - ) + split = markdown.markdown(text='---') + convert_stage_1 = markdown.markdown(text=txt, extensions=['mdx_math', 'fenced_code', 'tables', 'sane_lists'], extension_configs=markdown_extension_configs) convert_stage_1 = markdown_bug_hunt(convert_stage_1) # 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). # 1. convert to easy-to-copy tex (do not render math) - convert_stage_2_1, n = re.subn( - find_equation_pattern, - replace_math_no_render, - convert_stage_1, - flags=re.DOTALL, - ) + convert_stage_2_1, n = re.subn(find_equation_pattern, replace_math_no_render, convert_stage_1, flags=re.DOTALL) # 2. convert to rendered equation - convert_stage_2_2, n = re.subn( - find_equation_pattern, replace_math_render, convert_stage_1, flags=re.DOTALL - ) + convert_stage_2_2, n = re.subn(find_equation_pattern, replace_math_render, convert_stage_1, flags=re.DOTALL) # cat them together - return pre + convert_stage_2_1 + f"{split}" + convert_stage_2_2 + suf + return pre + convert_stage_2_1 + f'{split}' + convert_stage_2_2 + suf else: - return ( - pre - + markdown.markdown( - txt, extensions=["fenced_code", "codehilite", "tables", "sane_lists"] - ) - + suf - ) + return pre + markdown.markdown(txt, extensions=['fenced_code', 'codehilite', 'tables', 'sane_lists']) + suf sample = preprocess_newbing_out(sample) sample = close_up_code_segment_during_stream(sample) sample = markdown_convertion(sample) -with open("tmp.html", "w", encoding="utf8") as f: - f.write( - """ +with open('tmp.html', 'w', encoding='utf8') as f: + f.write(""" My Website - """ - ) + """) f.write(sample) diff --git a/docs/translate_english.json b/docs/translate_english.json index c7e0e66d74a992aa38d1b36bc2eb2e5934200ab9..91eba9d381f03429ba6960cf6018d813b33ae150 100644 --- a/docs/translate_english.json +++ b/docs/translate_english.json @@ -265,7 +265,7 @@ "例如chatglm&gpt-3.5-turbo&api2d-gpt-4": "e.g. chatglm&gpt-3.5-turbo&api2d-gpt-4", "先切换模型到openai或api2d": "Switch the model to openai or api2d first", "在这里输入分辨率": "Enter the resolution here", - "如1024x1024": "e.g. 1024x1024", + "如256x256": "e.g. 256x256", "默认": "Default", "建议您复制一个config_private.py放自己的秘密": "We suggest you to copy a config_private.py file to keep your secrets, such as API and proxy URLs, from being accidentally uploaded to Github and seen by others.", "如API和代理网址": "Such as API and proxy URLs", @@ -322,7 +322,7 @@ "任何文件": "Any file", "但推荐上传压缩文件": "But it is recommended to upload compressed files", "更换模型 & SysPrompt & 交互界面布局": "Change model & SysPrompt & interactive interface layout", - "浮动输入区": "Floating input area", + "底部输入区": "Bottom input area", "输入清除键": "Input clear key", "插件参数区": "Plugin parameter area", "显示/隐藏功能区": "Show/hide function area", @@ -430,6 +430,7 @@ "并显示到聊天当中": "And display it in the chat", "插件调度异常": "Plugin scheduling exception", "异常原因": "Exception reason", + "实验性函数调用出错": "Experimental function call error", "当前代理可用性": "Current proxy availability", "异常": "Exception", "将文本按照段落分隔符分割开": "Split the text into paragraphs according to the paragraph separator", @@ -501,8 +502,7 @@ "环境变量": "Environment variable", "不支持通过环境变量设置!": "Setting through environment variables is not supported!", "加载失败!": "Loading failed!", - "如": " e.g., ", - "成功读取环境变量": "Successfully read environment variable: ", + "成功读取环境变量": "Successfully read environment variables", "本项目现已支持OpenAI和API2D的api-key": "This project now supports api-keys for OpenAI and API2D", "也支持同时填写多个api-key": "It also supports filling in multiple api-keys at the same time", "您既可以在config.py中修改api-key": "You can modify the api-key in config.py", @@ -513,7 +513,7 @@ "请在config文件中修改API密钥之后再运行": "Please modify the API key in the config file before running", "网络代理状态": "Network proxy status", "未配置": "Not configured", - "无代理状态下很可能无法访问OpenAI家族的模型": "", + "无代理状态下很可能无法访问OpenAI家族的模型": "It is very likely that you cannot access OpenAI's models without a proxy", "建议": "Suggestion", "检查USE_PROXY选项是否修改": "Check if the USE_PROXY option has been modified", "已配置": "Configured", @@ -923,7 +923,7 @@ "的第": "The", "个片段": "fragment", "总结文章": "Summarize the article", - "根据以上的对话": "According to the conversation above", + "根据以上的对话": "According to the above dialogue", "的主要内容": "The main content of", "所有文件都总结完成了吗": "Are all files summarized?", "如果是.doc文件": "If it is a .doc file", @@ -1184,7 +1184,7 @@ "Call ChatGLM fail 不能正常加载ChatGLM的参数": "Call ChatGLM fail, unable to load parameters for ChatGLM", "不能正常加载ChatGLM的参数!": "Unable to load parameters for ChatGLM!", "多线程方法": "Multithreading method", - "函数的说明请见 request_llms/bridge_all.py": "For function details, please see request_llms/bridge_all.py", + "函数的说明请见 request_llm/bridge_all.py": "For function details, please see request_llm/bridge_all.py", "程序终止": "Program terminated", "单线程方法": "Single-threaded method", "等待ChatGLM响应中": "Waiting for response from ChatGLM", @@ -1501,7 +1501,7 @@ "发送请求到OpenAI后": "After sending the request to OpenAI", "上下布局": "Vertical Layout", "左右布局": "Horizontal Layout", - "对话窗的高度": "Height of the Conversation Window", + "对话窗的高度": "Height of the Dialogue Window", "重试的次数限制": "Retry Limit", "gpt4现在只对申请成功的人开放": "GPT-4 is now only open to those who have successfully applied", "提高限制请查询": "Please check for higher limits", @@ -1543,7 +1543,7 @@ "str类型": "str type", "所有音频都总结完成了吗": "Are all audio summaries completed?", "SummaryAudioVideo内容": "SummaryAudioVideo content", - "使用教程详情见 request_llms/README.md": "See request_llms/README.md for detailed usage instructions", + "使用教程详情见 request_llm/README.md": "See request_llm/README.md for detailed usage instructions", "删除中间文件夹": "Delete intermediate folder", "Claude组件初始化成功": "Claude component initialized successfully", "$c$ 是光速": "$c$ is the speed of light", @@ -1668,7 +1668,7 @@ "Markdown翻译指定语言": "TranslateMarkdownToSpecifiedLanguage", "Langchain知识库": "LangchainKnowledgeBase", "Latex英文纠错加PDF对比": "CorrectEnglishInLatexWithPDFComparison", - "Latex输出PDF": "OutputPDFFromLatex", + "Latex输出PDF结果": "OutputPDFFromLatex", "Latex翻译中文并重新编译PDF": "TranslateChineseToEnglishInLatexAndRecompilePDF", "sprint亮靛": "SprintIndigo", "寻找Latex主文件": "FindLatexMainFile", @@ -2183,8 +2183,9 @@ "找不到合适插件执行该任务": "Cannot find a suitable plugin to perform this task", "接驳VoidTerminal": "Connect to VoidTerminal", "**很好": "**Very good", - "对话|编程": "Conversation&ImageGenerating|Programming", - "对话|编程|学术": "Conversation&ImageGenerating|Programming|Academic", "4. 建议使用 GPT3.5 或更强的模型": "4. It is recommended to use GPT3.5 or a stronger model", + "对话|编程": "Conversation|Programming", + "对话|编程|学术": "Conversation|Programming|Academic", + "4. 建议使用 GPT3.5 或更强的模型": "4. It is recommended to use GPT3.5 or a stronger model", "「请调用插件翻译PDF论文": "Please call the plugin to translate the PDF paper", "3. 如果您使用「调用插件xxx」、「修改配置xxx」、「请问」等关键词": "3. If you use keywords such as 'call plugin xxx', 'modify configuration xxx', 'please', etc.", "以下是一篇学术论文的基本信息": "The following is the basic information of an academic paper", @@ -2512,499 +2513,5 @@ "此处待注入的知识库名称id": "The knowledge base name ID to be injected here", "您需要构建知识库后再运行此插件": "You need to build the knowledge base before running this plugin", "判定是否为公式 | 测试1 写出洛伦兹定律": "Determine whether it is a formula | Test 1 write out the Lorentz law", - "构建知识库后": "After building the knowledge base", - "找不到本地项目或无法处理": "Unable to find local project or unable to process", - "再做一个小修改": "Make another small modification", - "解析整个Matlab项目": "Parse the entire Matlab project", - "需要用GPT提取参数": "Need to extract parameters using GPT", - "文件路径": "File path", - "正在排队": "In queue", - "-=-=-=-=-=-=-=-= 写出第1个文件": "-=-=-=-=-=-=-=-= Write the first file", - "仅翻译后的文本 -=-=-=-=-=-=-=-=": "Translated text only -=-=-=-=-=-=-=-=", - "对话通道": "Conversation channel", - "找不到任何": "Unable to find any", - "正在启动": "Starting", - "开始创建新进程并执行代码! 时间限制": "Start creating a new process and executing the code! Time limit", - "解析Matlab项目": "Parse Matlab project", - "更换UI主题": "Change UI theme", - "⭐ 开始啦 !": "⭐ Let's start!", - "先提取当前英文标题": "First extract the current English title", - "睡一会防止触发google反爬虫": "Sleep for a while to prevent triggering Google anti-crawler", - "测试": "Test", - "-=-=-=-=-=-=-=-= 写出Markdown文件 -=-=-=-=-=-=-=-=": "-=-=-=-=-=-=-=-= Write out Markdown file", - "如果index是1的话": "If the index is 1", - "VoidTerminal已经实现了类似的代码": "VoidTerminal has already implemented similar code", - "等待线程锁": "Waiting for thread lock", - "那么我们默认代理生效": "Then we default to proxy", - "结果是一个有效文件": "The result is a valid file", - "⭐ 检查模块": "⭐ Check module", - "备份一份History作为记录": "Backup a copy of History as a record", - "作者Binary-Husky": "Author Binary-Husky", - "将csv文件转excel表格": "Convert CSV file to Excel table", - "获取文章摘要": "Get article summary", - "次代码生成尝试": "Attempt to generate code", - "如果参数是空的": "If the parameter is empty", - "请配置讯飞星火大模型的XFYUN_APPID": "Please configure XFYUN_APPID for the Xunfei Starfire model", - "-=-=-=-=-=-=-=-= 写出第2个文件": "Write the second file", - "代码生成阶段结束": "Code generation phase completed", - "则进行提醒": "Then remind", - "处理异常": "Handle exception", - "可能触发了google反爬虫机制": "May have triggered Google anti-crawler mechanism", - "AnalyzeAMatlabProject的所有源文件": "All source files of AnalyzeAMatlabProject", - "写入": "Write", - "我们5秒后再试一次...": "Let's try again in 5 seconds...", - "判断一下用户是否错误地通过对话通道进入": "Check if the user entered through the dialogue channel by mistake", - "结果": "Result", - "2. 如果没有文件": "2. If there is no file", - "由 test_on_sentence_end": "By test_on_sentence_end", - "则直接使用first section name": "Then directly use the first section name", - "太懒了": "Too lazy", - "记录当前的大章节标题": "Record the current chapter title", - "然后再次点击该插件! 至于您的文件": "Then click the plugin again! As for your file", - "此次我们的错误追踪是": "This time our error tracking is", - "首先在arxiv上搜索": "First search on arxiv", - "被新插件取代": "Replaced by a new plugin", - "正在处理文件": "Processing file", - "除了连接OpenAI之外": "In addition to connecting OpenAI", - "我们检查一下": "Let's check", - "进度": "Progress", - "处理少数情况下的特殊插件的锁定状态": "Handle the locked state of special plugins in a few cases", - "⭐ 开始执行": "⭐ Start execution", - "正常情况": "Normal situation", - "下个句子中已经说完的部分": "The part that has already been said in the next sentence", - "首次运行需要花费较长时间下载NOUGAT参数": "The first run takes a long time to download NOUGAT parameters", - "使用tex格式公式 测试2 给出柯西不等式": "Use the tex format formula to test 2 and give the Cauchy inequality", - "无法从bing获取信息!": "Unable to retrieve information from Bing!", - "秒. 请等待任务完成": "Wait for the task to complete", - "开始干正事": "Start doing real work", - "需要花费较长时间下载NOUGAT参数": "It takes a long time to download NOUGAT parameters", - "然后再次点击该插件": "Then click the plugin again", - "受到bing限制": "Restricted by Bing", - "检索文章的历史版本的题目": "Retrieve the titles of historical versions of the article", - "收尾": "Wrap up", - "给定了task": "Given a task", - "某段话的整个句子": "The whole sentence of a paragraph", - "-=-=-=-=-=-=-=-= 写出HTML文件 -=-=-=-=-=-=-=-=": "-=-=-=-=-=-=-=-= Write out HTML file -=-=-=-=-=-=-=-=", - "当前文件": "Current file", - "请在输入框内填写需求": "Please fill in the requirements in the input box", - "结果是一个字符串": "The result is a string", - "用插件实现」": "Implemented with a plugin", - "⭐ 到最后一步了": "⭐ Reached the final step", - "重新修改当前part的标题": "Modify the title of the current part again", - "请勿点击“提交”按钮或者“基础功能区”按钮": "Do not click the 'Submit' button or the 'Basic Function Area' button", - "正在执行命令": "Executing command", - "检测到**滞留的缓存文档**": "Detected **stuck cache document**", - "第三步": "Step three", - "失败了~ 别担心": "Failed~ Don't worry", - "动态代码解释器": "Dynamic code interpreter", - "开始执行": "Start executing", - "不给定task": "No task given", - "正在加载NOUGAT...": "Loading NOUGAT...", - "精准翻译PDF文档": "Accurate translation of PDF documents", - "时间限制TIME_LIMIT": "Time limit TIME_LIMIT", - "翻译前后混合 -=-=-=-=-=-=-=-=": "Mixed translation before and after -=-=-=-=-=-=-=-=", - "搞定代码生成": "Code generation is done", - "插件通道": "Plugin channel", - "智能体": "Intelligent agent", - "切换界面明暗 ☀": "Switch interface brightness ☀", - "交换图像的蓝色通道和红色通道": "Swap blue channel and red channel of the image", - "作为函数参数": "As a function parameter", - "先挑选偶数序列号": "First select even serial numbers", - "仅供测试": "For testing only", - "执行成功了": "Execution succeeded", - "开始逐个文件进行处理": "Start processing files one by one", - "当前文件处理列表": "Current file processing list", - "执行失败了": "Execution failed", - "请及时处理": "Please handle it in time", - "源文件": "Source file", - "裁剪图像": "Crop image", - "插件动态生成插件": "Dynamic generation of plugins", - "正在验证上述代码的有效性": "Validating the above code", - "⭐ = 关键步骤": "⭐ = Key step", - "!= 0 代表“提交”键对话通道": "!= 0 represents the 'Submit' key dialogue channel", - "解析python源代码项目": "Parsing Python source code project", - "请检查PDF是否损坏": "Please check if the PDF is damaged", - "插件动态生成": "Dynamic generation of plugins", - "⭐ 分离代码块": "⭐ Separating code blocks", - "已经被记忆": "Already memorized", - "默认用英文的": "Default to English", - "错误追踪": "Error tracking", - "对话&编程|编程|学术|智能体": "Conversation&ImageGenerating|Programming|Academic|Intelligent agent", - "请检查": "Please check", - "检测到被滞留的缓存文档": "Detected cached documents being left behind", - "还有哪些场合允许使用代理": "What other occasions allow the use of proxies", - "1. 如果有文件": "1. If there is a file", - "执行开始": "Execution starts", - "代码生成结束": "Code generation ends", - "请及时点击“**保存当前对话**”获取所有滞留文档": "Please click '**Save Current Dialogue**' in time to obtain all cached documents", - "需点击“**函数插件区**”按钮进行处理": "Click the '**Function Plugin Area**' button for processing", - "此函数已经弃用": "This function has been deprecated", - "以后再写": "Write it later", - "返回给定的url解析出的arxiv_id": "Return the arxiv_id parsed from the given URL", - "⭐ 文件上传区是否有东西": "⭐ Is there anything in the file upload area", - "Nougat解析论文失败": "Nougat failed to parse the paper", - "本源代码中": "In this source code", - "或者基础功能通道": "Or the basic function channel", - "使用zip压缩格式": "Using zip compression format", - "受到google限制": "Restricted by Google", - "如果是": "If it is", - "不用担心": "don't worry", - "显示/隐藏自定义菜单": "Show/Hide Custom Menu", - "1. 输入文本": "1. Enter Text", - "微软AutoGen": "Microsoft AutoGen", - "在没有声音之后": "After No Sound", - "⭐ 主进程 Docker 外挂文件夹监控": "⭐ Main Process Docker External Folder Monitoring", - "请求任务": "Request Task", - "推荐上传压缩文件": "Recommend Uploading Compressed File", - "我准备好处理下一个问题了": "I'm ready to handle the next question", - "输入要反馈的内容": "Enter the content to be feedbacked", - "当已经存在一个正在运行的MultiAgentTerminal时": "When there is already a running MultiAgentTerminal", - "也根据时间间隔": "Also according to the time interval", - "自定义功能": "Custom Function", - "上传文件后会自动把输入区修改为相应路径": "After uploading the file, the input area will be automatically modified to the corresponding path", - "缺少docker运行环境!": "Missing docker runtime environment!", - "暂不支持中转": "Transit is not supported temporarily", - "一些第三方接口的出现这样的错误": "Some third-party interfaces encounter such errors", - "项目Wiki": "Project Wiki", - "但是我们把上一帧同样加上": "But we also add the previous frame", - "AutoGen 执行失败": "AutoGen execution failed", - "程序抵达用户反馈节点": "The program reaches the user feedback node", - "预制功能": "Prefabricated Function", - "输入新按钮名称": "Enter the new button name", - "| 不需要输入参数": "| No input parameters required", - "如果有新文件出现": "If there is a new file", - "Bug反馈": "Bug Feedback", - "指定翻译成何种语言": "Specify the language to translate into", - "点击保存当前的对话按钮": "Click the save current conversation button", - "如果您需要补充些什么": "If you need to add something", - "HTTPS 秘钥和证书": "HTTPS Key and Certificate", - "输入exit": "Enter exit", - "输入新提示后缀": "Enter a new prompt suffix", - "如果是文本文件": "If it is a text file", - "支持动态切换主题": "Support dynamic theme switching", - "并与self.previous_work_dir_files中所记录的文件进行对比": "And compare with the files recorded in self.previous_work_dir_files", - "作者 Microsoft & Binary-Husky": "Author Microsoft & Binary-Husky", - "请在自定义菜单中定义提示词前缀": "Please define the prefix of the prompt word in the custom menu", - "一般情况下您不需要说什么": "In general, you don't need to say anything", - "「暗色主题已启用": "Dark theme enabled", - "继续向服务器发送n次音频数据": "Continue to send audio data to the server n times", - "获取fp的拓展名": "Get the extension name of fp", - "指令安装内置Gradio及其他依赖": "Command to install built-in Gradio and other dependencies", - "查看自动更新": "Check for automatic updates", - "则更新self.previous_work_dir_files中": "Then update in self.previous_work_dir_files", - "看门狗耐心": "Watchdog patience", - "检测到新生图像": "Detected new image", - "等待AutoGen执行结果": "Waiting for AutoGen execution result", - "自定义菜单": "Custom menu", - "保持链接激活": "Keep the link active", - "已经被新插件取代": "Has been replaced by a new plugin", - "检查当前的模型是否符合要求": "Check if the current model meets the requirements", - "交互功能模板Demo函数": "Interactive function template Demo function", - "上一帧没有人声": "No human voice in the previous frame", - "用于判断异常": "Used to judge exceptions", - "请阅读Wiki": "Please read the Wiki", - "查找wallhaven.cc的壁纸": "Search for wallpapers on wallhaven.cc", - "2. 点击任意基础功能区按钮": "2. Click any button in the basic function area", - "一些垃圾第三方接口的出现这样的错误": "Some errors caused by garbage third-party interfaces", - "再次点击VoidTerminal": "Click VoidTerminal again", - "结束信号已明确": "The end signal is clear", - "获取代理失败 无代理状态下很可能无法访问OpenAI家族的模型及谷歌学术 建议": "Failed to get proxy. It is very likely that you will not be able to access OpenAI family models and Google Scholar without a proxy. It is recommended", - "界面外观": "Interface appearance", - "如果您想终止程序": "If you want to terminate the program", - "2. 点击任意函数插件区按钮": "Click any function plugin area button", - "绕过openai访问频率限制": "Bypass openai access frequency limit", - "配置暗色主题或亮色主题": "Configure dark theme or light theme", - "自定义按钮的最大数量限制": "Maximum number limit for custom buttons", - "函数插件区使用说明": "Instructions for function plugin area", - "如何语音对话": "How to have a voice conversation", - "清空输入区": "Clear input area", - "文档清单如下": "The document list is as follows", - "由 audio_convertion_thread": "By audio_convertion_thread", - "音频的可视化表现": "Visual representation of audio", - "然后直接点击“提交”以继续": "Then click 'Submit' to continue", - "运行MultiAgentTerminal": "Run MultiAgentTerminal", - "自定义按钮1": "Custom button 1", - "查看历史上的今天事件": "View events from history", - "如遇到Bug请前往": "If you encounter a bug, please go to", - "当前插件只支持": "The current plugin only supports", - "而不是再次启动一个新的MultiAgentTerminal": "Instead of starting a new MultiAgentTerminal again", - "用户代理或助理代理未定义": "User agent or assistant agent is not defined", - "运行阶段-": "Running phase-", - "随机选择": "Random selection", - "直接点击“提交”以继续": "Click 'Submit' to continue", - "使用项目内置Gradio获取最优体验! 请运行": "Use the built-in Gradio for the best experience! Please run", - "直接点击“提交”以终止AutoGen并解锁": "Click 'Submit' to terminate AutoGen and unlock", - "Github源代码开源和更新": "Github source code is open source and updated", - "直接将用户输入传递给它": "Pass user input directly to it", - "这是一个面向开发者的插件Demo": "This is a plugin demo for developers", - "帮助": "Help", - "普通对话使用说明": "Instructions for normal conversation", - "自定义按钮": "Custom button", - "即使没有声音": "Even without sound", - "⭐ 主进程": "⭐ Main process", - "基础功能区使用说明": "Basic Function Area Usage Instructions", - "提前读取一些信息": "Read some information in advance", - "当用户点击了“等待反馈”按钮时": "When the user clicks the 'Wait for Feedback' button", - "选择一个需要自定义基础功能区按钮": "Select a button in the Basic Function Area that needs to be customized", - "VoidTerminal使用说明": "VoidTerminal Usage Instructions", - "兼容一下吧": "Let's make it compatible", - "⭐⭐ 子进程执行": "⭐⭐ Subprocess execution", - "首次": "For the first time", - "则直接显示文本内容": "Then display the text content directly", - "更新状态": "Update status", - "2. 点击提交": "2. Click Submit", - "⭐⭐ 子进程": "⭐⭐ Subprocess", - "输入新提示前缀": "Enter a new prompt prefix", - "等待用户输入超时": "Wait for user input timeout", - "把新文件和发生变化的文件的路径记录到 change_list 中": "Record the paths of new files and files that have changed in change_list", - "或者上传文件": "Or upload a file", - "或者文件的修改时间发生变化": "Or the modification time of the file has changed", - "1. 输入路径/问题": "1. Enter path/question", - "尝试直接连接": "Try to connect directly", - "未来将删除": "Will be deleted in the future", - "请在自定义菜单中定义提示词后缀": "Please define the suffix of the prompt word in the custom menu", - "将executor存储到cookie中": "Store the executor in the cookie", - "1. 输入问题": "1. Enter question", - "发送一些音频片段给服务器": "Send some audio clips to the server", - "点击VoidTerminal": "Click VoidTerminal", - "扫描路径下的所有文件": "Scan all files under the path", - "检测到新生文档": "Detect new documents", - "预热tiktoken模块": "Preheat the tiktoken module", - "等待您的进一步指令": "Waiting for your further instructions", - "实时语音对话": "Real-time voice conversation", - "确认并保存": "Confirm and save", - "「亮色主题已启用": "Light theme enabled", - "终止AutoGen程序": "Terminate AutoGen program", - "然后根据提示输入指令": "Then enter the command as prompted", - "请上传本地文件/压缩包供“函数插件区”功能调用": "Please upload local files/zip packages for 'Function Plugin Area' function call", - "上传文件": "Upload file", - "上一帧是否有人说话": "Was there anyone speaking in the previous frame", - "这是一个时刻聆听着的语音对话助手 | 没有输入参数": "This is a voice conversation assistant that is always listening | No input parameters", - "常见问题请查阅": "Please refer to the FAQ for common questions", - "更换模型 & Prompt": "Change model & Prompt", - "如何保存对话": "How to save the conversation", - "处理任务": "Process task", - "加载已保存": "Load saved", - "打开浏览器页面": "Open browser page", - "解锁插件": "Unlock plugin", - "如果话筒激活 / 如果处于回声收尾阶段": "If the microphone is active / If it is in the echo tail stage", - "分辨率": "Resolution", - "分析行业动态": "Analyze industry trends", - "在项目实施过程中提供支持": "Provide support during project implementation", - "azure 对齐支持 -=-=-=-=-=-=-": "Azure alignment support -=-=-=-=-=-=-", - "默认的系统提示词": "Default system prompts", - "为您解释复杂的技术概念": "Explain complex technical concepts to you", - "提供项目管理和协作建议": "Provide project management and collaboration advice", - "请从AVAIL_LLM_MODELS中选择": "Please select from AVAIL_LLM_MODELS", - "提高编程能力": "Improve programming skills", - "请注意Newbing组件已不再维护": "Please note that the Newbing component is no longer maintained", - "用于定义和切换多个azure模型 --": "Used to define and switch between multiple Azure models --", - "支持 256x256": "Supports 256x256", - "定义界面上“询问多个GPT模型”插件应该使用哪些模型": "Define which models the 'Ask multiple GPT models' plugin should use on the interface", - "必须是.png格式": "Must be in .png format", - "tokenizer只用于粗估token数量": "The tokenizer is only used to estimate the number of tokens", - "协助您进行文案策划和内容创作": "Assist you in copywriting and content creation", - "帮助您巩固编程基础": "Help you consolidate your programming foundation", - "修改需求": "Modify requirements", - "确保项目顺利进行": "Ensure the smooth progress of the project", - "帮助您了解市场发展和竞争态势": "Help you understand market development and competitive situation", - "不需要动态切换": "No need for dynamic switching", - "解答您在学习过程中遇到的问题": "Answer the questions you encounter during the learning process", - "Endpoint不正确": "Endpoint is incorrect", - "提供编程思路和建议": "Provide programming ideas and suggestions", - "先上传图片": "Upload the image first", - "提供计算机科学、数据科学、人工智能等相关领域的学习资源和建议": "Provide learning resources and advice in computer science, data science, artificial intelligence, and other related fields", - "提供写作建议和技巧": "Provide writing advice and tips", - "间隔": "Interval", - "此后不需要在此处添加api2d的接口了": "No need to add the api2d interface here anymore", - "4. 学习辅导": "4. Learning guidance", - "智谱AI大模型": "Zhipu AI large model", - "3. 项目支持": "3. Project support", - "但这是意料之中的": "But this is expected", - "检查endpoint是否可用": "Check if the endpoint is available", - "接入智谱大模型": "Access the intelligent spectrum model", - "如果您有任何问题或需要解答的议题": "If you have any questions or topics that need answers", - "api2d 对齐支持 -=-=-=-=-=-=-": "api2d alignment support -=-=-=-=-=-=-", - "支持多线程": "Support multi-threading", - "再输入修改需求": "Enter modification requirements again", - "Endpoint不满足要求": "Endpoint does not meet the requirements", - "检查endpoint是否合法": "Check if the endpoint is valid", - "为您制定技术战略提供参考和建议": "Provide reference and advice for developing your technical strategy", - "支持 1024x1024": "Support 1024x1024", - "因为下面的代码会自动添加": "Because the following code will be automatically added", - "尝试加载模型": "Try to load the model", - "使用DALLE3生成图片 | 输入参数字符串": "Use DALLE3 to generate images | Input parameter string", - "当前论文无需解析": "The current paper does not need to be parsed", - "单个azure模型部署": "Deploy a single Azure model", - "512x512 或 1024x1024": "512x512 or 1024x1024", - "至少是8k上下文的模型": "A model with at least 8k context", - "自动忽略重复的输入": "Automatically ignore duplicate inputs", - "让您更好地掌握知识": "Help you better grasp knowledge", - "文件列表": "File list", - "并在不同模型之间用": "And use it between different models", - "插件调用出错": "Plugin call error", - "帮助您撰写文章、报告、散文、故事等": "Help you write articles, reports, essays, stories, etc.", - "*实验性功能*": "*Experimental feature*", - "2. 编程": "2. Programming", - "让您更容易理解": "Make it easier for you to understand", - "的最大上下文长度太短": "The maximum context length is too short", - "方法二": "Method 2", - "多个azure模型部署+动态切换": "Deploy multiple Azure models + dynamic switching", - "详情请见额外文档 docs\\use_azure.md": "For details, please refer to the additional document docs\\use_azure.md", - "包括但不限于 Python、Java、C++ 等": "Including but not limited to Python, Java, C++, etc.", - "为您提供业界最新的新闻和技术趋势": "Providing you with the latest industry news and technology trends", - "自动检测并屏蔽失效的KEY": "Automatically detect and block invalid keys", - "请勿使用": "Please do not use", - "最后输入分辨率": "Enter the resolution at last", - "图片": "Image", - "请检查AZURE_ENDPOINT的配置! 当前的Endpoint为": "Please check the configuration of AZURE_ENDPOINT! The current Endpoint is", - "图片修改": "Image modification", - "已经收集到所有信息": "All information has been collected", - "加载API_KEY": "Loading API_KEY", - "协助您编写代码": "Assist you in writing code", - "我可以为您提供以下服务": "I can provide you with the following services", - "排队中请稍候 ...": "Please wait in line ...", - "建议您使用英文提示词": "It is recommended to use English prompts", - "不能支撑AutoGen运行": "Cannot support AutoGen operation", - "帮助您解决编程问题": "Help you solve programming problems", - "上次用户反馈输入为": "Last user feedback input is", - "请随时告诉我您的需求": "Please feel free to tell me your needs", - "有 sys_prompt 接口": "There is a sys_prompt interface", - "可能会覆盖之前的配置": "May overwrite previous configuration", - "5. 行业动态和趋势分析": "5. Industry dynamics and trend analysis", - "正在等待线程锁": "Waiting for thread lock", - "请输入分辨率": "Please enter the resolution", - "接驳void-terminal": "Connecting to void-terminal", - "启动DALLE2图像修改向导程序": "Launching DALLE2 image modification wizard program", - "加载模型失败": "Failed to load the model", - "是否使用Docker容器运行代码": "Whether to run the code using Docker container", - "请输入修改需求": "Please enter modification requirements", - "作为您的写作和编程助手": "As your writing and programming assistant", - "然后再次点击本插件": "Then click this plugin again", - "需要动态切换": "Dynamic switching is required", - "文心大模型4.0": "Wenxin Large Model 4.0", - "找不到任何.pdf拓展名的文件": "Cannot find any file with .pdf extension", - "在使用AutoGen插件时": "When using the AutoGen plugin", - "协助您规划项目进度和任务分配": "Assist you in planning project schedules and task assignments", - "1. 写作": "1. Writing", - "你亲手写的api名称": "The API name you wrote yourself", - "使用DALLE2生成图片 | 输入参数字符串": "Generate images using DALLE2 | Input parameter string", - "方法一": "Method 1", - "我会尽力提供帮助": "I will do my best to provide assistance", - "多个azure模型": "Multiple Azure models", - "准备就绪": "Ready", - "请随时提问": "Please feel free to ask", - "如果需要使用AZURE": "If you need to use AZURE", - "如果不是本地模型": "If it is not a local model", - "AZURE_CFG_ARRAY中配置的模型必须以azure开头": "The models configured in AZURE_CFG_ARRAY must start with 'azure'", - "API key has been deactivated. OpenAI以账户失效为由": "API key has been deactivated. OpenAI considers it as an account failure", - "请先上传图像": "Please upload the image first", - "高优先级": "High priority", - "请配置ZHIPUAI_API_KEY": "Please configure ZHIPUAI_API_KEY", - "单个azure模型": "Single Azure model", - "预留参数 context 未实现": "Reserved parameter 'context' not implemented", - "在输入区输入临时API_KEY后提交": "Submit after entering temporary API_KEY in the input area", - "鸟": "Bird", - "图片中需要修改的位置用橡皮擦擦除为纯白色": "Erase the areas in the image that need to be modified with an eraser to pure white", - "└── PDF文档精准解析": "└── Accurate parsing of PDF documents", - "└── ALLOW_RESET_CONFIG 是否允许通过自然语言描述修改本页的配置": "└── ALLOW_RESET_CONFIG Whether to allow modifying the configuration of this page through natural language description", - "等待指令": "Waiting for instructions", - "不存在": "Does not exist", - "选择游戏": "Select game", - "本地大模型示意图": "Local large model diagram", - "无视此消息即可": "You can ignore this message", - "即RGB=255": "That is, RGB=255", - "如需追问": "If you have further questions", - "也可以是具体的模型路径": "It can also be a specific model path", - "才会起作用": "Will take effect", - "下载失败": "Download failed", - "网页刷新后失效": "Invalid after webpage refresh", - "crazy_functions.互动小游戏-": "crazy_functions.Interactive mini game-", - "右对齐": "Right alignment", - "您可以调用下拉菜单中的“LoadConversationHistoryArchive”还原当下的对话": "You can use the 'LoadConversationHistoryArchive' in the drop-down menu to restore the current conversation", - "左对齐": "Left alignment", - "使用默认的 FP16": "Use default FP16", - "一小时": "One hour", - "从而方便内存的释放": "Thus facilitating memory release", - "如何临时更换API_KEY": "How to temporarily change API_KEY", - "请输入 1024x1024-HD": "Please enter 1024x1024-HD", - "使用 INT8 量化": "Use INT8 quantization", - "3. 输入修改需求": "3. Enter modification requirements", - "刷新界面 由于请求gpt需要一段时间": "Refreshing the interface takes some time due to the request for gpt", - "随机小游戏": "Random mini game", - "那么请在下面的QWEN_MODEL_SELECTION中指定具体的模型": "So please specify the specific model in QWEN_MODEL_SELECTION below", - "表值": "Table value", - "我画你猜": "I draw, you guess", - "狗": "Dog", - "2. 输入分辨率": "2. Enter resolution", - "鱼": "Fish", - "尚未完成": "Not yet completed", - "表头": "Table header", - "填localhost或者127.0.0.1": "Fill in localhost or 127.0.0.1", - "请上传jpg格式的图片": "Please upload images in jpg format", - "API_URL_REDIRECT填写格式是错误的": "The format of API_URL_REDIRECT is incorrect", - "├── RWKV的支持见Wiki": "Support for RWKV is available in the Wiki", - "如果中文Prompt效果不理想": "If the Chinese prompt is not effective", - "/SEAFILE_LOCAL/50503047/我的资料库/学位/paperlatex/aaai/Fu_8368_with_appendix": "/SEAFILE_LOCAL/50503047/My Library/Degree/paperlatex/aaai/Fu_8368_with_appendix", - "只有当AVAIL_LLM_MODELS包含了对应本地模型时": "Only when AVAIL_LLM_MODELS contains the corresponding local model", - "选择本地模型变体": "Choose the local model variant", - "如果您确信自己没填错": "If you are sure you haven't made a mistake", - "PyPDF2这个库有严重的内存泄露问题": "PyPDF2 library has serious memory leak issues", - "整理文件集合 输出消息": "Organize file collection and output message", - "没有检测到任何近期上传的图像文件": "No recently uploaded image files detected", - "游戏结束": "Game over", - "调用结束": "Call ended", - "猫": "Cat", - "请及时切换模型": "Please switch models in time", - "次中": "In the meantime", - "如需生成高清图像": "If you need to generate high-definition images", - "CPU 模式": "CPU mode", - "项目目录": "Project directory", - "动物": "Animal", - "居中对齐": "Center alignment", - "请注意拓展名需要小写": "Please note that the extension name needs to be lowercase", - "重试第": "Retry", - "实验性功能": "Experimental feature", - "猜错了": "Wrong guess", - "打开你的代理软件查看代理协议": "Open your proxy software to view the proxy agreement", - "您不需要再重复强调该文件的路径了": "You don't need to emphasize the file path again", - "请阅读": "Please read", - "请直接输入您的问题": "Please enter your question directly", - "API_URL_REDIRECT填错了": "API_URL_REDIRECT is filled incorrectly", - "谜底是": "The answer is", - "第一个模型": "The first model", - "你猜对了!": "You guessed it right!", - "已经接收到您上传的文件": "The file you uploaded has been received", - "您正在调用“图像生成”插件": "You are calling the 'Image Generation' plugin", - "刷新界面 界面更新": "Refresh the interface, interface update", - "如果之前已经初始化了游戏实例": "If the game instance has been initialized before", - "文件": "File", - "老鼠": "Mouse", - "列2": "Column 2", - "等待图片": "Waiting for image", - "使用 INT4 量化": "Use INT4 quantization", - "from crazy_functions.互动小游戏 import 随机小游戏": "TranslatedText", - "游戏主体": "TranslatedText", - "该模型不具备上下文对话能力": "TranslatedText", - "列3": "TranslatedText", - "清理": "TranslatedText", - "检查量化配置": "TranslatedText", - "如果游戏结束": "TranslatedText", - "蛇": "TranslatedText", - "则继续该实例;否则重新初始化": "TranslatedText", - "e.g. cat and 猫 are the same thing": "TranslatedText", - "第三个模型": "TranslatedText", - "如果你选择Qwen系列的模型": "TranslatedText", - "列4": "TranslatedText", - "输入“exit”获取答案": "TranslatedText", - "把它放到子进程中运行": "TranslatedText", - "列1": "TranslatedText", - "使用该模型需要额外依赖": "TranslatedText", - "再试试": "TranslatedText", - "1. 上传图片": "TranslatedText", - "保存状态": "TranslatedText", - "GPT-Academic对话存档": "TranslatedText", - "Arxiv论文精细翻译": "TranslatedText", - "from crazy_functions.AdvancedFunctionTemplate import 测试图表渲染": "from crazy_functions.AdvancedFunctionTemplate import test_chart_rendering", - "测试图表渲染": "test_chart_rendering" -} + "构建知识库后": "After building the knowledge base" +} \ No newline at end of file diff --git a/docs/translate_japanese.json b/docs/translate_japanese.json index a70f5df17b850760dee76f6433e6c028c4aed092..ecd370e9c350b8e549e51319aba9be095a904e0d 100644 --- a/docs/translate_japanese.json +++ b/docs/translate_japanese.json @@ -352,6 +352,7 @@ "感谢热情的": "熱心な感謝", "是本次输出": "今回の出力です", "协议": "プロトコル", + "实验性函数调用出错": "実験的な関数呼び出しエラー", "例如需要翻译的一段话": "翻訳が必要な例文", "本地文件地址": "ローカルファイルアドレス", "更好的UI视觉效果": "より良いUI視覚効果", @@ -781,7 +782,7 @@ "主进程统一调用函数接口": "メインプロセスが関数インターフェースを統一的に呼び出します", "再例如一个包含了待处理文件的路径": "処理待ちのファイルを含むパスの例", "负责把学术论文准确翻译成中文": "学術論文を正確に中国語に翻訳する責任があります", - "函数的说明请见 request_llms/bridge_all.py": "関数の説明については、request_llms/bridge_all.pyを参照してください", + "函数的说明请见 request_llm/bridge_all.py": "関数の説明については、request_llm/bridge_all.pyを参照してください", "然后回车提交": "そしてEnterを押して提出してください", "防止爆token": "トークンの爆発を防止する", "Latex项目全文中译英": "LaTeXプロジェクト全文の中国語から英語への翻訳", @@ -853,7 +854,7 @@ "查询版本和用户意见": "バージョンとユーザーの意見を検索する", "提取摘要": "要約を抽出する", "在gpt输出代码的中途": "GPTがコードを出力する途中で", - "如1024x1024": "1024x1024のように", + "如256x256": "256x256のように", "概括其内容": "内容を要約する", "剩下的情况都开头除去": "残りの場合はすべて先頭を除去する", "至少一个线程任务意外失败": "少なくとも1つのスレッドタスクが予期しない失敗をした", @@ -1006,6 +1007,7 @@ "第一部分": "第1部分", "的分析如下": "の分析は以下の通りです", "解决一个mdx_math的bug": "mdx_mathのバグを解決する", + "底部输入区": "下部の入力エリア", "函数插件输入输出接驳区": "関数プラグインの入出力接続エリア", "打开浏览器": "ブラウザを開く", "免费用户填3": "無料ユーザーは3を入力してください", @@ -1492,7 +1494,7 @@ "交互功能模板函数": "InteractiveFunctionTemplateFunction", "交互功能函数模板": "InteractiveFunctionFunctionTemplate", "Latex英文纠错加PDF对比": "LatexEnglishErrorCorrectionWithPDFComparison", - "Latex输出PDF": "LatexOutputPDFResult", + "Latex输出PDF结果": "LatexOutputPDFResult", "Latex翻译中文并重新编译PDF": "TranslateChineseAndRecompilePDF", "语音助手": "VoiceAssistant", "微调数据集生成": "FineTuneDatasetGeneration", @@ -1615,7 +1617,7 @@ "正在重试": "再試行中", "从而更全面地理解项目的整体功能": "プロジェクトの全体的な機能をより理解するために", "正在等您说完问题": "質問が完了するのをお待ちしています", - "使用教程详情见 request_llms/README.md": "使用方法の詳細については、request_llms/README.mdを参照してください", + "使用教程详情见 request_llm/README.md": "使用方法の詳細については、request_llm/README.mdを参照してください", "6.25 加入判定latex模板的代码": "6.25 テンプレートの判定コードを追加", "找不到任何音频或视频文件": "音声またはビデオファイルが見つかりません", "请求GPT模型的": "GPTモデルのリクエスト", @@ -2106,4 +2108,4 @@ "改变输入参数的顺序与结构": "入力パラメータの順序と構造を変更する", "正在精细切分latex文件": "LaTeXファイルを細かく分割しています", "读取文件": "ファイルを読み込んでいます" -} +} \ No newline at end of file diff --git a/docs/translate_std.json b/docs/translate_std.json index 581d83e7e0b1d3911f6ce5af0a907949b06ab65c..84690c2e8a8e52e27c428d27eae3435cb0f1e1ee 100644 --- a/docs/translate_std.json +++ b/docs/translate_std.json @@ -16,7 +16,7 @@ "批量Markdown翻译": "BatchTranslateMarkdown", "连接bing搜索回答问题": "ConnectBingSearchAnswerQuestion", "Langchain知识库": "LangchainKnowledgeBase", - "Latex输出PDF": "OutputPDFFromLatex", + "Latex输出PDF结果": "OutputPDFFromLatex", "把字符太少的块清除为回车": "ClearBlocksWithTooFewCharactersToNewline", "Latex精细分解与转化": "DecomposeAndConvertLatex", "解析一个C项目的头文件": "ParseCProjectHeaderFiles", @@ -90,19 +90,5 @@ "解析PDF_基于GROBID": "ParsePDF_BasedOnGROBID", "虚空终端主路由": "VoidTerminalMainRoute", "批量翻译PDF文档_NOUGAT": "BatchTranslatePDFDocuments_NOUGAT", - "解析PDF_基于NOUGAT": "ParsePDF_NOUGAT", - "解析一个Matlab项目": "AnalyzeAMatlabProject", - "函数动态生成": "DynamicFunctionGeneration", - "多智能体终端": "MultiAgentTerminal", - "多智能体": "MultiAgent", - "图片生成_DALLE2": "ImageGeneration_DALLE2", - "图片生成_DALLE3": "ImageGeneration_DALLE3", - "图片修改_DALLE2": "ImageModification_DALLE2", - "生成多种Mermaid图表": "GenerateMultipleMermaidCharts", - "知识库文件注入": "InjectKnowledgeBaseFiles", - "PDF翻译中文并重新编译PDF": "TranslatePDFToChineseAndRecompilePDF", - "随机小游戏": "RandomMiniGame", - "互动小游戏": "InteractiveMiniGame", - "解析历史输入": "ParseHistoricalInput", - "高阶功能模板函数示意图": "HighOrderFunctionTemplateDiagram" + "解析PDF_基于NOUGAT": "ParsePDF_NOUGAT" } \ No newline at end of file diff --git a/docs/translate_traditionalchinese.json b/docs/translate_traditionalchinese.json index 3378eda74fc53180be8323cb656be37cd25d6f3d..efaa62fc7c5012724d0975f8b1de488ccf3cbeff 100644 --- a/docs/translate_traditionalchinese.json +++ b/docs/translate_traditionalchinese.json @@ -123,7 +123,7 @@ "的第": "的第", "减少重复": "減少重複", "如果超过期限没有喂狗": "如果超過期限沒有餵狗", - "函数的说明请见 request_llms/bridge_all.py": "函數的說明請見 request_llms/bridge_all.py", + "函数的说明请见 request_llm/bridge_all.py": "函數的說明請見 request_llm/bridge_all.py", "第7步": "第7步", "说": "說", "中途接收可能的终止指令": "中途接收可能的終止指令", @@ -346,6 +346,7 @@ "情况会好转": "情況會好轉", "超过512个": "超過512個", "多线": "多線", + "底部输入区": "底部輸入區", "合并小写字母开头的段落块并替换为空格": "合併小寫字母開頭的段落塊並替換為空格", "暗色主题": "暗色主題", "提高限制请查询": "提高限制請查詢", @@ -780,6 +781,7 @@ "检测到程序终止": "偵測到程式終止", "对整个Latex项目进行润色": "對整個Latex專案進行潤色", "方法则会被调用": "方法則會被調用", + "实验性函数调用出错": "實驗性函數調用出錯", "把完整输入-输出结果显示在聊天框": "把完整輸入-輸出結果顯示在聊天框", "本地文件预览": "本地檔案預覽", "接下来请你逐文件分析下面的论文文件": "接下來請你逐檔案分析下面的論文檔案", @@ -1043,9 +1045,9 @@ "jittorllms响应异常": "jittorllms response exception", "在项目根目录运行这两个指令": "Run these two commands in the project root directory", "获取tokenizer": "Get tokenizer", - "chatbot 为WebUI中显示的对话列表": "chatbot is the list of conversations displayed in WebUI", + "chatbot 为WebUI中显示的对话列表": "chatbot is the list of dialogues displayed in WebUI", "test_解析一个Cpp项目": "test_parse a Cpp project", - "将对话记录history以Markdown格式写入文件中": "Write the conversations record history to a file in Markdown format", + "将对话记录history以Markdown格式写入文件中": "Write the dialogue record history to a file in Markdown format", "装饰器函数": "Decorator function", "玫瑰色": "Rose color", "将单空行": "刪除單行空白", @@ -1146,7 +1148,7 @@ "Y+回车=确认": "Y+回車=確認", "正在同时咨询ChatGPT和ChatGLM……": "正在同時諮詢ChatGPT和ChatGLM……", "根据 heuristic 规则": "根據heuristic規則", - "如1024x1024": "如1024x1024", + "如256x256": "如256x256", "函数插件区": "函數插件區", "*** API_KEY 导入成功": "*** API_KEY 導入成功", "请对下面的程序文件做一个概述文件名是": "請對下面的程序文件做一個概述文件名是", @@ -1468,7 +1470,7 @@ "交互功能模板函数": "InteractiveFunctionTemplateFunctions", "交互功能函数模板": "InteractiveFunctionFunctionTemplates", "Latex英文纠错加PDF对比": "LatexEnglishCorrectionWithPDFComparison", - "Latex输出PDF": "OutputPDFFromLatex", + "Latex输出PDF结果": "OutputPDFFromLatex", "Latex翻译中文并重新编译PDF": "TranslateLatexToChineseAndRecompilePDF", "语音助手": "VoiceAssistant", "微调数据集生成": "FineTuneDatasetGeneration", @@ -1886,7 +1888,7 @@ "请继续分析其他源代码": "請繼續分析其他源代碼", "质能方程式": "質能方程式", "功能尚不稳定": "功能尚不穩定", - "使用教程详情见 request_llms/README.md": "使用教程詳情見 request_llms/README.md", + "使用教程详情见 request_llm/README.md": "使用教程詳情見 request_llm/README.md", "从以上搜索结果中抽取信息": "從以上搜索結果中抽取信息", "虽然PDF生成失败了": "雖然PDF生成失敗了", "找图片": "尋找圖片", @@ -2270,4 +2272,4 @@ "标注节点的行数范围": "標註節點的行數範圍", "默认 True": "默認 True", "将两个PDF拼接": "將兩個PDF拼接" -} +} \ No newline at end of file diff --git a/docs/use_audio.md b/docs/use_audio.md index 0889325c9242e78d9fbf42704b0f3d8c61b18fb4..b461f58ac78ae27b94ec8ad4ccacb81ed760b55b 100644 --- a/docs/use_audio.md +++ b/docs/use_audio.md @@ -3,7 +3,7 @@ ## 1. 安装额外依赖 ``` -pip install --upgrade pyOpenSSL webrtcvad scipy git+https://github.com/aliyun/alibabacloud-nls-python-sdk.git +pip install --upgrade pyOpenSSL scipy git+https://github.com/aliyun/alibabacloud-nls-python-sdk.git ``` 如果因为特色网络问题导致上述命令无法执行: @@ -61,3 +61,4 @@ VI 两种音频监听模式切换时,需要刷新页面才有效。 VII 非localhost运行+非https情况下无法打开录音功能的坑:https://blog.csdn.net/weixin_39461487/article/details/109594434 ## 5.点击函数插件区“实时音频采集” 或者其他音频交互功能 + diff --git a/docs/use_azure.md b/docs/use_azure.md index 0e192ba6a215b834b5645bb8d48bba7883153240..f7e7b77ea413f381fb00a700621974b3fc03fbad 100644 --- a/docs/use_azure.md +++ b/docs/use_azure.md @@ -1,42 +1,3 @@ -# 微软Azure云接入指南 - -## 方法一(旧方法,只能接入一个Azure模型) - -- 通过以下教程,获取AZURE_ENDPOINT,AZURE_API_KEY,AZURE_ENGINE,直接修改 config 配置即可。配置的修改方法见本项目wiki。 - -## 方法二(新方法,接入多个Azure模型,并支持动态切换) - -- 在方法一的基础上,注册并获取多组 AZURE_ENDPOINT,AZURE_API_KEY,AZURE_ENGINE -- 修改config中的AZURE_CFG_ARRAY和AVAIL_LLM_MODELS配置项,按照格式填入多个Azure模型的配置,如下所示: - -``` -AZURE_CFG_ARRAY = { - "azure-gpt-3.5": # 第一个模型,azure模型必须以"azure-"开头,注意您还需要将"azure-gpt-3.5"加入AVAIL_LLM_MODELS(模型下拉菜单) - { - "AZURE_ENDPOINT": "https://你亲手写的api名称.openai.azure.com/", - "AZURE_API_KEY": "cccccccccccccccccccccccccccccccc", - "AZURE_ENGINE": "填入你亲手写的部署名1", - "AZURE_MODEL_MAX_TOKEN": 4096, - }, - "azure-gpt-4": # 第二个模型,azure模型必须以"azure-"开头,注意您还需要将"azure-gpt-4"加入AVAIL_LLM_MODELS(模型下拉菜单) - { - "AZURE_ENDPOINT": "https://你亲手写的api名称.openai.azure.com/", - "AZURE_API_KEY": "dddddddddddddddddddddddddddddddd", - "AZURE_ENGINE": "填入你亲手写的部署名2", - "AZURE_MODEL_MAX_TOKEN": 8192, - }, - "azure-gpt-3.5-16k": # 第三个模型,azure模型必须以"azure-"开头,注意您还需要将"azure-gpt-3.5-16k"加入AVAIL_LLM_MODELS(模型下拉菜单) - { - "AZURE_ENDPOINT": "https://你亲手写的api名称.openai.azure.com/", - "AZURE_API_KEY": "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", - "AZURE_ENGINE": "填入你亲手写的部署名3", - "AZURE_MODEL_MAX_TOKEN": 16384, - }, -} -``` - - - # 通过微软Azure云服务申请 Openai API 由于Openai和微软的关系,现在是可以通过微软的Azure云计算服务直接访问openai的api,免去了注册和网络的问题。 @@ -146,12 +107,6 @@ AZURE_API_KEY = "填入azure openai api的密钥" AZURE_API_VERSION = "2023-05-15" # 默认使用 2023-05-15 版本,无需修改 AZURE_ENGINE = "填入部署名" # 见上述图片 - -# 例如 -API_KEY = '6424e9d19e674092815cea1cb35e67a5' -AZURE_ENDPOINT = 'https://rhtjjjjjj.openai.azure.com/' -AZURE_ENGINE = 'qqwe' -LLM_MODEL = "azure-gpt-3.5" # 可选 ↓↓↓ ``` diff --git a/docs/waifu_plugin/autoload.js b/docs/waifu_plugin/autoload.js index d0648770b6d18512bfa4310508445e76cf72c11a..3464a5cd44b0d4e1b0f2528bd01fc1793275b964 100644 --- a/docs/waifu_plugin/autoload.js +++ b/docs/waifu_plugin/autoload.js @@ -8,8 +8,8 @@ try { live2d_settings['modelId'] = 5; // 默认模型 ID live2d_settings['modelTexturesId'] = 1; // 默认材质 ID live2d_settings['modelStorage'] = false; // 不储存模型 ID - live2d_settings['waifuSize'] = '210x187'; - live2d_settings['waifuTipsSize'] = '187x52'; + live2d_settings['waifuSize'] = '210x187'; + live2d_settings['waifuTipsSize'] = '187x52'; live2d_settings['canSwitchModel'] = true; live2d_settings['canSwitchTextures'] = true; live2d_settings['canSwitchHitokoto'] = false; diff --git a/docs/waifu_plugin/flat-ui-icons-regular.svg b/docs/waifu_plugin/flat-ui-icons-regular.svg index e05f3a0d31e417b72be11d5935cbb201729085dc..cb2727cac3c0f52b7370e851a1e2f3092ad76d1a 100644 --- a/docs/waifu_plugin/flat-ui-icons-regular.svg +++ b/docs/waifu_plugin/flat-ui-icons-regular.svg @@ -123,4 +123,4 @@ - + \ No newline at end of file diff --git a/docs/waifu_plugin/jquery-ui.min.js b/docs/waifu_plugin/jquery-ui.min.js index 862a649869db80cb6c8cd6d48f63ee0b56169a2c..25398a167415050ae8bfb0bfebac6aa3ab790909 100644 --- a/docs/waifu_plugin/jquery-ui.min.js +++ b/docs/waifu_plugin/jquery-ui.min.js @@ -10,4 +10,4 @@ this.isMultiLine=o||!a&&this._isContentEditable(this.element),this.valueMethod=t },_cacheMargins:function(){this.margins={left:parseInt(this.element.css("marginLeft"),10)||0,top:parseInt(this.element.css("marginTop"),10)||0,right:parseInt(this.element.css("marginRight"),10)||0,bottom:parseInt(this.element.css("marginBottom"),10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var e,i,s,n=this.options,o=this.document[0];return this.relativeContainer=null,n.containment?"window"===n.containment?(this.containment=[t(window).scrollLeft()-this.offset.relative.left-this.offset.parent.left,t(window).scrollTop()-this.offset.relative.top-this.offset.parent.top,t(window).scrollLeft()+t(window).width()-this.helperProportions.width-this.margins.left,t(window).scrollTop()+(t(window).height()||o.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top],void 0):"document"===n.containment?(this.containment=[0,0,t(o).width()-this.helperProportions.width-this.margins.left,(t(o).height()||o.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top],void 0):n.containment.constructor===Array?(this.containment=n.containment,void 0):("parent"===n.containment&&(n.containment=this.helper[0].parentNode),i=t(n.containment),s=i[0],s&&(e=/(scroll|auto)/.test(i.css("overflow")),this.containment=[(parseInt(i.css("borderLeftWidth"),10)||0)+(parseInt(i.css("paddingLeft"),10)||0),(parseInt(i.css("borderTopWidth"),10)||0)+(parseInt(i.css("paddingTop"),10)||0),(e?Math.max(s.scrollWidth,s.offsetWidth):s.offsetWidth)-(parseInt(i.css("borderRightWidth"),10)||0)-(parseInt(i.css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left-this.margins.right,(e?Math.max(s.scrollHeight,s.offsetHeight):s.offsetHeight)-(parseInt(i.css("borderBottomWidth"),10)||0)-(parseInt(i.css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top-this.margins.bottom],this.relativeContainer=i),void 0):(this.containment=null,void 0)},_convertPositionTo:function(t,e){e||(e=this.position);var i="absolute"===t?1:-1,s=this._isRootNode(this.scrollParent[0]);return{top:e.top+this.offset.relative.top*i+this.offset.parent.top*i-("fixed"===this.cssPosition?-this.offset.scroll.top:s?0:this.offset.scroll.top)*i,left:e.left+this.offset.relative.left*i+this.offset.parent.left*i-("fixed"===this.cssPosition?-this.offset.scroll.left:s?0:this.offset.scroll.left)*i}},_generatePosition:function(t,e){var i,s,n,o,a=this.options,r=this._isRootNode(this.scrollParent[0]),h=t.pageX,l=t.pageY;return r&&this.offset.scroll||(this.offset.scroll={top:this.scrollParent.scrollTop(),left:this.scrollParent.scrollLeft()}),e&&(this.containment&&(this.relativeContainer?(s=this.relativeContainer.offset(),i=[this.containment[0]+s.left,this.containment[1]+s.top,this.containment[2]+s.left,this.containment[3]+s.top]):i=this.containment,t.pageX-this.offset.click.lefti[2]&&(h=i[2]+this.offset.click.left),t.pageY-this.offset.click.top>i[3]&&(l=i[3]+this.offset.click.top)),a.grid&&(n=a.grid[1]?this.originalPageY+Math.round((l-this.originalPageY)/a.grid[1])*a.grid[1]:this.originalPageY,l=i?n-this.offset.click.top>=i[1]||n-this.offset.click.top>i[3]?n:n-this.offset.click.top>=i[1]?n-a.grid[1]:n+a.grid[1]:n,o=a.grid[0]?this.originalPageX+Math.round((h-this.originalPageX)/a.grid[0])*a.grid[0]:this.originalPageX,h=i?o-this.offset.click.left>=i[0]||o-this.offset.click.left>i[2]?o:o-this.offset.click.left>=i[0]?o-a.grid[0]:o+a.grid[0]:o),"y"===a.axis&&(h=this.originalPageX),"x"===a.axis&&(l=this.originalPageY)),{top:l-this.offset.click.top-this.offset.relative.top-this.offset.parent.top+("fixed"===this.cssPosition?-this.offset.scroll.top:r?0:this.offset.scroll.top),left:h-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+("fixed"===this.cssPosition?-this.offset.scroll.left:r?0:this.offset.scroll.left)}},_clear:function(){this._removeClass(this.helper,"ui-draggable-dragging"),this.helper[0]===this.element[0]||this.cancelHelperRemoval||this.helper.remove(),this.helper=null,this.cancelHelperRemoval=!1,this.destroyOnClear&&this.destroy()},_trigger:function(e,i,s){return s=s||this._uiHash(),t.ui.plugin.call(this,e,[i,s,this],!0),/^(drag|start|stop)/.test(e)&&(this.positionAbs=this._convertPositionTo("absolute"),s.offset=this.positionAbs),t.Widget.prototype._trigger.call(this,e,i,s)},plugins:{},_uiHash:function(){return{helper:this.helper,position:this.position,originalPosition:this.originalPosition,offset:this.positionAbs}}}),t.ui.plugin.add("draggable","connectToSortable",{start:function(e,i,s){var n=t.extend({},i,{item:s.element});s.sortables=[],t(s.options.connectToSortable).each(function(){var i=t(this).sortable("instance");i&&!i.options.disabled&&(s.sortables.push(i),i.refreshPositions(),i._trigger("activate",e,n))})},stop:function(e,i,s){var n=t.extend({},i,{item:s.element});s.cancelHelperRemoval=!1,t.each(s.sortables,function(){var t=this;t.isOver?(t.isOver=0,s.cancelHelperRemoval=!0,t.cancelHelperRemoval=!1,t._storedCSS={position:t.placeholder.css("position"),top:t.placeholder.css("top"),left:t.placeholder.css("left")},t._mouseStop(e),t.options.helper=t.options._helper):(t.cancelHelperRemoval=!0,t._trigger("deactivate",e,n))})},drag:function(e,i,s){t.each(s.sortables,function(){var n=!1,o=this;o.positionAbs=s.positionAbs,o.helperProportions=s.helperProportions,o.offset.click=s.offset.click,o._intersectsWith(o.containerCache)&&(n=!0,t.each(s.sortables,function(){return this.positionAbs=s.positionAbs,this.helperProportions=s.helperProportions,this.offset.click=s.offset.click,this!==o&&this._intersectsWith(this.containerCache)&&t.contains(o.element[0],this.element[0])&&(n=!1),n})),n?(o.isOver||(o.isOver=1,s._parent=i.helper.parent(),o.currentItem=i.helper.appendTo(o.element).data("ui-sortable-item",!0),o.options._helper=o.options.helper,o.options.helper=function(){return i.helper[0]},e.target=o.currentItem[0],o._mouseCapture(e,!0),o._mouseStart(e,!0,!0),o.offset.click.top=s.offset.click.top,o.offset.click.left=s.offset.click.left,o.offset.parent.left-=s.offset.parent.left-o.offset.parent.left,o.offset.parent.top-=s.offset.parent.top-o.offset.parent.top,s._trigger("toSortable",e),s.dropped=o.element,t.each(s.sortables,function(){this.refreshPositions()}),s.currentItem=s.element,o.fromOutside=s),o.currentItem&&(o._mouseDrag(e),i.position=o.position)):o.isOver&&(o.isOver=0,o.cancelHelperRemoval=!0,o.options._revert=o.options.revert,o.options.revert=!1,o._trigger("out",e,o._uiHash(o)),o._mouseStop(e,!0),o.options.revert=o.options._revert,o.options.helper=o.options._helper,o.placeholder&&o.placeholder.remove(),i.helper.appendTo(s._parent),s._refreshOffsets(e),i.position=s._generatePosition(e,!0),s._trigger("fromSortable",e),s.dropped=!1,t.each(s.sortables,function(){this.refreshPositions()}))})}}),t.ui.plugin.add("draggable","cursor",{start:function(e,i,s){var n=t("body"),o=s.options;n.css("cursor")&&(o._cursor=n.css("cursor")),n.css("cursor",o.cursor)},stop:function(e,i,s){var n=s.options;n._cursor&&t("body").css("cursor",n._cursor)}}),t.ui.plugin.add("draggable","opacity",{start:function(e,i,s){var n=t(i.helper),o=s.options;n.css("opacity")&&(o._opacity=n.css("opacity")),n.css("opacity",o.opacity)},stop:function(e,i,s){var n=s.options;n._opacity&&t(i.helper).css("opacity",n._opacity)}}),t.ui.plugin.add("draggable","scroll",{start:function(t,e,i){i.scrollParentNotHidden||(i.scrollParentNotHidden=i.helper.scrollParent(!1)),i.scrollParentNotHidden[0]!==i.document[0]&&"HTML"!==i.scrollParentNotHidden[0].tagName&&(i.overflowOffset=i.scrollParentNotHidden.offset())},drag:function(e,i,s){var n=s.options,o=!1,a=s.scrollParentNotHidden[0],r=s.document[0];a!==r&&"HTML"!==a.tagName?(n.axis&&"x"===n.axis||(s.overflowOffset.top+a.offsetHeight-e.pageY=0;d--)h=s.snapElements[d].left-s.margins.left,l=h+s.snapElements[d].width,c=s.snapElements[d].top-s.margins.top,u=c+s.snapElements[d].height,h-g>_||m>l+g||c-g>b||v>u+g||!t.contains(s.snapElements[d].item.ownerDocument,s.snapElements[d].item)?(s.snapElements[d].snapping&&s.options.snap.release&&s.options.snap.release.call(s.element,e,t.extend(s._uiHash(),{snapItem:s.snapElements[d].item})),s.snapElements[d].snapping=!1):("inner"!==f.snapMode&&(n=g>=Math.abs(c-b),o=g>=Math.abs(u-v),a=g>=Math.abs(h-_),r=g>=Math.abs(l-m),n&&(i.position.top=s._convertPositionTo("relative",{top:c-s.helperProportions.height,left:0}).top),o&&(i.position.top=s._convertPositionTo("relative",{top:u,left:0}).top),a&&(i.position.left=s._convertPositionTo("relative",{top:0,left:h-s.helperProportions.width}).left),r&&(i.position.left=s._convertPositionTo("relative",{top:0,left:l}).left)),p=n||o||a||r,"outer"!==f.snapMode&&(n=g>=Math.abs(c-v),o=g>=Math.abs(u-b),a=g>=Math.abs(h-m),r=g>=Math.abs(l-_),n&&(i.position.top=s._convertPositionTo("relative",{top:c,left:0}).top),o&&(i.position.top=s._convertPositionTo("relative",{top:u-s.helperProportions.height,left:0}).top),a&&(i.position.left=s._convertPositionTo("relative",{top:0,left:h}).left),r&&(i.position.left=s._convertPositionTo("relative",{top:0,left:l-s.helperProportions.width}).left)),!s.snapElements[d].snapping&&(n||o||a||r||p)&&s.options.snap.snap&&s.options.snap.snap.call(s.element,e,t.extend(s._uiHash(),{snapItem:s.snapElements[d].item})),s.snapElements[d].snapping=n||o||a||r||p)}}),t.ui.plugin.add("draggable","stack",{start:function(e,i,s){var n,o=s.options,a=t.makeArray(t(o.stack)).sort(function(e,i){return(parseInt(t(e).css("zIndex"),10)||0)-(parseInt(t(i).css("zIndex"),10)||0)});a.length&&(n=parseInt(t(a[0]).css("zIndex"),10)||0,t(a).each(function(e){t(this).css("zIndex",n+e)}),this.css("zIndex",n+a.length))}}),t.ui.plugin.add("draggable","zIndex",{start:function(e,i,s){var n=t(i.helper),o=s.options;n.css("zIndex")&&(o._zIndex=n.css("zIndex")),n.css("zIndex",o.zIndex)},stop:function(e,i,s){var n=s.options;n._zIndex&&t(i.helper).css("zIndex",n._zIndex)}}),t.ui.draggable,t.widget("ui.resizable",t.ui.mouse,{version:"1.12.1",widgetEventPrefix:"resize",options:{alsoResize:!1,animate:!1,animateDuration:"slow",animateEasing:"swing",aspectRatio:!1,autoHide:!1,classes:{"ui-resizable-se":"ui-icon ui-icon-gripsmall-diagonal-se"},containment:!1,ghost:!1,grid:!1,handles:"e,s,se",helper:!1,maxHeight:null,maxWidth:null,minHeight:10,minWidth:10,zIndex:90,resize:null,start:null,stop:null},_num:function(t){return parseFloat(t)||0},_isNumber:function(t){return!isNaN(parseFloat(t))},_hasScroll:function(e,i){if("hidden"===t(e).css("overflow"))return!1;var s=i&&"left"===i?"scrollLeft":"scrollTop",n=!1;return e[s]>0?!0:(e[s]=1,n=e[s]>0,e[s]=0,n)},_create:function(){var e,i=this.options,s=this;this._addClass("ui-resizable"),t.extend(this,{_aspectRatio:!!i.aspectRatio,aspectRatio:i.aspectRatio,originalElement:this.element,_proportionallyResizeElements:[],_helper:i.helper||i.ghost||i.animate?i.helper||"ui-resizable-helper":null}),this.element[0].nodeName.match(/^(canvas|textarea|input|select|button|img)$/i)&&(this.element.wrap(t("
").css({position:this.element.css("position"),width:this.element.outerWidth(),height:this.element.outerHeight(),top:this.element.css("top"),left:this.element.css("left")})),this.element=this.element.parent().data("ui-resizable",this.element.resizable("instance")),this.elementIsWrapper=!0,e={marginTop:this.originalElement.css("marginTop"),marginRight:this.originalElement.css("marginRight"),marginBottom:this.originalElement.css("marginBottom"),marginLeft:this.originalElement.css("marginLeft")},this.element.css(e),this.originalElement.css("margin",0),this.originalResizeStyle=this.originalElement.css("resize"),this.originalElement.css("resize","none"),this._proportionallyResizeElements.push(this.originalElement.css({position:"static",zoom:1,display:"block"})),this.originalElement.css(e),this._proportionallyResize()),this._setupHandles(),i.autoHide&&t(this.element).on("mouseenter",function(){i.disabled||(s._removeClass("ui-resizable-autohide"),s._handles.show())}).on("mouseleave",function(){i.disabled||s.resizing||(s._addClass("ui-resizable-autohide"),s._handles.hide())}),this._mouseInit()},_destroy:function(){this._mouseDestroy();var e,i=function(e){t(e).removeData("resizable").removeData("ui-resizable").off(".resizable").find(".ui-resizable-handle").remove()};return this.elementIsWrapper&&(i(this.element),e=this.element,this.originalElement.css({position:e.css("position"),width:e.outerWidth(),height:e.outerHeight(),top:e.css("top"),left:e.css("left")}).insertAfter(e),e.remove()),this.originalElement.css("resize",this.originalResizeStyle),i(this.originalElement),this},_setOption:function(t,e){switch(this._super(t,e),t){case"handles":this._removeHandles(),this._setupHandles();break;default:}},_setupHandles:function(){var e,i,s,n,o,a=this.options,r=this;if(this.handles=a.handles||(t(".ui-resizable-handle",this.element).length?{n:".ui-resizable-n",e:".ui-resizable-e",s:".ui-resizable-s",w:".ui-resizable-w",se:".ui-resizable-se",sw:".ui-resizable-sw",ne:".ui-resizable-ne",nw:".ui-resizable-nw"}:"e,s,se"),this._handles=t(),this.handles.constructor===String)for("all"===this.handles&&(this.handles="n,e,s,w,se,sw,ne,nw"),s=this.handles.split(","),this.handles={},i=0;s.length>i;i++)e=t.trim(s[i]),n="ui-resizable-"+e,o=t("
"),this._addClass(o,"ui-resizable-handle "+n),o.css({zIndex:a.zIndex}),this.handles[e]=".ui-resizable-"+e,this.element.append(o);this._renderAxis=function(e){var i,s,n,o;e=e||this.element;for(i in this.handles)this.handles[i].constructor===String?this.handles[i]=this.element.children(this.handles[i]).first().show():(this.handles[i].jquery||this.handles[i].nodeType)&&(this.handles[i]=t(this.handles[i]),this._on(this.handles[i],{mousedown:r._mouseDown})),this.elementIsWrapper&&this.originalElement[0].nodeName.match(/^(textarea|input|select|button)$/i)&&(s=t(this.handles[i],this.element),o=/sw|ne|nw|se|n|s/.test(i)?s.outerHeight():s.outerWidth(),n=["padding",/ne|nw|n/.test(i)?"Top":/se|sw|s/.test(i)?"Bottom":/^e$/.test(i)?"Right":"Left"].join(""),e.css(n,o),this._proportionallyResize()),this._handles=this._handles.add(this.handles[i])},this._renderAxis(this.element),this._handles=this._handles.add(this.element.find(".ui-resizable-handle")),this._handles.disableSelection(),this._handles.on("mouseover",function(){r.resizing||(this.className&&(o=this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i)),r.axis=o&&o[1]?o[1]:"se")}),a.autoHide&&(this._handles.hide(),this._addClass("ui-resizable-autohide"))},_removeHandles:function(){this._handles.remove()},_mouseCapture:function(e){var i,s,n=!1;for(i in this.handles)s=t(this.handles[i])[0],(s===e.target||t.contains(s,e.target))&&(n=!0);return!this.options.disabled&&n},_mouseStart:function(e){var i,s,n,o=this.options,a=this.element;return this.resizing=!0,this._renderProxy(),i=this._num(this.helper.css("left")),s=this._num(this.helper.css("top")),o.containment&&(i+=t(o.containment).scrollLeft()||0,s+=t(o.containment).scrollTop()||0),this.offset=this.helper.offset(),this.position={left:i,top:s},this.size=this._helper?{width:this.helper.width(),height:this.helper.height()}:{width:a.width(),height:a.height()},this.originalSize=this._helper?{width:a.outerWidth(),height:a.outerHeight()}:{width:a.width(),height:a.height()},this.sizeDiff={width:a.outerWidth()-a.width(),height:a.outerHeight()-a.height()},this.originalPosition={left:i,top:s},this.originalMousePosition={left:e.pageX,top:e.pageY},this.aspectRatio="number"==typeof o.aspectRatio?o.aspectRatio:this.originalSize.width/this.originalSize.height||1,n=t(".ui-resizable-"+this.axis).css("cursor"),t("body").css("cursor","auto"===n?this.axis+"-resize":n),this._addClass("ui-resizable-resizing"),this._propagate("start",e),!0},_mouseDrag:function(e){var i,s,n=this.originalMousePosition,o=this.axis,a=e.pageX-n.left||0,r=e.pageY-n.top||0,h=this._change[o];return this._updatePrevProperties(),h?(i=h.apply(this,[e,a,r]),this._updateVirtualBoundaries(e.shiftKey),(this._aspectRatio||e.shiftKey)&&(i=this._updateRatio(i,e)),i=this._respectSize(i,e),this._updateCache(i),this._propagate("resize",e),s=this._applyChanges(),!this._helper&&this._proportionallyResizeElements.length&&this._proportionallyResize(),t.isEmptyObject(s)||(this._updatePrevProperties(),this._trigger("resize",e,this.ui()),this._applyChanges()),!1):!1},_mouseStop:function(e){this.resizing=!1;var i,s,n,o,a,r,h,l=this.options,c=this;return this._helper&&(i=this._proportionallyResizeElements,s=i.length&&/textarea/i.test(i[0].nodeName),n=s&&this._hasScroll(i[0],"left")?0:c.sizeDiff.height,o=s?0:c.sizeDiff.width,a={width:c.helper.width()-o,height:c.helper.height()-n},r=parseFloat(c.element.css("left"))+(c.position.left-c.originalPosition.left)||null,h=parseFloat(c.element.css("top"))+(c.position.top-c.originalPosition.top)||null,l.animate||this.element.css(t.extend(a,{top:h,left:r})),c.helper.height(c.size.height),c.helper.width(c.size.width),this._helper&&!l.animate&&this._proportionallyResize()),t("body").css("cursor","auto"),this._removeClass("ui-resizable-resizing"),this._propagate("stop",e),this._helper&&this.helper.remove(),!1},_updatePrevProperties:function(){this.prevPosition={top:this.position.top,left:this.position.left},this.prevSize={width:this.size.width,height:this.size.height}},_applyChanges:function(){var t={};return this.position.top!==this.prevPosition.top&&(t.top=this.position.top+"px"),this.position.left!==this.prevPosition.left&&(t.left=this.position.left+"px"),this.size.width!==this.prevSize.width&&(t.width=this.size.width+"px"),this.size.height!==this.prevSize.height&&(t.height=this.size.height+"px"),this.helper.css(t),t},_updateVirtualBoundaries:function(t){var e,i,s,n,o,a=this.options;o={minWidth:this._isNumber(a.minWidth)?a.minWidth:0,maxWidth:this._isNumber(a.maxWidth)?a.maxWidth:1/0,minHeight:this._isNumber(a.minHeight)?a.minHeight:0,maxHeight:this._isNumber(a.maxHeight)?a.maxHeight:1/0},(this._aspectRatio||t)&&(e=o.minHeight*this.aspectRatio,s=o.minWidth/this.aspectRatio,i=o.maxHeight*this.aspectRatio,n=o.maxWidth/this.aspectRatio,e>o.minWidth&&(o.minWidth=e),s>o.minHeight&&(o.minHeight=s),o.maxWidth>i&&(o.maxWidth=i),o.maxHeight>n&&(o.maxHeight=n)),this._vBoundaries=o},_updateCache:function(t){this.offset=this.helper.offset(),this._isNumber(t.left)&&(this.position.left=t.left),this._isNumber(t.top)&&(this.position.top=t.top),this._isNumber(t.height)&&(this.size.height=t.height),this._isNumber(t.width)&&(this.size.width=t.width)},_updateRatio:function(t){var e=this.position,i=this.size,s=this.axis;return this._isNumber(t.height)?t.width=t.height*this.aspectRatio:this._isNumber(t.width)&&(t.height=t.width/this.aspectRatio),"sw"===s&&(t.left=e.left+(i.width-t.width),t.top=null),"nw"===s&&(t.top=e.top+(i.height-t.height),t.left=e.left+(i.width-t.width)),t},_respectSize:function(t){var e=this._vBoundaries,i=this.axis,s=this._isNumber(t.width)&&e.maxWidth&&e.maxWidtht.width,a=this._isNumber(t.height)&&e.minHeight&&e.minHeight>t.height,r=this.originalPosition.left+this.originalSize.width,h=this.originalPosition.top+this.originalSize.height,l=/sw|nw|w/.test(i),c=/nw|ne|n/.test(i);return o&&(t.width=e.minWidth),a&&(t.height=e.minHeight),s&&(t.width=e.maxWidth),n&&(t.height=e.maxHeight),o&&l&&(t.left=r-e.minWidth),s&&l&&(t.left=r-e.maxWidth),a&&c&&(t.top=h-e.minHeight),n&&c&&(t.top=h-e.maxHeight),t.width||t.height||t.left||!t.top?t.width||t.height||t.top||!t.left||(t.left=null):t.top=null,t},_getPaddingPlusBorderDimensions:function(t){for(var e=0,i=[],s=[t.css("borderTopWidth"),t.css("borderRightWidth"),t.css("borderBottomWidth"),t.css("borderLeftWidth")],n=[t.css("paddingTop"),t.css("paddingRight"),t.css("paddingBottom"),t.css("paddingLeft")];4>e;e++)i[e]=parseFloat(s[e])||0,i[e]+=parseFloat(n[e])||0;return{height:i[0]+i[2],width:i[1]+i[3]}},_proportionallyResize:function(){if(this._proportionallyResizeElements.length)for(var t,e=0,i=this.helper||this.element;this._proportionallyResizeElements.length>e;e++)t=this._proportionallyResizeElements[e],this.outerDimensions||(this.outerDimensions=this._getPaddingPlusBorderDimensions(t)),t.css({height:i.height()-this.outerDimensions.height||0,width:i.width()-this.outerDimensions.width||0})},_renderProxy:function(){var e=this.element,i=this.options;this.elementOffset=e.offset(),this._helper?(this.helper=this.helper||t("
"),this._addClass(this.helper,this._helper),this.helper.css({width:this.element.outerWidth(),height:this.element.outerHeight(),position:"absolute",left:this.elementOffset.left+"px",top:this.elementOffset.top+"px",zIndex:++i.zIndex}),this.helper.appendTo("body").disableSelection()):this.helper=this.element},_change:{e:function(t,e){return{width:this.originalSize.width+e}},w:function(t,e){var i=this.originalSize,s=this.originalPosition;return{left:s.left+e,width:i.width-e}},n:function(t,e,i){var s=this.originalSize,n=this.originalPosition;return{top:n.top+i,height:s.height-i}},s:function(t,e,i){return{height:this.originalSize.height+i}},se:function(e,i,s){return t.extend(this._change.s.apply(this,arguments),this._change.e.apply(this,[e,i,s]))},sw:function(e,i,s){return t.extend(this._change.s.apply(this,arguments),this._change.w.apply(this,[e,i,s]))},ne:function(e,i,s){return t.extend(this._change.n.apply(this,arguments),this._change.e.apply(this,[e,i,s]))},nw:function(e,i,s){return t.extend(this._change.n.apply(this,arguments),this._change.w.apply(this,[e,i,s]))}},_propagate:function(e,i){t.ui.plugin.call(this,e,[i,this.ui()]),"resize"!==e&&this._trigger(e,i,this.ui())},plugins:{},ui:function(){return{originalElement:this.originalElement,element:this.element,helper:this.helper,position:this.position,size:this.size,originalSize:this.originalSize,originalPosition:this.originalPosition}}}),t.ui.plugin.add("resizable","animate",{stop:function(e){var i=t(this).resizable("instance"),s=i.options,n=i._proportionallyResizeElements,o=n.length&&/textarea/i.test(n[0].nodeName),a=o&&i._hasScroll(n[0],"left")?0:i.sizeDiff.height,r=o?0:i.sizeDiff.width,h={width:i.size.width-r,height:i.size.height-a},l=parseFloat(i.element.css("left"))+(i.position.left-i.originalPosition.left)||null,c=parseFloat(i.element.css("top"))+(i.position.top-i.originalPosition.top)||null;i.element.animate(t.extend(h,c&&l?{top:c,left:l}:{}),{duration:s.animateDuration,easing:s.animateEasing,step:function(){var s={width:parseFloat(i.element.css("width")),height:parseFloat(i.element.css("height")),top:parseFloat(i.element.css("top")),left:parseFloat(i.element.css("left"))};n&&n.length&&t(n[0]).css({width:s.width,height:s.height}),i._updateCache(s),i._propagate("resize",e)}})}}),t.ui.plugin.add("resizable","containment",{start:function(){var e,i,s,n,o,a,r,h=t(this).resizable("instance"),l=h.options,c=h.element,u=l.containment,d=u instanceof t?u.get(0):/parent/.test(u)?c.parent().get(0):u;d&&(h.containerElement=t(d),/document/.test(u)||u===document?(h.containerOffset={left:0,top:0},h.containerPosition={left:0,top:0},h.parentData={element:t(document),left:0,top:0,width:t(document).width(),height:t(document).height()||document.body.parentNode.scrollHeight}):(e=t(d),i=[],t(["Top","Right","Left","Bottom"]).each(function(t,s){i[t]=h._num(e.css("padding"+s))}),h.containerOffset=e.offset(),h.containerPosition=e.position(),h.containerSize={height:e.innerHeight()-i[3],width:e.innerWidth()-i[1]},s=h.containerOffset,n=h.containerSize.height,o=h.containerSize.width,a=h._hasScroll(d,"left")?d.scrollWidth:o,r=h._hasScroll(d)?d.scrollHeight:n,h.parentData={element:d,left:s.left,top:s.top,width:a,height:r}))},resize:function(e){var i,s,n,o,a=t(this).resizable("instance"),r=a.options,h=a.containerOffset,l=a.position,c=a._aspectRatio||e.shiftKey,u={top:0,left:0},d=a.containerElement,p=!0;d[0]!==document&&/static/.test(d.css("position"))&&(u=h),l.left<(a._helper?h.left:0)&&(a.size.width=a.size.width+(a._helper?a.position.left-h.left:a.position.left-u.left),c&&(a.size.height=a.size.width/a.aspectRatio,p=!1),a.position.left=r.helper?h.left:0),l.top<(a._helper?h.top:0)&&(a.size.height=a.size.height+(a._helper?a.position.top-h.top:a.position.top),c&&(a.size.width=a.size.height*a.aspectRatio,p=!1),a.position.top=a._helper?h.top:0),n=a.containerElement.get(0)===a.element.parent().get(0),o=/relative|absolute/.test(a.containerElement.css("position")),n&&o?(a.offset.left=a.parentData.left+a.position.left,a.offset.top=a.parentData.top+a.position.top):(a.offset.left=a.element.offset().left,a.offset.top=a.element.offset().top),i=Math.abs(a.sizeDiff.width+(a._helper?a.offset.left-u.left:a.offset.left-h.left)),s=Math.abs(a.sizeDiff.height+(a._helper?a.offset.top-u.top:a.offset.top-h.top)),i+a.size.width>=a.parentData.width&&(a.size.width=a.parentData.width-i,c&&(a.size.height=a.size.width/a.aspectRatio,p=!1)),s+a.size.height>=a.parentData.height&&(a.size.height=a.parentData.height-s,c&&(a.size.width=a.size.height*a.aspectRatio,p=!1)),p||(a.position.left=a.prevPosition.left,a.position.top=a.prevPosition.top,a.size.width=a.prevSize.width,a.size.height=a.prevSize.height)},stop:function(){var e=t(this).resizable("instance"),i=e.options,s=e.containerOffset,n=e.containerPosition,o=e.containerElement,a=t(e.helper),r=a.offset(),h=a.outerWidth()-e.sizeDiff.width,l=a.outerHeight()-e.sizeDiff.height;e._helper&&!i.animate&&/relative/.test(o.css("position"))&&t(this).css({left:r.left-n.left-s.left,width:h,height:l}),e._helper&&!i.animate&&/static/.test(o.css("position"))&&t(this).css({left:r.left-n.left-s.left,width:h,height:l})}}),t.ui.plugin.add("resizable","alsoResize",{start:function(){var e=t(this).resizable("instance"),i=e.options;t(i.alsoResize).each(function(){var e=t(this);e.data("ui-resizable-alsoresize",{width:parseFloat(e.width()),height:parseFloat(e.height()),left:parseFloat(e.css("left")),top:parseFloat(e.css("top"))})})},resize:function(e,i){var s=t(this).resizable("instance"),n=s.options,o=s.originalSize,a=s.originalPosition,r={height:s.size.height-o.height||0,width:s.size.width-o.width||0,top:s.position.top-a.top||0,left:s.position.left-a.left||0};t(n.alsoResize).each(function(){var e=t(this),s=t(this).data("ui-resizable-alsoresize"),n={},o=e.parents(i.originalElement[0]).length?["width","height"]:["width","height","top","left"];t.each(o,function(t,e){var i=(s[e]||0)+(r[e]||0);i&&i>=0&&(n[e]=i||null)}),e.css(n)})},stop:function(){t(this).removeData("ui-resizable-alsoresize")}}),t.ui.plugin.add("resizable","ghost",{start:function(){var e=t(this).resizable("instance"),i=e.size;e.ghost=e.originalElement.clone(),e.ghost.css({opacity:.25,display:"block",position:"relative",height:i.height,width:i.width,margin:0,left:0,top:0}),e._addClass(e.ghost,"ui-resizable-ghost"),t.uiBackCompat!==!1&&"string"==typeof e.options.ghost&&e.ghost.addClass(this.options.ghost),e.ghost.appendTo(e.helper)},resize:function(){var e=t(this).resizable("instance");e.ghost&&e.ghost.css({position:"relative",height:e.size.height,width:e.size.width})},stop:function(){var e=t(this).resizable("instance");e.ghost&&e.helper&&e.helper.get(0).removeChild(e.ghost.get(0))}}),t.ui.plugin.add("resizable","grid",{resize:function(){var e,i=t(this).resizable("instance"),s=i.options,n=i.size,o=i.originalSize,a=i.originalPosition,r=i.axis,h="number"==typeof s.grid?[s.grid,s.grid]:s.grid,l=h[0]||1,c=h[1]||1,u=Math.round((n.width-o.width)/l)*l,d=Math.round((n.height-o.height)/c)*c,p=o.width+u,f=o.height+d,g=s.maxWidth&&p>s.maxWidth,m=s.maxHeight&&f>s.maxHeight,_=s.minWidth&&s.minWidth>p,v=s.minHeight&&s.minHeight>f;s.grid=h,_&&(p+=l),v&&(f+=c),g&&(p-=l),m&&(f-=c),/^(se|s|e)$/.test(r)?(i.size.width=p,i.size.height=f):/^(ne)$/.test(r)?(i.size.width=p,i.size.height=f,i.position.top=a.top-d):/^(sw)$/.test(r)?(i.size.width=p,i.size.height=f,i.position.left=a.left-u):((0>=f-c||0>=p-l)&&(e=i._getPaddingPlusBorderDimensions(this)),f-c>0?(i.size.height=f,i.position.top=a.top-d):(f=c-e.height,i.size.height=f,i.position.top=a.top+o.height-f),p-l>0?(i.size.width=p,i.position.left=a.left-u):(p=l-e.width,i.size.width=p,i.position.left=a.left+o.width-p))}}),t.ui.resizable,t.widget("ui.dialog",{version:"1.12.1",options:{appendTo:"body",autoOpen:!0,buttons:[],classes:{"ui-dialog":"ui-corner-all","ui-dialog-titlebar":"ui-corner-all"},closeOnEscape:!0,closeText:"Close",draggable:!0,hide:null,height:"auto",maxHeight:null,maxWidth:null,minHeight:150,minWidth:150,modal:!1,position:{my:"center",at:"center",of:window,collision:"fit",using:function(e){var i=t(this).css(e).offset().top;0>i&&t(this).css("top",e.top-i)}},resizable:!0,show:null,title:null,width:300,beforeClose:null,close:null,drag:null,dragStart:null,dragStop:null,focus:null,open:null,resize:null,resizeStart:null,resizeStop:null},sizeRelatedOptions:{buttons:!0,height:!0,maxHeight:!0,maxWidth:!0,minHeight:!0,minWidth:!0,width:!0},resizableRelatedOptions:{maxHeight:!0,maxWidth:!0,minHeight:!0,minWidth:!0},_create:function(){this.originalCss={display:this.element[0].style.display,width:this.element[0].style.width,minHeight:this.element[0].style.minHeight,maxHeight:this.element[0].style.maxHeight,height:this.element[0].style.height},this.originalPosition={parent:this.element.parent(),index:this.element.parent().children().index(this.element)},this.originalTitle=this.element.attr("title"),null==this.options.title&&null!=this.originalTitle&&(this.options.title=this.originalTitle),this.options.disabled&&(this.options.disabled=!1),this._createWrapper(),this.element.show().removeAttr("title").appendTo(this.uiDialog),this._addClass("ui-dialog-content","ui-widget-content"),this._createTitlebar(),this._createButtonPane(),this.options.draggable&&t.fn.draggable&&this._makeDraggable(),this.options.resizable&&t.fn.resizable&&this._makeResizable(),this._isOpen=!1,this._trackFocus()},_init:function(){this.options.autoOpen&&this.open()},_appendTo:function(){var e=this.options.appendTo;return e&&(e.jquery||e.nodeType)?t(e):this.document.find(e||"body").eq(0)},_destroy:function(){var t,e=this.originalPosition;this._untrackInstance(),this._destroyOverlay(),this.element.removeUniqueId().css(this.originalCss).detach(),this.uiDialog.remove(),this.originalTitle&&this.element.attr("title",this.originalTitle),t=e.parent.children().eq(e.index),t.length&&t[0]!==this.element[0]?t.before(this.element):e.parent.append(this.element)},widget:function(){return this.uiDialog },disable:t.noop,enable:t.noop,close:function(e){var i=this;this._isOpen&&this._trigger("beforeClose",e)!==!1&&(this._isOpen=!1,this._focusedElement=null,this._destroyOverlay(),this._untrackInstance(),this.opener.filter(":focusable").trigger("focus").length||t.ui.safeBlur(t.ui.safeActiveElement(this.document[0])),this._hide(this.uiDialog,this.options.hide,function(){i._trigger("close",e)}))},isOpen:function(){return this._isOpen},moveToTop:function(){this._moveToTop()},_moveToTop:function(e,i){var s=!1,n=this.uiDialog.siblings(".ui-front:visible").map(function(){return+t(this).css("z-index")}).get(),o=Math.max.apply(null,n);return o>=+this.uiDialog.css("z-index")&&(this.uiDialog.css("z-index",o+1),s=!0),s&&!i&&this._trigger("focus",e),s},open:function(){var e=this;return this._isOpen?(this._moveToTop()&&this._focusTabbable(),void 0):(this._isOpen=!0,this.opener=t(t.ui.safeActiveElement(this.document[0])),this._size(),this._position(),this._createOverlay(),this._moveToTop(null,!0),this.overlay&&this.overlay.css("z-index",this.uiDialog.css("z-index")-1),this._show(this.uiDialog,this.options.show,function(){e._focusTabbable(),e._trigger("focus")}),this._makeFocusTarget(),this._trigger("open"),void 0)},_focusTabbable:function(){var t=this._focusedElement;t||(t=this.element.find("[autofocus]")),t.length||(t=this.element.find(":tabbable")),t.length||(t=this.uiDialogButtonPane.find(":tabbable")),t.length||(t=this.uiDialogTitlebarClose.filter(":tabbable")),t.length||(t=this.uiDialog),t.eq(0).trigger("focus")},_keepFocus:function(e){function i(){var e=t.ui.safeActiveElement(this.document[0]),i=this.uiDialog[0]===e||t.contains(this.uiDialog[0],e);i||this._focusTabbable()}e.preventDefault(),i.call(this),this._delay(i)},_createWrapper:function(){this.uiDialog=t("
").hide().attr({tabIndex:-1,role:"dialog"}).appendTo(this._appendTo()),this._addClass(this.uiDialog,"ui-dialog","ui-widget ui-widget-content ui-front"),this._on(this.uiDialog,{keydown:function(e){if(this.options.closeOnEscape&&!e.isDefaultPrevented()&&e.keyCode&&e.keyCode===t.ui.keyCode.ESCAPE)return e.preventDefault(),this.close(e),void 0;if(e.keyCode===t.ui.keyCode.TAB&&!e.isDefaultPrevented()){var i=this.uiDialog.find(":tabbable"),s=i.filter(":first"),n=i.filter(":last");e.target!==n[0]&&e.target!==this.uiDialog[0]||e.shiftKey?e.target!==s[0]&&e.target!==this.uiDialog[0]||!e.shiftKey||(this._delay(function(){n.trigger("focus")}),e.preventDefault()):(this._delay(function(){s.trigger("focus")}),e.preventDefault())}},mousedown:function(t){this._moveToTop(t)&&this._focusTabbable()}}),this.element.find("[aria-describedby]").length||this.uiDialog.attr({"aria-describedby":this.element.uniqueId().attr("id")})},_createTitlebar:function(){var e;this.uiDialogTitlebar=t("
"),this._addClass(this.uiDialogTitlebar,"ui-dialog-titlebar","ui-widget-header ui-helper-clearfix"),this._on(this.uiDialogTitlebar,{mousedown:function(e){t(e.target).closest(".ui-dialog-titlebar-close")||this.uiDialog.trigger("focus")}}),this.uiDialogTitlebarClose=t("").button({label:t("").text(this.options.closeText).html(),icon:"ui-icon-closethick",showLabel:!1}).appendTo(this.uiDialogTitlebar),this._addClass(this.uiDialogTitlebarClose,"ui-dialog-titlebar-close"),this._on(this.uiDialogTitlebarClose,{click:function(t){t.preventDefault(),this.close(t)}}),e=t("").uniqueId().prependTo(this.uiDialogTitlebar),this._addClass(e,"ui-dialog-title"),this._title(e),this.uiDialogTitlebar.prependTo(this.uiDialog),this.uiDialog.attr({"aria-labelledby":e.attr("id")})},_title:function(t){this.options.title?t.text(this.options.title):t.html(" ")},_createButtonPane:function(){this.uiDialogButtonPane=t("
"),this._addClass(this.uiDialogButtonPane,"ui-dialog-buttonpane","ui-widget-content ui-helper-clearfix"),this.uiButtonSet=t("
").appendTo(this.uiDialogButtonPane),this._addClass(this.uiButtonSet,"ui-dialog-buttonset"),this._createButtons()},_createButtons:function(){var e=this,i=this.options.buttons;return this.uiDialogButtonPane.remove(),this.uiButtonSet.empty(),t.isEmptyObject(i)||t.isArray(i)&&!i.length?(this._removeClass(this.uiDialog,"ui-dialog-buttons"),void 0):(t.each(i,function(i,s){var n,o;s=t.isFunction(s)?{click:s,text:i}:s,s=t.extend({type:"button"},s),n=s.click,o={icon:s.icon,iconPosition:s.iconPosition,showLabel:s.showLabel,icons:s.icons,text:s.text},delete s.click,delete s.icon,delete s.iconPosition,delete s.showLabel,delete s.icons,"boolean"==typeof s.text&&delete s.text,t("",s).button(o).appendTo(e.uiButtonSet).on("click",function(){n.apply(e.element[0],arguments)})}),this._addClass(this.uiDialog,"ui-dialog-buttons"),this.uiDialogButtonPane.appendTo(this.uiDialog),void 0)},_makeDraggable:function(){function e(t){return{position:t.position,offset:t.offset}}var i=this,s=this.options;this.uiDialog.draggable({cancel:".ui-dialog-content, .ui-dialog-titlebar-close",handle:".ui-dialog-titlebar",containment:"document",start:function(s,n){i._addClass(t(this),"ui-dialog-dragging"),i._blockFrames(),i._trigger("dragStart",s,e(n))},drag:function(t,s){i._trigger("drag",t,e(s))},stop:function(n,o){var a=o.offset.left-i.document.scrollLeft(),r=o.offset.top-i.document.scrollTop();s.position={my:"left top",at:"left"+(a>=0?"+":"")+a+" "+"top"+(r>=0?"+":"")+r,of:i.window},i._removeClass(t(this),"ui-dialog-dragging"),i._unblockFrames(),i._trigger("dragStop",n,e(o))}})},_makeResizable:function(){function e(t){return{originalPosition:t.originalPosition,originalSize:t.originalSize,position:t.position,size:t.size}}var i=this,s=this.options,n=s.resizable,o=this.uiDialog.css("position"),a="string"==typeof n?n:"n,e,s,w,se,sw,ne,nw";this.uiDialog.resizable({cancel:".ui-dialog-content",containment:"document",alsoResize:this.element,maxWidth:s.maxWidth,maxHeight:s.maxHeight,minWidth:s.minWidth,minHeight:this._minHeight(),handles:a,start:function(s,n){i._addClass(t(this),"ui-dialog-resizing"),i._blockFrames(),i._trigger("resizeStart",s,e(n))},resize:function(t,s){i._trigger("resize",t,e(s))},stop:function(n,o){var a=i.uiDialog.offset(),r=a.left-i.document.scrollLeft(),h=a.top-i.document.scrollTop();s.height=i.uiDialog.height(),s.width=i.uiDialog.width(),s.position={my:"left top",at:"left"+(r>=0?"+":"")+r+" "+"top"+(h>=0?"+":"")+h,of:i.window},i._removeClass(t(this),"ui-dialog-resizing"),i._unblockFrames(),i._trigger("resizeStop",n,e(o))}}).css("position",o)},_trackFocus:function(){this._on(this.widget(),{focusin:function(e){this._makeFocusTarget(),this._focusedElement=t(e.target)}})},_makeFocusTarget:function(){this._untrackInstance(),this._trackingInstances().unshift(this)},_untrackInstance:function(){var e=this._trackingInstances(),i=t.inArray(this,e);-1!==i&&e.splice(i,1)},_trackingInstances:function(){var t=this.document.data("ui-dialog-instances");return t||(t=[],this.document.data("ui-dialog-instances",t)),t},_minHeight:function(){var t=this.options;return"auto"===t.height?t.minHeight:Math.min(t.minHeight,t.height)},_position:function(){var t=this.uiDialog.is(":visible");t||this.uiDialog.show(),this.uiDialog.position(this.options.position),t||this.uiDialog.hide()},_setOptions:function(e){var i=this,s=!1,n={};t.each(e,function(t,e){i._setOption(t,e),t in i.sizeRelatedOptions&&(s=!0),t in i.resizableRelatedOptions&&(n[t]=e)}),s&&(this._size(),this._position()),this.uiDialog.is(":data(ui-resizable)")&&this.uiDialog.resizable("option",n)},_setOption:function(e,i){var s,n,o=this.uiDialog;"disabled"!==e&&(this._super(e,i),"appendTo"===e&&this.uiDialog.appendTo(this._appendTo()),"buttons"===e&&this._createButtons(),"closeText"===e&&this.uiDialogTitlebarClose.button({label:t("").text(""+this.options.closeText).html()}),"draggable"===e&&(s=o.is(":data(ui-draggable)"),s&&!i&&o.draggable("destroy"),!s&&i&&this._makeDraggable()),"position"===e&&this._position(),"resizable"===e&&(n=o.is(":data(ui-resizable)"),n&&!i&&o.resizable("destroy"),n&&"string"==typeof i&&o.resizable("option","handles",i),n||i===!1||this._makeResizable()),"title"===e&&this._title(this.uiDialogTitlebar.find(".ui-dialog-title")))},_size:function(){var t,e,i,s=this.options;this.element.show().css({width:"auto",minHeight:0,maxHeight:"none",height:0}),s.minWidth>s.width&&(s.width=s.minWidth),t=this.uiDialog.css({height:"auto",width:s.width}).outerHeight(),e=Math.max(0,s.minHeight-t),i="number"==typeof s.maxHeight?Math.max(0,s.maxHeight-t):"none","auto"===s.height?this.element.css({minHeight:e,maxHeight:i,height:"auto"}):this.element.height(Math.max(0,s.height-t)),this.uiDialog.is(":data(ui-resizable)")&&this.uiDialog.resizable("option","minHeight",this._minHeight())},_blockFrames:function(){this.iframeBlocks=this.document.find("iframe").map(function(){var e=t(this);return t("
").css({position:"absolute",width:e.outerWidth(),height:e.outerHeight()}).appendTo(e.parent()).offset(e.offset())[0]})},_unblockFrames:function(){this.iframeBlocks&&(this.iframeBlocks.remove(),delete this.iframeBlocks)},_allowInteraction:function(e){return t(e.target).closest(".ui-dialog").length?!0:!!t(e.target).closest(".ui-datepicker").length},_createOverlay:function(){if(this.options.modal){var e=!0;this._delay(function(){e=!1}),this.document.data("ui-dialog-overlays")||this._on(this.document,{focusin:function(t){e||this._allowInteraction(t)||(t.preventDefault(),this._trackingInstances()[0]._focusTabbable())}}),this.overlay=t("
").appendTo(this._appendTo()),this._addClass(this.overlay,null,"ui-widget-overlay ui-front"),this._on(this.overlay,{mousedown:"_keepFocus"}),this.document.data("ui-dialog-overlays",(this.document.data("ui-dialog-overlays")||0)+1)}},_destroyOverlay:function(){if(this.options.modal&&this.overlay){var t=this.document.data("ui-dialog-overlays")-1;t?this.document.data("ui-dialog-overlays",t):(this._off(this.document,"focusin"),this.document.removeData("ui-dialog-overlays")),this.overlay.remove(),this.overlay=null}}}),t.uiBackCompat!==!1&&t.widget("ui.dialog",t.ui.dialog,{options:{dialogClass:""},_createWrapper:function(){this._super(),this.uiDialog.addClass(this.options.dialogClass)},_setOption:function(t,e){"dialogClass"===t&&this.uiDialog.removeClass(this.options.dialogClass).addClass(e),this._superApply(arguments)}}),t.ui.dialog,t.widget("ui.droppable",{version:"1.12.1",widgetEventPrefix:"drop",options:{accept:"*",addClasses:!0,greedy:!1,scope:"default",tolerance:"intersect",activate:null,deactivate:null,drop:null,out:null,over:null},_create:function(){var e,i=this.options,s=i.accept;this.isover=!1,this.isout=!0,this.accept=t.isFunction(s)?s:function(t){return t.is(s)},this.proportions=function(){return arguments.length?(e=arguments[0],void 0):e?e:e={width:this.element[0].offsetWidth,height:this.element[0].offsetHeight}},this._addToManager(i.scope),i.addClasses&&this._addClass("ui-droppable")},_addToManager:function(e){t.ui.ddmanager.droppables[e]=t.ui.ddmanager.droppables[e]||[],t.ui.ddmanager.droppables[e].push(this)},_splice:function(t){for(var e=0;t.length>e;e++)t[e]===this&&t.splice(e,1)},_destroy:function(){var e=t.ui.ddmanager.droppables[this.options.scope];this._splice(e)},_setOption:function(e,i){if("accept"===e)this.accept=t.isFunction(i)?i:function(t){return t.is(i)};else if("scope"===e){var s=t.ui.ddmanager.droppables[this.options.scope];this._splice(s),this._addToManager(i)}this._super(e,i)},_activate:function(e){var i=t.ui.ddmanager.current;this._addActiveClass(),i&&this._trigger("activate",e,this.ui(i))},_deactivate:function(e){var i=t.ui.ddmanager.current;this._removeActiveClass(),i&&this._trigger("deactivate",e,this.ui(i))},_over:function(e){var i=t.ui.ddmanager.current;i&&(i.currentItem||i.element)[0]!==this.element[0]&&this.accept.call(this.element[0],i.currentItem||i.element)&&(this._addHoverClass(),this._trigger("over",e,this.ui(i)))},_out:function(e){var i=t.ui.ddmanager.current;i&&(i.currentItem||i.element)[0]!==this.element[0]&&this.accept.call(this.element[0],i.currentItem||i.element)&&(this._removeHoverClass(),this._trigger("out",e,this.ui(i)))},_drop:function(e,i){var s=i||t.ui.ddmanager.current,n=!1;return s&&(s.currentItem||s.element)[0]!==this.element[0]?(this.element.find(":data(ui-droppable)").not(".ui-draggable-dragging").each(function(){var i=t(this).droppable("instance");return i.options.greedy&&!i.options.disabled&&i.options.scope===s.options.scope&&i.accept.call(i.element[0],s.currentItem||s.element)&&v(s,t.extend(i,{offset:i.element.offset()}),i.options.tolerance,e)?(n=!0,!1):void 0}),n?!1:this.accept.call(this.element[0],s.currentItem||s.element)?(this._removeActiveClass(),this._removeHoverClass(),this._trigger("drop",e,this.ui(s)),this.element):!1):!1},ui:function(t){return{draggable:t.currentItem||t.element,helper:t.helper,position:t.position,offset:t.positionAbs}},_addHoverClass:function(){this._addClass("ui-droppable-hover")},_removeHoverClass:function(){this._removeClass("ui-droppable-hover")},_addActiveClass:function(){this._addClass("ui-droppable-active")},_removeActiveClass:function(){this._removeClass("ui-droppable-active")}});var v=t.ui.intersect=function(){function t(t,e,i){return t>=e&&e+i>t}return function(e,i,s,n){if(!i.offset)return!1;var o=(e.positionAbs||e.position.absolute).left+e.margins.left,a=(e.positionAbs||e.position.absolute).top+e.margins.top,r=o+e.helperProportions.width,h=a+e.helperProportions.height,l=i.offset.left,c=i.offset.top,u=l+i.proportions().width,d=c+i.proportions().height;switch(s){case"fit":return o>=l&&u>=r&&a>=c&&d>=h;case"intersect":return o+e.helperProportions.width/2>l&&u>r-e.helperProportions.width/2&&a+e.helperProportions.height/2>c&&d>h-e.helperProportions.height/2;case"pointer":return t(n.pageY,c,i.proportions().height)&&t(n.pageX,l,i.proportions().width);case"touch":return(a>=c&&d>=a||h>=c&&d>=h||c>a&&h>d)&&(o>=l&&u>=o||r>=l&&u>=r||l>o&&r>u);default:return!1}}}();t.ui.ddmanager={current:null,droppables:{"default":[]},prepareOffsets:function(e,i){var s,n,o=t.ui.ddmanager.droppables[e.options.scope]||[],a=i?i.type:null,r=(e.currentItem||e.element).find(":data(ui-droppable)").addBack();t:for(s=0;o.length>s;s++)if(!(o[s].options.disabled||e&&!o[s].accept.call(o[s].element[0],e.currentItem||e.element))){for(n=0;r.length>n;n++)if(r[n]===o[s].element[0]){o[s].proportions().height=0;continue t}o[s].visible="none"!==o[s].element.css("display"),o[s].visible&&("mousedown"===a&&o[s]._activate.call(o[s],i),o[s].offset=o[s].element.offset(),o[s].proportions({width:o[s].element[0].offsetWidth,height:o[s].element[0].offsetHeight}))}},drop:function(e,i){var s=!1;return t.each((t.ui.ddmanager.droppables[e.options.scope]||[]).slice(),function(){this.options&&(!this.options.disabled&&this.visible&&v(e,this,this.options.tolerance,i)&&(s=this._drop.call(this,i)||s),!this.options.disabled&&this.visible&&this.accept.call(this.element[0],e.currentItem||e.element)&&(this.isout=!0,this.isover=!1,this._deactivate.call(this,i)))}),s},dragStart:function(e,i){e.element.parentsUntil("body").on("scroll.droppable",function(){e.options.refreshPositions||t.ui.ddmanager.prepareOffsets(e,i)})},drag:function(e,i){e.options.refreshPositions&&t.ui.ddmanager.prepareOffsets(e,i),t.each(t.ui.ddmanager.droppables[e.options.scope]||[],function(){if(!this.options.disabled&&!this.greedyChild&&this.visible){var s,n,o,a=v(e,this,this.options.tolerance,i),r=!a&&this.isover?"isout":a&&!this.isover?"isover":null;r&&(this.options.greedy&&(n=this.options.scope,o=this.element.parents(":data(ui-droppable)").filter(function(){return t(this).droppable("instance").options.scope===n}),o.length&&(s=t(o[0]).droppable("instance"),s.greedyChild="isover"===r)),s&&"isover"===r&&(s.isover=!1,s.isout=!0,s._out.call(s,i)),this[r]=!0,this["isout"===r?"isover":"isout"]=!1,this["isover"===r?"_over":"_out"].call(this,i),s&&"isout"===r&&(s.isout=!1,s.isover=!0,s._over.call(s,i)))}})},dragStop:function(e,i){e.element.parentsUntil("body").off("scroll.droppable"),e.options.refreshPositions||t.ui.ddmanager.prepareOffsets(e,i)}},t.uiBackCompat!==!1&&t.widget("ui.droppable",t.ui.droppable,{options:{hoverClass:!1,activeClass:!1},_addActiveClass:function(){this._super(),this.options.activeClass&&this.element.addClass(this.options.activeClass)},_removeActiveClass:function(){this._super(),this.options.activeClass&&this.element.removeClass(this.options.activeClass)},_addHoverClass:function(){this._super(),this.options.hoverClass&&this.element.addClass(this.options.hoverClass)},_removeHoverClass:function(){this._super(),this.options.hoverClass&&this.element.removeClass(this.options.hoverClass)}}),t.ui.droppable,t.widget("ui.progressbar",{version:"1.12.1",options:{classes:{"ui-progressbar":"ui-corner-all","ui-progressbar-value":"ui-corner-left","ui-progressbar-complete":"ui-corner-right"},max:100,value:0,change:null,complete:null},min:0,_create:function(){this.oldValue=this.options.value=this._constrainedValue(),this.element.attr({role:"progressbar","aria-valuemin":this.min}),this._addClass("ui-progressbar","ui-widget ui-widget-content"),this.valueDiv=t("
").appendTo(this.element),this._addClass(this.valueDiv,"ui-progressbar-value","ui-widget-header"),this._refreshValue()},_destroy:function(){this.element.removeAttr("role aria-valuemin aria-valuemax aria-valuenow"),this.valueDiv.remove()},value:function(t){return void 0===t?this.options.value:(this.options.value=this._constrainedValue(t),this._refreshValue(),void 0)},_constrainedValue:function(t){return void 0===t&&(t=this.options.value),this.indeterminate=t===!1,"number"!=typeof t&&(t=0),this.indeterminate?!1:Math.min(this.options.max,Math.max(this.min,t))},_setOptions:function(t){var e=t.value;delete t.value,this._super(t),this.options.value=this._constrainedValue(e),this._refreshValue()},_setOption:function(t,e){"max"===t&&(e=Math.max(this.min,e)),this._super(t,e)},_setOptionDisabled:function(t){this._super(t),this.element.attr("aria-disabled",t),this._toggleClass(null,"ui-state-disabled",!!t)},_percentage:function(){return this.indeterminate?100:100*(this.options.value-this.min)/(this.options.max-this.min)},_refreshValue:function(){var e=this.options.value,i=this._percentage();this.valueDiv.toggle(this.indeterminate||e>this.min).width(i.toFixed(0)+"%"),this._toggleClass(this.valueDiv,"ui-progressbar-complete",null,e===this.options.max)._toggleClass("ui-progressbar-indeterminate",null,this.indeterminate),this.indeterminate?(this.element.removeAttr("aria-valuenow"),this.overlayDiv||(this.overlayDiv=t("
").appendTo(this.valueDiv),this._addClass(this.overlayDiv,"ui-progressbar-overlay"))):(this.element.attr({"aria-valuemax":this.options.max,"aria-valuenow":e}),this.overlayDiv&&(this.overlayDiv.remove(),this.overlayDiv=null)),this.oldValue!==e&&(this.oldValue=e,this._trigger("change")),e===this.options.max&&this._trigger("complete")}}),t.widget("ui.selectable",t.ui.mouse,{version:"1.12.1",options:{appendTo:"body",autoRefresh:!0,distance:0,filter:"*",tolerance:"touch",selected:null,selecting:null,start:null,stop:null,unselected:null,unselecting:null},_create:function(){var e=this;this._addClass("ui-selectable"),this.dragged=!1,this.refresh=function(){e.elementPos=t(e.element[0]).offset(),e.selectees=t(e.options.filter,e.element[0]),e._addClass(e.selectees,"ui-selectee"),e.selectees.each(function(){var i=t(this),s=i.offset(),n={left:s.left-e.elementPos.left,top:s.top-e.elementPos.top};t.data(this,"selectable-item",{element:this,$element:i,left:n.left,top:n.top,right:n.left+i.outerWidth(),bottom:n.top+i.outerHeight(),startselected:!1,selected:i.hasClass("ui-selected"),selecting:i.hasClass("ui-selecting"),unselecting:i.hasClass("ui-unselecting")})})},this.refresh(),this._mouseInit(),this.helper=t("
"),this._addClass(this.helper,"ui-selectable-helper")},_destroy:function(){this.selectees.removeData("selectable-item"),this._mouseDestroy()},_mouseStart:function(e){var i=this,s=this.options;this.opos=[e.pageX,e.pageY],this.elementPos=t(this.element[0]).offset(),this.options.disabled||(this.selectees=t(s.filter,this.element[0]),this._trigger("start",e),t(s.appendTo).append(this.helper),this.helper.css({left:e.pageX,top:e.pageY,width:0,height:0}),s.autoRefresh&&this.refresh(),this.selectees.filter(".ui-selected").each(function(){var s=t.data(this,"selectable-item");s.startselected=!0,e.metaKey||e.ctrlKey||(i._removeClass(s.$element,"ui-selected"),s.selected=!1,i._addClass(s.$element,"ui-unselecting"),s.unselecting=!0,i._trigger("unselecting",e,{unselecting:s.element}))}),t(e.target).parents().addBack().each(function(){var s,n=t.data(this,"selectable-item");return n?(s=!e.metaKey&&!e.ctrlKey||!n.$element.hasClass("ui-selected"),i._removeClass(n.$element,s?"ui-unselecting":"ui-selected")._addClass(n.$element,s?"ui-selecting":"ui-unselecting"),n.unselecting=!s,n.selecting=s,n.selected=s,s?i._trigger("selecting",e,{selecting:n.element}):i._trigger("unselecting",e,{unselecting:n.element}),!1):void 0}))},_mouseDrag:function(e){if(this.dragged=!0,!this.options.disabled){var i,s=this,n=this.options,o=this.opos[0],a=this.opos[1],r=e.pageX,h=e.pageY;return o>r&&(i=r,r=o,o=i),a>h&&(i=h,h=a,a=i),this.helper.css({left:o,top:a,width:r-o,height:h-a}),this.selectees.each(function(){var i=t.data(this,"selectable-item"),l=!1,c={};i&&i.element!==s.element[0]&&(c.left=i.left+s.elementPos.left,c.right=i.right+s.elementPos.left,c.top=i.top+s.elementPos.top,c.bottom=i.bottom+s.elementPos.top,"touch"===n.tolerance?l=!(c.left>r||o>c.right||c.top>h||a>c.bottom):"fit"===n.tolerance&&(l=c.left>o&&r>c.right&&c.top>a&&h>c.bottom),l?(i.selected&&(s._removeClass(i.$element,"ui-selected"),i.selected=!1),i.unselecting&&(s._removeClass(i.$element,"ui-unselecting"),i.unselecting=!1),i.selecting||(s._addClass(i.$element,"ui-selecting"),i.selecting=!0,s._trigger("selecting",e,{selecting:i.element}))):(i.selecting&&((e.metaKey||e.ctrlKey)&&i.startselected?(s._removeClass(i.$element,"ui-selecting"),i.selecting=!1,s._addClass(i.$element,"ui-selected"),i.selected=!0):(s._removeClass(i.$element,"ui-selecting"),i.selecting=!1,i.startselected&&(s._addClass(i.$element,"ui-unselecting"),i.unselecting=!0),s._trigger("unselecting",e,{unselecting:i.element}))),i.selected&&(e.metaKey||e.ctrlKey||i.startselected||(s._removeClass(i.$element,"ui-selected"),i.selected=!1,s._addClass(i.$element,"ui-unselecting"),i.unselecting=!0,s._trigger("unselecting",e,{unselecting:i.element})))))}),!1}},_mouseStop:function(e){var i=this;return this.dragged=!1,t(".ui-unselecting",this.element[0]).each(function(){var s=t.data(this,"selectable-item");i._removeClass(s.$element,"ui-unselecting"),s.unselecting=!1,s.startselected=!1,i._trigger("unselected",e,{unselected:s.element})}),t(".ui-selecting",this.element[0]).each(function(){var s=t.data(this,"selectable-item");i._removeClass(s.$element,"ui-selecting")._addClass(s.$element,"ui-selected"),s.selecting=!1,s.selected=!0,s.startselected=!0,i._trigger("selected",e,{selected:s.element})}),this._trigger("stop",e),this.helper.remove(),!1}}),t.widget("ui.selectmenu",[t.ui.formResetMixin,{version:"1.12.1",defaultElement:"",widgetEventPrefix:"spin",options:{classes:{"ui-spinner":"ui-corner-all","ui-spinner-down":"ui-corner-br","ui-spinner-up":"ui-corner-tr"},culture:null,icons:{down:"ui-icon-triangle-1-s",up:"ui-icon-triangle-1-n"},incremental:!0,max:null,min:null,numberFormat:null,page:10,step:1,change:null,spin:null,start:null,stop:null},_create:function(){this._setOption("max",this.options.max),this._setOption("min",this.options.min),this._setOption("step",this.options.step),""!==this.value()&&this._value(this.element.val(),!0),this._draw(),this._on(this._events),this._refresh(),this._on(this.window,{beforeunload:function(){this.element.removeAttr("autocomplete")}})},_getCreateOptions:function(){var e=this._super(),i=this.element;return t.each(["min","max","step"],function(t,s){var n=i.attr(s);null!=n&&n.length&&(e[s]=n)}),e},_events:{keydown:function(t){this._start(t)&&this._keydown(t)&&t.preventDefault()},keyup:"_stop",focus:function(){this.previous=this.element.val()},blur:function(t){return this.cancelBlur?(delete this.cancelBlur,void 0):(this._stop(),this._refresh(),this.previous!==this.element.val()&&this._trigger("change",t),void 0)},mousewheel:function(t,e){if(e){if(!this.spinning&&!this._start(t))return!1;this._spin((e>0?1:-1)*this.options.step,t),clearTimeout(this.mousewheelTimer),this.mousewheelTimer=this._delay(function(){this.spinning&&this._stop(t)},100),t.preventDefault()}},"mousedown .ui-spinner-button":function(e){function i(){var e=this.element[0]===t.ui.safeActiveElement(this.document[0]);e||(this.element.trigger("focus"),this.previous=s,this._delay(function(){this.previous=s}))}var s;s=this.element[0]===t.ui.safeActiveElement(this.document[0])?this.previous:this.element.val(),e.preventDefault(),i.call(this),this.cancelBlur=!0,this._delay(function(){delete this.cancelBlur,i.call(this)}),this._start(e)!==!1&&this._repeat(null,t(e.currentTarget).hasClass("ui-spinner-up")?1:-1,e)},"mouseup .ui-spinner-button":"_stop","mouseenter .ui-spinner-button":function(e){return t(e.currentTarget).hasClass("ui-state-active")?this._start(e)===!1?!1:(this._repeat(null,t(e.currentTarget).hasClass("ui-spinner-up")?1:-1,e),void 0):void 0},"mouseleave .ui-spinner-button":"_stop"},_enhance:function(){this.uiSpinner=this.element.attr("autocomplete","off").wrap("").parent().append("")},_draw:function(){this._enhance(),this._addClass(this.uiSpinner,"ui-spinner","ui-widget ui-widget-content"),this._addClass("ui-spinner-input"),this.element.attr("role","spinbutton"),this.buttons=this.uiSpinner.children("a").attr("tabIndex",-1).attr("aria-hidden",!0).button({classes:{"ui-button":""}}),this._removeClass(this.buttons,"ui-corner-all"),this._addClass(this.buttons.first(),"ui-spinner-button ui-spinner-up"),this._addClass(this.buttons.last(),"ui-spinner-button ui-spinner-down"),this.buttons.first().button({icon:this.options.icons.up,showLabel:!1}),this.buttons.last().button({icon:this.options.icons.down,showLabel:!1}),this.buttons.height()>Math.ceil(.5*this.uiSpinner.height())&&this.uiSpinner.height()>0&&this.uiSpinner.height(this.uiSpinner.height())},_keydown:function(e){var i=this.options,s=t.ui.keyCode;switch(e.keyCode){case s.UP:return this._repeat(null,1,e),!0;case s.DOWN:return this._repeat(null,-1,e),!0;case s.PAGE_UP:return this._repeat(null,i.page,e),!0;case s.PAGE_DOWN:return this._repeat(null,-i.page,e),!0}return!1},_start:function(t){return this.spinning||this._trigger("start",t)!==!1?(this.counter||(this.counter=1),this.spinning=!0,!0):!1},_repeat:function(t,e,i){t=t||500,clearTimeout(this.timer),this.timer=this._delay(function(){this._repeat(40,e,i)},t),this._spin(e*this.options.step,i)},_spin:function(t,e){var i=this.value()||0;this.counter||(this.counter=1),i=this._adjustValue(i+t*this._increment(this.counter)),this.spinning&&this._trigger("spin",e,{value:i})===!1||(this._value(i),this.counter++)},_increment:function(e){var i=this.options.incremental;return i?t.isFunction(i)?i(e):Math.floor(e*e*e/5e4-e*e/500+17*e/200+1):1},_precision:function(){var t=this._precisionOf(this.options.step);return null!==this.options.min&&(t=Math.max(t,this._precisionOf(this.options.min))),t},_precisionOf:function(t){var e=""+t,i=e.indexOf(".");return-1===i?0:e.length-i-1},_adjustValue:function(t){var e,i,s=this.options;return e=null!==s.min?s.min:0,i=t-e,i=Math.round(i/s.step)*s.step,t=e+i,t=parseFloat(t.toFixed(this._precision())),null!==s.max&&t>s.max?s.max:null!==s.min&&s.min>t?s.min:t},_stop:function(t){this.spinning&&(clearTimeout(this.timer),clearTimeout(this.mousewheelTimer),this.counter=0,this.spinning=!1,this._trigger("stop",t))},_setOption:function(t,e){var i,s,n;return"culture"===t||"numberFormat"===t?(i=this._parse(this.element.val()),this.options[t]=e,this.element.val(this._format(i)),void 0):(("max"===t||"min"===t||"step"===t)&&"string"==typeof e&&(e=this._parse(e)),"icons"===t&&(s=this.buttons.first().find(".ui-icon"),this._removeClass(s,null,this.options.icons.up),this._addClass(s,null,e.up),n=this.buttons.last().find(".ui-icon"),this._removeClass(n,null,this.options.icons.down),this._addClass(n,null,e.down)),this._super(t,e),void 0)},_setOptionDisabled:function(t){this._super(t),this._toggleClass(this.uiSpinner,null,"ui-state-disabled",!!t),this.element.prop("disabled",!!t),this.buttons.button(t?"disable":"enable")},_setOptions:r(function(t){this._super(t)}),_parse:function(t){return"string"==typeof t&&""!==t&&(t=window.Globalize&&this.options.numberFormat?Globalize.parseFloat(t,10,this.options.culture):+t),""===t||isNaN(t)?null:t},_format:function(t){return""===t?"":window.Globalize&&this.options.numberFormat?Globalize.format(t,this.options.numberFormat,this.options.culture):t},_refresh:function(){this.element.attr({"aria-valuemin":this.options.min,"aria-valuemax":this.options.max,"aria-valuenow":this._parse(this.element.val())})},isValid:function(){var t=this.value();return null===t?!1:t===this._adjustValue(t)},_value:function(t,e){var i;""!==t&&(i=this._parse(t),null!==i&&(e||(i=this._adjustValue(i)),t=this._format(i))),this.element.val(t),this._refresh()},_destroy:function(){this.element.prop("disabled",!1).removeAttr("autocomplete role aria-valuemin aria-valuemax aria-valuenow"),this.uiSpinner.replaceWith(this.element)},stepUp:r(function(t){this._stepUp(t)}),_stepUp:function(t){this._start()&&(this._spin((t||1)*this.options.step),this._stop())},stepDown:r(function(t){this._stepDown(t)}),_stepDown:function(t){this._start()&&(this._spin((t||1)*-this.options.step),this._stop())},pageUp:r(function(t){this._stepUp((t||1)*this.options.page)}),pageDown:r(function(t){this._stepDown((t||1)*this.options.page)}),value:function(t){return arguments.length?(r(this._value).call(this,t),void 0):this._parse(this.element.val())},widget:function(){return this.uiSpinner}}),t.uiBackCompat!==!1&&t.widget("ui.spinner",t.ui.spinner,{_enhance:function(){this.uiSpinner=this.element.attr("autocomplete","off").wrap(this._uiSpinnerHtml()).parent().append(this._buttonHtml())},_uiSpinnerHtml:function(){return""},_buttonHtml:function(){return""}}),t.ui.spinner,t.widget("ui.tabs",{version:"1.12.1",delay:300,options:{active:null,classes:{"ui-tabs":"ui-corner-all","ui-tabs-nav":"ui-corner-all","ui-tabs-panel":"ui-corner-bottom","ui-tabs-tab":"ui-corner-top"},collapsible:!1,event:"click",heightStyle:"content",hide:null,show:null,activate:null,beforeActivate:null,beforeLoad:null,load:null},_isLocal:function(){var t=/#.*$/;return function(e){var i,s;i=e.href.replace(t,""),s=location.href.replace(t,"");try{i=decodeURIComponent(i)}catch(n){}try{s=decodeURIComponent(s)}catch(n){}return e.hash.length>1&&i===s}}(),_create:function(){var e=this,i=this.options;this.running=!1,this._addClass("ui-tabs","ui-widget ui-widget-content"),this._toggleClass("ui-tabs-collapsible",null,i.collapsible),this._processTabs(),i.active=this._initialActive(),t.isArray(i.disabled)&&(i.disabled=t.unique(i.disabled.concat(t.map(this.tabs.filter(".ui-state-disabled"),function(t){return e.tabs.index(t)}))).sort()),this.active=this.options.active!==!1&&this.anchors.length?this._findActive(i.active):t(),this._refresh(),this.active.length&&this.load(i.active)},_initialActive:function(){var e=this.options.active,i=this.options.collapsible,s=location.hash.substring(1);return null===e&&(s&&this.tabs.each(function(i,n){return t(n).attr("aria-controls")===s?(e=i,!1):void 0}),null===e&&(e=this.tabs.index(this.tabs.filter(".ui-tabs-active"))),(null===e||-1===e)&&(e=this.tabs.length?0:!1)),e!==!1&&(e=this.tabs.index(this.tabs.eq(e)),-1===e&&(e=i?!1:0)),!i&&e===!1&&this.anchors.length&&(e=0),e},_getCreateEventData:function(){return{tab:this.active,panel:this.active.length?this._getPanelForTab(this.active):t()}},_tabKeydown:function(e){var i=t(t.ui.safeActiveElement(this.document[0])).closest("li"),s=this.tabs.index(i),n=!0;if(!this._handlePageNav(e)){switch(e.keyCode){case t.ui.keyCode.RIGHT:case t.ui.keyCode.DOWN:s++;break;case t.ui.keyCode.UP:case t.ui.keyCode.LEFT:n=!1,s--;break;case t.ui.keyCode.END:s=this.anchors.length-1;break;case t.ui.keyCode.HOME:s=0;break;case t.ui.keyCode.SPACE:return e.preventDefault(),clearTimeout(this.activating),this._activate(s),void 0;case t.ui.keyCode.ENTER:return e.preventDefault(),clearTimeout(this.activating),this._activate(s===this.options.active?!1:s),void 0;default:return}e.preventDefault(),clearTimeout(this.activating),s=this._focusNextTab(s,n),e.ctrlKey||e.metaKey||(i.attr("aria-selected","false"),this.tabs.eq(s).attr("aria-selected","true"),this.activating=this._delay(function(){this.option("active",s)},this.delay))}},_panelKeydown:function(e){this._handlePageNav(e)||e.ctrlKey&&e.keyCode===t.ui.keyCode.UP&&(e.preventDefault(),this.active.trigger("focus"))},_handlePageNav:function(e){return e.altKey&&e.keyCode===t.ui.keyCode.PAGE_UP?(this._activate(this._focusNextTab(this.options.active-1,!1)),!0):e.altKey&&e.keyCode===t.ui.keyCode.PAGE_DOWN?(this._activate(this._focusNextTab(this.options.active+1,!0)),!0):void 0},_findNextTab:function(e,i){function s(){return e>n&&(e=0),0>e&&(e=n),e}for(var n=this.tabs.length-1;-1!==t.inArray(s(),this.options.disabled);)e=i?e+1:e-1;return e},_focusNextTab:function(t,e){return t=this._findNextTab(t,e),this.tabs.eq(t).trigger("focus"),t},_setOption:function(t,e){return"active"===t?(this._activate(e),void 0):(this._super(t,e),"collapsible"===t&&(this._toggleClass("ui-tabs-collapsible",null,e),e||this.options.active!==!1||this._activate(0)),"event"===t&&this._setupEvents(e),"heightStyle"===t&&this._setupHeightStyle(e),void 0)},_sanitizeSelector:function(t){return t?t.replace(/[!"$%&'()*+,.\/:;<=>?@\[\]\^`{|}~]/g,"\\$&"):""},refresh:function(){var e=this.options,i=this.tablist.children(":has(a[href])");e.disabled=t.map(i.filter(".ui-state-disabled"),function(t){return i.index(t)}),this._processTabs(),e.active!==!1&&this.anchors.length?this.active.length&&!t.contains(this.tablist[0],this.active[0])?this.tabs.length===e.disabled.length?(e.active=!1,this.active=t()):this._activate(this._findNextTab(Math.max(0,e.active-1),!1)):e.active=this.tabs.index(this.active):(e.active=!1,this.active=t()),this._refresh()},_refresh:function(){this._setOptionDisabled(this.options.disabled),this._setupEvents(this.options.event),this._setupHeightStyle(this.options.heightStyle),this.tabs.not(this.active).attr({"aria-selected":"false","aria-expanded":"false",tabIndex:-1}),this.panels.not(this._getPanelForTab(this.active)).hide().attr({"aria-hidden":"true"}),this.active.length?(this.active.attr({"aria-selected":"true","aria-expanded":"true",tabIndex:0}),this._addClass(this.active,"ui-tabs-active","ui-state-active"),this._getPanelForTab(this.active).show().attr({"aria-hidden":"false"})):this.tabs.eq(0).attr("tabIndex",0)},_processTabs:function(){var e=this,i=this.tabs,s=this.anchors,n=this.panels;this.tablist=this._getList().attr("role","tablist"),this._addClass(this.tablist,"ui-tabs-nav","ui-helper-reset ui-helper-clearfix ui-widget-header"),this.tablist.on("mousedown"+this.eventNamespace,"> li",function(e){t(this).is(".ui-state-disabled")&&e.preventDefault()}).on("focus"+this.eventNamespace,".ui-tabs-anchor",function(){t(this).closest("li").is(".ui-state-disabled")&&this.blur()}),this.tabs=this.tablist.find("> li:has(a[href])").attr({role:"tab",tabIndex:-1}),this._addClass(this.tabs,"ui-tabs-tab","ui-state-default"),this.anchors=this.tabs.map(function(){return t("a",this)[0]}).attr({role:"presentation",tabIndex:-1}),this._addClass(this.anchors,"ui-tabs-anchor"),this.panels=t(),this.anchors.each(function(i,s){var n,o,a,r=t(s).uniqueId().attr("id"),h=t(s).closest("li"),l=h.attr("aria-controls");e._isLocal(s)?(n=s.hash,a=n.substring(1),o=e.element.find(e._sanitizeSelector(n))):(a=h.attr("aria-controls")||t({}).uniqueId()[0].id,n="#"+a,o=e.element.find(n),o.length||(o=e._createPanel(a),o.insertAfter(e.panels[i-1]||e.tablist)),o.attr("aria-live","polite")),o.length&&(e.panels=e.panels.add(o)),l&&h.data("ui-tabs-aria-controls",l),h.attr({"aria-controls":a,"aria-labelledby":r}),o.attr("aria-labelledby",r)}),this.panels.attr("role","tabpanel"),this._addClass(this.panels,"ui-tabs-panel","ui-widget-content"),i&&(this._off(i.not(this.tabs)),this._off(s.not(this.anchors)),this._off(n.not(this.panels)))},_getList:function(){return this.tablist||this.element.find("ol, ul").eq(0)},_createPanel:function(e){return t("
").attr("id",e).data("ui-tabs-destroy",!0)},_setOptionDisabled:function(e){var i,s,n;for(t.isArray(e)&&(e.length?e.length===this.anchors.length&&(e=!0):e=!1),n=0;s=this.tabs[n];n++)i=t(s),e===!0||-1!==t.inArray(n,e)?(i.attr("aria-disabled","true"),this._addClass(i,null,"ui-state-disabled")):(i.removeAttr("aria-disabled"),this._removeClass(i,null,"ui-state-disabled"));this.options.disabled=e,this._toggleClass(this.widget(),this.widgetFullName+"-disabled",null,e===!0)},_setupEvents:function(e){var i={};e&&t.each(e.split(" "),function(t,e){i[e]="_eventHandler"}),this._off(this.anchors.add(this.tabs).add(this.panels)),this._on(!0,this.anchors,{click:function(t){t.preventDefault()}}),this._on(this.anchors,i),this._on(this.tabs,{keydown:"_tabKeydown"}),this._on(this.panels,{keydown:"_panelKeydown"}),this._focusable(this.tabs),this._hoverable(this.tabs)},_setupHeightStyle:function(e){var i,s=this.element.parent();"fill"===e?(i=s.height(),i-=this.element.outerHeight()-this.element.height(),this.element.siblings(":visible").each(function(){var e=t(this),s=e.css("position");"absolute"!==s&&"fixed"!==s&&(i-=e.outerHeight(!0))}),this.element.children().not(this.panels).each(function(){i-=t(this).outerHeight(!0)}),this.panels.each(function(){t(this).height(Math.max(0,i-t(this).innerHeight()+t(this).height()))}).css("overflow","auto")):"auto"===e&&(i=0,this.panels.each(function(){i=Math.max(i,t(this).height("").height())}).height(i))},_eventHandler:function(e){var i=this.options,s=this.active,n=t(e.currentTarget),o=n.closest("li"),a=o[0]===s[0],r=a&&i.collapsible,h=r?t():this._getPanelForTab(o),l=s.length?this._getPanelForTab(s):t(),c={oldTab:s,oldPanel:l,newTab:r?t():o,newPanel:h};e.preventDefault(),o.hasClass("ui-state-disabled")||o.hasClass("ui-tabs-loading")||this.running||a&&!i.collapsible||this._trigger("beforeActivate",e,c)===!1||(i.active=r?!1:this.tabs.index(o),this.active=a?t():o,this.xhr&&this.xhr.abort(),l.length||h.length||t.error("jQuery UI Tabs: Mismatching fragment identifier."),h.length&&this.load(this.tabs.index(o),e),this._toggle(e,c))},_toggle:function(e,i){function s(){o.running=!1,o._trigger("activate",e,i)}function n(){o._addClass(i.newTab.closest("li"),"ui-tabs-active","ui-state-active"),a.length&&o.options.show?o._show(a,o.options.show,s):(a.show(),s())}var o=this,a=i.newPanel,r=i.oldPanel;this.running=!0,r.length&&this.options.hide?this._hide(r,this.options.hide,function(){o._removeClass(i.oldTab.closest("li"),"ui-tabs-active","ui-state-active"),n()}):(this._removeClass(i.oldTab.closest("li"),"ui-tabs-active","ui-state-active"),r.hide(),n()),r.attr("aria-hidden","true"),i.oldTab.attr({"aria-selected":"false","aria-expanded":"false"}),a.length&&r.length?i.oldTab.attr("tabIndex",-1):a.length&&this.tabs.filter(function(){return 0===t(this).attr("tabIndex")}).attr("tabIndex",-1),a.attr("aria-hidden","false"),i.newTab.attr({"aria-selected":"true","aria-expanded":"true",tabIndex:0})},_activate:function(e){var i,s=this._findActive(e);s[0]!==this.active[0]&&(s.length||(s=this.active),i=s.find(".ui-tabs-anchor")[0],this._eventHandler({target:i,currentTarget:i,preventDefault:t.noop}))},_findActive:function(e){return e===!1?t():this.tabs.eq(e)},_getIndex:function(e){return"string"==typeof e&&(e=this.anchors.index(this.anchors.filter("[href$='"+t.ui.escapeSelector(e)+"']"))),e},_destroy:function(){this.xhr&&this.xhr.abort(),this.tablist.removeAttr("role").off(this.eventNamespace),this.anchors.removeAttr("role tabIndex").removeUniqueId(),this.tabs.add(this.panels).each(function(){t.data(this,"ui-tabs-destroy")?t(this).remove():t(this).removeAttr("role tabIndex aria-live aria-busy aria-selected aria-labelledby aria-hidden aria-expanded")}),this.tabs.each(function(){var e=t(this),i=e.data("ui-tabs-aria-controls");i?e.attr("aria-controls",i).removeData("ui-tabs-aria-controls"):e.removeAttr("aria-controls")}),this.panels.show(),"content"!==this.options.heightStyle&&this.panels.css("height","")},enable:function(e){var i=this.options.disabled;i!==!1&&(void 0===e?i=!1:(e=this._getIndex(e),i=t.isArray(i)?t.map(i,function(t){return t!==e?t:null}):t.map(this.tabs,function(t,i){return i!==e?i:null})),this._setOptionDisabled(i))},disable:function(e){var i=this.options.disabled;if(i!==!0){if(void 0===e)i=!0;else{if(e=this._getIndex(e),-1!==t.inArray(e,i))return;i=t.isArray(i)?t.merge([e],i).sort():[e]}this._setOptionDisabled(i)}},load:function(e,i){e=this._getIndex(e);var s=this,n=this.tabs.eq(e),o=n.find(".ui-tabs-anchor"),a=this._getPanelForTab(n),r={tab:n,panel:a},h=function(t,e){"abort"===e&&s.panels.stop(!1,!0),s._removeClass(n,"ui-tabs-loading"),a.removeAttr("aria-busy"),t===s.xhr&&delete s.xhr};this._isLocal(o[0])||(this.xhr=t.ajax(this._ajaxSettings(o,i,r)),this.xhr&&"canceled"!==this.xhr.statusText&&(this._addClass(n,"ui-tabs-loading"),a.attr("aria-busy","true"),this.xhr.done(function(t,e,n){setTimeout(function(){a.html(t),s._trigger("load",i,r),h(n,e)},1)}).fail(function(t,e){setTimeout(function(){h(t,e)},1)})))},_ajaxSettings:function(e,i,s){var n=this;return{url:e.attr("href").replace(/#.*$/,""),beforeSend:function(e,o){return n._trigger("beforeLoad",i,t.extend({jqXHR:e,ajaxSettings:o},s))}}},_getPanelForTab:function(e){var i=t(e).attr("aria-controls");return this.element.find(this._sanitizeSelector("#"+i))}}),t.uiBackCompat!==!1&&t.widget("ui.tabs",t.ui.tabs,{_processTabs:function(){this._superApply(arguments),this._addClass(this.tabs,"ui-tab")}}),t.ui.tabs,t.widget("ui.tooltip",{version:"1.12.1",options:{classes:{"ui-tooltip":"ui-corner-all ui-widget-shadow"},content:function(){var e=t(this).attr("title")||"";return t("").text(e).html()},hide:!0,items:"[title]:not([disabled])",position:{my:"left top+15",at:"left bottom",collision:"flipfit flip"},show:!0,track:!1,close:null,open:null},_addDescribedBy:function(e,i){var s=(e.attr("aria-describedby")||"").split(/\s+/);s.push(i),e.data("ui-tooltip-id",i).attr("aria-describedby",t.trim(s.join(" ")))},_removeDescribedBy:function(e){var i=e.data("ui-tooltip-id"),s=(e.attr("aria-describedby")||"").split(/\s+/),n=t.inArray(i,s);-1!==n&&s.splice(n,1),e.removeData("ui-tooltip-id"),s=t.trim(s.join(" ")),s?e.attr("aria-describedby",s):e.removeAttr("aria-describedby")},_create:function(){this._on({mouseover:"open",focusin:"open"}),this.tooltips={},this.parents={},this.liveRegion=t("
").attr({role:"log","aria-live":"assertive","aria-relevant":"additions"}).appendTo(this.document[0].body),this._addClass(this.liveRegion,null,"ui-helper-hidden-accessible"),this.disabledTitles=t([])},_setOption:function(e,i){var s=this;this._super(e,i),"content"===e&&t.each(this.tooltips,function(t,e){s._updateContent(e.element)})},_setOptionDisabled:function(t){this[t?"_disable":"_enable"]()},_disable:function(){var e=this;t.each(this.tooltips,function(i,s){var n=t.Event("blur");n.target=n.currentTarget=s.element[0],e.close(n,!0)}),this.disabledTitles=this.disabledTitles.add(this.element.find(this.options.items).addBack().filter(function(){var e=t(this);return e.is("[title]")?e.data("ui-tooltip-title",e.attr("title")).removeAttr("title"):void 0}))},_enable:function(){this.disabledTitles.each(function(){var e=t(this);e.data("ui-tooltip-title")&&e.attr("title",e.data("ui-tooltip-title"))}),this.disabledTitles=t([])},open:function(e){var i=this,s=t(e?e.target:this.element).closest(this.options.items);s.length&&!s.data("ui-tooltip-id")&&(s.attr("title")&&s.data("ui-tooltip-title",s.attr("title")),s.data("ui-tooltip-open",!0),e&&"mouseover"===e.type&&s.parents().each(function(){var e,s=t(this);s.data("ui-tooltip-open")&&(e=t.Event("blur"),e.target=e.currentTarget=this,i.close(e,!0)),s.attr("title")&&(s.uniqueId(),i.parents[this.id]={element:this,title:s.attr("title")},s.attr("title",""))}),this._registerCloseHandlers(e,s),this._updateContent(s,e))},_updateContent:function(t,e){var i,s=this.options.content,n=this,o=e?e.type:null;return"string"==typeof s||s.nodeType||s.jquery?this._open(e,t,s):(i=s.call(t[0],function(i){n._delay(function(){t.data("ui-tooltip-open")&&(e&&(e.type=o),this._open(e,t,i))})}),i&&this._open(e,t,i),void 0)},_open:function(e,i,s){function n(t){l.of=t,a.is(":hidden")||a.position(l)}var o,a,r,h,l=t.extend({},this.options.position);if(s){if(o=this._find(i))return o.tooltip.find(".ui-tooltip-content").html(s),void 0;i.is("[title]")&&(e&&"mouseover"===e.type?i.attr("title",""):i.removeAttr("title")),o=this._tooltip(i),a=o.tooltip,this._addDescribedBy(i,a.attr("id")),a.find(".ui-tooltip-content").html(s),this.liveRegion.children().hide(),h=t("
").html(a.find(".ui-tooltip-content").html()),h.removeAttr("name").find("[name]").removeAttr("name"),h.removeAttr("id").find("[id]").removeAttr("id"),h.appendTo(this.liveRegion),this.options.track&&e&&/^mouse/.test(e.type)?(this._on(this.document,{mousemove:n}),n(e)):a.position(t.extend({of:i},this.options.position)),a.hide(),this._show(a,this.options.show),this.options.track&&this.options.show&&this.options.show.delay&&(r=this.delayedShow=setInterval(function(){a.is(":visible")&&(n(l.of),clearInterval(r))},t.fx.interval)),this._trigger("open",e,{tooltip:a})}},_registerCloseHandlers:function(e,i){var s={keyup:function(e){if(e.keyCode===t.ui.keyCode.ESCAPE){var s=t.Event(e);s.currentTarget=i[0],this.close(s,!0)}}};i[0]!==this.element[0]&&(s.remove=function(){this._removeTooltip(this._find(i).tooltip)}),e&&"mouseover"!==e.type||(s.mouseleave="close"),e&&"focusin"!==e.type||(s.focusout="close"),this._on(!0,i,s)},close:function(e){var i,s=this,n=t(e?e.currentTarget:this.element),o=this._find(n);return o?(i=o.tooltip,o.closing||(clearInterval(this.delayedShow),n.data("ui-tooltip-title")&&!n.attr("title")&&n.attr("title",n.data("ui-tooltip-title")),this._removeDescribedBy(n),o.hiding=!0,i.stop(!0),this._hide(i,this.options.hide,function(){s._removeTooltip(t(this))}),n.removeData("ui-tooltip-open"),this._off(n,"mouseleave focusout keyup"),n[0]!==this.element[0]&&this._off(n,"remove"),this._off(this.document,"mousemove"),e&&"mouseleave"===e.type&&t.each(this.parents,function(e,i){t(i.element).attr("title",i.title),delete s.parents[e]}),o.closing=!0,this._trigger("close",e,{tooltip:i}),o.hiding||(o.closing=!1)),void 0):(n.removeData("ui-tooltip-open"),void 0)},_tooltip:function(e){var i=t("
").attr("role","tooltip"),s=t("
").appendTo(i),n=i.uniqueId().attr("id");return this._addClass(s,"ui-tooltip-content"),this._addClass(i,"ui-tooltip","ui-widget ui-widget-content"),i.appendTo(this._appendTo(e)),this.tooltips[n]={element:e,tooltip:i}},_find:function(t){var e=t.data("ui-tooltip-id");return e?this.tooltips[e]:null},_removeTooltip:function(t){t.remove(),delete this.tooltips[t.attr("id")]},_appendTo:function(t){var e=t.closest(".ui-front, dialog");return e.length||(e=this.document[0].body),e},_destroy:function(){var e=this;t.each(this.tooltips,function(i,s){var n=t.Event("blur"),o=s.element;n.target=n.currentTarget=o[0],e.close(n,!0),t("#"+i).remove(),o.data("ui-tooltip-title")&&(o.attr("title")||o.attr("title",o.data("ui-tooltip-title")),o.removeData("ui-tooltip-title"))}),this.liveRegion.remove()}}),t.uiBackCompat!==!1&&t.widget("ui.tooltip",t.ui.tooltip,{options:{tooltipClass:null},_tooltip:function(){var t=this._superApply(arguments);return this.options.tooltipClass&&t.tooltip.addClass(this.options.tooltipClass),t}}),t.ui.tooltip}); +this._delay(function(){n===this.counter&&this.refreshPositions(!s)})},_clear:function(t,e){function i(t,e,i){return function(s){i._trigger(t,s,e._uiHash(e))}}this.reverting=!1;var s,n=[];if(!this._noFinalSort&&this.currentItem.parent().length&&this.placeholder.before(this.currentItem),this._noFinalSort=null,this.helper[0]===this.currentItem[0]){for(s in this._storedCSS)("auto"===this._storedCSS[s]||"static"===this._storedCSS[s])&&(this._storedCSS[s]="");this.currentItem.css(this._storedCSS),this._removeClass(this.currentItem,"ui-sortable-helper")}else this.currentItem.show();for(this.fromOutside&&!e&&n.push(function(t){this._trigger("receive",t,this._uiHash(this.fromOutside))}),!this.fromOutside&&this.domPosition.prev===this.currentItem.prev().not(".ui-sortable-helper")[0]&&this.domPosition.parent===this.currentItem.parent()[0]||e||n.push(function(t){this._trigger("update",t,this._uiHash())}),this!==this.currentContainer&&(e||(n.push(function(t){this._trigger("remove",t,this._uiHash())}),n.push(function(t){return function(e){t._trigger("receive",e,this._uiHash(this))}}.call(this,this.currentContainer)),n.push(function(t){return function(e){t._trigger("update",e,this._uiHash(this))}}.call(this,this.currentContainer)))),s=this.containers.length-1;s>=0;s--)e||n.push(i("deactivate",this,this.containers[s])),this.containers[s].containerCache.over&&(n.push(i("out",this,this.containers[s])),this.containers[s].containerCache.over=0);if(this.storedCursor&&(this.document.find("body").css("cursor",this.storedCursor),this.storedStylesheet.remove()),this._storedOpacity&&this.helper.css("opacity",this._storedOpacity),this._storedZIndex&&this.helper.css("zIndex","auto"===this._storedZIndex?"":this._storedZIndex),this.dragging=!1,e||this._trigger("beforeStop",t,this._uiHash()),this.placeholder[0].parentNode.removeChild(this.placeholder[0]),this.cancelHelperRemoval||(this.helper[0]!==this.currentItem[0]&&this.helper.remove(),this.helper=null),!e){for(s=0;n.length>s;s++)n[s].call(this,t);this._trigger("stop",t,this._uiHash())}return this.fromOutside=!1,!this.cancelHelperRemoval},_trigger:function(){t.Widget.prototype._trigger.apply(this,arguments)===!1&&this.cancel()},_uiHash:function(e){var i=e||this;return{helper:i.helper,placeholder:i.placeholder||t([]),position:i.position,originalPosition:i.originalPosition,offset:i.positionAbs,item:i.currentItem,sender:e?e.element:null}}}),t.widget("ui.spinner",{version:"1.12.1",defaultElement:"",widgetEventPrefix:"spin",options:{classes:{"ui-spinner":"ui-corner-all","ui-spinner-down":"ui-corner-br","ui-spinner-up":"ui-corner-tr"},culture:null,icons:{down:"ui-icon-triangle-1-s",up:"ui-icon-triangle-1-n"},incremental:!0,max:null,min:null,numberFormat:null,page:10,step:1,change:null,spin:null,start:null,stop:null},_create:function(){this._setOption("max",this.options.max),this._setOption("min",this.options.min),this._setOption("step",this.options.step),""!==this.value()&&this._value(this.element.val(),!0),this._draw(),this._on(this._events),this._refresh(),this._on(this.window,{beforeunload:function(){this.element.removeAttr("autocomplete")}})},_getCreateOptions:function(){var e=this._super(),i=this.element;return t.each(["min","max","step"],function(t,s){var n=i.attr(s);null!=n&&n.length&&(e[s]=n)}),e},_events:{keydown:function(t){this._start(t)&&this._keydown(t)&&t.preventDefault()},keyup:"_stop",focus:function(){this.previous=this.element.val()},blur:function(t){return this.cancelBlur?(delete this.cancelBlur,void 0):(this._stop(),this._refresh(),this.previous!==this.element.val()&&this._trigger("change",t),void 0)},mousewheel:function(t,e){if(e){if(!this.spinning&&!this._start(t))return!1;this._spin((e>0?1:-1)*this.options.step,t),clearTimeout(this.mousewheelTimer),this.mousewheelTimer=this._delay(function(){this.spinning&&this._stop(t)},100),t.preventDefault()}},"mousedown .ui-spinner-button":function(e){function i(){var e=this.element[0]===t.ui.safeActiveElement(this.document[0]);e||(this.element.trigger("focus"),this.previous=s,this._delay(function(){this.previous=s}))}var s;s=this.element[0]===t.ui.safeActiveElement(this.document[0])?this.previous:this.element.val(),e.preventDefault(),i.call(this),this.cancelBlur=!0,this._delay(function(){delete this.cancelBlur,i.call(this)}),this._start(e)!==!1&&this._repeat(null,t(e.currentTarget).hasClass("ui-spinner-up")?1:-1,e)},"mouseup .ui-spinner-button":"_stop","mouseenter .ui-spinner-button":function(e){return t(e.currentTarget).hasClass("ui-state-active")?this._start(e)===!1?!1:(this._repeat(null,t(e.currentTarget).hasClass("ui-spinner-up")?1:-1,e),void 0):void 0},"mouseleave .ui-spinner-button":"_stop"},_enhance:function(){this.uiSpinner=this.element.attr("autocomplete","off").wrap("").parent().append("")},_draw:function(){this._enhance(),this._addClass(this.uiSpinner,"ui-spinner","ui-widget ui-widget-content"),this._addClass("ui-spinner-input"),this.element.attr("role","spinbutton"),this.buttons=this.uiSpinner.children("a").attr("tabIndex",-1).attr("aria-hidden",!0).button({classes:{"ui-button":""}}),this._removeClass(this.buttons,"ui-corner-all"),this._addClass(this.buttons.first(),"ui-spinner-button ui-spinner-up"),this._addClass(this.buttons.last(),"ui-spinner-button ui-spinner-down"),this.buttons.first().button({icon:this.options.icons.up,showLabel:!1}),this.buttons.last().button({icon:this.options.icons.down,showLabel:!1}),this.buttons.height()>Math.ceil(.5*this.uiSpinner.height())&&this.uiSpinner.height()>0&&this.uiSpinner.height(this.uiSpinner.height())},_keydown:function(e){var i=this.options,s=t.ui.keyCode;switch(e.keyCode){case s.UP:return this._repeat(null,1,e),!0;case s.DOWN:return this._repeat(null,-1,e),!0;case s.PAGE_UP:return this._repeat(null,i.page,e),!0;case s.PAGE_DOWN:return this._repeat(null,-i.page,e),!0}return!1},_start:function(t){return this.spinning||this._trigger("start",t)!==!1?(this.counter||(this.counter=1),this.spinning=!0,!0):!1},_repeat:function(t,e,i){t=t||500,clearTimeout(this.timer),this.timer=this._delay(function(){this._repeat(40,e,i)},t),this._spin(e*this.options.step,i)},_spin:function(t,e){var i=this.value()||0;this.counter||(this.counter=1),i=this._adjustValue(i+t*this._increment(this.counter)),this.spinning&&this._trigger("spin",e,{value:i})===!1||(this._value(i),this.counter++)},_increment:function(e){var i=this.options.incremental;return i?t.isFunction(i)?i(e):Math.floor(e*e*e/5e4-e*e/500+17*e/200+1):1},_precision:function(){var t=this._precisionOf(this.options.step);return null!==this.options.min&&(t=Math.max(t,this._precisionOf(this.options.min))),t},_precisionOf:function(t){var e=""+t,i=e.indexOf(".");return-1===i?0:e.length-i-1},_adjustValue:function(t){var e,i,s=this.options;return e=null!==s.min?s.min:0,i=t-e,i=Math.round(i/s.step)*s.step,t=e+i,t=parseFloat(t.toFixed(this._precision())),null!==s.max&&t>s.max?s.max:null!==s.min&&s.min>t?s.min:t},_stop:function(t){this.spinning&&(clearTimeout(this.timer),clearTimeout(this.mousewheelTimer),this.counter=0,this.spinning=!1,this._trigger("stop",t))},_setOption:function(t,e){var i,s,n;return"culture"===t||"numberFormat"===t?(i=this._parse(this.element.val()),this.options[t]=e,this.element.val(this._format(i)),void 0):(("max"===t||"min"===t||"step"===t)&&"string"==typeof e&&(e=this._parse(e)),"icons"===t&&(s=this.buttons.first().find(".ui-icon"),this._removeClass(s,null,this.options.icons.up),this._addClass(s,null,e.up),n=this.buttons.last().find(".ui-icon"),this._removeClass(n,null,this.options.icons.down),this._addClass(n,null,e.down)),this._super(t,e),void 0)},_setOptionDisabled:function(t){this._super(t),this._toggleClass(this.uiSpinner,null,"ui-state-disabled",!!t),this.element.prop("disabled",!!t),this.buttons.button(t?"disable":"enable")},_setOptions:r(function(t){this._super(t)}),_parse:function(t){return"string"==typeof t&&""!==t&&(t=window.Globalize&&this.options.numberFormat?Globalize.parseFloat(t,10,this.options.culture):+t),""===t||isNaN(t)?null:t},_format:function(t){return""===t?"":window.Globalize&&this.options.numberFormat?Globalize.format(t,this.options.numberFormat,this.options.culture):t},_refresh:function(){this.element.attr({"aria-valuemin":this.options.min,"aria-valuemax":this.options.max,"aria-valuenow":this._parse(this.element.val())})},isValid:function(){var t=this.value();return null===t?!1:t===this._adjustValue(t)},_value:function(t,e){var i;""!==t&&(i=this._parse(t),null!==i&&(e||(i=this._adjustValue(i)),t=this._format(i))),this.element.val(t),this._refresh()},_destroy:function(){this.element.prop("disabled",!1).removeAttr("autocomplete role aria-valuemin aria-valuemax aria-valuenow"),this.uiSpinner.replaceWith(this.element)},stepUp:r(function(t){this._stepUp(t)}),_stepUp:function(t){this._start()&&(this._spin((t||1)*this.options.step),this._stop())},stepDown:r(function(t){this._stepDown(t)}),_stepDown:function(t){this._start()&&(this._spin((t||1)*-this.options.step),this._stop())},pageUp:r(function(t){this._stepUp((t||1)*this.options.page)}),pageDown:r(function(t){this._stepDown((t||1)*this.options.page)}),value:function(t){return arguments.length?(r(this._value).call(this,t),void 0):this._parse(this.element.val())},widget:function(){return this.uiSpinner}}),t.uiBackCompat!==!1&&t.widget("ui.spinner",t.ui.spinner,{_enhance:function(){this.uiSpinner=this.element.attr("autocomplete","off").wrap(this._uiSpinnerHtml()).parent().append(this._buttonHtml())},_uiSpinnerHtml:function(){return""},_buttonHtml:function(){return""}}),t.ui.spinner,t.widget("ui.tabs",{version:"1.12.1",delay:300,options:{active:null,classes:{"ui-tabs":"ui-corner-all","ui-tabs-nav":"ui-corner-all","ui-tabs-panel":"ui-corner-bottom","ui-tabs-tab":"ui-corner-top"},collapsible:!1,event:"click",heightStyle:"content",hide:null,show:null,activate:null,beforeActivate:null,beforeLoad:null,load:null},_isLocal:function(){var t=/#.*$/;return function(e){var i,s;i=e.href.replace(t,""),s=location.href.replace(t,"");try{i=decodeURIComponent(i)}catch(n){}try{s=decodeURIComponent(s)}catch(n){}return e.hash.length>1&&i===s}}(),_create:function(){var e=this,i=this.options;this.running=!1,this._addClass("ui-tabs","ui-widget ui-widget-content"),this._toggleClass("ui-tabs-collapsible",null,i.collapsible),this._processTabs(),i.active=this._initialActive(),t.isArray(i.disabled)&&(i.disabled=t.unique(i.disabled.concat(t.map(this.tabs.filter(".ui-state-disabled"),function(t){return e.tabs.index(t)}))).sort()),this.active=this.options.active!==!1&&this.anchors.length?this._findActive(i.active):t(),this._refresh(),this.active.length&&this.load(i.active)},_initialActive:function(){var e=this.options.active,i=this.options.collapsible,s=location.hash.substring(1);return null===e&&(s&&this.tabs.each(function(i,n){return t(n).attr("aria-controls")===s?(e=i,!1):void 0}),null===e&&(e=this.tabs.index(this.tabs.filter(".ui-tabs-active"))),(null===e||-1===e)&&(e=this.tabs.length?0:!1)),e!==!1&&(e=this.tabs.index(this.tabs.eq(e)),-1===e&&(e=i?!1:0)),!i&&e===!1&&this.anchors.length&&(e=0),e},_getCreateEventData:function(){return{tab:this.active,panel:this.active.length?this._getPanelForTab(this.active):t()}},_tabKeydown:function(e){var i=t(t.ui.safeActiveElement(this.document[0])).closest("li"),s=this.tabs.index(i),n=!0;if(!this._handlePageNav(e)){switch(e.keyCode){case t.ui.keyCode.RIGHT:case t.ui.keyCode.DOWN:s++;break;case t.ui.keyCode.UP:case t.ui.keyCode.LEFT:n=!1,s--;break;case t.ui.keyCode.END:s=this.anchors.length-1;break;case t.ui.keyCode.HOME:s=0;break;case t.ui.keyCode.SPACE:return e.preventDefault(),clearTimeout(this.activating),this._activate(s),void 0;case t.ui.keyCode.ENTER:return e.preventDefault(),clearTimeout(this.activating),this._activate(s===this.options.active?!1:s),void 0;default:return}e.preventDefault(),clearTimeout(this.activating),s=this._focusNextTab(s,n),e.ctrlKey||e.metaKey||(i.attr("aria-selected","false"),this.tabs.eq(s).attr("aria-selected","true"),this.activating=this._delay(function(){this.option("active",s)},this.delay))}},_panelKeydown:function(e){this._handlePageNav(e)||e.ctrlKey&&e.keyCode===t.ui.keyCode.UP&&(e.preventDefault(),this.active.trigger("focus"))},_handlePageNav:function(e){return e.altKey&&e.keyCode===t.ui.keyCode.PAGE_UP?(this._activate(this._focusNextTab(this.options.active-1,!1)),!0):e.altKey&&e.keyCode===t.ui.keyCode.PAGE_DOWN?(this._activate(this._focusNextTab(this.options.active+1,!0)),!0):void 0},_findNextTab:function(e,i){function s(){return e>n&&(e=0),0>e&&(e=n),e}for(var n=this.tabs.length-1;-1!==t.inArray(s(),this.options.disabled);)e=i?e+1:e-1;return e},_focusNextTab:function(t,e){return t=this._findNextTab(t,e),this.tabs.eq(t).trigger("focus"),t},_setOption:function(t,e){return"active"===t?(this._activate(e),void 0):(this._super(t,e),"collapsible"===t&&(this._toggleClass("ui-tabs-collapsible",null,e),e||this.options.active!==!1||this._activate(0)),"event"===t&&this._setupEvents(e),"heightStyle"===t&&this._setupHeightStyle(e),void 0)},_sanitizeSelector:function(t){return t?t.replace(/[!"$%&'()*+,.\/:;<=>?@\[\]\^`{|}~]/g,"\\$&"):""},refresh:function(){var e=this.options,i=this.tablist.children(":has(a[href])");e.disabled=t.map(i.filter(".ui-state-disabled"),function(t){return i.index(t)}),this._processTabs(),e.active!==!1&&this.anchors.length?this.active.length&&!t.contains(this.tablist[0],this.active[0])?this.tabs.length===e.disabled.length?(e.active=!1,this.active=t()):this._activate(this._findNextTab(Math.max(0,e.active-1),!1)):e.active=this.tabs.index(this.active):(e.active=!1,this.active=t()),this._refresh()},_refresh:function(){this._setOptionDisabled(this.options.disabled),this._setupEvents(this.options.event),this._setupHeightStyle(this.options.heightStyle),this.tabs.not(this.active).attr({"aria-selected":"false","aria-expanded":"false",tabIndex:-1}),this.panels.not(this._getPanelForTab(this.active)).hide().attr({"aria-hidden":"true"}),this.active.length?(this.active.attr({"aria-selected":"true","aria-expanded":"true",tabIndex:0}),this._addClass(this.active,"ui-tabs-active","ui-state-active"),this._getPanelForTab(this.active).show().attr({"aria-hidden":"false"})):this.tabs.eq(0).attr("tabIndex",0)},_processTabs:function(){var e=this,i=this.tabs,s=this.anchors,n=this.panels;this.tablist=this._getList().attr("role","tablist"),this._addClass(this.tablist,"ui-tabs-nav","ui-helper-reset ui-helper-clearfix ui-widget-header"),this.tablist.on("mousedown"+this.eventNamespace,"> li",function(e){t(this).is(".ui-state-disabled")&&e.preventDefault()}).on("focus"+this.eventNamespace,".ui-tabs-anchor",function(){t(this).closest("li").is(".ui-state-disabled")&&this.blur()}),this.tabs=this.tablist.find("> li:has(a[href])").attr({role:"tab",tabIndex:-1}),this._addClass(this.tabs,"ui-tabs-tab","ui-state-default"),this.anchors=this.tabs.map(function(){return t("a",this)[0]}).attr({role:"presentation",tabIndex:-1}),this._addClass(this.anchors,"ui-tabs-anchor"),this.panels=t(),this.anchors.each(function(i,s){var n,o,a,r=t(s).uniqueId().attr("id"),h=t(s).closest("li"),l=h.attr("aria-controls");e._isLocal(s)?(n=s.hash,a=n.substring(1),o=e.element.find(e._sanitizeSelector(n))):(a=h.attr("aria-controls")||t({}).uniqueId()[0].id,n="#"+a,o=e.element.find(n),o.length||(o=e._createPanel(a),o.insertAfter(e.panels[i-1]||e.tablist)),o.attr("aria-live","polite")),o.length&&(e.panels=e.panels.add(o)),l&&h.data("ui-tabs-aria-controls",l),h.attr({"aria-controls":a,"aria-labelledby":r}),o.attr("aria-labelledby",r)}),this.panels.attr("role","tabpanel"),this._addClass(this.panels,"ui-tabs-panel","ui-widget-content"),i&&(this._off(i.not(this.tabs)),this._off(s.not(this.anchors)),this._off(n.not(this.panels)))},_getList:function(){return this.tablist||this.element.find("ol, ul").eq(0)},_createPanel:function(e){return t("
").attr("id",e).data("ui-tabs-destroy",!0)},_setOptionDisabled:function(e){var i,s,n;for(t.isArray(e)&&(e.length?e.length===this.anchors.length&&(e=!0):e=!1),n=0;s=this.tabs[n];n++)i=t(s),e===!0||-1!==t.inArray(n,e)?(i.attr("aria-disabled","true"),this._addClass(i,null,"ui-state-disabled")):(i.removeAttr("aria-disabled"),this._removeClass(i,null,"ui-state-disabled"));this.options.disabled=e,this._toggleClass(this.widget(),this.widgetFullName+"-disabled",null,e===!0)},_setupEvents:function(e){var i={};e&&t.each(e.split(" "),function(t,e){i[e]="_eventHandler"}),this._off(this.anchors.add(this.tabs).add(this.panels)),this._on(!0,this.anchors,{click:function(t){t.preventDefault()}}),this._on(this.anchors,i),this._on(this.tabs,{keydown:"_tabKeydown"}),this._on(this.panels,{keydown:"_panelKeydown"}),this._focusable(this.tabs),this._hoverable(this.tabs)},_setupHeightStyle:function(e){var i,s=this.element.parent();"fill"===e?(i=s.height(),i-=this.element.outerHeight()-this.element.height(),this.element.siblings(":visible").each(function(){var e=t(this),s=e.css("position");"absolute"!==s&&"fixed"!==s&&(i-=e.outerHeight(!0))}),this.element.children().not(this.panels).each(function(){i-=t(this).outerHeight(!0)}),this.panels.each(function(){t(this).height(Math.max(0,i-t(this).innerHeight()+t(this).height()))}).css("overflow","auto")):"auto"===e&&(i=0,this.panels.each(function(){i=Math.max(i,t(this).height("").height())}).height(i))},_eventHandler:function(e){var i=this.options,s=this.active,n=t(e.currentTarget),o=n.closest("li"),a=o[0]===s[0],r=a&&i.collapsible,h=r?t():this._getPanelForTab(o),l=s.length?this._getPanelForTab(s):t(),c={oldTab:s,oldPanel:l,newTab:r?t():o,newPanel:h};e.preventDefault(),o.hasClass("ui-state-disabled")||o.hasClass("ui-tabs-loading")||this.running||a&&!i.collapsible||this._trigger("beforeActivate",e,c)===!1||(i.active=r?!1:this.tabs.index(o),this.active=a?t():o,this.xhr&&this.xhr.abort(),l.length||h.length||t.error("jQuery UI Tabs: Mismatching fragment identifier."),h.length&&this.load(this.tabs.index(o),e),this._toggle(e,c))},_toggle:function(e,i){function s(){o.running=!1,o._trigger("activate",e,i)}function n(){o._addClass(i.newTab.closest("li"),"ui-tabs-active","ui-state-active"),a.length&&o.options.show?o._show(a,o.options.show,s):(a.show(),s())}var o=this,a=i.newPanel,r=i.oldPanel;this.running=!0,r.length&&this.options.hide?this._hide(r,this.options.hide,function(){o._removeClass(i.oldTab.closest("li"),"ui-tabs-active","ui-state-active"),n()}):(this._removeClass(i.oldTab.closest("li"),"ui-tabs-active","ui-state-active"),r.hide(),n()),r.attr("aria-hidden","true"),i.oldTab.attr({"aria-selected":"false","aria-expanded":"false"}),a.length&&r.length?i.oldTab.attr("tabIndex",-1):a.length&&this.tabs.filter(function(){return 0===t(this).attr("tabIndex")}).attr("tabIndex",-1),a.attr("aria-hidden","false"),i.newTab.attr({"aria-selected":"true","aria-expanded":"true",tabIndex:0})},_activate:function(e){var i,s=this._findActive(e);s[0]!==this.active[0]&&(s.length||(s=this.active),i=s.find(".ui-tabs-anchor")[0],this._eventHandler({target:i,currentTarget:i,preventDefault:t.noop}))},_findActive:function(e){return e===!1?t():this.tabs.eq(e)},_getIndex:function(e){return"string"==typeof e&&(e=this.anchors.index(this.anchors.filter("[href$='"+t.ui.escapeSelector(e)+"']"))),e},_destroy:function(){this.xhr&&this.xhr.abort(),this.tablist.removeAttr("role").off(this.eventNamespace),this.anchors.removeAttr("role tabIndex").removeUniqueId(),this.tabs.add(this.panels).each(function(){t.data(this,"ui-tabs-destroy")?t(this).remove():t(this).removeAttr("role tabIndex aria-live aria-busy aria-selected aria-labelledby aria-hidden aria-expanded")}),this.tabs.each(function(){var e=t(this),i=e.data("ui-tabs-aria-controls");i?e.attr("aria-controls",i).removeData("ui-tabs-aria-controls"):e.removeAttr("aria-controls")}),this.panels.show(),"content"!==this.options.heightStyle&&this.panels.css("height","")},enable:function(e){var i=this.options.disabled;i!==!1&&(void 0===e?i=!1:(e=this._getIndex(e),i=t.isArray(i)?t.map(i,function(t){return t!==e?t:null}):t.map(this.tabs,function(t,i){return i!==e?i:null})),this._setOptionDisabled(i))},disable:function(e){var i=this.options.disabled;if(i!==!0){if(void 0===e)i=!0;else{if(e=this._getIndex(e),-1!==t.inArray(e,i))return;i=t.isArray(i)?t.merge([e],i).sort():[e]}this._setOptionDisabled(i)}},load:function(e,i){e=this._getIndex(e);var s=this,n=this.tabs.eq(e),o=n.find(".ui-tabs-anchor"),a=this._getPanelForTab(n),r={tab:n,panel:a},h=function(t,e){"abort"===e&&s.panels.stop(!1,!0),s._removeClass(n,"ui-tabs-loading"),a.removeAttr("aria-busy"),t===s.xhr&&delete s.xhr};this._isLocal(o[0])||(this.xhr=t.ajax(this._ajaxSettings(o,i,r)),this.xhr&&"canceled"!==this.xhr.statusText&&(this._addClass(n,"ui-tabs-loading"),a.attr("aria-busy","true"),this.xhr.done(function(t,e,n){setTimeout(function(){a.html(t),s._trigger("load",i,r),h(n,e)},1)}).fail(function(t,e){setTimeout(function(){h(t,e)},1)})))},_ajaxSettings:function(e,i,s){var n=this;return{url:e.attr("href").replace(/#.*$/,""),beforeSend:function(e,o){return n._trigger("beforeLoad",i,t.extend({jqXHR:e,ajaxSettings:o},s))}}},_getPanelForTab:function(e){var i=t(e).attr("aria-controls");return this.element.find(this._sanitizeSelector("#"+i))}}),t.uiBackCompat!==!1&&t.widget("ui.tabs",t.ui.tabs,{_processTabs:function(){this._superApply(arguments),this._addClass(this.tabs,"ui-tab")}}),t.ui.tabs,t.widget("ui.tooltip",{version:"1.12.1",options:{classes:{"ui-tooltip":"ui-corner-all ui-widget-shadow"},content:function(){var e=t(this).attr("title")||"";return t("").text(e).html()},hide:!0,items:"[title]:not([disabled])",position:{my:"left top+15",at:"left bottom",collision:"flipfit flip"},show:!0,track:!1,close:null,open:null},_addDescribedBy:function(e,i){var s=(e.attr("aria-describedby")||"").split(/\s+/);s.push(i),e.data("ui-tooltip-id",i).attr("aria-describedby",t.trim(s.join(" ")))},_removeDescribedBy:function(e){var i=e.data("ui-tooltip-id"),s=(e.attr("aria-describedby")||"").split(/\s+/),n=t.inArray(i,s);-1!==n&&s.splice(n,1),e.removeData("ui-tooltip-id"),s=t.trim(s.join(" ")),s?e.attr("aria-describedby",s):e.removeAttr("aria-describedby")},_create:function(){this._on({mouseover:"open",focusin:"open"}),this.tooltips={},this.parents={},this.liveRegion=t("
").attr({role:"log","aria-live":"assertive","aria-relevant":"additions"}).appendTo(this.document[0].body),this._addClass(this.liveRegion,null,"ui-helper-hidden-accessible"),this.disabledTitles=t([])},_setOption:function(e,i){var s=this;this._super(e,i),"content"===e&&t.each(this.tooltips,function(t,e){s._updateContent(e.element)})},_setOptionDisabled:function(t){this[t?"_disable":"_enable"]()},_disable:function(){var e=this;t.each(this.tooltips,function(i,s){var n=t.Event("blur");n.target=n.currentTarget=s.element[0],e.close(n,!0)}),this.disabledTitles=this.disabledTitles.add(this.element.find(this.options.items).addBack().filter(function(){var e=t(this);return e.is("[title]")?e.data("ui-tooltip-title",e.attr("title")).removeAttr("title"):void 0}))},_enable:function(){this.disabledTitles.each(function(){var e=t(this);e.data("ui-tooltip-title")&&e.attr("title",e.data("ui-tooltip-title"))}),this.disabledTitles=t([])},open:function(e){var i=this,s=t(e?e.target:this.element).closest(this.options.items);s.length&&!s.data("ui-tooltip-id")&&(s.attr("title")&&s.data("ui-tooltip-title",s.attr("title")),s.data("ui-tooltip-open",!0),e&&"mouseover"===e.type&&s.parents().each(function(){var e,s=t(this);s.data("ui-tooltip-open")&&(e=t.Event("blur"),e.target=e.currentTarget=this,i.close(e,!0)),s.attr("title")&&(s.uniqueId(),i.parents[this.id]={element:this,title:s.attr("title")},s.attr("title",""))}),this._registerCloseHandlers(e,s),this._updateContent(s,e))},_updateContent:function(t,e){var i,s=this.options.content,n=this,o=e?e.type:null;return"string"==typeof s||s.nodeType||s.jquery?this._open(e,t,s):(i=s.call(t[0],function(i){n._delay(function(){t.data("ui-tooltip-open")&&(e&&(e.type=o),this._open(e,t,i))})}),i&&this._open(e,t,i),void 0)},_open:function(e,i,s){function n(t){l.of=t,a.is(":hidden")||a.position(l)}var o,a,r,h,l=t.extend({},this.options.position);if(s){if(o=this._find(i))return o.tooltip.find(".ui-tooltip-content").html(s),void 0;i.is("[title]")&&(e&&"mouseover"===e.type?i.attr("title",""):i.removeAttr("title")),o=this._tooltip(i),a=o.tooltip,this._addDescribedBy(i,a.attr("id")),a.find(".ui-tooltip-content").html(s),this.liveRegion.children().hide(),h=t("
").html(a.find(".ui-tooltip-content").html()),h.removeAttr("name").find("[name]").removeAttr("name"),h.removeAttr("id").find("[id]").removeAttr("id"),h.appendTo(this.liveRegion),this.options.track&&e&&/^mouse/.test(e.type)?(this._on(this.document,{mousemove:n}),n(e)):a.position(t.extend({of:i},this.options.position)),a.hide(),this._show(a,this.options.show),this.options.track&&this.options.show&&this.options.show.delay&&(r=this.delayedShow=setInterval(function(){a.is(":visible")&&(n(l.of),clearInterval(r))},t.fx.interval)),this._trigger("open",e,{tooltip:a})}},_registerCloseHandlers:function(e,i){var s={keyup:function(e){if(e.keyCode===t.ui.keyCode.ESCAPE){var s=t.Event(e);s.currentTarget=i[0],this.close(s,!0)}}};i[0]!==this.element[0]&&(s.remove=function(){this._removeTooltip(this._find(i).tooltip)}),e&&"mouseover"!==e.type||(s.mouseleave="close"),e&&"focusin"!==e.type||(s.focusout="close"),this._on(!0,i,s)},close:function(e){var i,s=this,n=t(e?e.currentTarget:this.element),o=this._find(n);return o?(i=o.tooltip,o.closing||(clearInterval(this.delayedShow),n.data("ui-tooltip-title")&&!n.attr("title")&&n.attr("title",n.data("ui-tooltip-title")),this._removeDescribedBy(n),o.hiding=!0,i.stop(!0),this._hide(i,this.options.hide,function(){s._removeTooltip(t(this))}),n.removeData("ui-tooltip-open"),this._off(n,"mouseleave focusout keyup"),n[0]!==this.element[0]&&this._off(n,"remove"),this._off(this.document,"mousemove"),e&&"mouseleave"===e.type&&t.each(this.parents,function(e,i){t(i.element).attr("title",i.title),delete s.parents[e]}),o.closing=!0,this._trigger("close",e,{tooltip:i}),o.hiding||(o.closing=!1)),void 0):(n.removeData("ui-tooltip-open"),void 0)},_tooltip:function(e){var i=t("
").attr("role","tooltip"),s=t("
").appendTo(i),n=i.uniqueId().attr("id");return this._addClass(s,"ui-tooltip-content"),this._addClass(i,"ui-tooltip","ui-widget ui-widget-content"),i.appendTo(this._appendTo(e)),this.tooltips[n]={element:e,tooltip:i}},_find:function(t){var e=t.data("ui-tooltip-id");return e?this.tooltips[e]:null},_removeTooltip:function(t){t.remove(),delete this.tooltips[t.attr("id")]},_appendTo:function(t){var e=t.closest(".ui-front, dialog");return e.length||(e=this.document[0].body),e},_destroy:function(){var e=this;t.each(this.tooltips,function(i,s){var n=t.Event("blur"),o=s.element;n.target=n.currentTarget=o[0],e.close(n,!0),t("#"+i).remove(),o.data("ui-tooltip-title")&&(o.attr("title")||o.attr("title",o.data("ui-tooltip-title")),o.removeData("ui-tooltip-title"))}),this.liveRegion.remove()}}),t.uiBackCompat!==!1&&t.widget("ui.tooltip",t.ui.tooltip,{options:{tooltipClass:null},_tooltip:function(){var t=this._superApply(arguments);return this.options.tooltipClass&&t.tooltip.addClass(this.options.tooltipClass),t}}),t.ui.tooltip}); \ No newline at end of file diff --git a/docs/waifu_plugin/source b/docs/waifu_plugin/source index 82d2ed01245d9ab6a6d70576398b96286b24790d..7201fd631355230715b825c8046718da50c2c75c 100644 --- a/docs/waifu_plugin/source +++ b/docs/waifu_plugin/source @@ -1 +1 @@ -https://github.com/fghrsh/live2d_demo +https://github.com/fghrsh/live2d_demo \ No newline at end of file diff --git a/docs/waifu_plugin/waifu-tips.js b/docs/waifu_plugin/waifu-tips.js index 6ae98395a14239861fbc8250d190971e34590434..8f9533a19e7d4914bde888ee2a107e4430242968 100644 --- a/docs/waifu_plugin/waifu-tips.js +++ b/docs/waifu_plugin/waifu-tips.js @@ -5,11 +5,11 @@ window.live2d_settings = Array(); /*       /`ー'    L//`ヽ、 Live2D 看板娘 参数设置      /  /,  /|  ,  ,    ', Version 1.4.2    イ  / /-‐/ i L_ ハ ヽ!  i Update 2018.11.12 -     レ ヘ 7イ`ト  レ'ァ-ト、!ハ|  | +     レ ヘ 7イ`ト  レ'ァ-ト、!ハ|  |      !,/7 '0'   ´0iソ|   |         |.从"  _   ,,,, / |./   | 网页添加 Live2D 看板娘      レ'| i>.、,,__ _,.イ /  .i  | https://www.fghrsh.net/post/123.html -       レ'| | / k_7_/レ'ヽ, ハ. | +       レ'| | / k_7_/レ'ヽ, ハ. |        | |/i 〈|/  i ,.ヘ | i | Thanks       .|/ / i:   ヘ!  \ | journey-ad / https://github.com/journey-ad/live2d_src         kヽ>、ハ   _,.ヘ、   /、! xiazeyu / https://github.com/xiazeyu/live2d-widget.js @@ -77,11 +77,11 @@ String.prototype.render = function(context) { return this.replace(tokenReg, function (word, slash1, token, slash2) { if (slash1 || slash2) { return word.replace('\\', ''); } - + var variables = token.replace(/\s/g, '').split('.'); var currentObject = context; var i, length, variable; - + for (i = 0, length = variables.length; i < length; ++i) { variable = variables[i]; currentObject = currentObject[variable]; @@ -101,9 +101,9 @@ function showMessage(text, timeout, flag) { if(flag || sessionStorage.getItem('waifu-text') === '' || sessionStorage.getItem('waifu-text') === null){ if(Array.isArray(text)) text = text[Math.floor(Math.random() * text.length + 1)-1]; if (live2d_settings.showF12Message) console.log('[Message]', text.replace(/<[^<>]+>/g,'')); - + if(flag) sessionStorage.setItem('waifu-text', text); - + $('.waifu-tips').stop(); $('.waifu-tips').html(text).fadeTo(200, 1); if (timeout === undefined) timeout = 5000; @@ -121,15 +121,15 @@ function hideMessage(timeout) { function initModel(waifuPath, type) { /* console welcome message */ eval(function(p,a,c,k,e,r){e=function(c){return(c35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('8.d(" ");8.d("\\U,.\\y\\5.\\1\\1\\1\\1/\\1,\\u\\2 \\H\\n\\1\\1\\1\\1\\1\\b \', !-\\r\\j-i\\1/\\1/\\g\\n\\1\\1\\1 \\1 \\a\\4\\f\'\\1\\1\\1 L/\\a\\4\\5\\2\\n\\1\\1 \\1 /\\1 \\a,\\1 /|\\1 ,\\1 ,\\1\\1\\1 \',\\n\\1\\1\\1\\q \\1/ /-\\j/\\1\\h\\E \\9 \\5!\\1 i\\n\\1\\1\\1 \\3 \\6 7\\q\\4\\c\\1 \\3\'\\s-\\c\\2!\\t|\\1 |\\n\\1\\1\\1\\1 !,/7 \'0\'\\1\\1 \\X\\w| \\1 |\\1\\1\\1\\n\\1\\1\\1\\1 |.\\x\\"\\1\\l\\1\\1 ,,,, / |./ \\1 |\\n\\1\\1\\1\\1 \\3\'| i\\z.\\2,,A\\l,.\\B / \\1.i \\1|\\n\\1\\1\\1\\1\\1 \\3\'| | / C\\D/\\3\'\\5,\\1\\9.\\1|\\n\\1\\1\\1\\1\\1\\1 | |/i \\m|/\\1 i\\1,.\\6 |\\F\\1|\\n\\1\\1\\1\\1\\1\\1.|/ /\\1\\h\\G \\1 \\6!\\1\\1\\b\\1|\\n\\1\\1\\1 \\1 \\1 k\\5>\\2\\9 \\1 o,.\\6\\2 \\1 /\\2!\\n\\1\\1\\1\\1\\1\\1 !\'\\m//\\4\\I\\g\', \\b \\4\'7\'\\J\'\\n\\1\\1\\1\\1\\1\\1 \\3\'\\K|M,p,\\O\\3|\\P\\n\\1\\1\\1\\1\\1 \\1\\1\\1\\c-,/\\1|p./\\n\\1\\1\\1\\1\\1 \\1\\1\\1\'\\f\'\\1\\1!o,.:\\Q \\R\\S\\T v"+e.V+" / W "+e.N);8.d(" ");',60,60,'|u3000|uff64|uff9a|uff40|u30fd|uff8d||console|uff8a|uff0f|uff3c|uff84|log|live2d_settings|uff70|u00b4|uff49||u2010||u3000_|u3008||_|___|uff72|u2500|uff67|u30cf|u30fc||u30bd|u4ece|u30d8|uff1e|__|u30a4|k_|uff17_|u3000L_|u3000i|uff1a|u3009|uff34|uff70r|u30fdL__||___i|l2dVerDate|u30f3|u30ce|nLive2D|u770b|u677f|u5a18|u304f__|l2dVersion|FGHRSH|u00b40i'.split('|'),0,{})); - + /* 判断 JQuery */ if (typeof($.ajax) != 'function') typeof(jQuery.ajax) == 'function' ? window.$ = jQuery : console.log('[Error] JQuery is not defined.'); - + /* 加载看板娘样式 */ live2d_settings.waifuSize = live2d_settings.waifuSize.split('x'); live2d_settings.waifuTipsSize = live2d_settings.waifuTipsSize.split('x'); live2d_settings.waifuEdgeSide = live2d_settings.waifuEdgeSide.split(':'); - + $("#live2d").attr("width",live2d_settings.waifuSize[0]); $("#live2d").attr("height",live2d_settings.waifuSize[1]); $(".waifu-tips").width(live2d_settings.waifuTipsSize[0]); @@ -138,32 +138,32 @@ function initModel(waifuPath, type) { $(".waifu-tips").css("font-size",live2d_settings.waifuFontSize); $(".waifu-tool").css("font-size",live2d_settings.waifuToolFont); $(".waifu-tool span").css("line-height",live2d_settings.waifuToolLine); - + if (live2d_settings.waifuEdgeSide[0] == 'left') $(".waifu").css("left",live2d_settings.waifuEdgeSide[1]+'px'); else if (live2d_settings.waifuEdgeSide[0] == 'right') $(".waifu").css("right",live2d_settings.waifuEdgeSide[1]+'px'); - + window.waifuResize = function() { $(window).width() <= Number(live2d_settings.waifuMinWidth.replace('px','')) ? $(".waifu").hide() : $(".waifu").show(); }; if (live2d_settings.waifuMinWidth != 'disable') { waifuResize(); $(window).resize(function() {waifuResize()}); } - + try { if (live2d_settings.waifuDraggable == 'axis-x') $(".waifu").draggable({ axis: "x", revert: live2d_settings.waifuDraggableRevert }); else if (live2d_settings.waifuDraggable == 'unlimited') $(".waifu").draggable({ revert: live2d_settings.waifuDraggableRevert }); else $(".waifu").css("transition", 'all .3s ease-in-out'); } catch(err) { console.log('[Error] JQuery UI is not defined.') } - + live2d_settings.homePageUrl = live2d_settings.homePageUrl == 'auto' ? window.location.protocol+'//'+window.location.hostname+'/' : live2d_settings.homePageUrl; if (window.location.protocol == 'file:' && live2d_settings.modelAPI.substr(0,2) == '//') live2d_settings.modelAPI = 'http:'+live2d_settings.modelAPI; - + $('.waifu-tool .fui-home').click(function (){ //window.location = 'https://www.fghrsh.net/'; window.location = live2d_settings.homePageUrl; }); - + $('.waifu-tool .fui-info-circle').click(function (){ //window.open('https://imjad.cn/archives/lab/add-dynamic-poster-girl-with-live2d-to-your-blog-02'); window.open(live2d_settings.aboutPageUrl); }); - + if (typeof(waifuPath) == "object") loadTipsMessage(waifuPath); else { $.ajax({ cache: true, @@ -172,7 +172,7 @@ function initModel(waifuPath, type) { success: function (result){ loadTipsMessage(result); } }); } - + if (!live2d_settings.showToolMenu) $('.waifu-tool').hide(); if (!live2d_settings.canCloseLive2d) $('.waifu-tool .fui-cross').hide(); if (!live2d_settings.canSwitchModel) $('.waifu-tool .fui-eye').hide(); @@ -185,7 +185,7 @@ function initModel(waifuPath, type) { if (waifuPath === undefined) waifuPath = ''; var modelId = localStorage.getItem('modelId'); var modelTexturesId = localStorage.getItem('modelTexturesId'); - + if (!live2d_settings.modelStorage || modelId == null) { var modelId = live2d_settings.modelId; var modelTexturesId = live2d_settings.modelTexturesId; @@ -204,7 +204,7 @@ function loadModel(modelId, modelTexturesId=0) { function loadTipsMessage(result) { window.waifu_tips = result; - + $.each(result.mouseover, function (index, tips){ $(document).on("mouseover", tips.selector, function (){ var text = getRandText(tips.text); @@ -223,50 +223,82 @@ function loadTipsMessage(result) { var now = new Date(); var after = tips.date.split('-')[0]; var before = tips.date.split('-')[1] || after; - - if((after.split('/')[0] <= now.getMonth()+1 && now.getMonth()+1 <= before.split('/')[0]) && + + if((after.split('/')[0] <= now.getMonth()+1 && now.getMonth()+1 <= before.split('/')[0]) && (after.split('/')[1] <= now.getDate() && now.getDate() <= before.split('/')[1])){ var text = getRandText(tips.text); text = text.render({year: now.getFullYear()}); showMessage(text, 6000, true); } }); - + if (live2d_settings.showF12OpenMsg) { re.toString = function() { showMessage(getRandText(result.waifu.console_open_msg), 5000, true); return ''; }; } - + if (live2d_settings.showCopyMessage) { $(document).on('copy', function() { showMessage(getRandText(result.waifu.copy_message), 5000, true); }); } - + $('.waifu-tool .fui-photo').click(function(){ showMessage(getRandText(result.waifu.screenshot_message), 5000, true); window.Live2D.captureName = live2d_settings.screenshotCaptureName; window.Live2D.captureFrame = true; }); - + $('.waifu-tool .fui-cross').click(function(){ sessionStorage.setItem('waifu-dsiplay', 'none'); showMessage(getRandText(result.waifu.hidden_message), 1300, true); window.setTimeout(function() {$('.waifu').hide();}, 1300); }); - + window.showWelcomeMessage = function(result) { - showMessage('欢迎使用GPT-Academic', 6000); + var text; + if (window.location.href == live2d_settings.homePageUrl) { + var now = (new Date()).getHours(); + if (now > 23 || now <= 5) text = getRandText(result.waifu.hour_tips['t23-5']); + else if (now > 5 && now <= 7) text = getRandText(result.waifu.hour_tips['t5-7']); + else if (now > 7 && now <= 11) text = getRandText(result.waifu.hour_tips['t7-11']); + else if (now > 11 && now <= 14) text = getRandText(result.waifu.hour_tips['t11-14']); + else if (now > 14 && now <= 17) text = getRandText(result.waifu.hour_tips['t14-17']); + else if (now > 17 && now <= 19) text = getRandText(result.waifu.hour_tips['t17-19']); + else if (now > 19 && now <= 21) text = getRandText(result.waifu.hour_tips['t19-21']); + else if (now > 21 && now <= 23) text = getRandText(result.waifu.hour_tips['t21-23']); + else text = getRandText(result.waifu.hour_tips.default); + } else { + var referrer_message = result.waifu.referrer_message; + if (document.referrer !== '') { + var referrer = document.createElement('a'); + referrer.href = document.referrer; + var domain = referrer.hostname.split('.')[1]; + if (window.location.hostname == referrer.hostname) + text = referrer_message.localhost[0] + document.title.split(referrer_message.localhost[2])[0] + referrer_message.localhost[1]; + else if (domain == 'baidu') + text = referrer_message.baidu[0] + referrer.search.split('&wd=')[1].split('&')[0] + referrer_message.baidu[1]; + else if (domain == 'so') + text = referrer_message.so[0] + referrer.search.split('&q=')[1].split('&')[0] + referrer_message.so[1]; + else if (domain == 'google') + text = referrer_message.google[0] + document.title.split(referrer_message.google[2])[0] + referrer_message.google[1]; + else { + $.each(result.waifu.referrer_hostname, function(i,val) {if (i==referrer.hostname) referrer.hostname = getRandText(val)}); + text = referrer_message.default[0] + referrer.hostname + referrer_message.default[1]; + } + } else text = referrer_message.none[0] + document.title.split(referrer_message.none[2])[0] + referrer_message.none[1]; + } + showMessage(text, 6000); }; if (live2d_settings.showWelcomeMessage) showWelcomeMessage(result); - + var waifu_tips = result.waifu; - + function loadOtherModel() { var modelId = modelStorageGetItem('modelId'); var modelRandMode = live2d_settings.modelRandMode; - + $.ajax({ cache: modelRandMode == 'switch' ? true : false, url: live2d_settings.modelAPI+modelRandMode+'/?id='+modelId, @@ -279,12 +311,12 @@ function loadTipsMessage(result) { } }); } - + function loadRandTextures() { var modelId = modelStorageGetItem('modelId'); var modelTexturesId = modelStorageGetItem('modelTexturesId'); var modelTexturesRandMode = live2d_settings.modelTexturesRandMode; - + $.ajax({ cache: modelTexturesRandMode == 'switch' ? true : false, url: live2d_settings.modelAPI+modelTexturesRandMode+'_textures/?id='+modelId+'-'+modelTexturesId, @@ -297,32 +329,32 @@ function loadTipsMessage(result) { } }); } - + function modelStorageGetItem(key) { return live2d_settings.modelStorage ? localStorage.getItem(key) : sessionStorage.getItem(key); } - + /* 检测用户活动状态,并在空闲时显示一言 */ if (live2d_settings.showHitokoto) { window.getActed = false; window.hitokotoTimer = 0; window.hitokotoInterval = false; $(document).mousemove(function(e){getActed = true;}).keydown(function(){getActed = true;}); setInterval(function(){ if (!getActed) ifActed(); else elseActed(); }, 1000); } - + function ifActed() { if (!hitokotoInterval) { hitokotoInterval = true; hitokotoTimer = window.setInterval(showHitokotoActed, 30000); } } - + function elseActed() { getActed = hitokotoInterval = false; window.clearInterval(hitokotoTimer); } - + function showHitokotoActed() { if ($(document)[0].visibilityState == 'visible') showHitokoto(); } - + function showHitokoto() { switch(live2d_settings.hitokotoAPI) { case 'lwl12.com': @@ -366,7 +398,7 @@ function loadTipsMessage(result) { }); } } - + $('.waifu-tool .fui-eye').click(function (){loadOtherModel()}); $('.waifu-tool .fui-user').click(function (){loadRandTextures()}); $('.waifu-tool .fui-chat').click(function (){showHitokoto()}); diff --git a/docs/waifu_plugin/waifu-tips.json b/docs/waifu_plugin/waifu-tips.json index c7d84e3e6835a3d0926c3a4539bd223affd0265c..229d5a14cae722e7f7dbaf23e23d11e6ce233199 100644 --- a/docs/waifu_plugin/waifu-tips.json +++ b/docs/waifu_plugin/waifu-tips.json @@ -31,7 +31,7 @@ }, "model_message": { "1": ["来自 Potion Maker 的 Pio 酱 ~"], - "2": ["来自 Potion Maker 的 Tia 酱 ~"] + "2": ["来自 Potion Maker 的 Tia 酱 ~"] }, "hitokoto_api_message": { "lwl12.com": ["这句一言来自 『{source}』", ",是 {creator} 投稿的", "。"], @@ -83,8 +83,8 @@ "很多强大的函数插件隐藏在下拉菜单中呢。", "红色的插件,使用之前需要把文件上传进去哦。", "想添加功能按钮吗?读读readme很容易就学会啦。", - "敏感或机密的信息,不可以问AI的哦!", - "LLM究竟是划时代的创新,还是扼杀创造力的毒药呢?" + "敏感或机密的信息,不可以问chatGPT的哦!", + "chatGPT究竟是划时代的创新,还是扼杀创造力的毒药呢?" ] } ], "click": [ @@ -92,6 +92,8 @@ "selector": ".waifu #live2d", "text": [ "是…是不小心碰到了吧", + "萝莉控是什么呀", + "你看到我的小熊了吗", "再摸的话我可要报警了!⌇●﹏●⌇", "110吗,这里有个变态一直在摸我(ó﹏ò。)" ] @@ -111,4 +113,4 @@ { "date": "11/05-11/12", "text": ["今年的双十一是和谁一起过的呢~"] }, { "date": "12/20-12/31", "text": ["这几天是圣诞节,主人肯定又去剁手买买买了~"] } ] -} +} \ No newline at end of file diff --git a/docs/waifu_plugin/waifu.css b/docs/waifu_plugin/waifu.css index 0a50344d79a66972067476f308a1544968e00a40..42639df0794e46fc58f66e2c772e2bf9ba605eed 100644 --- a/docs/waifu_plugin/waifu.css +++ b/docs/waifu_plugin/waifu.css @@ -287,4 +287,4 @@ } .fui-user:before { content: "\e631"; -} +} \ No newline at end of file diff --git a/flagged/modeling_moss.py b/flagged/modeling_moss.py deleted file mode 100644 index f191bf532c0e1b769e773f932a35f099f782de44..0000000000000000000000000000000000000000 --- a/flagged/modeling_moss.py +++ /dev/null @@ -1,2952 +0,0 @@ -""" PyTorch Moss model.""" - -from typing import Optional, Tuple, Union - -import torch -import torch.utils.checkpoint -from torch import nn -from torch.nn import CrossEntropyLoss -import transformers -from transformers.activations import ACT2FN -from transformers.modeling_utils import PreTrainedModel -from transformers.modeling_outputs import BaseModelOutputWithPast, CausalLMOutputWithPast -from transformers.utils import ( - add_code_sample_docstrings, - add_start_docstrings, - add_start_docstrings_to_model_forward, - logging -) - -from .configuration_moss import MossConfig - -logger = logging.get_logger(__name__) - -_CHECKPOINT_FOR_DOC = "fnlp/moss-moon-003-base" -_CONFIG_FOR_DOC = "MossConfig" - - -MOSS_PRETRAINED_MODEL_ARCHIVE_LIST = [ - "fnlp/moss-moon-003-base", - "fnlp/moss-moon-003-sft", - "fnlp/moss-moon-003-sft-plugin", - "fnlp/moss-moon-003-sft-int4", - "fnlp/moss-moon-003-sft-plugin-int4", - "fnlp/moss-moon-003-sft-int8", - "fnlp/moss-moon-003-sft-plugin-int8", -] - - -# Copied from transformers.models.gptj.modeling_gptj.create_sinusoidal_positions -def create_sinusoidal_positions(num_pos: int, dim: int) -> torch.Tensor: - inv_freq = 1.0 / (10000 ** (torch.arange(0, dim, 2) / dim)) - sinusoid_inp = torch.einsum("i , j -> i j", torch.arange(num_pos, dtype=torch.float), inv_freq).float() - return torch.cat((torch.sin(sinusoid_inp), torch.cos(sinusoid_inp)), dim=1) - - -# Copied from transformers.models.gptj.modeling_gptj.rotate_every_two -def rotate_every_two(x: torch.Tensor) -> torch.Tensor: - x1 = x[:, :, :, ::2] - x2 = x[:, :, :, 1::2] - x = torch.stack((-x2, x1), dim=-1) - return x.flatten(-2) # in einsum notation: rearrange(x, '... d j -> ... (d j)') - - -# Copied from transformers.models.gptj.modeling_gptj.apply_rotary_pos_emb -def apply_rotary_pos_emb(tensor: torch.Tensor, sin: torch.Tensor, cos: torch.Tensor) -> torch.Tensor: - sin = torch.repeat_interleave(sin[:, :, None, :], 2, 3) - cos = torch.repeat_interleave(cos[:, :, None, :], 2, 3) - return (tensor * cos) + (rotate_every_two(tensor) * sin) - - -class MossAttention(nn.Module): - def __init__(self, config): - super().__init__() - - max_positions = config.max_position_embeddings - self.register_buffer( - "causal_mask", - torch.tril(torch.ones((max_positions, max_positions), dtype=torch.bool)).view( - 1, 1, max_positions, max_positions - ), - ) - - self.attn_dropout = nn.Dropout(config.attn_pdrop) - self.resid_dropout = nn.Dropout(config.resid_pdrop) - - self.embed_dim = config.hidden_size - self.num_attention_heads = config.num_attention_heads - self.head_dim = self.embed_dim // self.num_attention_heads - if self.head_dim * self.num_attention_heads != self.embed_dim: - raise ValueError( - f"embed_dim must be divisible by num_attention_heads (got `embed_dim`: {self.embed_dim} and" - f" `num_attention_heads`: {self.num_attention_heads})." - ) - self.scale_attn = torch.sqrt(torch.tensor(self.head_dim, dtype=torch.float32)).to(torch.get_default_dtype()) - self.qkv_proj = nn.Linear(self.embed_dim, self.embed_dim * 3, bias=False) - - self.out_proj = nn.Linear(self.embed_dim, self.embed_dim, bias=False) - self.rotary_dim = config.rotary_dim - pos_embd_dim = self.rotary_dim or self.embed_dim - self.embed_positions = create_sinusoidal_positions(max_positions, pos_embd_dim) - - def _split_heads(self, x, n_head, dim_head, mp_num): - reshaped = x.reshape(x.shape[:-1] + (n_head // mp_num, dim_head)) - reshaped = reshaped.reshape(x.shape[:-2] + (-1,) + reshaped.shape[-1:]) - return reshaped - - def _merge_heads(self, tensor, num_attention_heads, attn_head_size): - """ - Merges attn_head_size dim and num_attn_heads dim into n_ctx - """ - if len(tensor.shape) == 5: - tensor = tensor.permute(0, 1, 3, 2, 4).contiguous() - elif len(tensor.shape) == 4: - tensor = tensor.permute(0, 2, 1, 3).contiguous() - else: - raise ValueError(f"Input tensor rank should be one of [4, 5], but is: {len(tensor.shape)}") - new_shape = tensor.size()[:-2] + (num_attention_heads * attn_head_size,) - return tensor.view(new_shape) - - def _attn( - self, - query, - key, - value, - attention_mask=None, - head_mask=None, - ): - # compute causal mask from causal mask buffer - query_length, key_length = query.size(-2), key.size(-2) - causal_mask = self.causal_mask[:, :, key_length - query_length : key_length, :key_length] - - # Keep the attention weights computation in fp32 to avoid overflow issues - query = query.to(torch.float32) - key = key.to(torch.float32) - - attn_weights = torch.matmul(query, key.transpose(-1, -2)) - - attn_weights = attn_weights / self.scale_attn - mask_value = torch.finfo(attn_weights.dtype).min - # Need to be a tensor, otherwise we get error: `RuntimeError: expected scalar type float but found double`. - # Need to be on the same device, otherwise `RuntimeError: ..., x and y to be on the same device` - mask_value = torch.tensor(mask_value, dtype=attn_weights.dtype).to(attn_weights.device) - attn_weights = torch.where(causal_mask, attn_weights, mask_value) - - if attention_mask is not None: - # Apply the attention mask - attn_weights = attn_weights + attention_mask - - attn_weights = nn.Softmax(dim=-1)(attn_weights) - attn_weights = attn_weights.to(value.dtype) - attn_weights = self.attn_dropout(attn_weights) - - # Mask heads if we want to - if head_mask is not None: - attn_weights = attn_weights * head_mask - - attn_output = torch.matmul(attn_weights, value) - - return attn_output, attn_weights - - def forward( - self, - hidden_states: Optional[torch.FloatTensor], - layer_past: Optional[Tuple[torch.Tensor]] = None, - attention_mask: Optional[torch.FloatTensor] = None, - position_ids: Optional[torch.LongTensor] = None, - head_mask: Optional[torch.FloatTensor] = None, - use_cache: Optional[bool] = False, - output_attentions: Optional[bool] = False, - ) -> Union[ - Tuple[torch.Tensor, Tuple[torch.Tensor]], - Optional[Tuple[torch.Tensor, Tuple[torch.Tensor], Tuple[torch.Tensor, ...]]], - ]: - qkv = self.qkv_proj(hidden_states) - # TODO(enijkamp): factor out number of logical TPU-v4 cores or make forward pass agnostic - mp_num = 4 - qkv_split = qkv.reshape(qkv.shape[:-1] + (mp_num, -1)) - - local_dim = self.head_dim * self.num_attention_heads // mp_num - query, value, key = torch.split(qkv_split, local_dim, dim=-1) - query = self._split_heads(query, self.num_attention_heads, self.head_dim, mp_num=mp_num) - key = self._split_heads(key, self.num_attention_heads, self.head_dim, mp_num=mp_num) - - value = self._split_heads(value, self.num_attention_heads, self.head_dim, mp_num=mp_num) - value = value.permute(0, 2, 1, 3) - - embed_positions = self.embed_positions - if embed_positions.device != position_ids.device: - embed_positions = embed_positions.to(position_ids.device) - self.embed_positions = embed_positions - - sincos = embed_positions[position_ids] - sin, cos = torch.split(sincos, sincos.shape[-1] // 2, dim=-1) - - if self.rotary_dim is not None: - k_rot = key[:, :, :, : self.rotary_dim] - k_pass = key[:, :, :, self.rotary_dim :] - - q_rot = query[:, :, :, : self.rotary_dim] - q_pass = query[:, :, :, self.rotary_dim :] - - k_rot = apply_rotary_pos_emb(k_rot, sin, cos) - q_rot = apply_rotary_pos_emb(q_rot, sin, cos) - - key = torch.cat([k_rot, k_pass], dim=-1) - query = torch.cat([q_rot, q_pass], dim=-1) - else: - key = apply_rotary_pos_emb(key, sin, cos) - query = apply_rotary_pos_emb(query, sin, cos) - - key = key.permute(0, 2, 1, 3) - query = query.permute(0, 2, 1, 3) - - if layer_past is not None: - past_key = layer_past[0] - past_value = layer_past[1] - key = torch.cat((past_key, key), dim=-2) - value = torch.cat((past_value, value), dim=-2) - - if use_cache is True: - present = (key, value) - else: - present = None - - # compute self-attention: V x Softmax(QK^T) - attn_output, attn_weights = self._attn(query, key, value, attention_mask, head_mask) - - attn_output = self._merge_heads(attn_output, self.num_attention_heads, self.head_dim) - attn_output = self.out_proj(attn_output) - attn_output = self.resid_dropout(attn_output) - - outputs = (attn_output, present) - if output_attentions: - outputs += (attn_weights,) - - return outputs # a, present, (attentions) - - -# Copied from transformers.models.gptj.modeling_gptj.GPTJMLP with GPTJ->Moss -class MossMLP(nn.Module): - def __init__(self, intermediate_size, config): # in MLP: intermediate_size= 4 * embed_dim - super().__init__() - embed_dim = config.n_embd - - self.fc_in = nn.Linear(embed_dim, intermediate_size) - self.fc_out = nn.Linear(intermediate_size, embed_dim) - - self.act = ACT2FN[config.activation_function] - self.dropout = nn.Dropout(config.resid_pdrop) - - def forward(self, hidden_states: Optional[torch.FloatTensor]) -> torch.FloatTensor: - hidden_states = self.fc_in(hidden_states) - hidden_states = self.act(hidden_states) - hidden_states = self.fc_out(hidden_states) - hidden_states = self.dropout(hidden_states) - return hidden_states - - -# Copied from transformers.models.gptj.modeling_gptj.GPTJBlock with GPTJ->Moss -class MossBlock(nn.Module): - def __init__(self, config): - super().__init__() - inner_dim = config.n_inner if config.n_inner is not None else 4 * config.n_embd - self.ln_1 = nn.LayerNorm(config.n_embd, eps=config.layer_norm_epsilon) - self.attn = MossAttention(config) - self.mlp = MossMLP(inner_dim, config) - - def forward( - self, - hidden_states: Optional[torch.FloatTensor], - layer_past: Optional[Tuple[torch.Tensor]] = None, - attention_mask: Optional[torch.FloatTensor] = None, - position_ids: Optional[torch.LongTensor] = None, - head_mask: Optional[torch.FloatTensor] = None, - use_cache: Optional[bool] = False, - output_attentions: Optional[bool] = False, - ) -> Union[Tuple[torch.Tensor], Optional[Tuple[torch.Tensor, Tuple[torch.FloatTensor, ...]]]]: - residual = hidden_states - hidden_states = self.ln_1(hidden_states) - attn_outputs = self.attn( - hidden_states=hidden_states, - layer_past=layer_past, - attention_mask=attention_mask, - position_ids=position_ids, - head_mask=head_mask, - use_cache=use_cache, - output_attentions=output_attentions, - ) - attn_output = attn_outputs[0] # output_attn: a, present, (attentions) - outputs = attn_outputs[1:] - - feed_forward_hidden_states = self.mlp(hidden_states) - hidden_states = attn_output + feed_forward_hidden_states + residual - - if use_cache: - outputs = (hidden_states,) + outputs - else: - outputs = (hidden_states,) + outputs[1:] - - return outputs # hidden_states, present, (attentions) - - -class MossPreTrainedModel(PreTrainedModel): - """ - An abstract class to handle weights initialization and a simple interface for downloading and loading pretrained - models. - """ - - config_class = MossConfig - base_model_prefix = "transformer" - supports_gradient_checkpointing = True - _no_split_modules = ["MossBlock"] - - def __init__(self, *inputs, **kwargs): - super().__init__(*inputs, **kwargs) - - def _init_weights(self, module): - """Initialize the weights.""" - if isinstance(module, (nn.Linear,)): - # Slightly different from Mesh Transformer JAX which uses truncated_normal for initialization - # cf https://github.com/pytorch/pytorch/pull/5617 - module.weight.data.normal_(mean=0.0, std=self.config.initializer_range) - if module.bias is not None: - module.bias.data.zero_() - elif isinstance(module, nn.Embedding): - module.weight.data.normal_(mean=0.0, std=self.config.initializer_range) - if module.padding_idx is not None: - module.weight.data[module.padding_idx].zero_() - elif isinstance(module, nn.LayerNorm): - module.bias.data.zero_() - module.weight.data.fill_(1.0) - - def _set_gradient_checkpointing(self, module, value=False): - if isinstance(module, MossModel): - module.gradient_checkpointing = value - - -MOSS_START_DOCSTRING = r""" - This model is a PyTorch [torch.nn.Module](https://pytorch.org/docs/stable/nn.html#torch.nn.Module) sub-class. Use - it as a regular PyTorch Module and refer to the PyTorch documentation for all matter related to general usage and - behavior. - - Parameters: - config ([`MossConfig`]): Model configuration class with all the parameters of the model. - Initializing with a config file does not load the weights associated with the model, only the - configuration. Check out the [`~PreTrainedModel.from_pretrained`] method to load the model weights. -""" - -MOSS_INPUTS_DOCSTRING = r""" - Args: - input_ids (`torch.LongTensor` of shape `({0})`): - Indices of input sequence tokens in the vocabulary. - - Indices can be obtained using [`AutoProcenizer`]. See [`PreTrainedTokenizer.encode`] and - [`PreTrainedTokenizer.__call__`] for details. - - [What are input IDs?](../glossary#input-ids) - attention_mask (`torch.FloatTensor` of shape `({0})`, *optional*): - Mask to avoid performing attention on padding token indices. Mask values selected in `[0, 1]`: - - - 1 for tokens that are **not masked**, - - 0 for tokens that are **masked**. - - [What are attention masks?](../glossary#attention-mask) - token_type_ids (`torch.LongTensor` of shape `({0})`, *optional*): - Segment token indices to indicate first and second portions of the inputs. Indices are selected in `[0, - 1]`: - - - 0 corresponds to a *sentence A* token, - - 1 corresponds to a *sentence B* token. - - [What are token type IDs?](../glossary#token-type-ids) - position_ids (`torch.LongTensor` of shape `({0})`, *optional*): - Indices of positions of each input sequence tokens in the position embeddings. Selected in the range `[0, - config.n_positions - 1]`. - - [What are position IDs?](../glossary#position-ids) - head_mask (`torch.FloatTensor` of shape `(num_attention_heads,)` or `(n_layer, num_attention_heads)`, *optional*): - Mask to nullify selected heads of the self-attention modules. Mask values selected in `[0, 1]`: - - - 1 indicates the head is **not masked**, - - 0 indicates the head is **masked**. - - inputs_embeds (`torch.FloatTensor` of shape `({0}, hidden_dim)`, *optional*): - Optionally, instead of passing `input_ids` you can choose to directly pass an embedded representation. This - is useful if you want more control over how to convert *input_ids* indices into associated vectors than the - model's internal embedding lookup matrix. - output_attentions (`bool`, *optional*): - Whether or not to return the attentions tensors of all attention layers. See `attentions` under returned - tensors for more detail. - output_hidden_states (`bool`, *optional*): - Whether or not to return the hidden states of all layers. See `hidden_states` under returned tensors for - more detail. - return_dict (`bool`, *optional*): - Whether or not to return a [`~utils.ModelOutput`] instead of a plain tuple. -""" - - -@add_start_docstrings( - "The bare Moss Model transformer outputting raw hidden-states without any specific head on top.", - MOSS_START_DOCSTRING, -) -class MossModel(MossPreTrainedModel): - def __init__(self, config): - super().__init__(config) - - self.embed_dim = config.n_embd - self.vocab_size = config.vocab_size - self.wte = nn.Embedding(config.vocab_size, self.embed_dim) - self.drop = nn.Dropout(config.embd_pdrop) - self.h = nn.ModuleList([MossBlock(config) for _ in range(config.n_layer)]) - self.ln_f = nn.LayerNorm(self.embed_dim, eps=config.layer_norm_epsilon) - self.rotary_dim = min(config.rotary_dim, config.n_ctx // config.num_attention_heads) - - self.gradient_checkpointing = False - - # Initialize weights and apply final processing - self.post_init() - - def get_input_embeddings(self): - return self.wte - - def set_input_embeddings(self, new_embeddings): - self.wte = new_embeddings - - @add_start_docstrings_to_model_forward(MOSS_INPUTS_DOCSTRING.format("batch_size, sequence_length")) - @add_code_sample_docstrings( - checkpoint=_CHECKPOINT_FOR_DOC, - output_type=BaseModelOutputWithPast, - config_class=_CONFIG_FOR_DOC, - ) - def forward( - self, - input_ids: Optional[torch.LongTensor] = None, - past_key_values: Optional[Tuple[Tuple[torch.Tensor]]] = None, - attention_mask: Optional[torch.FloatTensor] = None, - token_type_ids: Optional[torch.LongTensor] = None, - position_ids: Optional[torch.LongTensor] = None, - head_mask: Optional[torch.FloatTensor] = None, - inputs_embeds: Optional[torch.FloatTensor] = None, - use_cache: Optional[bool] = None, - output_attentions: Optional[bool] = None, - output_hidden_states: Optional[bool] = None, - return_dict: Optional[bool] = None, - ) -> Union[Tuple, BaseModelOutputWithPast]: - output_attentions = output_attentions if output_attentions is not None else self.config.output_attentions - output_hidden_states = ( - output_hidden_states if output_hidden_states is not None else self.config.output_hidden_states - ) - use_cache = use_cache if use_cache is not None else self.config.use_cache - return_dict = return_dict if return_dict is not None else self.config.use_return_dict - - if input_ids is not None and inputs_embeds is not None: - raise ValueError("You cannot specify both input_ids and inputs_embeds at the same time") - elif input_ids is not None: - input_shape = input_ids.size() - input_ids = input_ids.view(-1, input_shape[-1]) - batch_size = input_ids.shape[0] - elif inputs_embeds is not None: - input_shape = inputs_embeds.size()[:-1] - batch_size = inputs_embeds.shape[0] - else: - raise ValueError("You have to specify either input_ids or inputs_embeds") - - device = input_ids.device if input_ids is not None else inputs_embeds.device - - if token_type_ids is not None: - token_type_ids = token_type_ids.view(-1, input_shape[-1]) - - if position_ids is not None: - position_ids = position_ids.view(-1, input_shape[-1]).long() - - if past_key_values is None: - past_length = 0 - past_key_values = tuple([None] * len(self.h)) - else: - past_length = past_key_values[0][0].size(-2) - - if position_ids is None: - position_ids = torch.arange(past_length, input_shape[-1] + past_length, dtype=torch.long, device=device) - position_ids = position_ids.unsqueeze(0).view(-1, input_shape[-1]) - - # Attention mask. - if attention_mask is not None: - if batch_size <= 0: - raise ValueError("batch_size has to be defined and > 0") - attention_mask = attention_mask.view(batch_size, -1) - # We create a 3D attention mask from a 2D tensor mask. - # Sizes are [batch_size, 1, 1, to_seq_length] - # So we can broadcast to [batch_size, num_heads, from_seq_length, to_seq_length] - # this attention mask is more simple than the triangular masking of causal attention - # used in OpenAI GPT, we just need to prepare the broadcast dimension here. - attention_mask = attention_mask[:, None, None, :] - - # Since attention_mask is 1.0 for positions we want to attend and 0.0 for - # masked positions, this operation will create a tensor which is 0.0 for - # positions we want to attend and the dtype's smallest value for masked positions. - # Since we are adding it to the raw scores before the softmax, this is - # effectively the same as removing these entirely. - attention_mask = attention_mask.to(dtype=self.dtype) # fp16 compatibility - attention_mask = (1.0 - attention_mask) * torch.finfo(self.dtype).min - - # Prepare head mask if needed - # 1.0 in head_mask indicate we keep the head - # attention_probs has shape bsz x num_attention_heads x N x N - # head_mask has shape n_layer x batch x num_attention_heads x N x N - head_mask = self.get_head_mask(head_mask, self.config.n_layer) - - if inputs_embeds is None: - inputs_embeds = self.wte(input_ids) - - hidden_states = inputs_embeds - - if token_type_ids is not None: - token_type_embeds = self.wte(token_type_ids) - hidden_states = hidden_states + token_type_embeds - - hidden_states = self.drop(hidden_states) - - output_shape = input_shape + (hidden_states.size(-1),) - - if self.gradient_checkpointing and self.training: - if use_cache: - logger.warning_once( - "`use_cache=True` is incompatible with `config.gradient_checkpointing=True`. Setting " - "`use_cache=False`..." - ) - use_cache = False - - presents = () if use_cache else None - all_self_attentions = () if output_attentions else None - all_hidden_states = () if output_hidden_states else None - for i, (block, layer_past) in enumerate(zip(self.h, past_key_values)): - if output_hidden_states: - all_hidden_states = all_hidden_states + (hidden_states,) - - if self.gradient_checkpointing and self.training: - - def create_custom_forward(module): - def custom_forward(*inputs): - # None for past_key_value - return module(*inputs, use_cache, output_attentions) - - return custom_forward - - outputs = torch.utils.checkpoint.checkpoint( - create_custom_forward(block), - hidden_states, - None, - attention_mask, - position_ids, - head_mask[i], - ) - else: - outputs = block( - hidden_states=hidden_states, - layer_past=layer_past, - attention_mask=attention_mask, - position_ids=position_ids, - head_mask=head_mask[i], - use_cache=use_cache, - output_attentions=output_attentions, - ) - - hidden_states = outputs[0] - if use_cache is True: - presents = presents + (outputs[1],) - - if output_attentions: - all_self_attentions = all_self_attentions + (outputs[2 if use_cache else 1],) - - hidden_states = self.ln_f(hidden_states) - - hidden_states = hidden_states.view(output_shape) - # Add last hidden state - if output_hidden_states: - all_hidden_states = all_hidden_states + (hidden_states,) - - if not return_dict: - return tuple(v for v in [hidden_states, presents, all_hidden_states, all_self_attentions] if v is not None) - - return BaseModelOutputWithPast( - last_hidden_state=hidden_states, - past_key_values=presents, - hidden_states=all_hidden_states, - attentions=all_self_attentions, - ) - - -@add_start_docstrings( - """ - The Moss Model transformer with a language modeling head on top. - """, - MOSS_START_DOCSTRING, -) -class MossForCausalLM(MossPreTrainedModel): - _keys_to_ignore_on_load_missing = [r"h\.\d+\.attn\.causal_mask"] - - def __init__(self, config): - super().__init__(config) - if not hasattr(config, 'wbits'): - config.wbits = 32 - config.groupsize = 128 - - if config.wbits not in [4, 8, 32]: - logger.warning(f'Specify `wbits` with 4, 8 or 32 to load the model. ') - if config.wbits in [4, 8]: - def noop(*args, **kwargs): - pass - torch.nn.init.kaiming_uniform_ = noop - torch.nn.init.uniform_ = noop - torch.nn.init.normal_ = noop - - torch.set_default_dtype(torch.half) - transformers.modeling_utils._init_weights = False - torch.set_default_dtype(torch.half) - self.transformer = MossModel(config) - self.lm_head = nn.Linear(config.n_embd, config.vocab_size) - if config.wbits in [4, 8]: - torch.set_default_dtype(torch.float) - transformers.modeling_utils._init_weights = True - self.quantize(config.wbits, config.groupsize) - # Initialize weights and apply final processing - self.post_init() - - def get_output_embeddings(self): - return self.lm_head - - def set_output_embeddings(self, new_embeddings): - self.lm_head = new_embeddings - - def prepare_inputs_for_generation(self, input_ids, past_key_values=None, **kwargs): - token_type_ids = kwargs.get("token_type_ids", None) - # only last token for inputs_ids if past is defined in kwargs - if past_key_values: - input_ids = input_ids[:, -1].unsqueeze(-1) - if token_type_ids is not None: - token_type_ids = token_type_ids[:, -1].unsqueeze(-1) - - attention_mask = kwargs.get("attention_mask", None) - position_ids = kwargs.get("position_ids", None) - - if attention_mask is not None and position_ids is None: - # create position_ids on the fly for batch generation - position_ids = attention_mask.long().cumsum(-1) - 1 - position_ids.masked_fill_(attention_mask == 0, 1) - if past_key_values: - position_ids = position_ids[:, -1].unsqueeze(-1) - - return { - "input_ids": input_ids, - "past_key_values": past_key_values, - "use_cache": kwargs.get("use_cache"), - "position_ids": position_ids, - "attention_mask": attention_mask, - "token_type_ids": token_type_ids, - } - - @add_start_docstrings_to_model_forward(MOSS_INPUTS_DOCSTRING.format("batch_size, sequence_length")) - @add_code_sample_docstrings( - checkpoint=_CHECKPOINT_FOR_DOC, - output_type=CausalLMOutputWithPast, - config_class=_CONFIG_FOR_DOC, - ) - def forward( - self, - input_ids: Optional[torch.LongTensor] = None, - past_key_values: Optional[Tuple[Tuple[torch.Tensor]]] = None, - attention_mask: Optional[torch.FloatTensor] = None, - token_type_ids: Optional[torch.LongTensor] = None, - position_ids: Optional[torch.LongTensor] = None, - head_mask: Optional[torch.FloatTensor] = None, - inputs_embeds: Optional[torch.FloatTensor] = None, - labels: Optional[torch.LongTensor] = None, - use_cache: Optional[bool] = None, - output_attentions: Optional[bool] = None, - output_hidden_states: Optional[bool] = None, - return_dict: Optional[bool] = None, - ) -> Union[Tuple, CausalLMOutputWithPast]: - r""" - labels (`torch.LongTensor` of shape `(batch_size, sequence_length)`, *optional*): - Labels for language modeling. Note that the labels **are shifted** inside the model, i.e. you can set - `labels = input_ids` Indices are selected in `[-100, 0, ..., config.vocab_size]` All labels set to `-100` - are ignored (masked), the loss is only computed for labels in `[0, ..., config.vocab_size]` - """ - return_dict = return_dict if return_dict is not None else self.config.use_return_dict - - transformer_outputs = self.transformer( - input_ids, - past_key_values=past_key_values, - attention_mask=attention_mask, - token_type_ids=token_type_ids, - position_ids=position_ids, - head_mask=head_mask, - inputs_embeds=inputs_embeds, - use_cache=use_cache, - output_attentions=output_attentions, - output_hidden_states=output_hidden_states, - return_dict=return_dict, - ) - hidden_states = transformer_outputs[0] - - # make sure sampling in fp16 works correctly and - # compute loss in fp32 to match with mesh-tf version - # https://github.com/EleutherAI/gpt-neo/blob/89ce74164da2fb16179106f54e2269b5da8db333/models/gpt2/gpt2.py#L179 - lm_logits = self.lm_head(hidden_states).to(torch.float32) - - loss = None - if labels is not None: - # Shift so that tokens < n predict n - shift_logits = lm_logits[..., :-1, :].contiguous() - shift_labels = labels[..., 1:].contiguous() - # Flatten the tokens - loss_fct = CrossEntropyLoss() - loss = loss_fct(shift_logits.view(-1, shift_logits.size(-1)), shift_labels.view(-1)) - - loss = loss.to(hidden_states.dtype) - - if not return_dict: - output = (lm_logits,) + transformer_outputs[1:] - return ((loss,) + output) if loss is not None else output - - return CausalLMOutputWithPast( - loss=loss, - logits=lm_logits, - past_key_values=transformer_outputs.past_key_values, - hidden_states=transformer_outputs.hidden_states, - attentions=transformer_outputs.attentions, - ) - - @staticmethod - def _reorder_cache( - past_key_values: Tuple[Tuple[torch.Tensor]], beam_idx: torch.Tensor - ) -> Tuple[Tuple[torch.Tensor]]: - """ - This function is used to re-order the `past_key_values` cache if [`~PretrainedModel.beam_search`] or - [`~PretrainedModel.beam_sample`] is called. This is required to match `past_key_values` with the correct - beam_idx at every generation step. - """ - return tuple( - tuple(past_state.index_select(0, beam_idx.to(past_state.device)) for past_state in layer_past) - for layer_past in past_key_values - ) - - def quantize(self, wbits, groupsize): - from .quantization import quantize_with_gptq - return quantize_with_gptq(self, wbits, groupsize) - -""" PyTorch Moss model.""" - -from typing import Optional, Tuple, Union - -import torch -import torch.utils.checkpoint -from torch import nn -from torch.nn import CrossEntropyLoss -import transformers -from transformers.activations import ACT2FN -from transformers.modeling_utils import PreTrainedModel -from transformers.modeling_outputs import BaseModelOutputWithPast, CausalLMOutputWithPast -from transformers.utils import ( - add_code_sample_docstrings, - add_start_docstrings, - add_start_docstrings_to_model_forward, - logging -) - -from .configuration_moss import MossConfig - -logger = logging.get_logger(__name__) - -_CHECKPOINT_FOR_DOC = "fnlp/moss-moon-003-base" -_CONFIG_FOR_DOC = "MossConfig" - - -MOSS_PRETRAINED_MODEL_ARCHIVE_LIST = [ - "fnlp/moss-moon-003-base", - "fnlp/moss-moon-003-sft", - "fnlp/moss-moon-003-sft-plugin", - "fnlp/moss-moon-003-sft-int4", - "fnlp/moss-moon-003-sft-plugin-int4", - "fnlp/moss-moon-003-sft-int8", - "fnlp/moss-moon-003-sft-plugin-int8", -] - - -# Copied from transformers.models.gptj.modeling_gptj.create_sinusoidal_positions -def create_sinusoidal_positions(num_pos: int, dim: int) -> torch.Tensor: - inv_freq = 1.0 / (10000 ** (torch.arange(0, dim, 2) / dim)) - sinusoid_inp = torch.einsum("i , j -> i j", torch.arange(num_pos, dtype=torch.float), inv_freq).float() - return torch.cat((torch.sin(sinusoid_inp), torch.cos(sinusoid_inp)), dim=1) - - -# Copied from transformers.models.gptj.modeling_gptj.rotate_every_two -def rotate_every_two(x: torch.Tensor) -> torch.Tensor: - x1 = x[:, :, :, ::2] - x2 = x[:, :, :, 1::2] - x = torch.stack((-x2, x1), dim=-1) - return x.flatten(-2) # in einsum notation: rearrange(x, '... d j -> ... (d j)') - - -# Copied from transformers.models.gptj.modeling_gptj.apply_rotary_pos_emb -def apply_rotary_pos_emb(tensor: torch.Tensor, sin: torch.Tensor, cos: torch.Tensor) -> torch.Tensor: - sin = torch.repeat_interleave(sin[:, :, None, :], 2, 3) - cos = torch.repeat_interleave(cos[:, :, None, :], 2, 3) - return (tensor * cos) + (rotate_every_two(tensor) * sin) - - -class MossAttention(nn.Module): - def __init__(self, config): - super().__init__() - - max_positions = config.max_position_embeddings - self.register_buffer( - "causal_mask", - torch.tril(torch.ones((max_positions, max_positions), dtype=torch.bool)).view( - 1, 1, max_positions, max_positions - ), - ) - - self.attn_dropout = nn.Dropout(config.attn_pdrop) - self.resid_dropout = nn.Dropout(config.resid_pdrop) - - self.embed_dim = config.hidden_size - self.num_attention_heads = config.num_attention_heads - self.head_dim = self.embed_dim // self.num_attention_heads - if self.head_dim * self.num_attention_heads != self.embed_dim: - raise ValueError( - f"embed_dim must be divisible by num_attention_heads (got `embed_dim`: {self.embed_dim} and" - f" `num_attention_heads`: {self.num_attention_heads})." - ) - self.scale_attn = torch.sqrt(torch.tensor(self.head_dim, dtype=torch.float32)).to(torch.get_default_dtype()) - self.qkv_proj = nn.Linear(self.embed_dim, self.embed_dim * 3, bias=False) - - self.out_proj = nn.Linear(self.embed_dim, self.embed_dim, bias=False) - self.rotary_dim = config.rotary_dim - pos_embd_dim = self.rotary_dim or self.embed_dim - self.embed_positions = create_sinusoidal_positions(max_positions, pos_embd_dim) - - def _split_heads(self, x, n_head, dim_head, mp_num): - reshaped = x.reshape(x.shape[:-1] + (n_head // mp_num, dim_head)) - reshaped = reshaped.reshape(x.shape[:-2] + (-1,) + reshaped.shape[-1:]) - return reshaped - - def _merge_heads(self, tensor, num_attention_heads, attn_head_size): - """ - Merges attn_head_size dim and num_attn_heads dim into n_ctx - """ - if len(tensor.shape) == 5: - tensor = tensor.permute(0, 1, 3, 2, 4).contiguous() - elif len(tensor.shape) == 4: - tensor = tensor.permute(0, 2, 1, 3).contiguous() - else: - raise ValueError(f"Input tensor rank should be one of [4, 5], but is: {len(tensor.shape)}") - new_shape = tensor.size()[:-2] + (num_attention_heads * attn_head_size,) - return tensor.view(new_shape) - - def _attn( - self, - query, - key, - value, - attention_mask=None, - head_mask=None, - ): - # compute causal mask from causal mask buffer - query_length, key_length = query.size(-2), key.size(-2) - causal_mask = self.causal_mask[:, :, key_length - query_length : key_length, :key_length] - - # Keep the attention weights computation in fp32 to avoid overflow issues - query = query.to(torch.float32) - key = key.to(torch.float32) - - attn_weights = torch.matmul(query, key.transpose(-1, -2)) - - attn_weights = attn_weights / self.scale_attn - mask_value = torch.finfo(attn_weights.dtype).min - # Need to be a tensor, otherwise we get error: `RuntimeError: expected scalar type float but found double`. - # Need to be on the same device, otherwise `RuntimeError: ..., x and y to be on the same device` - mask_value = torch.tensor(mask_value, dtype=attn_weights.dtype).to(attn_weights.device) - attn_weights = torch.where(causal_mask, attn_weights, mask_value) - - if attention_mask is not None: - # Apply the attention mask - attn_weights = attn_weights + attention_mask - - attn_weights = nn.Softmax(dim=-1)(attn_weights) - attn_weights = attn_weights.to(value.dtype) - attn_weights = self.attn_dropout(attn_weights) - - # Mask heads if we want to - if head_mask is not None: - attn_weights = attn_weights * head_mask - - attn_output = torch.matmul(attn_weights, value) - - return attn_output, attn_weights - - def forward( - self, - hidden_states: Optional[torch.FloatTensor], - layer_past: Optional[Tuple[torch.Tensor]] = None, - attention_mask: Optional[torch.FloatTensor] = None, - position_ids: Optional[torch.LongTensor] = None, - head_mask: Optional[torch.FloatTensor] = None, - use_cache: Optional[bool] = False, - output_attentions: Optional[bool] = False, - ) -> Union[ - Tuple[torch.Tensor, Tuple[torch.Tensor]], - Optional[Tuple[torch.Tensor, Tuple[torch.Tensor], Tuple[torch.Tensor, ...]]], - ]: - qkv = self.qkv_proj(hidden_states) - # TODO(enijkamp): factor out number of logical TPU-v4 cores or make forward pass agnostic - mp_num = 4 - qkv_split = qkv.reshape(qkv.shape[:-1] + (mp_num, -1)) - - local_dim = self.head_dim * self.num_attention_heads // mp_num - query, value, key = torch.split(qkv_split, local_dim, dim=-1) - query = self._split_heads(query, self.num_attention_heads, self.head_dim, mp_num=mp_num) - key = self._split_heads(key, self.num_attention_heads, self.head_dim, mp_num=mp_num) - - value = self._split_heads(value, self.num_attention_heads, self.head_dim, mp_num=mp_num) - value = value.permute(0, 2, 1, 3) - - embed_positions = self.embed_positions - if embed_positions.device != position_ids.device: - embed_positions = embed_positions.to(position_ids.device) - self.embed_positions = embed_positions - - sincos = embed_positions[position_ids] - sin, cos = torch.split(sincos, sincos.shape[-1] // 2, dim=-1) - - if self.rotary_dim is not None: - k_rot = key[:, :, :, : self.rotary_dim] - k_pass = key[:, :, :, self.rotary_dim :] - - q_rot = query[:, :, :, : self.rotary_dim] - q_pass = query[:, :, :, self.rotary_dim :] - - k_rot = apply_rotary_pos_emb(k_rot, sin, cos) - q_rot = apply_rotary_pos_emb(q_rot, sin, cos) - - key = torch.cat([k_rot, k_pass], dim=-1) - query = torch.cat([q_rot, q_pass], dim=-1) - else: - key = apply_rotary_pos_emb(key, sin, cos) - query = apply_rotary_pos_emb(query, sin, cos) - - key = key.permute(0, 2, 1, 3) - query = query.permute(0, 2, 1, 3) - - if layer_past is not None: - past_key = layer_past[0] - past_value = layer_past[1] - key = torch.cat((past_key, key), dim=-2) - value = torch.cat((past_value, value), dim=-2) - - if use_cache is True: - present = (key, value) - else: - present = None - - # compute self-attention: V x Softmax(QK^T) - attn_output, attn_weights = self._attn(query, key, value, attention_mask, head_mask) - - attn_output = self._merge_heads(attn_output, self.num_attention_heads, self.head_dim) - attn_output = self.out_proj(attn_output) - attn_output = self.resid_dropout(attn_output) - - outputs = (attn_output, present) - if output_attentions: - outputs += (attn_weights,) - - return outputs # a, present, (attentions) - - -# Copied from transformers.models.gptj.modeling_gptj.GPTJMLP with GPTJ->Moss -class MossMLP(nn.Module): - def __init__(self, intermediate_size, config): # in MLP: intermediate_size= 4 * embed_dim - super().__init__() - embed_dim = config.n_embd - - self.fc_in = nn.Linear(embed_dim, intermediate_size) - self.fc_out = nn.Linear(intermediate_size, embed_dim) - - self.act = ACT2FN[config.activation_function] - self.dropout = nn.Dropout(config.resid_pdrop) - - def forward(self, hidden_states: Optional[torch.FloatTensor]) -> torch.FloatTensor: - hidden_states = self.fc_in(hidden_states) - hidden_states = self.act(hidden_states) - hidden_states = self.fc_out(hidden_states) - hidden_states = self.dropout(hidden_states) - return hidden_states - - -# Copied from transformers.models.gptj.modeling_gptj.GPTJBlock with GPTJ->Moss -class MossBlock(nn.Module): - def __init__(self, config): - super().__init__() - inner_dim = config.n_inner if config.n_inner is not None else 4 * config.n_embd - self.ln_1 = nn.LayerNorm(config.n_embd, eps=config.layer_norm_epsilon) - self.attn = MossAttention(config) - self.mlp = MossMLP(inner_dim, config) - - def forward( - self, - hidden_states: Optional[torch.FloatTensor], - layer_past: Optional[Tuple[torch.Tensor]] = None, - attention_mask: Optional[torch.FloatTensor] = None, - position_ids: Optional[torch.LongTensor] = None, - head_mask: Optional[torch.FloatTensor] = None, - use_cache: Optional[bool] = False, - output_attentions: Optional[bool] = False, - ) -> Union[Tuple[torch.Tensor], Optional[Tuple[torch.Tensor, Tuple[torch.FloatTensor, ...]]]]: - residual = hidden_states - hidden_states = self.ln_1(hidden_states) - attn_outputs = self.attn( - hidden_states=hidden_states, - layer_past=layer_past, - attention_mask=attention_mask, - position_ids=position_ids, - head_mask=head_mask, - use_cache=use_cache, - output_attentions=output_attentions, - ) - attn_output = attn_outputs[0] # output_attn: a, present, (attentions) - outputs = attn_outputs[1:] - - feed_forward_hidden_states = self.mlp(hidden_states) - hidden_states = attn_output + feed_forward_hidden_states + residual - - if use_cache: - outputs = (hidden_states,) + outputs - else: - outputs = (hidden_states,) + outputs[1:] - - return outputs # hidden_states, present, (attentions) - - -class MossPreTrainedModel(PreTrainedModel): - """ - An abstract class to handle weights initialization and a simple interface for downloading and loading pretrained - models. - """ - - config_class = MossConfig - base_model_prefix = "transformer" - supports_gradient_checkpointing = True - _no_split_modules = ["MossBlock"] - - def __init__(self, *inputs, **kwargs): - super().__init__(*inputs, **kwargs) - - def _init_weights(self, module): - """Initialize the weights.""" - if isinstance(module, (nn.Linear,)): - # Slightly different from Mesh Transformer JAX which uses truncated_normal for initialization - # cf https://github.com/pytorch/pytorch/pull/5617 - module.weight.data.normal_(mean=0.0, std=self.config.initializer_range) - if module.bias is not None: - module.bias.data.zero_() - elif isinstance(module, nn.Embedding): - module.weight.data.normal_(mean=0.0, std=self.config.initializer_range) - if module.padding_idx is not None: - module.weight.data[module.padding_idx].zero_() - elif isinstance(module, nn.LayerNorm): - module.bias.data.zero_() - module.weight.data.fill_(1.0) - - def _set_gradient_checkpointing(self, module, value=False): - if isinstance(module, MossModel): - module.gradient_checkpointing = value - - -MOSS_START_DOCSTRING = r""" - This model is a PyTorch [torch.nn.Module](https://pytorch.org/docs/stable/nn.html#torch.nn.Module) sub-class. Use - it as a regular PyTorch Module and refer to the PyTorch documentation for all matter related to general usage and - behavior. - - Parameters: - config ([`MossConfig`]): Model configuration class with all the parameters of the model. - Initializing with a config file does not load the weights associated with the model, only the - configuration. Check out the [`~PreTrainedModel.from_pretrained`] method to load the model weights. -""" - -MOSS_INPUTS_DOCSTRING = r""" - Args: - input_ids (`torch.LongTensor` of shape `({0})`): - Indices of input sequence tokens in the vocabulary. - - Indices can be obtained using [`AutoProcenizer`]. See [`PreTrainedTokenizer.encode`] and - [`PreTrainedTokenizer.__call__`] for details. - - [What are input IDs?](../glossary#input-ids) - attention_mask (`torch.FloatTensor` of shape `({0})`, *optional*): - Mask to avoid performing attention on padding token indices. Mask values selected in `[0, 1]`: - - - 1 for tokens that are **not masked**, - - 0 for tokens that are **masked**. - - [What are attention masks?](../glossary#attention-mask) - token_type_ids (`torch.LongTensor` of shape `({0})`, *optional*): - Segment token indices to indicate first and second portions of the inputs. Indices are selected in `[0, - 1]`: - - - 0 corresponds to a *sentence A* token, - - 1 corresponds to a *sentence B* token. - - [What are token type IDs?](../glossary#token-type-ids) - position_ids (`torch.LongTensor` of shape `({0})`, *optional*): - Indices of positions of each input sequence tokens in the position embeddings. Selected in the range `[0, - config.n_positions - 1]`. - - [What are position IDs?](../glossary#position-ids) - head_mask (`torch.FloatTensor` of shape `(num_attention_heads,)` or `(n_layer, num_attention_heads)`, *optional*): - Mask to nullify selected heads of the self-attention modules. Mask values selected in `[0, 1]`: - - - 1 indicates the head is **not masked**, - - 0 indicates the head is **masked**. - - inputs_embeds (`torch.FloatTensor` of shape `({0}, hidden_dim)`, *optional*): - Optionally, instead of passing `input_ids` you can choose to directly pass an embedded representation. This - is useful if you want more control over how to convert *input_ids* indices into associated vectors than the - model's internal embedding lookup matrix. - output_attentions (`bool`, *optional*): - Whether or not to return the attentions tensors of all attention layers. See `attentions` under returned - tensors for more detail. - output_hidden_states (`bool`, *optional*): - Whether or not to return the hidden states of all layers. See `hidden_states` under returned tensors for - more detail. - return_dict (`bool`, *optional*): - Whether or not to return a [`~utils.ModelOutput`] instead of a plain tuple. -""" - - -@add_start_docstrings( - "The bare Moss Model transformer outputting raw hidden-states without any specific head on top.", - MOSS_START_DOCSTRING, -) -class MossModel(MossPreTrainedModel): - def __init__(self, config): - super().__init__(config) - - self.embed_dim = config.n_embd - self.vocab_size = config.vocab_size - self.wte = nn.Embedding(config.vocab_size, self.embed_dim) - self.drop = nn.Dropout(config.embd_pdrop) - self.h = nn.ModuleList([MossBlock(config) for _ in range(config.n_layer)]) - self.ln_f = nn.LayerNorm(self.embed_dim, eps=config.layer_norm_epsilon) - self.rotary_dim = min(config.rotary_dim, config.n_ctx // config.num_attention_heads) - - self.gradient_checkpointing = False - - # Initialize weights and apply final processing - self.post_init() - - def get_input_embeddings(self): - return self.wte - - def set_input_embeddings(self, new_embeddings): - self.wte = new_embeddings - - @add_start_docstrings_to_model_forward(MOSS_INPUTS_DOCSTRING.format("batch_size, sequence_length")) - @add_code_sample_docstrings( - checkpoint=_CHECKPOINT_FOR_DOC, - output_type=BaseModelOutputWithPast, - config_class=_CONFIG_FOR_DOC, - ) - def forward( - self, - input_ids: Optional[torch.LongTensor] = None, - past_key_values: Optional[Tuple[Tuple[torch.Tensor]]] = None, - attention_mask: Optional[torch.FloatTensor] = None, - token_type_ids: Optional[torch.LongTensor] = None, - position_ids: Optional[torch.LongTensor] = None, - head_mask: Optional[torch.FloatTensor] = None, - inputs_embeds: Optional[torch.FloatTensor] = None, - use_cache: Optional[bool] = None, - output_attentions: Optional[bool] = None, - output_hidden_states: Optional[bool] = None, - return_dict: Optional[bool] = None, - ) -> Union[Tuple, BaseModelOutputWithPast]: - output_attentions = output_attentions if output_attentions is not None else self.config.output_attentions - output_hidden_states = ( - output_hidden_states if output_hidden_states is not None else self.config.output_hidden_states - ) - use_cache = use_cache if use_cache is not None else self.config.use_cache - return_dict = return_dict if return_dict is not None else self.config.use_return_dict - - if input_ids is not None and inputs_embeds is not None: - raise ValueError("You cannot specify both input_ids and inputs_embeds at the same time") - elif input_ids is not None: - input_shape = input_ids.size() - input_ids = input_ids.view(-1, input_shape[-1]) - batch_size = input_ids.shape[0] - elif inputs_embeds is not None: - input_shape = inputs_embeds.size()[:-1] - batch_size = inputs_embeds.shape[0] - else: - raise ValueError("You have to specify either input_ids or inputs_embeds") - - device = input_ids.device if input_ids is not None else inputs_embeds.device - - if token_type_ids is not None: - token_type_ids = token_type_ids.view(-1, input_shape[-1]) - - if position_ids is not None: - position_ids = position_ids.view(-1, input_shape[-1]).long() - - if past_key_values is None: - past_length = 0 - past_key_values = tuple([None] * len(self.h)) - else: - past_length = past_key_values[0][0].size(-2) - - if position_ids is None: - position_ids = torch.arange(past_length, input_shape[-1] + past_length, dtype=torch.long, device=device) - position_ids = position_ids.unsqueeze(0).view(-1, input_shape[-1]) - - # Attention mask. - if attention_mask is not None: - if batch_size <= 0: - raise ValueError("batch_size has to be defined and > 0") - attention_mask = attention_mask.view(batch_size, -1) - # We create a 3D attention mask from a 2D tensor mask. - # Sizes are [batch_size, 1, 1, to_seq_length] - # So we can broadcast to [batch_size, num_heads, from_seq_length, to_seq_length] - # this attention mask is more simple than the triangular masking of causal attention - # used in OpenAI GPT, we just need to prepare the broadcast dimension here. - attention_mask = attention_mask[:, None, None, :] - - # Since attention_mask is 1.0 for positions we want to attend and 0.0 for - # masked positions, this operation will create a tensor which is 0.0 for - # positions we want to attend and the dtype's smallest value for masked positions. - # Since we are adding it to the raw scores before the softmax, this is - # effectively the same as removing these entirely. - attention_mask = attention_mask.to(dtype=self.dtype) # fp16 compatibility - attention_mask = (1.0 - attention_mask) * torch.finfo(self.dtype).min - - # Prepare head mask if needed - # 1.0 in head_mask indicate we keep the head - # attention_probs has shape bsz x num_attention_heads x N x N - # head_mask has shape n_layer x batch x num_attention_heads x N x N - head_mask = self.get_head_mask(head_mask, self.config.n_layer) - - if inputs_embeds is None: - inputs_embeds = self.wte(input_ids) - - hidden_states = inputs_embeds - - if token_type_ids is not None: - token_type_embeds = self.wte(token_type_ids) - hidden_states = hidden_states + token_type_embeds - - hidden_states = self.drop(hidden_states) - - output_shape = input_shape + (hidden_states.size(-1),) - - if self.gradient_checkpointing and self.training: - if use_cache: - logger.warning_once( - "`use_cache=True` is incompatible with `config.gradient_checkpointing=True`. Setting " - "`use_cache=False`..." - ) - use_cache = False - - presents = () if use_cache else None - all_self_attentions = () if output_attentions else None - all_hidden_states = () if output_hidden_states else None - for i, (block, layer_past) in enumerate(zip(self.h, past_key_values)): - if output_hidden_states: - all_hidden_states = all_hidden_states + (hidden_states,) - - if self.gradient_checkpointing and self.training: - - def create_custom_forward(module): - def custom_forward(*inputs): - # None for past_key_value - return module(*inputs, use_cache, output_attentions) - - return custom_forward - - outputs = torch.utils.checkpoint.checkpoint( - create_custom_forward(block), - hidden_states, - None, - attention_mask, - position_ids, - head_mask[i], - ) - else: - outputs = block( - hidden_states=hidden_states, - layer_past=layer_past, - attention_mask=attention_mask, - position_ids=position_ids, - head_mask=head_mask[i], - use_cache=use_cache, - output_attentions=output_attentions, - ) - - hidden_states = outputs[0] - if use_cache is True: - presents = presents + (outputs[1],) - - if output_attentions: - all_self_attentions = all_self_attentions + (outputs[2 if use_cache else 1],) - - hidden_states = self.ln_f(hidden_states) - - hidden_states = hidden_states.view(output_shape) - # Add last hidden state - if output_hidden_states: - all_hidden_states = all_hidden_states + (hidden_states,) - - if not return_dict: - return tuple(v for v in [hidden_states, presents, all_hidden_states, all_self_attentions] if v is not None) - - return BaseModelOutputWithPast( - last_hidden_state=hidden_states, - past_key_values=presents, - hidden_states=all_hidden_states, - attentions=all_self_attentions, - ) - - -@add_start_docstrings( - """ - The Moss Model transformer with a language modeling head on top. - """, - MOSS_START_DOCSTRING, -) -class MossForCausalLM(MossPreTrainedModel): - _keys_to_ignore_on_load_missing = [r"h\.\d+\.attn\.causal_mask"] - - def __init__(self, config): - super().__init__(config) - if not hasattr(config, 'wbits'): - config.wbits = 32 - config.groupsize = 128 - - if config.wbits not in [4, 8, 32]: - logger.warning(f'Specify `wbits` with 4, 8 or 32 to load the model. ') - if config.wbits in [4, 8]: - def noop(*args, **kwargs): - pass - torch.nn.init.kaiming_uniform_ = noop - torch.nn.init.uniform_ = noop - torch.nn.init.normal_ = noop - - torch.set_default_dtype(torch.half) - transformers.modeling_utils._init_weights = False - torch.set_default_dtype(torch.half) - self.transformer = MossModel(config) - self.lm_head = nn.Linear(config.n_embd, config.vocab_size) - if config.wbits in [4, 8]: - torch.set_default_dtype(torch.float) - transformers.modeling_utils._init_weights = True - self.quantize(config.wbits, config.groupsize) - # Initialize weights and apply final processing - self.post_init() - - def get_output_embeddings(self): - return self.lm_head - - def set_output_embeddings(self, new_embeddings): - self.lm_head = new_embeddings - - def prepare_inputs_for_generation(self, input_ids, past_key_values=None, **kwargs): - token_type_ids = kwargs.get("token_type_ids", None) - # only last token for inputs_ids if past is defined in kwargs - if past_key_values: - input_ids = input_ids[:, -1].unsqueeze(-1) - if token_type_ids is not None: - token_type_ids = token_type_ids[:, -1].unsqueeze(-1) - - attention_mask = kwargs.get("attention_mask", None) - position_ids = kwargs.get("position_ids", None) - - if attention_mask is not None and position_ids is None: - # create position_ids on the fly for batch generation - position_ids = attention_mask.long().cumsum(-1) - 1 - position_ids.masked_fill_(attention_mask == 0, 1) - if past_key_values: - position_ids = position_ids[:, -1].unsqueeze(-1) - - return { - "input_ids": input_ids, - "past_key_values": past_key_values, - "use_cache": kwargs.get("use_cache"), - "position_ids": position_ids, - "attention_mask": attention_mask, - "token_type_ids": token_type_ids, - } - - @add_start_docstrings_to_model_forward(MOSS_INPUTS_DOCSTRING.format("batch_size, sequence_length")) - @add_code_sample_docstrings( - checkpoint=_CHECKPOINT_FOR_DOC, - output_type=CausalLMOutputWithPast, - config_class=_CONFIG_FOR_DOC, - ) - def forward( - self, - input_ids: Optional[torch.LongTensor] = None, - past_key_values: Optional[Tuple[Tuple[torch.Tensor]]] = None, - attention_mask: Optional[torch.FloatTensor] = None, - token_type_ids: Optional[torch.LongTensor] = None, - position_ids: Optional[torch.LongTensor] = None, - head_mask: Optional[torch.FloatTensor] = None, - inputs_embeds: Optional[torch.FloatTensor] = None, - labels: Optional[torch.LongTensor] = None, - use_cache: Optional[bool] = None, - output_attentions: Optional[bool] = None, - output_hidden_states: Optional[bool] = None, - return_dict: Optional[bool] = None, - ) -> Union[Tuple, CausalLMOutputWithPast]: - r""" - labels (`torch.LongTensor` of shape `(batch_size, sequence_length)`, *optional*): - Labels for language modeling. Note that the labels **are shifted** inside the model, i.e. you can set - `labels = input_ids` Indices are selected in `[-100, 0, ..., config.vocab_size]` All labels set to `-100` - are ignored (masked), the loss is only computed for labels in `[0, ..., config.vocab_size]` - """ - return_dict = return_dict if return_dict is not None else self.config.use_return_dict - - transformer_outputs = self.transformer( - input_ids, - past_key_values=past_key_values, - attention_mask=attention_mask, - token_type_ids=token_type_ids, - position_ids=position_ids, - head_mask=head_mask, - inputs_embeds=inputs_embeds, - use_cache=use_cache, - output_attentions=output_attentions, - output_hidden_states=output_hidden_states, - return_dict=return_dict, - ) - hidden_states = transformer_outputs[0] - - # make sure sampling in fp16 works correctly and - # compute loss in fp32 to match with mesh-tf version - # https://github.com/EleutherAI/gpt-neo/blob/89ce74164da2fb16179106f54e2269b5da8db333/models/gpt2/gpt2.py#L179 - lm_logits = self.lm_head(hidden_states).to(torch.float32) - - loss = None - if labels is not None: - # Shift so that tokens < n predict n - shift_logits = lm_logits[..., :-1, :].contiguous() - shift_labels = labels[..., 1:].contiguous() - # Flatten the tokens - loss_fct = CrossEntropyLoss() - loss = loss_fct(shift_logits.view(-1, shift_logits.size(-1)), shift_labels.view(-1)) - - loss = loss.to(hidden_states.dtype) - - if not return_dict: - output = (lm_logits,) + transformer_outputs[1:] - return ((loss,) + output) if loss is not None else output - - return CausalLMOutputWithPast( - loss=loss, - logits=lm_logits, - past_key_values=transformer_outputs.past_key_values, - hidden_states=transformer_outputs.hidden_states, - attentions=transformer_outputs.attentions, - ) - - @staticmethod - def _reorder_cache( - past_key_values: Tuple[Tuple[torch.Tensor]], beam_idx: torch.Tensor - ) -> Tuple[Tuple[torch.Tensor]]: - """ - This function is used to re-order the `past_key_values` cache if [`~PretrainedModel.beam_search`] or - [`~PretrainedModel.beam_sample`] is called. This is required to match `past_key_values` with the correct - beam_idx at every generation step. - """ - return tuple( - tuple(past_state.index_select(0, beam_idx.to(past_state.device)) for past_state in layer_past) - for layer_past in past_key_values - ) - - def quantize(self, wbits, groupsize): - from .quantization import quantize_with_gptq - return quantize_with_gptq(self, wbits, groupsize) - -""" PyTorch Moss model.""" - -from typing import Optional, Tuple, Union - -import torch -import torch.utils.checkpoint -from torch import nn -from torch.nn import CrossEntropyLoss -import transformers -from transformers.activations import ACT2FN -from transformers.modeling_utils import PreTrainedModel -from transformers.modeling_outputs import BaseModelOutputWithPast, CausalLMOutputWithPast -from transformers.utils import ( - add_code_sample_docstrings, - add_start_docstrings, - add_start_docstrings_to_model_forward, - logging -) - -from .configuration_moss import MossConfig - -logger = logging.get_logger(__name__) - -_CHECKPOINT_FOR_DOC = "fnlp/moss-moon-003-base" -_CONFIG_FOR_DOC = "MossConfig" - - -MOSS_PRETRAINED_MODEL_ARCHIVE_LIST = [ - "fnlp/moss-moon-003-base", - "fnlp/moss-moon-003-sft", - "fnlp/moss-moon-003-sft-plugin", - "fnlp/moss-moon-003-sft-int4", - "fnlp/moss-moon-003-sft-plugin-int4", - "fnlp/moss-moon-003-sft-int8", - "fnlp/moss-moon-003-sft-plugin-int8", -] - - -# Copied from transformers.models.gptj.modeling_gptj.create_sinusoidal_positions -def create_sinusoidal_positions(num_pos: int, dim: int) -> torch.Tensor: - inv_freq = 1.0 / (10000 ** (torch.arange(0, dim, 2) / dim)) - sinusoid_inp = torch.einsum("i , j -> i j", torch.arange(num_pos, dtype=torch.float), inv_freq).float() - return torch.cat((torch.sin(sinusoid_inp), torch.cos(sinusoid_inp)), dim=1) - - -# Copied from transformers.models.gptj.modeling_gptj.rotate_every_two -def rotate_every_two(x: torch.Tensor) -> torch.Tensor: - x1 = x[:, :, :, ::2] - x2 = x[:, :, :, 1::2] - x = torch.stack((-x2, x1), dim=-1) - return x.flatten(-2) # in einsum notation: rearrange(x, '... d j -> ... (d j)') - - -# Copied from transformers.models.gptj.modeling_gptj.apply_rotary_pos_emb -def apply_rotary_pos_emb(tensor: torch.Tensor, sin: torch.Tensor, cos: torch.Tensor) -> torch.Tensor: - sin = torch.repeat_interleave(sin[:, :, None, :], 2, 3) - cos = torch.repeat_interleave(cos[:, :, None, :], 2, 3) - return (tensor * cos) + (rotate_every_two(tensor) * sin) - - -class MossAttention(nn.Module): - def __init__(self, config): - super().__init__() - - max_positions = config.max_position_embeddings - self.register_buffer( - "causal_mask", - torch.tril(torch.ones((max_positions, max_positions), dtype=torch.bool)).view( - 1, 1, max_positions, max_positions - ), - ) - - self.attn_dropout = nn.Dropout(config.attn_pdrop) - self.resid_dropout = nn.Dropout(config.resid_pdrop) - - self.embed_dim = config.hidden_size - self.num_attention_heads = config.num_attention_heads - self.head_dim = self.embed_dim // self.num_attention_heads - if self.head_dim * self.num_attention_heads != self.embed_dim: - raise ValueError( - f"embed_dim must be divisible by num_attention_heads (got `embed_dim`: {self.embed_dim} and" - f" `num_attention_heads`: {self.num_attention_heads})." - ) - self.scale_attn = torch.sqrt(torch.tensor(self.head_dim, dtype=torch.float32)).to(torch.get_default_dtype()) - self.qkv_proj = nn.Linear(self.embed_dim, self.embed_dim * 3, bias=False) - - self.out_proj = nn.Linear(self.embed_dim, self.embed_dim, bias=False) - self.rotary_dim = config.rotary_dim - pos_embd_dim = self.rotary_dim or self.embed_dim - self.embed_positions = create_sinusoidal_positions(max_positions, pos_embd_dim) - - def _split_heads(self, x, n_head, dim_head, mp_num): - reshaped = x.reshape(x.shape[:-1] + (n_head // mp_num, dim_head)) - reshaped = reshaped.reshape(x.shape[:-2] + (-1,) + reshaped.shape[-1:]) - return reshaped - - def _merge_heads(self, tensor, num_attention_heads, attn_head_size): - """ - Merges attn_head_size dim and num_attn_heads dim into n_ctx - """ - if len(tensor.shape) == 5: - tensor = tensor.permute(0, 1, 3, 2, 4).contiguous() - elif len(tensor.shape) == 4: - tensor = tensor.permute(0, 2, 1, 3).contiguous() - else: - raise ValueError(f"Input tensor rank should be one of [4, 5], but is: {len(tensor.shape)}") - new_shape = tensor.size()[:-2] + (num_attention_heads * attn_head_size,) - return tensor.view(new_shape) - - def _attn( - self, - query, - key, - value, - attention_mask=None, - head_mask=None, - ): - # compute causal mask from causal mask buffer - query_length, key_length = query.size(-2), key.size(-2) - causal_mask = self.causal_mask[:, :, key_length - query_length : key_length, :key_length] - - # Keep the attention weights computation in fp32 to avoid overflow issues - query = query.to(torch.float32) - key = key.to(torch.float32) - - attn_weights = torch.matmul(query, key.transpose(-1, -2)) - - attn_weights = attn_weights / self.scale_attn - mask_value = torch.finfo(attn_weights.dtype).min - # Need to be a tensor, otherwise we get error: `RuntimeError: expected scalar type float but found double`. - # Need to be on the same device, otherwise `RuntimeError: ..., x and y to be on the same device` - mask_value = torch.tensor(mask_value, dtype=attn_weights.dtype).to(attn_weights.device) - attn_weights = torch.where(causal_mask, attn_weights, mask_value) - - if attention_mask is not None: - # Apply the attention mask - attn_weights = attn_weights + attention_mask - - attn_weights = nn.Softmax(dim=-1)(attn_weights) - attn_weights = attn_weights.to(value.dtype) - attn_weights = self.attn_dropout(attn_weights) - - # Mask heads if we want to - if head_mask is not None: - attn_weights = attn_weights * head_mask - - attn_output = torch.matmul(attn_weights, value) - - return attn_output, attn_weights - - def forward( - self, - hidden_states: Optional[torch.FloatTensor], - layer_past: Optional[Tuple[torch.Tensor]] = None, - attention_mask: Optional[torch.FloatTensor] = None, - position_ids: Optional[torch.LongTensor] = None, - head_mask: Optional[torch.FloatTensor] = None, - use_cache: Optional[bool] = False, - output_attentions: Optional[bool] = False, - ) -> Union[ - Tuple[torch.Tensor, Tuple[torch.Tensor]], - Optional[Tuple[torch.Tensor, Tuple[torch.Tensor], Tuple[torch.Tensor, ...]]], - ]: - qkv = self.qkv_proj(hidden_states) - # TODO(enijkamp): factor out number of logical TPU-v4 cores or make forward pass agnostic - mp_num = 4 - qkv_split = qkv.reshape(qkv.shape[:-1] + (mp_num, -1)) - - local_dim = self.head_dim * self.num_attention_heads // mp_num - query, value, key = torch.split(qkv_split, local_dim, dim=-1) - query = self._split_heads(query, self.num_attention_heads, self.head_dim, mp_num=mp_num) - key = self._split_heads(key, self.num_attention_heads, self.head_dim, mp_num=mp_num) - - value = self._split_heads(value, self.num_attention_heads, self.head_dim, mp_num=mp_num) - value = value.permute(0, 2, 1, 3) - - embed_positions = self.embed_positions - if embed_positions.device != position_ids.device: - embed_positions = embed_positions.to(position_ids.device) - self.embed_positions = embed_positions - - sincos = embed_positions[position_ids] - sin, cos = torch.split(sincos, sincos.shape[-1] // 2, dim=-1) - - if self.rotary_dim is not None: - k_rot = key[:, :, :, : self.rotary_dim] - k_pass = key[:, :, :, self.rotary_dim :] - - q_rot = query[:, :, :, : self.rotary_dim] - q_pass = query[:, :, :, self.rotary_dim :] - - k_rot = apply_rotary_pos_emb(k_rot, sin, cos) - q_rot = apply_rotary_pos_emb(q_rot, sin, cos) - - key = torch.cat([k_rot, k_pass], dim=-1) - query = torch.cat([q_rot, q_pass], dim=-1) - else: - key = apply_rotary_pos_emb(key, sin, cos) - query = apply_rotary_pos_emb(query, sin, cos) - - key = key.permute(0, 2, 1, 3) - query = query.permute(0, 2, 1, 3) - - if layer_past is not None: - past_key = layer_past[0] - past_value = layer_past[1] - key = torch.cat((past_key, key), dim=-2) - value = torch.cat((past_value, value), dim=-2) - - if use_cache is True: - present = (key, value) - else: - present = None - - # compute self-attention: V x Softmax(QK^T) - attn_output, attn_weights = self._attn(query, key, value, attention_mask, head_mask) - - attn_output = self._merge_heads(attn_output, self.num_attention_heads, self.head_dim) - attn_output = self.out_proj(attn_output) - attn_output = self.resid_dropout(attn_output) - - outputs = (attn_output, present) - if output_attentions: - outputs += (attn_weights,) - - return outputs # a, present, (attentions) - - -# Copied from transformers.models.gptj.modeling_gptj.GPTJMLP with GPTJ->Moss -class MossMLP(nn.Module): - def __init__(self, intermediate_size, config): # in MLP: intermediate_size= 4 * embed_dim - super().__init__() - embed_dim = config.n_embd - - self.fc_in = nn.Linear(embed_dim, intermediate_size) - self.fc_out = nn.Linear(intermediate_size, embed_dim) - - self.act = ACT2FN[config.activation_function] - self.dropout = nn.Dropout(config.resid_pdrop) - - def forward(self, hidden_states: Optional[torch.FloatTensor]) -> torch.FloatTensor: - hidden_states = self.fc_in(hidden_states) - hidden_states = self.act(hidden_states) - hidden_states = self.fc_out(hidden_states) - hidden_states = self.dropout(hidden_states) - return hidden_states - - -# Copied from transformers.models.gptj.modeling_gptj.GPTJBlock with GPTJ->Moss -class MossBlock(nn.Module): - def __init__(self, config): - super().__init__() - inner_dim = config.n_inner if config.n_inner is not None else 4 * config.n_embd - self.ln_1 = nn.LayerNorm(config.n_embd, eps=config.layer_norm_epsilon) - self.attn = MossAttention(config) - self.mlp = MossMLP(inner_dim, config) - - def forward( - self, - hidden_states: Optional[torch.FloatTensor], - layer_past: Optional[Tuple[torch.Tensor]] = None, - attention_mask: Optional[torch.FloatTensor] = None, - position_ids: Optional[torch.LongTensor] = None, - head_mask: Optional[torch.FloatTensor] = None, - use_cache: Optional[bool] = False, - output_attentions: Optional[bool] = False, - ) -> Union[Tuple[torch.Tensor], Optional[Tuple[torch.Tensor, Tuple[torch.FloatTensor, ...]]]]: - residual = hidden_states - hidden_states = self.ln_1(hidden_states) - attn_outputs = self.attn( - hidden_states=hidden_states, - layer_past=layer_past, - attention_mask=attention_mask, - position_ids=position_ids, - head_mask=head_mask, - use_cache=use_cache, - output_attentions=output_attentions, - ) - attn_output = attn_outputs[0] # output_attn: a, present, (attentions) - outputs = attn_outputs[1:] - - feed_forward_hidden_states = self.mlp(hidden_states) - hidden_states = attn_output + feed_forward_hidden_states + residual - - if use_cache: - outputs = (hidden_states,) + outputs - else: - outputs = (hidden_states,) + outputs[1:] - - return outputs # hidden_states, present, (attentions) - - -class MossPreTrainedModel(PreTrainedModel): - """ - An abstract class to handle weights initialization and a simple interface for downloading and loading pretrained - models. - """ - - config_class = MossConfig - base_model_prefix = "transformer" - supports_gradient_checkpointing = True - _no_split_modules = ["MossBlock"] - - def __init__(self, *inputs, **kwargs): - super().__init__(*inputs, **kwargs) - - def _init_weights(self, module): - """Initialize the weights.""" - if isinstance(module, (nn.Linear,)): - # Slightly different from Mesh Transformer JAX which uses truncated_normal for initialization - # cf https://github.com/pytorch/pytorch/pull/5617 - module.weight.data.normal_(mean=0.0, std=self.config.initializer_range) - if module.bias is not None: - module.bias.data.zero_() - elif isinstance(module, nn.Embedding): - module.weight.data.normal_(mean=0.0, std=self.config.initializer_range) - if module.padding_idx is not None: - module.weight.data[module.padding_idx].zero_() - elif isinstance(module, nn.LayerNorm): - module.bias.data.zero_() - module.weight.data.fill_(1.0) - - def _set_gradient_checkpointing(self, module, value=False): - if isinstance(module, MossModel): - module.gradient_checkpointing = value - - -MOSS_START_DOCSTRING = r""" - This model is a PyTorch [torch.nn.Module](https://pytorch.org/docs/stable/nn.html#torch.nn.Module) sub-class. Use - it as a regular PyTorch Module and refer to the PyTorch documentation for all matter related to general usage and - behavior. - - Parameters: - config ([`MossConfig`]): Model configuration class with all the parameters of the model. - Initializing with a config file does not load the weights associated with the model, only the - configuration. Check out the [`~PreTrainedModel.from_pretrained`] method to load the model weights. -""" - -MOSS_INPUTS_DOCSTRING = r""" - Args: - input_ids (`torch.LongTensor` of shape `({0})`): - Indices of input sequence tokens in the vocabulary. - - Indices can be obtained using [`AutoProcenizer`]. See [`PreTrainedTokenizer.encode`] and - [`PreTrainedTokenizer.__call__`] for details. - - [What are input IDs?](../glossary#input-ids) - attention_mask (`torch.FloatTensor` of shape `({0})`, *optional*): - Mask to avoid performing attention on padding token indices. Mask values selected in `[0, 1]`: - - - 1 for tokens that are **not masked**, - - 0 for tokens that are **masked**. - - [What are attention masks?](../glossary#attention-mask) - token_type_ids (`torch.LongTensor` of shape `({0})`, *optional*): - Segment token indices to indicate first and second portions of the inputs. Indices are selected in `[0, - 1]`: - - - 0 corresponds to a *sentence A* token, - - 1 corresponds to a *sentence B* token. - - [What are token type IDs?](../glossary#token-type-ids) - position_ids (`torch.LongTensor` of shape `({0})`, *optional*): - Indices of positions of each input sequence tokens in the position embeddings. Selected in the range `[0, - config.n_positions - 1]`. - - [What are position IDs?](../glossary#position-ids) - head_mask (`torch.FloatTensor` of shape `(num_attention_heads,)` or `(n_layer, num_attention_heads)`, *optional*): - Mask to nullify selected heads of the self-attention modules. Mask values selected in `[0, 1]`: - - - 1 indicates the head is **not masked**, - - 0 indicates the head is **masked**. - - inputs_embeds (`torch.FloatTensor` of shape `({0}, hidden_dim)`, *optional*): - Optionally, instead of passing `input_ids` you can choose to directly pass an embedded representation. This - is useful if you want more control over how to convert *input_ids* indices into associated vectors than the - model's internal embedding lookup matrix. - output_attentions (`bool`, *optional*): - Whether or not to return the attentions tensors of all attention layers. See `attentions` under returned - tensors for more detail. - output_hidden_states (`bool`, *optional*): - Whether or not to return the hidden states of all layers. See `hidden_states` under returned tensors for - more detail. - return_dict (`bool`, *optional*): - Whether or not to return a [`~utils.ModelOutput`] instead of a plain tuple. -""" - - -@add_start_docstrings( - "The bare Moss Model transformer outputting raw hidden-states without any specific head on top.", - MOSS_START_DOCSTRING, -) -class MossModel(MossPreTrainedModel): - def __init__(self, config): - super().__init__(config) - - self.embed_dim = config.n_embd - self.vocab_size = config.vocab_size - self.wte = nn.Embedding(config.vocab_size, self.embed_dim) - self.drop = nn.Dropout(config.embd_pdrop) - self.h = nn.ModuleList([MossBlock(config) for _ in range(config.n_layer)]) - self.ln_f = nn.LayerNorm(self.embed_dim, eps=config.layer_norm_epsilon) - self.rotary_dim = min(config.rotary_dim, config.n_ctx // config.num_attention_heads) - - self.gradient_checkpointing = False - - # Initialize weights and apply final processing - self.post_init() - - def get_input_embeddings(self): - return self.wte - - def set_input_embeddings(self, new_embeddings): - self.wte = new_embeddings - - @add_start_docstrings_to_model_forward(MOSS_INPUTS_DOCSTRING.format("batch_size, sequence_length")) - @add_code_sample_docstrings( - checkpoint=_CHECKPOINT_FOR_DOC, - output_type=BaseModelOutputWithPast, - config_class=_CONFIG_FOR_DOC, - ) - def forward( - self, - input_ids: Optional[torch.LongTensor] = None, - past_key_values: Optional[Tuple[Tuple[torch.Tensor]]] = None, - attention_mask: Optional[torch.FloatTensor] = None, - token_type_ids: Optional[torch.LongTensor] = None, - position_ids: Optional[torch.LongTensor] = None, - head_mask: Optional[torch.FloatTensor] = None, - inputs_embeds: Optional[torch.FloatTensor] = None, - use_cache: Optional[bool] = None, - output_attentions: Optional[bool] = None, - output_hidden_states: Optional[bool] = None, - return_dict: Optional[bool] = None, - ) -> Union[Tuple, BaseModelOutputWithPast]: - output_attentions = output_attentions if output_attentions is not None else self.config.output_attentions - output_hidden_states = ( - output_hidden_states if output_hidden_states is not None else self.config.output_hidden_states - ) - use_cache = use_cache if use_cache is not None else self.config.use_cache - return_dict = return_dict if return_dict is not None else self.config.use_return_dict - - if input_ids is not None and inputs_embeds is not None: - raise ValueError("You cannot specify both input_ids and inputs_embeds at the same time") - elif input_ids is not None: - input_shape = input_ids.size() - input_ids = input_ids.view(-1, input_shape[-1]) - batch_size = input_ids.shape[0] - elif inputs_embeds is not None: - input_shape = inputs_embeds.size()[:-1] - batch_size = inputs_embeds.shape[0] - else: - raise ValueError("You have to specify either input_ids or inputs_embeds") - - device = input_ids.device if input_ids is not None else inputs_embeds.device - - if token_type_ids is not None: - token_type_ids = token_type_ids.view(-1, input_shape[-1]) - - if position_ids is not None: - position_ids = position_ids.view(-1, input_shape[-1]).long() - - if past_key_values is None: - past_length = 0 - past_key_values = tuple([None] * len(self.h)) - else: - past_length = past_key_values[0][0].size(-2) - - if position_ids is None: - position_ids = torch.arange(past_length, input_shape[-1] + past_length, dtype=torch.long, device=device) - position_ids = position_ids.unsqueeze(0).view(-1, input_shape[-1]) - - # Attention mask. - if attention_mask is not None: - if batch_size <= 0: - raise ValueError("batch_size has to be defined and > 0") - attention_mask = attention_mask.view(batch_size, -1) - # We create a 3D attention mask from a 2D tensor mask. - # Sizes are [batch_size, 1, 1, to_seq_length] - # So we can broadcast to [batch_size, num_heads, from_seq_length, to_seq_length] - # this attention mask is more simple than the triangular masking of causal attention - # used in OpenAI GPT, we just need to prepare the broadcast dimension here. - attention_mask = attention_mask[:, None, None, :] - - # Since attention_mask is 1.0 for positions we want to attend and 0.0 for - # masked positions, this operation will create a tensor which is 0.0 for - # positions we want to attend and the dtype's smallest value for masked positions. - # Since we are adding it to the raw scores before the softmax, this is - # effectively the same as removing these entirely. - attention_mask = attention_mask.to(dtype=self.dtype) # fp16 compatibility - attention_mask = (1.0 - attention_mask) * torch.finfo(self.dtype).min - - # Prepare head mask if needed - # 1.0 in head_mask indicate we keep the head - # attention_probs has shape bsz x num_attention_heads x N x N - # head_mask has shape n_layer x batch x num_attention_heads x N x N - head_mask = self.get_head_mask(head_mask, self.config.n_layer) - - if inputs_embeds is None: - inputs_embeds = self.wte(input_ids) - - hidden_states = inputs_embeds - - if token_type_ids is not None: - token_type_embeds = self.wte(token_type_ids) - hidden_states = hidden_states + token_type_embeds - - hidden_states = self.drop(hidden_states) - - output_shape = input_shape + (hidden_states.size(-1),) - - if self.gradient_checkpointing and self.training: - if use_cache: - logger.warning_once( - "`use_cache=True` is incompatible with `config.gradient_checkpointing=True`. Setting " - "`use_cache=False`..." - ) - use_cache = False - - presents = () if use_cache else None - all_self_attentions = () if output_attentions else None - all_hidden_states = () if output_hidden_states else None - for i, (block, layer_past) in enumerate(zip(self.h, past_key_values)): - if output_hidden_states: - all_hidden_states = all_hidden_states + (hidden_states,) - - if self.gradient_checkpointing and self.training: - - def create_custom_forward(module): - def custom_forward(*inputs): - # None for past_key_value - return module(*inputs, use_cache, output_attentions) - - return custom_forward - - outputs = torch.utils.checkpoint.checkpoint( - create_custom_forward(block), - hidden_states, - None, - attention_mask, - position_ids, - head_mask[i], - ) - else: - outputs = block( - hidden_states=hidden_states, - layer_past=layer_past, - attention_mask=attention_mask, - position_ids=position_ids, - head_mask=head_mask[i], - use_cache=use_cache, - output_attentions=output_attentions, - ) - - hidden_states = outputs[0] - if use_cache is True: - presents = presents + (outputs[1],) - - if output_attentions: - all_self_attentions = all_self_attentions + (outputs[2 if use_cache else 1],) - - hidden_states = self.ln_f(hidden_states) - - hidden_states = hidden_states.view(output_shape) - # Add last hidden state - if output_hidden_states: - all_hidden_states = all_hidden_states + (hidden_states,) - - if not return_dict: - return tuple(v for v in [hidden_states, presents, all_hidden_states, all_self_attentions] if v is not None) - - return BaseModelOutputWithPast( - last_hidden_state=hidden_states, - past_key_values=presents, - hidden_states=all_hidden_states, - attentions=all_self_attentions, - ) - - -@add_start_docstrings( - """ - The Moss Model transformer with a language modeling head on top. - """, - MOSS_START_DOCSTRING, -) -class MossForCausalLM(MossPreTrainedModel): - _keys_to_ignore_on_load_missing = [r"h\.\d+\.attn\.causal_mask"] - - def __init__(self, config): - super().__init__(config) - if not hasattr(config, 'wbits'): - config.wbits = 32 - config.groupsize = 128 - - if config.wbits not in [4, 8, 32]: - logger.warning(f'Specify `wbits` with 4, 8 or 32 to load the model. ') - if config.wbits in [4, 8]: - def noop(*args, **kwargs): - pass - torch.nn.init.kaiming_uniform_ = noop - torch.nn.init.uniform_ = noop - torch.nn.init.normal_ = noop - - torch.set_default_dtype(torch.half) - transformers.modeling_utils._init_weights = False - torch.set_default_dtype(torch.half) - self.transformer = MossModel(config) - self.lm_head = nn.Linear(config.n_embd, config.vocab_size) - if config.wbits in [4, 8]: - torch.set_default_dtype(torch.float) - transformers.modeling_utils._init_weights = True - self.quantize(config.wbits, config.groupsize) - # Initialize weights and apply final processing - self.post_init() - - def get_output_embeddings(self): - return self.lm_head - - def set_output_embeddings(self, new_embeddings): - self.lm_head = new_embeddings - - def prepare_inputs_for_generation(self, input_ids, past_key_values=None, **kwargs): - token_type_ids = kwargs.get("token_type_ids", None) - # only last token for inputs_ids if past is defined in kwargs - if past_key_values: - input_ids = input_ids[:, -1].unsqueeze(-1) - if token_type_ids is not None: - token_type_ids = token_type_ids[:, -1].unsqueeze(-1) - - attention_mask = kwargs.get("attention_mask", None) - position_ids = kwargs.get("position_ids", None) - - if attention_mask is not None and position_ids is None: - # create position_ids on the fly for batch generation - position_ids = attention_mask.long().cumsum(-1) - 1 - position_ids.masked_fill_(attention_mask == 0, 1) - if past_key_values: - position_ids = position_ids[:, -1].unsqueeze(-1) - - return { - "input_ids": input_ids, - "past_key_values": past_key_values, - "use_cache": kwargs.get("use_cache"), - "position_ids": position_ids, - "attention_mask": attention_mask, - "token_type_ids": token_type_ids, - } - - @add_start_docstrings_to_model_forward(MOSS_INPUTS_DOCSTRING.format("batch_size, sequence_length")) - @add_code_sample_docstrings( - checkpoint=_CHECKPOINT_FOR_DOC, - output_type=CausalLMOutputWithPast, - config_class=_CONFIG_FOR_DOC, - ) - def forward( - self, - input_ids: Optional[torch.LongTensor] = None, - past_key_values: Optional[Tuple[Tuple[torch.Tensor]]] = None, - attention_mask: Optional[torch.FloatTensor] = None, - token_type_ids: Optional[torch.LongTensor] = None, - position_ids: Optional[torch.LongTensor] = None, - head_mask: Optional[torch.FloatTensor] = None, - inputs_embeds: Optional[torch.FloatTensor] = None, - labels: Optional[torch.LongTensor] = None, - use_cache: Optional[bool] = None, - output_attentions: Optional[bool] = None, - output_hidden_states: Optional[bool] = None, - return_dict: Optional[bool] = None, - ) -> Union[Tuple, CausalLMOutputWithPast]: - r""" - labels (`torch.LongTensor` of shape `(batch_size, sequence_length)`, *optional*): - Labels for language modeling. Note that the labels **are shifted** inside the model, i.e. you can set - `labels = input_ids` Indices are selected in `[-100, 0, ..., config.vocab_size]` All labels set to `-100` - are ignored (masked), the loss is only computed for labels in `[0, ..., config.vocab_size]` - """ - return_dict = return_dict if return_dict is not None else self.config.use_return_dict - - transformer_outputs = self.transformer( - input_ids, - past_key_values=past_key_values, - attention_mask=attention_mask, - token_type_ids=token_type_ids, - position_ids=position_ids, - head_mask=head_mask, - inputs_embeds=inputs_embeds, - use_cache=use_cache, - output_attentions=output_attentions, - output_hidden_states=output_hidden_states, - return_dict=return_dict, - ) - hidden_states = transformer_outputs[0] - - # make sure sampling in fp16 works correctly and - # compute loss in fp32 to match with mesh-tf version - # https://github.com/EleutherAI/gpt-neo/blob/89ce74164da2fb16179106f54e2269b5da8db333/models/gpt2/gpt2.py#L179 - lm_logits = self.lm_head(hidden_states).to(torch.float32) - - loss = None - if labels is not None: - # Shift so that tokens < n predict n - shift_logits = lm_logits[..., :-1, :].contiguous() - shift_labels = labels[..., 1:].contiguous() - # Flatten the tokens - loss_fct = CrossEntropyLoss() - loss = loss_fct(shift_logits.view(-1, shift_logits.size(-1)), shift_labels.view(-1)) - - loss = loss.to(hidden_states.dtype) - - if not return_dict: - output = (lm_logits,) + transformer_outputs[1:] - return ((loss,) + output) if loss is not None else output - - return CausalLMOutputWithPast( - loss=loss, - logits=lm_logits, - past_key_values=transformer_outputs.past_key_values, - hidden_states=transformer_outputs.hidden_states, - attentions=transformer_outputs.attentions, - ) - - @staticmethod - def _reorder_cache( - past_key_values: Tuple[Tuple[torch.Tensor]], beam_idx: torch.Tensor - ) -> Tuple[Tuple[torch.Tensor]]: - """ - This function is used to re-order the `past_key_values` cache if [`~PretrainedModel.beam_search`] or - [`~PretrainedModel.beam_sample`] is called. This is required to match `past_key_values` with the correct - beam_idx at every generation step. - """ - return tuple( - tuple(past_state.index_select(0, beam_idx.to(past_state.device)) for past_state in layer_past) - for layer_past in past_key_values - ) - - def quantize(self, wbits, groupsize): - from .quantization import quantize_with_gptq - return quantize_with_gptq(self, wbits, groupsize) - -""" PyTorch Moss model.""" - -from typing import Optional, Tuple, Union - -import torch -import torch.utils.checkpoint -from torch import nn -from torch.nn import CrossEntropyLoss -import transformers -from transformers.activations import ACT2FN -from transformers.modeling_utils import PreTrainedModel -from transformers.modeling_outputs import BaseModelOutputWithPast, CausalLMOutputWithPast -from transformers.utils import ( - add_code_sample_docstrings, - add_start_docstrings, - add_start_docstrings_to_model_forward, - logging -) - -from .configuration_moss import MossConfig - -logger = logging.get_logger(__name__) - -_CHECKPOINT_FOR_DOC = "fnlp/moss-moon-003-base" -_CONFIG_FOR_DOC = "MossConfig" - - -MOSS_PRETRAINED_MODEL_ARCHIVE_LIST = [ - "fnlp/moss-moon-003-base", - "fnlp/moss-moon-003-sft", - "fnlp/moss-moon-003-sft-plugin", - "fnlp/moss-moon-003-sft-int4", - "fnlp/moss-moon-003-sft-plugin-int4", - "fnlp/moss-moon-003-sft-int8", - "fnlp/moss-moon-003-sft-plugin-int8", -] - - -# Copied from transformers.models.gptj.modeling_gptj.create_sinusoidal_positions -def create_sinusoidal_positions(num_pos: int, dim: int) -> torch.Tensor: - inv_freq = 1.0 / (10000 ** (torch.arange(0, dim, 2) / dim)) - sinusoid_inp = torch.einsum("i , j -> i j", torch.arange(num_pos, dtype=torch.float), inv_freq).float() - return torch.cat((torch.sin(sinusoid_inp), torch.cos(sinusoid_inp)), dim=1) - - -# Copied from transformers.models.gptj.modeling_gptj.rotate_every_two -def rotate_every_two(x: torch.Tensor) -> torch.Tensor: - x1 = x[:, :, :, ::2] - x2 = x[:, :, :, 1::2] - x = torch.stack((-x2, x1), dim=-1) - return x.flatten(-2) # in einsum notation: rearrange(x, '... d j -> ... (d j)') - - -# Copied from transformers.models.gptj.modeling_gptj.apply_rotary_pos_emb -def apply_rotary_pos_emb(tensor: torch.Tensor, sin: torch.Tensor, cos: torch.Tensor) -> torch.Tensor: - sin = torch.repeat_interleave(sin[:, :, None, :], 2, 3) - cos = torch.repeat_interleave(cos[:, :, None, :], 2, 3) - return (tensor * cos) + (rotate_every_two(tensor) * sin) - - -class MossAttention(nn.Module): - def __init__(self, config): - super().__init__() - - max_positions = config.max_position_embeddings - self.register_buffer( - "causal_mask", - torch.tril(torch.ones((max_positions, max_positions), dtype=torch.bool)).view( - 1, 1, max_positions, max_positions - ), - ) - - self.attn_dropout = nn.Dropout(config.attn_pdrop) - self.resid_dropout = nn.Dropout(config.resid_pdrop) - - self.embed_dim = config.hidden_size - self.num_attention_heads = config.num_attention_heads - self.head_dim = self.embed_dim // self.num_attention_heads - if self.head_dim * self.num_attention_heads != self.embed_dim: - raise ValueError( - f"embed_dim must be divisible by num_attention_heads (got `embed_dim`: {self.embed_dim} and" - f" `num_attention_heads`: {self.num_attention_heads})." - ) - self.scale_attn = torch.sqrt(torch.tensor(self.head_dim, dtype=torch.float32)).to(torch.get_default_dtype()) - self.qkv_proj = nn.Linear(self.embed_dim, self.embed_dim * 3, bias=False) - - self.out_proj = nn.Linear(self.embed_dim, self.embed_dim, bias=False) - self.rotary_dim = config.rotary_dim - pos_embd_dim = self.rotary_dim or self.embed_dim - self.embed_positions = create_sinusoidal_positions(max_positions, pos_embd_dim) - - def _split_heads(self, x, n_head, dim_head, mp_num): - reshaped = x.reshape(x.shape[:-1] + (n_head // mp_num, dim_head)) - reshaped = reshaped.reshape(x.shape[:-2] + (-1,) + reshaped.shape[-1:]) - return reshaped - - def _merge_heads(self, tensor, num_attention_heads, attn_head_size): - """ - Merges attn_head_size dim and num_attn_heads dim into n_ctx - """ - if len(tensor.shape) == 5: - tensor = tensor.permute(0, 1, 3, 2, 4).contiguous() - elif len(tensor.shape) == 4: - tensor = tensor.permute(0, 2, 1, 3).contiguous() - else: - raise ValueError(f"Input tensor rank should be one of [4, 5], but is: {len(tensor.shape)}") - new_shape = tensor.size()[:-2] + (num_attention_heads * attn_head_size,) - return tensor.view(new_shape) - - def _attn( - self, - query, - key, - value, - attention_mask=None, - head_mask=None, - ): - # compute causal mask from causal mask buffer - query_length, key_length = query.size(-2), key.size(-2) - causal_mask = self.causal_mask[:, :, key_length - query_length : key_length, :key_length] - - # Keep the attention weights computation in fp32 to avoid overflow issues - query = query.to(torch.float32) - key = key.to(torch.float32) - - attn_weights = torch.matmul(query, key.transpose(-1, -2)) - - attn_weights = attn_weights / self.scale_attn - mask_value = torch.finfo(attn_weights.dtype).min - # Need to be a tensor, otherwise we get error: `RuntimeError: expected scalar type float but found double`. - # Need to be on the same device, otherwise `RuntimeError: ..., x and y to be on the same device` - mask_value = torch.tensor(mask_value, dtype=attn_weights.dtype).to(attn_weights.device) - attn_weights = torch.where(causal_mask, attn_weights, mask_value) - - if attention_mask is not None: - # Apply the attention mask - attn_weights = attn_weights + attention_mask - - attn_weights = nn.Softmax(dim=-1)(attn_weights) - attn_weights = attn_weights.to(value.dtype) - attn_weights = self.attn_dropout(attn_weights) - - # Mask heads if we want to - if head_mask is not None: - attn_weights = attn_weights * head_mask - - attn_output = torch.matmul(attn_weights, value) - - return attn_output, attn_weights - - def forward( - self, - hidden_states: Optional[torch.FloatTensor], - layer_past: Optional[Tuple[torch.Tensor]] = None, - attention_mask: Optional[torch.FloatTensor] = None, - position_ids: Optional[torch.LongTensor] = None, - head_mask: Optional[torch.FloatTensor] = None, - use_cache: Optional[bool] = False, - output_attentions: Optional[bool] = False, - ) -> Union[ - Tuple[torch.Tensor, Tuple[torch.Tensor]], - Optional[Tuple[torch.Tensor, Tuple[torch.Tensor], Tuple[torch.Tensor, ...]]], - ]: - qkv = self.qkv_proj(hidden_states) - # TODO(enijkamp): factor out number of logical TPU-v4 cores or make forward pass agnostic - mp_num = 4 - qkv_split = qkv.reshape(qkv.shape[:-1] + (mp_num, -1)) - - local_dim = self.head_dim * self.num_attention_heads // mp_num - query, value, key = torch.split(qkv_split, local_dim, dim=-1) - query = self._split_heads(query, self.num_attention_heads, self.head_dim, mp_num=mp_num) - key = self._split_heads(key, self.num_attention_heads, self.head_dim, mp_num=mp_num) - - value = self._split_heads(value, self.num_attention_heads, self.head_dim, mp_num=mp_num) - value = value.permute(0, 2, 1, 3) - - embed_positions = self.embed_positions - if embed_positions.device != position_ids.device: - embed_positions = embed_positions.to(position_ids.device) - self.embed_positions = embed_positions - - sincos = embed_positions[position_ids] - sin, cos = torch.split(sincos, sincos.shape[-1] // 2, dim=-1) - - if self.rotary_dim is not None: - k_rot = key[:, :, :, : self.rotary_dim] - k_pass = key[:, :, :, self.rotary_dim :] - - q_rot = query[:, :, :, : self.rotary_dim] - q_pass = query[:, :, :, self.rotary_dim :] - - k_rot = apply_rotary_pos_emb(k_rot, sin, cos) - q_rot = apply_rotary_pos_emb(q_rot, sin, cos) - - key = torch.cat([k_rot, k_pass], dim=-1) - query = torch.cat([q_rot, q_pass], dim=-1) - else: - key = apply_rotary_pos_emb(key, sin, cos) - query = apply_rotary_pos_emb(query, sin, cos) - - key = key.permute(0, 2, 1, 3) - query = query.permute(0, 2, 1, 3) - - if layer_past is not None: - past_key = layer_past[0] - past_value = layer_past[1] - key = torch.cat((past_key, key), dim=-2) - value = torch.cat((past_value, value), dim=-2) - - if use_cache is True: - present = (key, value) - else: - present = None - - # compute self-attention: V x Softmax(QK^T) - attn_output, attn_weights = self._attn(query, key, value, attention_mask, head_mask) - - attn_output = self._merge_heads(attn_output, self.num_attention_heads, self.head_dim) - attn_output = self.out_proj(attn_output) - attn_output = self.resid_dropout(attn_output) - - outputs = (attn_output, present) - if output_attentions: - outputs += (attn_weights,) - - return outputs # a, present, (attentions) - - -# Copied from transformers.models.gptj.modeling_gptj.GPTJMLP with GPTJ->Moss -class MossMLP(nn.Module): - def __init__(self, intermediate_size, config): # in MLP: intermediate_size= 4 * embed_dim - super().__init__() - embed_dim = config.n_embd - - self.fc_in = nn.Linear(embed_dim, intermediate_size) - self.fc_out = nn.Linear(intermediate_size, embed_dim) - - self.act = ACT2FN[config.activation_function] - self.dropout = nn.Dropout(config.resid_pdrop) - - def forward(self, hidden_states: Optional[torch.FloatTensor]) -> torch.FloatTensor: - hidden_states = self.fc_in(hidden_states) - hidden_states = self.act(hidden_states) - hidden_states = self.fc_out(hidden_states) - hidden_states = self.dropout(hidden_states) - return hidden_states - - -# Copied from transformers.models.gptj.modeling_gptj.GPTJBlock with GPTJ->Moss -class MossBlock(nn.Module): - def __init__(self, config): - super().__init__() - inner_dim = config.n_inner if config.n_inner is not None else 4 * config.n_embd - self.ln_1 = nn.LayerNorm(config.n_embd, eps=config.layer_norm_epsilon) - self.attn = MossAttention(config) - self.mlp = MossMLP(inner_dim, config) - - def forward( - self, - hidden_states: Optional[torch.FloatTensor], - layer_past: Optional[Tuple[torch.Tensor]] = None, - attention_mask: Optional[torch.FloatTensor] = None, - position_ids: Optional[torch.LongTensor] = None, - head_mask: Optional[torch.FloatTensor] = None, - use_cache: Optional[bool] = False, - output_attentions: Optional[bool] = False, - ) -> Union[Tuple[torch.Tensor], Optional[Tuple[torch.Tensor, Tuple[torch.FloatTensor, ...]]]]: - residual = hidden_states - hidden_states = self.ln_1(hidden_states) - attn_outputs = self.attn( - hidden_states=hidden_states, - layer_past=layer_past, - attention_mask=attention_mask, - position_ids=position_ids, - head_mask=head_mask, - use_cache=use_cache, - output_attentions=output_attentions, - ) - attn_output = attn_outputs[0] # output_attn: a, present, (attentions) - outputs = attn_outputs[1:] - - feed_forward_hidden_states = self.mlp(hidden_states) - hidden_states = attn_output + feed_forward_hidden_states + residual - - if use_cache: - outputs = (hidden_states,) + outputs - else: - outputs = (hidden_states,) + outputs[1:] - - return outputs # hidden_states, present, (attentions) - - -class MossPreTrainedModel(PreTrainedModel): - """ - An abstract class to handle weights initialization and a simple interface for downloading and loading pretrained - models. - """ - - config_class = MossConfig - base_model_prefix = "transformer" - supports_gradient_checkpointing = True - _no_split_modules = ["MossBlock"] - - def __init__(self, *inputs, **kwargs): - super().__init__(*inputs, **kwargs) - - def _init_weights(self, module): - """Initialize the weights.""" - if isinstance(module, (nn.Linear,)): - # Slightly different from Mesh Transformer JAX which uses truncated_normal for initialization - # cf https://github.com/pytorch/pytorch/pull/5617 - module.weight.data.normal_(mean=0.0, std=self.config.initializer_range) - if module.bias is not None: - module.bias.data.zero_() - elif isinstance(module, nn.Embedding): - module.weight.data.normal_(mean=0.0, std=self.config.initializer_range) - if module.padding_idx is not None: - module.weight.data[module.padding_idx].zero_() - elif isinstance(module, nn.LayerNorm): - module.bias.data.zero_() - module.weight.data.fill_(1.0) - - def _set_gradient_checkpointing(self, module, value=False): - if isinstance(module, MossModel): - module.gradient_checkpointing = value - - -MOSS_START_DOCSTRING = r""" - This model is a PyTorch [torch.nn.Module](https://pytorch.org/docs/stable/nn.html#torch.nn.Module) sub-class. Use - it as a regular PyTorch Module and refer to the PyTorch documentation for all matter related to general usage and - behavior. - - Parameters: - config ([`MossConfig`]): Model configuration class with all the parameters of the model. - Initializing with a config file does not load the weights associated with the model, only the - configuration. Check out the [`~PreTrainedModel.from_pretrained`] method to load the model weights. -""" - -MOSS_INPUTS_DOCSTRING = r""" - Args: - input_ids (`torch.LongTensor` of shape `({0})`): - Indices of input sequence tokens in the vocabulary. - - Indices can be obtained using [`AutoProcenizer`]. See [`PreTrainedTokenizer.encode`] and - [`PreTrainedTokenizer.__call__`] for details. - - [What are input IDs?](../glossary#input-ids) - attention_mask (`torch.FloatTensor` of shape `({0})`, *optional*): - Mask to avoid performing attention on padding token indices. Mask values selected in `[0, 1]`: - - - 1 for tokens that are **not masked**, - - 0 for tokens that are **masked**. - - [What are attention masks?](../glossary#attention-mask) - token_type_ids (`torch.LongTensor` of shape `({0})`, *optional*): - Segment token indices to indicate first and second portions of the inputs. Indices are selected in `[0, - 1]`: - - - 0 corresponds to a *sentence A* token, - - 1 corresponds to a *sentence B* token. - - [What are token type IDs?](../glossary#token-type-ids) - position_ids (`torch.LongTensor` of shape `({0})`, *optional*): - Indices of positions of each input sequence tokens in the position embeddings. Selected in the range `[0, - config.n_positions - 1]`. - - [What are position IDs?](../glossary#position-ids) - head_mask (`torch.FloatTensor` of shape `(num_attention_heads,)` or `(n_layer, num_attention_heads)`, *optional*): - Mask to nullify selected heads of the self-attention modules. Mask values selected in `[0, 1]`: - - - 1 indicates the head is **not masked**, - - 0 indicates the head is **masked**. - - inputs_embeds (`torch.FloatTensor` of shape `({0}, hidden_dim)`, *optional*): - Optionally, instead of passing `input_ids` you can choose to directly pass an embedded representation. This - is useful if you want more control over how to convert *input_ids* indices into associated vectors than the - model's internal embedding lookup matrix. - output_attentions (`bool`, *optional*): - Whether or not to return the attentions tensors of all attention layers. See `attentions` under returned - tensors for more detail. - output_hidden_states (`bool`, *optional*): - Whether or not to return the hidden states of all layers. See `hidden_states` under returned tensors for - more detail. - return_dict (`bool`, *optional*): - Whether or not to return a [`~utils.ModelOutput`] instead of a plain tuple. -""" - - -@add_start_docstrings( - "The bare Moss Model transformer outputting raw hidden-states without any specific head on top.", - MOSS_START_DOCSTRING, -) -class MossModel(MossPreTrainedModel): - def __init__(self, config): - super().__init__(config) - - self.embed_dim = config.n_embd - self.vocab_size = config.vocab_size - self.wte = nn.Embedding(config.vocab_size, self.embed_dim) - self.drop = nn.Dropout(config.embd_pdrop) - self.h = nn.ModuleList([MossBlock(config) for _ in range(config.n_layer)]) - self.ln_f = nn.LayerNorm(self.embed_dim, eps=config.layer_norm_epsilon) - self.rotary_dim = min(config.rotary_dim, config.n_ctx // config.num_attention_heads) - - self.gradient_checkpointing = False - - # Initialize weights and apply final processing - self.post_init() - - def get_input_embeddings(self): - return self.wte - - def set_input_embeddings(self, new_embeddings): - self.wte = new_embeddings - - @add_start_docstrings_to_model_forward(MOSS_INPUTS_DOCSTRING.format("batch_size, sequence_length")) - @add_code_sample_docstrings( - checkpoint=_CHECKPOINT_FOR_DOC, - output_type=BaseModelOutputWithPast, - config_class=_CONFIG_FOR_DOC, - ) - def forward( - self, - input_ids: Optional[torch.LongTensor] = None, - past_key_values: Optional[Tuple[Tuple[torch.Tensor]]] = None, - attention_mask: Optional[torch.FloatTensor] = None, - token_type_ids: Optional[torch.LongTensor] = None, - position_ids: Optional[torch.LongTensor] = None, - head_mask: Optional[torch.FloatTensor] = None, - inputs_embeds: Optional[torch.FloatTensor] = None, - use_cache: Optional[bool] = None, - output_attentions: Optional[bool] = None, - output_hidden_states: Optional[bool] = None, - return_dict: Optional[bool] = None, - ) -> Union[Tuple, BaseModelOutputWithPast]: - output_attentions = output_attentions if output_attentions is not None else self.config.output_attentions - output_hidden_states = ( - output_hidden_states if output_hidden_states is not None else self.config.output_hidden_states - ) - use_cache = use_cache if use_cache is not None else self.config.use_cache - return_dict = return_dict if return_dict is not None else self.config.use_return_dict - - if input_ids is not None and inputs_embeds is not None: - raise ValueError("You cannot specify both input_ids and inputs_embeds at the same time") - elif input_ids is not None: - input_shape = input_ids.size() - input_ids = input_ids.view(-1, input_shape[-1]) - batch_size = input_ids.shape[0] - elif inputs_embeds is not None: - input_shape = inputs_embeds.size()[:-1] - batch_size = inputs_embeds.shape[0] - else: - raise ValueError("You have to specify either input_ids or inputs_embeds") - - device = input_ids.device if input_ids is not None else inputs_embeds.device - - if token_type_ids is not None: - token_type_ids = token_type_ids.view(-1, input_shape[-1]) - - if position_ids is not None: - position_ids = position_ids.view(-1, input_shape[-1]).long() - - if past_key_values is None: - past_length = 0 - past_key_values = tuple([None] * len(self.h)) - else: - past_length = past_key_values[0][0].size(-2) - - if position_ids is None: - position_ids = torch.arange(past_length, input_shape[-1] + past_length, dtype=torch.long, device=device) - position_ids = position_ids.unsqueeze(0).view(-1, input_shape[-1]) - - # Attention mask. - if attention_mask is not None: - if batch_size <= 0: - raise ValueError("batch_size has to be defined and > 0") - attention_mask = attention_mask.view(batch_size, -1) - # We create a 3D attention mask from a 2D tensor mask. - # Sizes are [batch_size, 1, 1, to_seq_length] - # So we can broadcast to [batch_size, num_heads, from_seq_length, to_seq_length] - # this attention mask is more simple than the triangular masking of causal attention - # used in OpenAI GPT, we just need to prepare the broadcast dimension here. - attention_mask = attention_mask[:, None, None, :] - - # Since attention_mask is 1.0 for positions we want to attend and 0.0 for - # masked positions, this operation will create a tensor which is 0.0 for - # positions we want to attend and the dtype's smallest value for masked positions. - # Since we are adding it to the raw scores before the softmax, this is - # effectively the same as removing these entirely. - attention_mask = attention_mask.to(dtype=self.dtype) # fp16 compatibility - attention_mask = (1.0 - attention_mask) * torch.finfo(self.dtype).min - - # Prepare head mask if needed - # 1.0 in head_mask indicate we keep the head - # attention_probs has shape bsz x num_attention_heads x N x N - # head_mask has shape n_layer x batch x num_attention_heads x N x N - head_mask = self.get_head_mask(head_mask, self.config.n_layer) - - if inputs_embeds is None: - inputs_embeds = self.wte(input_ids) - - hidden_states = inputs_embeds - - if token_type_ids is not None: - token_type_embeds = self.wte(token_type_ids) - hidden_states = hidden_states + token_type_embeds - - hidden_states = self.drop(hidden_states) - - output_shape = input_shape + (hidden_states.size(-1),) - - if self.gradient_checkpointing and self.training: - if use_cache: - logger.warning_once( - "`use_cache=True` is incompatible with `config.gradient_checkpointing=True`. Setting " - "`use_cache=False`..." - ) - use_cache = False - - presents = () if use_cache else None - all_self_attentions = () if output_attentions else None - all_hidden_states = () if output_hidden_states else None - for i, (block, layer_past) in enumerate(zip(self.h, past_key_values)): - if output_hidden_states: - all_hidden_states = all_hidden_states + (hidden_states,) - - if self.gradient_checkpointing and self.training: - - def create_custom_forward(module): - def custom_forward(*inputs): - # None for past_key_value - return module(*inputs, use_cache, output_attentions) - - return custom_forward - - outputs = torch.utils.checkpoint.checkpoint( - create_custom_forward(block), - hidden_states, - None, - attention_mask, - position_ids, - head_mask[i], - ) - else: - outputs = block( - hidden_states=hidden_states, - layer_past=layer_past, - attention_mask=attention_mask, - position_ids=position_ids, - head_mask=head_mask[i], - use_cache=use_cache, - output_attentions=output_attentions, - ) - - hidden_states = outputs[0] - if use_cache is True: - presents = presents + (outputs[1],) - - if output_attentions: - all_self_attentions = all_self_attentions + (outputs[2 if use_cache else 1],) - - hidden_states = self.ln_f(hidden_states) - - hidden_states = hidden_states.view(output_shape) - # Add last hidden state - if output_hidden_states: - all_hidden_states = all_hidden_states + (hidden_states,) - - if not return_dict: - return tuple(v for v in [hidden_states, presents, all_hidden_states, all_self_attentions] if v is not None) - - return BaseModelOutputWithPast( - last_hidden_state=hidden_states, - past_key_values=presents, - hidden_states=all_hidden_states, - attentions=all_self_attentions, - ) - - -@add_start_docstrings( - """ - The Moss Model transformer with a language modeling head on top. - """, - MOSS_START_DOCSTRING, -) -class MossForCausalLM(MossPreTrainedModel): - _keys_to_ignore_on_load_missing = [r"h\.\d+\.attn\.causal_mask"] - - def __init__(self, config): - super().__init__(config) - if not hasattr(config, 'wbits'): - config.wbits = 32 - config.groupsize = 128 - - if config.wbits not in [4, 8, 32]: - logger.warning(f'Specify `wbits` with 4, 8 or 32 to load the model. ') - if config.wbits in [4, 8]: - def noop(*args, **kwargs): - pass - torch.nn.init.kaiming_uniform_ = noop - torch.nn.init.uniform_ = noop - torch.nn.init.normal_ = noop - - torch.set_default_dtype(torch.half) - transformers.modeling_utils._init_weights = False - torch.set_default_dtype(torch.half) - self.transformer = MossModel(config) - self.lm_head = nn.Linear(config.n_embd, config.vocab_size) - if config.wbits in [4, 8]: - torch.set_default_dtype(torch.float) - transformers.modeling_utils._init_weights = True - self.quantize(config.wbits, config.groupsize) - # Initialize weights and apply final processing - self.post_init() - - def get_output_embeddings(self): - return self.lm_head - - def set_output_embeddings(self, new_embeddings): - self.lm_head = new_embeddings - - def prepare_inputs_for_generation(self, input_ids, past_key_values=None, **kwargs): - token_type_ids = kwargs.get("token_type_ids", None) - # only last token for inputs_ids if past is defined in kwargs - if past_key_values: - input_ids = input_ids[:, -1].unsqueeze(-1) - if token_type_ids is not None: - token_type_ids = token_type_ids[:, -1].unsqueeze(-1) - - attention_mask = kwargs.get("attention_mask", None) - position_ids = kwargs.get("position_ids", None) - - if attention_mask is not None and position_ids is None: - # create position_ids on the fly for batch generation - position_ids = attention_mask.long().cumsum(-1) - 1 - position_ids.masked_fill_(attention_mask == 0, 1) - if past_key_values: - position_ids = position_ids[:, -1].unsqueeze(-1) - - return { - "input_ids": input_ids, - "past_key_values": past_key_values, - "use_cache": kwargs.get("use_cache"), - "position_ids": position_ids, - "attention_mask": attention_mask, - "token_type_ids": token_type_ids, - } - - @add_start_docstrings_to_model_forward(MOSS_INPUTS_DOCSTRING.format("batch_size, sequence_length")) - @add_code_sample_docstrings( - checkpoint=_CHECKPOINT_FOR_DOC, - output_type=CausalLMOutputWithPast, - config_class=_CONFIG_FOR_DOC, - ) - def forward( - self, - input_ids: Optional[torch.LongTensor] = None, - past_key_values: Optional[Tuple[Tuple[torch.Tensor]]] = None, - attention_mask: Optional[torch.FloatTensor] = None, - token_type_ids: Optional[torch.LongTensor] = None, - position_ids: Optional[torch.LongTensor] = None, - head_mask: Optional[torch.FloatTensor] = None, - inputs_embeds: Optional[torch.FloatTensor] = None, - labels: Optional[torch.LongTensor] = None, - use_cache: Optional[bool] = None, - output_attentions: Optional[bool] = None, - output_hidden_states: Optional[bool] = None, - return_dict: Optional[bool] = None, - ) -> Union[Tuple, CausalLMOutputWithPast]: - r""" - labels (`torch.LongTensor` of shape `(batch_size, sequence_length)`, *optional*): - Labels for language modeling. Note that the labels **are shifted** inside the model, i.e. you can set - `labels = input_ids` Indices are selected in `[-100, 0, ..., config.vocab_size]` All labels set to `-100` - are ignored (masked), the loss is only computed for labels in `[0, ..., config.vocab_size]` - """ - return_dict = return_dict if return_dict is not None else self.config.use_return_dict - - transformer_outputs = self.transformer( - input_ids, - past_key_values=past_key_values, - attention_mask=attention_mask, - token_type_ids=token_type_ids, - position_ids=position_ids, - head_mask=head_mask, - inputs_embeds=inputs_embeds, - use_cache=use_cache, - output_attentions=output_attentions, - output_hidden_states=output_hidden_states, - return_dict=return_dict, - ) - hidden_states = transformer_outputs[0] - - # make sure sampling in fp16 works correctly and - # compute loss in fp32 to match with mesh-tf version - # https://github.com/EleutherAI/gpt-neo/blob/89ce74164da2fb16179106f54e2269b5da8db333/models/gpt2/gpt2.py#L179 - lm_logits = self.lm_head(hidden_states).to(torch.float32) - - loss = None - if labels is not None: - # Shift so that tokens < n predict n - shift_logits = lm_logits[..., :-1, :].contiguous() - shift_labels = labels[..., 1:].contiguous() - # Flatten the tokens - loss_fct = CrossEntropyLoss() - loss = loss_fct(shift_logits.view(-1, shift_logits.size(-1)), shift_labels.view(-1)) - - loss = loss.to(hidden_states.dtype) - - if not return_dict: - output = (lm_logits,) + transformer_outputs[1:] - return ((loss,) + output) if loss is not None else output - - return CausalLMOutputWithPast( - loss=loss, - logits=lm_logits, - past_key_values=transformer_outputs.past_key_values, - hidden_states=transformer_outputs.hidden_states, - attentions=transformer_outputs.attentions, - ) - - @staticmethod - def _reorder_cache( - past_key_values: Tuple[Tuple[torch.Tensor]], beam_idx: torch.Tensor - ) -> Tuple[Tuple[torch.Tensor]]: - """ - This function is used to re-order the `past_key_values` cache if [`~PretrainedModel.beam_search`] or - [`~PretrainedModel.beam_sample`] is called. This is required to match `past_key_values` with the correct - beam_idx at every generation step. - """ - return tuple( - tuple(past_state.index_select(0, beam_idx.to(past_state.device)) for past_state in layer_past) - for layer_past in past_key_values - ) - - def quantize(self, wbits, groupsize): - from .quantization import quantize_with_gptq - return quantize_with_gptq(self, wbits, groupsize) - diff --git a/multi_language.py b/multi_language.py index c65872aa08a0b0088d94467054594c422978ca38..8e3ac9d7208d4258be408e8ddc3126baf98c6967 100644 --- a/multi_language.py +++ b/multi_language.py @@ -13,7 +13,6 @@ 4. Run `python multi_language.py`. Note: You need to run it multiple times to increase translation coverage because GPT makes mistakes sometimes. - (You can also run `CACHE_ONLY=True python multi_language.py` to use cached translation mapping) 5. Find the translated program in `multi-language\English\*` @@ -36,9 +35,7 @@ import pickle import time from toolbox import get_conf -CACHE_ONLY = os.environ.get('CACHE_ONLY', False) - -CACHE_FOLDER = get_conf('PATH_LOGGING') +CACHE_FOLDER, = get_conf('PATH_LOGGING') blacklist = ['multi-language', CACHE_FOLDER, '.git', 'private_upload', 'multi_language.py', 'build', '.github', '.vscode', '__pycache__', 'venv'] @@ -182,12 +179,12 @@ cached_translation = read_map_from_json(language=LANG) def trans(word_to_translate, language, special=False): if len(word_to_translate) == 0: return {} from crazy_functions.crazy_utils import request_gpt_model_multi_threads_with_very_awesome_ui_and_high_efficiency - from toolbox import get_conf, ChatBotWithCookies, load_chat_cookies - - cookies = load_chat_cookies() + from toolbox import get_conf, ChatBotWithCookies + proxies, WEB_PORT, LLM_MODEL, CONCURRENT_COUNT, AUTHENTICATION, CHATBOT_HEIGHT, LAYOUT, API_KEY = \ + get_conf('proxies', 'WEB_PORT', 'LLM_MODEL', 'CONCURRENT_COUNT', 'AUTHENTICATION', 'CHATBOT_HEIGHT', 'LAYOUT', 'API_KEY') llm_kwargs = { - 'api_key': cookies['api_key'], - 'llm_model': cookies['llm_model'], + 'api_key': API_KEY, + 'llm_model': LLM_MODEL, 'top_p':1.0, 'max_length': None, 'temperature':0.4, @@ -245,15 +242,15 @@ def trans(word_to_translate, language, special=False): def trans_json(word_to_translate, language, special=False): if len(word_to_translate) == 0: return {} from crazy_functions.crazy_utils import request_gpt_model_multi_threads_with_very_awesome_ui_and_high_efficiency - from toolbox import get_conf, ChatBotWithCookies, load_chat_cookies - - cookies = load_chat_cookies() + from toolbox import get_conf, ChatBotWithCookies + proxies, WEB_PORT, LLM_MODEL, CONCURRENT_COUNT, AUTHENTICATION, CHATBOT_HEIGHT, LAYOUT, API_KEY = \ + get_conf('proxies', 'WEB_PORT', 'LLM_MODEL', 'CONCURRENT_COUNT', 'AUTHENTICATION', 'CHATBOT_HEIGHT', 'LAYOUT', 'API_KEY') llm_kwargs = { - 'api_key': cookies['api_key'], - 'llm_model': cookies['llm_model'], + 'api_key': API_KEY, + 'llm_model': LLM_MODEL, 'top_p':1.0, 'max_length': None, - 'temperature':0.4, + 'temperature':0.1, } import random N_EACH_REQ = random.randint(16, 32) @@ -339,10 +336,7 @@ def step_1_core_key_translate(): if d not in cached_translation_keys: need_translate.append(d) - if CACHE_ONLY: - need_translate_mapping = {} - else: - need_translate_mapping = trans(need_translate, language=LANG_STD, special=True) + need_translate_mapping = trans(need_translate, language=LANG_STD, special=True) map_to_json(need_translate_mapping, language=LANG_STD) cached_translation = read_map_from_json(language=LANG_STD) cached_translation = dict(sorted(cached_translation.items(), key=lambda x: -len(x[0]))) @@ -352,9 +346,9 @@ def step_1_core_key_translate(): chinese_core_keys_norepeat_mapping.update({k:cached_translation[k]}) chinese_core_keys_norepeat_mapping = dict(sorted(chinese_core_keys_norepeat_mapping.items(), key=lambda x: -len(x[0]))) - # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + # =============================================== # copy - # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + # =============================================== def copy_source_code(): from toolbox import get_conf @@ -367,9 +361,9 @@ def step_1_core_key_translate(): shutil.copytree('./', backup_dir, ignore=lambda x, y: blacklist) copy_source_code() - # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + # =============================================== # primary key replace - # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + # =============================================== directory_path = f'./multi-language/{LANG}/' for root, dirs, files in os.walk(directory_path): for file in files: @@ -389,9 +383,9 @@ def step_1_core_key_translate(): def step_2_core_key_translate(): - # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= + # ================================================================================================= # step2 - # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= + # ================================================================================================= def load_string(strings, string_input): string_ = string_input.strip().strip(',').strip().strip('.').strip() @@ -482,19 +476,17 @@ def step_2_core_key_translate(): if d not in cached_translation_keys: need_translate.append(d) - if CACHE_ONLY: - up = {} - else: - up = trans_json(need_translate, language=LANG, special=False) + + up = trans_json(need_translate, language=LANG, special=False) map_to_json(up, language=LANG) cached_translation = read_map_from_json(language=LANG) LANG_STD = 'std' cached_translation.update(read_map_from_json(language=LANG_STD)) cached_translation = dict(sorted(cached_translation.items(), key=lambda x: -len(x[0]))) - # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + # =============================================== # literal key replace - # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + # =============================================== directory_path = f'./multi-language/{LANG}/' for root, dirs, files in os.walk(directory_path): for file in files: diff --git a/request_llm/README.md b/request_llm/README.md new file mode 100644 index 0000000000000000000000000000000000000000..545bc1ffba8b79a49d994cfedcc2a787475181b2 --- /dev/null +++ b/request_llm/README.md @@ -0,0 +1,79 @@ +# 如何使用其他大语言模型 + +## ChatGLM + +- 安装依赖 `pip install -r request_llm/requirements_chatglm.txt` +- 修改配置,在config.py中将LLM_MODEL的值改为"chatglm" + +``` sh +LLM_MODEL = "chatglm" +``` +- 运行! +``` sh +`python main.py` +``` + +## Claude-Stack + +- 请参考此教程获取 https://zhuanlan.zhihu.com/p/627485689 + - 1、SLACK_CLAUDE_BOT_ID + - 2、SLACK_CLAUDE_USER_TOKEN + +- 把token加入config.py + +## Newbing + +- 使用cookie editor获取cookie(json) +- 把cookie(json)加入config.py (NEWBING_COOKIES) + +## Moss +- 使用docker-compose + +## RWKV +- 使用docker-compose + +## LLAMA +- 使用docker-compose + +## 盘古 +- 使用docker-compose + + +--- +## Text-Generation-UI (TGUI,调试中,暂不可用) + +### 1. 部署TGUI +``` sh +# 1 下载模型 +git clone https://github.com/oobabooga/text-generation-webui.git +# 2 这个仓库的最新代码有问题,回滚到几周之前 +git reset --hard fcda3f87767e642d1c0411776e549e1d3894843d +# 3 切换路径 +cd text-generation-webui +# 4 安装text-generation的额外依赖 +pip install accelerate bitsandbytes flexgen gradio llamacpp markdown numpy peft requests rwkv safetensors sentencepiece tqdm datasets git+https://github.com/huggingface/transformers +# 5 下载模型 +python download-model.py facebook/galactica-1.3b +# 其他可选如 facebook/opt-1.3b +# facebook/galactica-1.3b +# facebook/galactica-6.7b +# facebook/galactica-120b +# facebook/pygmalion-1.3b 等 +# 详情见 https://github.com/oobabooga/text-generation-webui + +# 6 启动text-generation +python server.py --cpu --listen --listen-port 7865 --model facebook_galactica-1.3b +``` + +### 2. 修改config.py + +``` sh +# LLM_MODEL格式: tgui:[模型]@[ws地址]:[ws端口] , 端口要和上面给定的端口一致 +LLM_MODEL = "tgui:galactica-1.3b@localhost:7860" +``` + +### 3. 运行! +``` sh +cd chatgpt-academic +python main.py +``` diff --git a/request_llms/bridge_all.py b/request_llm/bridge_all.py similarity index 65% rename from request_llms/bridge_all.py rename to request_llm/bridge_all.py index e20570f93502c5a6dc633640c90f5968f7c70f1f..bb325e460742cececeaf1683d331c593bcba2915 100644 --- a/request_llms/bridge_all.py +++ b/request_llm/bridge_all.py @@ -8,32 +8,23 @@ 具备多线程调用能力的函数:在函数插件中被调用,灵活而简洁 2. predict_no_ui_long_connection(...) """ -import tiktoken, copy +import tiktoken from functools import lru_cache from concurrent.futures import ThreadPoolExecutor -from toolbox import get_conf, trimmed_format_exc, apply_gpt_academic_string_mask +from toolbox import get_conf, trimmed_format_exc from .bridge_chatgpt import predict_no_ui_long_connection as chatgpt_noui from .bridge_chatgpt import predict as chatgpt_ui -from .bridge_chatgpt_vision import predict_no_ui_long_connection as chatgpt_vision_noui -from .bridge_chatgpt_vision import predict as chatgpt_vision_ui - from .bridge_chatglm import predict_no_ui_long_connection as chatglm_noui from .bridge_chatglm import predict as chatglm_ui -from .bridge_chatglm3 import predict_no_ui_long_connection as chatglm3_noui -from .bridge_chatglm3 import predict as chatglm3_ui +from .bridge_chatglm import predict_no_ui_long_connection as chatglm_noui +from .bridge_chatglm import predict as chatglm_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 - -from .bridge_zhipu import predict_no_ui_long_connection as zhipu_noui -from .bridge_zhipu import predict as zhipu_ui - colors = ['#FF00FF', '#00FFFF', '#FF0000', '#990099', '#009999', '#990044'] class LazyloadTiktoken(object): @@ -47,13 +38,13 @@ class LazyloadTiktoken(object): tmp = tiktoken.encoding_for_model(model) print('加载tokenizer完毕') return tmp - + def encode(self, *args, **kwargs): - encoder = self.get_encoder(self.model) + encoder = self.get_encoder(self.model) return encoder.encode(*args, **kwargs) - + def decode(self, *args, **kwargs): - encoder = self.get_encoder(self.model) + encoder = self.get_encoder(self.model) return encoder.decode(*args, **kwargs) # Endpoint 重定向 @@ -61,12 +52,11 @@ API_URL_REDIRECT, AZURE_ENDPOINT, AZURE_ENGINE = get_conf("API_URL_REDIRECT", "A openai_endpoint = "https://api.openai.com/v1/chat/completions" api2d_endpoint = "https://openai.api2d.net/v1/chat/completions" newbing_endpoint = "wss://sydney.bing.com/sydney/ChatHub" -if not AZURE_ENDPOINT.endswith('/'): AZURE_ENDPOINT += '/' azure_endpoint = AZURE_ENDPOINT + f'openai/deployments/{AZURE_ENGINE}/chat/completions?api-version=2023-05-15' # 兼容旧版的配置 try: - API_URL = get_conf("API_URL") - if API_URL != "https://api.openai.com/v1/chat/completions": + API_URL, = get_conf("API_URL") + if API_URL != "https://api.openai.com/v1/chat/completions": openai_endpoint = API_URL print("警告!API_URL配置选项将被弃用,请更换为API_URL_REDIRECT配置") except: @@ -98,12 +88,12 @@ model_info = { "tokenizer": tokenizer_gpt35, "token_cnt": get_token_num_gpt35, }, - + "gpt-3.5-turbo-16k": { "fn_with_ui": chatgpt_ui, "fn_without_ui": chatgpt_noui, "endpoint": openai_endpoint, - "max_token": 16385, + "max_token": 1024*16, "tokenizer": tokenizer_gpt35, "token_cnt": get_token_num_gpt35, }, @@ -121,16 +111,7 @@ model_info = { "fn_with_ui": chatgpt_ui, "fn_without_ui": chatgpt_noui, "endpoint": openai_endpoint, - "max_token": 16385, - "tokenizer": tokenizer_gpt35, - "token_cnt": get_token_num_gpt35, - }, - - "gpt-3.5-turbo-1106": {#16k - "fn_with_ui": chatgpt_ui, - "fn_without_ui": chatgpt_noui, - "endpoint": openai_endpoint, - "max_token": 16385, + "max_token": 1024 * 16, "tokenizer": tokenizer_gpt35, "token_cnt": get_token_num_gpt35, }, @@ -144,61 +125,6 @@ model_info = { "token_cnt": get_token_num_gpt4, }, - "gpt-4-32k": { - "fn_with_ui": chatgpt_ui, - "fn_without_ui": chatgpt_noui, - "endpoint": openai_endpoint, - "max_token": 32768, - "tokenizer": tokenizer_gpt4, - "token_cnt": get_token_num_gpt4, - }, - - "gpt-4-turbo-preview": { - "fn_with_ui": chatgpt_ui, - "fn_without_ui": chatgpt_noui, - "endpoint": openai_endpoint, - "max_token": 128000, - "tokenizer": tokenizer_gpt4, - "token_cnt": get_token_num_gpt4, - }, - - "gpt-4-1106-preview": { - "fn_with_ui": chatgpt_ui, - "fn_without_ui": chatgpt_noui, - "endpoint": openai_endpoint, - "max_token": 128000, - "tokenizer": tokenizer_gpt4, - "token_cnt": get_token_num_gpt4, - }, - - "gpt-4-0125-preview": { - "fn_with_ui": chatgpt_ui, - "fn_without_ui": chatgpt_noui, - "endpoint": openai_endpoint, - "max_token": 128000, - "tokenizer": tokenizer_gpt4, - "token_cnt": get_token_num_gpt4, - }, - - "gpt-3.5-random": { - "fn_with_ui": chatgpt_ui, - "fn_without_ui": chatgpt_noui, - "endpoint": openai_endpoint, - "max_token": 4096, - "tokenizer": tokenizer_gpt4, - "token_cnt": get_token_num_gpt4, - }, - - "gpt-4-vision-preview": { - "fn_with_ui": chatgpt_vision_ui, - "fn_without_ui": chatgpt_vision_noui, - "endpoint": openai_endpoint, - "max_token": 4096, - "tokenizer": tokenizer_gpt4, - "token_cnt": get_token_num_gpt4, - }, - - # azure openai "azure-gpt-3.5":{ "fn_with_ui": chatgpt_ui, @@ -209,34 +135,16 @@ model_info = { "token_cnt": get_token_num_gpt35, }, - "azure-gpt-4":{ + # api_2d + "api2d-gpt-3.5-turbo": { "fn_with_ui": chatgpt_ui, "fn_without_ui": chatgpt_noui, - "endpoint": azure_endpoint, - "max_token": 8192, - "tokenizer": tokenizer_gpt4, - "token_cnt": get_token_num_gpt4, - }, - - # 智谱AI - "glm-4": { - "fn_with_ui": zhipu_ui, - "fn_without_ui": zhipu_noui, - "endpoint": None, - "max_token": 10124 * 8, - "tokenizer": tokenizer_gpt35, - "token_cnt": get_token_num_gpt35, - }, - "glm-3-turbo": { - "fn_with_ui": zhipu_ui, - "fn_without_ui": zhipu_noui, - "endpoint": None, - "max_token": 10124 * 4, + "endpoint": api2d_endpoint, + "max_token": 4096, "tokenizer": tokenizer_gpt35, "token_cnt": get_token_num_gpt35, }, - # api_2d (此后不需要在此处添加api2d的接口了,因为下面的代码会自动添加) "api2d-gpt-4": { "fn_with_ui": chatgpt_ui, "fn_without_ui": chatgpt_noui, @@ -263,14 +171,6 @@ model_info = { "tokenizer": tokenizer_gpt35, "token_cnt": get_token_num_gpt35, }, - "chatglm3": { - "fn_with_ui": chatglm3_ui, - "fn_without_ui": chatglm3_noui, - "endpoint": None, - "max_token": 8192, - "tokenizer": tokenizer_gpt35, - "token_cnt": get_token_num_gpt35, - }, "qianfan": { "fn_with_ui": qianfan_ui, "fn_without_ui": qianfan_noui, @@ -279,38 +179,8 @@ 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 对齐支持 -=-=-=-=-=-=- -for model in AVAIL_LLM_MODELS: - if model.startswith('api2d-') and (model.replace('api2d-','') in model_info.keys()): - mi = copy.deepcopy(model_info[model.replace('api2d-','')]) - mi.update({"endpoint": api2d_endpoint}) - model_info.update({model: mi}) - -# -=-=-=-=-=-=- azure 对齐支持 -=-=-=-=-=-=- -for model in AVAIL_LLM_MODELS: - if model.startswith('azure-') and (model.replace('azure-','') in model_info.keys()): - mi = copy.deepcopy(model_info[model.replace('azure-','')]) - mi.update({"endpoint": azure_endpoint}) - model_info.update({model: mi}) - # -=-=-=-=-=-=- 以下部分是新加入的模型,可能附带额外依赖 -=-=-=-=-=-=- if "claude-1-100k" in AVAIL_LLM_MODELS or "claude-2" in AVAIL_LLM_MODELS: from .bridge_claude import predict_no_ui_long_connection as claude_noui @@ -480,63 +350,31 @@ if "chatglm_onnx" in AVAIL_LLM_MODELS: }) except: print(trimmed_format_exc()) -if "qwen-local" in AVAIL_LLM_MODELS: - try: - from .bridge_qwen_local import predict_no_ui_long_connection as qwen_local_noui - from .bridge_qwen_local import predict as qwen_local_ui - model_info.update({ - "qwen-local": { - "fn_with_ui": qwen_local_ui, - "fn_without_ui": qwen_local_noui, - "endpoint": None, - "max_token": 4096, - "tokenizer": tokenizer_gpt35, - "token_cnt": get_token_num_gpt35, - } - }) - except: - print(trimmed_format_exc()) -if "qwen-turbo" in AVAIL_LLM_MODELS or "qwen-plus" in AVAIL_LLM_MODELS or "qwen-max" in AVAIL_LLM_MODELS: # zhipuai +if "qwen" in AVAIL_LLM_MODELS: try: from .bridge_qwen import predict_no_ui_long_connection as qwen_noui from .bridge_qwen import predict as qwen_ui model_info.update({ - "qwen-turbo": { - "fn_with_ui": qwen_ui, - "fn_without_ui": qwen_noui, - "endpoint": None, - "max_token": 6144, - "tokenizer": tokenizer_gpt35, - "token_cnt": get_token_num_gpt35, - }, - "qwen-plus": { + "qwen": { "fn_with_ui": qwen_ui, "fn_without_ui": qwen_noui, "endpoint": None, - "max_token": 30720, - "tokenizer": tokenizer_gpt35, - "token_cnt": get_token_num_gpt35, - }, - "qwen-max": { - "fn_with_ui": qwen_ui, - "fn_without_ui": qwen_noui, - "endpoint": None, - "max_token": 28672, + "max_token": 4096, "tokenizer": tokenizer_gpt35, "token_cnt": get_token_num_gpt35, } }) except: print(trimmed_format_exc()) -if "spark" in AVAIL_LLM_MODELS: # 讯飞星火认知大模型 +if "chatgpt_website" in AVAIL_LLM_MODELS: # 接入一些逆向工程https://github.com/acheong08/ChatGPT-to-API/ try: - from .bridge_spark import predict_no_ui_long_connection as spark_noui - from .bridge_spark import predict as spark_ui + from .bridge_chatgpt_website import predict_no_ui_long_connection as chatgpt_website_noui + from .bridge_chatgpt_website import predict as chatgpt_website_ui model_info.update({ - "spark": { - "fn_with_ui": spark_ui, - "fn_without_ui": spark_noui, - "endpoint": None, + "chatgpt_website": { + "fn_with_ui": chatgpt_website_ui, + "fn_without_ui": chatgpt_website_noui, + "endpoint": openai_endpoint, "max_token": 4096, "tokenizer": tokenizer_gpt35, "token_cnt": get_token_num_gpt35, @@ -544,12 +382,12 @@ if "spark" in AVAIL_LLM_MODELS: # 讯飞星火认知大模型 }) except: print(trimmed_format_exc()) -if "sparkv2" in AVAIL_LLM_MODELS: # 讯飞星火认知大模型 +if "spark" in AVAIL_LLM_MODELS: # 讯飞星火认知大模型 try: from .bridge_spark import predict_no_ui_long_connection as spark_noui from .bridge_spark import predict as spark_ui model_info.update({ - "sparkv2": { + "spark": { "fn_with_ui": spark_ui, "fn_without_ui": spark_noui, "endpoint": None, @@ -560,20 +398,12 @@ if "sparkv2" in AVAIL_LLM_MODELS: # 讯飞星火认知大模型 }) except: print(trimmed_format_exc()) -if "sparkv3" in AVAIL_LLM_MODELS or "sparkv3.5" in AVAIL_LLM_MODELS: # 讯飞星火认知大模型 +if "sparkv2" in AVAIL_LLM_MODELS: # 讯飞星火认知大模型 try: from .bridge_spark import predict_no_ui_long_connection as spark_noui from .bridge_spark import predict as spark_ui model_info.update({ - "sparkv3": { - "fn_with_ui": spark_ui, - "fn_without_ui": spark_noui, - "endpoint": None, - "max_token": 4096, - "tokenizer": tokenizer_gpt35, - "token_cnt": get_token_num_gpt35, - }, - "sparkv3.5": { + "sparkv2": { "fn_with_ui": spark_ui, "fn_without_ui": spark_noui, "endpoint": None, @@ -600,77 +430,6 @@ if "llama2" in AVAIL_LLM_MODELS: # llama2 }) except: print(trimmed_format_exc()) -if "zhipuai" in AVAIL_LLM_MODELS: # zhipuai 是glm-4的别名,向后兼容配置 - try: - model_info.update({ - "zhipuai": { - "fn_with_ui": zhipu_ui, - "fn_without_ui": zhipu_noui, - "endpoint": None, - "max_token": 10124 * 8, - "tokenizer": tokenizer_gpt35, - "token_cnt": get_token_num_gpt35, - }, - }) - except: - print(trimmed_format_exc()) -if "deepseekcoder" in AVAIL_LLM_MODELS: # deepseekcoder - try: - from .bridge_deepseekcoder import predict_no_ui_long_connection as deepseekcoder_noui - from .bridge_deepseekcoder import predict as deepseekcoder_ui - model_info.update({ - "deepseekcoder": { - "fn_with_ui": deepseekcoder_ui, - "fn_without_ui": deepseekcoder_noui, - "endpoint": None, - "max_token": 2048, - "tokenizer": tokenizer_gpt35, - "token_cnt": get_token_num_gpt35, - } - }) - except: - print(trimmed_format_exc()) -# if "skylark" in AVAIL_LLM_MODELS: -# try: -# from .bridge_skylark2 import predict_no_ui_long_connection as skylark_noui -# from .bridge_skylark2 import predict as skylark_ui -# model_info.update({ -# "skylark": { -# "fn_with_ui": skylark_ui, -# "fn_without_ui": skylark_noui, -# "endpoint": None, -# "max_token": 4096, -# "tokenizer": tokenizer_gpt35, -# "token_cnt": get_token_num_gpt35, -# } -# }) -# except: -# print(trimmed_format_exc()) - - -# <-- 用于定义和切换多个azure模型 --> -AZURE_CFG_ARRAY = get_conf("AZURE_CFG_ARRAY") -if len(AZURE_CFG_ARRAY) > 0: - for azure_model_name, azure_cfg_dict in AZURE_CFG_ARRAY.items(): - # 可能会覆盖之前的配置,但这是意料之中的 - if not azure_model_name.startswith('azure'): - raise ValueError("AZURE_CFG_ARRAY中配置的模型必须以azure开头") - endpoint_ = azure_cfg_dict["AZURE_ENDPOINT"] + \ - f'openai/deployments/{azure_cfg_dict["AZURE_ENGINE"]}/chat/completions?api-version=2023-05-15' - model_info.update({ - azure_model_name: { - "fn_with_ui": chatgpt_ui, - "fn_without_ui": chatgpt_noui, - "endpoint": endpoint_, - "azure_api_key": azure_cfg_dict["AZURE_API_KEY"], - "max_token": azure_cfg_dict["AZURE_MODEL_MAX_TOKEN"], - "tokenizer": tokenizer_gpt35, # tokenizer只用于粗估token数量 - "token_cnt": get_token_num_gpt35, - } - }) - if azure_model_name not in AVAIL_LLM_MODELS: - AVAIL_LLM_MODELS += [azure_model_name] - @@ -688,7 +447,7 @@ def LLM_CATCH_EXCEPTION(f): return decorated -def predict_no_ui_long_connection(inputs, llm_kwargs, history, sys_prompt, observe_window=[], console_slience=False): +def predict_no_ui_long_connection(inputs, llm_kwargs, history, sys_prompt, observe_window, console_slience=False): """ 发送至LLM,等待回复,一次性完成,不显示中间过程。但内部用stream的方法避免中途网线被掐。 inputs: @@ -704,7 +463,6 @@ def predict_no_ui_long_connection(inputs, llm_kwargs, history, sys_prompt, obser """ import threading, time, copy - inputs = apply_gpt_academic_string_mask(inputs, mode="show_llm") model = llm_kwargs['llm_model'] n_model = 1 if '&' not in model: @@ -719,7 +477,7 @@ def predict_no_ui_long_connection(inputs, llm_kwargs, history, sys_prompt, obser executor = ThreadPoolExecutor(max_workers=4) models = model.split('&') n_model = len(models) - + window_len = len(observe_window) assert window_len==3 window_mutex = [["", time.time(), ""] for _ in range(n_model)] + [True] @@ -738,7 +496,7 @@ def predict_no_ui_long_connection(inputs, llm_kwargs, history, sys_prompt, obser time.sleep(0.25) if not window_mutex[-1]: break # 看门狗(watchdog) - for i in range(n_model): + for i in range(n_model): window_mutex[i][1] = observe_window[1] # 观察窗(window) chat_string = [] @@ -778,7 +536,6 @@ def predict(inputs, llm_kwargs, *args, **kwargs): additional_fn代表点击的哪个按钮,按钮见functional.py """ - inputs = apply_gpt_academic_string_mask(inputs, mode="show_llm") method = model_info[llm_kwargs['llm_model']]["fn_with_ui"] # 如果这里报错,检查config中的AVAIL_LLM_MODELS选项 yield from method(inputs, llm_kwargs, *args, **kwargs) diff --git a/request_llm/bridge_azure_test.py b/request_llm/bridge_azure_test.py new file mode 100644 index 0000000000000000000000000000000000000000..edc68f747d650e20a9e42d65dbcac1923d5cb192 --- /dev/null +++ b/request_llm/bridge_azure_test.py @@ -0,0 +1,241 @@ +""" + 该文件中主要包含三个函数 + + 不具备多线程能力的函数: + 1. predict: 正常对话时使用,具备完备的交互功能,不可多线程 + + 具备多线程调用能力的函数 + 2. predict_no_ui:高级实验性功能模块调用,不会实时显示在界面上,参数简单,可以多线程并行,方便实现复杂的功能逻辑 + 3. predict_no_ui_long_connection:在实验过程中发现调用predict_no_ui处理长文档时,和openai的连接容易断掉,这个函数用stream的方式解决这个问题,同样支持多线程 +""" + +import logging +import traceback +import importlib +import openai +import time + + +# 读取config.py文件中关于AZURE OPENAI API的信息 +from toolbox import get_conf, update_ui, clip_history, trimmed_format_exc +TIMEOUT_SECONDS, MAX_RETRY, AZURE_ENGINE, AZURE_ENDPOINT, AZURE_API_VERSION, AZURE_API_KEY = \ + get_conf('TIMEOUT_SECONDS', 'MAX_RETRY',"AZURE_ENGINE","AZURE_ENDPOINT", "AZURE_API_VERSION", "AZURE_API_KEY") + + +def get_full_error(chunk, stream_response): + """ + 获取完整的从Openai返回的报错 + """ + while True: + try: + chunk += next(stream_response) + except: + break + return chunk + +def predict(inputs, llm_kwargs, plugin_kwargs, chatbot, history=[], system_prompt='', stream = True, additional_fn=None): + """ + 发送至azure openai api,流式获取输出。 + 用于基础的对话功能。 + inputs 是本次问询的输入 + top_p, temperature是chatGPT的内部调优参数 + history 是之前的对话列表(注意无论是inputs还是history,内容太长了都会触发token数量溢出的错误) + chatbot 为WebUI中显示的对话列表,修改它,然后yeild出去,可以直接修改对话界面内容 + additional_fn代表点击的哪个按钮,按钮见functional.py + """ + print(llm_kwargs["llm_model"]) + + if additional_fn is not None: + import core_functional + importlib.reload(core_functional) # 热更新prompt + core_functional = core_functional.get_core_functions() + if "PreProcess" in core_functional[additional_fn]: inputs = core_functional[additional_fn]["PreProcess"](inputs) # 获取预处理函数(如果有的话) + inputs = core_functional[additional_fn]["Prefix"] + inputs + core_functional[additional_fn]["Suffix"] + + raw_input = inputs + logging.info(f'[raw_input] {raw_input}') + chatbot.append((inputs, "")) + yield from update_ui(chatbot=chatbot, history=history, msg="等待响应") # 刷新界面 + + + payload = generate_azure_payload(inputs, llm_kwargs, history, system_prompt, stream) + + history.append(inputs); history.append("") + + retry = 0 + while True: + try: + + openai.api_type = "azure" + openai.api_version = AZURE_API_VERSION + openai.api_base = AZURE_ENDPOINT + openai.api_key = AZURE_API_KEY + response = openai.ChatCompletion.create(timeout=TIMEOUT_SECONDS, **payload);break + + except: + retry += 1 + chatbot[-1] = ((chatbot[-1][0], "获取response失败,重试中。。。")) + 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 = "" + is_head_of_the_stream = True + if stream: + + stream_response = response + + while True: + try: + chunk = next(stream_response) + + except StopIteration: + from toolbox import regular_txt_to_markdown; tb_str = '```\n' + trimmed_format_exc() + '```' + chatbot[-1] = (chatbot[-1][0], f"[Local Message] 远程返回错误: \n\n{tb_str} \n\n{regular_txt_to_markdown(chunk)}") + yield from update_ui(chatbot=chatbot, history=history, msg="远程返回错误:" + chunk) # 刷新界面 + return + + if is_head_of_the_stream and (r'"object":"error"' not in chunk): + # 数据流的第一帧不携带content + is_head_of_the_stream = False; continue + + if chunk: + #print(chunk) + try: + if "delta" in chunk["choices"][0]: + if chunk["choices"][0]["finish_reason"] == "stop": + logging.info(f'[response] {gpt_replying_buffer}') + break + status_text = f"finish_reason: {chunk['choices'][0]['finish_reason']}" + gpt_replying_buffer = gpt_replying_buffer + chunk["choices"][0]["delta"]["content"] + + history[-1] = gpt_replying_buffer + chatbot[-1] = (history[-2], history[-1]) + yield from update_ui(chatbot=chatbot, history=history, msg=status_text) # 刷新界面 + + except Exception as e: + traceback.print_exc() + yield from update_ui(chatbot=chatbot, history=history, msg="Json解析不合常规") # 刷新界面 + chunk = get_full_error(chunk, stream_response) + + error_msg = chunk + yield from update_ui(chatbot=chatbot, history=history, msg="Json异常" + error_msg) # 刷新界面 + return + + +def predict_no_ui_long_connection(inputs, llm_kwargs, history=[], sys_prompt="", observe_window=None, console_slience=False): + """ + 发送至AZURE OPENAI API,等待回复,一次性完成,不显示中间过程。但内部用stream的方法避免中途网线被掐。 + inputs: + 是本次问询的输入 + sys_prompt: + 系统静默prompt + llm_kwargs: + chatGPT的内部调优参数 + history: + 是之前的对话列表 + observe_window = None: + 用于负责跨越线程传递已经输出的部分,大部分时候仅仅为了fancy的视觉效果,留空即可。observe_window[0]:观测窗。observe_window[1]:看门狗 + """ + watch_dog_patience = 5 # 看门狗的耐心, 设置5秒即可 + payload = generate_azure_payload(inputs, llm_kwargs, history, system_prompt=sys_prompt, stream=True) + retry = 0 + while True: + + try: + openai.api_type = "azure" + openai.api_version = AZURE_API_VERSION + openai.api_base = AZURE_ENDPOINT + openai.api_key = AZURE_API_KEY + response = openai.ChatCompletion.create(timeout=TIMEOUT_SECONDS, **payload);break + + except: + retry += 1 + traceback.print_exc() + if retry > MAX_RETRY: raise TimeoutError + if MAX_RETRY!=0: print(f'请求超时,正在重试 ({retry}/{MAX_RETRY}) ……') + + + stream_response = response + result = '' + while True: + try: chunk = next(stream_response) + except StopIteration: + break + except: + chunk = next(stream_response) # 失败了,重试一次?再失败就没办法了。 + + if len(chunk)==0: continue + if not chunk.startswith('data:'): + error_msg = get_full_error(chunk, stream_response) + if "reduce the length" in error_msg: + raise ConnectionAbortedError("AZURE OPENAI API拒绝了请求:" + error_msg) + else: + raise RuntimeError("AZURE OPENAI API拒绝了请求:" + error_msg) + if ('data: [DONE]' in chunk): break + + delta = chunk["delta"] + if len(delta) == 0: break + if "role" in delta: continue + if "content" in delta: + result += delta["content"] + if not console_slience: print(delta["content"], end='') + if observe_window is not None: + # 观测窗,把已经获取的数据显示出去 + if len(observe_window) >= 1: observe_window[0] += delta["content"] + # 看门狗,如果超过期限没有喂狗,则终止 + if len(observe_window) >= 2: + if (time.time()-observe_window[1]) > watch_dog_patience: + raise RuntimeError("用户取消了程序。") + else: raise RuntimeError("意外Json结构:"+delta) + if chunk['finish_reason'] == 'length': + raise ConnectionAbortedError("正常结束,但显示Token不足,导致输出不完整,请削减单次输入的文本量。") + return result + + +def generate_azure_payload(inputs, llm_kwargs, history, system_prompt, stream): + """ + 整合所有信息,选择LLM模型,生成 azure openai api请求,为发送请求做准备 + """ + + conversation_cnt = len(history) // 2 + + messages = [{"role": "system", "content": system_prompt}] + if conversation_cnt: + for index in range(0, 2*conversation_cnt, 2): + what_i_have_asked = {} + what_i_have_asked["role"] = "user" + what_i_have_asked["content"] = history[index] + what_gpt_answer = {} + what_gpt_answer["role"] = "assistant" + what_gpt_answer["content"] = history[index+1] + if what_i_have_asked["content"] != "": + if what_gpt_answer["content"] == "": continue + messages.append(what_i_have_asked) + messages.append(what_gpt_answer) + else: + messages[-1]['content'] = what_gpt_answer['content'] + + what_i_ask_now = {} + what_i_ask_now["role"] = "user" + what_i_ask_now["content"] = inputs + messages.append(what_i_ask_now) + + payload = { + "model": llm_kwargs['llm_model'], + "messages": messages, + "temperature": llm_kwargs['temperature'], # 1.0, + "top_p": llm_kwargs['top_p'], # 1.0, + "n": 1, + "stream": stream, + "presence_penalty": 0, + "frequency_penalty": 0, + "engine": AZURE_ENGINE + } + try: + print(f" {llm_kwargs['llm_model']} : {conversation_cnt} : {inputs[:100]} ..........") + except: + print('输入中可能存在乱码。') + return payload + + diff --git a/request_llm/bridge_chatglm.py b/request_llm/bridge_chatglm.py new file mode 100644 index 0000000000000000000000000000000000000000..6dac86395da134aa896da9d9a7c84ccd94e795d0 --- /dev/null +++ b/request_llm/bridge_chatglm.py @@ -0,0 +1,166 @@ + +from transformers import AutoModel, AutoTokenizer +import time +import threading +import importlib +from toolbox import update_ui, get_conf +from multiprocessing import Process, Pipe + +load_message = "ChatGLM尚未加载,加载需要一段时间。注意,取决于`config.py`的配置,ChatGLM消耗大量的内存(CPU)或显存(GPU),也许会导致低配计算机卡死 ……" + +################################################################################# +class GetGLMHandle(Process): + def __init__(self): + super().__init__(daemon=True) + self.parent, self.child = Pipe() + self.chatglm_model = None + self.chatglm_tokenizer = None + self.info = "" + self.success = True + self.check_dependency() + self.start() + self.threadLock = threading.Lock() + + def check_dependency(self): + try: + import sentencepiece + self.info = "依赖检测通过" + self.success = True + except: + self.info = "缺少ChatGLM的依赖,如果要使用ChatGLM,除了基础的pip依赖以外,您还需要运行`pip install -r request_llm/requirements_chatglm.txt`安装ChatGLM的依赖。" + self.success = False + + def ready(self): + return self.chatglm_model is not None + + def run(self): + # 子进程执行 + # 第一次运行,加载参数 + retry = 0 + LOCAL_MODEL_QUANT, device = get_conf('LOCAL_MODEL_QUANT', 'LOCAL_MODEL_DEVICE') + + if LOCAL_MODEL_QUANT == "INT4": # INT4 + _model_name_ = "THUDM/chatglm2-6b-int4" + elif LOCAL_MODEL_QUANT == "INT8": # INT8 + _model_name_ = "THUDM/chatglm2-6b-int8" + else: + _model_name_ = "THUDM/chatglm2-6b" # FP16 + + while True: + try: + if self.chatglm_model is None: + self.chatglm_tokenizer = AutoTokenizer.from_pretrained(_model_name_, trust_remote_code=True) + if device=='cpu': + self.chatglm_model = AutoModel.from_pretrained(_model_name_, trust_remote_code=True).float() + else: + self.chatglm_model = AutoModel.from_pretrained(_model_name_, trust_remote_code=True).half().cuda() + self.chatglm_model = self.chatglm_model.eval() + break + else: + break + except: + retry += 1 + if retry > 3: + self.child.send('[Local Message] Call ChatGLM fail 不能正常加载ChatGLM的参数。') + raise RuntimeError("不能正常加载ChatGLM的参数!") + + while True: + # 进入任务等待状态 + kwargs = self.child.recv() + # 收到消息,开始请求 + try: + for response, history in self.chatglm_model.stream_chat(self.chatglm_tokenizer, **kwargs): + self.child.send(response) + # # 中途接收可能的终止指令(如果有的话) + # if self.child.poll(): + # command = self.child.recv() + # if command == '[Terminate]': break + except: + from toolbox import trimmed_format_exc + self.child.send('[Local Message] Call ChatGLM fail.' + '\n```\n' + trimmed_format_exc() + '\n```\n') + # 请求处理结束,开始下一个循环 + self.child.send('[Finish]') + + def stream_chat(self, **kwargs): + # 主进程执行 + self.threadLock.acquire() + self.parent.send(kwargs) + while True: + res = self.parent.recv() + if res != '[Finish]': + yield res + else: + break + self.threadLock.release() + +global glm_handle +glm_handle = None +################################################################################# +def predict_no_ui_long_connection(inputs, llm_kwargs, history=[], sys_prompt="", observe_window=[], console_slience=False): + """ + 多线程方法 + 函数的说明请见 request_llm/bridge_all.py + """ + global glm_handle + if glm_handle is None: + glm_handle = GetGLMHandle() + if len(observe_window) >= 1: observe_window[0] = load_message + "\n\n" + glm_handle.info + if not glm_handle.success: + error = glm_handle.info + glm_handle = None + raise RuntimeError(error) + + # chatglm 没有 sys_prompt 接口,因此把prompt加入 history + history_feedin = [] + history_feedin.append(["What can I do?", sys_prompt]) + for i in range(len(history)//2): + history_feedin.append([history[2*i], history[2*i+1]] ) + + watch_dog_patience = 5 # 看门狗 (watchdog) 的耐心, 设置5秒即可 + response = "" + for response in glm_handle.stream_chat(query=inputs, history=history_feedin, max_length=llm_kwargs['max_length'], top_p=llm_kwargs['top_p'], temperature=llm_kwargs['temperature']): + if len(observe_window) >= 1: observe_window[0] = response + if len(observe_window) >= 2: + if (time.time()-observe_window[1]) > watch_dog_patience: + raise RuntimeError("程序终止。") + return response + + + +def predict(inputs, llm_kwargs, plugin_kwargs, chatbot, history=[], system_prompt='', stream = True, additional_fn=None): + """ + 单线程方法 + 函数的说明请见 request_llm/bridge_all.py + """ + chatbot.append((inputs, "")) + + global glm_handle + if glm_handle is None: + glm_handle = GetGLMHandle() + chatbot[-1] = (inputs, load_message + "\n\n" + glm_handle.info) + yield from update_ui(chatbot=chatbot, history=[]) + if not glm_handle.success: + glm_handle = None + return + + if additional_fn is not None: + from core_functional import handle_core_functionality + inputs, history = handle_core_functionality(additional_fn, inputs, history, chatbot) + + # 处理历史信息 + history_feedin = [] + history_feedin.append(["What can I do?", system_prompt] ) + for i in range(len(history)//2): + history_feedin.append([history[2*i], history[2*i+1]] ) + + # 开始接收chatglm的回复 + response = "[Local Message]: 等待ChatGLM响应中 ..." + for response in glm_handle.stream_chat(query=inputs, history=history_feedin, max_length=llm_kwargs['max_length'], top_p=llm_kwargs['top_p'], temperature=llm_kwargs['temperature']): + chatbot[-1] = (inputs, response) + yield from update_ui(chatbot=chatbot, history=history) + + # 总结输出 + if response == "[Local Message]: 等待ChatGLM响应中 ...": + response = "[Local Message]: ChatGLM响应异常 ..." + history.extend([inputs, response]) + yield from update_ui(chatbot=chatbot, history=history) diff --git a/request_llms/bridge_chatglmft.py b/request_llm/bridge_chatglmft.py similarity index 93% rename from request_llms/bridge_chatglmft.py rename to request_llm/bridge_chatglmft.py index d812bae3c36dc22e6c40e78b54e0fbbda665e989..71af94213e1824f8c664d5759812b6057d3b29a2 100644 --- a/request_llms/bridge_chatglmft.py +++ b/request_llm/bridge_chatglmft.py @@ -44,7 +44,7 @@ class GetGLMFTHandle(Process): self.info = "依赖检测通过" self.success = True except: - self.info = "缺少ChatGLMFT的依赖,如果要使用ChatGLMFT,除了基础的pip依赖以外,您还需要运行`pip install -r request_llms/requirements_chatglm.txt`安装ChatGLM的依赖。" + self.info = "缺少ChatGLMFT的依赖,如果要使用ChatGLMFT,除了基础的pip依赖以外,您还需要运行`pip install -r request_llm/requirements_chatglm.txt`安装ChatGLM的依赖。" self.success = False def ready(self): @@ -59,11 +59,11 @@ class GetGLMFTHandle(Process): if self.chatglmft_model is None: from transformers import AutoConfig import torch - # conf = 'request_llms/current_ptune_model.json' + # conf = 'request_llm/current_ptune_model.json' # if not os.path.exists(conf): raise RuntimeError('找不到微调模型信息') # with open(conf, 'r', encoding='utf8') as f: # model_args = json.loads(f.read()) - CHATGLM_PTUNING_CHECKPOINT = get_conf('CHATGLM_PTUNING_CHECKPOINT') + CHATGLM_PTUNING_CHECKPOINT, = get_conf('CHATGLM_PTUNING_CHECKPOINT') assert os.path.exists(CHATGLM_PTUNING_CHECKPOINT), "找不到微调模型检查点" conf = os.path.join(CHATGLM_PTUNING_CHECKPOINT, "config.json") with open(conf, 'r', encoding='utf8') as f: @@ -87,7 +87,7 @@ class GetGLMFTHandle(Process): new_prefix_state_dict[k[len("transformer.prefix_encoder."):]] = v model.transformer.prefix_encoder.load_state_dict(new_prefix_state_dict) - if model_args['quantization_bit'] is not None and model_args['quantization_bit'] != 0: + if model_args['quantization_bit'] is not None: print(f"Quantized to {model_args['quantization_bit']} bit") model = model.quantize(model_args['quantization_bit']) model = model.cuda() @@ -140,7 +140,7 @@ glmft_handle = None def predict_no_ui_long_connection(inputs, llm_kwargs, history=[], sys_prompt="", observe_window=[], console_slience=False): """ 多线程方法 - 函数的说明请见 request_llms/bridge_all.py + 函数的说明请见 request_llm/bridge_all.py """ global glmft_handle if glmft_handle is None: @@ -171,7 +171,7 @@ def predict_no_ui_long_connection(inputs, llm_kwargs, history=[], sys_prompt="", def predict(inputs, llm_kwargs, plugin_kwargs, chatbot, history=[], system_prompt='', stream = True, additional_fn=None): """ 单线程方法 - 函数的说明请见 request_llms/bridge_all.py + 函数的说明请见 request_llm/bridge_all.py """ chatbot.append((inputs, "")) @@ -195,13 +195,13 @@ def predict(inputs, llm_kwargs, plugin_kwargs, chatbot, history=[], system_promp history_feedin.append([history[2*i], history[2*i+1]] ) # 开始接收chatglmft的回复 - response = "[Local Message] 等待ChatGLMFT响应中 ..." + response = "[Local Message]: 等待ChatGLMFT响应中 ..." for response in glmft_handle.stream_chat(query=inputs, history=history_feedin, max_length=llm_kwargs['max_length'], top_p=llm_kwargs['top_p'], temperature=llm_kwargs['temperature']): chatbot[-1] = (inputs, response) yield from update_ui(chatbot=chatbot, history=history) # 总结输出 - if response == "[Local Message] 等待ChatGLMFT响应中 ...": - response = "[Local Message] ChatGLMFT响应异常 ..." + if response == "[Local Message]: 等待ChatGLMFT响应中 ...": + response = "[Local Message]: ChatGLMFT响应异常 ..." history.extend([inputs, response]) yield from update_ui(chatbot=chatbot, history=history) diff --git a/request_llms/bridge_chatglmonnx.py b/request_llm/bridge_chatglmonnx.py similarity index 82% rename from request_llms/bridge_chatglmonnx.py rename to request_llm/bridge_chatglmonnx.py index 4b905718f63089c1355d244d61c67df07c3dc521..594bcca15f04c7d9790da95fee2a1d51252c07d1 100644 --- a/request_llms/bridge_chatglmonnx.py +++ b/request_llm/bridge_chatglmonnx.py @@ -1,5 +1,5 @@ model_name = "ChatGLM-ONNX" -cmd_to_install = "`pip install -r request_llms/requirements_chatglm_onnx.txt`" +cmd_to_install = "`pip install -r request_llm/requirements_chatglm_onnx.txt`" from transformers import AutoModel, AutoTokenizer @@ -8,7 +8,7 @@ import threading import importlib from toolbox import update_ui, get_conf from multiprocessing import Process, Pipe -from .local_llm_class import LocalLLMHandle, get_local_llm_predict_fns +from .local_llm_class import LocalLLMHandle, get_local_llm_predict_fns, SingletonLocalLLM from .chatglmoonx import ChatGLMModel, chat_template @@ -17,6 +17,7 @@ from .chatglmoonx import ChatGLMModel, chat_template # ------------------------------------------------------------------------------------------------------------------------ # 🔌💻 Local Model # ------------------------------------------------------------------------------------------------------------------------ +@SingletonLocalLLM class GetONNXGLMHandle(LocalLLMHandle): def load_model_info(self): @@ -27,13 +28,13 @@ class GetONNXGLMHandle(LocalLLMHandle): def load_model_and_tokenizer(self): # 🏃‍♂️🏃‍♂️🏃‍♂️ 子进程执行 import os, glob - if not len(glob.glob("./request_llms/ChatGLM-6b-onnx-u8s8/chatglm-6b-int8-onnx-merged/*.bin")) >= 7: # 该模型有七个 bin 文件 + if not len(glob.glob("./request_llm/ChatGLM-6b-onnx-u8s8/chatglm-6b-int8-onnx-merged/*.bin")) >= 7: # 该模型有七个 bin 文件 from huggingface_hub import snapshot_download - snapshot_download(repo_id="K024/ChatGLM-6b-onnx-u8s8", local_dir="./request_llms/ChatGLM-6b-onnx-u8s8") + snapshot_download(repo_id="K024/ChatGLM-6b-onnx-u8s8", local_dir="./request_llm/ChatGLM-6b-onnx-u8s8") def create_model(): return ChatGLMModel( - tokenizer_path = "./request_llms/ChatGLM-6b-onnx-u8s8/chatglm-6b-int8-onnx-merged/sentencepiece.model", - onnx_model_path = "./request_llms/ChatGLM-6b-onnx-u8s8/chatglm-6b-int8-onnx-merged/chatglm-6b-int8.onnx" + tokenizer_path = "./request_llm/ChatGLM-6b-onnx-u8s8/chatglm-6b-int8-onnx-merged/sentencepiece.model", + onnx_model_path = "./request_llm/ChatGLM-6b-onnx-u8s8/chatglm-6b-int8-onnx-merged/chatglm-6b-int8.onnx" ) self._model = create_model() return self._model, None diff --git a/request_llms/bridge_chatgpt.py b/request_llm/bridge_chatgpt.py similarity index 74% rename from request_llms/bridge_chatgpt.py rename to request_llm/bridge_chatgpt.py index ecb8423b4621dfe4ccedf3c679e8b007389112ab..a1b6ba47d3e91790ad50e8de9a583267ae4dd3ec 100644 --- a/request_llms/bridge_chatgpt.py +++ b/request_llm/bridge_chatgpt.py @@ -7,7 +7,8 @@ 1. predict: 正常对话时使用,具备完备的交互功能,不可多线程 具备多线程调用能力的函数 - 2. predict_no_ui_long_connection:支持多线程 + 2. predict_no_ui:高级实验性功能模块调用,不会实时显示在界面上,参数简单,可以多线程并行,方便实现复杂的功能逻辑 + 3. predict_no_ui_long_connection:在实验过程中发现调用predict_no_ui处理长文档时,和openai的连接容易断掉,这个函数用stream的方式解决这个问题,同样支持多线程 """ import json @@ -17,13 +18,12 @@ import logging import traceback import requests import importlib -import random # config_private.py放自己的秘密如API和代理网址 # 读取时首先看是否存在私密的config_private配置文件(不受git管控),如果有,则覆盖原config文件 from toolbox import get_conf, update_ui, is_any_api_key, select_api_key, what_keys, clip_history, trimmed_format_exc, is_the_upload_folder -proxies, TIMEOUT_SECONDS, MAX_RETRY, API_ORG, AZURE_CFG_ARRAY = \ - get_conf('proxies', 'TIMEOUT_SECONDS', 'MAX_RETRY', 'API_ORG', 'AZURE_CFG_ARRAY') +proxies, TIMEOUT_SECONDS, MAX_RETRY, API_ORG = \ + get_conf('proxies', 'TIMEOUT_SECONDS', 'MAX_RETRY', 'API_ORG') timeout_bot_msg = '[Local Message] Request timeout. Network error. Please check proxy settings in config.py.' + \ '网络错误,检查代理服务器是否可用,以及代理设置的格式是否正确,格式须是[协议]://[地址]:[端口],缺一不可。' @@ -39,34 +39,6 @@ def get_full_error(chunk, stream_response): break return chunk -def decode_chunk(chunk): - # 提前读取一些信息 (用于判断异常) - chunk_decoded = chunk.decode() - chunkjson = None - has_choices = False - choice_valid = False - has_content = False - has_role = False - try: - chunkjson = json.loads(chunk_decoded[6:]) - has_choices = 'choices' in chunkjson - if has_choices: choice_valid = (len(chunkjson['choices']) > 0) - if has_choices and choice_valid: has_content = ("content" in chunkjson['choices'][0]["delta"]) - if has_content: has_content = (chunkjson['choices'][0]["delta"]["content"] is not None) - if has_choices and choice_valid: has_role = "role" in chunkjson['choices'][0]["delta"] - except: - pass - return chunk_decoded, chunkjson, has_choices, choice_valid, has_content, has_role - -from functools import lru_cache -@lru_cache(maxsize=32) -def verify_endpoint(endpoint): - """ - 检查endpoint是否可用 - """ - if "你亲手写的api名称" in endpoint: - raise ValueError("Endpoint不正确, 请检查AZURE_ENDPOINT的配置! 当前的Endpoint为:" + endpoint) - return endpoint def predict_no_ui_long_connection(inputs, llm_kwargs, history=[], sys_prompt="", observe_window=None, console_slience=False): """ @@ -89,7 +61,7 @@ def predict_no_ui_long_connection(inputs, llm_kwargs, history=[], sys_prompt="", try: # make a POST request to the API endpoint, stream=False from .bridge_all import model_info - endpoint = verify_endpoint(model_info[llm_kwargs['llm_model']]['endpoint']) + endpoint = model_info[llm_kwargs['llm_model']]['endpoint'] response = requests.post(endpoint, headers=headers, proxies=proxies, json=payload, stream=True, timeout=TIMEOUT_SECONDS); break except requests.exceptions.ReadTimeout as e: @@ -98,31 +70,24 @@ def predict_no_ui_long_connection(inputs, llm_kwargs, history=[], sys_prompt="", if retry > MAX_RETRY: raise TimeoutError if MAX_RETRY!=0: print(f'请求超时,正在重试 ({retry}/{MAX_RETRY}) ……') - stream_response = response.iter_lines() + stream_response = response.iter_lines() result = '' json_data = None while True: - try: chunk = next(stream_response) + try: chunk = next(stream_response).decode() except StopIteration: break except requests.exceptions.ConnectionError: - chunk = next(stream_response) # 失败了,重试一次?再失败就没办法了。 - chunk_decoded, chunkjson, has_choices, choice_valid, has_content, has_role = decode_chunk(chunk) - if len(chunk_decoded)==0: continue - if not chunk_decoded.startswith('data:'): - error_msg = get_full_error(chunk, stream_response).decode() + chunk = next(stream_response).decode() # 失败了,重试一次?再失败就没办法了。 + if len(chunk)==0: continue + if not chunk.startswith('data:'): + error_msg = get_full_error(chunk.encode('utf8'), stream_response).decode() if "reduce the length" in error_msg: raise ConnectionAbortedError("OpenAI拒绝了请求:" + error_msg) - elif """type":"upstream_error","param":"307""" in error_msg: - raise ConnectionAbortedError("正常结束,但显示Token不足,导致输出不完整,请削减单次输入的文本量。") else: raise RuntimeError("OpenAI拒绝了请求:" + error_msg) - if ('data: [DONE]' in chunk_decoded): break # api2d 正常完成 - # 提前读取一些信息 (用于判断异常) - if has_choices and not choice_valid: - # 一些垃圾第三方接口的出现这样的错误 - continue - json_data = chunkjson['choices'][0] + if ('data: [DONE]' in chunk): break # api2d 正常完成 + json_data = json.loads(chunk.lstrip('data:'))['choices'][0] delta = json_data["delta"] if len(delta) == 0: break if "role" in delta: continue @@ -188,22 +153,14 @@ def predict(inputs, llm_kwargs, plugin_kwargs, chatbot, history=[], system_promp yield from update_ui(chatbot=chatbot, history=history, msg="api-key不满足要求") # 刷新界面 return - # 检查endpoint是否合法 - try: - from .bridge_all import model_info - endpoint = verify_endpoint(model_info[llm_kwargs['llm_model']]['endpoint']) - except: - tb_str = '```\n' + trimmed_format_exc() + '```' - chatbot[-1] = (inputs, tb_str) - yield from update_ui(chatbot=chatbot, history=history, msg="Endpoint不满足要求") # 刷新界面 - return - history.append(inputs); history.append("") retry = 0 while True: try: # make a POST request to the API endpoint, stream=True + from .bridge_all import model_info + endpoint = model_info[llm_kwargs['llm_model']]['endpoint'] response = requests.post(endpoint, headers=headers, proxies=proxies, json=payload, stream=True, timeout=TIMEOUT_SECONDS);break except: @@ -234,39 +191,23 @@ def predict(inputs, llm_kwargs, plugin_kwargs, chatbot, history=[], system_promp yield from update_ui(chatbot=chatbot, history=history, msg="非OpenAI官方接口返回了错误:" + chunk.decode()) # 刷新界面 return - # 提前读取一些信息 (用于判断异常) - chunk_decoded, chunkjson, has_choices, choice_valid, has_content, has_role = decode_chunk(chunk) - + chunk_decoded = chunk.decode() if is_head_of_the_stream and (r'"object":"error"' not in chunk_decoded) and (r"content" not in chunk_decoded): # 数据流的第一帧不携带content is_head_of_the_stream = False; continue if chunk: try: - if has_choices and not choice_valid: - # 一些垃圾第三方接口的出现这样的错误 - continue - if ('data: [DONE]' not in chunk_decoded) and len(chunk_decoded) > 0 and (chunkjson is None): - # 传递进来一些奇怪的东西 - raise ValueError(f'无法读取以下数据,请检查配置。\n\n{chunk_decoded}') # 前者是API2D的结束条件,后者是OPENAI的结束条件 - if ('data: [DONE]' in chunk_decoded) or (len(chunkjson['choices'][0]["delta"]) == 0): + if ('data: [DONE]' in chunk_decoded) or (len(json.loads(chunk_decoded[6:])['choices'][0]["delta"]) == 0): # 判定为数据流的结束,gpt_replying_buffer也写完了 logging.info(f'[response] {gpt_replying_buffer}') break # 处理数据流的主体 + chunkjson = json.loads(chunk_decoded[6:]) status_text = f"finish_reason: {chunkjson['choices'][0].get('finish_reason', 'null')}" # 如果这里抛出异常,一般是文本过长,详情见get_full_error的输出 - if has_content: - # 正常情况 - gpt_replying_buffer = gpt_replying_buffer + chunkjson['choices'][0]["delta"]["content"] - elif has_role: - # 一些第三方接口的出现这样的错误,兼容一下吧 - continue - else: - # 一些垃圾第三方接口的出现这样的错误 - gpt_replying_buffer = gpt_replying_buffer + chunkjson['choices'][0]["delta"]["content"] - + gpt_replying_buffer = gpt_replying_buffer + chunkjson['choices'][0]["delta"]["content"] history[-1] = gpt_replying_buffer chatbot[-1] = (history[-2], history[-1]) yield from update_ui(chatbot=chatbot, history=history, msg=status_text) # 刷新界面 @@ -298,8 +239,6 @@ def handle_error(inputs, llm_kwargs, chatbot, history, chunk_decoded, error_msg) chatbot[-1] = (chatbot[-1][0], "[Local Message] Your account is not active. OpenAI以账户失效为由, 拒绝服务." + openai_website) elif "associated with a deactivated account" in error_msg: chatbot[-1] = (chatbot[-1][0], "[Local Message] You are associated with a deactivated account. OpenAI以账户失效为由, 拒绝服务." + openai_website) - elif "API key has been deactivated" in error_msg: - chatbot[-1] = (chatbot[-1][0], "[Local Message] API key has been deactivated. OpenAI以账户失效为由, 拒绝服务." + openai_website) elif "bad forward key" in error_msg: chatbot[-1] = (chatbot[-1][0], "[Local Message] Bad forward key. API2D账户额度不足.") elif "Not enough point" in error_msg: @@ -324,11 +263,7 @@ def generate_payload(inputs, llm_kwargs, history, system_prompt, stream): "Authorization": f"Bearer {api_key}" } if API_ORG.startswith('org-'): headers.update({"OpenAI-Organization": API_ORG}) - if llm_kwargs['llm_model'].startswith('azure-'): - headers.update({"api-key": api_key}) - if llm_kwargs['llm_model'] in AZURE_CFG_ARRAY.keys(): - azure_api_key_unshared = AZURE_CFG_ARRAY[llm_kwargs['llm_model']]["AZURE_API_KEY"] - headers.update({"api-key": azure_api_key_unshared}) + if llm_kwargs['llm_model'].startswith('azure-'): headers.update({"api-key": api_key}) conversation_cnt = len(history) // 2 @@ -353,23 +288,9 @@ def generate_payload(inputs, llm_kwargs, history, system_prompt, stream): what_i_ask_now["role"] = "user" what_i_ask_now["content"] = inputs messages.append(what_i_ask_now) - model = llm_kwargs['llm_model'] - if llm_kwargs['llm_model'].startswith('api2d-'): - model = llm_kwargs['llm_model'][len('api2d-'):] - - if model == "gpt-3.5-random": # 随机选择, 绕过openai访问频率限制 - model = random.choice([ - "gpt-3.5-turbo", - "gpt-3.5-turbo-16k", - "gpt-3.5-turbo-1106", - "gpt-3.5-turbo-0613", - "gpt-3.5-turbo-16k-0613", - "gpt-3.5-turbo-0301", - ]) - logging.info("Random select model:" + model) payload = { - "model": model, + "model": llm_kwargs['llm_model'].strip('api2d-'), "messages": messages, "temperature": llm_kwargs['temperature'], # 1.0, "top_p": llm_kwargs['top_p'], # 1.0, diff --git a/request_llms/bridge_chatgpt_website.py b/request_llm/bridge_chatgpt_website.py similarity index 97% rename from request_llms/bridge_chatgpt_website.py rename to request_llm/bridge_chatgpt_website.py index f2f0709099961884f0e8f7644d3cfc9a72d11333..7f3147b1d6dfb0c3889b2a21bf9ebcea0b17ca5f 100644 --- a/request_llms/bridge_chatgpt_website.py +++ b/request_llm/bridge_chatgpt_website.py @@ -7,7 +7,8 @@ 1. predict: 正常对话时使用,具备完备的交互功能,不可多线程 具备多线程调用能力的函数 - 2. predict_no_ui_long_connection:支持多线程 + 2. predict_no_ui:高级实验性功能模块调用,不会实时显示在界面上,参数简单,可以多线程并行,方便实现复杂的功能逻辑 + 3. predict_no_ui_long_connection:在实验过程中发现调用predict_no_ui处理长文档时,和openai的连接容易断掉,这个函数用stream的方式解决这个问题,同样支持多线程 """ import json diff --git a/request_llms/bridge_claude.py b/request_llm/bridge_claude.py similarity index 97% rename from request_llms/bridge_claude.py rename to request_llm/bridge_claude.py index 42b75052f80977a29efec1c3755bcbf56ff47d76..6084b1f15c9832fd11a36bb58d8187f4e2a7a931 100644 --- a/request_llms/bridge_claude.py +++ b/request_llm/bridge_claude.py @@ -7,7 +7,7 @@ 1. predict: 正常对话时使用,具备完备的交互功能,不可多线程 具备多线程调用能力的函数 - 2. predict_no_ui_long_connection:支持多线程 + 2. predict_no_ui_long_connection:在实验过程中发现调用predict_no_ui处理长文档时,和openai的连接容易断掉,这个函数用stream的方式解决这个问题,同样支持多线程 """ import os diff --git a/request_llms/bridge_internlm.py b/request_llm/bridge_internlm.py similarity index 91% rename from request_llms/bridge_internlm.py rename to request_llm/bridge_internlm.py index b2be36a4e692b6d6c0513174d13f35c9d055812c..0ec65b641d366b572640f9d9690e1d9ab86ed40b 100644 --- a/request_llms/bridge_internlm.py +++ b/request_llm/bridge_internlm.py @@ -1,13 +1,13 @@ model_name = "InternLM" -cmd_to_install = "`pip install -r request_llms/requirements_chatglm.txt`" +cmd_to_install = "`pip install -r request_llm/requirements_chatglm.txt`" from transformers import AutoModel, AutoTokenizer import time import threading import importlib -from toolbox import update_ui, get_conf, ProxyNetworkActivate +from toolbox import update_ui, get_conf from multiprocessing import Process, Pipe -from .local_llm_class import LocalLLMHandle, get_local_llm_predict_fns +from .local_llm_class import LocalLLMHandle, get_local_llm_predict_fns, SingletonLocalLLM # ------------------------------------------------------------------------------------------------------------------------ @@ -34,6 +34,7 @@ def combine_history(prompt, hist): # ------------------------------------------------------------------------------------------------------------------------ # 🔌💻 Local Model # ------------------------------------------------------------------------------------------------------------------------ +@SingletonLocalLLM class GetInternlmHandle(LocalLLMHandle): def load_model_info(self): @@ -51,16 +52,15 @@ class GetInternlmHandle(LocalLLMHandle): # 🏃‍♂️🏃‍♂️🏃‍♂️ 子进程执行 import torch from transformers import AutoModelForCausalLM, AutoTokenizer - device = get_conf('LOCAL_MODEL_DEVICE') - with ProxyNetworkActivate('Download_LLM'): - if self._model is None: - tokenizer = AutoTokenizer.from_pretrained("internlm/internlm-chat-7b", trust_remote_code=True) - if device=='cpu': - model = AutoModelForCausalLM.from_pretrained("internlm/internlm-chat-7b", trust_remote_code=True).to(torch.bfloat16) - else: - model = AutoModelForCausalLM.from_pretrained("internlm/internlm-chat-7b", trust_remote_code=True).to(torch.bfloat16).cuda() - - model = model.eval() + device, = get_conf('LOCAL_MODEL_DEVICE') + if self._model is None: + tokenizer = AutoTokenizer.from_pretrained("internlm/internlm-chat-7b", trust_remote_code=True) + if device=='cpu': + model = AutoModelForCausalLM.from_pretrained("internlm/internlm-chat-7b", trust_remote_code=True).to(torch.bfloat16) + else: + model = AutoModelForCausalLM.from_pretrained("internlm/internlm-chat-7b", trust_remote_code=True).to(torch.bfloat16).cuda() + + model = model.eval() return model, tokenizer def llm_stream_generator(self, **kwargs): @@ -94,9 +94,8 @@ class GetInternlmHandle(LocalLLMHandle): inputs = tokenizer([prompt], padding=True, return_tensors="pt") input_length = len(inputs["input_ids"][0]) - device = get_conf('LOCAL_MODEL_DEVICE') for k, v in inputs.items(): - inputs[k] = v.to(device) + inputs[k] = v.cuda() input_ids = inputs["input_ids"] batch_size, input_ids_seq_length = input_ids.shape[0], input_ids.shape[-1] if generation_config is None: diff --git a/request_llms/bridge_jittorllms_llama.py b/request_llm/bridge_jittorllms_llama.py similarity index 90% rename from request_llms/bridge_jittorllms_llama.py rename to request_llm/bridge_jittorllms_llama.py index 2d3005e52d327839b08668a6413d462682baa046..d4853578fadff9f572c86f7f0fe79f9c8c8c1474 100644 --- a/request_llms/bridge_jittorllms_llama.py +++ b/request_llm/bridge_jittorllms_llama.py @@ -28,8 +28,8 @@ class GetGLMHandle(Process): self.success = True except: from toolbox import trimmed_format_exc - self.info = r"缺少jittorllms的依赖,如果要使用jittorllms,除了基础的pip依赖以外,您还需要运行`pip install -r request_llms/requirements_jittorllms.txt -i https://pypi.jittor.org/simple -I`"+\ - r"和`git clone https://gitlink.org.cn/jittor/JittorLLMs.git --depth 1 request_llms/jittorllms`两个指令来安装jittorllms的依赖(在项目根目录运行这两个指令)。" +\ + self.info = r"缺少jittorllms的依赖,如果要使用jittorllms,除了基础的pip依赖以外,您还需要运行`pip install -r request_llm/requirements_jittorllms.txt -i https://pypi.jittor.org/simple -I`"+\ + r"和`git clone https://gitlink.org.cn/jittor/JittorLLMs.git --depth 1 request_llm/jittorllms`两个指令来安装jittorllms的依赖(在项目根目录运行这两个指令)。" +\ r"警告:安装jittorllms依赖后将完全破坏现有的pytorch环境,建议使用docker环境!" + trimmed_format_exc() self.success = False @@ -45,15 +45,15 @@ class GetGLMHandle(Process): env = os.environ.get("PATH", "") os.environ["PATH"] = env.replace('/cuda/bin', '/x/bin') root_dir_assume = os.path.abspath(os.path.dirname(__file__) + '/..') - os.chdir(root_dir_assume + '/request_llms/jittorllms') - sys.path.append(root_dir_assume + '/request_llms/jittorllms') + os.chdir(root_dir_assume + '/request_llm/jittorllms') + sys.path.append(root_dir_assume + '/request_llm/jittorllms') validate_path() # validate path so you can run from base directory def load_model(): import types try: if self.jittorllms_model is None: - device = get_conf('LOCAL_MODEL_DEVICE') + device, = get_conf('LOCAL_MODEL_DEVICE') from .jittorllms.models import get_model # availabel_models = ["chatglm", "pangualpha", "llama", "chatrwkv"] args_dict = {'model': 'llama'} @@ -109,7 +109,7 @@ llama_glm_handle = None def predict_no_ui_long_connection(inputs, llm_kwargs, history=[], sys_prompt="", observe_window=[], console_slience=False): """ 多线程方法 - 函数的说明请见 request_llms/bridge_all.py + 函数的说明请见 request_llm/bridge_all.py """ global llama_glm_handle if llama_glm_handle is None: @@ -140,7 +140,7 @@ def predict_no_ui_long_connection(inputs, llm_kwargs, history=[], sys_prompt="", def predict(inputs, llm_kwargs, plugin_kwargs, chatbot, history=[], system_prompt='', stream = True, additional_fn=None): """ 单线程方法 - 函数的说明请见 request_llms/bridge_all.py + 函数的说明请见 request_llm/bridge_all.py """ chatbot.append((inputs, "")) @@ -163,13 +163,13 @@ def predict(inputs, llm_kwargs, plugin_kwargs, chatbot, history=[], system_promp history_feedin.append([history[2*i], history[2*i+1]] ) # 开始接收jittorllms的回复 - response = "[Local Message] 等待jittorllms响应中 ..." + response = "[Local Message]: 等待jittorllms响应中 ..." for response in llama_glm_handle.stream_chat(query=inputs, history=history_feedin, system_prompt=system_prompt, max_length=llm_kwargs['max_length'], top_p=llm_kwargs['top_p'], temperature=llm_kwargs['temperature']): chatbot[-1] = (inputs, response) yield from update_ui(chatbot=chatbot, history=history) # 总结输出 - if response == "[Local Message] 等待jittorllms响应中 ...": - response = "[Local Message] jittorllms响应异常 ..." + if response == "[Local Message]: 等待jittorllms响应中 ...": + response = "[Local Message]: jittorllms响应异常 ..." history.extend([inputs, response]) yield from update_ui(chatbot=chatbot, history=history) diff --git a/request_llms/bridge_jittorllms_pangualpha.py b/request_llm/bridge_jittorllms_pangualpha.py similarity index 90% rename from request_llms/bridge_jittorllms_pangualpha.py rename to request_llm/bridge_jittorllms_pangualpha.py index 26401764c9bab23cc5412253128589b631c4c0b2..20a30213032e957113d6377d7c7f5a9912ea22b1 100644 --- a/request_llms/bridge_jittorllms_pangualpha.py +++ b/request_llm/bridge_jittorllms_pangualpha.py @@ -28,8 +28,8 @@ class GetGLMHandle(Process): self.success = True except: from toolbox import trimmed_format_exc - self.info = r"缺少jittorllms的依赖,如果要使用jittorllms,除了基础的pip依赖以外,您还需要运行`pip install -r request_llms/requirements_jittorllms.txt -i https://pypi.jittor.org/simple -I`"+\ - r"和`git clone https://gitlink.org.cn/jittor/JittorLLMs.git --depth 1 request_llms/jittorllms`两个指令来安装jittorllms的依赖(在项目根目录运行这两个指令)。" +\ + self.info = r"缺少jittorllms的依赖,如果要使用jittorllms,除了基础的pip依赖以外,您还需要运行`pip install -r request_llm/requirements_jittorllms.txt -i https://pypi.jittor.org/simple -I`"+\ + r"和`git clone https://gitlink.org.cn/jittor/JittorLLMs.git --depth 1 request_llm/jittorllms`两个指令来安装jittorllms的依赖(在项目根目录运行这两个指令)。" +\ r"警告:安装jittorllms依赖后将完全破坏现有的pytorch环境,建议使用docker环境!" + trimmed_format_exc() self.success = False @@ -45,15 +45,15 @@ class GetGLMHandle(Process): env = os.environ.get("PATH", "") os.environ["PATH"] = env.replace('/cuda/bin', '/x/bin') root_dir_assume = os.path.abspath(os.path.dirname(__file__) + '/..') - os.chdir(root_dir_assume + '/request_llms/jittorllms') - sys.path.append(root_dir_assume + '/request_llms/jittorllms') + os.chdir(root_dir_assume + '/request_llm/jittorllms') + sys.path.append(root_dir_assume + '/request_llm/jittorllms') validate_path() # validate path so you can run from base directory def load_model(): import types try: if self.jittorllms_model is None: - device = get_conf('LOCAL_MODEL_DEVICE') + device, = get_conf('LOCAL_MODEL_DEVICE') from .jittorllms.models import get_model # availabel_models = ["chatglm", "pangualpha", "llama", "chatrwkv"] args_dict = {'model': 'pangualpha'} @@ -109,7 +109,7 @@ pangu_glm_handle = None def predict_no_ui_long_connection(inputs, llm_kwargs, history=[], sys_prompt="", observe_window=[], console_slience=False): """ 多线程方法 - 函数的说明请见 request_llms/bridge_all.py + 函数的说明请见 request_llm/bridge_all.py """ global pangu_glm_handle if pangu_glm_handle is None: @@ -140,7 +140,7 @@ def predict_no_ui_long_connection(inputs, llm_kwargs, history=[], sys_prompt="", def predict(inputs, llm_kwargs, plugin_kwargs, chatbot, history=[], system_prompt='', stream = True, additional_fn=None): """ 单线程方法 - 函数的说明请见 request_llms/bridge_all.py + 函数的说明请见 request_llm/bridge_all.py """ chatbot.append((inputs, "")) @@ -163,13 +163,13 @@ def predict(inputs, llm_kwargs, plugin_kwargs, chatbot, history=[], system_promp history_feedin.append([history[2*i], history[2*i+1]] ) # 开始接收jittorllms的回复 - response = "[Local Message] 等待jittorllms响应中 ..." + response = "[Local Message]: 等待jittorllms响应中 ..." for response in pangu_glm_handle.stream_chat(query=inputs, history=history_feedin, system_prompt=system_prompt, max_length=llm_kwargs['max_length'], top_p=llm_kwargs['top_p'], temperature=llm_kwargs['temperature']): chatbot[-1] = (inputs, response) yield from update_ui(chatbot=chatbot, history=history) # 总结输出 - if response == "[Local Message] 等待jittorllms响应中 ...": - response = "[Local Message] jittorllms响应异常 ..." + if response == "[Local Message]: 等待jittorllms响应中 ...": + response = "[Local Message]: jittorllms响应异常 ..." history.extend([inputs, response]) yield from update_ui(chatbot=chatbot, history=history) diff --git a/request_llms/bridge_jittorllms_rwkv.py b/request_llm/bridge_jittorllms_rwkv.py similarity index 90% rename from request_llms/bridge_jittorllms_rwkv.py rename to request_llm/bridge_jittorllms_rwkv.py index 0021a50d0ab1f6bb2a909003f1ea36ccffa326c7..ee4f592f5a1a3e6022b41c899e342bd7e55ed44f 100644 --- a/request_llms/bridge_jittorllms_rwkv.py +++ b/request_llm/bridge_jittorllms_rwkv.py @@ -28,8 +28,8 @@ class GetGLMHandle(Process): self.success = True except: from toolbox import trimmed_format_exc - self.info = r"缺少jittorllms的依赖,如果要使用jittorllms,除了基础的pip依赖以外,您还需要运行`pip install -r request_llms/requirements_jittorllms.txt -i https://pypi.jittor.org/simple -I`"+\ - r"和`git clone https://gitlink.org.cn/jittor/JittorLLMs.git --depth 1 request_llms/jittorllms`两个指令来安装jittorllms的依赖(在项目根目录运行这两个指令)。" +\ + self.info = r"缺少jittorllms的依赖,如果要使用jittorllms,除了基础的pip依赖以外,您还需要运行`pip install -r request_llm/requirements_jittorllms.txt -i https://pypi.jittor.org/simple -I`"+\ + r"和`git clone https://gitlink.org.cn/jittor/JittorLLMs.git --depth 1 request_llm/jittorllms`两个指令来安装jittorllms的依赖(在项目根目录运行这两个指令)。" +\ r"警告:安装jittorllms依赖后将完全破坏现有的pytorch环境,建议使用docker环境!" + trimmed_format_exc() self.success = False @@ -45,15 +45,15 @@ class GetGLMHandle(Process): env = os.environ.get("PATH", "") os.environ["PATH"] = env.replace('/cuda/bin', '/x/bin') root_dir_assume = os.path.abspath(os.path.dirname(__file__) + '/..') - os.chdir(root_dir_assume + '/request_llms/jittorllms') - sys.path.append(root_dir_assume + '/request_llms/jittorllms') + os.chdir(root_dir_assume + '/request_llm/jittorllms') + sys.path.append(root_dir_assume + '/request_llm/jittorllms') validate_path() # validate path so you can run from base directory def load_model(): import types try: if self.jittorllms_model is None: - device = get_conf('LOCAL_MODEL_DEVICE') + device, = get_conf('LOCAL_MODEL_DEVICE') from .jittorllms.models import get_model # availabel_models = ["chatglm", "pangualpha", "llama", "chatrwkv"] args_dict = {'model': 'chatrwkv'} @@ -109,7 +109,7 @@ rwkv_glm_handle = None def predict_no_ui_long_connection(inputs, llm_kwargs, history=[], sys_prompt="", observe_window=[], console_slience=False): """ 多线程方法 - 函数的说明请见 request_llms/bridge_all.py + 函数的说明请见 request_llm/bridge_all.py """ global rwkv_glm_handle if rwkv_glm_handle is None: @@ -140,7 +140,7 @@ def predict_no_ui_long_connection(inputs, llm_kwargs, history=[], sys_prompt="", def predict(inputs, llm_kwargs, plugin_kwargs, chatbot, history=[], system_prompt='', stream = True, additional_fn=None): """ 单线程方法 - 函数的说明请见 request_llms/bridge_all.py + 函数的说明请见 request_llm/bridge_all.py """ chatbot.append((inputs, "")) @@ -163,13 +163,13 @@ def predict(inputs, llm_kwargs, plugin_kwargs, chatbot, history=[], system_promp history_feedin.append([history[2*i], history[2*i+1]] ) # 开始接收jittorllms的回复 - response = "[Local Message] 等待jittorllms响应中 ..." + response = "[Local Message]: 等待jittorllms响应中 ..." for response in rwkv_glm_handle.stream_chat(query=inputs, history=history_feedin, system_prompt=system_prompt, max_length=llm_kwargs['max_length'], top_p=llm_kwargs['top_p'], temperature=llm_kwargs['temperature']): chatbot[-1] = (inputs, response) yield from update_ui(chatbot=chatbot, history=history) # 总结输出 - if response == "[Local Message] 等待jittorllms响应中 ...": - response = "[Local Message] jittorllms响应异常 ..." + if response == "[Local Message]: 等待jittorllms响应中 ...": + response = "[Local Message]: jittorllms响应异常 ..." history.extend([inputs, response]) yield from update_ui(chatbot=chatbot, history=history) diff --git a/request_llms/bridge_llama2.py b/request_llm/bridge_llama2.py similarity index 94% rename from request_llms/bridge_llama2.py rename to request_llm/bridge_llama2.py index bfa3c14ae63cb1eafe85b6d81810b0f70303a900..e236c94272b110b2d4e4eb72812a270a0c8b3226 100644 --- a/request_llms/bridge_llama2.py +++ b/request_llm/bridge_llama2.py @@ -1,18 +1,19 @@ model_name = "LLaMA" -cmd_to_install = "`pip install -r request_llms/requirements_chatglm.txt`" +cmd_to_install = "`pip install -r request_llm/requirements_chatglm.txt`" from transformers import AutoModelForCausalLM, AutoTokenizer, TextIteratorStreamer from toolbox import update_ui, get_conf, ProxyNetworkActivate from multiprocessing import Process, Pipe -from .local_llm_class import LocalLLMHandle, get_local_llm_predict_fns +from .local_llm_class import LocalLLMHandle, get_local_llm_predict_fns, SingletonLocalLLM from threading import Thread # ------------------------------------------------------------------------------------------------------------------------ # 🔌💻 Local Model # ------------------------------------------------------------------------------------------------------------------------ -class GetLlamaHandle(LocalLLMHandle): +@SingletonLocalLLM +class GetONNXGLMHandle(LocalLLMHandle): def load_model_info(self): # 🏃‍♂️🏃‍♂️🏃‍♂️ 子进程执行 @@ -29,7 +30,7 @@ class GetLlamaHandle(LocalLLMHandle): with open(os.path.expanduser('~/.cache/huggingface/token'), 'w') as f: f.write(huggingface_token) model_id = 'meta-llama/Llama-2-7b-chat-hf' - with ProxyNetworkActivate('Download_LLM'): + with ProxyNetworkActivate(): self._tokenizer = AutoTokenizer.from_pretrained(model_id, use_auth_token=huggingface_token) # use fp16 model = AutoModelForCausalLM.from_pretrained(model_id, use_auth_token=huggingface_token).eval() @@ -87,4 +88,4 @@ class GetLlamaHandle(LocalLLMHandle): # ------------------------------------------------------------------------------------------------------------------------ # 🔌💻 GPT-Academic Interface # ------------------------------------------------------------------------------------------------------------------------ -predict_no_ui_long_connection, predict = get_local_llm_predict_fns(GetLlamaHandle, model_name) \ No newline at end of file +predict_no_ui_long_connection, predict = get_local_llm_predict_fns(GetONNXGLMHandle, model_name) \ No newline at end of file diff --git a/request_llms/bridge_moss.py b/request_llm/bridge_moss.py similarity index 93% rename from request_llms/bridge_moss.py rename to request_llm/bridge_moss.py index ee8907cf01a6958b92d5abeed3487ee9f21524f9..3c6217d2b285c499490d81e9a744b2dd6f485e24 100644 --- a/request_llms/bridge_moss.py +++ b/request_llm/bridge_moss.py @@ -1,6 +1,8 @@ +from transformers import AutoModel, AutoTokenizer import time import threading +import importlib from toolbox import update_ui, get_conf from multiprocessing import Process, Pipe @@ -22,12 +24,12 @@ class GetGLMHandle(Process): def check_dependency(self): # 主进程执行 try: import datasets, os - assert os.path.exists('request_llms/moss/models') + assert os.path.exists('request_llm/moss/models') self.info = "依赖检测通过" self.success = True except: self.info = """ - 缺少MOSS的依赖,如果要使用MOSS,除了基础的pip依赖以外,您还需要运行`pip install -r request_llms/requirements_moss.txt`和`git clone https://github.com/OpenLMLab/MOSS.git request_llms/moss`安装MOSS的依赖。 + 缺少MOSS的依赖,如果要使用MOSS,除了基础的pip依赖以外,您还需要运行`pip install -r request_llm/requirements_moss.txt`和`git clone https://github.com/OpenLMLab/MOSS.git request_llm/moss`安装MOSS的依赖。 """ self.success = False return self.success @@ -108,8 +110,8 @@ class GetGLMHandle(Process): def validate_path(): import os, sys root_dir_assume = os.path.abspath(os.path.dirname(__file__) + '/..') - os.chdir(root_dir_assume + '/request_llms/moss') - sys.path.append(root_dir_assume + '/request_llms/moss') + os.chdir(root_dir_assume + '/request_llm/moss') + sys.path.append(root_dir_assume + '/request_llm/moss') validate_path() # validate path so you can run from base directory try: @@ -174,7 +176,7 @@ moss_handle = None def predict_no_ui_long_connection(inputs, llm_kwargs, history=[], sys_prompt="", observe_window=[], console_slience=False): """ 多线程方法 - 函数的说明请见 request_llms/bridge_all.py + 函数的说明请见 request_llm/bridge_all.py """ global moss_handle if moss_handle is None: @@ -204,7 +206,7 @@ def predict_no_ui_long_connection(inputs, llm_kwargs, history=[], sys_prompt="", def predict(inputs, llm_kwargs, plugin_kwargs, chatbot, history=[], system_prompt='', stream = True, additional_fn=None): """ 单线程方法 - 函数的说明请见 request_llms/bridge_all.py + 函数的说明请见 request_llm/bridge_all.py """ chatbot.append((inputs, "")) @@ -217,7 +219,7 @@ def predict(inputs, llm_kwargs, plugin_kwargs, chatbot, history=[], system_promp moss_handle = None return else: - response = "[Local Message] 等待MOSS响应中 ..." + response = "[Local Message]: 等待MOSS响应中 ..." chatbot[-1] = (inputs, response) yield from update_ui(chatbot=chatbot, history=history) @@ -236,7 +238,7 @@ def predict(inputs, llm_kwargs, plugin_kwargs, chatbot, history=[], system_promp yield from update_ui(chatbot=chatbot, history=history) # 总结输出 - if response == "[Local Message] 等待MOSS响应中 ...": - response = "[Local Message] MOSS响应异常 ..." + if response == "[Local Message]: 等待MOSS响应中 ...": + response = "[Local Message]: MOSS响应异常 ..." history.extend([inputs, response.strip('<|MOSS|>: ')]) yield from update_ui(chatbot=chatbot, history=history) diff --git a/request_llm/bridge_newbing.py b/request_llm/bridge_newbing.py new file mode 100644 index 0000000000000000000000000000000000000000..2136f01beb3edd25b94dd8048c20b63a14ef905e --- /dev/null +++ b/request_llm/bridge_newbing.py @@ -0,0 +1,254 @@ +""" +======================================================================== +第一部分:来自EdgeGPT.py +https://github.com/acheong08/EdgeGPT +======================================================================== +""" +from .edge_gpt import NewbingChatbot +load_message = "等待NewBing响应。" + +""" +======================================================================== +第二部分:子进程Worker(调用主体) +======================================================================== +""" +import time +import json +import re +import logging +import asyncio +import importlib +import threading +from toolbox import update_ui, get_conf, trimmed_format_exc +from multiprocessing import Process, Pipe + +def preprocess_newbing_out(s): + pattern = r'\^(\d+)\^' # 匹配^数字^ + sub = lambda m: '('+m.group(1)+')' # 将匹配到的数字作为替换值 + result = re.sub(pattern, sub, s) # 替换操作 + if '[1]' in result: + result += '\n\n```reference\n' + "\n".join([r for r in result.split('\n') if r.startswith('[')]) + '\n```\n' + return result + +def preprocess_newbing_out_simple(result): + if '[1]' in result: + result += '\n\n```reference\n' + "\n".join([r for r in result.split('\n') if r.startswith('[')]) + '\n```\n' + return result + +class NewBingHandle(Process): + def __init__(self): + super().__init__(daemon=True) + self.parent, self.child = Pipe() + self.newbing_model = None + self.info = "" + self.success = True + self.local_history = [] + self.check_dependency() + self.start() + self.threadLock = threading.Lock() + + def check_dependency(self): + try: + self.success = False + import certifi, httpx, rich + self.info = "依赖检测通过,等待NewBing响应。注意目前不能多人同时调用NewBing接口(有线程锁),否则将导致每个人的NewBing问询历史互相渗透。调用NewBing时,会自动使用已配置的代理。" + self.success = True + except: + self.info = "缺少的依赖,如果要使用Newbing,除了基础的pip依赖以外,您还需要运行`pip install -r request_llm/requirements_newbing.txt`安装Newbing的依赖。" + self.success = False + + def ready(self): + return self.newbing_model is not None + + async def async_run(self): + # 读取配置 + NEWBING_STYLE, = get_conf('NEWBING_STYLE') + from request_llm.bridge_all import model_info + endpoint = model_info['newbing']['endpoint'] + while True: + # 等待 + kwargs = self.child.recv() + question=kwargs['query'] + history=kwargs['history'] + system_prompt=kwargs['system_prompt'] + + # 是否重置 + if len(self.local_history) > 0 and len(history)==0: + await self.newbing_model.reset() + self.local_history = [] + + # 开始问问题 + prompt = "" + if system_prompt not in self.local_history: + self.local_history.append(system_prompt) + prompt += system_prompt + '\n' + + # 追加历史 + for ab in history: + a, b = ab + if a not in self.local_history: + self.local_history.append(a) + prompt += a + '\n' + # if b not in self.local_history: + # self.local_history.append(b) + # prompt += b + '\n' + + # 问题 + prompt += question + self.local_history.append(question) + print('question:', prompt) + # 提交 + async for final, response in self.newbing_model.ask_stream( + prompt=question, + conversation_style=NEWBING_STYLE, # ["creative", "balanced", "precise"] + wss_link=endpoint, # "wss://sydney.bing.com/sydney/ChatHub" + ): + if not final: + print(response) + self.child.send(str(response)) + else: + print('-------- receive final ---------') + self.child.send('[Finish]') + # self.local_history.append(response) + + + def run(self): + """ + 这个函数运行在子进程 + """ + # 第一次运行,加载参数 + self.success = False + self.local_history = [] + if (self.newbing_model is None) or (not self.success): + # 代理设置 + proxies, = get_conf('proxies') + if proxies is None: + self.proxies_https = None + else: + self.proxies_https = proxies['https'] + # cookie + NEWBING_COOKIES, = get_conf('NEWBING_COOKIES') + try: + cookies = json.loads(NEWBING_COOKIES) + except: + self.success = False + tb_str = '\n```\n' + trimmed_format_exc() + '\n```\n' + self.child.send(f'[Local Message] 不能加载Newbing组件。NEWBING_COOKIES未填写或有格式错误。') + self.child.send('[Fail]') + self.child.send('[Finish]') + raise RuntimeError(f"不能加载Newbing组件。NEWBING_COOKIES未填写或有格式错误。") + + try: + self.newbing_model = NewbingChatbot(proxy=self.proxies_https, cookies=cookies) + except: + self.success = False + tb_str = '\n```\n' + trimmed_format_exc() + '\n```\n' + self.child.send(f'[Local Message] 不能加载Newbing组件。{tb_str}') + self.child.send('[Fail]') + self.child.send('[Finish]') + raise RuntimeError(f"不能加载Newbing组件。") + + self.success = True + try: + # 进入任务等待状态 + asyncio.run(self.async_run()) + except Exception: + tb_str = '\n```\n' + trimmed_format_exc() + '\n```\n' + self.child.send(f'[Local Message] Newbing失败 {tb_str}.') + self.child.send('[Fail]') + self.child.send('[Finish]') + + def stream_chat(self, **kwargs): + """ + 这个函数运行在主进程 + """ + self.threadLock.acquire() + self.parent.send(kwargs) # 发送请求到子进程 + while True: + res = self.parent.recv() # 等待newbing回复的片段 + if res == '[Finish]': + break # 结束 + elif res == '[Fail]': + self.success = False + break + else: + yield res # newbing回复的片段 + self.threadLock.release() + + +""" +======================================================================== +第三部分:主进程统一调用函数接口 +======================================================================== +""" +global newbing_handle +newbing_handle = None + +def predict_no_ui_long_connection(inputs, llm_kwargs, history=[], sys_prompt="", observe_window=None, console_slience=False): + """ + 多线程方法 + 函数的说明请见 request_llm/bridge_all.py + """ + global newbing_handle + if (newbing_handle is None) or (not newbing_handle.success): + newbing_handle = NewBingHandle() + observe_window[0] = load_message + "\n\n" + newbing_handle.info + if not newbing_handle.success: + error = newbing_handle.info + newbing_handle = None + raise RuntimeError(error) + + # 没有 sys_prompt 接口,因此把prompt加入 history + history_feedin = [] + for i in range(len(history)//2): + history_feedin.append([history[2*i], history[2*i+1]] ) + + watch_dog_patience = 5 # 看门狗 (watchdog) 的耐心, 设置5秒即可 + response = "" + observe_window[0] = "[Local Message]: 等待NewBing响应中 ..." + for response in newbing_handle.stream_chat(query=inputs, history=history_feedin, system_prompt=sys_prompt, max_length=llm_kwargs['max_length'], top_p=llm_kwargs['top_p'], temperature=llm_kwargs['temperature']): + observe_window[0] = preprocess_newbing_out_simple(response) + if len(observe_window) >= 2: + if (time.time()-observe_window[1]) > watch_dog_patience: + raise RuntimeError("程序终止。") + return preprocess_newbing_out_simple(response) + +def predict(inputs, llm_kwargs, plugin_kwargs, chatbot, history=[], system_prompt='', stream = True, additional_fn=None): + """ + 单线程方法 + 函数的说明请见 request_llm/bridge_all.py + """ + chatbot.append((inputs, "[Local Message]: 等待NewBing响应中 ...")) + + global newbing_handle + if (newbing_handle is None) or (not newbing_handle.success): + newbing_handle = NewBingHandle() + chatbot[-1] = (inputs, load_message + "\n\n" + newbing_handle.info) + yield from update_ui(chatbot=chatbot, history=[]) + if not newbing_handle.success: + newbing_handle = None + return + + if additional_fn is not None: + import core_functional + importlib.reload(core_functional) # 热更新prompt + core_functional = core_functional.get_core_functions() + if "PreProcess" in core_functional[additional_fn]: inputs = core_functional[additional_fn]["PreProcess"](inputs) # 获取预处理函数(如果有的话) + inputs = core_functional[additional_fn]["Prefix"] + inputs + core_functional[additional_fn]["Suffix"] + + history_feedin = [] + for i in range(len(history)//2): + history_feedin.append([history[2*i], history[2*i+1]] ) + + chatbot[-1] = (inputs, "[Local Message]: 等待NewBing响应中 ...") + response = "[Local Message]: 等待NewBing响应中 ..." + yield from update_ui(chatbot=chatbot, history=history, msg="NewBing响应缓慢,尚未完成全部响应,请耐心完成后再提交新问题。") + for response in newbing_handle.stream_chat(query=inputs, history=history_feedin, system_prompt=system_prompt, max_length=llm_kwargs['max_length'], top_p=llm_kwargs['top_p'], temperature=llm_kwargs['temperature']): + chatbot[-1] = (inputs, preprocess_newbing_out(response)) + yield from update_ui(chatbot=chatbot, history=history, msg="NewBing响应缓慢,尚未完成全部响应,请耐心完成后再提交新问题。") + if response == "[Local Message]: 等待NewBing响应中 ...": response = "[Local Message]: NewBing响应异常,请刷新界面重试 ..." + history.extend([inputs, response]) + logging.info(f'[raw_input] {inputs}') + logging.info(f'[response] {response}') + yield from update_ui(chatbot=chatbot, history=history, msg="完成全部响应,请提交新问题。") + diff --git a/request_llm/bridge_newbingfree.py b/request_llm/bridge_newbingfree.py new file mode 100644 index 0000000000000000000000000000000000000000..cc6e9b733b48fe255c15bc9fae3c9abd74f276ca --- /dev/null +++ b/request_llm/bridge_newbingfree.py @@ -0,0 +1,245 @@ +""" +======================================================================== +第一部分:来自EdgeGPT.py +https://github.com/acheong08/EdgeGPT +======================================================================== +""" +from .edge_gpt_free import Chatbot as NewbingChatbot +load_message = "等待NewBing响应。" + +""" +======================================================================== +第二部分:子进程Worker(调用主体) +======================================================================== +""" +import time +import json +import re +import logging +import asyncio +import importlib +import threading +from toolbox import update_ui, get_conf, trimmed_format_exc +from multiprocessing import Process, Pipe + +def preprocess_newbing_out(s): + pattern = r'\^(\d+)\^' # 匹配^数字^ + sub = lambda m: '('+m.group(1)+')' # 将匹配到的数字作为替换值 + result = re.sub(pattern, sub, s) # 替换操作 + if '[1]' in result: + result += '\n\n```reference\n' + "\n".join([r for r in result.split('\n') if r.startswith('[')]) + '\n```\n' + return result + +def preprocess_newbing_out_simple(result): + if '[1]' in result: + result += '\n\n```reference\n' + "\n".join([r for r in result.split('\n') if r.startswith('[')]) + '\n```\n' + return result + +class NewBingHandle(Process): + def __init__(self): + super().__init__(daemon=True) + self.parent, self.child = Pipe() + self.newbing_model = None + self.info = "" + self.success = True + self.local_history = [] + self.check_dependency() + self.start() + self.threadLock = threading.Lock() + + def check_dependency(self): + try: + self.success = False + import certifi, httpx, rich + self.info = "依赖检测通过,等待NewBing响应。注意目前不能多人同时调用NewBing接口(有线程锁),否则将导致每个人的NewBing问询历史互相渗透。调用NewBing时,会自动使用已配置的代理。" + self.success = True + except: + self.info = "缺少的依赖,如果要使用Newbing,除了基础的pip依赖以外,您还需要运行`pip install -r request_llm/requirements_newbing.txt`安装Newbing的依赖。" + self.success = False + + def ready(self): + return self.newbing_model is not None + + async def async_run(self): + # 读取配置 + NEWBING_STYLE, = get_conf('NEWBING_STYLE') + from request_llm.bridge_all import model_info + endpoint = model_info['newbing']['endpoint'] + while True: + # 等待 + kwargs = self.child.recv() + question=kwargs['query'] + history=kwargs['history'] + system_prompt=kwargs['system_prompt'] + + # 是否重置 + if len(self.local_history) > 0 and len(history)==0: + await self.newbing_model.reset() + self.local_history = [] + + # 开始问问题 + prompt = "" + if system_prompt not in self.local_history: + self.local_history.append(system_prompt) + prompt += system_prompt + '\n' + + # 追加历史 + for ab in history: + a, b = ab + if a not in self.local_history: + self.local_history.append(a) + prompt += a + '\n' + + # 问题 + prompt += question + self.local_history.append(question) + print('question:', prompt) + # 提交 + async for final, response in self.newbing_model.ask_stream( + prompt=question, + conversation_style=NEWBING_STYLE, # ["creative", "balanced", "precise"] + wss_link=endpoint, # "wss://sydney.bing.com/sydney/ChatHub" + ): + if not final: + print(response) + self.child.send(str(response)) + else: + print('-------- receive final ---------') + self.child.send('[Finish]') + # self.local_history.append(response) + + + def run(self): + """ + 这个函数运行在子进程 + """ + # 第一次运行,加载参数 + self.success = False + self.local_history = [] + if (self.newbing_model is None) or (not self.success): + # 代理设置 + proxies, NEWBING_COOKIES = get_conf('proxies', 'NEWBING_COOKIES') + if proxies is None: + self.proxies_https = None + else: + self.proxies_https = proxies['https'] + + if (NEWBING_COOKIES is not None) and len(NEWBING_COOKIES) > 100: + try: + cookies = json.loads(NEWBING_COOKIES) + except: + self.success = False + tb_str = '\n```\n' + trimmed_format_exc() + '\n```\n' + self.child.send(f'[Local Message] NEWBING_COOKIES未填写或有格式错误。') + self.child.send('[Fail]'); self.child.send('[Finish]') + raise RuntimeError(f"NEWBING_COOKIES未填写或有格式错误。") + else: + cookies = None + + try: + self.newbing_model = NewbingChatbot(proxy=self.proxies_https, cookies=cookies) + except: + self.success = False + tb_str = '\n```\n' + trimmed_format_exc() + '\n```\n' + self.child.send(f'[Local Message] 不能加载Newbing组件。{tb_str}') + self.child.send('[Fail]') + self.child.send('[Finish]') + raise RuntimeError(f"不能加载Newbing组件。") + + self.success = True + try: + # 进入任务等待状态 + asyncio.run(self.async_run()) + except Exception: + tb_str = '\n```\n' + trimmed_format_exc() + '\n```\n' + self.child.send(f'[Local Message] Newbing 请求失败,报错信息如下. 如果是与网络相关的问题,建议更换代理协议(推荐http)或代理节点 {tb_str}.') + self.child.send('[Fail]') + self.child.send('[Finish]') + + def stream_chat(self, **kwargs): + """ + 这个函数运行在主进程 + """ + self.threadLock.acquire() # 获取线程锁 + self.parent.send(kwargs) # 请求子进程 + while True: + res = self.parent.recv() # 等待newbing回复的片段 + if res == '[Finish]': break # 结束 + elif res == '[Fail]': self.success = False; break # 失败 + else: yield res # newbing回复的片段 + self.threadLock.release() # 释放线程锁 + + +""" +======================================================================== +第三部分:主进程统一调用函数接口 +======================================================================== +""" +global newbingfree_handle +newbingfree_handle = None + +def predict_no_ui_long_connection(inputs, llm_kwargs, history=[], sys_prompt="", observe_window=[], console_slience=False): + """ + 多线程方法 + 函数的说明请见 request_llm/bridge_all.py + """ + global newbingfree_handle + if (newbingfree_handle is None) or (not newbingfree_handle.success): + newbingfree_handle = NewBingHandle() + if len(observe_window) >= 1: observe_window[0] = load_message + "\n\n" + newbingfree_handle.info + if not newbingfree_handle.success: + error = newbingfree_handle.info + newbingfree_handle = None + raise RuntimeError(error) + + # 没有 sys_prompt 接口,因此把prompt加入 history + history_feedin = [] + for i in range(len(history)//2): + history_feedin.append([history[2*i], history[2*i+1]] ) + + watch_dog_patience = 5 # 看门狗 (watchdog) 的耐心, 设置5秒即可 + response = "" + if len(observe_window) >= 1: observe_window[0] = "[Local Message]: 等待NewBing响应中 ..." + for response in newbingfree_handle.stream_chat(query=inputs, history=history_feedin, system_prompt=sys_prompt, max_length=llm_kwargs['max_length'], top_p=llm_kwargs['top_p'], temperature=llm_kwargs['temperature']): + if len(observe_window) >= 1: observe_window[0] = preprocess_newbing_out_simple(response) + if len(observe_window) >= 2: + if (time.time()-observe_window[1]) > watch_dog_patience: + raise RuntimeError("程序终止。") + return preprocess_newbing_out_simple(response) + +def predict(inputs, llm_kwargs, plugin_kwargs, chatbot, history=[], system_prompt='', stream = True, additional_fn=None): + """ + 单线程方法 + 函数的说明请见 request_llm/bridge_all.py + """ + chatbot.append((inputs, "[Local Message]: 等待NewBing响应中 ...")) + + global newbingfree_handle + if (newbingfree_handle is None) or (not newbingfree_handle.success): + newbingfree_handle = NewBingHandle() + chatbot[-1] = (inputs, load_message + "\n\n" + newbingfree_handle.info) + yield from update_ui(chatbot=chatbot, history=[]) + if not newbingfree_handle.success: + newbingfree_handle = None + return + + if additional_fn is not None: + from core_functional import handle_core_functionality + inputs, history = handle_core_functionality(additional_fn, inputs, history, chatbot) + + history_feedin = [] + for i in range(len(history)//2): + history_feedin.append([history[2*i], history[2*i+1]] ) + + chatbot[-1] = (inputs, "[Local Message]: 等待NewBing响应中 ...") + response = "[Local Message]: 等待NewBing响应中 ..." + yield from update_ui(chatbot=chatbot, history=history, msg="NewBing响应缓慢,尚未完成全部响应,请耐心完成后再提交新问题。") + for response in newbingfree_handle.stream_chat(query=inputs, history=history_feedin, system_prompt=system_prompt, max_length=llm_kwargs['max_length'], top_p=llm_kwargs['top_p'], temperature=llm_kwargs['temperature']): + chatbot[-1] = (inputs, preprocess_newbing_out(response)) + yield from update_ui(chatbot=chatbot, history=history, msg="NewBing响应缓慢,尚未完成全部响应,请耐心完成后再提交新问题。") + if response == "[Local Message]: 等待NewBing响应中 ...": response = "[Local Message]: NewBing响应异常,请刷新界面重试 ..." + history.extend([inputs, response]) + logging.info(f'[raw_input] {inputs}') + logging.info(f'[response] {response}') + yield from update_ui(chatbot=chatbot, history=history, msg="完成全部响应,请提交新问题。") + diff --git a/request_llms/bridge_qianfan.py b/request_llm/bridge_qianfan.py similarity index 91% rename from request_llms/bridge_qianfan.py rename to request_llm/bridge_qianfan.py index 0f02457b23847e32efd10726a65d719d904e6aa5..be7397607a71681edc240be48d1889ce51008af5 100644 --- a/request_llms/bridge_qianfan.py +++ b/request_llm/bridge_qianfan.py @@ -75,12 +75,11 @@ def generate_message_payload(inputs, llm_kwargs, history, system_prompt): def generate_from_baidu_qianfan(inputs, llm_kwargs, history, system_prompt): - BAIDU_CLOUD_QIANFAN_MODEL = get_conf('BAIDU_CLOUD_QIANFAN_MODEL') + BAIDU_CLOUD_QIANFAN_MODEL, = get_conf('BAIDU_CLOUD_QIANFAN_MODEL') url_lib = { - "ERNIE-Bot-4": "https://aip.baidubce.com/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/completions_pro", - "ERNIE-Bot": "https://aip.baidubce.com/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/completions", - "ERNIE-Bot-turbo": "https://aip.baidubce.com/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/eb-instant", + "ERNIE-Bot": "https://aip.baidubce.com/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/completions" , + "ERNIE-Bot-turbo": "https://aip.baidubce.com/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/eb-instant" , "BLOOMZ-7B": "https://aip.baidubce.com/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/bloomz_7b1", "Llama-2-70B-Chat": "https://aip.baidubce.com/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/llama_2_70b", @@ -120,7 +119,7 @@ def generate_from_baidu_qianfan(inputs, llm_kwargs, history, system_prompt): def predict_no_ui_long_connection(inputs, llm_kwargs, history=[], sys_prompt="", observe_window=[], console_slience=False): """ ⭐多线程方法 - 函数的说明请见 request_llms/bridge_all.py + 函数的说明请见 request_llm/bridge_all.py """ watch_dog_patience = 5 response = "" @@ -135,7 +134,7 @@ def predict_no_ui_long_connection(inputs, llm_kwargs, history=[], sys_prompt="", def predict(inputs, llm_kwargs, plugin_kwargs, chatbot, history=[], system_prompt='', stream = True, additional_fn=None): """ ⭐单线程方法 - 函数的说明请见 request_llms/bridge_all.py + 函数的说明请见 request_llm/bridge_all.py """ chatbot.append((inputs, "")) @@ -146,17 +145,21 @@ def predict(inputs, llm_kwargs, plugin_kwargs, chatbot, history=[], system_promp yield from update_ui(chatbot=chatbot, history=history) # 开始接收回复 try: - response = f"[Local Message] 等待{model_name}响应中 ..." for response in generate_from_baidu_qianfan(inputs, llm_kwargs, history, system_prompt): chatbot[-1] = (inputs, response) yield from update_ui(chatbot=chatbot, history=history) - history.extend([inputs, response]) - yield from update_ui(chatbot=chatbot, history=history) except ConnectionAbortedError as e: from .bridge_all import model_info if len(history) >= 2: history[-1] = ""; history[-2] = "" # 清除当前溢出的输入:history[-2] 是本次输入, history[-1] 是本次输出 - history = clip_history(inputs=inputs, history=history, tokenizer=model_info[llm_kwargs['llm_model']]['tokenizer'], + history = clip_history(inputs=inputs, history=history, tokenizer=model_info[llm_kwargs['llm_model']]['tokenizer'], max_token_limit=(model_info[llm_kwargs['llm_model']]['max_token'])) # history至少释放二分之一 chatbot[-1] = (chatbot[-1][0], "[Local Message] Reduce the length. 本次输入过长, 或历史数据过长. 历史缓存数据已部分释放, 您可以请再次尝试. (若再次失败则更可能是因为输入过长.)") yield from update_ui(chatbot=chatbot, history=history, msg="异常") # 刷新界面 return + + # 总结输出 + response = f"[Local Message]: {model_name}响应异常 ..." + if response == f"[Local Message]: 等待{model_name}响应中 ...": + response = f"[Local Message]: {model_name}响应异常 ..." + history.extend([inputs, response]) + yield from update_ui(chatbot=chatbot, history=history) \ No newline at end of file diff --git a/request_llms/bridge_qwen_local.py b/request_llm/bridge_qwen.py similarity index 61% rename from request_llms/bridge_qwen_local.py rename to request_llm/bridge_qwen.py index e6c2dd5cdf7b6ba59b474b3c38afebc77014dd14..07ed243feb25274213ccee90f862662080809f84 100644 --- a/request_llms/bridge_qwen_local.py +++ b/request_llm/bridge_qwen.py @@ -1,15 +1,22 @@ -model_name = "Qwen_Local" -cmd_to_install = "`pip install -r request_llms/requirements_qwen_local.txt`" +model_name = "Qwen" +cmd_to_install = "`pip install -r request_llm/requirements_qwen.txt`" -from toolbox import ProxyNetworkActivate, get_conf -from .local_llm_class import LocalLLMHandle, get_local_llm_predict_fns + +from transformers import AutoModel, AutoTokenizer +import time +import threading +import importlib +from toolbox import update_ui, get_conf +from multiprocessing import Process, Pipe +from .local_llm_class import LocalLLMHandle, get_local_llm_predict_fns, SingletonLocalLLM # ------------------------------------------------------------------------------------------------------------------------ # 🔌💻 Local Model # ------------------------------------------------------------------------------------------------------------------------ -class GetQwenLMHandle(LocalLLMHandle): +@SingletonLocalLLM +class GetONNXGLMHandle(LocalLLMHandle): def load_model_info(self): # 🏃‍♂️🏃‍♂️🏃‍♂️ 子进程执行 @@ -18,16 +25,18 @@ class GetQwenLMHandle(LocalLLMHandle): def load_model_and_tokenizer(self): # 🏃‍♂️🏃‍♂️🏃‍♂️ 子进程执行 - # from modelscope import AutoModelForCausalLM, AutoTokenizer, GenerationConfig - from transformers import AutoModelForCausalLM, AutoTokenizer - from transformers.generation import GenerationConfig - with ProxyNetworkActivate('Download_LLM'): - model_id = get_conf('QWEN_LOCAL_MODEL_SELECTION') - self._tokenizer = AutoTokenizer.from_pretrained(model_id, trust_remote_code=True, resume_download=True) - # use fp16 - model = AutoModelForCausalLM.from_pretrained(model_id, device_map="auto", trust_remote_code=True).eval() - model.generation_config = GenerationConfig.from_pretrained(model_id, trust_remote_code=True) # 可指定不同的生成长度、top_p等相关超参 - self._model = model + import os, glob + import os + import platform + from modelscope import AutoModelForCausalLM, AutoTokenizer, GenerationConfig + + model_id = 'qwen/Qwen-7B-Chat' + revision = 'v1.0.1' + self._tokenizer = AutoTokenizer.from_pretrained(model_id, revision=revision, trust_remote_code=True) + # use fp16 + model = AutoModelForCausalLM.from_pretrained(model_id, device_map="auto", revision=revision, trust_remote_code=True, fp16=True).eval() + model.generation_config = GenerationConfig.from_pretrained(model_id, trust_remote_code=True) # 可指定不同的生成长度、top_p等相关超参 + self._model = model return self._model, self._tokenizer @@ -43,7 +52,7 @@ class GetQwenLMHandle(LocalLLMHandle): query, max_length, top_p, temperature, history = adaptor(kwargs) - for response in self._model.chat_stream(self._tokenizer, query, history=history): + for response in self._model.chat(self._tokenizer, query, history=history, stream=True): yield response def try_to_import_special_deps(self, **kwargs): @@ -56,4 +65,4 @@ class GetQwenLMHandle(LocalLLMHandle): # ------------------------------------------------------------------------------------------------------------------------ # 🔌💻 GPT-Academic Interface # ------------------------------------------------------------------------------------------------------------------------ -predict_no_ui_long_connection, predict = get_local_llm_predict_fns(GetQwenLMHandle, model_name) \ No newline at end of file +predict_no_ui_long_connection, predict = get_local_llm_predict_fns(GetONNXGLMHandle, model_name) \ No newline at end of file diff --git a/request_llms/bridge_spark.py b/request_llm/bridge_spark.py similarity index 75% rename from request_llms/bridge_spark.py rename to request_llm/bridge_spark.py index 8449494c13a60d736058616b4264c589dbb35430..0fe925f7a0354fe6361e9d11ae074dd287813e9f 100644 --- a/request_llms/bridge_spark.py +++ b/request_llm/bridge_spark.py @@ -8,15 +8,15 @@ from multiprocessing import Process, Pipe model_name = '星火认知大模型' def validate_key(): - XFYUN_APPID = get_conf('XFYUN_APPID') - if XFYUN_APPID == '00000000' or XFYUN_APPID == '': + XFYUN_APPID, = get_conf('XFYUN_APPID', ) + if XFYUN_APPID == '00000000' or XFYUN_APPID == '': return False return True def predict_no_ui_long_connection(inputs, llm_kwargs, history=[], sys_prompt="", observe_window=[], console_slience=False): """ ⭐多线程方法 - 函数的说明请见 request_llms/bridge_all.py + 函数的说明请见 request_llm/bridge_all.py """ watch_dog_patience = 5 response = "" @@ -26,7 +26,7 @@ def predict_no_ui_long_connection(inputs, llm_kwargs, history=[], sys_prompt="", from .com_sparkapi import SparkRequestInstance sri = SparkRequestInstance() - for response in sri.generate(inputs, llm_kwargs, history, sys_prompt, use_image_api=False): + for response in sri.generate(inputs, llm_kwargs, history, sys_prompt): if len(observe_window) >= 1: observe_window[0] = response if len(observe_window) >= 2: @@ -36,29 +36,28 @@ def predict_no_ui_long_connection(inputs, llm_kwargs, history=[], sys_prompt="", def predict(inputs, llm_kwargs, plugin_kwargs, chatbot, history=[], system_prompt='', stream = True, additional_fn=None): """ ⭐单线程方法 - 函数的说明请见 request_llms/bridge_all.py + 函数的说明请见 request_llm/bridge_all.py """ chatbot.append((inputs, "")) yield from update_ui(chatbot=chatbot, history=history) if validate_key() is False: - yield from update_ui_lastest_msg(lastmsg="[Local Message] 请配置讯飞星火大模型的XFYUN_APPID, XFYUN_API_KEY, XFYUN_API_SECRET", chatbot=chatbot, history=history, delay=0) + yield from update_ui_lastest_msg(lastmsg="[Local Message]: 请配置讯飞星火大模型的XFYUN_APPID, XFYUN_API_KEY, XFYUN_API_SECRET", chatbot=chatbot, history=history, delay=0) return if additional_fn is not None: from core_functional import handle_core_functionality inputs, history = handle_core_functionality(additional_fn, inputs, history, chatbot) - # 开始接收回复 + # 开始接收回复 from .com_sparkapi import SparkRequestInstance sri = SparkRequestInstance() - response = f"[Local Message] 等待{model_name}响应中 ..." - for response in sri.generate(inputs, llm_kwargs, history, system_prompt, use_image_api=True): + for response in sri.generate(inputs, llm_kwargs, history, system_prompt): chatbot[-1] = (inputs, response) yield from update_ui(chatbot=chatbot, history=history) # 总结输出 - if response == f"[Local Message] 等待{model_name}响应中 ...": - response = f"[Local Message] {model_name}响应异常 ..." + if response == f"[Local Message]: 等待{model_name}响应中 ...": + response = f"[Local Message]: {model_name}响应异常 ..." history.extend([inputs, response]) yield from update_ui(chatbot=chatbot, history=history) \ No newline at end of file diff --git a/request_llms/bridge_stackclaude.py b/request_llm/bridge_stackclaude.py similarity index 53% rename from request_llms/bridge_stackclaude.py rename to request_llm/bridge_stackclaude.py index 21590b8a0853e169d4f9bcf2397d6bb487f19558..3f2ee67428f9c8323eca0f7006ad4d4f767a6b58 100644 --- a/request_llms/bridge_stackclaude.py +++ b/request_llm/bridge_stackclaude.py @@ -7,15 +7,14 @@ import logging import time from toolbox import get_conf import asyncio - load_message = "正在加载Claude组件,请稍候..." try: """ - =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ======================================================================== 第一部分:Slack API Client https://github.com/yokonsan/claude-in-slack-api - =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ======================================================================== """ from slack_sdk.errors import SlackApiError @@ -24,23 +23,20 @@ try: class SlackClient(AsyncWebClient): """SlackClient类用于与Slack API进行交互,实现消息发送、接收等功能。 - 属性: - - CHANNEL_ID:str类型,表示频道ID。 + 属性: + - CHANNEL_ID:str类型,表示频道ID。 - 方法: - - open_channel():异步方法。通过调用conversations_open方法打开一个频道,并将返回的频道ID保存在属性CHANNEL_ID中。 - - chat(text: str):异步方法。向已打开的频道发送一条文本消息。 - - get_slack_messages():异步方法。获取已打开频道的最新消息并返回消息列表,目前不支持历史消息查询。 - - get_reply():异步方法。循环监听已打开频道的消息,如果收到"Typing…_"结尾的消息说明Claude还在继续输出,否则结束循环。 + 方法: + - open_channel():异步方法。通过调用conversations_open方法打开一个频道,并将返回的频道ID保存在属性CHANNEL_ID中。 + - chat(text: str):异步方法。向已打开的频道发送一条文本消息。 + - get_slack_messages():异步方法。获取已打开频道的最新消息并返回消息列表,目前不支持历史消息查询。 + - get_reply():异步方法。循环监听已打开频道的消息,如果收到"Typing…_"结尾的消息说明Claude还在继续输出,否则结束循环。 """ - CHANNEL_ID = None async def open_channel(self): - response = await self.conversations_open( - users=get_conf("SLACK_CLAUDE_BOT_ID") - ) + response = await self.conversations_open(users=get_conf('SLACK_CLAUDE_BOT_ID')[0]) self.CHANNEL_ID = response["channel"]["id"] async def chat(self, text): @@ -53,39 +49,33 @@ try: async def get_slack_messages(self): try: # TODO:暂时不支持历史消息,因为在同一个频道里存在多人使用时历史消息渗透问题 - resp = await self.conversations_history( - channel=self.CHANNEL_ID, oldest=self.LAST_TS, limit=1 - ) - msg = [ - msg - for msg in resp["messages"] - if msg.get("user") == get_conf("SLACK_CLAUDE_BOT_ID") - ] + resp = await self.conversations_history(channel=self.CHANNEL_ID, oldest=self.LAST_TS, limit=1) + msg = [msg for msg in resp["messages"] + if msg.get("user") == get_conf('SLACK_CLAUDE_BOT_ID')[0]] return msg except (SlackApiError, KeyError) as e: raise RuntimeError(f"获取Slack消息失败。") - + async def get_reply(self): while True: slack_msgs = await self.get_slack_messages() if len(slack_msgs) == 0: await asyncio.sleep(0.5) continue - + msg = slack_msgs[-1] if msg["text"].endswith("Typing…_"): yield False, msg["text"] else: yield True, msg["text"] break - except: pass """ -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +======================================================================== 第二部分:子进程Worker(调用主体) -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +======================================================================== """ @@ -98,7 +88,7 @@ class ClaudeHandle(Process): self.success = True self.local_history = [] self.check_dependency() - if self.success: + if self.success: self.start() self.threadLock = threading.Lock() @@ -106,52 +96,47 @@ class ClaudeHandle(Process): try: self.success = False import slack_sdk - self.info = "依赖检测通过,等待Claude响应。注意目前不能多人同时调用Claude接口(有线程锁),否则将导致每个人的Claude问询历史互相渗透。调用Claude时,会自动使用已配置的代理。" self.success = True except: - self.info = "缺少的依赖,如果要使用Claude,除了基础的pip依赖以外,您还需要运行`pip install -r request_llms/requirements_slackclaude.txt`安装Claude的依赖,然后重启程序。" + self.info = "缺少的依赖,如果要使用Claude,除了基础的pip依赖以外,您还需要运行`pip install -r request_llm/requirements_slackclaude.txt`安装Claude的依赖,然后重启程序。" self.success = False def ready(self): - return self.claude_model is not None - + return self.claude_model is not None + async def async_run(self): await self.claude_model.open_channel() while True: # 等待 kwargs = self.child.recv() - question = kwargs["query"] - history = kwargs["history"] + question = kwargs['query'] + history = kwargs['history'] # 开始问问题 prompt = "" # 问题 prompt += question - print("question:", prompt) + print('question:', prompt) # 提交 await self.claude_model.chat(prompt) - + # 获取回复 - async for final, response in self.claude_model.get_reply(): + async for final, response in self.claude_model.get_reply(): if not final: print(response) self.child.send(str(response)) else: # 防止丢失最后一条消息 slack_msgs = await self.claude_model.get_slack_messages() - last_msg = ( - slack_msgs[-1]["text"] - if slack_msgs and len(slack_msgs) > 0 - else "" - ) + last_msg = slack_msgs[-1]["text"] if slack_msgs and len(slack_msgs) > 0 else "" if last_msg: self.child.send(last_msg) - print("-------- receive final ---------") - self.child.send("[Finish]") - + print('-------- receive final ---------') + self.child.send('[Finish]') + def run(self): """ 这个函数运行在子进程 @@ -161,24 +146,22 @@ class ClaudeHandle(Process): self.local_history = [] if (self.claude_model is None) or (not self.success): # 代理设置 - proxies = get_conf("proxies") + proxies, = get_conf('proxies') if proxies is None: self.proxies_https = None else: - self.proxies_https = proxies["https"] + self.proxies_https = proxies['https'] try: - SLACK_CLAUDE_USER_TOKEN = get_conf("SLACK_CLAUDE_USER_TOKEN") - self.claude_model = SlackClient( - token=SLACK_CLAUDE_USER_TOKEN, proxy=self.proxies_https - ) - print("Claude组件初始化成功。") + SLACK_CLAUDE_USER_TOKEN, = get_conf('SLACK_CLAUDE_USER_TOKEN') + self.claude_model = SlackClient(token=SLACK_CLAUDE_USER_TOKEN, proxy=self.proxies_https) + print('Claude组件初始化成功。') except: self.success = False - tb_str = "\n```\n" + trimmed_format_exc() + "\n```\n" - self.child.send(f"[Local Message] 不能加载Claude组件。{tb_str}") - self.child.send("[Fail]") - self.child.send("[Finish]") + tb_str = '\n```\n' + trimmed_format_exc() + '\n```\n' + self.child.send(f'[Local Message] 不能加载Claude组件。{tb_str}') + self.child.send('[Fail]') + self.child.send('[Finish]') raise RuntimeError(f"不能加载Claude组件。") self.success = True @@ -186,49 +169,42 @@ class ClaudeHandle(Process): # 进入任务等待状态 asyncio.run(self.async_run()) except Exception: - tb_str = "\n```\n" + trimmed_format_exc() + "\n```\n" - self.child.send(f"[Local Message] Claude失败 {tb_str}.") - self.child.send("[Fail]") - self.child.send("[Finish]") + tb_str = '\n```\n' + trimmed_format_exc() + '\n```\n' + self.child.send(f'[Local Message] Claude失败 {tb_str}.') + self.child.send('[Fail]') + self.child.send('[Finish]') def stream_chat(self, **kwargs): """ 这个函数运行在主进程 """ self.threadLock.acquire() - self.parent.send(kwargs) # 发送请求到子进程 + self.parent.send(kwargs) # 发送请求到子进程 while True: - res = self.parent.recv() # 等待Claude回复的片段 - if res == "[Finish]": - break # 结束 - elif res == "[Fail]": + res = self.parent.recv() # 等待Claude回复的片段 + if res == '[Finish]': + break # 结束 + elif res == '[Fail]': self.success = False break else: - yield res # Claude回复的片段 + yield res # Claude回复的片段 self.threadLock.release() """ -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +======================================================================== 第三部分:主进程统一调用函数接口 -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +======================================================================== """ global claude_handle claude_handle = None -def predict_no_ui_long_connection( - inputs, - llm_kwargs, - history=[], - sys_prompt="", - observe_window=None, - console_slience=False, -): +def predict_no_ui_long_connection(inputs, llm_kwargs, history=[], sys_prompt="", observe_window=None, console_slience=False): """ - 多线程方法 - 函数的说明请见 request_llms/bridge_all.py + 多线程方法 + 函数的说明请见 request_llm/bridge_all.py """ global claude_handle if (claude_handle is None) or (not claude_handle.success): @@ -241,42 +217,26 @@ def predict_no_ui_long_connection( # 没有 sys_prompt 接口,因此把prompt加入 history history_feedin = [] - for i in range(len(history) // 2): - history_feedin.append([history[2 * i], history[2 * i + 1]]) + for i in range(len(history)//2): + history_feedin.append([history[2*i], history[2*i+1]]) watch_dog_patience = 5 # 看门狗 (watchdog) 的耐心, 设置5秒即可 response = "" - observe_window[0] = "[Local Message] 等待Claude响应中 ..." - for response in claude_handle.stream_chat( - query=inputs, - history=history_feedin, - system_prompt=sys_prompt, - max_length=llm_kwargs["max_length"], - top_p=llm_kwargs["top_p"], - temperature=llm_kwargs["temperature"], - ): + observe_window[0] = "[Local Message]: 等待Claude响应中 ..." + for response in claude_handle.stream_chat(query=inputs, history=history_feedin, system_prompt=sys_prompt, max_length=llm_kwargs['max_length'], top_p=llm_kwargs['top_p'], temperature=llm_kwargs['temperature']): observe_window[0] = preprocess_newbing_out_simple(response) if len(observe_window) >= 2: - if (time.time() - observe_window[1]) > watch_dog_patience: + if (time.time()-observe_window[1]) > watch_dog_patience: raise RuntimeError("程序终止。") return preprocess_newbing_out_simple(response) -def predict( - inputs, - llm_kwargs, - plugin_kwargs, - chatbot, - history=[], - system_prompt="", - stream=True, - additional_fn=None, -): +def predict(inputs, llm_kwargs, plugin_kwargs, chatbot, history=[], system_prompt='', stream=True, additional_fn=None): """ - 单线程方法 - 函数的说明请见 request_llms/bridge_all.py + 单线程方法 + 函数的说明请见 request_llm/bridge_all.py """ - chatbot.append((inputs, "[Local Message] 等待Claude响应中 ...")) + chatbot.append((inputs, "[Local Message]: 等待Claude响应中 ...")) global claude_handle if (claude_handle is None) or (not claude_handle.success): @@ -289,30 +249,21 @@ def predict( if additional_fn is not None: from core_functional import handle_core_functionality - - inputs, history = handle_core_functionality( - additional_fn, inputs, history, chatbot - ) + inputs, history = handle_core_functionality(additional_fn, inputs, history, chatbot) history_feedin = [] - for i in range(len(history) // 2): - history_feedin.append([history[2 * i], history[2 * i + 1]]) - - chatbot[-1] = (inputs, "[Local Message] 等待Claude响应中 ...") - response = "[Local Message] 等待Claude响应中 ..." - yield from update_ui( - chatbot=chatbot, history=history, msg="Claude响应缓慢,尚未完成全部响应,请耐心完成后再提交新问题。" - ) - for response in claude_handle.stream_chat( - query=inputs, history=history_feedin, system_prompt=system_prompt - ): + for i in range(len(history)//2): + history_feedin.append([history[2*i], history[2*i+1]]) + + chatbot[-1] = (inputs, "[Local Message]: 等待Claude响应中 ...") + response = "[Local Message]: 等待Claude响应中 ..." + yield from update_ui(chatbot=chatbot, history=history, msg="Claude响应缓慢,尚未完成全部响应,请耐心完成后再提交新问题。") + for response in claude_handle.stream_chat(query=inputs, history=history_feedin, system_prompt=system_prompt): chatbot[-1] = (inputs, preprocess_newbing_out(response)) - yield from update_ui( - chatbot=chatbot, history=history, msg="Claude响应缓慢,尚未完成全部响应,请耐心完成后再提交新问题。" - ) - if response == "[Local Message] 等待Claude响应中 ...": - response = "[Local Message] Claude响应异常,请刷新界面重试 ..." + yield from update_ui(chatbot=chatbot, history=history, msg="Claude响应缓慢,尚未完成全部响应,请耐心完成后再提交新问题。") + if response == "[Local Message]: 等待Claude响应中 ...": + response = "[Local Message]: Claude响应异常,请刷新界面重试 ..." history.extend([inputs, response]) - logging.info(f"[raw_input] {inputs}") - logging.info(f"[response] {response}") + logging.info(f'[raw_input] {inputs}') + logging.info(f'[response] {response}') yield from update_ui(chatbot=chatbot, history=history, msg="完成全部响应,请提交新问题。") diff --git a/request_llms/bridge_tgui.py b/request_llm/bridge_tgui.py similarity index 100% rename from request_llms/bridge_tgui.py rename to request_llm/bridge_tgui.py diff --git a/request_llms/chatglmoonx.py b/request_llm/chatglmoonx.py similarity index 100% rename from request_llms/chatglmoonx.py rename to request_llm/chatglmoonx.py diff --git a/request_llms/com_sparkapi.py b/request_llm/com_sparkapi.py similarity index 78% rename from request_llms/com_sparkapi.py rename to request_llm/com_sparkapi.py index 359e407ae51a945e87acab6f6363fbb4a6507a0a..ae970b9a1cc1d8fb4f87c9f5ee7f558661185428 100644 --- a/request_llms/com_sparkapi.py +++ b/request_llm/com_sparkapi.py @@ -1,4 +1,4 @@ -from toolbox import get_conf, get_pictures_list, encode_image +from toolbox import get_conf import base64 import datetime import hashlib @@ -64,21 +64,18 @@ class SparkRequestInstance(): self.api_key = XFYUN_API_KEY self.gpt_url = "ws://spark-api.xf-yun.com/v1.1/chat" self.gpt_url_v2 = "ws://spark-api.xf-yun.com/v2.1/chat" - self.gpt_url_v3 = "ws://spark-api.xf-yun.com/v3.1/chat" - self.gpt_url_v35 = "wss://spark-api.xf-yun.com/v3.5/chat" - self.gpt_url_img = "wss://spark-api.cn-huabei-1.xf-yun.com/v2.1/image" self.time_to_yield_event = threading.Event() self.time_to_exit_event = threading.Event() self.result_buf = "" - def generate(self, inputs, llm_kwargs, history, system_prompt, use_image_api=False): + def generate(self, inputs, llm_kwargs, history, system_prompt): llm_kwargs = llm_kwargs history = history system_prompt = system_prompt import _thread as thread - thread.start_new_thread(self.create_blocking_request, (inputs, llm_kwargs, history, system_prompt, use_image_api)) + thread.start_new_thread(self.create_blocking_request, (inputs, llm_kwargs, history, system_prompt)) while True: self.time_to_yield_event.wait(timeout=1) if self.time_to_yield_event.is_set(): @@ -87,22 +84,12 @@ class SparkRequestInstance(): return self.result_buf - def create_blocking_request(self, inputs, llm_kwargs, history, system_prompt, use_image_api): + def create_blocking_request(self, inputs, llm_kwargs, history, system_prompt): if llm_kwargs['llm_model'] == 'sparkv2': gpt_url = self.gpt_url_v2 - elif llm_kwargs['llm_model'] == 'sparkv3': - gpt_url = self.gpt_url_v3 - elif llm_kwargs['llm_model'] == 'sparkv3.5': - gpt_url = self.gpt_url_v35 else: gpt_url = self.gpt_url - file_manifest = [] - if use_image_api and llm_kwargs.get('most_recent_uploaded'): - if llm_kwargs['most_recent_uploaded'].get('path'): - file_manifest = get_pictures_list(llm_kwargs['most_recent_uploaded']['path']) - if len(file_manifest) > 0: - print('正在使用讯飞图片理解API') - gpt_url = self.gpt_url_img + wsParam = Ws_Param(self.appid, self.api_key, self.api_secret, gpt_url) websocket.enableTrace(False) wsUrl = wsParam.create_url() @@ -111,8 +98,9 @@ class SparkRequestInstance(): def on_open(ws): import _thread as thread thread.start_new_thread(run, (ws,)) + def run(ws, *args): - data = json.dumps(gen_params(ws.appid, *ws.all_args, file_manifest)) + data = json.dumps(gen_params(ws.appid, *ws.all_args)) ws.send(data) # 收到websocket消息的处理 @@ -151,18 +139,9 @@ class SparkRequestInstance(): ws.all_args = (inputs, llm_kwargs, history, system_prompt) ws.run_forever(sslopt={"cert_reqs": ssl.CERT_NONE}) -def generate_message_payload(inputs, llm_kwargs, history, system_prompt, file_manifest): +def generate_message_payload(inputs, llm_kwargs, history, system_prompt): conversation_cnt = len(history) // 2 - messages = [] - if file_manifest: - base64_images = [] - for image_path in file_manifest: - base64_images.append(encode_image(image_path)) - for img_s in base64_images: - if img_s not in str(messages): - messages.append({"role": "user", "content": img_s, "content_type": "image"}) - else: - messages = [{"role": "system", "content": system_prompt}] + messages = [{"role": "system", "content": system_prompt}] if conversation_cnt: for index in range(0, 2*conversation_cnt, 2): what_i_have_asked = {} @@ -185,18 +164,10 @@ def generate_message_payload(inputs, llm_kwargs, history, system_prompt, file_ma return messages -def gen_params(appid, inputs, llm_kwargs, history, system_prompt, file_manifest): +def gen_params(appid, inputs, llm_kwargs, history, system_prompt): """ 通过appid和用户的提问来生成请参数 """ - domains = { - "spark": "general", - "sparkv2": "generalv2", - "sparkv3": "generalv3", - "sparkv3.5": "generalv3.5", - } - domains_select = domains[llm_kwargs['llm_model']] - if file_manifest: domains_select = 'image' data = { "header": { "app_id": appid, @@ -204,7 +175,7 @@ def gen_params(appid, inputs, llm_kwargs, history, system_prompt, file_manifest) }, "parameter": { "chat": { - "domain": domains_select, + "domain": "generalv2" if llm_kwargs['llm_model'] == 'sparkv2' else "general", "temperature": llm_kwargs["temperature"], "random_threshold": 0.5, "max_tokens": 4096, @@ -213,7 +184,7 @@ def gen_params(appid, inputs, llm_kwargs, history, system_prompt, file_manifest) }, "payload": { "message": { - "text": generate_message_payload(inputs, llm_kwargs, history, system_prompt, file_manifest) + "text": generate_message_payload(inputs, llm_kwargs, history, system_prompt) } } } diff --git a/request_llm/edge_gpt.py b/request_llm/edge_gpt.py new file mode 100644 index 0000000000000000000000000000000000000000..bbf84000d84a42de80d3c051a24f06336af76aaf --- /dev/null +++ b/request_llm/edge_gpt.py @@ -0,0 +1,409 @@ +""" +======================================================================== +第一部分:来自EdgeGPT.py +https://github.com/acheong08/EdgeGPT +======================================================================== +""" + +import argparse +import asyncio +import json +import os +import random +import re +import ssl +import sys +import uuid +from enum import Enum +from typing import Generator +from typing import Literal +from typing import Optional +from typing import Union +import websockets.client as websockets + +DELIMITER = "\x1e" + + +# Generate random IP between range 13.104.0.0/14 +FORWARDED_IP = ( + f"13.{random.randint(104, 107)}.{random.randint(0, 255)}.{random.randint(0, 255)}" +) + +HEADERS = { + "accept": "application/json", + "accept-language": "en-US,en;q=0.9", + "content-type": "application/json", + "sec-ch-ua": '"Not_A Brand";v="99", "Microsoft Edge";v="110", "Chromium";v="110"', + "sec-ch-ua-arch": '"x86"', + "sec-ch-ua-bitness": '"64"', + "sec-ch-ua-full-version": '"109.0.1518.78"', + "sec-ch-ua-full-version-list": '"Chromium";v="110.0.5481.192", "Not A(Brand";v="24.0.0.0", "Microsoft Edge";v="110.0.1587.69"', + "sec-ch-ua-mobile": "?0", + "sec-ch-ua-model": "", + "sec-ch-ua-platform": '"Windows"', + "sec-ch-ua-platform-version": '"15.0.0"', + "sec-fetch-dest": "empty", + "sec-fetch-mode": "cors", + "sec-fetch-site": "same-origin", + "x-ms-client-request-id": str(uuid.uuid4()), + "x-ms-useragent": "azsdk-js-api-client-factory/1.0.0-beta.1 core-rest-pipeline/1.10.0 OS/Win32", + "Referer": "https://www.bing.com/search?q=Bing+AI&showconv=1&FORM=hpcodx", + "Referrer-Policy": "origin-when-cross-origin", + "x-forwarded-for": FORWARDED_IP, +} + +HEADERS_INIT_CONVER = { + "authority": "edgeservices.bing.com", + "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", + "accept-language": "en-US,en;q=0.9", + "cache-control": "max-age=0", + "sec-ch-ua": '"Chromium";v="110", "Not A(Brand";v="24", "Microsoft Edge";v="110"', + "sec-ch-ua-arch": '"x86"', + "sec-ch-ua-bitness": '"64"', + "sec-ch-ua-full-version": '"110.0.1587.69"', + "sec-ch-ua-full-version-list": '"Chromium";v="110.0.5481.192", "Not A(Brand";v="24.0.0.0", "Microsoft Edge";v="110.0.1587.69"', + "sec-ch-ua-mobile": "?0", + "sec-ch-ua-model": '""', + "sec-ch-ua-platform": '"Windows"', + "sec-ch-ua-platform-version": '"15.0.0"', + "sec-fetch-dest": "document", + "sec-fetch-mode": "navigate", + "sec-fetch-site": "none", + "sec-fetch-user": "?1", + "upgrade-insecure-requests": "1", + "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36 Edg/110.0.1587.69", + "x-edge-shopping-flag": "1", + "x-forwarded-for": FORWARDED_IP, +} + +def get_ssl_context(): + import certifi + ssl_context = ssl.create_default_context() + ssl_context.load_verify_locations(certifi.where()) + return ssl_context + + + +class NotAllowedToAccess(Exception): + pass + + +class ConversationStyle(Enum): + creative = "h3imaginative,clgalileo,gencontentv3" + balanced = "galileo" + precise = "h3precise,clgalileo" + + +CONVERSATION_STYLE_TYPE = Optional[ + Union[ConversationStyle, Literal["creative", "balanced", "precise"]] +] + + +def _append_identifier(msg: dict) -> str: + """ + Appends special character to end of message to identify end of message + """ + # Convert dict to json string + return json.dumps(msg) + DELIMITER + + +def _get_ran_hex(length: int = 32) -> str: + """ + Returns random hex string + """ + return "".join(random.choice("0123456789abcdef") for _ in range(length)) + + +class _ChatHubRequest: + """ + Request object for ChatHub + """ + + def __init__( + self, + conversation_signature: str, + client_id: str, + conversation_id: str, + invocation_id: int = 0, + ) -> None: + self.struct: dict = {} + + self.client_id: str = client_id + self.conversation_id: str = conversation_id + self.conversation_signature: str = conversation_signature + self.invocation_id: int = invocation_id + + def update( + self, + prompt, + conversation_style, + options, + ) -> None: + """ + Updates request object + """ + if options is None: + options = [ + "deepleo", + "enable_debug_commands", + "disable_emoji_spoken_text", + "enablemm", + ] + if conversation_style: + if not isinstance(conversation_style, ConversationStyle): + conversation_style = getattr(ConversationStyle, conversation_style) + options = [ + "nlu_direct_response_filter", + "deepleo", + "disable_emoji_spoken_text", + "responsible_ai_policy_235", + "enablemm", + conversation_style.value, + "dtappid", + "cricinfo", + "cricinfov2", + "dv3sugg", + ] + self.struct = { + "arguments": [ + { + "source": "cib", + "optionsSets": options, + "sliceIds": [ + "222dtappid", + "225cricinfo", + "224locals0", + ], + "traceId": _get_ran_hex(32), + "isStartOfSession": self.invocation_id == 0, + "message": { + "author": "user", + "inputMethod": "Keyboard", + "text": prompt, + "messageType": "Chat", + }, + "conversationSignature": self.conversation_signature, + "participant": { + "id": self.client_id, + }, + "conversationId": self.conversation_id, + }, + ], + "invocationId": str(self.invocation_id), + "target": "chat", + "type": 4, + } + self.invocation_id += 1 + + +class _Conversation: + """ + Conversation API + """ + + def __init__( + self, + cookies, + proxy, + ) -> None: + self.struct: dict = { + "conversationId": None, + "clientId": None, + "conversationSignature": None, + "result": {"value": "Success", "message": None}, + } + import httpx + self.proxy = proxy + proxy = ( + proxy + or os.environ.get("all_proxy") + or os.environ.get("ALL_PROXY") + or os.environ.get("https_proxy") + or os.environ.get("HTTPS_PROXY") + or None + ) + if proxy is not None and proxy.startswith("socks5h://"): + proxy = "socks5://" + proxy[len("socks5h://") :] + self.session = httpx.Client( + proxies=proxy, + timeout=30, + headers=HEADERS_INIT_CONVER, + ) + for cookie in cookies: + self.session.cookies.set(cookie["name"], cookie["value"]) + + # Send GET request + response = self.session.get( + url=os.environ.get("BING_PROXY_URL") + or "https://edgeservices.bing.com/edgesvc/turing/conversation/create", + ) + if response.status_code != 200: + response = self.session.get( + "https://edge.churchless.tech/edgesvc/turing/conversation/create", + ) + if response.status_code != 200: + print(f"Status code: {response.status_code}") + print(response.text) + print(response.url) + raise Exception("Authentication failed") + try: + self.struct = response.json() + except (json.decoder.JSONDecodeError, NotAllowedToAccess) as exc: + raise Exception( + "Authentication failed. You have not been accepted into the beta.", + ) from exc + if self.struct["result"]["value"] == "UnauthorizedRequest": + raise NotAllowedToAccess(self.struct["result"]["message"]) + + +class _ChatHub: + """ + Chat API + """ + + def __init__(self, conversation) -> None: + self.wss = None + self.request: _ChatHubRequest + self.loop: bool + self.task: asyncio.Task + print(conversation.struct) + self.request = _ChatHubRequest( + conversation_signature=conversation.struct["conversationSignature"], + client_id=conversation.struct["clientId"], + conversation_id=conversation.struct["conversationId"], + ) + + async def ask_stream( + self, + prompt: str, + wss_link: str, + conversation_style: CONVERSATION_STYLE_TYPE = None, + raw: bool = False, + options: dict = None, + ) -> Generator[str, None, None]: + """ + Ask a question to the bot + """ + if self.wss and not self.wss.closed: + await self.wss.close() + # Check if websocket is closed + self.wss = await websockets.connect( + wss_link, + extra_headers=HEADERS, + max_size=None, + ssl=get_ssl_context() + ) + await self._initial_handshake() + # Construct a ChatHub request + self.request.update( + prompt=prompt, + conversation_style=conversation_style, + options=options, + ) + # Send request + await self.wss.send(_append_identifier(self.request.struct)) + final = False + while not final: + objects = str(await self.wss.recv()).split(DELIMITER) + for obj in objects: + if obj is None or not obj: + continue + response = json.loads(obj) + if response.get("type") != 2 and raw: + yield False, response + elif response.get("type") == 1 and response["arguments"][0].get( + "messages", + ): + resp_txt = response["arguments"][0]["messages"][0]["adaptiveCards"][ + 0 + ]["body"][0].get("text") + yield False, resp_txt + elif response.get("type") == 2: + final = True + yield True, response + + async def _initial_handshake(self) -> None: + await self.wss.send(_append_identifier({"protocol": "json", "version": 1})) + await self.wss.recv() + + async def close(self) -> None: + """ + Close the connection + """ + if self.wss and not self.wss.closed: + await self.wss.close() + + +class NewbingChatbot: + """ + Combines everything to make it seamless + """ + + def __init__( + self, + cookies, + proxy + ) -> None: + if cookies is None: + cookies = {} + self.cookies = cookies + self.proxy = proxy + self.chat_hub: _ChatHub = _ChatHub( + _Conversation(self.cookies, self.proxy), + ) + + async def ask( + self, + prompt: str, + wss_link: str, + conversation_style: CONVERSATION_STYLE_TYPE = None, + options: dict = None, + ) -> dict: + """ + Ask a question to the bot + """ + async for final, response in self.chat_hub.ask_stream( + prompt=prompt, + conversation_style=conversation_style, + wss_link=wss_link, + options=options, + ): + if final: + return response + await self.chat_hub.wss.close() + return None + + async def ask_stream( + self, + prompt: str, + wss_link: str, + conversation_style: CONVERSATION_STYLE_TYPE = None, + raw: bool = False, + options: dict = None, + ) -> Generator[str, None, None]: + """ + Ask a question to the bot + """ + async for response in self.chat_hub.ask_stream( + prompt=prompt, + conversation_style=conversation_style, + wss_link=wss_link, + raw=raw, + options=options, + ): + yield response + + async def close(self) -> None: + """ + Close the connection + """ + await self.chat_hub.close() + + async def reset(self) -> None: + """ + Reset the conversation + """ + await self.close() + self.chat_hub = _ChatHub(_Conversation(self.cookies, self.proxy)) + + diff --git a/request_llms/edge_gpt_free.py b/request_llm/edge_gpt_free.py similarity index 98% rename from request_llms/edge_gpt_free.py rename to request_llm/edge_gpt_free.py index d0122a52852fcb0f369d2269410569d8cad7c73b..22ff05272b634e8557ceb83501248cc238074366 100644 --- a/request_llms/edge_gpt_free.py +++ b/request_llm/edge_gpt_free.py @@ -1,8 +1,8 @@ """ -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +======================================================================== 第一部分:来自EdgeGPT.py https://github.com/acheong08/EdgeGPT -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +======================================================================== """ """ Main.py @@ -196,9 +196,9 @@ class _ChatHubRequest: self, prompt: str, conversation_style: CONVERSATION_STYLE_TYPE, - options=None, - webpage_context=None, - search_result=False, + options = None, + webpage_context = None, + search_result = False, ) -> None: """ Updates request object @@ -294,9 +294,9 @@ class _Conversation: def __init__( self, - proxy=None, - async_mode=False, - cookies=None, + proxy = None, + async_mode = False, + cookies = None, ) -> None: if async_mode: return @@ -350,8 +350,8 @@ class _Conversation: @staticmethod async def create( - proxy=None, - cookies=None, + proxy = None, + cookies = None, ): self = _Conversation(async_mode=True) self.struct = { @@ -418,8 +418,8 @@ class _ChatHub: def __init__( self, conversation: _Conversation, - proxy=None, - cookies=None, + proxy = None, + cookies = None, ) -> None: self.session = None self.wss = None @@ -441,7 +441,7 @@ class _ChatHub: conversation_style: CONVERSATION_STYLE_TYPE = None, raw: bool = False, options: dict = None, - webpage_context=None, + webpage_context = None, search_result: bool = False, ) -> Generator[str, None, None]: """ @@ -452,12 +452,10 @@ class _ChatHub: ws_cookies = [] for cookie in self.cookies: ws_cookies.append(f"{cookie['name']}={cookie['value']}") - req_header.update( - { - "Cookie": ";".join(ws_cookies), - } - ) - + req_header.update({ + 'Cookie': ';'.join(ws_cookies), + }) + timeout = aiohttp.ClientTimeout(total=30) self.session = aiohttp.ClientSession(timeout=timeout) @@ -523,9 +521,9 @@ class _ChatHub: msg = await self.wss.receive() try: objects = msg.data.split(DELIMITER) - except: + except : continue - + for obj in objects: if obj is None or not obj: continue @@ -626,8 +624,8 @@ class Chatbot: def __init__( self, - proxy=None, - cookies=None, + proxy = None, + cookies = None, ) -> None: self.proxy = proxy self.chat_hub: _ChatHub = _ChatHub( @@ -638,8 +636,8 @@ class Chatbot: @staticmethod async def create( - proxy=None, - cookies=None, + proxy = None, + cookies = None, ): self = Chatbot.__new__(Chatbot) self.proxy = proxy @@ -656,7 +654,7 @@ class Chatbot: wss_link: str = "wss://sydney.bing.com/sydney/ChatHub", conversation_style: CONVERSATION_STYLE_TYPE = None, options: dict = None, - webpage_context=None, + webpage_context = None, search_result: bool = False, ) -> dict: """ @@ -682,7 +680,7 @@ class Chatbot: conversation_style: CONVERSATION_STYLE_TYPE = None, raw: bool = False, options: dict = None, - webpage_context=None, + webpage_context = None, search_result: bool = False, ) -> Generator[str, None, None]: """ diff --git a/request_llm/local_llm_class.py b/request_llm/local_llm_class.py new file mode 100644 index 0000000000000000000000000000000000000000..c9c7253440e9630ec77524598ad9a4a318190739 --- /dev/null +++ b/request_llm/local_llm_class.py @@ -0,0 +1,180 @@ +from transformers import AutoModel, AutoTokenizer +import time +import threading +import importlib +from toolbox import update_ui, get_conf, Singleton +from multiprocessing import Process, Pipe + +def SingletonLocalLLM(cls): + """ + 一个单实例装饰器 + """ + _instance = {} + def _singleton(*args, **kargs): + if cls not in _instance: + _instance[cls] = cls(*args, **kargs) + return _instance[cls] + elif _instance[cls].corrupted: + _instance[cls] = cls(*args, **kargs) + return _instance[cls] + else: + return _instance[cls] + return _singleton + +class LocalLLMHandle(Process): + def __init__(self): + # ⭐主进程执行 + super().__init__(daemon=True) + self.corrupted = False + self.load_model_info() + self.parent, self.child = Pipe() + self.running = True + self._model = None + self._tokenizer = None + self.info = "" + self.check_dependency() + self.start() + self.threadLock = threading.Lock() + + def load_model_info(self): + # 🏃‍♂️🏃‍♂️🏃‍♂️ 子进程执行 + raise NotImplementedError("Method not implemented yet") + self.model_name = "" + self.cmd_to_install = "" + + def load_model_and_tokenizer(self): + """ + This function should return the model and the tokenizer + """ + # 🏃‍♂️🏃‍♂️🏃‍♂️ 子进程执行 + raise NotImplementedError("Method not implemented yet") + + def llm_stream_generator(self, **kwargs): + # 🏃‍♂️🏃‍♂️🏃‍♂️ 子进程执行 + raise NotImplementedError("Method not implemented yet") + + def try_to_import_special_deps(self, **kwargs): + """ + import something that will raise error if the user does not install requirement_*.txt + """ + # ⭐主进程执行 + raise NotImplementedError("Method not implemented yet") + + def check_dependency(self): + # ⭐主进程执行 + try: + self.try_to_import_special_deps() + self.info = "依赖检测通过" + self.running = True + except: + self.info = f"缺少{self.model_name}的依赖,如果要使用{self.model_name},除了基础的pip依赖以外,您还需要运行{self.cmd_to_install}安装{self.model_name}的依赖。" + self.running = False + + def run(self): + # 🏃‍♂️🏃‍♂️🏃‍♂️ 子进程执行 + # 第一次运行,加载参数 + try: + self._model, self._tokenizer = self.load_model_and_tokenizer() + except: + self.running = False + from toolbox import trimmed_format_exc + self.child.send(f'[Local Message] 不能正常加载{self.model_name}的参数.' + '\n```\n' + trimmed_format_exc() + '\n```\n') + self.child.send('[FinishBad]') + raise RuntimeError(f"不能正常加载{self.model_name}的参数!") + + while True: + # 进入任务等待状态 + kwargs = self.child.recv() + # 收到消息,开始请求 + try: + for response_full in self.llm_stream_generator(**kwargs): + self.child.send(response_full) + self.child.send('[Finish]') + # 请求处理结束,开始下一个循环 + except: + from toolbox import trimmed_format_exc + self.child.send(f'[Local Message] 调用{self.model_name}失败.' + '\n```\n' + trimmed_format_exc() + '\n```\n') + self.child.send('[Finish]') + + def stream_chat(self, **kwargs): + # ⭐主进程执行 + self.threadLock.acquire() + self.parent.send(kwargs) + while True: + res = self.parent.recv() + if res == '[Finish]': + break + if res == '[FinishBad]': + self.running = False + self.corrupted = True + break + else: + yield res + self.threadLock.release() + + + +def get_local_llm_predict_fns(LLMSingletonClass, model_name): + load_message = f"{model_name}尚未加载,加载需要一段时间。注意,取决于`config.py`的配置,{model_name}消耗大量的内存(CPU)或显存(GPU),也许会导致低配计算机卡死 ……" + + def predict_no_ui_long_connection(inputs, llm_kwargs, history=[], sys_prompt="", observe_window=[], console_slience=False): + """ + ⭐多线程方法 + 函数的说明请见 request_llm/bridge_all.py + """ + _llm_handle = LLMSingletonClass() + if len(observe_window) >= 1: observe_window[0] = load_message + "\n\n" + _llm_handle.info + if not _llm_handle.running: raise RuntimeError(_llm_handle.info) + + # chatglm 没有 sys_prompt 接口,因此把prompt加入 history + history_feedin = [] + history_feedin.append([sys_prompt, "Certainly!"]) + for i in range(len(history)//2): + history_feedin.append([history[2*i], history[2*i+1]] ) + + watch_dog_patience = 5 # 看门狗 (watchdog) 的耐心, 设置5秒即可 + response = "" + for response in _llm_handle.stream_chat(query=inputs, history=history_feedin, max_length=llm_kwargs['max_length'], top_p=llm_kwargs['top_p'], temperature=llm_kwargs['temperature']): + if len(observe_window) >= 1: + observe_window[0] = response + if len(observe_window) >= 2: + if (time.time()-observe_window[1]) > watch_dog_patience: raise RuntimeError("程序终止。") + return response + + + + def predict(inputs, llm_kwargs, plugin_kwargs, chatbot, history=[], system_prompt='', stream = True, additional_fn=None): + """ + ⭐单线程方法 + 函数的说明请见 request_llm/bridge_all.py + """ + chatbot.append((inputs, "")) + + _llm_handle = LLMSingletonClass() + chatbot[-1] = (inputs, load_message + "\n\n" + _llm_handle.info) + yield from update_ui(chatbot=chatbot, history=[]) + if not _llm_handle.running: raise RuntimeError(_llm_handle.info) + + if additional_fn is not None: + from core_functional import handle_core_functionality + inputs, history = handle_core_functionality(additional_fn, inputs, history, chatbot) + + # 处理历史信息 + history_feedin = [] + history_feedin.append([system_prompt, "Certainly!"]) + for i in range(len(history)//2): + history_feedin.append([history[2*i], history[2*i+1]] ) + + # 开始接收回复 + response = f"[Local Message]: 等待{model_name}响应中 ..." + for response in _llm_handle.stream_chat(query=inputs, history=history_feedin, max_length=llm_kwargs['max_length'], top_p=llm_kwargs['top_p'], temperature=llm_kwargs['temperature']): + chatbot[-1] = (inputs, response) + yield from update_ui(chatbot=chatbot, history=history) + + # 总结输出 + if response == f"[Local Message]: 等待{model_name}响应中 ...": + response = f"[Local Message]: {model_name}响应异常 ..." + history.extend([inputs, response]) + yield from update_ui(chatbot=chatbot, history=history) + + return predict_no_ui_long_connection, predict \ No newline at end of file diff --git a/request_llms/requirements_chatglm.txt b/request_llm/requirements_chatglm.txt similarity index 56% rename from request_llms/requirements_chatglm.txt rename to request_llm/requirements_chatglm.txt index dabdd8ea519c3f9e59031bb6b73d55502c89f99a..b2629f83d9dc3e54589d59c02de585afa58772b4 100644 --- a/request_llms/requirements_chatglm.txt +++ b/request_llm/requirements_chatglm.txt @@ -1,5 +1,6 @@ protobuf +transformers>=4.27.1 cpm_kernels torch>=1.10 mdtex2html -sentencepiece +sentencepiece \ No newline at end of file diff --git a/request_llms/requirements_chatglm_onnx.txt b/request_llm/requirements_chatglm_onnx.txt similarity index 66% rename from request_llms/requirements_chatglm_onnx.txt rename to request_llm/requirements_chatglm_onnx.txt index 2cd11f69d06adea5a276d6832e6571b7e66c2a5c..70ab6684a7c3472daa381154f276725ca91840fa 100644 --- a/request_llms/requirements_chatglm_onnx.txt +++ b/request_llm/requirements_chatglm_onnx.txt @@ -1,4 +1,5 @@ protobuf +transformers>=4.27.1 cpm_kernels torch>=1.10 mdtex2html @@ -6,3 +7,5 @@ sentencepiece numpy onnxruntime sentencepiece +streamlit +streamlit-chat diff --git a/request_llms/requirements_jittorllms.txt b/request_llm/requirements_jittorllms.txt similarity index 69% rename from request_llms/requirements_jittorllms.txt rename to request_llm/requirements_jittorllms.txt index 2bd2da8bb2b8cc3624758c52e1bd429d95df607c..1d86ff81eb096542ef8e1a903947ea40f826238a 100644 --- a/request_llms/requirements_jittorllms.txt +++ b/request_llm/requirements_jittorllms.txt @@ -2,5 +2,6 @@ jittor >= 1.3.7.9 jtorch >= 0.1.3 torch torchvision +transformers==4.26.1 pandas -jieba +jieba \ No newline at end of file diff --git a/request_llms/requirements_moss.txt b/request_llm/requirements_moss.txt similarity index 69% rename from request_llms/requirements_moss.txt rename to request_llm/requirements_moss.txt index a1f84f0415d98a848a412d6bce77d90792de633f..8dd75bffbe224648b6bc2c3a3b21bb49803ba8da 100644 --- a/request_llms/requirements_moss.txt +++ b/request_llm/requirements_moss.txt @@ -1,7 +1,10 @@ torch +transformers==4.25.1 sentencepiece datasets accelerate matplotlib huggingface_hub triton +streamlit + diff --git a/request_llms/requirements_newbing.txt b/request_llm/requirements_newbing.txt similarity index 100% rename from request_llms/requirements_newbing.txt rename to request_llm/requirements_newbing.txt diff --git a/request_llm/requirements_qwen.txt b/request_llm/requirements_qwen.txt new file mode 100644 index 0000000000000000000000000000000000000000..3d7d62a05d2023abc94dbbe1c61ff49fc7796c41 --- /dev/null +++ b/request_llm/requirements_qwen.txt @@ -0,0 +1,2 @@ +modelscope +transformers_stream_generator \ No newline at end of file diff --git a/request_llm/requirements_slackclaude.txt b/request_llm/requirements_slackclaude.txt new file mode 100644 index 0000000000000000000000000000000000000000..472d58c2844b20e171720c873d794959c24fdce7 --- /dev/null +++ b/request_llm/requirements_slackclaude.txt @@ -0,0 +1 @@ +slack-sdk==3.21.3 \ No newline at end of file diff --git a/request_llm/test_llms.py b/request_llm/test_llms.py new file mode 100644 index 0000000000000000000000000000000000000000..ae6967be7b0c48d4c2af7a51335bd9becbc24d88 --- /dev/null +++ b/request_llm/test_llms.py @@ -0,0 +1,78 @@ +# """ +# 对各个llm模型进行单元测试 +# """ +def validate_path(): + import os, sys + dir_name = os.path.dirname(__file__) + root_dir_assume = os.path.abspath(os.path.dirname(__file__) + '/..') + os.chdir(root_dir_assume) + sys.path.append(root_dir_assume) + +validate_path() # validate path so you can run from base directory +if __name__ == "__main__": + from request_llm.bridge_newbingfree import predict_no_ui_long_connection + # from request_llm.bridge_moss import predict_no_ui_long_connection + # from request_llm.bridge_jittorllms_pangualpha import predict_no_ui_long_connection + # from request_llm.bridge_jittorllms_llama import predict_no_ui_long_connection + + llm_kwargs = { + 'max_length': 512, + 'top_p': 1, + 'temperature': 1, + } + + result = predict_no_ui_long_connection(inputs="你好", + llm_kwargs=llm_kwargs, + history=[], + sys_prompt="") + print('final result:', result) + + + result = predict_no_ui_long_connection(inputs="what is a hero?", + llm_kwargs=llm_kwargs, + history=["hello world"], + sys_prompt="") + print('final result:', result) + + result = predict_no_ui_long_connection(inputs="如何理解传奇?", + llm_kwargs=llm_kwargs, + history=[], + sys_prompt="") + print('final result:', result) + + # # print(result) + # from multiprocessing import Process, Pipe + # class GetGLMHandle(Process): + # def __init__(self): + # super().__init__(daemon=True) + # pass + # def run(self): + # # 子进程执行 + # # 第一次运行,加载参数 + # def validate_path(): + # import os, sys + # dir_name = os.path.dirname(__file__) + # root_dir_assume = os.path.abspath(os.path.dirname(__file__) + '/..') + # os.chdir(root_dir_assume + '/request_llm/jittorllms') + # sys.path.append(root_dir_assume + '/request_llm/jittorllms') + # validate_path() # validate path so you can run from base directory + + # jittorllms_model = None + # import types + # try: + # if jittorllms_model is None: + # from models import get_model + # # availabel_models = ["chatglm", "pangualpha", "llama", "chatrwkv"] + # args_dict = {'model': 'chatrwkv'} + # print('self.jittorllms_model = get_model(types.SimpleNamespace(**args_dict))') + # jittorllms_model = get_model(types.SimpleNamespace(**args_dict)) + # print('done get model') + # except: + # # self.child.send('[Local Message] Call jittorllms fail 不能正常加载jittorllms的参数。') + # raise RuntimeError("不能正常加载jittorllms的参数!") + + # x = GetGLMHandle() + # x.start() + + + # input() \ No newline at end of file diff --git a/request_llms/README.md b/request_llms/README.md deleted file mode 100644 index 5a51592ab8751bed5583532c8d552ba492c54c86..0000000000000000000000000000000000000000 --- a/request_llms/README.md +++ /dev/null @@ -1,35 +0,0 @@ -P.S. 如果您按照以下步骤成功接入了新的大模型,欢迎发Pull Requests(如果您在自己接入新模型的过程中遇到困难,欢迎加README底部QQ群联系群主) - - -# 如何接入其他本地大语言模型 - -1. 复制`request_llms/bridge_llama2.py`,重命名为你喜欢的名字 - -2. 修改`load_model_and_tokenizer`方法,加载你的模型和分词器(去该模型官网找demo,复制粘贴即可) - -3. 修改`llm_stream_generator`方法,定义推理模型(去该模型官网找demo,复制粘贴即可) - -4. 命令行测试 - - 修改`tests/test_llms.py`(聪慧如您,只需要看一眼该文件就明白怎么修改了) - - 运行`python tests/test_llms.py` - -5. 测试通过后,在`request_llms/bridge_all.py`中做最后的修改,把你的模型完全接入到框架中(聪慧如您,只需要看一眼该文件就明白怎么修改了) - -6. 修改`LLM_MODEL`配置,然后运行`python main.py`,测试最后的效果 - - -# 如何接入其他在线大语言模型 - -1. 复制`request_llms/bridge_zhipu.py`,重命名为你喜欢的名字 - -2. 修改`predict_no_ui_long_connection` - -3. 修改`predict` - -4. 命令行测试 - - 修改`tests/test_llms.py`(聪慧如您,只需要看一眼该文件就明白怎么修改了) - - 运行`python tests/test_llms.py` - -5. 测试通过后,在`request_llms/bridge_all.py`中做最后的修改,把你的模型完全接入到框架中(聪慧如您,只需要看一眼该文件就明白怎么修改了) - -6. 修改`LLM_MODEL`配置,然后运行`python main.py`,测试最后的效果 diff --git a/request_llms/bridge_chatglm.py b/request_llms/bridge_chatglm.py deleted file mode 100644 index c58495dccfc7d64f194b5f6904b6660141c41cad..0000000000000000000000000000000000000000 --- a/request_llms/bridge_chatglm.py +++ /dev/null @@ -1,78 +0,0 @@ -model_name = "ChatGLM" -cmd_to_install = "`pip install -r request_llms/requirements_chatglm.txt`" - - -from toolbox import get_conf, ProxyNetworkActivate -from .local_llm_class import LocalLLMHandle, get_local_llm_predict_fns - - - -# ------------------------------------------------------------------------------------------------------------------------ -# 🔌💻 Local Model -# ------------------------------------------------------------------------------------------------------------------------ -class GetGLM2Handle(LocalLLMHandle): - - def load_model_info(self): - # 🏃‍♂️🏃‍♂️🏃‍♂️ 子进程执行 - self.model_name = model_name - self.cmd_to_install = cmd_to_install - - def load_model_and_tokenizer(self): - # 🏃‍♂️🏃‍♂️🏃‍♂️ 子进程执行 - import os, glob - import os - import platform - from transformers import AutoModel, AutoTokenizer - LOCAL_MODEL_QUANT, device = get_conf('LOCAL_MODEL_QUANT', 'LOCAL_MODEL_DEVICE') - - if LOCAL_MODEL_QUANT == "INT4": # INT4 - _model_name_ = "THUDM/chatglm2-6b-int4" - elif LOCAL_MODEL_QUANT == "INT8": # INT8 - _model_name_ = "THUDM/chatglm2-6b-int8" - else: - _model_name_ = "THUDM/chatglm2-6b" # FP16 - - with ProxyNetworkActivate('Download_LLM'): - chatglm_tokenizer = AutoTokenizer.from_pretrained(_model_name_, trust_remote_code=True) - if device=='cpu': - chatglm_model = AutoModel.from_pretrained(_model_name_, trust_remote_code=True).float() - else: - chatglm_model = AutoModel.from_pretrained(_model_name_, trust_remote_code=True).half().cuda() - chatglm_model = chatglm_model.eval() - - self._model = chatglm_model - self._tokenizer = chatglm_tokenizer - return self._model, self._tokenizer - - def llm_stream_generator(self, **kwargs): - # 🏃‍♂️🏃‍♂️🏃‍♂️ 子进程执行 - def adaptor(kwargs): - query = kwargs['query'] - max_length = kwargs['max_length'] - top_p = kwargs['top_p'] - temperature = kwargs['temperature'] - history = kwargs['history'] - return query, max_length, top_p, temperature, history - - query, max_length, top_p, temperature, history = adaptor(kwargs) - - for response, history in self._model.stream_chat(self._tokenizer, - query, - history, - max_length=max_length, - top_p=top_p, - temperature=temperature, - ): - yield response - - def try_to_import_special_deps(self, **kwargs): - # import something that will raise error if the user does not install requirement_*.txt - # 🏃‍♂️🏃‍♂️🏃‍♂️ 主进程执行 - import importlib - # importlib.import_module('modelscope') - - -# ------------------------------------------------------------------------------------------------------------------------ -# 🔌💻 GPT-Academic Interface -# ------------------------------------------------------------------------------------------------------------------------ -predict_no_ui_long_connection, predict = get_local_llm_predict_fns(GetGLM2Handle, model_name) \ No newline at end of file diff --git a/request_llms/bridge_chatglm3.py b/request_llms/bridge_chatglm3.py deleted file mode 100644 index 3caa4769d39ae8f56780caf43ddff6373600410d..0000000000000000000000000000000000000000 --- a/request_llms/bridge_chatglm3.py +++ /dev/null @@ -1,77 +0,0 @@ -model_name = "ChatGLM3" -cmd_to_install = "`pip install -r request_llms/requirements_chatglm.txt`" - - -from toolbox import get_conf, ProxyNetworkActivate -from .local_llm_class import LocalLLMHandle, get_local_llm_predict_fns - - - -# ------------------------------------------------------------------------------------------------------------------------ -# 🔌💻 Local Model -# ------------------------------------------------------------------------------------------------------------------------ -class GetGLM3Handle(LocalLLMHandle): - - def load_model_info(self): - # 🏃‍♂️🏃‍♂️🏃‍♂️ 子进程执行 - self.model_name = model_name - self.cmd_to_install = cmd_to_install - - def load_model_and_tokenizer(self): - # 🏃‍♂️🏃‍♂️🏃‍♂️ 子进程执行 - from transformers import AutoModel, AutoTokenizer - import os, glob - import os - import platform - LOCAL_MODEL_QUANT, device = get_conf('LOCAL_MODEL_QUANT', 'LOCAL_MODEL_DEVICE') - - if LOCAL_MODEL_QUANT == "INT4": # INT4 - _model_name_ = "THUDM/chatglm3-6b-int4" - elif LOCAL_MODEL_QUANT == "INT8": # INT8 - _model_name_ = "THUDM/chatglm3-6b-int8" - else: - _model_name_ = "THUDM/chatglm3-6b" # FP16 - with ProxyNetworkActivate('Download_LLM'): - chatglm_tokenizer = AutoTokenizer.from_pretrained(_model_name_, trust_remote_code=True) - if device=='cpu': - chatglm_model = AutoModel.from_pretrained(_model_name_, trust_remote_code=True, device='cpu').float() - else: - chatglm_model = AutoModel.from_pretrained(_model_name_, trust_remote_code=True, device='cuda') - chatglm_model = chatglm_model.eval() - - self._model = chatglm_model - self._tokenizer = chatglm_tokenizer - return self._model, self._tokenizer - - def llm_stream_generator(self, **kwargs): - # 🏃‍♂️🏃‍♂️🏃‍♂️ 子进程执行 - def adaptor(kwargs): - query = kwargs['query'] - max_length = kwargs['max_length'] - top_p = kwargs['top_p'] - temperature = kwargs['temperature'] - history = kwargs['history'] - return query, max_length, top_p, temperature, history - - query, max_length, top_p, temperature, history = adaptor(kwargs) - - for response, history in self._model.stream_chat(self._tokenizer, - query, - history, - max_length=max_length, - top_p=top_p, - temperature=temperature, - ): - yield response - - def try_to_import_special_deps(self, **kwargs): - # import something that will raise error if the user does not install requirement_*.txt - # 🏃‍♂️🏃‍♂️🏃‍♂️ 主进程执行 - import importlib - # importlib.import_module('modelscope') - - -# ------------------------------------------------------------------------------------------------------------------------ -# 🔌💻 GPT-Academic Interface -# ------------------------------------------------------------------------------------------------------------------------ -predict_no_ui_long_connection, predict = get_local_llm_predict_fns(GetGLM3Handle, model_name, history_format='chatglm3') \ No newline at end of file diff --git a/request_llms/bridge_chatgpt_vision.py b/request_llms/bridge_chatgpt_vision.py deleted file mode 100644 index ebcf9689a3d74fed75531619bd02dd27993dad5e..0000000000000000000000000000000000000000 --- a/request_llms/bridge_chatgpt_vision.py +++ /dev/null @@ -1,312 +0,0 @@ -""" - 该文件中主要包含三个函数 - - 不具备多线程能力的函数: - 1. predict: 正常对话时使用,具备完备的交互功能,不可多线程 - - 具备多线程调用能力的函数 - 2. predict_no_ui_long_connection:支持多线程 -""" - -import json -import time -import logging -import requests -import base64 -import os -import glob -from toolbox import get_conf, update_ui, is_any_api_key, select_api_key, what_keys, clip_history, trimmed_format_exc, is_the_upload_folder, \ - update_ui_lastest_msg, get_max_token, encode_image, have_any_recent_upload_image_files - - -proxies, TIMEOUT_SECONDS, MAX_RETRY, API_ORG, AZURE_CFG_ARRAY = \ - get_conf('proxies', 'TIMEOUT_SECONDS', 'MAX_RETRY', 'API_ORG', 'AZURE_CFG_ARRAY') - -timeout_bot_msg = '[Local Message] Request timeout. Network error. Please check proxy settings in config.py.' + \ - '网络错误,检查代理服务器是否可用,以及代理设置的格式是否正确,格式须是[协议]://[地址]:[端口],缺一不可。' - - -def report_invalid_key(key): - if get_conf("BLOCK_INVALID_APIKEY"): - # 实验性功能,自动检测并屏蔽失效的KEY,请勿使用 - from request_llms.key_manager import ApiKeyManager - api_key = ApiKeyManager().add_key_to_blacklist(key) - -def get_full_error(chunk, stream_response): - """ - 获取完整的从Openai返回的报错 - """ - while True: - try: - chunk += next(stream_response) - except: - break - return chunk - -def decode_chunk(chunk): - # 提前读取一些信息 (用于判断异常) - chunk_decoded = chunk.decode() - chunkjson = None - has_choices = False - choice_valid = False - has_content = False - has_role = False - try: - chunkjson = json.loads(chunk_decoded[6:]) - has_choices = 'choices' in chunkjson - if has_choices: choice_valid = (len(chunkjson['choices']) > 0) - if has_choices and choice_valid: has_content = "content" in chunkjson['choices'][0]["delta"] - if has_choices and choice_valid: has_role = "role" in chunkjson['choices'][0]["delta"] - except: - pass - return chunk_decoded, chunkjson, has_choices, choice_valid, has_content, has_role - -from functools import lru_cache -@lru_cache(maxsize=32) -def verify_endpoint(endpoint): - """ - 检查endpoint是否可用 - """ - return endpoint - -def predict_no_ui_long_connection(inputs, llm_kwargs, history=[], sys_prompt="", observe_window=None, console_slience=False): - raise NotImplementedError - - -def predict(inputs, llm_kwargs, plugin_kwargs, chatbot, history=[], system_prompt='', stream = True, additional_fn=None): - - have_recent_file, image_paths = have_any_recent_upload_image_files(chatbot) - - if is_any_api_key(inputs): - chatbot._cookies['api_key'] = inputs - chatbot.append(("输入已识别为openai的api_key", what_keys(inputs))) - yield from update_ui(chatbot=chatbot, history=history, msg="api_key已导入") # 刷新界面 - return - elif not is_any_api_key(chatbot._cookies['api_key']): - chatbot.append((inputs, "缺少api_key。\n\n1. 临时解决方案:直接在输入区键入api_key,然后回车提交。\n\n2. 长效解决方案:在config.py中配置。")) - yield from update_ui(chatbot=chatbot, history=history, msg="缺少api_key") # 刷新界面 - return - if not have_recent_file: - chatbot.append((inputs, "没有检测到任何近期上传的图像文件,请上传jpg格式的图片,此外,请注意拓展名需要小写")) - yield from update_ui(chatbot=chatbot, history=history, msg="等待图片") # 刷新界面 - return - if os.path.exists(inputs): - chatbot.append((inputs, "已经接收到您上传的文件,您不需要再重复强调该文件的路径了,请直接输入您的问题。")) - yield from update_ui(chatbot=chatbot, history=history, msg="等待指令") # 刷新界面 - return - - - user_input = inputs - if additional_fn is not None: - from core_functional import handle_core_functionality - inputs, history = handle_core_functionality(additional_fn, inputs, history, chatbot) - - raw_input = inputs - logging.info(f'[raw_input] {raw_input}') - def make_media_input(inputs, image_paths): - for image_path in image_paths: - inputs = inputs + f'

' - return inputs - chatbot.append((make_media_input(inputs, image_paths), "")) - yield from update_ui(chatbot=chatbot, history=history, msg="等待响应") # 刷新界面 - - # check mis-behavior - if is_the_upload_folder(user_input): - chatbot[-1] = (inputs, f"[Local Message] 检测到操作错误!当您上传文档之后,需点击“**函数插件区**”按钮进行处理,请勿点击“提交”按钮或者“基础功能区”按钮。") - yield from update_ui(chatbot=chatbot, history=history, msg="正常") # 刷新界面 - time.sleep(2) - - try: - headers, payload, api_key = generate_payload(inputs, llm_kwargs, history, system_prompt, image_paths) - except RuntimeError as e: - chatbot[-1] = (inputs, f"您提供的api-key不满足要求,不包含任何可用于{llm_kwargs['llm_model']}的api-key。您可能选择了错误的模型或请求源。") - yield from update_ui(chatbot=chatbot, history=history, msg="api-key不满足要求") # 刷新界面 - return - - # 检查endpoint是否合法 - try: - from .bridge_all import model_info - endpoint = verify_endpoint(model_info[llm_kwargs['llm_model']]['endpoint']) - except: - tb_str = '```\n' + trimmed_format_exc() + '```' - chatbot[-1] = (inputs, tb_str) - yield from update_ui(chatbot=chatbot, history=history, msg="Endpoint不满足要求") # 刷新界面 - return - - history.append(make_media_input(inputs, image_paths)) - history.append("") - - retry = 0 - while True: - try: - # make a POST request to the API endpoint, stream=True - response = requests.post(endpoint, headers=headers, proxies=proxies, - json=payload, stream=True, timeout=TIMEOUT_SECONDS);break - except: - 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 = "" - - is_head_of_the_stream = True - if stream: - stream_response = response.iter_lines() - while True: - try: - chunk = next(stream_response) - except StopIteration: - # 非OpenAI官方接口的出现这样的报错,OpenAI和API2D不会走这里 - chunk_decoded = chunk.decode() - error_msg = chunk_decoded - # 首先排除一个one-api没有done数据包的第三方Bug情形 - if len(gpt_replying_buffer.strip()) > 0 and len(error_msg) == 0: - yield from update_ui(chatbot=chatbot, history=history, msg="检测到有缺陷的非OpenAI官方接口,建议选择更稳定的接口。") - break - # 其他情况,直接返回报错 - chatbot, history = handle_error(inputs, llm_kwargs, chatbot, history, chunk_decoded, error_msg, api_key) - yield from update_ui(chatbot=chatbot, history=history, msg="非OpenAI官方接口返回了错误:" + chunk.decode()) # 刷新界面 - return - - # 提前读取一些信息 (用于判断异常) - chunk_decoded, chunkjson, has_choices, choice_valid, has_content, has_role = decode_chunk(chunk) - - if is_head_of_the_stream and (r'"object":"error"' not in chunk_decoded) and (r"content" not in chunk_decoded): - # 数据流的第一帧不携带content - is_head_of_the_stream = False; continue - - if chunk: - try: - if has_choices and not choice_valid: - # 一些垃圾第三方接口的出现这样的错误 - continue - # 前者是API2D的结束条件,后者是OPENAI的结束条件 - if ('data: [DONE]' in chunk_decoded) or (len(chunkjson['choices'][0]["delta"]) == 0): - # 判定为数据流的结束,gpt_replying_buffer也写完了 - lastmsg = chatbot[-1][-1] + f"\n\n\n\n「{llm_kwargs['llm_model']}调用结束,该模型不具备上下文对话能力,如需追问,请及时切换模型。」" - yield from update_ui_lastest_msg(lastmsg, chatbot, history, delay=1) - logging.info(f'[response] {gpt_replying_buffer}') - break - # 处理数据流的主体 - status_text = f"finish_reason: {chunkjson['choices'][0].get('finish_reason', 'null')}" - # 如果这里抛出异常,一般是文本过长,详情见get_full_error的输出 - if has_content: - # 正常情况 - gpt_replying_buffer = gpt_replying_buffer + chunkjson['choices'][0]["delta"]["content"] - elif has_role: - # 一些第三方接口的出现这样的错误,兼容一下吧 - continue - else: - # 一些垃圾第三方接口的出现这样的错误 - gpt_replying_buffer = gpt_replying_buffer + chunkjson['choices'][0]["delta"]["content"] - - history[-1] = gpt_replying_buffer - chatbot[-1] = (history[-2], history[-1]) - yield from update_ui(chatbot=chatbot, history=history, msg=status_text) # 刷新界面 - except Exception as e: - yield from update_ui(chatbot=chatbot, history=history, msg="Json解析不合常规") # 刷新界面 - chunk = get_full_error(chunk, stream_response) - chunk_decoded = chunk.decode() - error_msg = chunk_decoded - chatbot, history = handle_error(inputs, llm_kwargs, chatbot, history, chunk_decoded, error_msg, api_key) - yield from update_ui(chatbot=chatbot, history=history, msg="Json异常" + error_msg) # 刷新界面 - print(error_msg) - return - -def handle_error(inputs, llm_kwargs, chatbot, history, chunk_decoded, error_msg, api_key=""): - from .bridge_all import model_info - openai_website = ' 请登录OpenAI查看详情 https://platform.openai.com/signup' - if "reduce the length" in error_msg: - if len(history) >= 2: history[-1] = ""; history[-2] = "" # 清除当前溢出的输入:history[-2] 是本次输入, history[-1] 是本次输出 - history = clip_history(inputs=inputs, history=history, tokenizer=model_info[llm_kwargs['llm_model']]['tokenizer'], - max_token_limit=(model_info[llm_kwargs['llm_model']]['max_token'])) # history至少释放二分之一 - chatbot[-1] = (chatbot[-1][0], "[Local Message] Reduce the length. 本次输入过长, 或历史数据过长. 历史缓存数据已部分释放, 您可以请再次尝试. (若再次失败则更可能是因为输入过长.)") - elif "does not exist" in error_msg: - chatbot[-1] = (chatbot[-1][0], f"[Local Message] Model {llm_kwargs['llm_model']} does not exist. 模型不存在, 或者您没有获得体验资格.") - elif "Incorrect API key" in error_msg: - chatbot[-1] = (chatbot[-1][0], "[Local Message] Incorrect API key. OpenAI以提供了不正确的API_KEY为由, 拒绝服务. " + openai_website); report_invalid_key(api_key) - elif "exceeded your current quota" in error_msg: - chatbot[-1] = (chatbot[-1][0], "[Local Message] You exceeded your current quota. OpenAI以账户额度不足为由, 拒绝服务." + openai_website); report_invalid_key(api_key) - elif "account is not active" in error_msg: - chatbot[-1] = (chatbot[-1][0], "[Local Message] Your account is not active. OpenAI以账户失效为由, 拒绝服务." + openai_website); report_invalid_key(api_key) - elif "associated with a deactivated account" in error_msg: - chatbot[-1] = (chatbot[-1][0], "[Local Message] You are associated with a deactivated account. OpenAI以账户失效为由, 拒绝服务." + openai_website); report_invalid_key(api_key) - elif "API key has been deactivated" in error_msg: - chatbot[-1] = (chatbot[-1][0], "[Local Message] API key has been deactivated. OpenAI以账户失效为由, 拒绝服务." + openai_website); report_invalid_key(api_key) - elif "bad forward key" in error_msg: - chatbot[-1] = (chatbot[-1][0], "[Local Message] Bad forward key. API2D账户额度不足.") - elif "Not enough point" in error_msg: - chatbot[-1] = (chatbot[-1][0], "[Local Message] Not enough point. API2D账户点数不足.") - else: - from toolbox import regular_txt_to_markdown - tb_str = '```\n' + trimmed_format_exc() + '```' - chatbot[-1] = (chatbot[-1][0], f"[Local Message] 异常 \n\n{tb_str} \n\n{regular_txt_to_markdown(chunk_decoded)}") - return chatbot, history - - -def generate_payload(inputs, llm_kwargs, history, system_prompt, image_paths): - """ - 整合所有信息,选择LLM模型,生成http请求,为发送请求做准备 - """ - if not is_any_api_key(llm_kwargs['api_key']): - raise AssertionError("你提供了错误的API_KEY。\n\n1. 临时解决方案:直接在输入区键入api_key,然后回车提交。\n\n2. 长效解决方案:在config.py中配置。") - - api_key = select_api_key(llm_kwargs['api_key'], llm_kwargs['llm_model']) - - headers = { - "Content-Type": "application/json", - "Authorization": f"Bearer {api_key}" - } - if API_ORG.startswith('org-'): headers.update({"OpenAI-Organization": API_ORG}) - if llm_kwargs['llm_model'].startswith('azure-'): - headers.update({"api-key": api_key}) - if llm_kwargs['llm_model'] in AZURE_CFG_ARRAY.keys(): - azure_api_key_unshared = AZURE_CFG_ARRAY[llm_kwargs['llm_model']]["AZURE_API_KEY"] - headers.update({"api-key": azure_api_key_unshared}) - - base64_images = [] - for image_path in image_paths: - base64_images.append(encode_image(image_path)) - - messages = [] - what_i_ask_now = {} - what_i_ask_now["role"] = "user" - what_i_ask_now["content"] = [] - what_i_ask_now["content"].append({ - "type": "text", - "text": inputs - }) - - for image_path, base64_image in zip(image_paths, base64_images): - what_i_ask_now["content"].append({ - "type": "image_url", - "image_url": { - "url": f"data:image/jpeg;base64,{base64_image}" - } - }) - - messages.append(what_i_ask_now) - model = llm_kwargs['llm_model'] - if llm_kwargs['llm_model'].startswith('api2d-'): - model = llm_kwargs['llm_model'][len('api2d-'):] - - payload = { - "model": model, - "messages": messages, - "temperature": llm_kwargs['temperature'], # 1.0, - "top_p": llm_kwargs['top_p'], # 1.0, - "n": 1, - "stream": True, - "max_tokens": get_max_token(llm_kwargs), - "presence_penalty": 0, - "frequency_penalty": 0, - } - try: - print(f" {llm_kwargs['llm_model']} : {inputs[:100]} ..........") - except: - print('输入中可能存在乱码。') - return headers, payload, api_key - - diff --git a/request_llms/bridge_deepseekcoder.py b/request_llms/bridge_deepseekcoder.py deleted file mode 100644 index 89964abeea71de3790abfa222177972ea7fc1d75..0000000000000000000000000000000000000000 --- a/request_llms/bridge_deepseekcoder.py +++ /dev/null @@ -1,129 +0,0 @@ -model_name = "deepseek-coder-6.7b-instruct" -cmd_to_install = "未知" # "`pip install -r request_llms/requirements_qwen.txt`" - -import os -from toolbox import ProxyNetworkActivate -from toolbox import get_conf -from .local_llm_class import LocalLLMHandle, get_local_llm_predict_fns -from threading import Thread -import torch - -def download_huggingface_model(model_name, max_retry, local_dir): - from huggingface_hub import snapshot_download - for i in range(1, max_retry): - try: - snapshot_download(repo_id=model_name, local_dir=local_dir, resume_download=True) - break - except Exception as e: - print(f'\n\n下载失败,重试第{i}次中...\n\n') - return local_dir -# ------------------------------------------------------------------------------------------------------------------------ -# 🔌💻 Local Model -# ------------------------------------------------------------------------------------------------------------------------ -class GetCoderLMHandle(LocalLLMHandle): - - def load_model_info(self): - # 🏃‍♂️🏃‍♂️🏃‍♂️ 子进程执行 - self.model_name = model_name - self.cmd_to_install = cmd_to_install - - def load_model_and_tokenizer(self): - # 🏃‍♂️🏃‍♂️🏃‍♂️ 子进程执行 - with ProxyNetworkActivate('Download_LLM'): - from transformers import AutoTokenizer, AutoModelForCausalLM, TextIteratorStreamer - model_name = "deepseek-ai/deepseek-coder-6.7b-instruct" - # local_dir = f"~/.cache/{model_name}" - # if not os.path.exists(local_dir): - # tokenizer = download_huggingface_model(model_name, max_retry=128, local_dir=local_dir) - tokenizer = AutoTokenizer.from_pretrained(model_name, trust_remote_code=True) - self._streamer = TextIteratorStreamer(tokenizer) - device_map = { - "transformer.word_embeddings": 0, - "transformer.word_embeddings_layernorm": 0, - "lm_head": 0, - "transformer.h": 0, - "transformer.ln_f": 0, - "model.embed_tokens": 0, - "model.layers": 0, - "model.norm": 0, - } - - # 检查量化配置 - quantization_type = get_conf('LOCAL_MODEL_QUANT') - - if get_conf('LOCAL_MODEL_DEVICE') != 'cpu': - if quantization_type == "INT8": - from transformers import BitsAndBytesConfig - # 使用 INT8 量化 - model = AutoModelForCausalLM.from_pretrained(model_name, trust_remote_code=True, load_in_8bit=True, - device_map=device_map) - elif quantization_type == "INT4": - from transformers import BitsAndBytesConfig - # 使用 INT4 量化 - bnb_config = BitsAndBytesConfig( - load_in_4bit=True, - bnb_4bit_use_double_quant=True, - bnb_4bit_quant_type="nf4", - bnb_4bit_compute_dtype=torch.bfloat16 - ) - model = AutoModelForCausalLM.from_pretrained(model_name, trust_remote_code=True, - quantization_config=bnb_config, device_map=device_map) - else: - # 使用默认的 FP16 - model = AutoModelForCausalLM.from_pretrained(model_name, trust_remote_code=True, - torch_dtype=torch.bfloat16, device_map=device_map) - else: - # CPU 模式 - model = AutoModelForCausalLM.from_pretrained(model_name, trust_remote_code=True, - torch_dtype=torch.bfloat16) - - return model, tokenizer - - def llm_stream_generator(self, **kwargs): - # 🏃‍♂️🏃‍♂️🏃‍♂️ 子进程执行 - def adaptor(kwargs): - query = kwargs['query'] - max_length = kwargs['max_length'] - top_p = kwargs['top_p'] - temperature = kwargs['temperature'] - history = kwargs['history'] - return query, max_length, top_p, temperature, history - - query, max_length, top_p, temperature, history = adaptor(kwargs) - history.append({ 'role': 'user', 'content': query}) - messages = history - inputs = self._tokenizer.apply_chat_template(messages, return_tensors="pt") - if inputs.shape[1] > max_length: - inputs = inputs[:, -max_length:] - inputs = inputs.to(self._model.device) - generation_kwargs = dict( - inputs=inputs, - max_new_tokens=max_length, - do_sample=False, - top_p=top_p, - streamer = self._streamer, - top_k=50, - temperature=temperature, - num_return_sequences=1, - eos_token_id=32021, - ) - thread = Thread(target=self._model.generate, kwargs=generation_kwargs, daemon=True) - thread.start() - generated_text = "" - for new_text in self._streamer: - generated_text += new_text - # print(generated_text) - yield generated_text - - - def try_to_import_special_deps(self, **kwargs): pass - # import something that will raise error if the user does not install requirement_*.txt - # 🏃‍♂️🏃‍♂️🏃‍♂️ 主进程执行 - # import importlib - # importlib.import_module('modelscope') - - -# ------------------------------------------------------------------------------------------------------------------------ -# 🔌💻 GPT-Academic Interface -# ------------------------------------------------------------------------------------------------------------------------ -predict_no_ui_long_connection, predict = get_local_llm_predict_fns(GetCoderLMHandle, model_name, history_format='chatglm3') \ No newline at end of file diff --git a/request_llms/bridge_google_gemini.py b/request_llms/bridge_google_gemini.py deleted file mode 100644 index cb85ecb6d342481d2036695dfab8b2a63cd8c70a..0000000000000000000000000000000000000000 --- a/request_llms/bridge_google_gemini.py +++ /dev/null @@ -1,118 +0,0 @@ -# encoding: utf-8 -# @Time : 2023/12/21 -# @Author : Spike -# @Descr : -import json -import re -import os -import time -from request_llms.com_google import GoogleChatInit -from toolbox import get_conf, update_ui, update_ui_lastest_msg, have_any_recent_upload_image_files, trimmed_format_exc - -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 - - # 适配润色区域 - if additional_fn is not None: - from core_functional import handle_core_functionality - inputs, history = handle_core_functionality(additional_fn, inputs, history, chatbot) - - if "vision" in llm_kwargs["llm_model"]: - have_recent_file, image_paths = have_any_recent_upload_image_files(chatbot) - if not have_recent_file: - chatbot.append((inputs, "没有检测到任何近期上传的图像文件,请上传jpg格式的图片,此外,请注意拓展名需要小写")) - yield from update_ui(chatbot=chatbot, history=history, msg="等待图片") # 刷新界面 - return - def make_media_input(inputs, image_paths): - for image_path in image_paths: - inputs = inputs + f'

' - return inputs - if have_recent_file: - inputs = make_media_input(inputs, image_paths) - - 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], trimmed_format_exc())) - yield from update_ui(chatbot=chatbot, history=history, msg="请求失败") # 刷新界面 - return - 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/bridge_newbingfree.py b/request_llms/bridge_newbingfree.py deleted file mode 100644 index 13573ede0977880c04547c37ca334a29d5e272fa..0000000000000000000000000000000000000000 --- a/request_llms/bridge_newbingfree.py +++ /dev/null @@ -1,311 +0,0 @@ -""" -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -第一部分:来自EdgeGPT.py -https://github.com/acheong08/EdgeGPT -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -""" -from .edge_gpt_free import Chatbot as NewbingChatbot - -load_message = "等待NewBing响应。" - -""" -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -第二部分:子进程Worker(调用主体) -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -""" -import time -import json -import re -import logging -import asyncio -import importlib -import threading -from toolbox import update_ui, get_conf, trimmed_format_exc -from multiprocessing import Process, Pipe - - -def preprocess_newbing_out(s): - pattern = r"\^(\d+)\^" # 匹配^数字^ - sub = lambda m: "(" + m.group(1) + ")" # 将匹配到的数字作为替换值 - result = re.sub(pattern, sub, s) # 替换操作 - if "[1]" in result: - result += ( - "\n\n```reference\n" - + "\n".join([r for r in result.split("\n") if r.startswith("[")]) - + "\n```\n" - ) - return result - - -def preprocess_newbing_out_simple(result): - if "[1]" in result: - result += ( - "\n\n```reference\n" - + "\n".join([r for r in result.split("\n") if r.startswith("[")]) - + "\n```\n" - ) - return result - - -class NewBingHandle(Process): - def __init__(self): - super().__init__(daemon=True) - self.parent, self.child = Pipe() - self.newbing_model = None - self.info = "" - self.success = True - self.local_history = [] - self.check_dependency() - self.start() - self.threadLock = threading.Lock() - - def check_dependency(self): - try: - self.success = False - import certifi, httpx, rich - - self.info = "依赖检测通过,等待NewBing响应。注意目前不能多人同时调用NewBing接口(有线程锁),否则将导致每个人的NewBing问询历史互相渗透。调用NewBing时,会自动使用已配置的代理。" - self.success = True - except: - self.info = "缺少的依赖,如果要使用Newbing,除了基础的pip依赖以外,您还需要运行`pip install -r request_llms/requirements_newbing.txt`安装Newbing的依赖。" - self.success = False - - def ready(self): - return self.newbing_model is not None - - async def async_run(self): - # 读取配置 - NEWBING_STYLE = get_conf("NEWBING_STYLE") - from request_llms.bridge_all import model_info - - endpoint = model_info["newbing"]["endpoint"] - while True: - # 等待 - kwargs = self.child.recv() - question = kwargs["query"] - history = kwargs["history"] - system_prompt = kwargs["system_prompt"] - - # 是否重置 - if len(self.local_history) > 0 and len(history) == 0: - await self.newbing_model.reset() - self.local_history = [] - - # 开始问问题 - prompt = "" - if system_prompt not in self.local_history: - self.local_history.append(system_prompt) - prompt += system_prompt + "\n" - - # 追加历史 - for ab in history: - a, b = ab - if a not in self.local_history: - self.local_history.append(a) - prompt += a + "\n" - - # 问题 - prompt += question - self.local_history.append(question) - print("question:", prompt) - # 提交 - async for final, response in self.newbing_model.ask_stream( - prompt=question, - conversation_style=NEWBING_STYLE, # ["creative", "balanced", "precise"] - wss_link=endpoint, # "wss://sydney.bing.com/sydney/ChatHub" - ): - if not final: - print(response) - self.child.send(str(response)) - else: - print("-------- receive final ---------") - self.child.send("[Finish]") - # self.local_history.append(response) - - def run(self): - """ - 这个函数运行在子进程 - """ - # 第一次运行,加载参数 - self.success = False - self.local_history = [] - if (self.newbing_model is None) or (not self.success): - # 代理设置 - proxies, NEWBING_COOKIES = get_conf("proxies", "NEWBING_COOKIES") - if proxies is None: - self.proxies_https = None - else: - self.proxies_https = proxies["https"] - - if (NEWBING_COOKIES is not None) and len(NEWBING_COOKIES) > 100: - try: - cookies = json.loads(NEWBING_COOKIES) - except: - self.success = False - tb_str = "\n```\n" + trimmed_format_exc() + "\n```\n" - self.child.send(f"[Local Message] NEWBING_COOKIES未填写或有格式错误。") - self.child.send("[Fail]") - self.child.send("[Finish]") - raise RuntimeError(f"NEWBING_COOKIES未填写或有格式错误。") - else: - cookies = None - - try: - self.newbing_model = NewbingChatbot( - proxy=self.proxies_https, cookies=cookies - ) - except: - self.success = False - tb_str = "\n```\n" + trimmed_format_exc() + "\n```\n" - self.child.send( - f"[Local Message] 不能加载Newbing组件,请注意Newbing组件已不再维护。{tb_str}" - ) - self.child.send("[Fail]") - self.child.send("[Finish]") - raise RuntimeError(f"不能加载Newbing组件,请注意Newbing组件已不再维护。") - - self.success = True - try: - # 进入任务等待状态 - asyncio.run(self.async_run()) - except Exception: - tb_str = "\n```\n" + trimmed_format_exc() + "\n```\n" - self.child.send( - f"[Local Message] Newbing 请求失败,报错信息如下. 如果是与网络相关的问题,建议更换代理协议(推荐http)或代理节点 {tb_str}." - ) - self.child.send("[Fail]") - self.child.send("[Finish]") - - def stream_chat(self, **kwargs): - """ - 这个函数运行在主进程 - """ - self.threadLock.acquire() # 获取线程锁 - self.parent.send(kwargs) # 请求子进程 - while True: - res = self.parent.recv() # 等待newbing回复的片段 - if res == "[Finish]": - break # 结束 - elif res == "[Fail]": - self.success = False - break # 失败 - else: - yield res # newbing回复的片段 - self.threadLock.release() # 释放线程锁 - - -""" -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -第三部分:主进程统一调用函数接口 -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -""" -global newbingfree_handle -newbingfree_handle = None - - -def predict_no_ui_long_connection( - inputs, - llm_kwargs, - history=[], - sys_prompt="", - observe_window=[], - console_slience=False, -): - """ - 多线程方法 - 函数的说明请见 request_llms/bridge_all.py - """ - global newbingfree_handle - if (newbingfree_handle is None) or (not newbingfree_handle.success): - newbingfree_handle = NewBingHandle() - if len(observe_window) >= 1: - observe_window[0] = load_message + "\n\n" + newbingfree_handle.info - if not newbingfree_handle.success: - error = newbingfree_handle.info - newbingfree_handle = None - raise RuntimeError(error) - - # 没有 sys_prompt 接口,因此把prompt加入 history - history_feedin = [] - for i in range(len(history) // 2): - history_feedin.append([history[2 * i], history[2 * i + 1]]) - - watch_dog_patience = 5 # 看门狗 (watchdog) 的耐心, 设置5秒即可 - response = "" - if len(observe_window) >= 1: - observe_window[0] = "[Local Message] 等待NewBing响应中 ..." - for response in newbingfree_handle.stream_chat( - query=inputs, - history=history_feedin, - system_prompt=sys_prompt, - max_length=llm_kwargs["max_length"], - top_p=llm_kwargs["top_p"], - temperature=llm_kwargs["temperature"], - ): - if len(observe_window) >= 1: - observe_window[0] = preprocess_newbing_out_simple(response) - if len(observe_window) >= 2: - if (time.time() - observe_window[1]) > watch_dog_patience: - raise RuntimeError("程序终止。") - return preprocess_newbing_out_simple(response) - - -def predict( - inputs, - llm_kwargs, - plugin_kwargs, - chatbot, - history=[], - system_prompt="", - stream=True, - additional_fn=None, -): - """ - 单线程方法 - 函数的说明请见 request_llms/bridge_all.py - """ - chatbot.append((inputs, "[Local Message] 等待NewBing响应中 ...")) - - global newbingfree_handle - if (newbingfree_handle is None) or (not newbingfree_handle.success): - newbingfree_handle = NewBingHandle() - chatbot[-1] = (inputs, load_message + "\n\n" + newbingfree_handle.info) - yield from update_ui(chatbot=chatbot, history=[]) - if not newbingfree_handle.success: - newbingfree_handle = None - return - - if additional_fn is not None: - from core_functional import handle_core_functionality - - inputs, history = handle_core_functionality( - additional_fn, inputs, history, chatbot - ) - - history_feedin = [] - for i in range(len(history) // 2): - history_feedin.append([history[2 * i], history[2 * i + 1]]) - - chatbot[-1] = (inputs, "[Local Message] 等待NewBing响应中 ...") - response = "[Local Message] 等待NewBing响应中 ..." - yield from update_ui( - chatbot=chatbot, history=history, msg="NewBing响应缓慢,尚未完成全部响应,请耐心完成后再提交新问题。" - ) - for response in newbingfree_handle.stream_chat( - query=inputs, - history=history_feedin, - system_prompt=system_prompt, - max_length=llm_kwargs["max_length"], - top_p=llm_kwargs["top_p"], - temperature=llm_kwargs["temperature"], - ): - chatbot[-1] = (inputs, preprocess_newbing_out(response)) - yield from update_ui( - chatbot=chatbot, history=history, msg="NewBing响应缓慢,尚未完成全部响应,请耐心完成后再提交新问题。" - ) - if response == "[Local Message] 等待NewBing响应中 ...": - response = "[Local Message] NewBing响应异常,请刷新界面重试 ..." - history.extend([inputs, response]) - logging.info(f"[raw_input] {inputs}") - logging.info(f"[response] {response}") - yield from update_ui(chatbot=chatbot, history=history, msg="完成全部响应,请提交新问题。") diff --git a/request_llms/bridge_qwen.py b/request_llms/bridge_qwen.py deleted file mode 100644 index 808c2c75c42b03c108374324ea9b775ab19c378b..0000000000000000000000000000000000000000 --- a/request_llms/bridge_qwen.py +++ /dev/null @@ -1,63 +0,0 @@ -import time -import os -from toolbox import update_ui, get_conf, update_ui_lastest_msg -from toolbox import check_packages, report_exception - -model_name = 'Qwen' - -def predict_no_ui_long_connection(inputs, llm_kwargs, history=[], sys_prompt="", observe_window=[], console_slience=False): - """ - ⭐多线程方法 - 函数的说明请见 request_llms/bridge_all.py - """ - watch_dog_patience = 5 - response = "" - - from .com_qwenapi import QwenRequestInstance - sri = QwenRequestInstance() - for response in sri.generate(inputs, llm_kwargs, history, sys_prompt): - if len(observe_window) >= 1: - observe_window[0] = response - if len(observe_window) >= 2: - if (time.time()-observe_window[1]) > watch_dog_patience: raise RuntimeError("程序终止。") - return response - -def predict(inputs, llm_kwargs, plugin_kwargs, chatbot, history=[], system_prompt='', stream = True, additional_fn=None): - """ - ⭐单线程方法 - 函数的说明请见 request_llms/bridge_all.py - """ - chatbot.append((inputs, "")) - yield from update_ui(chatbot=chatbot, history=history) - - # 尝试导入依赖,如果缺少依赖,则给出安装建议 - try: - check_packages(["dashscope"]) - except: - yield from update_ui_lastest_msg(f"导入软件依赖失败。使用该模型需要额外依赖,安装方法```pip install --upgrade dashscope```。", - chatbot=chatbot, history=history, delay=0) - return - - # 检查DASHSCOPE_API_KEY - if get_conf("DASHSCOPE_API_KEY") == "": - yield from update_ui_lastest_msg(f"请配置 DASHSCOPE_API_KEY。", - chatbot=chatbot, history=history, delay=0) - return - - if additional_fn is not None: - from core_functional import handle_core_functionality - inputs, history = handle_core_functionality(additional_fn, inputs, history, chatbot) - - # 开始接收回复 - from .com_qwenapi import QwenRequestInstance - sri = QwenRequestInstance() - response = f"[Local Message] 等待{model_name}响应中 ..." - for response in sri.generate(inputs, llm_kwargs, history, system_prompt): - chatbot[-1] = (inputs, response) - yield from update_ui(chatbot=chatbot, history=history) - - # 总结输出 - if response == f"[Local Message] 等待{model_name}响应中 ...": - response = f"[Local Message] {model_name}响应异常 ..." - history.extend([inputs, response]) - yield from update_ui(chatbot=chatbot, history=history) \ No newline at end of file diff --git a/request_llms/bridge_skylark2.py b/request_llms/bridge_skylark2.py deleted file mode 100644 index 1a8edcbca842ce642a3abe68813593754e307487..0000000000000000000000000000000000000000 --- a/request_llms/bridge_skylark2.py +++ /dev/null @@ -1,68 +0,0 @@ -import time -from toolbox import update_ui, get_conf, update_ui_lastest_msg -from toolbox import check_packages, report_exception - -model_name = '云雀大模型' - -def validate_key(): - YUNQUE_SECRET_KEY = get_conf("YUNQUE_SECRET_KEY") - if YUNQUE_SECRET_KEY == '': return False - return True - -def predict_no_ui_long_connection(inputs, llm_kwargs, history=[], sys_prompt="", observe_window=[], console_slience=False): - """ - ⭐ 多线程方法 - 函数的说明请见 request_llms/bridge_all.py - """ - watch_dog_patience = 5 - response = "" - - if validate_key() is False: - raise RuntimeError('请配置YUNQUE_SECRET_KEY') - - from .com_skylark2api import YUNQUERequestInstance - sri = YUNQUERequestInstance() - for response in sri.generate(inputs, llm_kwargs, history, sys_prompt): - if len(observe_window) >= 1: - observe_window[0] = response - if len(observe_window) >= 2: - if (time.time()-observe_window[1]) > watch_dog_patience: raise RuntimeError("程序终止。") - return response - -def predict(inputs, llm_kwargs, plugin_kwargs, chatbot, history=[], system_prompt='', stream = True, additional_fn=None): - """ - ⭐ 单线程方法 - 函数的说明请见 request_llms/bridge_all.py - """ - chatbot.append((inputs, "")) - yield from update_ui(chatbot=chatbot, history=history) - - # 尝试导入依赖,如果缺少依赖,则给出安装建议 - try: - check_packages(["zhipuai"]) - except: - yield from update_ui_lastest_msg(f"导入软件依赖失败。使用该模型需要额外依赖,安装方法```pip install --upgrade zhipuai```。", - chatbot=chatbot, history=history, delay=0) - return - - if validate_key() is False: - yield from update_ui_lastest_msg(lastmsg="[Local Message] 请配置HUOSHAN_API_KEY", chatbot=chatbot, history=history, delay=0) - return - - if additional_fn is not None: - from core_functional import handle_core_functionality - inputs, history = handle_core_functionality(additional_fn, inputs, history, chatbot) - - # 开始接收回复 - from .com_skylark2api import YUNQUERequestInstance - sri = YUNQUERequestInstance() - response = f"[Local Message] 等待{model_name}响应中 ..." - for response in sri.generate(inputs, llm_kwargs, history, system_prompt): - chatbot[-1] = (inputs, response) - yield from update_ui(chatbot=chatbot, history=history) - - # 总结输出 - if response == f"[Local Message] 等待{model_name}响应中 ...": - response = f"[Local Message] {model_name}响应异常 ..." - history.extend([inputs, response]) - yield from update_ui(chatbot=chatbot, history=history) \ No newline at end of file diff --git a/request_llms/bridge_zhipu.py b/request_llms/bridge_zhipu.py deleted file mode 100644 index ecb3b7550e499c73a784acd3f966fb7f635bb1ed..0000000000000000000000000000000000000000 --- a/request_llms/bridge_zhipu.py +++ /dev/null @@ -1,93 +0,0 @@ -import time -import os -from toolbox import update_ui, get_conf, update_ui_lastest_msg -from toolbox import check_packages, report_exception, have_any_recent_upload_image_files - -model_name = '智谱AI大模型' -zhipuai_default_model = 'glm-4' - -def validate_key(): - ZHIPUAI_API_KEY = get_conf("ZHIPUAI_API_KEY") - if ZHIPUAI_API_KEY == '': return False - return True - -def make_media_input(inputs, image_paths): - for image_path in image_paths: - inputs = inputs + f'

' - return inputs - -def predict_no_ui_long_connection(inputs, llm_kwargs, history=[], sys_prompt="", observe_window=[], console_slience=False): - """ - ⭐多线程方法 - 函数的说明请见 request_llms/bridge_all.py - """ - watch_dog_patience = 5 - response = "" - - if llm_kwargs["llm_model"] == "zhipuai": - llm_kwargs["llm_model"] = zhipuai_default_model - - if validate_key() is False: - raise RuntimeError('请配置ZHIPUAI_API_KEY') - - # 开始接收回复 - from .com_zhipuglm import ZhipuChatInit - zhipu_bro_init = ZhipuChatInit() - for chunk, response in zhipu_bro_init.generate_chat(inputs, llm_kwargs, history, sys_prompt): - if len(observe_window) >= 1: - observe_window[0] = response - if len(observe_window) >= 2: - if (time.time() - observe_window[1]) > watch_dog_patience: - raise RuntimeError("程序终止。") - return response - - -def predict(inputs, llm_kwargs, plugin_kwargs, chatbot, history=[], system_prompt='', stream=True, additional_fn=None): - """ - ⭐单线程方法 - 函数的说明请见 request_llms/bridge_all.py - """ - chatbot.append([inputs, ""]) - yield from update_ui(chatbot=chatbot, history=history) - - # 尝试导入依赖,如果缺少依赖,则给出安装建议 - try: - check_packages(["zhipuai"]) - except: - yield from update_ui_lastest_msg(f"导入软件依赖失败。使用该模型需要额外依赖,安装方法```pip install --upgrade zhipuai```。", - chatbot=chatbot, history=history, delay=0) - return - - if validate_key() is False: - yield from update_ui_lastest_msg(lastmsg="[Local Message] 请配置ZHIPUAI_API_KEY", chatbot=chatbot, history=history, delay=0) - return - - if additional_fn is not None: - from core_functional import handle_core_functionality - inputs, history = handle_core_functionality(additional_fn, inputs, history, chatbot) - chatbot[-1] = [inputs, ""] - yield from update_ui(chatbot=chatbot, history=history) - - if llm_kwargs["llm_model"] == "zhipuai": - llm_kwargs["llm_model"] = zhipuai_default_model - - if llm_kwargs["llm_model"] in ["glm-4v"]: - have_recent_file, image_paths = have_any_recent_upload_image_files(chatbot) - if not have_recent_file: - chatbot.append((inputs, "没有检测到任何近期上传的图像文件,请上传jpg格式的图片,此外,请注意拓展名需要小写")) - yield from update_ui(chatbot=chatbot, history=history, msg="等待图片") # 刷新界面 - return - if have_recent_file: - inputs = make_media_input(inputs, image_paths) - chatbot[-1] = [inputs, ""] - yield from update_ui(chatbot=chatbot, history=history) - - - # 开始接收回复 - from .com_zhipuglm import ZhipuChatInit - zhipu_bro_init = ZhipuChatInit() - for chunk, response in zhipu_bro_init.generate_chat(inputs, llm_kwargs, history, system_prompt): - chatbot[-1] = [inputs, response] - yield from update_ui(chatbot=chatbot, history=history) - history.extend([inputs, response]) - yield from update_ui(chatbot=chatbot, history=history) \ No newline at end of file diff --git a/request_llms/com_google.py b/request_llms/com_google.py deleted file mode 100644 index e66d659af5a0fb99ff803162f4fd0b6e5505ee29..0000000000000000000000000000000000000000 --- a/request_llms/com_google.py +++ /dev/null @@ -1,201 +0,0 @@ -# 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, get_pictures_list, to_markdown_tabs - -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, llm_kwargs): - if llm_kwargs["most_recent_uploaded"].get("path"): - image_paths = get_pictures_list(llm_kwargs["most_recent_uploaded"]["path"]) - md_encode = [] - for md_path in image_paths: - type_ = os.path.splitext(md_path)[1].replace(".", "") - type_ = "jpeg" if type_ == "jpg" else type_ - md_encode.append({"data": encode_image(md_path), "type": type_}) - 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'
' - if md: - a = f"![{__file}]({__file})" - return a - - - -class GoogleChatInit: - def __init__(self): - self.url_gemini = "https://generativelanguage.googleapis.com/v1beta/models/%m:streamGenerateContent?key=%k" - - def generate_chat(self, inputs, llm_kwargs, history, system_prompt): - headers, payload = self.generate_message_payload( - inputs, llm_kwargs, history, system_prompt - ) - response = requests.post( - url=self.url_gemini, - headers=headers, - data=json.dumps(payload), - stream=True, - proxies=proxies, - timeout=TIMEOUT_SECONDS, - ) - return response.iter_lines() - - def __conversation_user(self, user_input, llm_kwargs): - what_i_have_asked = {"role": "user", "parts": []} - if "vision" not in self.url_gemini: - input_ = user_input - encode_img = [] - else: - input_, encode_img = input_encode_handler(user_input, llm_kwargs=llm_kwargs) - what_i_have_asked["parts"].append({"text": input_}) - if encode_img: - for data in encode_img: - what_i_have_asked["parts"].append( - { - "inline_data": { - "mime_type": f"image/{data['type']}", - "data": data["data"], - } - } - ) - return what_i_have_asked - - def __conversation_history(self, history, llm_kwargs): - messages = [] - conversation_cnt = len(history) // 2 - if conversation_cnt: - for index in range(0, 2 * conversation_cnt, 2): - what_i_have_asked = self.__conversation_user(history[index], llm_kwargs) - what_gpt_answer = { - "role": "model", - "parts": [{"text": history[index + 1]}], - } - messages.append(what_i_have_asked) - messages.append(what_gpt_answer) - return messages - - def generate_message_payload( - self, inputs, llm_kwargs, history, system_prompt - ) -> Tuple[Dict, Dict]: - messages = [ - # {"role": "system", "parts": [{"text": system_prompt}]}, # gemini 不允许对话轮次为偶数,所以这个没有用,看后续支持吧。。。 - # {"role": "user", "parts": [{"text": ""}]}, - # {"role": "model", "parts": [{"text": ""}]} - ] - self.url_gemini = self.url_gemini.replace( - "%m", llm_kwargs["llm_model"] - ).replace("%k", get_conf("GEMINI_API_KEY")) - header = {"Content-Type": "application/json"} - if "vision" not in self.url_gemini: # 不是vision 才处理history - messages.extend( - self.__conversation_history(history, llm_kwargs) - ) # 处理 history - messages.append(self.__conversation_user(inputs, llm_kwargs)) # 处理用户对话 - payload = { - "contents": messages, - "generationConfig": { - # "maxOutputTokens": 800, - "stopSequences": str(llm_kwargs.get("stop", "")).split(" "), - "temperature": llm_kwargs.get("temperature", 1), - "topP": llm_kwargs.get("top_p", 0.8), - "topK": 10, - }, - } - return header, payload - - -if __name__ == "__main__": - google = GoogleChatInit() - # print(gootle.generate_message_payload('你好呀', {}, ['123123', '3123123'], '')) - # gootle.input_encode_handle('123123[123123](./123123), ![53425](./asfafa/fff.jpg)') diff --git a/request_llms/com_qwenapi.py b/request_llms/com_qwenapi.py deleted file mode 100644 index 5807600d3e94607f3eee96b758f3fda04a848dd0..0000000000000000000000000000000000000000 --- a/request_llms/com_qwenapi.py +++ /dev/null @@ -1,94 +0,0 @@ -from http import HTTPStatus -from toolbox import get_conf -import threading -import logging - -timeout_bot_msg = '[Local Message] Request timeout. Network error.' - -class QwenRequestInstance(): - def __init__(self): - import dashscope - self.time_to_yield_event = threading.Event() - self.time_to_exit_event = threading.Event() - self.result_buf = "" - - def validate_key(): - DASHSCOPE_API_KEY = get_conf("DASHSCOPE_API_KEY") - if DASHSCOPE_API_KEY == '': return False - return True - - if not validate_key(): - raise RuntimeError('请配置 DASHSCOPE_API_KEY') - dashscope.api_key = get_conf("DASHSCOPE_API_KEY") - - - def generate(self, inputs, llm_kwargs, history, system_prompt): - # import _thread as thread - from dashscope import Generation - QWEN_MODEL = { - 'qwen-turbo': Generation.Models.qwen_turbo, - 'qwen-plus': Generation.Models.qwen_plus, - 'qwen-max': Generation.Models.qwen_max, - }[llm_kwargs['llm_model']] - top_p = llm_kwargs.get('top_p', 0.8) - if top_p == 0: top_p += 1e-5 - if top_p == 1: top_p -= 1e-5 - - self.result_buf = "" - responses = Generation.call( - model=QWEN_MODEL, - messages=generate_message_payload(inputs, llm_kwargs, history, system_prompt), - top_p=top_p, - temperature=llm_kwargs.get('temperature', 1.0), - result_format='message', - stream=True, - incremental_output=True - ) - - for response in responses: - if response.status_code == HTTPStatus.OK: - if response.output.choices[0].finish_reason == 'stop': - yield self.result_buf - break - elif response.output.choices[0].finish_reason == 'length': - self.result_buf += "[Local Message] 生成长度过长,后续输出被截断" - yield self.result_buf - break - else: - self.result_buf += response.output.choices[0].message.content - yield self.result_buf - else: - self.result_buf += f"[Local Message] 请求错误:状态码:{response.status_code},错误码:{response.code},消息:{response.message}" - yield self.result_buf - break - logging.info(f'[raw_input] {inputs}') - logging.info(f'[response] {self.result_buf}') - return self.result_buf - - -def generate_message_payload(inputs, llm_kwargs, history, system_prompt): - conversation_cnt = len(history) // 2 - if system_prompt == '': system_prompt = 'Hello!' - messages = [{"role": "user", "content": system_prompt}, {"role": "assistant", "content": "Certainly!"}] - if conversation_cnt: - for index in range(0, 2*conversation_cnt, 2): - what_i_have_asked = {} - what_i_have_asked["role"] = "user" - what_i_have_asked["content"] = history[index] - what_gpt_answer = {} - what_gpt_answer["role"] = "assistant" - what_gpt_answer["content"] = history[index+1] - if what_i_have_asked["content"] != "": - if what_gpt_answer["content"] == "": - continue - if what_gpt_answer["content"] == timeout_bot_msg: - continue - messages.append(what_i_have_asked) - messages.append(what_gpt_answer) - else: - messages[-1]['content'] = what_gpt_answer['content'] - what_i_ask_now = {} - what_i_ask_now["role"] = "user" - what_i_ask_now["content"] = inputs - messages.append(what_i_ask_now) - return messages diff --git a/request_llms/com_skylark2api.py b/request_llms/com_skylark2api.py deleted file mode 100644 index 2530eccaab9e05f10f16fabe3293103b52058f0e..0000000000000000000000000000000000000000 --- a/request_llms/com_skylark2api.py +++ /dev/null @@ -1,95 +0,0 @@ -from toolbox import get_conf -import threading -import logging -import os - -timeout_bot_msg = '[Local Message] Request timeout. Network error.' -#os.environ['VOLC_ACCESSKEY'] = '' -#os.environ['VOLC_SECRETKEY'] = '' - -class YUNQUERequestInstance(): - def __init__(self): - - self.time_to_yield_event = threading.Event() - self.time_to_exit_event = threading.Event() - - self.result_buf = "" - - def generate(self, inputs, llm_kwargs, history, system_prompt): - # import _thread as thread - from volcengine.maas import MaasService, MaasException - - maas = MaasService('maas-api.ml-platform-cn-beijing.volces.com', 'cn-beijing') - - YUNQUE_SECRET_KEY, YUNQUE_ACCESS_KEY,YUNQUE_MODEL = get_conf("YUNQUE_SECRET_KEY", "YUNQUE_ACCESS_KEY","YUNQUE_MODEL") - maas.set_ak(YUNQUE_ACCESS_KEY) #填写 VOLC_ACCESSKEY - maas.set_sk(YUNQUE_SECRET_KEY) #填写 'VOLC_SECRETKEY' - - self.result_buf = "" - - req = { - "model": { - "name": YUNQUE_MODEL, - "version": "1.0", # use default version if not specified. - }, - "parameters": { - "max_new_tokens": 4000, # 输出文本的最大tokens限制 - "min_new_tokens": 1, # 输出文本的最小tokens限制 - "temperature": llm_kwargs['temperature'], # 用于控制生成文本的随机性和创造性,Temperature值越大随机性越大,取值范围0~1 - "top_p": llm_kwargs['top_p'], # 用于控制输出tokens的多样性,TopP值越大输出的tokens类型越丰富,取值范围0~1 - "top_k": 0, # 选择预测值最大的k个token进行采样,取值范围0-1000,0表示不生效 - "max_prompt_tokens": 4000, # 最大输入 token 数,如果给出的 prompt 的 token 长度超过此限制,取最后 max_prompt_tokens 个 token 输入模型。 - }, - "messages": self.generate_message_payload(inputs, llm_kwargs, history, system_prompt) - } - - response = maas.stream_chat(req) - - for resp in response: - self.result_buf += resp.choice.message.content - yield self.result_buf - ''' - for event in response.events(): - if event.event == "add": - self.result_buf += event.data - yield self.result_buf - elif event.event == "error" or event.event == "interrupted": - raise RuntimeError("Unknown error:" + event.data) - elif event.event == "finish": - yield self.result_buf - break - else: - raise RuntimeError("Unknown error:" + str(event)) - - logging.info(f'[raw_input] {inputs}') - logging.info(f'[response] {self.result_buf}') - ''' - return self.result_buf - - def generate_message_payload(inputs, llm_kwargs, history, system_prompt): - from volcengine.maas import ChatRole - conversation_cnt = len(history) // 2 - messages = [{"role": ChatRole.USER, "content": system_prompt}, - {"role": ChatRole.ASSISTANT, "content": "Certainly!"}] - if conversation_cnt: - for index in range(0, 2 * conversation_cnt, 2): - what_i_have_asked = {} - what_i_have_asked["role"] = ChatRole.USER - what_i_have_asked["content"] = history[index] - what_gpt_answer = {} - what_gpt_answer["role"] = ChatRole.ASSISTANT - what_gpt_answer["content"] = history[index + 1] - if what_i_have_asked["content"] != "": - if what_gpt_answer["content"] == "": - continue - if what_gpt_answer["content"] == timeout_bot_msg: - continue - messages.append(what_i_have_asked) - messages.append(what_gpt_answer) - else: - messages[-1]['content'] = what_gpt_answer['content'] - what_i_ask_now = {} - what_i_ask_now["role"] = ChatRole.USER - what_i_ask_now["content"] = inputs - messages.append(what_i_ask_now) - return messages \ No newline at end of file diff --git a/request_llms/com_zhipuapi.py b/request_llms/com_zhipuapi.py deleted file mode 100644 index d8b763c9087d4b505c2a75f277ec4e1c49de3edd..0000000000000000000000000000000000000000 --- a/request_llms/com_zhipuapi.py +++ /dev/null @@ -1,70 +0,0 @@ -from toolbox import get_conf -import threading -import logging - -timeout_bot_msg = '[Local Message] Request timeout. Network error.' - -class ZhipuRequestInstance(): - def __init__(self): - - self.time_to_yield_event = threading.Event() - self.time_to_exit_event = threading.Event() - - self.result_buf = "" - - def generate(self, inputs, llm_kwargs, history, system_prompt): - # import _thread as thread - import zhipuai - ZHIPUAI_API_KEY, ZHIPUAI_MODEL = get_conf("ZHIPUAI_API_KEY", "ZHIPUAI_MODEL") - zhipuai.api_key = ZHIPUAI_API_KEY - self.result_buf = "" - response = zhipuai.model_api.sse_invoke( - model=ZHIPUAI_MODEL, - prompt=generate_message_payload(inputs, llm_kwargs, history, system_prompt), - top_p=llm_kwargs['top_p']*0.7, # 智谱的API抽风,手动*0.7给做个线性变换 - temperature=llm_kwargs['temperature']*0.95, # 智谱的API抽风,手动*0.7给做个线性变换 - ) - for event in response.events(): - if event.event == "add": - # if self.result_buf == "" and event.data.startswith(" "): - # event.data = event.data.lstrip(" ") # 每次智谱为啥都要带个空格开头呢? - self.result_buf += event.data - yield self.result_buf - elif event.event == "error" or event.event == "interrupted": - raise RuntimeError("Unknown error:" + event.data) - elif event.event == "finish": - yield self.result_buf - break - else: - raise RuntimeError("Unknown error:" + str(event)) - if self.result_buf == "": - yield "智谱没有返回任何数据, 请检查ZHIPUAI_API_KEY和ZHIPUAI_MODEL是否填写正确." - logging.info(f'[raw_input] {inputs}') - logging.info(f'[response] {self.result_buf}') - return self.result_buf - -def generate_message_payload(inputs, llm_kwargs, history, system_prompt): - conversation_cnt = len(history) // 2 - messages = [{"role": "user", "content": system_prompt}, {"role": "assistant", "content": "Certainly!"}] - if conversation_cnt: - for index in range(0, 2*conversation_cnt, 2): - what_i_have_asked = {} - what_i_have_asked["role"] = "user" - what_i_have_asked["content"] = history[index] - what_gpt_answer = {} - what_gpt_answer["role"] = "assistant" - what_gpt_answer["content"] = history[index+1] - if what_i_have_asked["content"] != "": - if what_gpt_answer["content"] == "": - continue - if what_gpt_answer["content"] == timeout_bot_msg: - continue - messages.append(what_i_have_asked) - messages.append(what_gpt_answer) - else: - messages[-1]['content'] = what_gpt_answer['content'] - what_i_ask_now = {} - what_i_ask_now["role"] = "user" - what_i_ask_now["content"] = inputs - messages.append(what_i_ask_now) - return messages diff --git a/request_llms/com_zhipuglm.py b/request_llms/com_zhipuglm.py deleted file mode 100644 index 2e96d3fd87b1759b0dd52206b5dc03b7b760aa52..0000000000000000000000000000000000000000 --- a/request_llms/com_zhipuglm.py +++ /dev/null @@ -1,84 +0,0 @@ -# encoding: utf-8 -# @Time : 2024/1/22 -# @Author : Kilig947 & binary husky -# @Descr : 兼容最新的智谱Ai -from toolbox import get_conf -from zhipuai import ZhipuAI -from toolbox import get_conf, encode_image, get_pictures_list -import logging, os - - -def input_encode_handler(inputs, llm_kwargs): - if llm_kwargs["most_recent_uploaded"].get("path"): - image_paths = get_pictures_list(llm_kwargs["most_recent_uploaded"]["path"]) - md_encode = [] - for md_path in image_paths: - type_ = os.path.splitext(md_path)[1].replace(".", "") - type_ = "jpeg" if type_ == "jpg" else type_ - md_encode.append({"data": encode_image(md_path), "type": type_}) - return inputs, md_encode - - -class ZhipuChatInit: - - def __init__(self): - ZHIPUAI_API_KEY, ZHIPUAI_MODEL = get_conf("ZHIPUAI_API_KEY", "ZHIPUAI_MODEL") - if len(ZHIPUAI_MODEL) > 0: - logging.error('ZHIPUAI_MODEL 配置项选项已经弃用,请在LLM_MODEL中配置') - self.zhipu_bro = ZhipuAI(api_key=ZHIPUAI_API_KEY) - self.model = '' - - def __conversation_user(self, user_input: str, llm_kwargs): - if self.model not in ["glm-4v"]: - return {"role": "user", "content": user_input} - else: - input_, encode_img = input_encode_handler(user_input, llm_kwargs=llm_kwargs) - what_i_have_asked = {"role": "user", "content": []} - what_i_have_asked['content'].append({"type": 'text', "text": user_input}) - if encode_img: - img_d = {"type": "image_url", - "image_url": {'url': encode_img}} - what_i_have_asked['content'].append(img_d) - return what_i_have_asked - - def __conversation_history(self, history, llm_kwargs): - messages = [] - conversation_cnt = len(history) // 2 - if conversation_cnt: - for index in range(0, 2 * conversation_cnt, 2): - what_i_have_asked = self.__conversation_user(history[index], llm_kwargs) - what_gpt_answer = { - "role": "assistant", - "content": history[index + 1] - } - messages.append(what_i_have_asked) - messages.append(what_gpt_answer) - return messages - - def __conversation_message_payload(self, inputs, llm_kwargs, history, system_prompt): - messages = [] - if system_prompt: - messages.append({"role": "system", "content": system_prompt}) - self.model = llm_kwargs['llm_model'] - messages.extend(self.__conversation_history(history, llm_kwargs)) # 处理 history - messages.append(self.__conversation_user(inputs, llm_kwargs)) # 处理用户对话 - response = self.zhipu_bro.chat.completions.create( - model=self.model, messages=messages, stream=True, - temperature=llm_kwargs.get('temperature', 0.95) * 0.95, # 只能传默认的 temperature 和 top_p - top_p=llm_kwargs.get('top_p', 0.7) * 0.7, - max_tokens=llm_kwargs.get('max_tokens', 1024 * 4), # 最大输出模型的一半 - ) - return response - - def generate_chat(self, inputs, llm_kwargs, history, system_prompt): - self.model = llm_kwargs['llm_model'] - response = self.__conversation_message_payload(inputs, llm_kwargs, history, system_prompt) - bro_results = '' - for chunk in response: - bro_results += chunk.choices[0].delta.content - yield chunk.choices[0].delta.content, bro_results - - -if __name__ == '__main__': - zhipu = ZhipuChatInit() - zhipu.generate_chat('你好', {'llm_model': 'glm-4'}, [], '你是WPSAi') diff --git a/request_llms/key_manager.py b/request_llms/key_manager.py deleted file mode 100644 index 8563d2ef823e79cb9242ca924ac5b525dc21fffb..0000000000000000000000000000000000000000 --- a/request_llms/key_manager.py +++ /dev/null @@ -1,29 +0,0 @@ -import random - -def Singleton(cls): - _instance = {} - - def _singleton(*args, **kargs): - if cls not in _instance: - _instance[cls] = cls(*args, **kargs) - return _instance[cls] - - return _singleton - - -@Singleton -class OpenAI_ApiKeyManager(): - def __init__(self, mode='blacklist') -> None: - # self.key_avail_list = [] - self.key_black_list = [] - - def add_key_to_blacklist(self, key): - self.key_black_list.append(key) - - def select_avail_key(self, key_list): - # select key from key_list, but avoid keys also in self.key_black_list, raise error if no key can be found - available_keys = [key for key in key_list if key not in self.key_black_list] - if not available_keys: - raise KeyError("No available key found.") - selected_key = random.choice(available_keys) - return selected_key \ No newline at end of file diff --git a/request_llms/local_llm_class.py b/request_llms/local_llm_class.py deleted file mode 100644 index ec7cfd2195211587691628094a803e8432714ee9..0000000000000000000000000000000000000000 --- a/request_llms/local_llm_class.py +++ /dev/null @@ -1,319 +0,0 @@ -import time -import threading -from toolbox import update_ui, Singleton -from multiprocessing import Process, Pipe -from contextlib import redirect_stdout -from request_llms.queued_pipe import create_queue_pipe - -class ThreadLock(object): - def __init__(self): - self._lock = threading.Lock() - - def acquire(self): - # print("acquiring", self) - #traceback.print_tb - self._lock.acquire() - # print("acquired", self) - - def release(self): - # print("released", self) - #traceback.print_tb - self._lock.release() - - def __enter__(self): - self.acquire() - - def __exit__(self, type, value, traceback): - self.release() - -@Singleton -class GetSingletonHandle(): - def __init__(self): - self.llm_model_already_running = {} - - def get_llm_model_instance(self, cls, *args, **kargs): - if cls not in self.llm_model_already_running: - self.llm_model_already_running[cls] = cls(*args, **kargs) - return self.llm_model_already_running[cls] - elif self.llm_model_already_running[cls].corrupted: - self.llm_model_already_running[cls] = cls(*args, **kargs) - return self.llm_model_already_running[cls] - else: - return self.llm_model_already_running[cls] - -def reset_tqdm_output(): - import sys, tqdm - def status_printer(self, file): - fp = file - if fp in (sys.stderr, sys.stdout): - getattr(sys.stderr, 'flush', lambda: None)() - getattr(sys.stdout, 'flush', lambda: None)() - - def fp_write(s): - print(s) - last_len = [0] - - def print_status(s): - from tqdm.utils import disp_len - len_s = disp_len(s) - fp_write('\r' + s + (' ' * max(last_len[0] - len_s, 0))) - last_len[0] = len_s - return print_status - tqdm.tqdm.status_printer = status_printer - - -class LocalLLMHandle(Process): - def __init__(self): - # ⭐run in main process - super().__init__(daemon=True) - self.is_main_process = True # init - self.corrupted = False - self.load_model_info() - self.parent, self.child = create_queue_pipe() - self.parent_state, self.child_state = create_queue_pipe() - # allow redirect_stdout - self.std_tag = "[Subprocess Message] " - self.running = True - self._model = None - self._tokenizer = None - self.state = "" - self.check_dependency() - self.is_main_process = False # state wrap for child process - self.start() - self.is_main_process = True # state wrap for child process - self.threadLock = ThreadLock() - - def get_state(self): - # ⭐run in main process - while self.parent_state.poll(): - self.state = self.parent_state.recv() - return self.state - - def set_state(self, new_state): - # ⭐run in main process or 🏃‍♂️🏃‍♂️🏃‍♂️ run in child process - if self.is_main_process: - self.state = new_state - else: - self.child_state.send(new_state) - - def load_model_info(self): - # 🏃‍♂️🏃‍♂️🏃‍♂️ run in child process - raise NotImplementedError("Method not implemented yet") - self.model_name = "" - self.cmd_to_install = "" - - def load_model_and_tokenizer(self): - """ - This function should return the model and the tokenizer - """ - # 🏃‍♂️🏃‍♂️🏃‍♂️ run in child process - raise NotImplementedError("Method not implemented yet") - - def llm_stream_generator(self, **kwargs): - # 🏃‍♂️🏃‍♂️🏃‍♂️ run in child process - raise NotImplementedError("Method not implemented yet") - - def try_to_import_special_deps(self, **kwargs): - """ - import something that will raise error if the user does not install requirement_*.txt - """ - # ⭐run in main process - raise NotImplementedError("Method not implemented yet") - - def check_dependency(self): - # ⭐run in main process - try: - self.try_to_import_special_deps() - self.set_state("`依赖检测通过`") - self.running = True - except: - self.set_state(f"缺少{self.model_name}的依赖,如果要使用{self.model_name},除了基础的pip依赖以外,您还需要运行{self.cmd_to_install}安装{self.model_name}的依赖。") - self.running = False - - def run(self): - # 🏃‍♂️🏃‍♂️🏃‍♂️ run in child process - # 第一次运行,加载参数 - self.child.flush = lambda *args: None - self.child.write = lambda x: self.child.send(self.std_tag + x) - reset_tqdm_output() - self.set_state("`尝试加载模型`") - try: - with redirect_stdout(self.child): - self._model, self._tokenizer = self.load_model_and_tokenizer() - except: - self.set_state("`加载模型失败`") - self.running = False - from toolbox import trimmed_format_exc - self.child.send( - f'[Local Message] 不能正常加载{self.model_name}的参数.' + '\n```\n' + trimmed_format_exc() + '\n```\n') - self.child.send('[FinishBad]') - raise RuntimeError(f"不能正常加载{self.model_name}的参数!") - - self.set_state("`准备就绪`") - while True: - # 进入任务等待状态 - kwargs = self.child.recv() - # 收到消息,开始请求 - try: - for response_full in self.llm_stream_generator(**kwargs): - self.child.send(response_full) - # print('debug' + response_full) - self.child.send('[Finish]') - # 请求处理结束,开始下一个循环 - except: - from toolbox import trimmed_format_exc - self.child.send( - f'[Local Message] 调用{self.model_name}失败.' + '\n```\n' + trimmed_format_exc() + '\n```\n') - self.child.send('[Finish]') - - def clear_pending_messages(self): - # ⭐run in main process - while True: - if self.parent.poll(): - self.parent.recv() - continue - for _ in range(5): - time.sleep(0.5) - if self.parent.poll(): - r = self.parent.recv() - continue - break - return - - def stream_chat(self, **kwargs): - # ⭐run in main process - if self.get_state() == "`准备就绪`": - yield "`正在等待线程锁,排队中请稍候 ...`" - - with self.threadLock: - if self.parent.poll(): - yield "`排队中请稍候 ...`" - self.clear_pending_messages() - self.parent.send(kwargs) - std_out = "" - std_out_clip_len = 4096 - while True: - res = self.parent.recv() - # pipe_watch_dog.feed() - if res.startswith(self.std_tag): - new_output = res[len(self.std_tag):] - std_out = std_out[:std_out_clip_len] - print(new_output, end='') - std_out = new_output + std_out - yield self.std_tag + '\n```\n' + std_out + '\n```\n' - elif res == '[Finish]': - break - elif res == '[FinishBad]': - self.running = False - self.corrupted = True - break - else: - std_out = "" - yield res - -def get_local_llm_predict_fns(LLMSingletonClass, model_name, history_format='classic'): - load_message = f"{model_name}尚未加载,加载需要一段时间。注意,取决于`config.py`的配置,{model_name}消耗大量的内存(CPU)或显存(GPU),也许会导致低配计算机卡死 ……" - - def predict_no_ui_long_connection(inputs, llm_kwargs, history=[], sys_prompt="", observe_window=[], console_slience=False): - """ - refer to request_llms/bridge_all.py - """ - _llm_handle = GetSingletonHandle().get_llm_model_instance(LLMSingletonClass) - if len(observe_window) >= 1: - observe_window[0] = load_message + "\n\n" + _llm_handle.get_state() - if not _llm_handle.running: - raise RuntimeError(_llm_handle.get_state()) - - if history_format == 'classic': - # 没有 sys_prompt 接口,因此把prompt加入 history - history_feedin = [] - history_feedin.append([sys_prompt, "Certainly!"]) - for i in range(len(history)//2): - history_feedin.append([history[2*i], history[2*i+1]]) - elif history_format == 'chatglm3': - # 有 sys_prompt 接口 - conversation_cnt = len(history) // 2 - history_feedin = [{"role": "system", "content": sys_prompt}] - if conversation_cnt: - for index in range(0, 2*conversation_cnt, 2): - what_i_have_asked = {} - what_i_have_asked["role"] = "user" - what_i_have_asked["content"] = history[index] - what_gpt_answer = {} - what_gpt_answer["role"] = "assistant" - what_gpt_answer["content"] = history[index+1] - if what_i_have_asked["content"] != "": - if what_gpt_answer["content"] == "": - continue - history_feedin.append(what_i_have_asked) - history_feedin.append(what_gpt_answer) - else: - history_feedin[-1]['content'] = what_gpt_answer['content'] - - watch_dog_patience = 5 # 看门狗 (watchdog) 的耐心, 设置5秒即可 - response = "" - for response in _llm_handle.stream_chat(query=inputs, history=history_feedin, max_length=llm_kwargs['max_length'], top_p=llm_kwargs['top_p'], temperature=llm_kwargs['temperature']): - if len(observe_window) >= 1: - observe_window[0] = response - if len(observe_window) >= 2: - if (time.time()-observe_window[1]) > watch_dog_patience: - raise RuntimeError("程序终止。") - return response - - def predict(inputs, llm_kwargs, plugin_kwargs, chatbot, history=[], system_prompt='', stream=True, additional_fn=None): - """ - refer to request_llms/bridge_all.py - """ - chatbot.append((inputs, "")) - - _llm_handle = GetSingletonHandle().get_llm_model_instance(LLMSingletonClass) - chatbot[-1] = (inputs, load_message + "\n\n" + _llm_handle.get_state()) - yield from update_ui(chatbot=chatbot, history=[]) - if not _llm_handle.running: - raise RuntimeError(_llm_handle.get_state()) - - if additional_fn is not None: - from core_functional import handle_core_functionality - inputs, history = handle_core_functionality( - additional_fn, inputs, history, chatbot) - - # 处理历史信息 - if history_format == 'classic': - # 没有 sys_prompt 接口,因此把prompt加入 history - history_feedin = [] - history_feedin.append([system_prompt, "Certainly!"]) - for i in range(len(history)//2): - history_feedin.append([history[2*i], history[2*i+1]]) - elif history_format == 'chatglm3': - # 有 sys_prompt 接口 - conversation_cnt = len(history) // 2 - history_feedin = [{"role": "system", "content": system_prompt}] - if conversation_cnt: - for index in range(0, 2*conversation_cnt, 2): - what_i_have_asked = {} - what_i_have_asked["role"] = "user" - what_i_have_asked["content"] = history[index] - what_gpt_answer = {} - what_gpt_answer["role"] = "assistant" - what_gpt_answer["content"] = history[index+1] - if what_i_have_asked["content"] != "": - if what_gpt_answer["content"] == "": - continue - history_feedin.append(what_i_have_asked) - history_feedin.append(what_gpt_answer) - else: - history_feedin[-1]['content'] = what_gpt_answer['content'] - - # 开始接收回复 - response = f"[Local Message] 等待{model_name}响应中 ..." - for response in _llm_handle.stream_chat(query=inputs, history=history_feedin, max_length=llm_kwargs['max_length'], top_p=llm_kwargs['top_p'], temperature=llm_kwargs['temperature']): - chatbot[-1] = (inputs, response) - yield from update_ui(chatbot=chatbot, history=history) - - # 总结输出 - if response == f"[Local Message] 等待{model_name}响应中 ...": - response = f"[Local Message] {model_name}响应异常 ..." - history.extend([inputs, response]) - yield from update_ui(chatbot=chatbot, history=history) - - return predict_no_ui_long_connection, predict diff --git a/request_llms/moss b/request_llms/moss deleted file mode 160000 index 4d905bcead53739d4395b145cae2be308b1df795..0000000000000000000000000000000000000000 --- a/request_llms/moss +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 4d905bcead53739d4395b145cae2be308b1df795 diff --git a/request_llms/queued_pipe.py b/request_llms/queued_pipe.py deleted file mode 100644 index 1fc2e5bd53801898dbf0c98268de9e10c37bace9..0000000000000000000000000000000000000000 --- a/request_llms/queued_pipe.py +++ /dev/null @@ -1,24 +0,0 @@ -from multiprocessing import Pipe, Queue -import time -import threading - -class PipeSide(object): - def __init__(self, q_2remote, q_2local) -> None: - self.q_2remote = q_2remote - self.q_2local = q_2local - - def recv(self): - return self.q_2local.get() - - def send(self, buf): - self.q_2remote.put(buf) - - def poll(self): - return not self.q_2local.empty() - -def create_queue_pipe(): - q_p2c = Queue() - q_c2p = Queue() - pipe_c = PipeSide(q_2local=q_p2c, q_2remote=q_c2p) - pipe_p = PipeSide(q_2local=q_c2p, q_2remote=q_p2c) - return pipe_c, pipe_p diff --git a/request_llms/requirements_qwen.txt b/request_llms/requirements_qwen.txt deleted file mode 100644 index e9617907be68516ff85ab10097a5e52423664c8e..0000000000000000000000000000000000000000 --- a/request_llms/requirements_qwen.txt +++ /dev/null @@ -1 +0,0 @@ -dashscope diff --git a/request_llms/requirements_qwen_local.txt b/request_llms/requirements_qwen_local.txt deleted file mode 100644 index c4715f3f5e48ff41e828a86b69c2fa90c039fe14..0000000000000000000000000000000000000000 --- a/request_llms/requirements_qwen_local.txt +++ /dev/null @@ -1,5 +0,0 @@ -modelscope -transformers_stream_generator -auto-gptq -optimum -urllib3<2 diff --git a/request_llms/requirements_slackclaude.txt b/request_llms/requirements_slackclaude.txt deleted file mode 100644 index 7c8563efb570325a9145f1e9af972ee34b394904..0000000000000000000000000000000000000000 --- a/request_llms/requirements_slackclaude.txt +++ /dev/null @@ -1 +0,0 @@ -slack-sdk==3.21.3 diff --git a/requirements.txt b/requirements.txt index 007c5a775de882e9e83ddceb1904d7be1b9fffac..0a9a4c83f90cd9796ff9e5c52b3512eeb4c19e68 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,28 +1,22 @@ -https://public.agent-matrix.com/publish/gradio-3.32.8-py3-none-any.whl -gradio-client==0.8 -pypdf2==2.12.1 -zhipuai>=2 +pydantic==1.10.11 tiktoken>=0.3.3 requests[socks] -pydantic==2.5.2 -protobuf==3.18 -transformers>=4.27.1 -scipdf_parser>=0.52 +transformers python-markdown-math -pymdown-extensions -websocket-client beautifulsoup4 prompt_toolkit latex2mathml python-docx mdtex2html anthropic -pyautogen colorama Markdown pygments pymupdf openai -arxiv numpy +arxiv rich +pypdf2==2.12.1 +websocket-client +scipdf_parser>=0.3 diff --git a/shared_utils/advanced_markdown_format.py b/shared_utils/advanced_markdown_format.py deleted file mode 100644 index a015fd608914ed41982be743bc45ca9541d2166c..0000000000000000000000000000000000000000 --- a/shared_utils/advanced_markdown_format.py +++ /dev/null @@ -1,361 +0,0 @@ -import markdown -import re -import os -import math -from textwrap import dedent -from functools import lru_cache -from pymdownx.superfences import fence_code_format -from latex2mathml.converter import convert as tex2mathml -from shared_utils.config_loader import get_conf as get_conf -from shared_utils.text_mask import apply_gpt_academic_string_mask - -markdown_extension_configs = { - "mdx_math": { - "enable_dollar_delimiter": True, - "use_gitlab_delimiters": False, - }, -} - -code_highlight_configs = { - "pymdownx.superfences": { - "css_class": "codehilite", - "custom_fences": [ - {"name": "mermaid", "class": "mermaid", "format": fence_code_format} - ], - }, - "pymdownx.highlight": { - "css_class": "codehilite", - "guess_lang": True, - # 'auto_title': True, - # 'linenums': True - }, -} - -code_highlight_configs_block_mermaid = { - "pymdownx.superfences": { - "css_class": "codehilite", - # "custom_fences": [ - # {"name": "mermaid", "class": "mermaid", "format": fence_code_format} - # ], - }, - "pymdownx.highlight": { - "css_class": "codehilite", - "guess_lang": True, - # 'auto_title': True, - # 'linenums': True - }, -} - -def tex2mathml_catch_exception(content, *args, **kwargs): - try: - content = tex2mathml(content, *args, **kwargs) - except: - content = content - return content - - -def replace_math_no_render(match): - content = match.group(1) - if "mode=display" in match.group(0): - content = content.replace("\n", "
") - return f'$${content}$$' - else: - return f'${content}$' - - -def replace_math_render(match): - content = match.group(1) - if "mode=display" in match.group(0): - if "\\begin{aligned}" in content: - content = content.replace("\\begin{aligned}", "\\begin{array}") - content = content.replace("\\end{aligned}", "\\end{array}") - content = content.replace("&", " ") - content = tex2mathml_catch_exception(content, display="block") - return content - else: - return tex2mathml_catch_exception(content) - - -def markdown_bug_hunt(content): - """ - 解决一个mdx_math的bug(单$包裹begin命令时多余\n", "") - return content - - -def is_equation(txt): - """ - 判定是否为公式 | 测试1 写出洛伦兹定律,使用tex格式公式 测试2 给出柯西不等式,使用latex格式 测试3 写出麦克斯韦方程组 - """ - if "```" in txt and "```reference" not in txt: - return False - if "$" not in txt and "\\[" not in txt: - return False - mathpatterns = { - r"(?^[ \t]*(?:~{3,}|`{3,}))[ ]* # opening fence - ((\{(?P[^\}\n]*)\})| # (optional {attrs} or - (\.?(?P[\w#.+-]*)[ ]*)? # optional (.)lang - (hl_lines=(?P"|')(?P.*?)(?P=quot)[ ]*)?) # optional hl_lines) - \n # newline (end of opening fence) - (?P.*?)(?<=\n) # the code block - (?P=fence)[ ]*$ # closing fence - """ - ), - re.MULTILINE | re.DOTALL | re.VERBOSE, -) - - -def get_line_range(re_match_obj, txt): - start_pos, end_pos = re_match_obj.regs[0] - num_newlines_before = txt[: start_pos + 1].count("\n") - line_start = num_newlines_before - line_end = num_newlines_before + txt[start_pos:end_pos].count("\n") + 1 - return line_start, line_end - - -def fix_code_segment_indent(txt): - lines = [] - change_any = False - txt_tmp = txt - while True: - re_match_obj = FENCED_BLOCK_RE.search(txt_tmp) - if not re_match_obj: - break - if len(lines) == 0: - lines = txt.split("\n") - - # 清空 txt_tmp 对应的位置方便下次搜索 - start_pos, end_pos = re_match_obj.regs[0] - txt_tmp = txt_tmp[:start_pos] + " " * (end_pos - start_pos) + txt_tmp[end_pos:] - line_start, line_end = get_line_range(re_match_obj, txt) - - # 获取公共缩进 - shared_indent_cnt = 1e5 - for i in range(line_start, line_end): - stripped_string = lines[i].lstrip() - num_spaces = len(lines[i]) - len(stripped_string) - if num_spaces < shared_indent_cnt: - shared_indent_cnt = num_spaces - - # 修复缩进 - if (shared_indent_cnt < 1e5) and (shared_indent_cnt % 4) == 3: - num_spaces_should_be = math.ceil(shared_indent_cnt / 4) * 4 - for i in range(line_start, line_end): - add_n = num_spaces_should_be - shared_indent_cnt - lines[i] = " " * add_n + lines[i] - if not change_any: # 遇到第一个 - change_any = True - - if change_any: - return "\n".join(lines) - else: - return txt - - -@lru_cache(maxsize=128) # 使用 lru缓存 加快转换速度 -def markdown_convertion(txt): - """ - 将Markdown格式的文本转换为HTML格式。如果包含数学公式,则先将公式转换为HTML格式。 - """ - pre = '
' - suf = "
" - if txt.startswith(pre) and txt.endswith(suf): - # print('警告,输入了已经经过转化的字符串,二次转化可能出问题') - return txt # 已经被转化过,不需要再次转化 - - find_equation_pattern = r'\n""" - - # 添加Live2D - if ADD_WAIFU: - for jsf in [ - "file=themes/waifu_plugin/jquery.min.js", - "file=themes/waifu_plugin/jquery-ui.min.js", - ]: - js += f"""\n""" - return js \ No newline at end of file diff --git a/themes/contrast.css b/themes/contrast.css index 980a7e4fb6228723b8b83faf1892da9bad25298b..54a1b2b4480bde6ac17938fd73691b13f43d84ef 100644 --- a/themes/contrast.css +++ b/themes/contrast.css @@ -17,7 +17,7 @@ --button-primary-text-color-hover: #FFFFFF; --button-secondary-text-color: #FFFFFF; --button-secondary-text-color-hover: #FFFFFF; - + --border-bottom-right-radius: 0px; --border-bottom-left-radius: 0px; @@ -51,8 +51,8 @@ --button-primary-border-color-hover: #3cff00; --button-secondary-border-color: #3cff00; --button-secondary-border-color-hover: #3cff00; - - + + --body-background-fill: #000000; --background-fill-primary: #000000; --background-fill-secondary: #000000; @@ -103,7 +103,7 @@ --button-primary-text-color-hover: #FFFFFF; --button-secondary-text-color: #FFFFFF; --button-secondary-text-color-hover: #FFFFFF; - + --border-bottom-right-radius: 0px; @@ -138,8 +138,8 @@ --button-primary-border-color-hover: #3cff00; --button-secondary-border-color: #3cff00; --button-secondary-border-color-hover: #3cff00; - - + + --body-background-fill: #000000; --background-fill-primary: #000000; --background-fill-secondary: #000000; @@ -198,7 +198,7 @@ } /* 小按钮 */ -.sm { +.sm.svelte-1ipelgc { font-family: "Microsoft YaHei UI", "Helvetica", "Microsoft YaHei", "ui-sans-serif", "sans-serif", "system-ui"; --button-small-text-weight: 600; --button-small-text-size: 16px; @@ -208,7 +208,7 @@ border-top-left-radius: 0px; } -#plugin-panel .sm { +#plugin-panel .sm.svelte-1ipelgc { font-family: "Microsoft YaHei UI", "Helvetica", "Microsoft YaHei", "ui-sans-serif", "sans-serif", "system-ui"; --button-small-text-weight: 400; --button-small-text-size: 14px; @@ -479,3 +479,4 @@ .dark .codehilite .vi { color: #89DDFF } /* Name.Variable.Instance */ .dark .codehilite .vm { color: #82AAFF } /* Name.Variable.Magic */ .dark .codehilite .il { color: #F78C6C } /* Literal.Number.Integer.Long */ + diff --git a/themes/contrast.py b/themes/contrast.py index 1e98837755de43f0eb99b02dd4d344064ee600da..fd4ef0465bd97db3a4cb5c20ac749e364a640677 100644 --- a/themes/contrast.py +++ b/themes/contrast.py @@ -1,26 +1,16 @@ -import os import gradio as gr from toolbox import get_conf - -CODE_HIGHLIGHT, ADD_WAIFU, LAYOUT = get_conf("CODE_HIGHLIGHT", "ADD_WAIFU", "LAYOUT") -theme_dir = os.path.dirname(__file__) - +CODE_HIGHLIGHT, ADD_WAIFU, LAYOUT = get_conf('CODE_HIGHLIGHT', 'ADD_WAIFU', 'LAYOUT') def adjust_theme(): + try: color_er = gr.themes.utils.colors.fuchsia set_theme = gr.themes.Default( primary_hue=gr.themes.utils.colors.orange, neutral_hue=gr.themes.utils.colors.gray, - font=[ - "Helvetica", - "Microsoft YaHei", - "ui-sans-serif", - "sans-serif", - "system-ui", - ], - font_mono=["ui-monospace", "Consolas", "monospace"], - ) + font=["Helvetica", "Microsoft YaHei", "ui-sans-serif", "sans-serif", "system-ui"], + font_mono=["ui-monospace", "Consolas", "monospace"]) set_theme.set( # Colors input_background_fill_dark="*neutral_800", @@ -67,29 +57,32 @@ def adjust_theme(): button_cancel_text_color_dark="white", ) - from themes.common import get_common_html_javascript_code - js = get_common_html_javascript_code() - - if not hasattr(gr, "RawTemplateResponse"): - gr.RawTemplateResponse = gr.routes.templates.TemplateResponse - gradio_original_template_fn = gr.RawTemplateResponse - + if LAYOUT=="TOP-DOWN": + js = "" + else: + with open('themes/common.js', 'r', encoding='utf8') as f: + js = f"" + + # 添加一个萌萌的看板娘 + if ADD_WAIFU: + js += """ + + + + """ + gradio_original_template_fn = gr.routes.templates.TemplateResponse def gradio_new_template_fn(*args, **kwargs): res = gradio_original_template_fn(*args, **kwargs) - res.body = res.body.replace(b"", f"{js}".encode("utf8")) + res.body = res.body.replace(b'', f'{js}'.encode("utf8")) res.init_headers() return res - - gr.routes.templates.TemplateResponse = ( - gradio_new_template_fn # override gradio template - ) + gr.routes.templates.TemplateResponse = gradio_new_template_fn # override gradio template except: set_theme = None - print("gradio版本较旧, 不能自定义字体和颜色") + print('gradio版本较旧, 不能自定义字体和颜色') return set_theme - -with open(os.path.join(theme_dir, "contrast.css"), "r", encoding="utf-8") as f: +with open("themes/contrast.css", "r", encoding="utf-8") as f: advanced_css = f.read() -with open(os.path.join(theme_dir, "common.css"), "r", encoding="utf-8") as f: +with open("themes/common.css", "r", encoding="utf-8") as f: advanced_css += f.read() diff --git a/themes/cookies.py b/themes/cookies.py deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/themes/default.css b/themes/default.css index 5a9e3ea7a2f1c213cb2a4035e1eba5c1a70643e4..a35cd1d420576e36e82aff8d3e1147629bac2546 100644 --- a/themes/default.css +++ b/themes/default.css @@ -1,8 +1,3 @@ -/* 插件下拉菜单 */ -#elem_audio { - border-style: hidden !important; -} - .dark { --background-fill-primary: #050810; --body-background-fill: var(--background-fill-primary); @@ -14,15 +9,15 @@ border-radius: 4px; } -#plugin-panel .dropdown-arrow { - width: 25px; +#plugin-panel .dropdown-arrow.svelte-p5edak { + width: 50px; } #plugin-panel input.svelte-aqlk7e.svelte-aqlk7e.svelte-aqlk7e { padding-left: 5px; } /* 小按钮 */ -#basic-panel .sm { +.sm.svelte-1ipelgc { font-family: "Microsoft YaHei UI", "Helvetica", "Microsoft YaHei", "ui-sans-serif", "sans-serif", "system-ui"; --button-small-text-weight: 600; --button-small-text-size: 16px; @@ -32,7 +27,7 @@ border-top-left-radius: 6px; } -#plugin-panel .sm { +#plugin-panel .sm.svelte-1ipelgc { font-family: "Microsoft YaHei UI", "Helvetica", "Microsoft YaHei", "ui-sans-serif", "sans-serif", "system-ui"; --button-small-text-weight: 400; --button-small-text-size: 14px; @@ -303,3 +298,4 @@ .dark .codehilite .vi { color: #89DDFF } /* Name.Variable.Instance */ .dark .codehilite .vm { color: #82AAFF } /* Name.Variable.Magic */ .dark .codehilite .il { color: #F78C6C } /* Literal.Number.Integer.Long */ + diff --git a/themes/default.py b/themes/default.py index a65b0119f36b694c41abd06609eeeee96f958a21..2611e7aab7e7b6a41a3ef4c21a4f47b22409bebe 100644 --- a/themes/default.py +++ b/themes/default.py @@ -1,26 +1,16 @@ -import os import gradio as gr from toolbox import get_conf - -CODE_HIGHLIGHT, ADD_WAIFU, LAYOUT = get_conf("CODE_HIGHLIGHT", "ADD_WAIFU", "LAYOUT") -theme_dir = os.path.dirname(__file__) - +CODE_HIGHLIGHT, ADD_WAIFU, LAYOUT = get_conf('CODE_HIGHLIGHT', 'ADD_WAIFU', 'LAYOUT') def adjust_theme(): + try: color_er = gr.themes.utils.colors.fuchsia set_theme = gr.themes.Default( primary_hue=gr.themes.utils.colors.orange, neutral_hue=gr.themes.utils.colors.gray, - font=[ - "Helvetica", - "Microsoft YaHei", - "ui-sans-serif", - "sans-serif", - "system-ui", - ], - font_mono=["ui-monospace", "Consolas", "monospace"], - ) + font=["Helvetica", "Microsoft YaHei", "ui-sans-serif", "sans-serif", "system-ui"], + font_mono=["ui-monospace", "Consolas", "monospace"]) set_theme.set( # Colors input_background_fill_dark="*neutral_800", @@ -67,28 +57,32 @@ def adjust_theme(): button_cancel_text_color_dark="white", ) - from themes.common import get_common_html_javascript_code - js = get_common_html_javascript_code() - if not hasattr(gr, "RawTemplateResponse"): - gr.RawTemplateResponse = gr.routes.templates.TemplateResponse - gradio_original_template_fn = gr.RawTemplateResponse - + if LAYOUT=="TOP-DOWN": + js = "" + else: + with open('themes/common.js', 'r', encoding='utf8') as f: + js = f"" + + # 添加一个萌萌的看板娘 + if ADD_WAIFU: + js += """ + + + + """ + gradio_original_template_fn = gr.routes.templates.TemplateResponse def gradio_new_template_fn(*args, **kwargs): res = gradio_original_template_fn(*args, **kwargs) - res.body = res.body.replace(b"", f"{js}".encode("utf8")) + res.body = res.body.replace(b'', f'{js}'.encode("utf8")) res.init_headers() return res - - gr.routes.templates.TemplateResponse = ( - gradio_new_template_fn # override gradio template - ) + gr.routes.templates.TemplateResponse = gradio_new_template_fn # override gradio template except: set_theme = None - print("gradio版本较旧, 不能自定义字体和颜色") + print('gradio版本较旧, 不能自定义字体和颜色') return set_theme - -with open(os.path.join(theme_dir, "default.css"), "r", encoding="utf-8") as f: +with open("themes/default.css", "r", encoding="utf-8") as f: advanced_css = f.read() -with open(os.path.join(theme_dir, "common.css"), "r", encoding="utf-8") as f: +with open("themes/common.css", "r", encoding="utf-8") as f: advanced_css += f.read() diff --git a/themes/gradios.py b/themes/gradios.py index 14d88a2996df118e4ac4a21717a4568df2d04226..8b661a567cc80e9f1a94b0a1df737e9699d0476a 100644 --- a/themes/gradios.py +++ b/themes/gradios.py @@ -1,59 +1,46 @@ -import logging -import os import gradio as gr +import logging from toolbox import get_conf, ProxyNetworkActivate - -CODE_HIGHLIGHT, ADD_WAIFU, LAYOUT = get_conf("CODE_HIGHLIGHT", "ADD_WAIFU", "LAYOUT") -theme_dir = os.path.dirname(__file__) - - -def dynamic_set_theme(THEME): - set_theme = gr.themes.ThemeClass() - with ProxyNetworkActivate("Download_Gradio_Theme"): - logging.info("正在下载Gradio主题,请稍等。") - if THEME.startswith("Huggingface-"): - THEME = THEME.lstrip("Huggingface-") - if THEME.startswith("huggingface-"): - THEME = THEME.lstrip("huggingface-") - set_theme = set_theme.from_hub(THEME.lower()) - return set_theme - +CODE_HIGHLIGHT, ADD_WAIFU, LAYOUT = get_conf('CODE_HIGHLIGHT', 'ADD_WAIFU', 'LAYOUT') def adjust_theme(): + try: set_theme = gr.themes.ThemeClass() - with ProxyNetworkActivate("Download_Gradio_Theme"): - logging.info("正在下载Gradio主题,请稍等。") - THEME = get_conf("THEME") - if THEME.startswith("Huggingface-"): - THEME = THEME.lstrip("Huggingface-") - if THEME.startswith("huggingface-"): - THEME = THEME.lstrip("huggingface-") + with ProxyNetworkActivate(): + logging.info('正在下载Gradio主题,请稍等。') + THEME, = get_conf('THEME') + if THEME.startswith('Huggingface-'): THEME = THEME.lstrip('Huggingface-') + if THEME.startswith('huggingface-'): THEME = THEME.lstrip('huggingface-') set_theme = set_theme.from_hub(THEME.lower()) - from themes.common import get_common_html_javascript_code - js = get_common_html_javascript_code() - - if not hasattr(gr, "RawTemplateResponse"): - gr.RawTemplateResponse = gr.routes.templates.TemplateResponse - gradio_original_template_fn = gr.RawTemplateResponse - + if LAYOUT=="TOP-DOWN": + js = "" + else: + with open('themes/common.js', 'r', encoding='utf8') as f: + js = f"" + + # 添加一个萌萌的看板娘 + if ADD_WAIFU: + js += """ + + + + """ + gradio_original_template_fn = gr.routes.templates.TemplateResponse def gradio_new_template_fn(*args, **kwargs): res = gradio_original_template_fn(*args, **kwargs) - res.body = res.body.replace(b"", f"{js}".encode("utf8")) + res.body = res.body.replace(b'', f'{js}'.encode("utf8")) res.init_headers() return res - - gr.routes.templates.TemplateResponse = ( - gradio_new_template_fn # override gradio template - ) - except Exception: + gr.routes.templates.TemplateResponse = gradio_new_template_fn # override gradio template + except Exception as e: set_theme = None from toolbox import trimmed_format_exc - - logging.error("gradio版本较旧, 不能自定义字体和颜色:", trimmed_format_exc()) + logging.error('gradio版本较旧, 不能自定义字体和颜色:', trimmed_format_exc()) return set_theme - -with open(os.path.join(theme_dir, "common.css"), "r", encoding="utf-8") as f: +# with open("themes/default.css", "r", encoding="utf-8") as f: +# advanced_css = f.read() +with open("themes/common.css", "r", encoding="utf-8") as f: advanced_css = f.read() diff --git a/themes/green.css b/themes/green.css index 85dd80139fb25a11b33ab1e67729b9297b73baa7..dd109d53fda81949834f74d767c77940709d557c 100644 --- a/themes/green.css +++ b/themes/green.css @@ -197,12 +197,12 @@ footer { } textarea.svelte-1pie7s6 { background: #e7e6e6 !important; - width: 100% !important; + width: 96% !important; } .dark textarea.svelte-1pie7s6 { background: var(--input-background-fill) !important; - width: 100% !important; + width: 96% !important; } .dark input[type=number].svelte-1cl284s { @@ -256,13 +256,13 @@ textarea.svelte-1pie7s6 { max-height: 95% !important; overflow-y: auto !important; }*/ -/* .app.svelte-1mya07g.svelte-1mya07g { +.app.svelte-1mya07g.svelte-1mya07g { max-width: 100%; position: relative; padding: var(--size-4); width: 100%; height: 100%; -} */ +} .gradio-container-3-32-2 h1 { font-weight: 700 !important; @@ -508,14 +508,12 @@ ol:not(.options), ul:not(.options) { [data-testid = "bot"] { max-width: 85%; border-bottom-left-radius: 0 !important; - box-shadow: 2px 2px 0px 1px rgba(0, 0, 0, 0.06); background-color: var(--message-bot-background-color-light) !important; } [data-testid = "user"] { max-width: 85%; width: auto !important; border-bottom-right-radius: 0 !important; - box-shadow: 2px 2px 0px 1px rgba(0, 0, 0, 0.06); background-color: var(--message-user-background-color-light) !important; } .dark [data-testid = "bot"] { diff --git a/themes/green.js b/themes/green.js index 7801b970d253b2372456ab0b25804189a3434bf5..65948c0344e85c098a7f96e176fa8388575ca07a 100644 --- a/themes/green.js +++ b/themes/green.js @@ -38,4 +38,4 @@ function setSlider() { window.addEventListener("DOMContentLoaded", () => { set_elements(); -}); +}); \ No newline at end of file diff --git a/themes/green.py b/themes/green.py index b16249a8e712b7387a3b5fcca332cf435bdaf1fb..5aa9e8b0f7673a9cf83d9916bcb249158f8b95d0 100644 --- a/themes/green.py +++ b/themes/green.py @@ -1,10 +1,6 @@ -import os import gradio as gr from toolbox import get_conf - -CODE_HIGHLIGHT, ADD_WAIFU, LAYOUT = get_conf("CODE_HIGHLIGHT", "ADD_WAIFU", "LAYOUT") -theme_dir = os.path.dirname(__file__) - +CODE_HIGHLIGHT, ADD_WAIFU, LAYOUT = get_conf('CODE_HIGHLIGHT', 'ADD_WAIFU', 'LAYOUT') def adjust_theme(): try: @@ -52,6 +48,7 @@ def adjust_theme(): c900="#2B2B2B", c950="#171717", ), + radius_size=gr.themes.sizes.radius_sm, ).set( button_primary_background_fill="*primary_500", @@ -76,32 +73,38 @@ def adjust_theme(): chatbot_code_background_color_dark="*neutral_950", ) - from themes.common import get_common_html_javascript_code - js = get_common_html_javascript_code() + js = '' + if LAYOUT=="TOP-DOWN": + js = "" + else: + with open('themes/common.js', 'r', encoding='utf8') as f: + js = f"" - with open(os.path.join(theme_dir, "green.js"), "r", encoding="utf8") as f: + # 添加一个萌萌的看板娘 + if ADD_WAIFU: + js += """ + + + + """ + + with open('themes/green.js', 'r', encoding='utf8') as f: js += f"" - - if not hasattr(gr, "RawTemplateResponse"): - gr.RawTemplateResponse = gr.routes.templates.TemplateResponse - gradio_original_template_fn = gr.RawTemplateResponse - + + gradio_original_template_fn = gr.routes.templates.TemplateResponse def gradio_new_template_fn(*args, **kwargs): res = gradio_original_template_fn(*args, **kwargs) - res.body = res.body.replace(b"", f"{js}".encode("utf8")) + res.body = res.body.replace(b'', f'{js}'.encode("utf8")) res.init_headers() return res - - gr.routes.templates.TemplateResponse = ( - gradio_new_template_fn # override gradio template - ) + gr.routes.templates.TemplateResponse = gradio_new_template_fn # override gradio template except: set_theme = None - print("gradio版本较旧, 不能自定义字体和颜色") + print('gradio版本较旧, 不能自定义字体和颜色') return set_theme -with open(os.path.join(theme_dir, "green.css"), "r", encoding="utf-8") as f: +with open("themes/green.css", "r", encoding="utf-8") as f: advanced_css = f.read() -with open(os.path.join(theme_dir, "common.css"), "r", encoding="utf-8") as f: +with open("themes/common.css", "r", encoding="utf-8") as f: advanced_css += f.read() diff --git a/themes/mermaid.min.js b/themes/mermaid.min.js deleted file mode 100644 index b842822bd75fdc06508b732335864a2ffd66a418..0000000000000000000000000000000000000000 --- a/themes/mermaid.min.js +++ /dev/null @@ -1 +0,0 @@ -// we have moved mermaid-related code to gradio-fix repository: binary-husky/gradio-fix@32150d0 diff --git a/themes/mermaid_editor.js b/themes/mermaid_editor.js deleted file mode 100644 index b842822bd75fdc06508b732335864a2ffd66a418..0000000000000000000000000000000000000000 --- a/themes/mermaid_editor.js +++ /dev/null @@ -1 +0,0 @@ -// we have moved mermaid-related code to gradio-fix repository: binary-husky/gradio-fix@32150d0 diff --git a/themes/mermaid_loader.js b/themes/mermaid_loader.js deleted file mode 100644 index b842822bd75fdc06508b732335864a2ffd66a418..0000000000000000000000000000000000000000 --- a/themes/mermaid_loader.js +++ /dev/null @@ -1 +0,0 @@ -// we have moved mermaid-related code to gradio-fix repository: binary-husky/gradio-fix@32150d0 diff --git a/themes/pako.esm.mjs b/themes/pako.esm.mjs deleted file mode 100644 index b842822bd75fdc06508b732335864a2ffd66a418..0000000000000000000000000000000000000000 --- a/themes/pako.esm.mjs +++ /dev/null @@ -1 +0,0 @@ -// we have moved mermaid-related code to gradio-fix repository: binary-husky/gradio-fix@32150d0 diff --git a/themes/theme.py b/themes/theme.py index 6bbe4f060bc8f36b4e9954e6cfb0c86b76b7c2dc..dbb8f1e23aabf4d1d2e37a00fc485561c369b8c1 100644 --- a/themes/theme.py +++ b/themes/theme.py @@ -1,196 +1,18 @@ -import pickle -import base64 -import uuid +import gradio as gr from toolbox import get_conf +THEME, = get_conf('THEME') + +if THEME == 'Chuanhu-Small-and-Beautiful': + from .green import adjust_theme, advanced_css + theme_declaration = "

[Chuanhu-Small-and-Beautiful主题]

" +elif THEME == 'High-Contrast': + from .contrast import adjust_theme, advanced_css + theme_declaration = "" +elif '/' in THEME: + from .gradios import adjust_theme, advanced_css + theme_declaration = "" +else: + from .default import adjust_theme, advanced_css + theme_declaration = "" -""" --=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -第 1 部分 -加载主题相关的工具函数 --=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -""" - -def load_dynamic_theme(THEME): - adjust_dynamic_theme = None - if THEME == "Chuanhu-Small-and-Beautiful": - from .green import adjust_theme, advanced_css - - theme_declaration = ( - '

[Chuanhu-Small-and-Beautiful主题]

' - ) - elif THEME == "High-Contrast": - from .contrast import adjust_theme, advanced_css - - theme_declaration = "" - elif "/" in THEME: - from .gradios import adjust_theme, advanced_css - from .gradios import dynamic_set_theme - - adjust_dynamic_theme = dynamic_set_theme(THEME) - theme_declaration = "" - else: - from .default import adjust_theme, advanced_css - - theme_declaration = "" - return adjust_theme, advanced_css, theme_declaration, adjust_dynamic_theme - - -adjust_theme, advanced_css, theme_declaration, _ = load_dynamic_theme(get_conf("THEME")) - - -""" --=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -第 2 部分 -cookie相关工具函数 --=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -""" - -def init_cookie(cookies): - # 为每一位访问的用户赋予一个独一无二的uuid编码 - cookies.update({"uuid": uuid.uuid4()}) - return cookies - - -def to_cookie_str(d): - # Pickle the dictionary and encode it as a string - pickled_dict = pickle.dumps(d) - cookie_value = base64.b64encode(pickled_dict).decode("utf-8") - return cookie_value - - -def from_cookie_str(c): - # Decode the base64-encoded string and unpickle it into a dictionary - pickled_dict = base64.b64decode(c.encode("utf-8")) - return pickle.loads(pickled_dict) - - -""" --=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -第 3 部分 -内嵌的javascript代码 --=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -""" - -js_code_for_css_changing = """(css) => { - var existingStyles = document.querySelectorAll("body > gradio-app > div > style") - for (var i = 0; i < existingStyles.length; i++) { - var style = existingStyles[i]; - style.parentNode.removeChild(style); - } - var existingStyles = document.querySelectorAll("style[data-loaded-css]"); - for (var i = 0; i < existingStyles.length; i++) { - var style = existingStyles[i]; - style.parentNode.removeChild(style); - } - var styleElement = document.createElement('style'); - styleElement.setAttribute('data-loaded-css', 'placeholder'); - styleElement.innerHTML = css; - document.body.appendChild(styleElement); -} -""" - - -js_code_for_toggle_darkmode = """() => { - if (document.querySelectorAll('.dark').length) { - setCookie("js_darkmode_cookie", "False", 365); - document.querySelectorAll('.dark').forEach(el => el.classList.remove('dark')); - } else { - setCookie("js_darkmode_cookie", "True", 365); - document.querySelector('body').classList.add('dark'); - } - document.querySelectorAll('code_pending_render').forEach(code => {code.remove();}) -}""" - - -js_code_for_persistent_cookie_init = """(py_pickle_cookie, cookie) => { - return [getCookie("py_pickle_cookie"), cookie]; -} -""" - - -js_code_reset = """ -(a,b,c)=>{ - return [[], [], "已重置"]; -} -""" - - -js_code_clear = """ -(a,b)=>{ - return ["", ""]; -} -""" - - -js_code_show_or_hide = """ -(display_panel_arr)=>{ -setTimeout(() => { - // get conf - display_panel_arr = get_checkbox_selected_items("cbs"); - - ////////////////////// 输入清除键 /////////////////////////// - let searchString = "输入清除键"; - let ele = "none"; - if (display_panel_arr.includes(searchString)) { - let clearButton = document.getElementById("elem_clear"); - let clearButton2 = document.getElementById("elem_clear2"); - clearButton.style.display = "block"; - clearButton2.style.display = "block"; - setCookie("js_clearbtn_show_cookie", "True", 365); - } else { - let clearButton = document.getElementById("elem_clear"); - let clearButton2 = document.getElementById("elem_clear2"); - clearButton.style.display = "none"; - clearButton2.style.display = "none"; - setCookie("js_clearbtn_show_cookie", "False", 365); - } - - ////////////////////// 基础功能区 /////////////////////////// - searchString = "基础功能区"; - if (display_panel_arr.includes(searchString)) { - ele = document.getElementById("basic-panel"); - ele.style.display = "block"; - } else { - ele = document.getElementById("basic-panel"); - ele.style.display = "none"; - } - - ////////////////////// 函数插件区 /////////////////////////// - searchString = "函数插件区"; - if (display_panel_arr.includes(searchString)) { - ele = document.getElementById("plugin-panel"); - ele.style.display = "block"; - } else { - ele = document.getElementById("plugin-panel"); - ele.style.display = "none"; - } - -}, 50); -} -""" - - - -js_code_show_or_hide_group2 = """ -(display_panel_arr)=>{ -setTimeout(() => { - // console.log("display_panel_arr"); - // get conf - display_panel_arr = get_checkbox_selected_items("cbsc"); - - ////////////////////// 添加Live2D形象 /////////////////////////// - let searchString = "添加Live2D形象"; - let ele = "none"; - if (display_panel_arr.includes(searchString)) { - setCookie("js_live2d_show_cookie", "True", 365); - loadLive2D(); - } else { - setCookie("js_live2d_show_cookie", "False", 365); - $('.waifu').hide(); - } - - -}, 50); -} -""" diff --git a/themes/waifu_plugin/autoload.js b/themes/waifu_plugin/autoload.js deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/themes/waifu_plugin/flat-ui-icons-regular.eot b/themes/waifu_plugin/flat-ui-icons-regular.eot deleted file mode 100644 index 536680e9f1070d3feb03038448f4ef4764a6784a..0000000000000000000000000000000000000000 Binary files a/themes/waifu_plugin/flat-ui-icons-regular.eot and /dev/null differ diff --git a/themes/waifu_plugin/flat-ui-icons-regular.svg b/themes/waifu_plugin/flat-ui-icons-regular.svg deleted file mode 100644 index e05f3a0d31e417b72be11d5935cbb201729085dc..0000000000000000000000000000000000000000 --- a/themes/waifu_plugin/flat-ui-icons-regular.svg +++ /dev/null @@ -1,126 +0,0 @@ - - - - - -{ - "fontFamily": "flat-ui-icons", - "majorVersion": 1, - "minorVersion": 1, - "fontURL": "http://designmodo.com/flat", - "designer": "Sergey Shmidt", - "designerURL": "http://designmodo.com", - "license": "Attribution-NonCommercial-NoDerivs 3.0 Unported", - "licenseURL": "http://creativecommons.org/licenses/by-nc-nd/3.0/", - "version": "Version 1.1", - "fontId": "flat-ui-icons", - "psName": "flat-ui-icons", - "subFamily": "Regular", - "fullName": "flat-ui-icons", - "description": "Generated by IcoMoon" -} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/themes/waifu_plugin/flat-ui-icons-regular.ttf b/themes/waifu_plugin/flat-ui-icons-regular.ttf deleted file mode 100644 index f4933ff3590f3c3644d32fe50f5d7148c2ede9b6..0000000000000000000000000000000000000000 Binary files a/themes/waifu_plugin/flat-ui-icons-regular.ttf and /dev/null differ diff --git a/themes/waifu_plugin/flat-ui-icons-regular.woff b/themes/waifu_plugin/flat-ui-icons-regular.woff deleted file mode 100644 index f9e9805e768525c296ed284e1bc803ca9e757679..0000000000000000000000000000000000000000 Binary files a/themes/waifu_plugin/flat-ui-icons-regular.woff and /dev/null differ diff --git a/themes/waifu_plugin/jquery-ui.min.js b/themes/waifu_plugin/jquery-ui.min.js deleted file mode 100644 index 862a649869db80cb6c8cd6d48f63ee0b56169a2c..0000000000000000000000000000000000000000 --- a/themes/waifu_plugin/jquery-ui.min.js +++ /dev/null @@ -1,13 +0,0 @@ -/*! jQuery UI - v1.12.1 - 2016-09-14 -* http://jqueryui.com -* Includes: widget.js, position.js, data.js, disable-selection.js, effect.js, effects/effect-blind.js, effects/effect-bounce.js, effects/effect-clip.js, effects/effect-drop.js, effects/effect-explode.js, effects/effect-fade.js, effects/effect-fold.js, effects/effect-highlight.js, effects/effect-puff.js, effects/effect-pulsate.js, effects/effect-scale.js, effects/effect-shake.js, effects/effect-size.js, effects/effect-slide.js, effects/effect-transfer.js, focusable.js, form-reset-mixin.js, jquery-1-7.js, keycode.js, labels.js, scroll-parent.js, tabbable.js, unique-id.js, widgets/accordion.js, widgets/autocomplete.js, widgets/button.js, widgets/checkboxradio.js, widgets/controlgroup.js, widgets/datepicker.js, widgets/dialog.js, widgets/draggable.js, widgets/droppable.js, widgets/menu.js, widgets/mouse.js, widgets/progressbar.js, widgets/resizable.js, widgets/selectable.js, widgets/selectmenu.js, widgets/slider.js, widgets/sortable.js, widgets/spinner.js, widgets/tabs.js, widgets/tooltip.js -* Copyright jQuery Foundation and other contributors; Licensed MIT */ - -(function(t){"function"==typeof define&&define.amd?define(["jquery"],t):t(jQuery)})(function(t){function e(t){for(var e=t.css("visibility");"inherit"===e;)t=t.parent(),e=t.css("visibility");return"hidden"!==e}function i(t){for(var e,i;t.length&&t[0]!==document;){if(e=t.css("position"),("absolute"===e||"relative"===e||"fixed"===e)&&(i=parseInt(t.css("zIndex"),10),!isNaN(i)&&0!==i))return i;t=t.parent()}return 0}function s(){this._curInst=null,this._keyEvent=!1,this._disabledInputs=[],this._datepickerShowing=!1,this._inDialog=!1,this._mainDivId="ui-datepicker-div",this._inlineClass="ui-datepicker-inline",this._appendClass="ui-datepicker-append",this._triggerClass="ui-datepicker-trigger",this._dialogClass="ui-datepicker-dialog",this._disableClass="ui-datepicker-disabled",this._unselectableClass="ui-datepicker-unselectable",this._currentClass="ui-datepicker-current-day",this._dayOverClass="ui-datepicker-days-cell-over",this.regional=[],this.regional[""]={closeText:"Done",prevText:"Prev",nextText:"Next",currentText:"Today",monthNames:["January","February","March","April","May","June","July","August","September","October","November","December"],monthNamesShort:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],dayNames:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],dayNamesShort:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],dayNamesMin:["Su","Mo","Tu","We","Th","Fr","Sa"],weekHeader:"Wk",dateFormat:"mm/dd/yy",firstDay:0,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""},this._defaults={showOn:"focus",showAnim:"fadeIn",showOptions:{},defaultDate:null,appendText:"",buttonText:"...",buttonImage:"",buttonImageOnly:!1,hideIfNoPrevNext:!1,navigationAsDateFormat:!1,gotoCurrent:!1,changeMonth:!1,changeYear:!1,yearRange:"c-10:c+10",showOtherMonths:!1,selectOtherMonths:!1,showWeek:!1,calculateWeek:this.iso8601Week,shortYearCutoff:"+10",minDate:null,maxDate:null,duration:"fast",beforeShowDay:null,beforeShow:null,onSelect:null,onChangeMonthYear:null,onClose:null,numberOfMonths:1,showCurrentAtPos:0,stepMonths:1,stepBigMonths:12,altField:"",altFormat:"",constrainInput:!0,showButtonPanel:!1,autoSize:!1,disabled:!1},t.extend(this._defaults,this.regional[""]),this.regional.en=t.extend(!0,{},this.regional[""]),this.regional["en-US"]=t.extend(!0,{},this.regional.en),this.dpDiv=n(t("
"))}function n(e){var i="button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a";return e.on("mouseout",i,function(){t(this).removeClass("ui-state-hover"),-1!==this.className.indexOf("ui-datepicker-prev")&&t(this).removeClass("ui-datepicker-prev-hover"),-1!==this.className.indexOf("ui-datepicker-next")&&t(this).removeClass("ui-datepicker-next-hover")}).on("mouseover",i,o)}function o(){t.datepicker._isDisabledDatepicker(m.inline?m.dpDiv.parent()[0]:m.input[0])||(t(this).parents(".ui-datepicker-calendar").find("a").removeClass("ui-state-hover"),t(this).addClass("ui-state-hover"),-1!==this.className.indexOf("ui-datepicker-prev")&&t(this).addClass("ui-datepicker-prev-hover"),-1!==this.className.indexOf("ui-datepicker-next")&&t(this).addClass("ui-datepicker-next-hover"))}function a(e,i){t.extend(e,i);for(var s in i)null==i[s]&&(e[s]=i[s]);return e}function r(t){return function(){var e=this.element.val();t.apply(this,arguments),this._refresh(),e!==this.element.val()&&this._trigger("change")}}t.ui=t.ui||{},t.ui.version="1.12.1";var h=0,l=Array.prototype.slice;t.cleanData=function(e){return function(i){var s,n,o;for(o=0;null!=(n=i[o]);o++)try{s=t._data(n,"events"),s&&s.remove&&t(n).triggerHandler("remove")}catch(a){}e(i)}}(t.cleanData),t.widget=function(e,i,s){var n,o,a,r={},h=e.split(".")[0];e=e.split(".")[1];var l=h+"-"+e;return s||(s=i,i=t.Widget),t.isArray(s)&&(s=t.extend.apply(null,[{}].concat(s))),t.expr[":"][l.toLowerCase()]=function(e){return!!t.data(e,l)},t[h]=t[h]||{},n=t[h][e],o=t[h][e]=function(t,e){return this._createWidget?(arguments.length&&this._createWidget(t,e),void 0):new o(t,e)},t.extend(o,n,{version:s.version,_proto:t.extend({},s),_childConstructors:[]}),a=new i,a.options=t.widget.extend({},a.options),t.each(s,function(e,s){return t.isFunction(s)?(r[e]=function(){function t(){return i.prototype[e].apply(this,arguments)}function n(t){return i.prototype[e].apply(this,t)}return function(){var e,i=this._super,o=this._superApply;return this._super=t,this._superApply=n,e=s.apply(this,arguments),this._super=i,this._superApply=o,e}}(),void 0):(r[e]=s,void 0)}),o.prototype=t.widget.extend(a,{widgetEventPrefix:n?a.widgetEventPrefix||e:e},r,{constructor:o,namespace:h,widgetName:e,widgetFullName:l}),n?(t.each(n._childConstructors,function(e,i){var s=i.prototype;t.widget(s.namespace+"."+s.widgetName,o,i._proto)}),delete n._childConstructors):i._childConstructors.push(o),t.widget.bridge(e,o),o},t.widget.extend=function(e){for(var i,s,n=l.call(arguments,1),o=0,a=n.length;a>o;o++)for(i in n[o])s=n[o][i],n[o].hasOwnProperty(i)&&void 0!==s&&(e[i]=t.isPlainObject(s)?t.isPlainObject(e[i])?t.widget.extend({},e[i],s):t.widget.extend({},s):s);return e},t.widget.bridge=function(e,i){var s=i.prototype.widgetFullName||e;t.fn[e]=function(n){var o="string"==typeof n,a=l.call(arguments,1),r=this;return o?this.length||"instance"!==n?this.each(function(){var i,o=t.data(this,s);return"instance"===n?(r=o,!1):o?t.isFunction(o[n])&&"_"!==n.charAt(0)?(i=o[n].apply(o,a),i!==o&&void 0!==i?(r=i&&i.jquery?r.pushStack(i.get()):i,!1):void 0):t.error("no such method '"+n+"' for "+e+" widget instance"):t.error("cannot call methods on "+e+" prior to initialization; "+"attempted to call method '"+n+"'")}):r=void 0:(a.length&&(n=t.widget.extend.apply(null,[n].concat(a))),this.each(function(){var e=t.data(this,s);e?(e.option(n||{}),e._init&&e._init()):t.data(this,s,new i(n,this))})),r}},t.Widget=function(){},t.Widget._childConstructors=[],t.Widget.prototype={widgetName:"widget",widgetEventPrefix:"",defaultElement:"
",options:{classes:{},disabled:!1,create:null},_createWidget:function(e,i){i=t(i||this.defaultElement||this)[0],this.element=t(i),this.uuid=h++,this.eventNamespace="."+this.widgetName+this.uuid,this.bindings=t(),this.hoverable=t(),this.focusable=t(),this.classesElementLookup={},i!==this&&(t.data(i,this.widgetFullName,this),this._on(!0,this.element,{remove:function(t){t.target===i&&this.destroy()}}),this.document=t(i.style?i.ownerDocument:i.document||i),this.window=t(this.document[0].defaultView||this.document[0].parentWindow)),this.options=t.widget.extend({},this.options,this._getCreateOptions(),e),this._create(),this.options.disabled&&this._setOptionDisabled(this.options.disabled),this._trigger("create",null,this._getCreateEventData()),this._init()},_getCreateOptions:function(){return{}},_getCreateEventData:t.noop,_create:t.noop,_init:t.noop,destroy:function(){var e=this;this._destroy(),t.each(this.classesElementLookup,function(t,i){e._removeClass(i,t)}),this.element.off(this.eventNamespace).removeData(this.widgetFullName),this.widget().off(this.eventNamespace).removeAttr("aria-disabled"),this.bindings.off(this.eventNamespace)},_destroy:t.noop,widget:function(){return this.element},option:function(e,i){var s,n,o,a=e;if(0===arguments.length)return t.widget.extend({},this.options);if("string"==typeof e)if(a={},s=e.split("."),e=s.shift(),s.length){for(n=a[e]=t.widget.extend({},this.options[e]),o=0;s.length-1>o;o++)n[s[o]]=n[s[o]]||{},n=n[s[o]];if(e=s.pop(),1===arguments.length)return void 0===n[e]?null:n[e];n[e]=i}else{if(1===arguments.length)return void 0===this.options[e]?null:this.options[e];a[e]=i}return this._setOptions(a),this},_setOptions:function(t){var e;for(e in t)this._setOption(e,t[e]);return this},_setOption:function(t,e){return"classes"===t&&this._setOptionClasses(e),this.options[t]=e,"disabled"===t&&this._setOptionDisabled(e),this},_setOptionClasses:function(e){var i,s,n;for(i in e)n=this.classesElementLookup[i],e[i]!==this.options.classes[i]&&n&&n.length&&(s=t(n.get()),this._removeClass(n,i),s.addClass(this._classes({element:s,keys:i,classes:e,add:!0})))},_setOptionDisabled:function(t){this._toggleClass(this.widget(),this.widgetFullName+"-disabled",null,!!t),t&&(this._removeClass(this.hoverable,null,"ui-state-hover"),this._removeClass(this.focusable,null,"ui-state-focus"))},enable:function(){return this._setOptions({disabled:!1})},disable:function(){return this._setOptions({disabled:!0})},_classes:function(e){function i(i,o){var a,r;for(r=0;i.length>r;r++)a=n.classesElementLookup[i[r]]||t(),a=e.add?t(t.unique(a.get().concat(e.element.get()))):t(a.not(e.element).get()),n.classesElementLookup[i[r]]=a,s.push(i[r]),o&&e.classes[i[r]]&&s.push(e.classes[i[r]])}var s=[],n=this;return e=t.extend({element:this.element,classes:this.options.classes||{}},e),this._on(e.element,{remove:"_untrackClassesElement"}),e.keys&&i(e.keys.match(/\S+/g)||[],!0),e.extra&&i(e.extra.match(/\S+/g)||[]),s.join(" ")},_untrackClassesElement:function(e){var i=this;t.each(i.classesElementLookup,function(s,n){-1!==t.inArray(e.target,n)&&(i.classesElementLookup[s]=t(n.not(e.target).get()))})},_removeClass:function(t,e,i){return this._toggleClass(t,e,i,!1)},_addClass:function(t,e,i){return this._toggleClass(t,e,i,!0)},_toggleClass:function(t,e,i,s){s="boolean"==typeof s?s:i;var n="string"==typeof t||null===t,o={extra:n?e:i,keys:n?t:e,element:n?this.element:t,add:s};return o.element.toggleClass(this._classes(o),s),this},_on:function(e,i,s){var n,o=this;"boolean"!=typeof e&&(s=i,i=e,e=!1),s?(i=n=t(i),this.bindings=this.bindings.add(i)):(s=i,i=this.element,n=this.widget()),t.each(s,function(s,a){function r(){return e||o.options.disabled!==!0&&!t(this).hasClass("ui-state-disabled")?("string"==typeof a?o[a]:a).apply(o,arguments):void 0}"string"!=typeof a&&(r.guid=a.guid=a.guid||r.guid||t.guid++);var h=s.match(/^([\w:-]*)\s*(.*)$/),l=h[1]+o.eventNamespace,c=h[2];c?n.on(l,c,r):i.on(l,r)})},_off:function(e,i){i=(i||"").split(" ").join(this.eventNamespace+" ")+this.eventNamespace,e.off(i).off(i),this.bindings=t(this.bindings.not(e).get()),this.focusable=t(this.focusable.not(e).get()),this.hoverable=t(this.hoverable.not(e).get())},_delay:function(t,e){function i(){return("string"==typeof t?s[t]:t).apply(s,arguments)}var s=this;return setTimeout(i,e||0)},_hoverable:function(e){this.hoverable=this.hoverable.add(e),this._on(e,{mouseenter:function(e){this._addClass(t(e.currentTarget),null,"ui-state-hover")},mouseleave:function(e){this._removeClass(t(e.currentTarget),null,"ui-state-hover")}})},_focusable:function(e){this.focusable=this.focusable.add(e),this._on(e,{focusin:function(e){this._addClass(t(e.currentTarget),null,"ui-state-focus")},focusout:function(e){this._removeClass(t(e.currentTarget),null,"ui-state-focus")}})},_trigger:function(e,i,s){var n,o,a=this.options[e];if(s=s||{},i=t.Event(i),i.type=(e===this.widgetEventPrefix?e:this.widgetEventPrefix+e).toLowerCase(),i.target=this.element[0],o=i.originalEvent)for(n in o)n in i||(i[n]=o[n]);return this.element.trigger(i,s),!(t.isFunction(a)&&a.apply(this.element[0],[i].concat(s))===!1||i.isDefaultPrevented())}},t.each({show:"fadeIn",hide:"fadeOut"},function(e,i){t.Widget.prototype["_"+e]=function(s,n,o){"string"==typeof n&&(n={effect:n});var a,r=n?n===!0||"number"==typeof n?i:n.effect||i:e;n=n||{},"number"==typeof n&&(n={duration:n}),a=!t.isEmptyObject(n),n.complete=o,n.delay&&s.delay(n.delay),a&&t.effects&&t.effects.effect[r]?s[e](n):r!==e&&s[r]?s[r](n.duration,n.easing,o):s.queue(function(i){t(this)[e](),o&&o.call(s[0]),i()})}}),t.widget,function(){function e(t,e,i){return[parseFloat(t[0])*(u.test(t[0])?e/100:1),parseFloat(t[1])*(u.test(t[1])?i/100:1)]}function i(e,i){return parseInt(t.css(e,i),10)||0}function s(e){var i=e[0];return 9===i.nodeType?{width:e.width(),height:e.height(),offset:{top:0,left:0}}:t.isWindow(i)?{width:e.width(),height:e.height(),offset:{top:e.scrollTop(),left:e.scrollLeft()}}:i.preventDefault?{width:0,height:0,offset:{top:i.pageY,left:i.pageX}}:{width:e.outerWidth(),height:e.outerHeight(),offset:e.offset()}}var n,o=Math.max,a=Math.abs,r=/left|center|right/,h=/top|center|bottom/,l=/[\+\-]\d+(\.[\d]+)?%?/,c=/^\w+/,u=/%$/,d=t.fn.position;t.position={scrollbarWidth:function(){if(void 0!==n)return n;var e,i,s=t("
"),o=s.children()[0];return t("body").append(s),e=o.offsetWidth,s.css("overflow","scroll"),i=o.offsetWidth,e===i&&(i=s[0].clientWidth),s.remove(),n=e-i},getScrollInfo:function(e){var i=e.isWindow||e.isDocument?"":e.element.css("overflow-x"),s=e.isWindow||e.isDocument?"":e.element.css("overflow-y"),n="scroll"===i||"auto"===i&&e.widthi?"left":e>0?"right":"center",vertical:0>r?"top":s>0?"bottom":"middle"};l>p&&p>a(e+i)&&(u.horizontal="center"),c>f&&f>a(s+r)&&(u.vertical="middle"),u.important=o(a(e),a(i))>o(a(s),a(r))?"horizontal":"vertical",n.using.call(this,t,u)}),h.offset(t.extend(D,{using:r}))})},t.ui.position={fit:{left:function(t,e){var i,s=e.within,n=s.isWindow?s.scrollLeft:s.offset.left,a=s.width,r=t.left-e.collisionPosition.marginLeft,h=n-r,l=r+e.collisionWidth-a-n;e.collisionWidth>a?h>0&&0>=l?(i=t.left+h+e.collisionWidth-a-n,t.left+=h-i):t.left=l>0&&0>=h?n:h>l?n+a-e.collisionWidth:n:h>0?t.left+=h:l>0?t.left-=l:t.left=o(t.left-r,t.left)},top:function(t,e){var i,s=e.within,n=s.isWindow?s.scrollTop:s.offset.top,a=e.within.height,r=t.top-e.collisionPosition.marginTop,h=n-r,l=r+e.collisionHeight-a-n;e.collisionHeight>a?h>0&&0>=l?(i=t.top+h+e.collisionHeight-a-n,t.top+=h-i):t.top=l>0&&0>=h?n:h>l?n+a-e.collisionHeight:n:h>0?t.top+=h:l>0?t.top-=l:t.top=o(t.top-r,t.top)}},flip:{left:function(t,e){var i,s,n=e.within,o=n.offset.left+n.scrollLeft,r=n.width,h=n.isWindow?n.scrollLeft:n.offset.left,l=t.left-e.collisionPosition.marginLeft,c=l-h,u=l+e.collisionWidth-r-h,d="left"===e.my[0]?-e.elemWidth:"right"===e.my[0]?e.elemWidth:0,p="left"===e.at[0]?e.targetWidth:"right"===e.at[0]?-e.targetWidth:0,f=-2*e.offset[0];0>c?(i=t.left+d+p+f+e.collisionWidth-r-o,(0>i||a(c)>i)&&(t.left+=d+p+f)):u>0&&(s=t.left-e.collisionPosition.marginLeft+d+p+f-h,(s>0||u>a(s))&&(t.left+=d+p+f))},top:function(t,e){var i,s,n=e.within,o=n.offset.top+n.scrollTop,r=n.height,h=n.isWindow?n.scrollTop:n.offset.top,l=t.top-e.collisionPosition.marginTop,c=l-h,u=l+e.collisionHeight-r-h,d="top"===e.my[1],p=d?-e.elemHeight:"bottom"===e.my[1]?e.elemHeight:0,f="top"===e.at[1]?e.targetHeight:"bottom"===e.at[1]?-e.targetHeight:0,g=-2*e.offset[1];0>c?(s=t.top+p+f+g+e.collisionHeight-r-o,(0>s||a(c)>s)&&(t.top+=p+f+g)):u>0&&(i=t.top-e.collisionPosition.marginTop+p+f+g-h,(i>0||u>a(i))&&(t.top+=p+f+g))}},flipfit:{left:function(){t.ui.position.flip.left.apply(this,arguments),t.ui.position.fit.left.apply(this,arguments)},top:function(){t.ui.position.flip.top.apply(this,arguments),t.ui.position.fit.top.apply(this,arguments)}}}}(),t.ui.position,t.extend(t.expr[":"],{data:t.expr.createPseudo?t.expr.createPseudo(function(e){return function(i){return!!t.data(i,e)}}):function(e,i,s){return!!t.data(e,s[3])}}),t.fn.extend({disableSelection:function(){var t="onselectstart"in document.createElement("div")?"selectstart":"mousedown";return function(){return this.on(t+".ui-disableSelection",function(t){t.preventDefault()})}}(),enableSelection:function(){return this.off(".ui-disableSelection")}});var c="ui-effects-",u="ui-effects-style",d="ui-effects-animated",p=t;t.effects={effect:{}},function(t,e){function i(t,e,i){var s=u[e.type]||{};return null==t?i||!e.def?null:e.def:(t=s.floor?~~t:parseFloat(t),isNaN(t)?e.def:s.mod?(t+s.mod)%s.mod:0>t?0:t>s.max?s.max:t)}function s(i){var s=l(),n=s._rgba=[];return i=i.toLowerCase(),f(h,function(t,o){var a,r=o.re.exec(i),h=r&&o.parse(r),l=o.space||"rgba";return h?(a=s[l](h),s[c[l].cache]=a[c[l].cache],n=s._rgba=a._rgba,!1):e}),n.length?("0,0,0,0"===n.join()&&t.extend(n,o.transparent),s):o[i]}function n(t,e,i){return i=(i+1)%1,1>6*i?t+6*(e-t)*i:1>2*i?e:2>3*i?t+6*(e-t)*(2/3-i):t}var o,a="backgroundColor borderBottomColor borderLeftColor borderRightColor borderTopColor color columnRuleColor outlineColor textDecorationColor textEmphasisColor",r=/^([\-+])=\s*(\d+\.?\d*)/,h=[{re:/rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,parse:function(t){return[t[1],t[2],t[3],t[4]]}},{re:/rgba?\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,parse:function(t){return[2.55*t[1],2.55*t[2],2.55*t[3],t[4]]}},{re:/#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})/,parse:function(t){return[parseInt(t[1],16),parseInt(t[2],16),parseInt(t[3],16)]}},{re:/#([a-f0-9])([a-f0-9])([a-f0-9])/,parse:function(t){return[parseInt(t[1]+t[1],16),parseInt(t[2]+t[2],16),parseInt(t[3]+t[3],16)]}},{re:/hsla?\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,space:"hsla",parse:function(t){return[t[1],t[2]/100,t[3]/100,t[4]]}}],l=t.Color=function(e,i,s,n){return new t.Color.fn.parse(e,i,s,n)},c={rgba:{props:{red:{idx:0,type:"byte"},green:{idx:1,type:"byte"},blue:{idx:2,type:"byte"}}},hsla:{props:{hue:{idx:0,type:"degrees"},saturation:{idx:1,type:"percent"},lightness:{idx:2,type:"percent"}}}},u={"byte":{floor:!0,max:255},percent:{max:1},degrees:{mod:360,floor:!0}},d=l.support={},p=t("

")[0],f=t.each;p.style.cssText="background-color:rgba(1,1,1,.5)",d.rgba=p.style.backgroundColor.indexOf("rgba")>-1,f(c,function(t,e){e.cache="_"+t,e.props.alpha={idx:3,type:"percent",def:1}}),l.fn=t.extend(l.prototype,{parse:function(n,a,r,h){if(n===e)return this._rgba=[null,null,null,null],this;(n.jquery||n.nodeType)&&(n=t(n).css(a),a=e);var u=this,d=t.type(n),p=this._rgba=[];return a!==e&&(n=[n,a,r,h],d="array"),"string"===d?this.parse(s(n)||o._default):"array"===d?(f(c.rgba.props,function(t,e){p[e.idx]=i(n[e.idx],e)}),this):"object"===d?(n instanceof l?f(c,function(t,e){n[e.cache]&&(u[e.cache]=n[e.cache].slice())}):f(c,function(e,s){var o=s.cache;f(s.props,function(t,e){if(!u[o]&&s.to){if("alpha"===t||null==n[t])return;u[o]=s.to(u._rgba)}u[o][e.idx]=i(n[t],e,!0)}),u[o]&&0>t.inArray(null,u[o].slice(0,3))&&(u[o][3]=1,s.from&&(u._rgba=s.from(u[o])))}),this):e},is:function(t){var i=l(t),s=!0,n=this;return f(c,function(t,o){var a,r=i[o.cache];return r&&(a=n[o.cache]||o.to&&o.to(n._rgba)||[],f(o.props,function(t,i){return null!=r[i.idx]?s=r[i.idx]===a[i.idx]:e})),s}),s},_space:function(){var t=[],e=this;return f(c,function(i,s){e[s.cache]&&t.push(i)}),t.pop()},transition:function(t,e){var s=l(t),n=s._space(),o=c[n],a=0===this.alpha()?l("transparent"):this,r=a[o.cache]||o.to(a._rgba),h=r.slice();return s=s[o.cache],f(o.props,function(t,n){var o=n.idx,a=r[o],l=s[o],c=u[n.type]||{};null!==l&&(null===a?h[o]=l:(c.mod&&(l-a>c.mod/2?a+=c.mod:a-l>c.mod/2&&(a-=c.mod)),h[o]=i((l-a)*e+a,n)))}),this[n](h)},blend:function(e){if(1===this._rgba[3])return this;var i=this._rgba.slice(),s=i.pop(),n=l(e)._rgba;return l(t.map(i,function(t,e){return(1-s)*n[e]+s*t}))},toRgbaString:function(){var e="rgba(",i=t.map(this._rgba,function(t,e){return null==t?e>2?1:0:t});return 1===i[3]&&(i.pop(),e="rgb("),e+i.join()+")"},toHslaString:function(){var e="hsla(",i=t.map(this.hsla(),function(t,e){return null==t&&(t=e>2?1:0),e&&3>e&&(t=Math.round(100*t)+"%"),t});return 1===i[3]&&(i.pop(),e="hsl("),e+i.join()+")"},toHexString:function(e){var i=this._rgba.slice(),s=i.pop();return e&&i.push(~~(255*s)),"#"+t.map(i,function(t){return t=(t||0).toString(16),1===t.length?"0"+t:t}).join("")},toString:function(){return 0===this._rgba[3]?"transparent":this.toRgbaString()}}),l.fn.parse.prototype=l.fn,c.hsla.to=function(t){if(null==t[0]||null==t[1]||null==t[2])return[null,null,null,t[3]];var e,i,s=t[0]/255,n=t[1]/255,o=t[2]/255,a=t[3],r=Math.max(s,n,o),h=Math.min(s,n,o),l=r-h,c=r+h,u=.5*c;return e=h===r?0:s===r?60*(n-o)/l+360:n===r?60*(o-s)/l+120:60*(s-n)/l+240,i=0===l?0:.5>=u?l/c:l/(2-c),[Math.round(e)%360,i,u,null==a?1:a]},c.hsla.from=function(t){if(null==t[0]||null==t[1]||null==t[2])return[null,null,null,t[3]];var e=t[0]/360,i=t[1],s=t[2],o=t[3],a=.5>=s?s*(1+i):s+i-s*i,r=2*s-a;return[Math.round(255*n(r,a,e+1/3)),Math.round(255*n(r,a,e)),Math.round(255*n(r,a,e-1/3)),o]},f(c,function(s,n){var o=n.props,a=n.cache,h=n.to,c=n.from;l.fn[s]=function(s){if(h&&!this[a]&&(this[a]=h(this._rgba)),s===e)return this[a].slice();var n,r=t.type(s),u="array"===r||"object"===r?s:arguments,d=this[a].slice();return f(o,function(t,e){var s=u["object"===r?t:e.idx];null==s&&(s=d[e.idx]),d[e.idx]=i(s,e)}),c?(n=l(c(d)),n[a]=d,n):l(d)},f(o,function(e,i){l.fn[e]||(l.fn[e]=function(n){var o,a=t.type(n),h="alpha"===e?this._hsla?"hsla":"rgba":s,l=this[h](),c=l[i.idx];return"undefined"===a?c:("function"===a&&(n=n.call(this,c),a=t.type(n)),null==n&&i.empty?this:("string"===a&&(o=r.exec(n),o&&(n=c+parseFloat(o[2])*("+"===o[1]?1:-1))),l[i.idx]=n,this[h](l)))})})}),l.hook=function(e){var i=e.split(" ");f(i,function(e,i){t.cssHooks[i]={set:function(e,n){var o,a,r="";if("transparent"!==n&&("string"!==t.type(n)||(o=s(n)))){if(n=l(o||n),!d.rgba&&1!==n._rgba[3]){for(a="backgroundColor"===i?e.parentNode:e;(""===r||"transparent"===r)&&a&&a.style;)try{r=t.css(a,"backgroundColor"),a=a.parentNode}catch(h){}n=n.blend(r&&"transparent"!==r?r:"_default")}n=n.toRgbaString()}try{e.style[i]=n}catch(h){}}},t.fx.step[i]=function(e){e.colorInit||(e.start=l(e.elem,i),e.end=l(e.end),e.colorInit=!0),t.cssHooks[i].set(e.elem,e.start.transition(e.end,e.pos))}})},l.hook(a),t.cssHooks.borderColor={expand:function(t){var e={};return f(["Top","Right","Bottom","Left"],function(i,s){e["border"+s+"Color"]=t}),e}},o=t.Color.names={aqua:"#00ffff",black:"#000000",blue:"#0000ff",fuchsia:"#ff00ff",gray:"#808080",green:"#008000",lime:"#00ff00",maroon:"#800000",navy:"#000080",olive:"#808000",purple:"#800080",red:"#ff0000",silver:"#c0c0c0",teal:"#008080",white:"#ffffff",yellow:"#ffff00",transparent:[null,null,null,0],_default:"#ffffff"}}(p),function(){function e(e){var i,s,n=e.ownerDocument.defaultView?e.ownerDocument.defaultView.getComputedStyle(e,null):e.currentStyle,o={};if(n&&n.length&&n[0]&&n[n[0]])for(s=n.length;s--;)i=n[s],"string"==typeof n[i]&&(o[t.camelCase(i)]=n[i]);else for(i in n)"string"==typeof n[i]&&(o[i]=n[i]);return o}function i(e,i){var s,o,a={};for(s in i)o=i[s],e[s]!==o&&(n[s]||(t.fx.step[s]||!isNaN(parseFloat(o)))&&(a[s]=o));return a}var s=["add","remove","toggle"],n={border:1,borderBottom:1,borderColor:1,borderLeft:1,borderRight:1,borderTop:1,borderWidth:1,margin:1,padding:1};t.each(["borderLeftStyle","borderRightStyle","borderBottomStyle","borderTopStyle"],function(e,i){t.fx.step[i]=function(t){("none"!==t.end&&!t.setAttr||1===t.pos&&!t.setAttr)&&(p.style(t.elem,i,t.end),t.setAttr=!0)}}),t.fn.addBack||(t.fn.addBack=function(t){return this.add(null==t?this.prevObject:this.prevObject.filter(t))}),t.effects.animateClass=function(n,o,a,r){var h=t.speed(o,a,r);return this.queue(function(){var o,a=t(this),r=a.attr("class")||"",l=h.children?a.find("*").addBack():a;l=l.map(function(){var i=t(this);return{el:i,start:e(this)}}),o=function(){t.each(s,function(t,e){n[e]&&a[e+"Class"](n[e])})},o(),l=l.map(function(){return this.end=e(this.el[0]),this.diff=i(this.start,this.end),this}),a.attr("class",r),l=l.map(function(){var e=this,i=t.Deferred(),s=t.extend({},h,{queue:!1,complete:function(){i.resolve(e)}});return this.el.animate(this.diff,s),i.promise()}),t.when.apply(t,l.get()).done(function(){o(),t.each(arguments,function(){var e=this.el;t.each(this.diff,function(t){e.css(t,"")})}),h.complete.call(a[0])})})},t.fn.extend({addClass:function(e){return function(i,s,n,o){return s?t.effects.animateClass.call(this,{add:i},s,n,o):e.apply(this,arguments)}}(t.fn.addClass),removeClass:function(e){return function(i,s,n,o){return arguments.length>1?t.effects.animateClass.call(this,{remove:i},s,n,o):e.apply(this,arguments)}}(t.fn.removeClass),toggleClass:function(e){return function(i,s,n,o,a){return"boolean"==typeof s||void 0===s?n?t.effects.animateClass.call(this,s?{add:i}:{remove:i},n,o,a):e.apply(this,arguments):t.effects.animateClass.call(this,{toggle:i},s,n,o)}}(t.fn.toggleClass),switchClass:function(e,i,s,n,o){return t.effects.animateClass.call(this,{add:i,remove:e},s,n,o)}})}(),function(){function e(e,i,s,n){return t.isPlainObject(e)&&(i=e,e=e.effect),e={effect:e},null==i&&(i={}),t.isFunction(i)&&(n=i,s=null,i={}),("number"==typeof i||t.fx.speeds[i])&&(n=s,s=i,i={}),t.isFunction(s)&&(n=s,s=null),i&&t.extend(e,i),s=s||i.duration,e.duration=t.fx.off?0:"number"==typeof s?s:s in t.fx.speeds?t.fx.speeds[s]:t.fx.speeds._default,e.complete=n||i.complete,e}function i(e){return!e||"number"==typeof e||t.fx.speeds[e]?!0:"string"!=typeof e||t.effects.effect[e]?t.isFunction(e)?!0:"object"!=typeof e||e.effect?!1:!0:!0}function s(t,e){var i=e.outerWidth(),s=e.outerHeight(),n=/^rect\((-?\d*\.?\d*px|-?\d+%|auto),?\s*(-?\d*\.?\d*px|-?\d+%|auto),?\s*(-?\d*\.?\d*px|-?\d+%|auto),?\s*(-?\d*\.?\d*px|-?\d+%|auto)\)$/,o=n.exec(t)||["",0,i,s,0];return{top:parseFloat(o[1])||0,right:"auto"===o[2]?i:parseFloat(o[2]),bottom:"auto"===o[3]?s:parseFloat(o[3]),left:parseFloat(o[4])||0}}t.expr&&t.expr.filters&&t.expr.filters.animated&&(t.expr.filters.animated=function(e){return function(i){return!!t(i).data(d)||e(i)}}(t.expr.filters.animated)),t.uiBackCompat!==!1&&t.extend(t.effects,{save:function(t,e){for(var i=0,s=e.length;s>i;i++)null!==e[i]&&t.data(c+e[i],t[0].style[e[i]])},restore:function(t,e){for(var i,s=0,n=e.length;n>s;s++)null!==e[s]&&(i=t.data(c+e[s]),t.css(e[s],i))},setMode:function(t,e){return"toggle"===e&&(e=t.is(":hidden")?"show":"hide"),e},createWrapper:function(e){if(e.parent().is(".ui-effects-wrapper"))return e.parent();var i={width:e.outerWidth(!0),height:e.outerHeight(!0),"float":e.css("float")},s=t("

").addClass("ui-effects-wrapper").css({fontSize:"100%",background:"transparent",border:"none",margin:0,padding:0}),n={width:e.width(),height:e.height()},o=document.activeElement;try{o.id}catch(a){o=document.body}return e.wrap(s),(e[0]===o||t.contains(e[0],o))&&t(o).trigger("focus"),s=e.parent(),"static"===e.css("position")?(s.css({position:"relative"}),e.css({position:"relative"})):(t.extend(i,{position:e.css("position"),zIndex:e.css("z-index")}),t.each(["top","left","bottom","right"],function(t,s){i[s]=e.css(s),isNaN(parseInt(i[s],10))&&(i[s]="auto")}),e.css({position:"relative",top:0,left:0,right:"auto",bottom:"auto"})),e.css(n),s.css(i).show()},removeWrapper:function(e){var i=document.activeElement;return e.parent().is(".ui-effects-wrapper")&&(e.parent().replaceWith(e),(e[0]===i||t.contains(e[0],i))&&t(i).trigger("focus")),e}}),t.extend(t.effects,{version:"1.12.1",define:function(e,i,s){return s||(s=i,i="effect"),t.effects.effect[e]=s,t.effects.effect[e].mode=i,s},scaledDimensions:function(t,e,i){if(0===e)return{height:0,width:0,outerHeight:0,outerWidth:0};var s="horizontal"!==i?(e||100)/100:1,n="vertical"!==i?(e||100)/100:1;return{height:t.height()*n,width:t.width()*s,outerHeight:t.outerHeight()*n,outerWidth:t.outerWidth()*s}},clipToBox:function(t){return{width:t.clip.right-t.clip.left,height:t.clip.bottom-t.clip.top,left:t.clip.left,top:t.clip.top}},unshift:function(t,e,i){var s=t.queue();e>1&&s.splice.apply(s,[1,0].concat(s.splice(e,i))),t.dequeue()},saveStyle:function(t){t.data(u,t[0].style.cssText)},restoreStyle:function(t){t[0].style.cssText=t.data(u)||"",t.removeData(u)},mode:function(t,e){var i=t.is(":hidden");return"toggle"===e&&(e=i?"show":"hide"),(i?"hide"===e:"show"===e)&&(e="none"),e},getBaseline:function(t,e){var i,s;switch(t[0]){case"top":i=0;break;case"middle":i=.5;break;case"bottom":i=1;break;default:i=t[0]/e.height}switch(t[1]){case"left":s=0;break;case"center":s=.5;break;case"right":s=1;break;default:s=t[1]/e.width}return{x:s,y:i}},createPlaceholder:function(e){var i,s=e.css("position"),n=e.position();return e.css({marginTop:e.css("marginTop"),marginBottom:e.css("marginBottom"),marginLeft:e.css("marginLeft"),marginRight:e.css("marginRight")}).outerWidth(e.outerWidth()).outerHeight(e.outerHeight()),/^(static|relative)/.test(s)&&(s="absolute",i=t("<"+e[0].nodeName+">").insertAfter(e).css({display:/^(inline|ruby)/.test(e.css("display"))?"inline-block":"block",visibility:"hidden",marginTop:e.css("marginTop"),marginBottom:e.css("marginBottom"),marginLeft:e.css("marginLeft"),marginRight:e.css("marginRight"),"float":e.css("float")}).outerWidth(e.outerWidth()).outerHeight(e.outerHeight()).addClass("ui-effects-placeholder"),e.data(c+"placeholder",i)),e.css({position:s,left:n.left,top:n.top}),i},removePlaceholder:function(t){var e=c+"placeholder",i=t.data(e);i&&(i.remove(),t.removeData(e))},cleanUp:function(e){t.effects.restoreStyle(e),t.effects.removePlaceholder(e)},setTransition:function(e,i,s,n){return n=n||{},t.each(i,function(t,i){var o=e.cssUnit(i);o[0]>0&&(n[i]=o[0]*s+o[1])}),n}}),t.fn.extend({effect:function(){function i(e){function i(){r.removeData(d),t.effects.cleanUp(r),"hide"===s.mode&&r.hide(),a()}function a(){t.isFunction(h)&&h.call(r[0]),t.isFunction(e)&&e()}var r=t(this);s.mode=c.shift(),t.uiBackCompat===!1||o?"none"===s.mode?(r[l](),a()):n.call(r[0],s,i):(r.is(":hidden")?"hide"===l:"show"===l)?(r[l](),a()):n.call(r[0],s,a)}var s=e.apply(this,arguments),n=t.effects.effect[s.effect],o=n.mode,a=s.queue,r=a||"fx",h=s.complete,l=s.mode,c=[],u=function(e){var i=t(this),s=t.effects.mode(i,l)||o;i.data(d,!0),c.push(s),o&&("show"===s||s===o&&"hide"===s)&&i.show(),o&&"none"===s||t.effects.saveStyle(i),t.isFunction(e)&&e()};return t.fx.off||!n?l?this[l](s.duration,h):this.each(function(){h&&h.call(this)}):a===!1?this.each(u).each(i):this.queue(r,u).queue(r,i)},show:function(t){return function(s){if(i(s))return t.apply(this,arguments);var n=e.apply(this,arguments);return n.mode="show",this.effect.call(this,n) -}}(t.fn.show),hide:function(t){return function(s){if(i(s))return t.apply(this,arguments);var n=e.apply(this,arguments);return n.mode="hide",this.effect.call(this,n)}}(t.fn.hide),toggle:function(t){return function(s){if(i(s)||"boolean"==typeof s)return t.apply(this,arguments);var n=e.apply(this,arguments);return n.mode="toggle",this.effect.call(this,n)}}(t.fn.toggle),cssUnit:function(e){var i=this.css(e),s=[];return t.each(["em","px","%","pt"],function(t,e){i.indexOf(e)>0&&(s=[parseFloat(i),e])}),s},cssClip:function(t){return t?this.css("clip","rect("+t.top+"px "+t.right+"px "+t.bottom+"px "+t.left+"px)"):s(this.css("clip"),this)},transfer:function(e,i){var s=t(this),n=t(e.to),o="fixed"===n.css("position"),a=t("body"),r=o?a.scrollTop():0,h=o?a.scrollLeft():0,l=n.offset(),c={top:l.top-r,left:l.left-h,height:n.innerHeight(),width:n.innerWidth()},u=s.offset(),d=t("
").appendTo("body").addClass(e.className).css({top:u.top-r,left:u.left-h,height:s.innerHeight(),width:s.innerWidth(),position:o?"fixed":"absolute"}).animate(c,e.duration,e.easing,function(){d.remove(),t.isFunction(i)&&i()})}}),t.fx.step.clip=function(e){e.clipInit||(e.start=t(e.elem).cssClip(),"string"==typeof e.end&&(e.end=s(e.end,e.elem)),e.clipInit=!0),t(e.elem).cssClip({top:e.pos*(e.end.top-e.start.top)+e.start.top,right:e.pos*(e.end.right-e.start.right)+e.start.right,bottom:e.pos*(e.end.bottom-e.start.bottom)+e.start.bottom,left:e.pos*(e.end.left-e.start.left)+e.start.left})}}(),function(){var e={};t.each(["Quad","Cubic","Quart","Quint","Expo"],function(t,i){e[i]=function(e){return Math.pow(e,t+2)}}),t.extend(e,{Sine:function(t){return 1-Math.cos(t*Math.PI/2)},Circ:function(t){return 1-Math.sqrt(1-t*t)},Elastic:function(t){return 0===t||1===t?t:-Math.pow(2,8*(t-1))*Math.sin((80*(t-1)-7.5)*Math.PI/15)},Back:function(t){return t*t*(3*t-2)},Bounce:function(t){for(var e,i=4;((e=Math.pow(2,--i))-1)/11>t;);return 1/Math.pow(4,3-i)-7.5625*Math.pow((3*e-2)/22-t,2)}}),t.each(e,function(e,i){t.easing["easeIn"+e]=i,t.easing["easeOut"+e]=function(t){return 1-i(1-t)},t.easing["easeInOut"+e]=function(t){return.5>t?i(2*t)/2:1-i(-2*t+2)/2}})}();var f=t.effects;t.effects.define("blind","hide",function(e,i){var s={up:["bottom","top"],vertical:["bottom","top"],down:["top","bottom"],left:["right","left"],horizontal:["right","left"],right:["left","right"]},n=t(this),o=e.direction||"up",a=n.cssClip(),r={clip:t.extend({},a)},h=t.effects.createPlaceholder(n);r.clip[s[o][0]]=r.clip[s[o][1]],"show"===e.mode&&(n.cssClip(r.clip),h&&h.css(t.effects.clipToBox(r)),r.clip=a),h&&h.animate(t.effects.clipToBox(r),e.duration,e.easing),n.animate(r,{queue:!1,duration:e.duration,easing:e.easing,complete:i})}),t.effects.define("bounce",function(e,i){var s,n,o,a=t(this),r=e.mode,h="hide"===r,l="show"===r,c=e.direction||"up",u=e.distance,d=e.times||5,p=2*d+(l||h?1:0),f=e.duration/p,g=e.easing,m="up"===c||"down"===c?"top":"left",_="up"===c||"left"===c,v=0,b=a.queue().length;for(t.effects.createPlaceholder(a),o=a.css(m),u||(u=a["top"===m?"outerHeight":"outerWidth"]()/3),l&&(n={opacity:1},n[m]=o,a.css("opacity",0).css(m,_?2*-u:2*u).animate(n,f,g)),h&&(u/=Math.pow(2,d-1)),n={},n[m]=o;d>v;v++)s={},s[m]=(_?"-=":"+=")+u,a.animate(s,f,g).animate(n,f,g),u=h?2*u:u/2;h&&(s={opacity:0},s[m]=(_?"-=":"+=")+u,a.animate(s,f,g)),a.queue(i),t.effects.unshift(a,b,p+1)}),t.effects.define("clip","hide",function(e,i){var s,n={},o=t(this),a=e.direction||"vertical",r="both"===a,h=r||"horizontal"===a,l=r||"vertical"===a;s=o.cssClip(),n.clip={top:l?(s.bottom-s.top)/2:s.top,right:h?(s.right-s.left)/2:s.right,bottom:l?(s.bottom-s.top)/2:s.bottom,left:h?(s.right-s.left)/2:s.left},t.effects.createPlaceholder(o),"show"===e.mode&&(o.cssClip(n.clip),n.clip=s),o.animate(n,{queue:!1,duration:e.duration,easing:e.easing,complete:i})}),t.effects.define("drop","hide",function(e,i){var s,n=t(this),o=e.mode,a="show"===o,r=e.direction||"left",h="up"===r||"down"===r?"top":"left",l="up"===r||"left"===r?"-=":"+=",c="+="===l?"-=":"+=",u={opacity:0};t.effects.createPlaceholder(n),s=e.distance||n["top"===h?"outerHeight":"outerWidth"](!0)/2,u[h]=l+s,a&&(n.css(u),u[h]=c+s,u.opacity=1),n.animate(u,{queue:!1,duration:e.duration,easing:e.easing,complete:i})}),t.effects.define("explode","hide",function(e,i){function s(){b.push(this),b.length===u*d&&n()}function n(){p.css({visibility:"visible"}),t(b).remove(),i()}var o,a,r,h,l,c,u=e.pieces?Math.round(Math.sqrt(e.pieces)):3,d=u,p=t(this),f=e.mode,g="show"===f,m=p.show().css("visibility","hidden").offset(),_=Math.ceil(p.outerWidth()/d),v=Math.ceil(p.outerHeight()/u),b=[];for(o=0;u>o;o++)for(h=m.top+o*v,c=o-(u-1)/2,a=0;d>a;a++)r=m.left+a*_,l=a-(d-1)/2,p.clone().appendTo("body").wrap("
").css({position:"absolute",visibility:"visible",left:-a*_,top:-o*v}).parent().addClass("ui-effects-explode").css({position:"absolute",overflow:"hidden",width:_,height:v,left:r+(g?l*_:0),top:h+(g?c*v:0),opacity:g?0:1}).animate({left:r+(g?0:l*_),top:h+(g?0:c*v),opacity:g?1:0},e.duration||500,e.easing,s)}),t.effects.define("fade","toggle",function(e,i){var s="show"===e.mode;t(this).css("opacity",s?0:1).animate({opacity:s?1:0},{queue:!1,duration:e.duration,easing:e.easing,complete:i})}),t.effects.define("fold","hide",function(e,i){var s=t(this),n=e.mode,o="show"===n,a="hide"===n,r=e.size||15,h=/([0-9]+)%/.exec(r),l=!!e.horizFirst,c=l?["right","bottom"]:["bottom","right"],u=e.duration/2,d=t.effects.createPlaceholder(s),p=s.cssClip(),f={clip:t.extend({},p)},g={clip:t.extend({},p)},m=[p[c[0]],p[c[1]]],_=s.queue().length;h&&(r=parseInt(h[1],10)/100*m[a?0:1]),f.clip[c[0]]=r,g.clip[c[0]]=r,g.clip[c[1]]=0,o&&(s.cssClip(g.clip),d&&d.css(t.effects.clipToBox(g)),g.clip=p),s.queue(function(i){d&&d.animate(t.effects.clipToBox(f),u,e.easing).animate(t.effects.clipToBox(g),u,e.easing),i()}).animate(f,u,e.easing).animate(g,u,e.easing).queue(i),t.effects.unshift(s,_,4)}),t.effects.define("highlight","show",function(e,i){var s=t(this),n={backgroundColor:s.css("backgroundColor")};"hide"===e.mode&&(n.opacity=0),t.effects.saveStyle(s),s.css({backgroundImage:"none",backgroundColor:e.color||"#ffff99"}).animate(n,{queue:!1,duration:e.duration,easing:e.easing,complete:i})}),t.effects.define("size",function(e,i){var s,n,o,a=t(this),r=["fontSize"],h=["borderTopWidth","borderBottomWidth","paddingTop","paddingBottom"],l=["borderLeftWidth","borderRightWidth","paddingLeft","paddingRight"],c=e.mode,u="effect"!==c,d=e.scale||"both",p=e.origin||["middle","center"],f=a.css("position"),g=a.position(),m=t.effects.scaledDimensions(a),_=e.from||m,v=e.to||t.effects.scaledDimensions(a,0);t.effects.createPlaceholder(a),"show"===c&&(o=_,_=v,v=o),n={from:{y:_.height/m.height,x:_.width/m.width},to:{y:v.height/m.height,x:v.width/m.width}},("box"===d||"both"===d)&&(n.from.y!==n.to.y&&(_=t.effects.setTransition(a,h,n.from.y,_),v=t.effects.setTransition(a,h,n.to.y,v)),n.from.x!==n.to.x&&(_=t.effects.setTransition(a,l,n.from.x,_),v=t.effects.setTransition(a,l,n.to.x,v))),("content"===d||"both"===d)&&n.from.y!==n.to.y&&(_=t.effects.setTransition(a,r,n.from.y,_),v=t.effects.setTransition(a,r,n.to.y,v)),p&&(s=t.effects.getBaseline(p,m),_.top=(m.outerHeight-_.outerHeight)*s.y+g.top,_.left=(m.outerWidth-_.outerWidth)*s.x+g.left,v.top=(m.outerHeight-v.outerHeight)*s.y+g.top,v.left=(m.outerWidth-v.outerWidth)*s.x+g.left),a.css(_),("content"===d||"both"===d)&&(h=h.concat(["marginTop","marginBottom"]).concat(r),l=l.concat(["marginLeft","marginRight"]),a.find("*[width]").each(function(){var i=t(this),s=t.effects.scaledDimensions(i),o={height:s.height*n.from.y,width:s.width*n.from.x,outerHeight:s.outerHeight*n.from.y,outerWidth:s.outerWidth*n.from.x},a={height:s.height*n.to.y,width:s.width*n.to.x,outerHeight:s.height*n.to.y,outerWidth:s.width*n.to.x};n.from.y!==n.to.y&&(o=t.effects.setTransition(i,h,n.from.y,o),a=t.effects.setTransition(i,h,n.to.y,a)),n.from.x!==n.to.x&&(o=t.effects.setTransition(i,l,n.from.x,o),a=t.effects.setTransition(i,l,n.to.x,a)),u&&t.effects.saveStyle(i),i.css(o),i.animate(a,e.duration,e.easing,function(){u&&t.effects.restoreStyle(i)})})),a.animate(v,{queue:!1,duration:e.duration,easing:e.easing,complete:function(){var e=a.offset();0===v.opacity&&a.css("opacity",_.opacity),u||(a.css("position","static"===f?"relative":f).offset(e),t.effects.saveStyle(a)),i()}})}),t.effects.define("scale",function(e,i){var s=t(this),n=e.mode,o=parseInt(e.percent,10)||(0===parseInt(e.percent,10)?0:"effect"!==n?0:100),a=t.extend(!0,{from:t.effects.scaledDimensions(s),to:t.effects.scaledDimensions(s,o,e.direction||"both"),origin:e.origin||["middle","center"]},e);e.fade&&(a.from.opacity=1,a.to.opacity=0),t.effects.effect.size.call(this,a,i)}),t.effects.define("puff","hide",function(e,i){var s=t.extend(!0,{},e,{fade:!0,percent:parseInt(e.percent,10)||150});t.effects.effect.scale.call(this,s,i)}),t.effects.define("pulsate","show",function(e,i){var s=t(this),n=e.mode,o="show"===n,a="hide"===n,r=o||a,h=2*(e.times||5)+(r?1:0),l=e.duration/h,c=0,u=1,d=s.queue().length;for((o||!s.is(":visible"))&&(s.css("opacity",0).show(),c=1);h>u;u++)s.animate({opacity:c},l,e.easing),c=1-c;s.animate({opacity:c},l,e.easing),s.queue(i),t.effects.unshift(s,d,h+1)}),t.effects.define("shake",function(e,i){var s=1,n=t(this),o=e.direction||"left",a=e.distance||20,r=e.times||3,h=2*r+1,l=Math.round(e.duration/h),c="up"===o||"down"===o?"top":"left",u="up"===o||"left"===o,d={},p={},f={},g=n.queue().length;for(t.effects.createPlaceholder(n),d[c]=(u?"-=":"+=")+a,p[c]=(u?"+=":"-=")+2*a,f[c]=(u?"-=":"+=")+2*a,n.animate(d,l,e.easing);r>s;s++)n.animate(p,l,e.easing).animate(f,l,e.easing);n.animate(p,l,e.easing).animate(d,l/2,e.easing).queue(i),t.effects.unshift(n,g,h+1)}),t.effects.define("slide","show",function(e,i){var s,n,o=t(this),a={up:["bottom","top"],down:["top","bottom"],left:["right","left"],right:["left","right"]},r=e.mode,h=e.direction||"left",l="up"===h||"down"===h?"top":"left",c="up"===h||"left"===h,u=e.distance||o["top"===l?"outerHeight":"outerWidth"](!0),d={};t.effects.createPlaceholder(o),s=o.cssClip(),n=o.position()[l],d[l]=(c?-1:1)*u+n,d.clip=o.cssClip(),d.clip[a[h][1]]=d.clip[a[h][0]],"show"===r&&(o.cssClip(d.clip),o.css(l,d[l]),d.clip=s,d[l]=n),o.animate(d,{queue:!1,duration:e.duration,easing:e.easing,complete:i})});var f;t.uiBackCompat!==!1&&(f=t.effects.define("transfer",function(e,i){t(this).transfer(e,i)})),t.ui.focusable=function(i,s){var n,o,a,r,h,l=i.nodeName.toLowerCase();return"area"===l?(n=i.parentNode,o=n.name,i.href&&o&&"map"===n.nodeName.toLowerCase()?(a=t("img[usemap='#"+o+"']"),a.length>0&&a.is(":visible")):!1):(/^(input|select|textarea|button|object)$/.test(l)?(r=!i.disabled,r&&(h=t(i).closest("fieldset")[0],h&&(r=!h.disabled))):r="a"===l?i.href||s:s,r&&t(i).is(":visible")&&e(t(i)))},t.extend(t.expr[":"],{focusable:function(e){return t.ui.focusable(e,null!=t.attr(e,"tabindex"))}}),t.ui.focusable,t.fn.form=function(){return"string"==typeof this[0].form?this.closest("form"):t(this[0].form)},t.ui.formResetMixin={_formResetHandler:function(){var e=t(this);setTimeout(function(){var i=e.data("ui-form-reset-instances");t.each(i,function(){this.refresh()})})},_bindFormResetHandler:function(){if(this.form=this.element.form(),this.form.length){var t=this.form.data("ui-form-reset-instances")||[];t.length||this.form.on("reset.ui-form-reset",this._formResetHandler),t.push(this),this.form.data("ui-form-reset-instances",t)}},_unbindFormResetHandler:function(){if(this.form.length){var e=this.form.data("ui-form-reset-instances");e.splice(t.inArray(this,e),1),e.length?this.form.data("ui-form-reset-instances",e):this.form.removeData("ui-form-reset-instances").off("reset.ui-form-reset")}}},"1.7"===t.fn.jquery.substring(0,3)&&(t.each(["Width","Height"],function(e,i){function s(e,i,s,o){return t.each(n,function(){i-=parseFloat(t.css(e,"padding"+this))||0,s&&(i-=parseFloat(t.css(e,"border"+this+"Width"))||0),o&&(i-=parseFloat(t.css(e,"margin"+this))||0)}),i}var n="Width"===i?["Left","Right"]:["Top","Bottom"],o=i.toLowerCase(),a={innerWidth:t.fn.innerWidth,innerHeight:t.fn.innerHeight,outerWidth:t.fn.outerWidth,outerHeight:t.fn.outerHeight};t.fn["inner"+i]=function(e){return void 0===e?a["inner"+i].call(this):this.each(function(){t(this).css(o,s(this,e)+"px")})},t.fn["outer"+i]=function(e,n){return"number"!=typeof e?a["outer"+i].call(this,e):this.each(function(){t(this).css(o,s(this,e,!0,n)+"px")})}}),t.fn.addBack=function(t){return this.add(null==t?this.prevObject:this.prevObject.filter(t))}),t.ui.keyCode={BACKSPACE:8,COMMA:188,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,LEFT:37,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SPACE:32,TAB:9,UP:38},t.ui.escapeSelector=function(){var t=/([!"#$%&'()*+,.\/:;<=>?@[\]^`{|}~])/g;return function(e){return e.replace(t,"\\$1")}}(),t.fn.labels=function(){var e,i,s,n,o;return this[0].labels&&this[0].labels.length?this.pushStack(this[0].labels):(n=this.eq(0).parents("label"),s=this.attr("id"),s&&(e=this.eq(0).parents().last(),o=e.add(e.length?e.siblings():this.siblings()),i="label[for='"+t.ui.escapeSelector(s)+"']",n=n.add(o.find(i).addBack(i))),this.pushStack(n))},t.fn.scrollParent=function(e){var i=this.css("position"),s="absolute"===i,n=e?/(auto|scroll|hidden)/:/(auto|scroll)/,o=this.parents().filter(function(){var e=t(this);return s&&"static"===e.css("position")?!1:n.test(e.css("overflow")+e.css("overflow-y")+e.css("overflow-x"))}).eq(0);return"fixed"!==i&&o.length?o:t(this[0].ownerDocument||document)},t.extend(t.expr[":"],{tabbable:function(e){var i=t.attr(e,"tabindex"),s=null!=i;return(!s||i>=0)&&t.ui.focusable(e,s)}}),t.fn.extend({uniqueId:function(){var t=0;return function(){return this.each(function(){this.id||(this.id="ui-id-"+ ++t)})}}(),removeUniqueId:function(){return this.each(function(){/^ui-id-\d+$/.test(this.id)&&t(this).removeAttr("id")})}}),t.widget("ui.accordion",{version:"1.12.1",options:{active:0,animate:{},classes:{"ui-accordion-header":"ui-corner-top","ui-accordion-header-collapsed":"ui-corner-all","ui-accordion-content":"ui-corner-bottom"},collapsible:!1,event:"click",header:"> li > :first-child, > :not(li):even",heightStyle:"auto",icons:{activeHeader:"ui-icon-triangle-1-s",header:"ui-icon-triangle-1-e"},activate:null,beforeActivate:null},hideProps:{borderTopWidth:"hide",borderBottomWidth:"hide",paddingTop:"hide",paddingBottom:"hide",height:"hide"},showProps:{borderTopWidth:"show",borderBottomWidth:"show",paddingTop:"show",paddingBottom:"show",height:"show"},_create:function(){var e=this.options;this.prevShow=this.prevHide=t(),this._addClass("ui-accordion","ui-widget ui-helper-reset"),this.element.attr("role","tablist"),e.collapsible||e.active!==!1&&null!=e.active||(e.active=0),this._processPanels(),0>e.active&&(e.active+=this.headers.length),this._refresh()},_getCreateEventData:function(){return{header:this.active,panel:this.active.length?this.active.next():t()}},_createIcons:function(){var e,i,s=this.options.icons;s&&(e=t(""),this._addClass(e,"ui-accordion-header-icon","ui-icon "+s.header),e.prependTo(this.headers),i=this.active.children(".ui-accordion-header-icon"),this._removeClass(i,s.header)._addClass(i,null,s.activeHeader)._addClass(this.headers,"ui-accordion-icons"))},_destroyIcons:function(){this._removeClass(this.headers,"ui-accordion-icons"),this.headers.children(".ui-accordion-header-icon").remove()},_destroy:function(){var t;this.element.removeAttr("role"),this.headers.removeAttr("role aria-expanded aria-selected aria-controls tabIndex").removeUniqueId(),this._destroyIcons(),t=this.headers.next().css("display","").removeAttr("role aria-hidden aria-labelledby").removeUniqueId(),"content"!==this.options.heightStyle&&t.css("height","")},_setOption:function(t,e){return"active"===t?(this._activate(e),void 0):("event"===t&&(this.options.event&&this._off(this.headers,this.options.event),this._setupEvents(e)),this._super(t,e),"collapsible"!==t||e||this.options.active!==!1||this._activate(0),"icons"===t&&(this._destroyIcons(),e&&this._createIcons()),void 0)},_setOptionDisabled:function(t){this._super(t),this.element.attr("aria-disabled",t),this._toggleClass(null,"ui-state-disabled",!!t),this._toggleClass(this.headers.add(this.headers.next()),null,"ui-state-disabled",!!t)},_keydown:function(e){if(!e.altKey&&!e.ctrlKey){var i=t.ui.keyCode,s=this.headers.length,n=this.headers.index(e.target),o=!1;switch(e.keyCode){case i.RIGHT:case i.DOWN:o=this.headers[(n+1)%s];break;case i.LEFT:case i.UP:o=this.headers[(n-1+s)%s];break;case i.SPACE:case i.ENTER:this._eventHandler(e);break;case i.HOME:o=this.headers[0];break;case i.END:o=this.headers[s-1]}o&&(t(e.target).attr("tabIndex",-1),t(o).attr("tabIndex",0),t(o).trigger("focus"),e.preventDefault())}},_panelKeyDown:function(e){e.keyCode===t.ui.keyCode.UP&&e.ctrlKey&&t(e.currentTarget).prev().trigger("focus")},refresh:function(){var e=this.options;this._processPanels(),e.active===!1&&e.collapsible===!0||!this.headers.length?(e.active=!1,this.active=t()):e.active===!1?this._activate(0):this.active.length&&!t.contains(this.element[0],this.active[0])?this.headers.length===this.headers.find(".ui-state-disabled").length?(e.active=!1,this.active=t()):this._activate(Math.max(0,e.active-1)):e.active=this.headers.index(this.active),this._destroyIcons(),this._refresh()},_processPanels:function(){var t=this.headers,e=this.panels;this.headers=this.element.find(this.options.header),this._addClass(this.headers,"ui-accordion-header ui-accordion-header-collapsed","ui-state-default"),this.panels=this.headers.next().filter(":not(.ui-accordion-content-active)").hide(),this._addClass(this.panels,"ui-accordion-content","ui-helper-reset ui-widget-content"),e&&(this._off(t.not(this.headers)),this._off(e.not(this.panels)))},_refresh:function(){var e,i=this.options,s=i.heightStyle,n=this.element.parent();this.active=this._findActive(i.active),this._addClass(this.active,"ui-accordion-header-active","ui-state-active")._removeClass(this.active,"ui-accordion-header-collapsed"),this._addClass(this.active.next(),"ui-accordion-content-active"),this.active.next().show(),this.headers.attr("role","tab").each(function(){var e=t(this),i=e.uniqueId().attr("id"),s=e.next(),n=s.uniqueId().attr("id");e.attr("aria-controls",n),s.attr("aria-labelledby",i)}).next().attr("role","tabpanel"),this.headers.not(this.active).attr({"aria-selected":"false","aria-expanded":"false",tabIndex:-1}).next().attr({"aria-hidden":"true"}).hide(),this.active.length?this.active.attr({"aria-selected":"true","aria-expanded":"true",tabIndex:0}).next().attr({"aria-hidden":"false"}):this.headers.eq(0).attr("tabIndex",0),this._createIcons(),this._setupEvents(i.event),"fill"===s?(e=n.height(),this.element.siblings(":visible").each(function(){var i=t(this),s=i.css("position");"absolute"!==s&&"fixed"!==s&&(e-=i.outerHeight(!0))}),this.headers.each(function(){e-=t(this).outerHeight(!0)}),this.headers.next().each(function(){t(this).height(Math.max(0,e-t(this).innerHeight()+t(this).height()))}).css("overflow","auto")):"auto"===s&&(e=0,this.headers.next().each(function(){var i=t(this).is(":visible");i||t(this).show(),e=Math.max(e,t(this).css("height","").height()),i||t(this).hide()}).height(e))},_activate:function(e){var i=this._findActive(e)[0];i!==this.active[0]&&(i=i||this.active[0],this._eventHandler({target:i,currentTarget:i,preventDefault:t.noop}))},_findActive:function(e){return"number"==typeof e?this.headers.eq(e):t()},_setupEvents:function(e){var i={keydown:"_keydown"};e&&t.each(e.split(" "),function(t,e){i[e]="_eventHandler"}),this._off(this.headers.add(this.headers.next())),this._on(this.headers,i),this._on(this.headers.next(),{keydown:"_panelKeyDown"}),this._hoverable(this.headers),this._focusable(this.headers)},_eventHandler:function(e){var i,s,n=this.options,o=this.active,a=t(e.currentTarget),r=a[0]===o[0],h=r&&n.collapsible,l=h?t():a.next(),c=o.next(),u={oldHeader:o,oldPanel:c,newHeader:h?t():a,newPanel:l};e.preventDefault(),r&&!n.collapsible||this._trigger("beforeActivate",e,u)===!1||(n.active=h?!1:this.headers.index(a),this.active=r?t():a,this._toggle(u),this._removeClass(o,"ui-accordion-header-active","ui-state-active"),n.icons&&(i=o.children(".ui-accordion-header-icon"),this._removeClass(i,null,n.icons.activeHeader)._addClass(i,null,n.icons.header)),r||(this._removeClass(a,"ui-accordion-header-collapsed")._addClass(a,"ui-accordion-header-active","ui-state-active"),n.icons&&(s=a.children(".ui-accordion-header-icon"),this._removeClass(s,null,n.icons.header)._addClass(s,null,n.icons.activeHeader)),this._addClass(a.next(),"ui-accordion-content-active")))},_toggle:function(e){var i=e.newPanel,s=this.prevShow.length?this.prevShow:e.oldPanel;this.prevShow.add(this.prevHide).stop(!0,!0),this.prevShow=i,this.prevHide=s,this.options.animate?this._animate(i,s,e):(s.hide(),i.show(),this._toggleComplete(e)),s.attr({"aria-hidden":"true"}),s.prev().attr({"aria-selected":"false","aria-expanded":"false"}),i.length&&s.length?s.prev().attr({tabIndex:-1,"aria-expanded":"false"}):i.length&&this.headers.filter(function(){return 0===parseInt(t(this).attr("tabIndex"),10)}).attr("tabIndex",-1),i.attr("aria-hidden","false").prev().attr({"aria-selected":"true","aria-expanded":"true",tabIndex:0})},_animate:function(t,e,i){var s,n,o,a=this,r=0,h=t.css("box-sizing"),l=t.length&&(!e.length||t.index()",delay:300,options:{icons:{submenu:"ui-icon-caret-1-e"},items:"> *",menus:"ul",position:{my:"left top",at:"right top"},role:"menu",blur:null,focus:null,select:null},_create:function(){this.activeMenu=this.element,this.mouseHandled=!1,this.element.uniqueId().attr({role:this.options.role,tabIndex:0}),this._addClass("ui-menu","ui-widget ui-widget-content"),this._on({"mousedown .ui-menu-item":function(t){t.preventDefault()},"click .ui-menu-item":function(e){var i=t(e.target),s=t(t.ui.safeActiveElement(this.document[0]));!this.mouseHandled&&i.not(".ui-state-disabled").length&&(this.select(e),e.isPropagationStopped()||(this.mouseHandled=!0),i.has(".ui-menu").length?this.expand(e):!this.element.is(":focus")&&s.closest(".ui-menu").length&&(this.element.trigger("focus",[!0]),this.active&&1===this.active.parents(".ui-menu").length&&clearTimeout(this.timer)))},"mouseenter .ui-menu-item":function(e){if(!this.previousFilter){var i=t(e.target).closest(".ui-menu-item"),s=t(e.currentTarget);i[0]===s[0]&&(this._removeClass(s.siblings().children(".ui-state-active"),null,"ui-state-active"),this.focus(e,s))}},mouseleave:"collapseAll","mouseleave .ui-menu":"collapseAll",focus:function(t,e){var i=this.active||this.element.find(this.options.items).eq(0);e||this.focus(t,i)},blur:function(e){this._delay(function(){var i=!t.contains(this.element[0],t.ui.safeActiveElement(this.document[0]));i&&this.collapseAll(e)})},keydown:"_keydown"}),this.refresh(),this._on(this.document,{click:function(t){this._closeOnDocumentClick(t)&&this.collapseAll(t),this.mouseHandled=!1}})},_destroy:function(){var e=this.element.find(".ui-menu-item").removeAttr("role aria-disabled"),i=e.children(".ui-menu-item-wrapper").removeUniqueId().removeAttr("tabIndex role aria-haspopup");this.element.removeAttr("aria-activedescendant").find(".ui-menu").addBack().removeAttr("role aria-labelledby aria-expanded aria-hidden aria-disabled tabIndex").removeUniqueId().show(),i.children().each(function(){var e=t(this);e.data("ui-menu-submenu-caret")&&e.remove()})},_keydown:function(e){var i,s,n,o,a=!0;switch(e.keyCode){case t.ui.keyCode.PAGE_UP:this.previousPage(e);break;case t.ui.keyCode.PAGE_DOWN:this.nextPage(e);break;case t.ui.keyCode.HOME:this._move("first","first",e);break;case t.ui.keyCode.END:this._move("last","last",e);break;case t.ui.keyCode.UP:this.previous(e);break;case t.ui.keyCode.DOWN:this.next(e);break;case t.ui.keyCode.LEFT:this.collapse(e);break;case t.ui.keyCode.RIGHT:this.active&&!this.active.is(".ui-state-disabled")&&this.expand(e);break;case t.ui.keyCode.ENTER:case t.ui.keyCode.SPACE:this._activate(e);break;case t.ui.keyCode.ESCAPE:this.collapse(e);break;default:a=!1,s=this.previousFilter||"",o=!1,n=e.keyCode>=96&&105>=e.keyCode?""+(e.keyCode-96):String.fromCharCode(e.keyCode),clearTimeout(this.filterTimer),n===s?o=!0:n=s+n,i=this._filterMenuItems(n),i=o&&-1!==i.index(this.active.next())?this.active.nextAll(".ui-menu-item"):i,i.length||(n=String.fromCharCode(e.keyCode),i=this._filterMenuItems(n)),i.length?(this.focus(e,i),this.previousFilter=n,this.filterTimer=this._delay(function(){delete this.previousFilter},1e3)):delete this.previousFilter}a&&e.preventDefault()},_activate:function(t){this.active&&!this.active.is(".ui-state-disabled")&&(this.active.children("[aria-haspopup='true']").length?this.expand(t):this.select(t))},refresh:function(){var e,i,s,n,o,a=this,r=this.options.icons.submenu,h=this.element.find(this.options.menus);this._toggleClass("ui-menu-icons",null,!!this.element.find(".ui-icon").length),s=h.filter(":not(.ui-menu)").hide().attr({role:this.options.role,"aria-hidden":"true","aria-expanded":"false"}).each(function(){var e=t(this),i=e.prev(),s=t("").data("ui-menu-submenu-caret",!0);a._addClass(s,"ui-menu-icon","ui-icon "+r),i.attr("aria-haspopup","true").prepend(s),e.attr("aria-labelledby",i.attr("id"))}),this._addClass(s,"ui-menu","ui-widget ui-widget-content ui-front"),e=h.add(this.element),i=e.find(this.options.items),i.not(".ui-menu-item").each(function(){var e=t(this);a._isDivider(e)&&a._addClass(e,"ui-menu-divider","ui-widget-content")}),n=i.not(".ui-menu-item, .ui-menu-divider"),o=n.children().not(".ui-menu").uniqueId().attr({tabIndex:-1,role:this._itemRole()}),this._addClass(n,"ui-menu-item")._addClass(o,"ui-menu-item-wrapper"),i.filter(".ui-state-disabled").attr("aria-disabled","true"),this.active&&!t.contains(this.element[0],this.active[0])&&this.blur()},_itemRole:function(){return{menu:"menuitem",listbox:"option"}[this.options.role]},_setOption:function(t,e){if("icons"===t){var i=this.element.find(".ui-menu-icon");this._removeClass(i,null,this.options.icons.submenu)._addClass(i,null,e.submenu)}this._super(t,e)},_setOptionDisabled:function(t){this._super(t),this.element.attr("aria-disabled",t+""),this._toggleClass(null,"ui-state-disabled",!!t)},focus:function(t,e){var i,s,n;this.blur(t,t&&"focus"===t.type),this._scrollIntoView(e),this.active=e.first(),s=this.active.children(".ui-menu-item-wrapper"),this._addClass(s,null,"ui-state-active"),this.options.role&&this.element.attr("aria-activedescendant",s.attr("id")),n=this.active.parent().closest(".ui-menu-item").children(".ui-menu-item-wrapper"),this._addClass(n,null,"ui-state-active"),t&&"keydown"===t.type?this._close():this.timer=this._delay(function(){this._close()},this.delay),i=e.children(".ui-menu"),i.length&&t&&/^mouse/.test(t.type)&&this._startOpening(i),this.activeMenu=e.parent(),this._trigger("focus",t,{item:e})},_scrollIntoView:function(e){var i,s,n,o,a,r;this._hasScroll()&&(i=parseFloat(t.css(this.activeMenu[0],"borderTopWidth"))||0,s=parseFloat(t.css(this.activeMenu[0],"paddingTop"))||0,n=e.offset().top-this.activeMenu.offset().top-i-s,o=this.activeMenu.scrollTop(),a=this.activeMenu.height(),r=e.outerHeight(),0>n?this.activeMenu.scrollTop(o+n):n+r>a&&this.activeMenu.scrollTop(o+n-a+r))},blur:function(t,e){e||clearTimeout(this.timer),this.active&&(this._removeClass(this.active.children(".ui-menu-item-wrapper"),null,"ui-state-active"),this._trigger("blur",t,{item:this.active}),this.active=null)},_startOpening:function(t){clearTimeout(this.timer),"true"===t.attr("aria-hidden")&&(this.timer=this._delay(function(){this._close(),this._open(t)},this.delay))},_open:function(e){var i=t.extend({of:this.active},this.options.position);clearTimeout(this.timer),this.element.find(".ui-menu").not(e.parents(".ui-menu")).hide().attr("aria-hidden","true"),e.show().removeAttr("aria-hidden").attr("aria-expanded","true").position(i)},collapseAll:function(e,i){clearTimeout(this.timer),this.timer=this._delay(function(){var s=i?this.element:t(e&&e.target).closest(this.element.find(".ui-menu"));s.length||(s=this.element),this._close(s),this.blur(e),this._removeClass(s.find(".ui-state-active"),null,"ui-state-active"),this.activeMenu=s},this.delay)},_close:function(t){t||(t=this.active?this.active.parent():this.element),t.find(".ui-menu").hide().attr("aria-hidden","true").attr("aria-expanded","false")},_closeOnDocumentClick:function(e){return!t(e.target).closest(".ui-menu").length},_isDivider:function(t){return!/[^\-\u2014\u2013\s]/.test(t.text())},collapse:function(t){var e=this.active&&this.active.parent().closest(".ui-menu-item",this.element);e&&e.length&&(this._close(),this.focus(t,e))},expand:function(t){var e=this.active&&this.active.children(".ui-menu ").find(this.options.items).first();e&&e.length&&(this._open(e.parent()),this._delay(function(){this.focus(t,e)}))},next:function(t){this._move("next","first",t)},previous:function(t){this._move("prev","last",t)},isFirstItem:function(){return this.active&&!this.active.prevAll(".ui-menu-item").length},isLastItem:function(){return this.active&&!this.active.nextAll(".ui-menu-item").length},_move:function(t,e,i){var s;this.active&&(s="first"===t||"last"===t?this.active["first"===t?"prevAll":"nextAll"](".ui-menu-item").eq(-1):this.active[t+"All"](".ui-menu-item").eq(0)),s&&s.length&&this.active||(s=this.activeMenu.find(this.options.items)[e]()),this.focus(i,s)},nextPage:function(e){var i,s,n;return this.active?(this.isLastItem()||(this._hasScroll()?(s=this.active.offset().top,n=this.element.height(),this.active.nextAll(".ui-menu-item").each(function(){return i=t(this),0>i.offset().top-s-n}),this.focus(e,i)):this.focus(e,this.activeMenu.find(this.options.items)[this.active?"last":"first"]())),void 0):(this.next(e),void 0)},previousPage:function(e){var i,s,n;return this.active?(this.isFirstItem()||(this._hasScroll()?(s=this.active.offset().top,n=this.element.height(),this.active.prevAll(".ui-menu-item").each(function(){return i=t(this),i.offset().top-s+n>0}),this.focus(e,i)):this.focus(e,this.activeMenu.find(this.options.items).first())),void 0):(this.next(e),void 0)},_hasScroll:function(){return this.element.outerHeight()",options:{appendTo:null,autoFocus:!1,delay:300,minLength:1,position:{my:"left top",at:"left bottom",collision:"none"},source:null,change:null,close:null,focus:null,open:null,response:null,search:null,select:null},requestIndex:0,pending:0,_create:function(){var e,i,s,n=this.element[0].nodeName.toLowerCase(),o="textarea"===n,a="input"===n; -this.isMultiLine=o||!a&&this._isContentEditable(this.element),this.valueMethod=this.element[o||a?"val":"text"],this.isNewMenu=!0,this._addClass("ui-autocomplete-input"),this.element.attr("autocomplete","off"),this._on(this.element,{keydown:function(n){if(this.element.prop("readOnly"))return e=!0,s=!0,i=!0,void 0;e=!1,s=!1,i=!1;var o=t.ui.keyCode;switch(n.keyCode){case o.PAGE_UP:e=!0,this._move("previousPage",n);break;case o.PAGE_DOWN:e=!0,this._move("nextPage",n);break;case o.UP:e=!0,this._keyEvent("previous",n);break;case o.DOWN:e=!0,this._keyEvent("next",n);break;case o.ENTER:this.menu.active&&(e=!0,n.preventDefault(),this.menu.select(n));break;case o.TAB:this.menu.active&&this.menu.select(n);break;case o.ESCAPE:this.menu.element.is(":visible")&&(this.isMultiLine||this._value(this.term),this.close(n),n.preventDefault());break;default:i=!0,this._searchTimeout(n)}},keypress:function(s){if(e)return e=!1,(!this.isMultiLine||this.menu.element.is(":visible"))&&s.preventDefault(),void 0;if(!i){var n=t.ui.keyCode;switch(s.keyCode){case n.PAGE_UP:this._move("previousPage",s);break;case n.PAGE_DOWN:this._move("nextPage",s);break;case n.UP:this._keyEvent("previous",s);break;case n.DOWN:this._keyEvent("next",s)}}},input:function(t){return s?(s=!1,t.preventDefault(),void 0):(this._searchTimeout(t),void 0)},focus:function(){this.selectedItem=null,this.previous=this._value()},blur:function(t){return this.cancelBlur?(delete this.cancelBlur,void 0):(clearTimeout(this.searching),this.close(t),this._change(t),void 0)}}),this._initSource(),this.menu=t("