diff --git a/README.md b/README.md index f2473b62..9f0c4893 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ If you like this project, please give it a Star. If you've come up with more use > > 2.本项目中每个文件的功能都在自译解[`self_analysis.md`](https://github.com/binary-husky/chatgpt_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)详细说明。随着版本的迭代,您也可以随时自行点击相关函数插件,调用GPT重新生成项目的自我解析报告。常见问题汇总在[`wiki`](https://github.com/binary-husky/chatgpt_academic/wiki/%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98)当中。 > - +> 3.已支持OpenAI和API2D的api-key共存,可在配置文件中填写如`API_KEY="openai-key1,openai-key2,api2d-key3"`。需要临时更换`API_KEY`时,在输入区输入临时的`API_KEY`然后回车键提交后即可生效。
@@ -40,6 +40,7 @@ If you like this project, please give it a Star. If you've come up with more use Latex全文翻译、润色 | [函数插件] 一键翻译或润色latex论文 批量注释生成 | [函数插件] 一键批量生成函数注释 chat分析报告生成 | [函数插件] 运行后自动生成总结汇报 +Markdown中英互译 | [函数插件] 看到上面5种语言的[README](https://github.com/binary-husky/chatgpt_academic/blob/master/docs/README_EN.md)了吗? [arxiv小助手](https://www.bilibili.com/video/BV1LM4y1279X) | [函数插件] 输入arxiv文章url即可一键翻译摘要+下载PDF [PDF论文全文翻译功能](https://www.bilibili.com/video/BV1KT411x7Wn) | [函数插件] PDF论文提取题目&摘要+翻译全文(多线程) [谷歌学术统合小助手](https://www.bilibili.com/video/BV19L411U7ia) | [函数插件] 给定任意谷歌学术搜索页面URL,让gpt帮你选择有趣的文章 @@ -53,7 +54,7 @@ huggingface免科学上网[在线体验](https://huggingface.co/spaces/qingxu98/
-- 新界面(修改config.py中的LAYOUT选项即可实现“左右布局”和“上下布局”的切换) +- 新界面(修改`config.py`中的LAYOUT选项即可实现“左右布局”和“上下布局”的切换)
@@ -101,8 +102,8 @@ cd chatgpt_academic 在`config.py`中,配置 海外Proxy 和 OpenAI API KEY,说明如下 ``` -1. 如果你在国内,需要设置海外代理才能够顺利使用 OpenAI API,设置方法请仔细阅读config.py(1.修改其中的USE_PROXY为True; 2.按照说明修改其中的proxies)。 -2. 配置 OpenAI API KEY。你需要在 OpenAI 官网上注册并获取 API KEY。一旦你拿到了 API KEY,在 config.py 文件里配置好即可。 +1. 如果你在国内,需要设置海外代理才能够顺利使用OpenAI API,设置方法请仔细阅读config.py(1.修改其中的USE_PROXY为True; 2.按照说明修改其中的proxies)。 +2. 配置 OpenAI API KEY。支持任意数量的OpenAI的密钥和API2D的密钥共存/负载均衡,多个KEY用英文逗号分隔即可,例如输入 API_KEY="OpenAI密钥1,API2D密钥2,OpenAI密钥3,OpenAI密钥4" 3. 与代理网络有关的issue(网络超时、代理不起作用)汇总到 https://github.com/binary-husky/chatgpt_academic/issues/1 ``` (P.S. 程序运行时会优先检查是否存在名为`config_private.py`的私密配置文件,并用其中的配置覆盖`config.py`的同名配置。因此,如果您能理解我们的配置读取逻辑,我们强烈建议您在`config.py`旁边创建一个名为`config_private.py`的新配置文件,并把`config.py`中的配置转移(复制)到`config_private.py`中。`config_private.py`不受git管控,可以让您的隐私信息更加安全。) @@ -110,19 +111,17 @@ cd chatgpt_academic 3. 安装依赖 ```sh -# (选择一)推荐 -python -m pip install -r requirements.txt +# (选择I: 如熟悉python)推荐 +python -m pip install -r requirements.txt +# 备注:使用官方pip源或者阿里pip源,其他pip源(如一些大学的pip)有可能出问题,临时换源方法:python -m pip install -r requirements.txt -i https://mirrors.aliyun.com/pypi/simple/ -# (选择二)如果您使用anaconda,步骤也是类似的: -# (选择二.1)conda create -n gptac_venv python=3.11 -# (选择二.2)conda activate gptac_venv -# (选择二.3)python -m pip install -r requirements.txt - -# 备注:使用官方pip源或者阿里pip源,其他pip源(如一些大学的pip)有可能出问题,临时换源方法: -# python -m pip install -r requirements.txt -i https://mirrors.aliyun.com/pypi/simple/ +# (选择II: 如不熟悉python)使用anaconda,步骤也是类似的: +# (II-1)conda create -n gptac_venv python=3.11 +# (II-2)conda activate gptac_venv +# (II-3)python -m pip install -r requirements.txt ``` -如果需要支持清华ChatGLM,需要额外安装更多依赖(不熟悉python者、电脑配置不佳者,建议不要尝试): +如果需要支持清华ChatGLM后端,需要额外安装更多依赖(前提条件:熟悉python + 电脑配置够强): ```sh python -m pip install -r request_llm/requirements_chatglm.txt ``` @@ -135,54 +134,48 @@ python main.py 5. 测试函数插件 ``` - 测试Python项目分析 - input区域 输入 `./crazy_functions/test_project/python/dqn` , 然后点击 "解析整个Python项目" -- 测试自我代码解读 + (选择1)input区域 输入 `./crazy_functions/test_project/python/dqn` , 然后点击 "解析整个Python项目" + (选择2)展开文件上传区,将python文件/包含python文件的压缩包拖拽进去,在出现反馈提示后, 然后点击 "解析整个Python项目" +- 测试自我代码解读(本项目自译解) 点击 "[多线程Demo] 解析此项目本身(源码自译解)" -- 测试实验功能模板函数(要求gpt回答历史上的今天发生了什么),您可以根据此函数为模板,实现更复杂的功能 +- 测试函数插件模板函数(要求gpt回答历史上的今天发生了什么),您可以根据此函数为模板,实现更复杂的功能 点击 "[函数插件模板Demo] 历史上的今天" - 函数插件区下拉菜单中有更多功能可供选择 ``` -## 安装-方法2:使用docker (Linux) +## 安装-方法2:使用Docker 1. 仅ChatGPT(推荐大多数人选择) + ``` sh # 下载项目 git clone https://github.com/binary-husky/chatgpt_academic.git cd chatgpt_academic -# 配置 海外Proxy 和 OpenAI API KEY +# 配置 “海外Proxy”, “API_KEY” 以及 “WEB_PORT” (例如50923) 等 用任意文本编辑器编辑 config.py # 安装 docker build -t gpt-academic . -# 运行 +#(最后一步-选择1)在Linux环境下,用`--net=host`更方便快捷 docker run --rm -it --net=host gpt-academic - -# 测试函数插件 -## 测试函数插件模板函数(要求gpt回答历史上的今天发生了什么),您可以根据此函数为模板,实现更复杂的功能 -点击 "[函数插件模板Demo] 历史上的今天" -## 测试给Latex项目写摘要 -input区域 输入 ./crazy_functions/test_project/latex/attention , 然后点击 "读Tex论文写摘要" -## 测试Python项目分析 -input区域 输入 ./crazy_functions/test_project/python/dqn , 然后点击 "解析整个Python项目" - -函数插件区下拉菜单中有更多功能可供选择 +#(最后一步-选择2)在macOS/windows环境下,只能用-p选项将容器上的端口(例如50923)暴露给主机上的端口 +docker run --rm -it -p 50923:50923 gpt-academic ``` -2. ChatGPT+ChatGLM(需要对docker非常熟悉 + 电脑配置足够强) +2. ChatGPT+ChatGLM(需要对Docker熟悉 + 读懂Dockerfile + 电脑配置够强) ``` sh -# 修改dockerfile +# 修改Dockerfile cd docs && nano Dockerfile+ChatGLM -# How to build | 如何构建 (Dockerfile+ChatGLM在docs路径下,请先cd docs) +# 构建 (Dockerfile+ChatGLM在docs路径下,请先cd docs) docker build -t gpt-academic --network=host -f Dockerfile+ChatGLM . -# How to run | 如何运行 (1) 直接运行: +# 运行 (1) 直接运行: docker run --rm -it --net=host --gpus=all gpt-academic -# How to run | 如何运行 (2) 我想运行之前进容器做一些调整: +# 运行 (2) 我想运行之前进容器做一些调整: docker run --rm -it --net=host --gpus=all gpt-academic bash ``` -## 安装-方法3:其他部署方式 +## 安装-方法3:其他部署方式(需要云服务器知识与经验) 1. 远程云服务器部署 请访问[部署wiki-1](https://github.com/binary-husky/chatgpt_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) @@ -201,7 +194,9 @@ docker run --rm -it --net=host --gpus=all gpt-academic bash --- -## 自定义新的便捷按钮(学术快捷键自定义) +## 自定义新的便捷按钮 / 自定义函数插件 + +1. 自定义新的便捷按钮(学术快捷键) 任意文本编辑器打开`core_functional.py`,添加条目如下,然后重启程序即可。(如果按钮已经添加成功并可见,那么前缀、后缀都支持热修改,无需重启程序即可生效。) 例如 ``` @@ -217,19 +212,25 @@ docker run --rm -it --net=host --gpus=all gpt-academic bash +2. 自定义函数插件 + +编写强大的函数插件来执行任何你想得到的和想不到的任务。 +本项目的插件编写、调试难度很低,只要您具备一定的python基础知识,就可以仿照我们提供的模板实现自己的插件功能。 +详情请参考[函数插件指南](https://github.com/binary-husky/chatgpt_academic/wiki/%E5%87%BD%E6%95%B0%E6%8F%92%E4%BB%B6%E6%8C%87%E5%8D%97)。 + + --- ## 部分功能展示 -### 图片显示: +1. 图片显示:
- -### 如果一个程序能够读懂并剖析自己: +2. 本项目的代码自译解(如果一个程序能够读懂并剖析自己):
@@ -239,7 +240,7 @@ docker run --rm -it --net=host --gpus=all gpt-academic bash
-### 其他任意Python/Cpp项目剖析: +3. 其他任意Python/Cpp/Java/Go/Rect/...项目剖析:
@@ -248,31 +249,39 @@ docker run --rm -it --net=host --gpus=all gpt-academic bash -### Latex论文一键阅读理解与摘要生成 +4. Latex论文一键阅读理解与摘要生成
-### 自动报告生成 +5. 自动报告生成
-### 模块化功能设计 +6. 模块化功能设计
-### 源代码转译英文 +7. 源代码转译英文
+8. 互联网在线信息综合 + +
+ +
+ + + ## Todo 与 版本规划: - version 3.2+ (todo): 函数插件支持更多参数接口 - version 3.1: 支持同时问询多个gpt模型!支持api2d,支持多个apikey负载均衡 diff --git a/config.py b/config.py index 5cb03fb4..6da37810 100644 --- a/config.py +++ b/config.py @@ -56,3 +56,7 @@ CONCURRENT_COUNT = 100 # 设置用户名和密码(不需要修改)(相关功能不稳定,与gradio版本和网络都相关,如果本地使用不建议加这个) # [("username", "password"), ("username2", "password2"), ...] AUTHENTICATION = [] + +# 重新URL重新定向,实现更换API_URL的作用(常规情况下,不要修改!!) +# 格式 {"https://api.openai.com/v1/chat/completions": "重定向的URL"} +API_URL_REDIRECT = {} diff --git a/crazy_functional.py b/crazy_functional.py index 6f4d37ee..8e3ab6a8 100644 --- a/crazy_functional.py +++ b/crazy_functional.py @@ -173,20 +173,23 @@ def get_crazy_functions(): ###################### 第三组插件 ########################### # [第三组插件]: 尚未充分测试的函数插件,放在这里 - try: - from crazy_functions.下载arxiv论文翻译摘要 import 下载arxiv论文并翻译摘要 - function_plugins.update({ - "一键下载arxiv论文并翻译摘要(先在input输入编号,如1812.10695)": { - "Color": "stop", - "AsButton": False, # 加入下拉菜单中 - "Function": HotReload(下载arxiv论文并翻译摘要) - } - }) - - except Exception as err: - print(f'[下载arxiv论文并翻译摘要] 插件导入失败 {str(err)}') + from crazy_functions.下载arxiv论文翻译摘要 import 下载arxiv论文并翻译摘要 + function_plugins.update({ + "一键下载arxiv论文并翻译摘要(先在input输入编号,如1812.10695)": { + "Color": "stop", + "AsButton": False, # 加入下拉菜单中 + "Function": HotReload(下载arxiv论文并翻译摘要) + } + }) - + from crazy_functions.联网的ChatGPT import 连接网络回答问题 + function_plugins.update({ + "连接网络回答问题(先输入问题,再点击按钮,需要访问谷歌)": { + "Color": "stop", + "AsButton": False, # 加入下拉菜单中 + "Function": HotReload(连接网络回答问题) + } + }) ###################### 第n组插件 ########################### return function_plugins diff --git a/crazy_functions/crazy_functions_test.py b/crazy_functions/crazy_functions_test.py index 2838e543..7b0f0725 100644 --- a/crazy_functions/crazy_functions_test.py +++ b/crazy_functions/crazy_functions_test.py @@ -12,7 +12,7 @@ def validate_path(): sys.path.append(root_dir_assume) validate_path() # validate path so you can run from base directory - +from colorful import * 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') @@ -79,14 +79,46 @@ def test_下载arxiv论文并翻译摘要(): for cookies, cb, hist, msg in 下载arxiv论文并翻译摘要(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port): print(cb) -test_解析一个Python项目() -test_Latex英文润色() -test_Markdown中译英() -test_批量翻译PDF文档() -test_谷歌检索小助手() -test_总结word文档() -test_下载arxiv论文并翻译摘要() -test_解析一个Cpp项目() +def test_联网回答问题(): + from crazy_functions.联网的ChatGPT import 连接网络回答问题 + # txt = "“我们称之为高效”是什么梗?" + # >> 从第0份、第1份、第2份搜索结果可以看出,“我们称之为高效”是指在游戏社区中,用户们用来形容一些游戏策略或行为非常高效且能够带来好的效果的用语。这个用语最初可能是在群星(Stellaris)这个游戏里面流行起来的,后来也传播到了其他游戏中,比如巨像(Titan)等游戏。其中第1份搜索结果中的一篇文章也指出,“我们称之为高效”这 一用语来源于群星(Stellaris)游戏中的一个情节。 + # txt = "为什么说枪毙P社玩家没有一个冤枉的?" + # >> 它们都是关于一个知乎用户所发的帖子,引用了一群游戏玩家对于需要对P社玩家进行枪毙的讨论,这个话题的本质是玩家们对于P 社游戏中的政治与历史元素的不同看法,以及其中不少玩家以极端立场宣扬的想法和言论,因此有人就以枪毙这些玩家来回应此类言论。但是这个话题本身并没有实质内容,只是一个玩笑或者恶搞,并不应该被当做真实的态度或者观点,因此这种说法没有实际意义。 + # txt = "谁是应急食品?" + # >> '根据以上搜索结果可以得知,应急食品是“原神”游戏中的角色派蒙的外号。' + # txt = "道路千万条,安全第一条。后面两句是?" + # >> '行车不规范,亲人两行泪。' + # txt = "What is in the canister?" + # >> Rainbow Six Siege 游戏中 Smoke 的 Canister 中装有何种物质相关的官方信息。 + # txt = "失败的man是什么?" + # >> 根据第1份搜索结果,可以得知失败的man是指一位在B站购买了蜘蛛侠COS服后穿上后被网友嘲笑的UP主,而“失败的man”是蜘蛛侠英文名“spiderman”的谐音梗,并且网友们还 给这位UP主起了“苍蝇侠”的外号。因此,失败的man是指这位UP主在穿上蜘蛛侠COS服后被网友嘲笑的情况。 + # txt = "老六是什么,起源于哪里?" + # >> 老六是网络流行语,最初起源于游戏《CSGO》,指游戏中玩家中独来独往、游离于队伍之外的“自由人”或玩得比较菜或者玩得比较阴险的人 ,后来逐渐演变成指玩得比较阴险的玩家。 + # txt = "罗小黑战记因为什么经常被吐槽?" + # >> 3. 更新速度。罗小黑战记的更新时间不定,时而快时而慢,给观众留下了等待的时间过长的印象。 + # txt = "沙特、伊朗最近的关系如何?" + # >> 最近在中国的斡旋下,沙特和伊朗于3月10日达成了恢复两国外交关系的协议,这表明两国关系已经重新回到正常化状态。 + # txt = "You should have gone for the head. What does that mean?" + # >> The phrase "You should have gone for the head" is a quote from the Marvel movies, Avengers: Infinity War and Avengers: Endgame. It was spoken by the character Thanos in Infinity War and by Thor in Endgame. + txt = "AutoGPT是什么?" + # >> AutoGPT是一个基于GPT-4语言模型的开源应用程序。它可以根据用户需求自主执行任务,包括事件分析、营销方案撰写、代码编程、数学运算等等,并完全不需要用户插手。它可以自己思考,给出实现的步骤和实现细节,甚至可以自问自答执 行任务。最近它在GitHub上爆火,成为了业内最热门的项目之一。 + # txt = "钟离带什么圣遗物?" + for cookies, cb, hist, msg in 连接网络回答问题(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port): + print("当前问答:", cb[-1][-1].replace("\n"," ")) + for i, it in enumerate(cb): print亮蓝(it[0]); print亮黄(it[1]) + +# test_解析一个Python项目() +# test_Latex英文润色() +# test_Markdown中译英() +# test_批量翻译PDF文档() +# test_谷歌检索小助手() +# test_总结word文档() +# test_下载arxiv论文并翻译摘要() +# test_解析一个Cpp项目() + +test_联网回答问题() + input("程序完成,回车退出。") print("退出。") \ No newline at end of file diff --git a/crazy_functions/联网的ChatGPT.py b/crazy_functions/联网的ChatGPT.py new file mode 100644 index 00000000..6a7d118b --- /dev/null +++ b/crazy_functions/联网的ChatGPT.py @@ -0,0 +1,102 @@ +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_llm.bridge_all import model_info + +def google(query, proxies): + query = query # 在此处替换您要搜索的关键词 + url = f"https://www.google.com/search?q={query}" + headers = {'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.61 Safari/537.36'} + response = requests.get(url, headers=headers, proxies=proxies) + soup = BeautifulSoup(response.content, 'html.parser') + results = [] + for g in soup.find_all('div', class_='g'): + anchors = g.find_all('a') + if anchors: + link = anchors[0]['href'] + if link.startswith('/url?q='): + link = link[7:] + if not link.startswith('http'): + continue + title = g.find('h3').text + item = {'title': title, 'link': link} + results.append(item) + + for r in results: + print(r['link']) + return results + +def scrape_text(url, proxies) -> str: + """Scrape text from a webpage + + Args: + url (str): The URL to scrape text from + + Returns: + str: The scraped text + """ + headers = { + 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.61 Safari/537.36', + 'Content-Type': 'text/plain', + } + try: + response = requests.get(url, headers=headers, proxies=proxies, timeout=8) + if response.encoding == "ISO-8859-1": response.encoding = response.apparent_encoding + except: + return "无法连接到该网页" + soup = BeautifulSoup(response.text, "html.parser") + for script in soup(["script", "style"]): + script.extract() + text = soup.get_text() + lines = (line.strip() for line in text.splitlines()) + chunks = (phrase.strip() for line in lines for phrase in line.split(" ")) + text = "\n".join(chunk for chunk in chunks if chunk) + return text + +@CatchException +def 连接网络回答问题(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 当前软件运行的端口号 + """ + history = [] # 清空历史,以免输入溢出 + chatbot.append((f"请结合互联网信息回答以下问题:{txt}", + "[Local Message] 请注意,您正在调用一个[函数插件]的模板,该模板可以实现ChatGPT联网信息综合。该函数面向希望实现更多有趣功能的开发者,它可以作为创建新功能函数的模板。您若希望分享新的功能模组,请不吝PR!")) + yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 # 由于请求gpt需要一段时间,我们先及时地做一次界面更新 + + # ------------- < 第1步:爬取搜索引擎的结果 > ------------- + from toolbox import get_conf + proxies, = get_conf('proxies') + urls = google(txt, proxies) + history = [] + + # ------------- < 第2步:依次访问网页 > ------------- + max_search_result = 5 # 最多收纳多少个网页的结果 + for index, url in enumerate(urls[:max_search_result]): + res = scrape_text(url['link'], proxies) + history.extend([f"第{index}份搜索结果:", res]) + chatbot.append([f"第{index}份搜索结果:", res[:500]+"......"]) + yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 # 由于请求gpt需要一段时间,我们先及时地做一次界面更新 + + # ------------- < 第3步:ChatGPT综合 > ------------- + i_say = f"从以上搜索结果中抽取信息,然后回答问题:{txt}" + i_say, history = input_clipping( # 裁剪输入,从最长的条目开始裁剪,防止爆token + inputs=i_say, + history=history, + max_token_limit=model_info[llm_kwargs['llm_model']]['max_token']*3//4 + ) + 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=history, + sys_prompt="请从给定的若干条搜索结果中抽取信息,对最相关的两个搜索结果进行总结,然后回答问题。" + ) + chatbot[-1] = (i_say, gpt_say) + history.append(i_say);history.append(gpt_say) + yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 # 界面更新 + diff --git a/main.py b/main.py index 0e722650..6ec26a57 100644 --- a/main.py +++ b/main.py @@ -57,7 +57,7 @@ def main(): cookies = gr.State({'api_key': API_KEY, 'llm_model': LLM_MODEL}) with gr_L1(): with gr_L2(scale=2): - chatbot = gr.Chatbot() + chatbot = gr.Chatbot(label=f"当前模型:{LLM_MODEL}") chatbot.style(height=CHATBOT_HEIGHT) history = gr.State([]) with gr_L2(scale=1): @@ -113,7 +113,7 @@ def main(): with gr.Row(): resetBtn2 = gr.Button("重置", variant="secondary"); resetBtn2.style(size="sm") stopBtn2 = gr.Button("停止", variant="secondary"); stopBtn2.style(size="sm") - clearBtn2 = gr.Button("清除", variant="secondary", visible=False); clearBtn.style(size="sm") + clearBtn2 = gr.Button("清除", variant="secondary", visible=False); clearBtn2.style(size="sm") # 功能区显示开关与功能区的互动 def fn_area_visibility(a): ret = {} @@ -156,6 +156,9 @@ def main(): variant = crazy_fns[k]["Color"] if "Color" in crazy_fns[k] else "secondary" return {switchy_bt: gr.update(value=k, variant=variant)} dropdown.select(on_dropdown_changed, [dropdown], [switchy_bt] ) + def on_md_dropdown_changed(k): + return {chatbot: gr.update(label="当前模型:"+k)} + md_dropdown.select(on_md_dropdown_changed, [md_dropdown], [chatbot] ) # 随变按钮的回调函数注册 def route(k, *args, **kwargs): if k in [r"打开插件列表", r"请先从插件列表中选择"]: return @@ -187,4 +190,4 @@ def main(): demo.queue(concurrency_count=CONCURRENT_COUNT).launch(server_name="0.0.0.0", share=False, favicon_path="docs/logo.png") if __name__ == "__main__": - main() \ No newline at end of file + main() diff --git a/request_llm/bridge_all.py b/request_llm/bridge_all.py index f1f4ee1a..d1bc5189 100644 --- a/request_llm/bridge_all.py +++ b/request_llm/bridge_all.py @@ -9,8 +9,9 @@ 2. predict_no_ui_long_connection:在实验过程中发现调用predict_no_ui处理长文档时,和openai的连接容易断掉,这个函数用stream的方式解决这个问题,同样支持多线程 """ import tiktoken -from functools import wraps, lru_cache +from functools import lru_cache from concurrent.futures import ThreadPoolExecutor +from toolbox import get_conf from .bridge_chatgpt import predict_no_ui_long_connection as chatgpt_noui from .bridge_chatgpt import predict as chatgpt_ui @@ -42,18 +43,37 @@ class LazyloadTiktoken(object): def decode(self, *args, **kwargs): encoder = self.get_encoder(self.model) return encoder.decode(*args, **kwargs) - + +# Endpoint 重定向 +API_URL_REDIRECT, = get_conf("API_URL_REDIRECT") +openai_endpoint = "https://api.openai.com/v1/chat/completions" +api2d_endpoint = "https://openai.api2d.net/v1/chat/completions" +# 兼容旧版的配置 +try: + 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: + pass +# 新版配置 +if openai_endpoint in API_URL_REDIRECT: openai_endpoint = API_URL_REDIRECT[openai_endpoint] +if api2d_endpoint in API_URL_REDIRECT: api2d_endpoint = API_URL_REDIRECT[api2d_endpoint] + + +# 获取tokenizer tokenizer_gpt35 = LazyloadTiktoken("gpt-3.5-turbo") tokenizer_gpt4 = LazyloadTiktoken("gpt-4") get_token_num_gpt35 = lambda txt: len(tokenizer_gpt35.encode(txt, disallowed_special=())) get_token_num_gpt4 = lambda txt: len(tokenizer_gpt4.encode(txt, disallowed_special=())) + model_info = { # openai "gpt-3.5-turbo": { "fn_with_ui": chatgpt_ui, "fn_without_ui": chatgpt_noui, - "endpoint": "https://api.openai.com/v1/chat/completions", + "endpoint": openai_endpoint, "max_token": 4096, "tokenizer": tokenizer_gpt35, "token_cnt": get_token_num_gpt35, @@ -62,7 +82,7 @@ model_info = { "gpt-4": { "fn_with_ui": chatgpt_ui, "fn_without_ui": chatgpt_noui, - "endpoint": "https://api.openai.com/v1/chat/completions", + "endpoint": openai_endpoint, "max_token": 8192, "tokenizer": tokenizer_gpt4, "token_cnt": get_token_num_gpt4, @@ -72,7 +92,7 @@ model_info = { "api2d-gpt-3.5-turbo": { "fn_with_ui": chatgpt_ui, "fn_without_ui": chatgpt_noui, - "endpoint": "https://openai.api2d.net/v1/chat/completions", + "endpoint": api2d_endpoint, "max_token": 4096, "tokenizer": tokenizer_gpt35, "token_cnt": get_token_num_gpt35, @@ -81,7 +101,7 @@ model_info = { "api2d-gpt-4": { "fn_with_ui": chatgpt_ui, "fn_without_ui": chatgpt_noui, - "endpoint": "https://openai.api2d.net/v1/chat/completions", + "endpoint": api2d_endpoint, "max_token": 8192, "tokenizer": tokenizer_gpt4, "token_cnt": get_token_num_gpt4, diff --git a/request_llm/bridge_chatgpt.py b/request_llm/bridge_chatgpt.py index 8c915c2a..c1a900b1 100644 --- a/request_llm/bridge_chatgpt.py +++ b/request_llm/bridge_chatgpt.py @@ -21,7 +21,7 @@ import importlib # config_private.py放自己的秘密如API和代理网址 # 读取时首先看是否存在私密的config_private配置文件(不受git管控),如果有,则覆盖原config文件 -from toolbox import get_conf, update_ui, is_any_api_key, select_api_key +from toolbox import get_conf, update_ui, is_any_api_key, select_api_key, what_keys proxies, API_KEY, TIMEOUT_SECONDS, MAX_RETRY = \ get_conf('proxies', 'API_KEY', 'TIMEOUT_SECONDS', 'MAX_RETRY') @@ -118,7 +118,7 @@ def predict(inputs, llm_kwargs, plugin_kwargs, chatbot, history=[], system_promp """ if is_any_api_key(inputs): chatbot._cookies['api_key'] = inputs - chatbot.append(("输入已识别为openai的api_key", "api_key已导入")) + 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']): @@ -141,7 +141,7 @@ def predict(inputs, llm_kwargs, plugin_kwargs, chatbot, history=[], system_promp try: headers, payload = generate_payload(inputs, llm_kwargs, history, system_prompt, stream) except RuntimeError as e: - chatbot[-1] = (inputs, f"您提供的api-key不满足要求,不包含任何可用于{llm_kwargs['llm_model']}的api-key。") + chatbot[-1] = (inputs, f"您提供的api-key不满足要求,不包含任何可用于{llm_kwargs['llm_model']}的api-key。您可能选择了错误的模型或请求源。") yield from update_ui(chatbot=chatbot, history=history, msg="api-key不满足要求") # 刷新界面 return @@ -208,6 +208,8 @@ def predict(inputs, llm_kwargs, plugin_kwargs, chatbot, history=[], system_promp chatbot[-1] = (chatbot[-1][0], "[Local Message] You exceeded your current quota. OpenAI以账户额度不足为由,拒绝服务.") 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' + traceback.format_exc() + '```' diff --git a/toolbox.py b/toolbox.py index 038d7be8..d2c9e6ec 100644 --- a/toolbox.py +++ b/toolbox.py @@ -432,6 +432,19 @@ def is_any_api_key(key): else: return is_openai_api_key(key) or is_api2d_key(key) +def what_keys(keys): + avail_key_list = {'OpenAI Key':0, "API2D Key":0} + key_list = keys.split(',') + + for k in key_list: + if is_openai_api_key(k): + avail_key_list['OpenAI Key'] += 1 + + for k in key_list: + if is_api2d_key(k): + avail_key_list['API2D Key'] += 1 + + return f"检测到: OpenAI Key {avail_key_list['OpenAI Key']} 个,API2D Key {avail_key_list['API2D Key']} 个" def select_api_key(keys, llm_model): import random @@ -447,20 +460,22 @@ def select_api_key(keys, llm_model): if is_api2d_key(k): avail_key_list.append(k) if len(avail_key_list) == 0: - raise RuntimeError(f"您提供的api-key不满足要求,不包含任何可用于{llm_model}的api-key。") + raise RuntimeError(f"您提供的api-key不满足要求,不包含任何可用于{llm_model}的api-key。您可能选择了错误的模型或请求源。") api_key = random.choice(avail_key_list) # 随机负载均衡 return api_key @lru_cache(maxsize=128) def read_single_conf_with_lru_cache(arg): - from colorful import print亮红, print亮绿 + from colorful import print亮红, print亮绿, print亮蓝 try: r = getattr(importlib.import_module('config_private'), arg) except: r = getattr(importlib.import_module('config'), arg) # 在读取API_KEY时,检查一下是不是忘了改config if arg == 'API_KEY': + print亮蓝(f"[API_KEY] 本项目现已支持OpenAI和API2D的api-key。也支持同时填写多个api-key,如API_KEY=\"openai-key1,openai-key2,api2d-key3\"") + print亮蓝(f"[API_KEY] 您既可以在config.py中修改api-key(s),也可以在问题输入区输入临时的api-key(s),然后回车键提交后即可生效。") if is_any_api_key(r): print亮绿(f"[API_KEY] 您的 API_KEY 是: {r[:15]}*** API_KEY 导入成功") else: