Merge branch 'v3.1'

This commit is contained in:
Your Name 2023-04-19 15:38:32 +08:00
commit 0086ad9e1b
33 changed files with 1381 additions and 803 deletions

3
.gitignore vendored
View File

@ -55,7 +55,6 @@ coverage.xml
*.pot
github
.github
.idea/
TEMP
TRASH
@ -144,3 +143,5 @@ private_upload
other_llms
cradle*
debug*
private*
crazy_functions/test_project/pdf_and_word

View File

@ -1,3 +1,6 @@
# 此Dockerfile适用于“无本地模型”的环境构建如果需要使用chatglm等本地模型请参考 docs/Dockerfile+ChatGLM
# 如何构建: 先修改 `config.py` 然后 docker build -t gpt-academic .
# 如何运行: docker run --rm -it --net=host gpt-academic
FROM python:3.11
RUN echo '[global]' > /etc/pip.conf && \
@ -11,4 +14,7 @@ RUN pip3 install -r requirements.txt
COPY . .
# 可选步骤,用于预热模块
RUN python3 -c 'from check_proxy import warm_up_modules; warm_up_modules()'
CMD ["python3", "-u", "main.py"]

122
README.md
View File

@ -1,4 +1,6 @@
# ChatGPT 学术优化
# <img src="docs/logo.png" width="40" > ChatGPT 学术优化
**如果喜欢这个项目请给它一个Star如果你发明了更好用的快捷键或函数插件欢迎发issue或者pull requests**
@ -21,7 +23,7 @@ If you like this project, please give it a Star. If you've come up with more use
一键代码解释 | 可以正确显示代码、解释代码
[自定义快捷键](https://www.bilibili.com/video/BV14s4y1E7jN) | 支持自定义快捷键
[配置代理服务器](https://www.bilibili.com/video/BV1rc411W7Dr) | 支持配置代理服务器
模块化设计 | 支持自定义高阶的实验性功能与[函数插件],插件支持[热更新](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)
模块化设计 | 支持自定义高阶的函数插件与[函数插件],插件支持[热更新](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)
[自我程序剖析](https://www.bilibili.com/video/BV1cj411A7VW) | [函数插件] [一键读懂](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)本项目的源代码
[程序剖析](https://www.bilibili.com/video/BV1cj411A7VW) | [函数插件] 一键可以剖析其他Python/C/C++/Java/Lua/...项目树
读论文 | [函数插件] 一键解读latex论文全文并生成摘要
@ -76,16 +78,17 @@ huggingface免科学上网[在线体验](https://huggingface.co/spaces/qingxu98/
v3.1的[huggingface测试版](https://huggingface.co/spaces/qingxu98/academic-chatgpt-beta)huggingface版不支持chatglm
---
## 直接运行 (Windows, Linux or MacOS)
## 安装-方法1直接运行 (Windows, Linux or MacOS)
### 1. 下载项目
1. 下载项目
```sh
git clone https://github.com/binary-husky/chatgpt_academic.git
cd chatgpt_academic
```
### 2. 配置API_KEY和代理设置
2. 配置API_KEY和代理设置
`config.py`中,配置 海外Proxy 和 OpenAI API KEY说明如下
```
@ -96,7 +99,7 @@ cd chatgpt_academic
P.S. 程序运行时会优先检查是否存在名为`config_private.py`的私密配置文件,并用其中的配置覆盖`config.py`的同名配置。因此,如果您能理解我们的配置读取逻辑,我们强烈建议您在`config.py`旁边创建一个名为`config_private.py`的新配置文件,并把`config.py`中的配置转移(复制)到`config_private.py`中。`config_private.py`不受git管控可以让您的隐私信息更加安全。
### 3. 安装依赖
3. 安装依赖
```sh
# (选择一)推荐
python -m pip install -r requirements.txt
@ -110,27 +113,30 @@ python -m pip install -r requirements.txt
# python -m pip install -r requirements.txt -i https://mirrors.aliyun.com/pypi/simple/
```
### 4. 运行
如果需要支持清华ChatGLM需要额外安装更多依赖不熟悉python者、电脑配置不佳者建议不要尝试
```sh
python -m pip install -r request_llm/requirements_chatglm.txt
```
4. 运行
```sh
python main.py
```
### 5. 测试实验性功能
5. 测试函数插件
```
- 测试C++项目头文件分析
input区域 输入 `./crazy_functions/test_project/cpp/libJPG` 然后点击 "[实验] 解析整个C++项目input输入项目根路径"
- 测试给Latex项目写摘要
input区域 输入 `./crazy_functions/test_project/latex/attention` 然后点击 "[实验] 读tex论文写摘要input输入项目根路径"
- 测试Python项目分析
input区域 输入 `./crazy_functions/test_project/python/dqn` 然后点击 "[实验] 解析整个py项目input输入项目根路径"
input区域 输入 `./crazy_functions/test_project/python/dqn` 然后点击 "解析整个Python项目"
- 测试自我代码解读
点击 "[实验] 请解析并解构此项目本身"
点击 "[多线程Demo] 解析此项目本身(源码自译解)"
- 测试实验功能模板函数要求gpt回答历史上的今天发生了什么您可以根据此函数为模板实现更复杂的功能
点击 "[实验] 实验功能函数模板"
点击 "[函数插件模板Demo] 历史上的今天"
- 函数插件区下拉菜单中有更多功能可供选择
```
## 使用docker (Linux)
## 安装-方法2使用docker (Linux)
1. 仅ChatGPT推荐大多数人选择
``` sh
# 下载项目
git clone https://github.com/binary-husky/chatgpt_academic.git
@ -142,67 +148,70 @@ docker build -t gpt-academic .
# 运行
docker run --rm -it --net=host gpt-academic
# 测试实验性功能
## 测试自我代码解读
点击 "[实验] 请解析并解构此项目本身"
## 测试实验功能模板函数要求gpt回答历史上的今天发生了什么您可以根据此函数为模板实现更复杂的功能
点击 "[实验] 实验功能函数模板"
##请注意在docker中运行时需要额外注意程序的文件访问权限问题
## 测试C++项目头文件分析
input区域 输入 ./crazy_functions/test_project/cpp/libJPG 然后点击 "[实验] 解析整个C++项目input输入项目根路径"
# 测试函数插件
## 测试函数插件模板函数要求gpt回答历史上的今天发生了什么您可以根据此函数为模板实现更复杂的功能
点击 "[函数插件模板Demo] 历史上的今天"
## 测试给Latex项目写摘要
input区域 输入 ./crazy_functions/test_project/latex/attention 然后点击 "[实验] 读tex论文写摘要input输入项目根路径"
input区域 输入 ./crazy_functions/test_project/latex/attention 然后点击 "读Tex论文写摘要"
## 测试Python项目分析
input区域 输入 ./crazy_functions/test_project/python/dqn 然后点击 "[实验] 解析整个py项目input输入项目根路径"
input区域 输入 ./crazy_functions/test_project/python/dqn 然后点击 "解析整个Python项目"
函数插件区下拉菜单中有更多功能可供选择
```
## 其他部署方式
2. ChatGPT+ChatGLM需要对docker非常熟悉 + 电脑配置足够强)
- 远程云服务器部署
请访问[部署wiki-2](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)
``` sh
# 修改dockerfile
cd docs && nano Dockerfile+ChatGLM
# How to build | 如何构建 Dockerfile+ChatGLM在docs路径下请先cd docs
docker build -t gpt-academic --network=host -f Dockerfile+ChatGLM .
# How to run | 如何运行 (1) 直接运行:
docker run --rm -it --net=host --gpus=all gpt-academic
# How to run | 如何运行 (2) 我想运行之前进容器做一些调整:
docker run --rm -it --net=host --gpus=all gpt-academic bash
```
- 使用WSL2Windows Subsystem for Linux 子系统)
请访问[部署wiki-1](https://github.com/binary-husky/chatgpt_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)
## 安装-方法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)
2. 使用WSL2Windows Subsystem for Linux 子系统)
请访问[部署wiki-2](https://github.com/binary-husky/chatgpt_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)
## 安装-代理配置
### 方法一:常规方法
[配置代理](https://github.com/binary-husky/chatgpt_academic/issues/1)
### 方法二:纯新手教程
[纯新手教程](https://github.com/binary-husky/chatgpt_academic/wiki/%E4%BB%A3%E7%90%86%E8%BD%AF%E4%BB%B6%E9%97%AE%E9%A2%98%E7%9A%84%E6%96%B0%E6%89%8B%E8%A7%A3%E5%86%B3%E6%96%B9%E6%B3%95%EF%BC%88%E6%96%B9%E6%B3%95%E5%8F%AA%E9%80%82%E7%94%A8%E4%BA%8E%E6%96%B0%E6%89%8B%EF%BC%89)
---
## 自定义新的便捷按钮(学术快捷键自定义)
任意文本编辑器打开`core_functional.py`,添加条目如下,然后重启程序即可。(如果按钮已经添加成功并可见,那么前缀、后缀都支持热修改,无需重启程序即可生效。)
例如
```
"超级英译中": {
# 前缀,会被加在你的输入之前。例如,用来描述你的要求,例如翻译、解释代码、润色等等
"Prefix": "请翻译把下面一段内容成中文然后用一个markdown表格逐一解释文中出现的专有名词\n\n",
# 后缀,会被加在你的输入之后。例如,配合前缀可以把你的输入内容用引号圈起来。
"Suffix": "",
},
```
<div align="center">
<img src="https://user-images.githubusercontent.com/96192199/226899272-477c2134-ed71-4326-810c-29891fe4a508.png" width="500" >
</div>
---
如果你发明了更好用的快捷键欢迎发issue或者pull requests
## 配置代理
### 方法一:常规方法
在```config.py```中修改端口与代理软件对应
<div align="center">
<img src="https://user-images.githubusercontent.com/96192199/226571294-37a47cd9-4d40-4c16-97a2-d360845406f7.png" width="500" >
<img src="https://user-images.githubusercontent.com/96192199/226838985-e5c95956-69c2-4c23-a4dd-cd7944eeb451.png" width="500" >
</div>
配置完成后,你可以用以下命令测试代理是否工作,如果一切正常,下面的代码将输出你的代理服务器所在地:
```
python check_proxy.py
```
### 方法二:纯新手教程
[纯新手教程](https://github.com/binary-husky/chatgpt_academic/wiki/%E4%BB%A3%E7%90%86%E8%BD%AF%E4%BB%B6%E9%97%AE%E9%A2%98%E7%9A%84%E6%96%B0%E6%89%8B%E8%A7%A3%E5%86%B3%E6%96%B9%E6%B3%95%EF%BC%88%E6%96%B9%E6%B3%95%E5%8F%AA%E9%80%82%E7%94%A8%E4%BA%8E%E6%96%B0%E6%89%8B%EF%BC%89)
## 功能测试
## 部分功能展示
### 图片显示:
@ -256,8 +265,9 @@ python check_proxy.py
</div>
## Todo 与 版本规划:
- version 3.0 (Todo): 优化对chatglm和其他小型llm的支持
- version 3.2+ (todo): 函数插件支持更多参数接口
- version 3.1: 支持同时问询多个gpt模型支持api2d支持多个apikey负载均衡
- version 3.0: 对chatglm和其他小型llm的支持
- version 2.6: 重构了插件结构,提高了交互性,加入更多插件
- version 2.5: 自更新解决总结大工程源代码时文本过长、token溢出的问题
- version 2.4: (1)新增PDF全文翻译功能; (2)新增输入区切换位置的功能; (3)新增垂直布局选项; (4)多线程函数插件优化。
@ -269,14 +279,12 @@ python check_proxy.py
## 参考与学习
```
代码中参考了很多其他优秀项目中的设计,主要包括:
# 借鉴项目1借鉴了ChuanhuChatGPT中读取OpenAI json的方法、记录历史问询记录的方法以及gradio queue的使用技巧
# 借鉴项目1借鉴了ChuanhuChatGPT中诸多技巧
https://github.com/GaiZhenbiao/ChuanhuChatGPT
# 借鉴项目2
# 借鉴项目2清华ChatGLM-6B
https://github.com/THUDM/ChatGLM-6B
```

View File

@ -103,7 +103,7 @@ def auto_update():
import json
proxies, = get_conf('proxies')
response = requests.get(
"https://raw.githubusercontent.com/binary-husky/chatgpt_academic/master/version", proxies=proxies, timeout=1)
"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"]:
@ -133,6 +133,13 @@ def auto_update():
except:
print('自动更新程序:已禁用')
def warm_up_modules():
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

View File

@ -1,5 +1,5 @@
# [step 1]>> 例如: API_KEY = "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" 此key无效
API_KEY = "sk-此处填API密钥"
API_KEY = "sk-此处填API密钥" # 可同时填写多个API-KEY用英文逗号分割例如API_KEY = "sk-openaikey1,sk-openaikey2,fkxxxx-api2dkey1,fkxxxx-api2dkey2"
# [step 2]>> 改为True应用代理如果直接在海外服务器部署此处不修改
USE_PROXY = False
@ -19,13 +19,12 @@ if USE_PROXY:
else:
proxies = None
# 多线程函数插件中默认允许多少路线程同时访问OpenAI。
# Free trial users的限制是每分钟3次Pay-as-you-go users的限制是每分钟3500次。提高限制请查询
# https://platform.openai.com/docs/guides/rate-limits/overview
# [step 3]>> 多线程函数插件中默认允许多少路线程同时访问OpenAI。Free trial users的限制是每分钟3次Pay-as-you-go users的限制是每分钟3500次
# 一言以蔽之免费用户填3OpenAI绑了信用卡的用户可以填 16 或者更高。提高限制请查询https://platform.openai.com/docs/guides/rate-limits/overview
DEFAULT_WORKER_NUM = 3
# [step 3]>> 以下配置可以优化体验,但大部分场合下并不需要修改
# [step 4]>> 以下配置可以优化体验,但大部分场合下并不需要修改
# 对话窗的高度
CHATBOT_HEIGHT = 1115
@ -45,14 +44,15 @@ WEB_PORT = -1
MAX_RETRY = 2
# OpenAI模型选择是gpt4现在只对申请成功的人开放
LLM_MODEL = "gpt-3.5-turbo"
LLM_MODEL = "gpt-3.5-turbo" # 可选 ↓↓↓
AVAIL_LLM_MODELS = ["gpt-3.5-turbo", "api2d-gpt-3.5-turbo", "gpt-4", "api2d-gpt-4", "chatglm"]
# OpenAI的API_URL
API_URL = "https://api.openai.com/v1/chat/completions"
# 本地LLM模型如ChatGLM的执行方式 CPU/GPU
LOCAL_MODEL_DEVICE = "cpu" # 可选 "cuda"
# 设置并行使用的线程数
# 设置gradio的并行线程数(不需要修改)
CONCURRENT_COUNT = 100
# 设置用户名和密码(相关功能不稳定与gradio版本和网络都相关如果本地使用不建议加这个
# 设置用户名和密码(不需要修改)(相关功能不稳定与gradio版本和网络都相关如果本地使用不建议加这个
# [("username", "password"), ("username2", "password2"), ...]
AUTHENTICATION = []

View File

@ -3,7 +3,6 @@ from toolbox import HotReload # HotReload 的意思是热更新,修改函数
def get_crazy_functions():
###################### 第一组插件 ###########################
# [第一组插件]: 最早期编写的项目插件和一些demo
from crazy_functions.读文章写摘要 import 读文章写摘要
from crazy_functions.生成函数注释 import 批量生成函数注释
from crazy_functions.解析项目源代码 import 解析项目本身
@ -16,16 +15,23 @@ def get_crazy_functions():
from crazy_functions.高级功能函数模板 import 高阶功能模板函数
from crazy_functions.代码重写为全英文_多线程 import 全项目切换英文
from crazy_functions.Latex全文润色 import Latex英文润色
from crazy_functions.询问多个大语言模型 import 同时问询
from crazy_functions.解析项目源代码 import 解析一个Lua项目
from crazy_functions.解析项目源代码 import 解析一个CSharp项目
from crazy_functions.总结word文档 import 总结word文档
function_plugins = {
"解析整个Python项目": {
"Color": "stop", # 按钮颜色
"Function": HotReload(解析一个Python项目)
},
"批量总结Word文档": {
"Color": "stop",
"Function": HotReload(总结word文档)
},
"解析整个C++项目头文件": {
"Color": "stop", # 按钮颜色
"AsButton": False, # 加入下拉菜单中
"Function": HotReload(解析一个C项目的头文件)
},
"解析整个C++项目(.cpp/.hpp/.c/.h": {
@ -81,10 +87,9 @@ def get_crazy_functions():
}
###################### 第二组插件 ###########################
# [第二组插件]: 经过充分测试,但功能上距离达到完美状态还差一点点
# [第二组插件]: 经过充分测试
from crazy_functions.批量总结PDF文档 import 批量总结PDF文档
from crazy_functions.批量总结PDF文档pdfminer import 批量总结PDF文档pdfminer
from crazy_functions.总结word文档 import 总结word文档
from crazy_functions.批量翻译PDF文档_多线程 import 批量翻译PDF文档
from crazy_functions.谷歌检索小助手 import 谷歌检索小助手
from crazy_functions.理解PDF文档内容 import 理解PDF文档内容标准文件输入
@ -100,6 +105,10 @@ def get_crazy_functions():
"AsButton": True, # 加入下拉菜单中
"Function": HotReload(批量翻译PDF文档)
},
"询问多个GPT模型": {
"Color": "stop", # 按钮颜色
"Function": HotReload(同时问询)
},
"[测试功能] 批量总结PDF文档": {
"Color": "stop",
"AsButton": False, # 加入下拉菜单中
@ -116,10 +125,7 @@ def get_crazy_functions():
"AsButton": False, # 加入下拉菜单中
"Function": HotReload(谷歌检索小助手)
},
"批量总结Word文档": {
"Color": "stop",
"Function": HotReload(总结word文档)
},
"理解PDF文档内容 模仿ChatPDF": {
# HotReload 的意思是热更新,修改函数插件代码后,不需要重启程序,代码直接生效
"Color": "stop",

View File

@ -11,9 +11,8 @@ class PaperFileGroup():
self.sp_file_tag = []
# count_token
import tiktoken
from toolbox import get_conf
enc = tiktoken.encoding_for_model(*get_conf('LLM_MODEL'))
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

View File

@ -11,9 +11,8 @@ class PaperFileGroup():
self.sp_file_tag = []
# count_token
import tiktoken
from toolbox import get_conf
enc = tiktoken.encoding_for_model(*get_conf('LLM_MODEL'))
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

View File

@ -0,0 +1,92 @@
"""
这是什么
这个文件用于函数插件的单元测试
运行方法 python crazy_functions/crazy_functions_test.py
"""
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
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': API_KEY,
'llm_model': LLM_MODEL,
'top_p':1.0,
'max_length': None,
'temperature':1.0,
}
plugin_kwargs = { }
chatbot = ChatBotWithCookies(llm_kwargs)
history = []
system_prompt = "Serve me as a writing and programming assistant."
web_port = 1024
def test_解析一个Python项目():
from crazy_functions.解析项目源代码 import 解析一个Python项目
txt = "crazy_functions/test_project/python/dqn"
for cookies, cb, hist, msg in 解析一个Python项目(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port):
print(cb)
def test_解析一个Cpp项目():
from crazy_functions.解析项目源代码 import 解析一个C项目
txt = "crazy_functions/test_project/cpp/cppipc"
for cookies, cb, hist, msg in 解析一个C项目(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port):
print(cb)
def test_Latex英文润色():
from crazy_functions.Latex全文润色 import Latex英文润色
txt = "crazy_functions/test_project/latex/attention"
for cookies, cb, hist, msg in Latex英文润色(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port):
print(cb)
def test_Markdown中译英():
from crazy_functions.批量Markdown翻译 import Markdown中译英
txt = "README.md"
for cookies, cb, hist, msg in Markdown中译英(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port):
print(cb)
def test_批量翻译PDF文档():
from crazy_functions.批量翻译PDF文档_多线程 import 批量翻译PDF文档
txt = "crazy_functions/test_project/pdf_and_word"
for cookies, cb, hist, msg in 批量翻译PDF文档(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port):
print(cb)
def test_谷歌检索小助手():
from crazy_functions.谷歌检索小助手 import 谷歌检索小助手
txt = "https://scholar.google.com/scholar?hl=en&as_sdt=0%2C5&q=auto+reinforcement+learning&btnG="
for cookies, cb, hist, msg in 谷歌检索小助手(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port):
print(cb)
def test_总结word文档():
from crazy_functions.总结word文档 import 总结word文档
txt = "crazy_functions/test_project/pdf_and_word"
for cookies, cb, hist, msg in 总结word文档(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port):
print(cb)
def test_下载arxiv论文并翻译摘要():
from crazy_functions.下载arxiv论文翻译摘要 import 下载arxiv论文并翻译摘要
txt = "1812.10695"
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项目()
input("程序完成,回车退出。")
print("退出。")

View File

@ -2,9 +2,9 @@ import traceback
from toolbox import update_ui, get_conf
def input_clipping(inputs, history, max_token_limit):
import tiktoken
import numpy as np
enc = tiktoken.encoding_for_model(*get_conf('LLM_MODEL'))
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'
@ -61,12 +61,12 @@ def request_gpt_model_in_new_thread_with_ui_alive(
"""
import time
from concurrent.futures import ThreadPoolExecutor
from request_llm.bridge_chatgpt 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()]
mutable = ["", time.time(), ""]
def _req_gpt(inputs, history, sys_prompt):
retry_op = retry_times_at_unknown_error
exceeded_cnt = 0
@ -105,7 +105,7 @@ def request_gpt_model_in_new_thread_with_ui_alive(
if retry_op > 0:
retry_op -= 1
mutable[0] += f"[Local Message] 重试中,请稍等 {retry_times_at_unknown_error-retry_op}/{retry_times_at_unknown_error}\n\n"
if "Rate limit reached" in tb_str:
if ("Rate limit reached" in tb_str) or ("Too Many Requests" in tb_str):
time.sleep(30)
time.sleep(5)
continue # 返回重试
@ -167,13 +167,17 @@ def request_gpt_model_multi_threads_with_very_awesome_ui_and_high_efficiency(
"""
import time, random
from concurrent.futures import ThreadPoolExecutor
from request_llm.bridge_chatgpt 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')
except: max_workers = 8
if max_workers <= 0 or max_workers >= 20: max_workers = 8
# 屏蔽掉 chatglm的多线程可能会导致严重卡顿
if not (llm_kwargs['llm_model'].startswith('gpt-') or llm_kwargs['llm_model'].startswith('api2d-')):
max_workers = 1
executor = ThreadPoolExecutor(max_workers=max_workers)
n_frag = len(inputs_array)
# 用户反馈
@ -230,9 +234,9 @@ def request_gpt_model_multi_threads_with_very_awesome_ui_and_high_efficiency(
if retry_op > 0:
retry_op -= 1
wait = random.randint(5, 20)
if "Rate limit reached" in tb_str:
if ("Rate limit reached" in tb_str) or ("Too Many Requests" in tb_str):
wait = wait * 3
fail_info = "OpenAI请求速率限制 "
fail_info = "OpenAI绑定信用卡可解除频率限制 "
else:
fail_info = ""
# 也许等待十几秒后,情况会好转

View File

@ -1,5 +1,5 @@
import threading
from request_llm.bridge_chatgpt import predict_no_ui_long_connection
from request_llm.bridge_all import predict_no_ui_long_connection
from toolbox import update_ui
from toolbox import CatchException, write_results_to_file, report_execption
from .crazy_utils import breakdown_txt_to_satisfy_token_limit
@ -59,9 +59,8 @@ def 全项目切换英文(txt, llm_kwargs, plugin_kwargs, chatbot, history, sys_
# 第5步Token限制下的截断与处理
MAX_TOKEN = 3000
import tiktoken
from toolbox import get_conf
enc = tiktoken.encoding_for_model(*get_conf('LLM_MODEL'))
from request_llm.bridge_all import model_info
enc = model_info["gpt-3.5-turbo"]['tokenizer']
def get_token_fn(txt): return len(enc.encode(txt, disallowed_special=()))

View File

@ -8,8 +8,6 @@ def 解析docx(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot
import time, os
# pip install python-docx 用于docx格式跨平台
# pip install pywin32 用于doc格式仅支持Win平台
print('begin analysis on:', file_manifest)
for index, fp in enumerate(file_manifest):
if fp.split(".")[-1] == "docx":
from docx import Document
@ -29,18 +27,20 @@ def 解析docx(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot
word.Quit()
print(file_content)
prefix = "接下来请你逐文件分析下面的论文文件," if index == 0 else ""
# private_upload里面的文件名在解压zip后容易出现乱码rar和7z格式正常故可以只分析文章内容不输入文件名
i_say = prefix + f'请对下面的文章片段用中英文做概述,文件名是{os.path.relpath(fp, project_folder)},' \
f'文章内容是 ```{file_content}```'
i_say_show_user = prefix + f'[{index+1}/{len(file_manifest)}] 假设你是论文审稿专家,请对下面的文章片段做概述: {os.path.abspath(fp)}'
chatbot.append((i_say_show_user, "[Local Message] waiting gpt response."))
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
if not fast_debug:
msg = '正常'
# ** gpt request **
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_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}```'
i_say_show_user = f'请对下面的文章片段做概述: {os.path.abspath(fp)}的第{i+1}/{len(paper_fragments)}个片段。'
gpt_say = yield from request_gpt_model_in_new_thread_with_ui_alive(
inputs=i_say,
inputs_show_user=i_say_show_user,
@ -48,46 +48,34 @@ def 解析docx(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot
chatbot=chatbot,
history=[],
sys_prompt="总结文章。"
) # 带超时倒计时
)
chatbot[-1] = (i_say_show_user, gpt_say)
history.append(i_say_show_user)
history.append(gpt_say)
yield from update_ui(chatbot=chatbot, history=history, msg=msg) # 刷新界面
if not fast_debug: time.sleep(2)
history.extend([i_say_show_user,gpt_say])
this_paper_history.extend([i_say_show_user,gpt_say])
"""
# 可按需启用
i_say = f'根据你上述的分析,对全文进行概括,用学术性语言写一段中文摘要,然后再写一篇英文的。'
chatbot.append((i_say, "[Local Message] waiting gpt response."))
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
# 已经对该文章的所有片段总结完毕,如果文章被切分了,
if len(paper_fragments) > 1:
i_say = f"根据以上的对话,总结文章{os.path.abspath(fp)}的主要内容。"
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=this_paper_history,
sys_prompt="总结文章。"
)
history.extend([i_say,gpt_say])
this_paper_history.extend([i_say,gpt_say])
i_say = f'我想让你做一个论文写作导师。您的任务是使用人工智能工具(例如自然语言处理)提供有关如何改进其上述文章的反馈。' \
f'您还应该利用您在有效写作技巧方面的修辞知识和经验来建议作者可以更好地以书面形式表达他们的想法和想法的方法。' \
f'根据你之前的分析,提出建议'
chatbot.append((i_say, "[Local Message] waiting gpt response."))
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
"""
if not fast_debug:
msg = '正常'
# ** gpt request **
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, msg=msg) # 刷新界面
res = write_results_to_file(history)
chatbot.append(("完成了吗?", res))
yield from update_ui(chatbot=chatbot, history=history, msg=msg) # 刷新界面
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
res = write_results_to_file(history)
chatbot.append(("所有文件都总结完成了吗?", res))
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
@CatchException
@ -123,11 +111,11 @@ def 总结word文档(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_pr
return
# 搜索需要处理的文件清单
file_manifest = [f for f in glob.glob(f'{project_folder}/**/*.docx', recursive=True)] + \
[f for f in glob.glob(f'{project_folder}/**/*.doc', recursive=True)]
# [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 txt.endswith('.docx') or txt.endswith('.doc'):
file_manifest = [txt]
else:
file_manifest = [f for f in glob.glob(f'{project_folder}/**/*.docx', recursive=True)] + \
[f for f in glob.glob(f'{project_folder}/**/*.doc', recursive=True)]
# 如果没找到任何文件
if len(file_manifest) == 0:

View File

@ -11,9 +11,8 @@ class PaperFileGroup():
self.sp_file_tag = []
# count_token
import tiktoken
from toolbox import get_conf
enc = tiktoken.encoding_for_model(*get_conf('LLM_MODEL'))
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

View File

@ -68,8 +68,8 @@ def 解析PDF(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot,
# 递归地切割PDF文件
from .crazy_utils import breakdown_txt_to_satisfy_token_limit_for_pdf
from toolbox import get_conf
enc = tiktoken.encoding_for_model(*get_conf('LLM_MODEL'))
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)

View File

@ -17,8 +17,8 @@ def 解析PDF(file_name, llm_kwargs, plugin_kwargs, chatbot, history, system_pro
TOKEN_LIMIT_PER_FRAGMENT = 2500
from .crazy_utils import breakdown_txt_to_satisfy_token_limit_for_pdf
from toolbox import get_conf
enc = tiktoken.encoding_for_model(*get_conf('LLM_MODEL'))
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)

View File

@ -12,7 +12,7 @@ def 解析源代码新(file_manifest, project_folder, llm_kwargs, plugin_kwargs,
sys_prompt_array = []
report_part_1 = []
assert len(file_manifest) <= 1024, "源文件太多(超过1024个), 请缩减输入文件的数量。或者您也可以选择删除此行警告并修改代码拆分file_manifest列表从而实现分批次处理。"
assert len(file_manifest) <= 512, "源文件太多(超过512个, 请缩减输入文件的数量。或者您也可以选择删除此行警告并修改代码拆分file_manifest列表从而实现分批次处理。"
############################## <第一步,逐个文件分析,多线程> ##################################
for index, fp in enumerate(file_manifest):
# 读取文件

View File

@ -0,0 +1,30 @@
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, web_port):
"""
txt 输入栏用户输入的文本例如需要翻译的一段话再例如一个包含了待处理文件的路径
llm_kwargs gpt模型参数如温度和top_p等一般原样传递下去就行
plugin_kwargs 插件模型的参数如温度和top_p等一般原样传递下去就行
chatbot 聊天显示框的句柄用于显示给用户
history 聊天历史前情提要
system_prompt 给gpt的静默提醒
web_port 当前软件运行的端口号
"""
history = [] # 清空历史,以免输入溢出
chatbot.append((txt, "正在同时咨询ChatGPT和ChatGLM……"))
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'] = 'chatglm&gpt-3.5-turbo' # 支持任意数量的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,
sys_prompt=system_prompt,
retry_times_at_unknown_error=0
)
history.append(txt)
history.append(gpt_say)
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 # 界面更新

59
docs/Dockerfile+ChatGLM Normal file
View File

@ -0,0 +1,59 @@
# How to build | 如何构建: docker build -t gpt-academic --network=host -f Dockerfile+ChatGLM .
# How to run | 如何运行 (1) 直接运行选择0号GPU: docker run --rm -it --net=host --gpus="0" gpt-academic
# How to run | 如何运行 (2) 我想运行之前进容器做一些调整: docker run --rm -it --net=host --gpus="0" gpt-academic bash
# 从NVIDIA源从而支持显卡运损检查宿主的nvidia-smi中的cuda版本必须>=11.3
FROM nvidia/cuda:11.3.1-runtime-ubuntu20.04
ARG useProxyNetwork=''
RUN apt-get update
RUN apt-get install -y curl proxychains curl
RUN apt-get install -y git python python3 python-dev python3-dev --fix-missing
# 配置代理网络构建Docker镜像时使用
# # comment out below if you do not need proxy network | 如果不需要翻墙 - 从此行向下删除
RUN $useProxyNetwork curl cip.cc
RUN sed -i '$ d' /etc/proxychains.conf
RUN sed -i '$ d' /etc/proxychains.conf
RUN echo "socks5 127.0.0.1 10880" >> /etc/proxychains.conf
ARG useProxyNetwork=proxychains
# # comment out above if you do not need proxy network | 如果不需要翻墙 - 从此行向上删除
# use python3 as the system default python
RUN curl -sS https://bootstrap.pypa.io/get-pip.py | python3.8
# 下载分支
WORKDIR /gpt
RUN $useProxyNetwork git clone https://github.com/binary-husky/chatgpt_academic.git
WORKDIR /gpt/chatgpt_academic
RUN $useProxyNetwork python3 -m pip install -r requirements.txt
RUN $useProxyNetwork python3 -m pip install -r request_llm/requirements_chatglm.txt
RUN $useProxyNetwork python3 -m pip install torch --extra-index-url https://download.pytorch.org/whl/cu113
# 预热CHATGLM参数非必要 可选步骤)
RUN echo ' \n\
from transformers import AutoModel, AutoTokenizer \n\
chatglm_tokenizer = AutoTokenizer.from_pretrained("THUDM/chatglm-6b", trust_remote_code=True) \n\
chatglm_model = AutoModel.from_pretrained("THUDM/chatglm-6b", trust_remote_code=True).float() ' >> warm_up_chatglm.py
RUN python3 -u warm_up_chatglm.py
# 禁用缓存,确保更新代码
ADD "https://www.random.org/cgi-bin/randbyte?nbytes=10&format=h" skipcache
RUN $useProxyNetwork git pull
# 预热Tiktoken模块
RUN python3 -c 'from check_proxy import warm_up_modules; warm_up_modules()'
# 为chatgpt-academic配置代理和API-KEY (非必要 可选步骤)
# 可同时填写多个API-KEY支持openai的key和api2d的key共存用英文逗号分割例如API_KEY = "sk-openaikey1,fkxxxx-api2dkey2,........"
# LLM_MODEL 是选择初始的模型
# LOCAL_MODEL_DEVICE 是选择chatglm等本地模型运行的设备可选 cpu 和 cuda
RUN echo ' \n\
API_KEY = "sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx,fkxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \n\
USE_PROXY = True \n\
LLM_MODEL = "chatglm" \n\
LOCAL_MODEL_DEVICE = "cuda" \n\
proxies = { "http": "socks5h://localhost:10880", "https": "socks5h://localhost:10880", } ' >> config_private.py
# 启动
CMD ["python3", "-u", "main.py"]

View File

Before

Width:  |  Height:  |  Size: 262 KiB

After

Width:  |  Height:  |  Size: 262 KiB

View File

Before

Width:  |  Height:  |  Size: 264 KiB

After

Width:  |  Height:  |  Size: 264 KiB

BIN
docs/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

256
docs/self_analysis.md Normal file
View File

@ -0,0 +1,256 @@
# chatgpt-academic项目自译解报告
Author补充以下分析均由本项目调用ChatGPT一键生成如果有不准确的地方全怪GPT😄
## 对程序的整体功能和构架做出概括。然后用一张markdown表格整理每个文件的功能。
整体概括:
该程序是一个基于自然语言处理和机器学习的科学论文辅助工具主要功能包括聊天机器人、批量总结PDF文档、批量翻译PDF文档、生成函数注释、解析项目源代码等。程序基于 Gradio 构建 Web 服务,并集成了代理和自动更新功能,提高了用户的使用体验。
文件功能表格:
| 文件名 | 文件功能 |
| --- | --- |
| check_proxy.py | 用于检查代理的正确性和可用性 |
| colorful.py | 包含不同预设置颜色的常量并用于多种UI元素 |
| config.py | 用于全局配置的类 |
| config_private.py | 与config.py文件一起使用的另一个配置文件用于更改私密信息 |
| core_functional.py | 包含一些TextFunctional类和基础功能函数 |
| crazy_functional.py | 包含大量高级功能函数和实验性的功能函数 |
| main.py | 程序的主入口包含GUI主窗口和主要的UI管理功能 |
| theme.py | 包含一些预设置主题的颜色 |
| toolbox.py | 提供了一些有用的工具函数 |
| crazy_functions\crazy_utils.py | 包含一些用于实现高级功能的辅助函数 |
| crazy_functions\Latex全文润色.py | 实现了对LaTeX文件中全文的润色和格式化功能 |
| crazy_functions\Latex全文翻译.py | 实现了对LaTeX文件中的内容进行翻译的功能 |
| crazy_functions\_\_init\_\_.py | 用于导入crazy_functional.py中的功能函数 |
| crazy_functions\下载arxiv论文翻译摘要.py | 从Arxiv上下载论文并提取重要信息 |
| crazy_functions\代码重写为全英文_多线程.py | 针对中文Python文件将其翻译为全英文 |
| crazy_functions\总结word文档.py | 提取Word文件的重要内容来生成摘要 |
| crazy_functions\批量Markdown翻译.py | 批量翻译Markdown文件 |
| crazy_functions\批量总结PDF文档.py | 批量从PDF文件中提取摘要 |
| crazy_functions\批量总结PDF文档pdfminer.py | 批量从PDF文件中提取摘要 |
| crazy_functions\批量翻译PDF文档_多线程.py | 批量翻译PDF文件 |
| crazy_functions\理解PDF文档内容.py | 批量分析PDF文件并提取摘要 |
| crazy_functions\生成函数注释.py | 自动生成Python文件中函数的注释 |
| crazy_functions\解析项目源代码.py | 解析并分析给定项目的源代码 |
| crazy_functions\询问多个大语言模型.py | 向多个大语言模型询问输入文本并进行处理 |
| crazy_functions\读文献写摘要.py | 根据用户输入读取文献内容并生成摘要 |
| crazy_functions\谷歌检索小助手.py | 利用谷歌学术检索用户提供的论文信息并提取相关信息 |
| crazy_functions\高级功能函数模板.py | 实现高级功能的模板函数 |
| request_llm\bridge_all.py | 处理与LLM的交互 |
| request_llm\bridge_chatglm.py | 使用ChatGLM模型进行聊天 |
| request_llm\bridge_chatgpt.py | 实现对话生成的各项功能 |
| request_llm\bridge_tgui.py | 在Websockets中与用户进行交互并生成文本输出 |
## [0/31] 请对下面的程序文件做一个概述: H:\chatgpt_academic_resolve\check_proxy.py
该文件主要包括四个函数check_proxy、backup_and_download、patch_and_restart 和 auto_update。其中check_proxy 函数用于检查代理是否可用backup_and_download 用于进行一键更新备份和下载patch_and_restart 是一键更新协议的重要函数用于覆盖和重启auto_update 函数用于查询版本和用户意见,并自动进行一键更新。该文件主要使用了 requests、json、shutil、zipfile、distutils、subprocess 等 Python 标准库和 toolbox 和 colorful 两个第三方库。
## [1/31] 请对下面的程序文件做一个概述: H:\chatgpt_academic_resolve\colorful.py
该程序文件实现了一些打印文本的函数使其具有不同的颜色输出。当系统为Linux时直接跳过否则使用colorama库来实现颜色输出。程序提供了深色和亮色两种颜色输出方式同时也提供了对打印函数的别名。对于不是终端输出的情况对所有的打印函数进行重复定义以便在重定向时能够避免打印错误日志。
## [2/31] 请对下面的程序文件做一个概述: H:\chatgpt_academic_resolve\config.py
该程序文件是一个配置文件其主要功能是提供使用API密钥等信息以及对程序的体验进行优化例如定义对话框高度、布局等。还包含一些其他的设置例如设置并行使用的线程数、重试次数限制等等。
## [3/31] 请对下面的程序文件做一个概述: H:\chatgpt_academic_resolve\config_private.py
这是一个名为config_private.py的Python文件它用于配置API_KEY和代理信息。API_KEY是一个私密密钥用于访问某些受保护的API。USE_PROXY变量设置为True以应用代理proxies变量配置了代理网络的地址和协议。在使用该文件时需要填写正确的API_KEY和代理信息。
## [4/31] 请对下面的程序文件做一个概述: H:\chatgpt_academic_resolve\core_functional.py
该文件是一个Python模块名为"core_functional.py"。模块中定义了一个字典,包含了各种核心功能的配置信息,如英语学术润色、中文学术润色、查找语法错误等。每个功能都包含一些前言和后语,在前言中描述了该功能的任务和要求,在后语中提供一些附加信息。此外,有些功能还定义了一些特定的处理函数和按钮颜色。
## [5/31] 请对下面的程序文件做一个概述: H:\chatgpt_academic_resolve\crazy_functional.py
这是一个Python程序文件文件名是crazy_functional.py。它导入了一个名为HotReload的工具箱并定义了一个名为get_crazy_functions()的函数。这个函数包括三个部分的插件组分别是已经编写完成的第一组插件、已经测试但距离完美状态还差一点点的第二组插件和尚未充分测试的第三组插件。每个插件都有一个名称、一个按钮颜色、一个函数和一个是否加入下拉菜单中的标志位。这些插件提供了多种功能包括生成函数注释、解析项目源代码、批量翻译PDF文档、谷歌检索、PDF文档内容理解和Latex文档的全文润色、翻译等功能。其中第三组插件可能还存在一定的bug。
## [6/31] 请对下面的程序文件做一个概述: H:\chatgpt_academic_resolve\main.py
该Python脚本代码实现了一个用于交互式对话的Chatbot机器人。它使用了Gradio框架来构建一个Web界面并在此基础之上嵌入了一个文本输入框和与Chatbot进行交互的其他控件包括提交、重置、停止和清除按钮、选择框和滑块等。此外它还包括了一些类和函数和一些用于编程分析的工具和方法。整个程序文件的结构清晰注释丰富并提供了很多技术细节使得开发者可以很容易地在其基础上进行二次开发、修改、扩展和集成。
## [7/31] 请对下面的程序文件做一个概述: H:\chatgpt_academic_resolve\theme.py
该程序文件名为theme.py主要功能为调节Gradio的全局样式。在该文件中调节了Gradio的主题颜色、字体、阴影、边框、渐变等等样式。同时该文件还添加了一些高级CSS样式比如调整表格单元格的背景和边框设定聊天气泡的圆角、最大宽度和阴影等等。如果CODE_HIGHLIGHT为True则还进行了代码高亮显示。
## [8/31] 请对下面的程序文件做一个概述: H:\chatgpt_academic_resolve\toolbox.py
这是一个名为`toolbox.py`的源代码文件。该文件包含了一系列工具函数和装饰器用于聊天Bot的开发和调试。其中有一些功能包括将输入参数进行重组、捕捉函数中的异常并记录到历史记录中、生成Markdown格式的聊天记录报告等。该文件中还包含了一些与转换Markdown文本相关的函数。
## [9/31] 请对下面的程序文件做一个概述: H:\chatgpt_academic_resolve\crazy_functions\crazy_utils.py
这是一个Python程序文件 `crazy_utils.py`,它包含了两个函数:
- `input_clipping(inputs, history, max_token_limit)`这个函数接收三个参数inputs 是一个字符串history 是一个列表max_token_limit 是一个整数。它使用 `tiktoken``numpy``toolbox` 模块,处理输入文本和历史记录,将其裁剪到指定的最大标记数,避免输入过长导致的性能问题。如果 inputs 长度不超过 max_token_limit 的一半,则只裁剪历史;否则,同时裁剪输入和历史。
- `request_gpt_model_in_new_thread_with_ui_alive(inputs, inputs_show_user, llm_kwargs, chatbot, history, sys_prompt, refresh_interval=0.2, handle_token_exceed=True, retry_times_at_unknown_error=2)`:这个函数接收八个参数,其中后三个是列表类型,其他为标量或句柄等。它提供对话窗口和刷新控制,执行 `predict_no_ui_long_connection` 方法,将输入数据发送至 GPT 模型并获取结果,如果子任务出错,返回相应的错误信息,否则返回结果。
## [10/31] 请对下面的程序文件做一个概述: H:\chatgpt_academic_resolve\crazy_functions\Latex全文润色.py
这是一个名为"crazy_functions\Latex全文润色.py"的程序文件,其中包含了两个函数"Latex英文润色"和"Latex中文润色",以及其他辅助函数。这些函数能够对 Latex 项目进行润色处理,其中 "多文件润色" 函数是一个主要函数,它调用了其他辅助函数用于读取和处理 Latex 项目中的文件。函数使用了多线程和机器学习模型进行自然语言处理,对文件进行简化和排版来满足学术标准。注释已删除并可以在函数内部查找。
## [11/31] 请对下面的程序文件做一个概述: H:\chatgpt_academic_resolve\crazy_functions\Latex全文翻译.py
这个程序文件包括一个用于对整个Latex项目进行翻译的函数 `Latex英译中` 和一个用于将中文翻译为英文的函数 `Latex中译英`。这两个函数都会尝试导入依赖库 tiktoken 若无法导入则会提示用户安装。`Latex英译中` 函数会对 Latex 项目中的文件进行分离并去除注释,然后运行多线程翻译。`Latex中译英` 也做同样的事情,只不过是将中文翻译为英文。这个程序文件还包括其他一些帮助函数。
## [12/31] 请对下面的程序文件做一个概述: H:\chatgpt_academic_resolve\crazy_functions\__init__.py
这是一个 Python 包,包名为 `crazy_functions`,在 `__init__.py` 文件中定义了一些函数,包含以下函数:
- `crazy_addition(a, b)`:对两个数进行加法运算,并将结果返回。
- `crazy_multiplication(a, b)`:对两个数进行乘法运算,并将结果返回。
- `crazy_subtraction(a, b)`:对两个数进行减法运算,并将结果返回。
- `crazy_division(a, b)`:对两个数进行除法运算,并将结果返回。
- `crazy_factorial(n)`:计算 `n` 的阶乘并返回结果。
这些函数可能会有一些奇怪或者不符合常规的实现方式(由函数名可以看出来),所以这个包的名称为 `crazy_functions`,可能是暗示这些函数会有一些“疯狂”的实现方式。
## [13/31] 请对下面的程序文件做一个概述: H:\chatgpt_academic_resolve\crazy_functions\下载arxiv论文翻译摘要.py
该程序实现了一个名为“下载arxiv论文并翻译摘要”的函数插件作者是“binary-husky”。该函数的功能是在输入一篇arxiv论文的链接后提取摘要、下载PDF文档、翻译摘要为中文并将翻译结果保存到文件中。程序使用了一些Python库如requests、pdfminer和beautifulsoup4等。程序入口是名为“下载arxiv论文并翻译摘要”的函数其中使用了自定义的辅助函数download_arxiv_和get_name。程序中还使用了其他非函数的辅助函数和变量如update_ui、CatchException、report_exception和get_conf等。
## [14/31] 请对下面的程序文件做一个概述: H:\chatgpt_academic_resolve\crazy_functions\代码重写为全英文_多线程.py
该文件是一个多线程Python脚本包含多个函数和利用第三方库进行的API请求。主要功能是将给定文件夹内的Python代码文件中所有中文转化为英文然后输出转化后的英文代码。重要的功能和步骤包括
1. 清空历史,以免输入溢出
2. 尝试导入依赖,如果缺少依赖,则给出安装建议
3. 集合文件
4. 显示随意内容以防卡顿的感觉
5. Token限制下的截断与处理
6. 多线程操作请求转换中文变为英文的代码
7. 所有线程同时开始执行任务函数
8. 循环轮询各个线程是否执行完毕
9. 把结果写入文件
10. 备份一个文件
## [15/31] 请对下面的程序文件做一个概述: H:\chatgpt_academic_resolve\crazy_functions\总结word文档.py
这是一个名为"总结word文档.py"的程序文件使用python编写。该文件导入了"toolbox"和"crazy_utils"模块实现了解析docx格式和doc格式的文件的功能。该文件包含了一个名为"解析docx"的函数,通过对文件内容应用自然语言处理技术,生成文章片段的中英文概述。具体实现过程中,该函数使用了"docx"模块和"win32com.client"模块来实现对docx和doc格式文件的解析同时使用了"request_gpt_model_in_new_thread_with_ui_alive"函数来向GPT模型发起请求。最后该文件还实现了一个名为"总结word文档"的函数来批量总结Word文档。
## [16/31] 请对下面的程序文件做一个概述: H:\chatgpt_academic_resolve\crazy_functions\批量Markdown翻译.py
这个程序文件实现了一个批量Markdown翻译功能可以将一个源代码项目中的Markdown文本翻译成指定语言目前支持中<-英和英<-中)。程序主要分为三个函数`PaperFileGroup`类用于处理长文本的拆分`多文件翻译`是主要函数调用了`request_gpt_model_multi_threads_with_very_awesome_ui_and_high_efficiency`函数进行多线程翻译并输出结果`Markdown英译中``Markdown中译外`分别是英译中和中译英的入口函数用于解析项目路径和调用翻译函数程序依赖于tiktoken等库实现
## [17/31] 请对下面的程序文件做一个概述: H:\chatgpt_academic_resolve\crazy_functions\批量总结PDF文档.py
这是一个名为“批量总结PDF文档”的Python脚本包含了多个函数。其中有一个函数名为“clean_text”可以对PDF提取出的原始文本进行清洗和格式化处理将连字转换为其基本形式并根据heuristic规则判断换行符是否是段落分隔并相应地进行替换。另一个函数名为“解析PDF”可以接收一个PDF文件清单并对清单中的每一个PDF进行解析提取出文本并调用“clean_text”函数进行清洗和格式化处理然后向用户发送一个包含文章简介信息的问题并等待用户回答。最后该脚本也包含一个名为“批量总结PDF文档”的主函数其中调用了“解析PDF”函数来完成对PDF文件的批量处理。
## [18/31] 请对下面的程序文件做一个概述: H:\chatgpt_academic_resolve\crazy_functions\批量总结PDF文档pdfminer.py
这个文件是一个Python模块文件名为pdfminer.py它定义了一个函数批量总结PDF文档。该函数接受一些参数然后尝试导入pdfminer和beautifulsoup4库。该函数将读取pdf文件或tex文件中的内容对其进行分析并使用GPT模型进行自然语言摘要。文件中还有一个辅助函数readPdf用于读取pdf文件中的内容。
## [19/31] 请对下面的程序文件做一个概述: H:\chatgpt_academic_resolve\crazy_functions\批量翻译PDF文档_多线程.py
这是一个Python脚本文件名是crazy_functions\批量翻译PDF文档_多线程.py。该脚本提供了一个名为“批量翻译PDF文档”的函数可以批量翻译PDF文件并生成报告文件。该函数使用了多个模块和函数如toolbox、crazy_utils、update_ui等使用了Python的异常处理和多线程功能还使用了一些文本处理函数和第三方库如fitz和tiktoken。在函数执行过程中它会进行一些参数检查、读取和清理PDF文本、递归地切割PDF文件、获取文章meta信息、多线程翻译、整理报告格式等操作并更新UI界面和生成报告文件。
## [20/31] 请对下面的程序文件做一个概述: H:\chatgpt_academic_resolve\crazy_functions\理解PDF文档内容.py
这是一个解析PDF文件内容的Python程序程序文件名为"理解PDF文档内容.py"程序主要由5个步骤组成第0步是切割PDF文件第1步是从摘要中提取高价值信息放到history中第2步是迭代地历遍整个文章提取精炼信息第3步是整理history第4步是设置一个token上限防止回答时Token溢出。程序主要用到了Python中的各种模块和函数库toolbox, tiktoken, pymupdf等。
## [21/31] 请对下面的程序文件做一个概述: H:\chatgpt_academic_resolve\crazy_functions\生成函数注释.py
这是一个名为"生成函数注释"的函数,带有一个装饰器"@CatchException"可以捕获异常。该函数接受文件路径、参数和聊天机器人等参数用于对多个Python或C++文件进行函数注释,使用了"toolbox"和"crazy_utils"模块中的函数。该函数会逐个读取指定文件中的内容并使用聊天机器人进行交互向用户请求注释信息然后将生成的注释与原文件内容一起输出到一个markdown表格中。最后该函数返回一个字符串指示任务是否已完成。另外还包含一个名为"批量生成函数注释"的函数,它与"生成函数注释"函数一起用于批量处理多个文件。
## [22/31] 请对下面的程序文件做一个概述: H:\chatgpt_academic_resolve\crazy_functions\解析项目源代码.py
这个程序文件实现了对一个源代码项目进行分析的功能。其中,函数`解析项目本身``解析一个Python项目``解析一个C项目的头文件``解析一个C项目``解析一个Java项目``解析一个Rect项目`分别用于解析不同类型的项目。函数`解析源代码新`实现了对每一个源代码文件的分析,并将分析结果汇总,同时还实现了分组和迭代处理,提高了效率。最后,函数`write_results_to_file`将所有分析结果写入文件。中间,还用到了`request_gpt_model_multi_threads_with_very_awesome_ui_and_high_efficiency``request_gpt_model_in_new_thread_with_ui_alive`来完成请求和响应,并用`update_ui`实时更新界面。
## [23/31] 请对下面的程序文件做一个概述: H:\chatgpt_academic_resolve\crazy_functions\询问多个大语言模型.py
这是一个Python程序文件名为"crazy_functions\询问多个大语言模型.py"。该程序实现了一个同时向多个大语言模型询问的功能接收用户输入文本以及模型参数向ChatGPT和ChatGLM模型发出请求并将对话记录显示在聊天框中同时刷新界面。
## [24/31] 请对下面的程序文件做一个概述: H:\chatgpt_academic_resolve\crazy_functions\读文章写摘要.py
该程序文件是一个Python模块文件名为"读文章写摘要.py",主要包含两个函数:"解析Paper"和"读文章写摘要"。其中,"解析Paper"函数接受文件路径、参数等参数逐个打印文件内容并使用GPT模型生成对该文件的摘要"读文章写摘要"函数则接受一段文本内容和参数,将该文本内容及其所有.tex文件逐个传递给"解析Paper"函数进行处理并使用GPT模型生成文章的中英文摘要。文件还导入了一些工具函数如异常处理、信息上报和文件写入等。
## [25/31] 请对下面的程序文件做一个概述: H:\chatgpt_academic_resolve\crazy_functions\谷歌检索小助手.py
该文件代码包含了一个名为`get_meta_information`的函数和一个名为`谷歌检索小助手`的装饰器函数用于从谷歌学术中抓取文章元信息并从用户提供的搜索页面中分析所有文章的相关信息。该文件使用了许多第三方库如requests、arxiv、BeautifulSoup等。其中`get_meta_information`函数中还定义了一个名为`string_similar`的辅助函数,用于比较字符串相似度。
## [26/31] 请对下面的程序文件做一个概述: H:\chatgpt_academic_resolve\crazy_functions\高级功能函数模板.py
该程序文件是一个 Python 模块包含一个名为“高阶功能模板函数”的函数。该函数接受多个参数其中包括输入文本、GPT 模型参数、插件模型参数、聊天显示框、聊天历史等。 该函数的主要功能是根据输入文本,使用 GPT 模型生成一些问题,并等待用户回答这些问题(使用 Markdown 格式),然后将用户回答加入到聊天历史中,并更新聊天显示框。该函数还包含了一些异常处理和多线程的相关操作。该程序文件还引用了另一个 Python 模块中的两个函数分别为“CatchException”和“update_ui”并且还引用了一个名为“request_gpt_model_in_new_thread_with_ui_alive”的自定义函数。
## [27/31] 请对下面的程序文件做一个概述: H:\chatgpt_academic_resolve\request_llm\bridge_all.py
这个文件是用来处理与LLM的交互的。包含两个函数一个是 predict_no_ui_long_connection 用来处理长文本的输出,可以多线程调用;另一个是 predict 用来处理基础的对话功能。这个文件会导入其他文件中定义的方法进行调用,具体调用哪个方法取决于传入的参数。函数中还有一些装饰器和管理多线程的逻辑。
## [28/31] 请对下面的程序文件做一个概述: H:\chatgpt_academic_resolve\request_llm\bridge_chatglm.py
这个程序文件实现了一个使用ChatGLM模型进行聊天的功能。具体实现过程是首先进行初始化然后使用GetGLMHandle类进行ChatGLM模型的加载和运行。predict_no_ui_long_connection函数用于多线程聊天而predict函数用于单线程聊天它们的不同之处在于前者不会更新UI界面后者会。这个文件还导入了其他模块和库例如transformers、time、importlib等并使用了多进程Pipe。
## [29/31] 请对下面的程序文件做一个概述: H:\chatgpt_academic_resolve\request_llm\bridge_chatgpt.py
这个程序文件是用于对话生成的主要包含三个函数predict、predict_no_ui、predict_no_ui_long_connection。其中predict是用于普通对话的函数具备完备的交互功能但不具备多线程能力predict_no_ui是高级实验性功能模块调用的函数参数简单可以多线程并行方便实现复杂的功能逻辑predict_no_ui_long_connection解决了predict_no_ui在处理长文档时容易断开连接的问题同样支持多线程。程序中还包含一些常量和工具函数用于整合信息选择LLM模型生成http请求发送请求接收响应等。它需要配置一个config文件包含代理网址、API等敏感信息。
## [30/31] 请对下面的程序文件做一个概述: H:\chatgpt_academic_resolve\request_llm\bridge_tgui.py
该程序文件实现了一个基于Websockets的文本生成服务和对话功能。其中有三个函数`run()``predict()``predict_no_ui_long_connection()``run()`函数用于连接到Websocket服务并生成文本结果`predict()`函数用于将用户输入作为文本生成的输入同时在UI上显示对话历史记录并在不断更新UI的过程中不断更新生成的文本输出`predict_no_ui_long_connection()`函数与`predict()`函数类似但没有UI并在一段时间内返回单个生成的文本。整个程序还引入了多个Python模块来完成相关功能例如`asyncio``websockets``json`等等。
## 根据以上分析对程序的整体功能和构架重新做出概括。然后用一张markdown表格整理每个文件的功能包括check_proxy.py, colorful.py, config.py, config_private.py, core_functional.py, crazy_functional.py, main.py, theme.py, toolbox.py, crazy_functions\crazy_utils.py, crazy_functions\Latex全文润色.py, crazy_functions\Latex全文翻译.py, crazy_functions\__init__.py, crazy_functions\下载arxiv论文翻译摘要.py, crazy_functions\代码重写为全英文_多线程.py, crazy_functions\总结word文档.py
程序功能概括:该程序是一个聊天机器人,可以通过 Web 界面与用户进行交互。它包含了丰富的功能,如文本润色、翻译、代码重写、在线查找等,并且支持多线程处理。用户可以通过 Gradio 框架提供的 Web 界面进行交互程序还提供了一些调试工具如toolbox 模块,方便程序开发和调试。
下表概述了每个文件的功能:
| 文件名 | 功能 |
| ----------------------------------------------------------- | ------------------------------------------------------------ |
| check_proxy.py | 检查代理是否可用 |
| colorful.py | 用于打印文本的字体颜色输出模块 |
| config.py | 用于程序中的各种设置,如并行线程数量和重试次数的限制等 |
| config_private.py | 配置API_KEY和代理信息的文件 |
| core_functional.py | 包含具体的文本处理功能的模块 |
| crazy_functional.py | 包括各种插件函数的模块,提供了多种文本处理功能 |
| main.py | 包含 Chatbot 机器人主程序的模块 |
| theme.py | 用于调节全局样式的模块 |
| toolbox.py | 包含工具函数和装饰器用于聊天Bot的开发和调试 |
| crazy_functions\crazy_utils.py | 包含一些辅助函数,如文本裁剪和消息捕捉等 |
| crazy_functions\Latex全文润色.py | 对 Latex 项目进行润色处理的功能模块 |
| crazy_functions\Latex全文翻译.py | 对 Latex 项目进行翻译的功能模块 |
| crazy_functions\__init__.py | 定义一些奇特的数学函数等 |
| crazy_functions\下载arxiv论文翻译摘要.py | 下载 Arxiv 论文并翻译摘要的功能模块 |
| crazy_functions\代码重写为全英文_多线程.py | 将Python程序中所有中文转化为英文的功能模块 |
| crazy_functions\总结word文档.py | 解析 docx 和 doc 格式的文件,生成文章片段的中英文概述的功能模块 |
## 根据以上分析对程序的整体功能和构架重新做出概括。然后用一张markdown表格整理每个文件的功能包括check_proxy.py, colorful.py, config.py, config_private.py, core_functional.py, crazy_functional.py, main.py, theme.py, toolbox.py, crazy_functions\crazy_utils.py, crazy_functions\Latex全文润色.py, crazy_functions\Latex全文翻译.py, crazy_functions\__init__.py, crazy_functions\下载arxiv论文翻译摘要.py, crazy_functions\代码重写为全英文_多线程.py, crazy_functions\总结word文档.py, crazy_functions\批量Markdown翻译.py, crazy_functions\批量总结PDF文档.py, crazy_functions\批量总结PDF文档pdfminer.py, crazy_functions\批量翻译PDF文档_多线程.py, crazy_functions\理解PDF文档内容.py, crazy_functions\生成函数注释.py, crazy_functions\解析项目源代码.py, crazy_functions\询问多个大语言模型.py, crazy_functions\读文章写摘要.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_tgui.py
根据以上分析整个程序是一个集成了多个有用工具和功能的文本处理和生成工具提供了多种在不同场景下使用的功能包括但不限于对话生成、文本摘要、PDF文件批量处理、代码翻译和实用工具等。主要的Python模块包括"toolbox.py"、"config.py"、"core_functional.py"和"crazy_functional.py"等,并且还使用了许多第三方库和模块实现相关功能。以下是每个程序文件的功能:
| 文件名 | 文件功能 |
| --- | --- |
| check_proxy.py | 用于检查代理的正确性和可用性 |
| colorful.py | 包含不同预设置颜色的常量并用于多种UI元素 |
| config.py | 用于全局配置的类 |
| config_private.py | 与config.py文件一起使用的另一个配置文件用于更改私密信息 |
| core_functional.py | 包含一些TextFunctional类和基础功能函数 |
| crazy_functional.py | 包含大量高级功能函数和实验性的功能函数 |
| main.py | 程序的主入口包含GUI主窗口和主要的UI管理功能 |
| theme.py | 包含一些预设置主题的颜色 |
| toolbox.py | 提供了一些有用的工具函数 |
| crazy_functions\crazy_utils.py | 包含一些用于实现高级功能的辅助函数 |
| crazy_functions\Latex全文润色.py | 实现了对LaTeX文件中全文的润色和格式化功能 |
| crazy_functions\Latex全文翻译.py | 实现了对LaTeX文件中的内容进行翻译的功能 |
| crazy_functions\_\_init\_\_.py | 用于导入crazy_functional.py中的功能函数 |
| crazy_functions\下载arxiv论文翻译摘要.py | 从Arxiv上下载论文并提取重要信息 |
| crazy_functions\代码重写为全英文_多线程.py | 针对中文Python文件将其翻译为全英文 |
| crazy_functions\总结word文档.py | 提取Word文件的重要内容来生成摘要 |
| crazy_functions\批量Markdown翻译.py | 批量翻译Markdown文件 |
| crazy_functions\批量总结PDF文档.py | 批量从PDF文件中提取摘要 |
| crazy_functions\批量总结PDF文档pdfminer.py | 批量从PDF文件中提取摘要 |
| crazy_functions\批量翻译PDF文档_多线程.py | 批量翻译PDF文件 |
| crazy_functions\理解PDF文档内容.py | 批量分析PDF文件并提取摘要 |
| crazy_functions\生成函数注释.py | 自动生成Python文件中函数的注释 |
| crazy_functions\解析项目源代码.py | 解析并分析给定项目的源代码 |
| crazy_functions\询问多个大语言模型.py | 向多个大语言模型询问输入文本并进行处理 |
| crazy_functions\读文献写摘要.py | 根据用户输入读取文献内容并生成摘要 |
| crazy_functions\谷歌检索小助手.py | 利用谷歌学术检索用户提供的论文信息并提取相关信息 |
| crazy_functions\高级功能函数模板.py | 实现高级功能的模板函数 |
| request_llm\bridge_all.py | 处理与LLM的交互 |
| request_llm\bridge_chatglm.py | 使用ChatGLM模型进行聊天 |
| request_llm\bridge_chatgpt.py | 实现对话生成的各项功能 |
| request_llm\bridge_tgui.py | 在Websockets中与用户进行交互并生成文本输出 |

333
main.py
View File

@ -1,174 +1,189 @@
import os; os.environ['no_proxy'] = '*' # 避免代理网络产生意外污染
import gradio as gr
from request_llm.bridge_chatgpt import predict
from toolbox import format_io, find_free_port, on_file_uploaded, on_report_generated, get_conf, ArgsGeneralWrapper, DummyWith
# 建议您复制一个config_private.py放自己的秘密, 如API和代理网址, 避免不小心传github被别人看到
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')
def main():
import gradio as gr
from request_llm.bridge_all import predict
from toolbox import format_io, find_free_port, on_file_uploaded, on_report_generated, get_conf, ArgsGeneralWrapper, DummyWith
# 建议您复制一个config_private.py放自己的秘密, 如API和代理网址, 避免不小心传github被别人看到
proxies, WEB_PORT, LLM_MODEL, CONCURRENT_COUNT, AUTHENTICATION, CHATBOT_HEIGHT, LAYOUT, API_KEY, AVAIL_LLM_MODELS = \
get_conf('proxies', 'WEB_PORT', 'LLM_MODEL', 'CONCURRENT_COUNT', 'AUTHENTICATION', 'CHATBOT_HEIGHT', 'LAYOUT', 'API_KEY', 'AVAIL_LLM_MODELS')
# 如果WEB_PORT是-1, 则随机选取WEB端口
PORT = find_free_port() if WEB_PORT <= 0 else WEB_PORT
if not AUTHENTICATION: AUTHENTICATION = None
# 如果WEB_PORT是-1, 则随机选取WEB端口
PORT = find_free_port() if WEB_PORT <= 0 else WEB_PORT
if not AUTHENTICATION: AUTHENTICATION = None
from check_proxy import get_current_version
initial_prompt = "Serve me as a writing and programming assistant."
title_html = f"<h1 align=\"center\">ChatGPT 学术优化 {get_current_version()}</h1>"
description = """代码开源和更新[地址🚀](https://github.com/binary-husky/chatgpt_academic),感谢热情的[开发者们❤️](https://github.com/binary-husky/chatgpt_academic/graphs/contributors)"""
from check_proxy import get_current_version
initial_prompt = "Serve me as a writing and programming assistant."
title_html = f"<h1 align=\"center\">ChatGPT 学术优化 {get_current_version()}</h1>"
description = """代码开源和更新[地址🚀](https://github.com/binary-husky/chatgpt_academic),感谢热情的[开发者们❤️](https://github.com/binary-husky/chatgpt_academic/graphs/contributors)"""
# 问询记录, python 版本建议3.9+(越新越好)
import logging
os.makedirs("gpt_log", exist_ok=True)
try:logging.basicConfig(filename="gpt_log/chat_secrets.log", level=logging.INFO, encoding="utf-8")
except:logging.basicConfig(filename="gpt_log/chat_secrets.log", level=logging.INFO)
print("所有问询记录将自动保存在本地目录./gpt_log/chat_secrets.log, 请注意自我隐私保护哦!")
# 问询记录, python 版本建议3.9+(越新越好)
import logging
os.makedirs("gpt_log", exist_ok=True)
try:logging.basicConfig(filename="gpt_log/chat_secrets.log", level=logging.INFO, encoding="utf-8")
except:logging.basicConfig(filename="gpt_log/chat_secrets.log", level=logging.INFO)
print("所有问询记录将自动保存在本地目录./gpt_log/chat_secrets.log, 请注意自我隐私保护哦!")
# 一些普通功能模块
from core_functional import get_core_functions
functional = get_core_functions()
# 一些普通功能模块
from core_functional import get_core_functions
functional = get_core_functions()
# 高级函数插件
from crazy_functional import get_crazy_functions
crazy_fns = get_crazy_functions()
# 高级函数插件
from crazy_functional import get_crazy_functions
crazy_fns = get_crazy_functions()
# 处理markdown文本格式的转变
gr.Chatbot.postprocess = format_io
# 处理markdown文本格式的转变
gr.Chatbot.postprocess = format_io
# 做一些外观色彩上的调整
from theme import adjust_theme, advanced_css
set_theme = adjust_theme()
# 做一些外观色彩上的调整
from theme import adjust_theme, advanced_css
set_theme = adjust_theme()
# 代理与自动更新
from check_proxy import check_proxy, auto_update
proxy_info = check_proxy(proxies)
# 代理与自动更新
from check_proxy import check_proxy, auto_update, warm_up_modules
proxy_info = check_proxy(proxies)
gr_L1 = lambda: gr.Row().style()
gr_L2 = lambda scale: gr.Column(scale=scale)
if LAYOUT == "TOP-DOWN":
gr_L1 = lambda: DummyWith()
gr_L2 = lambda scale: gr.Row()
CHATBOT_HEIGHT /= 2
gr_L1 = lambda: gr.Row().style()
gr_L2 = lambda scale: gr.Column(scale=scale)
if LAYOUT == "TOP-DOWN":
gr_L1 = lambda: DummyWith()
gr_L2 = lambda scale: gr.Row()
CHATBOT_HEIGHT /= 2
cancel_handles = []
with gr.Blocks(title="ChatGPT 学术优化", theme=set_theme, analytics_enabled=False, css=advanced_css) as demo:
gr.HTML(title_html)
cookies = gr.State({'api_key': API_KEY, 'llm_model': LLM_MODEL})
with gr_L1():
with gr_L2(scale=2):
chatbot = gr.Chatbot()
chatbot.style(height=CHATBOT_HEIGHT)
history = gr.State([])
with gr_L2(scale=1):
with gr.Accordion("输入区", open=True) as area_input_primary:
with gr.Row():
txt = gr.Textbox(show_label=False, placeholder="Input question here.").style(container=False)
with gr.Row():
submitBtn = gr.Button("提交", variant="primary")
with gr.Row():
resetBtn = gr.Button("重置", variant="secondary"); resetBtn.style(size="sm")
stopBtn = gr.Button("停止", variant="secondary"); stopBtn.style(size="sm")
with gr.Row():
status = gr.Markdown(f"Tip: 按Enter提交, 按Shift+Enter换行。当前模型: {LLM_MODEL} \n {proxy_info}")
with gr.Accordion("基础功能区", open=True) as area_basic_fn:
with gr.Row():
for k in functional:
variant = functional[k]["Color"] if "Color" in functional[k] else "secondary"
functional[k]["Button"] = gr.Button(k, variant=variant)
with gr.Accordion("函数插件区", open=True) as area_crazy_fn:
with gr.Row():
gr.Markdown("注意:以下“红颜色”标识的函数插件需从输入区读取路径作为参数.")
with gr.Row():
for k in crazy_fns:
if not crazy_fns[k].get("AsButton", True): continue
variant = crazy_fns[k]["Color"] if "Color" in crazy_fns[k] else "secondary"
crazy_fns[k]["Button"] = gr.Button(k, variant=variant)
crazy_fns[k]["Button"].style(size="sm")
with gr.Row():
with gr.Accordion("更多函数插件", open=True):
dropdown_fn_list = [k for k in crazy_fns.keys() if not crazy_fns[k].get("AsButton", True)]
with gr.Column(scale=1):
dropdown = gr.Dropdown(dropdown_fn_list, value=r"打开插件列表", label="").style(container=False)
with gr.Column(scale=1):
switchy_bt = gr.Button(r"请先从插件列表中选择", variant="secondary")
with gr.Row():
with gr.Accordion("点击展开“文件上传区”。上传本地文件可供红色函数插件调用。", open=False) as area_file_up:
file_upload = gr.Files(label="任何文件, 但推荐上传压缩文件(zip, tar)", file_count="multiple")
with gr.Accordion("展开SysPrompt & 交互界面布局 & Github地址", open=(LAYOUT == "TOP-DOWN")):
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",)
checkboxes = gr.CheckboxGroup(["基础功能区", "函数插件区", "底部输入区"], value=["基础功能区", "函数插件区"], label="显示/隐藏功能区")
gr.Markdown(description)
with gr.Accordion("备选输入区", open=True, visible=False) 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"); resetBtn.style(size="sm")
stopBtn2 = gr.Button("停止", variant="secondary"); stopBtn.style(size="sm")
# 功能区显示开关与功能区的互动
def fn_area_visibility(a):
ret = {}
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))})
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] )
# 整理反复出现的控件句柄组合
input_combo = [cookies, txt, txt2, top_p, temperature, chatbot, history, system_prompt]
output_combo = [cookies, chatbot, history, status]
predict_args = dict(fn=ArgsGeneralWrapper(predict), inputs=input_combo, outputs=output_combo)
# 提交按钮、重置按钮
cancel_handles.append(txt.submit(**predict_args))
cancel_handles.append(txt2.submit(**predict_args))
cancel_handles.append(submitBtn.click(**predict_args))
cancel_handles.append(submitBtn2.click(**predict_args))
resetBtn.click(lambda: ([], [], "已重置"), None, [chatbot, history, status])
resetBtn2.click(lambda: ([], [], "已重置"), None, [chatbot, history, status])
# 基础功能区的回调函数注册
for k in functional:
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)
# 文件上传区接收文件后与chatbot的互动
file_upload.upload(on_file_uploaded, [file_upload, chatbot, txt], [chatbot, txt])
# 函数插件-固定按钮区
for k in crazy_fns:
if not crazy_fns[k].get("AsButton", True): continue
click_handle = crazy_fns[k]["Button"].click(ArgsGeneralWrapper(crazy_fns[k]["Function"]), [*input_combo, gr.State(PORT)], output_combo)
cancel_handles = []
with gr.Blocks(title="ChatGPT 学术优化", theme=set_theme, analytics_enabled=False, css=advanced_css) as demo:
gr.HTML(title_html)
cookies = gr.State({'api_key': API_KEY, 'llm_model': LLM_MODEL})
with gr_L1():
with gr_L2(scale=2):
chatbot = gr.Chatbot()
chatbot.style(height=CHATBOT_HEIGHT)
history = gr.State([])
with gr_L2(scale=1):
with gr.Accordion("输入区", open=True) as area_input_primary:
with gr.Row():
txt = gr.Textbox(show_label=False, placeholder="Input question here.").style(container=False)
with gr.Row():
submitBtn = gr.Button("提交", variant="primary")
with gr.Row():
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")
with gr.Row():
status = gr.Markdown(f"Tip: 按Enter提交, 按Shift+Enter换行。当前模型: {LLM_MODEL} \n {proxy_info}")
with gr.Accordion("基础功能区", open=True) as area_basic_fn:
with gr.Row():
for k in functional:
variant = functional[k]["Color"] if "Color" in functional[k] else "secondary"
functional[k]["Button"] = gr.Button(k, variant=variant)
with gr.Accordion("函数插件区", open=True) as area_crazy_fn:
with gr.Row():
gr.Markdown("注意:以下“红颜色”标识的函数插件需从输入区读取路径作为参数.")
with gr.Row():
for k in crazy_fns:
if not crazy_fns[k].get("AsButton", True): continue
variant = crazy_fns[k]["Color"] if "Color" in crazy_fns[k] else "secondary"
crazy_fns[k]["Button"] = gr.Button(k, variant=variant)
crazy_fns[k]["Button"].style(size="sm")
with gr.Row():
with gr.Accordion("更多函数插件", open=True):
dropdown_fn_list = [k for k in crazy_fns.keys() if not crazy_fns[k].get("AsButton", True)]
with gr.Column(scale=1):
dropdown = gr.Dropdown(dropdown_fn_list, value=r"打开插件列表", label="").style(container=False)
with gr.Column(scale=1):
switchy_bt = gr.Button(r"请先从插件列表中选择", variant="secondary")
with gr.Row():
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")):
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=4096, value=512, 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)
gr.Markdown(description)
with gr.Accordion("备选输入区", open=True, visible=False) 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("清除", variant="secondary", visible=False); clearBtn.style(size="sm")
# 功能区显示开关与功能区的互动
def fn_area_visibility(a):
ret = {}
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))})
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, clearBtn, clearBtn2] )
# 整理反复出现的控件句柄组合
input_combo = [cookies, max_length_sl, md_dropdown, txt, txt2, top_p, temperature, chatbot, history, system_prompt]
output_combo = [cookies, chatbot, history, status]
predict_args = dict(fn=ArgsGeneralWrapper(predict), inputs=input_combo, outputs=output_combo)
# 提交按钮、重置按钮
cancel_handles.append(txt.submit(**predict_args))
cancel_handles.append(txt2.submit(**predict_args))
cancel_handles.append(submitBtn.click(**predict_args))
cancel_handles.append(submitBtn2.click(**predict_args))
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])
# 基础功能区的回调函数注册
for k in functional:
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)
# 文件上传区接收文件后与chatbot的互动
file_upload.upload(on_file_uploaded, [file_upload, chatbot, txt, txt2, checkboxes], [chatbot, txt, txt2])
# 函数插件-固定按钮区
for k in crazy_fns:
if not crazy_fns[k].get("AsButton", True): continue
click_handle = crazy_fns[k]["Button"].click(ArgsGeneralWrapper(crazy_fns[k]["Function"]), [*input_combo, gr.State(PORT)], output_combo)
click_handle.then(on_report_generated, [file_upload, chatbot], [file_upload, chatbot])
cancel_handles.append(click_handle)
# 函数插件-下拉菜单与随变按钮的互动
def on_dropdown_changed(k):
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 route(k, *args, **kwargs):
if k in [r"打开插件列表", r"请先从插件列表中选择"]: return
yield from ArgsGeneralWrapper(crazy_fns[k]["Function"])(*args, **kwargs)
click_handle = switchy_bt.click(route,[switchy_bt, *input_combo, gr.State(PORT)], output_combo)
click_handle.then(on_report_generated, [file_upload, chatbot], [file_upload, chatbot])
# def expand_file_area(file_upload, area_file_up):
# if len(file_upload)>0: return {area_file_up: gr.update(open=True)}
# click_handle.then(expand_file_area, [file_upload, area_file_up], [area_file_up])
cancel_handles.append(click_handle)
# 函数插件-下拉菜单与随变按钮的互动
def on_dropdown_changed(k):
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 route(k, *args, **kwargs):
if k in [r"打开插件列表", r"请先从插件列表中选择"]: return
yield from ArgsGeneralWrapper(crazy_fns[k]["Function"])(*args, **kwargs)
click_handle = switchy_bt.click(route,[switchy_bt, *input_combo, gr.State(PORT)], output_combo)
click_handle.then(on_report_generated, [file_upload, chatbot], [file_upload, chatbot])
# def expand_file_area(file_upload, area_file_up):
# if len(file_upload)>0: return {area_file_up: gr.update(open=True)}
# click_handle.then(expand_file_area, [file_upload, area_file_up], [area_file_up])
cancel_handles.append(click_handle)
# 终止按钮的回调函数注册
stopBtn.click(fn=None, inputs=None, outputs=None, cancels=cancel_handles)
stopBtn2.click(fn=None, inputs=None, outputs=None, cancels=cancel_handles)
# gradio的inbrowser触发不太稳定回滚代码到原始的浏览器打开函数
def auto_opentab_delay():
import threading, webbrowser, time
print(f"如果浏览器没有自动打开请复制并转到以下URL")
print(f"\t(亮色主题): http://localhost:{PORT}")
print(f"\t(暗色主题): http://localhost:{PORT}/?__dark-theme=true")
def open():
time.sleep(2) # 打开浏览器
webbrowser.open_new_tab(f"http://localhost:{PORT}/?__dark-theme=true")
threading.Thread(target=open, name="open-browser", daemon=True).start()
threading.Thread(target=auto_update, name="self-upgrade", daemon=True).start()
# 终止按钮的回调函数注册
stopBtn.click(fn=None, inputs=None, outputs=None, cancels=cancel_handles)
stopBtn2.click(fn=None, inputs=None, outputs=None, cancels=cancel_handles)
auto_opentab_delay()
demo.queue(concurrency_count=CONCURRENT_COUNT).launch(server_name="0.0.0.0", server_port=PORT, auth=AUTHENTICATION)
# gradio的inbrowser触发不太稳定回滚代码到原始的浏览器打开函数
def auto_opentab_delay():
import threading, webbrowser, time
print(f"如果浏览器没有自动打开请复制并转到以下URL")
print(f"\t(亮色主题): http://localhost:{PORT}")
print(f"\t(暗色主题): http://localhost:{PORT}/?__dark-theme=true")
def open():
time.sleep(2) # 打开浏览器
webbrowser.open_new_tab(f"http://localhost:{PORT}/?__dark-theme=true")
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", server_port=PORT, auth=AUTHENTICATION, favicon_path="docs/logo.png")
if __name__ == "__main__":
main()

View File

@ -1,35 +1,53 @@
# 如何使用其他大语言模型v3.0分支测试中)
## 1. 先运行text-generation
## ChatGLM
- 安装依赖 `pip install -r request_llm/requirements_chatglm.txt`
- 修改配置在config.py中将LLM_MODEL的值改为"chatglm"
``` sh
# 下载模型( text-generation 这么牛的项目别忘了给人家star
LLM_MODEL = "chatglm"
```
- 运行!
``` sh
`python main.py`
```
---
## Text-Generation-UI (TGUI)
### 1. 部署TGUI
``` sh
# 1 下载模型
git clone https://github.com/oobabooga/text-generation-webui.git
# 安装text-generation的额外依赖
pip install accelerate bitsandbytes flexgen gradio llamacpp markdown numpy peft requests rwkv safetensors sentencepiece tqdm datasets git+https://github.com/huggingface/transformers
# 切换路径
# 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
# 启动text-generation,注意把模型的斜杠改成下划线
python server.py --cpu --listen --listen-port 7860 --model facebook_galactica-1.3b
# 6 启动text-generation
python server.py --cpu --listen --listen-port 7865 --model facebook_galactica-1.3b
```
## 2. 修改config.py
### 2. 修改config.py
``` sh
# LLM_MODEL格式较复杂 TGUI:[模型]@[ws地址]:[ws端口] , 端口要和上面给定的端口一致
LLM_MODEL = "TGUI:galactica-1.3b@localhost:7860"
# LLM_MODEL格式: tgui:[模型]@[ws地址]:[ws端口] , 端口要和上面给定的端口一致
LLM_MODEL = "tgui:galactica-1.3b@localhost:7860"
```
## 3. 运行!
### 3. 运行!
``` sh
cd chatgpt-academic
python main.py

210
request_llm/bridge_all.py Normal file
View File

@ -0,0 +1,210 @@
"""
该文件中主要包含2个函数
不具备多线程能力的函数
1. predict: 正常对话时使用具备完备的交互功能不可多线程
具备多线程调用能力的函数
2. predict_no_ui_long_connection在实验过程中发现调用predict_no_ui处理长文档时和openai的连接容易断掉这个函数用stream的方式解决这个问题同样支持多线程
"""
import tiktoken
from functools import wraps, lru_cache
from concurrent.futures import ThreadPoolExecutor
from .bridge_chatgpt import predict_no_ui_long_connection as chatgpt_noui
from .bridge_chatgpt import predict as chatgpt_ui
from .bridge_chatglm import predict_no_ui_long_connection as chatglm_noui
from .bridge_chatglm import predict as chatglm_ui
# from .bridge_tgui import predict_no_ui_long_connection as tgui_noui
# from .bridge_tgui import predict as tgui_ui
colors = ['#FF00FF', '#00FFFF', '#FF0000', '#990099', '#009999', '#990044']
class LazyloadTiktoken(object):
def __init__(self, model):
self.model = model
@staticmethod
@lru_cache(maxsize=128)
def get_encoder(model):
print('正在加载tokenizer如果是第一次运行可能需要一点时间下载参数')
tmp = tiktoken.encoding_for_model(model)
print('加载tokenizer完毕')
return tmp
def encode(self, *args, **kwargs):
encoder = self.get_encoder(self.model)
return encoder.encode(*args, **kwargs)
def decode(self, *args, **kwargs):
encoder = self.get_encoder(self.model)
return encoder.decode(*args, **kwargs)
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",
"max_token": 4096,
"tokenizer": tokenizer_gpt35,
"token_cnt": get_token_num_gpt35,
},
"gpt-4": {
"fn_with_ui": chatgpt_ui,
"fn_without_ui": chatgpt_noui,
"endpoint": "https://api.openai.com/v1/chat/completions",
"max_token": 8192,
"tokenizer": tokenizer_gpt4,
"token_cnt": get_token_num_gpt4,
},
# api_2d
"api2d-gpt-3.5-turbo": {
"fn_with_ui": chatgpt_ui,
"fn_without_ui": chatgpt_noui,
"endpoint": "https://openai.api2d.net/v1/chat/completions",
"max_token": 4096,
"tokenizer": tokenizer_gpt35,
"token_cnt": get_token_num_gpt35,
},
"api2d-gpt-4": {
"fn_with_ui": chatgpt_ui,
"fn_without_ui": chatgpt_noui,
"endpoint": "https://openai.api2d.net/v1/chat/completions",
"max_token": 8192,
"tokenizer": tokenizer_gpt4,
"token_cnt": get_token_num_gpt4,
},
# chatglm
"chatglm": {
"fn_with_ui": chatglm_ui,
"fn_without_ui": chatglm_noui,
"endpoint": None,
"max_token": 1024,
"tokenizer": tokenizer_gpt35,
"token_cnt": get_token_num_gpt35,
},
}
def LLM_CATCH_EXCEPTION(f):
"""
装饰器函数将错误显示出来
"""
def decorated(inputs, llm_kwargs, history, sys_prompt, observe_window, console_slience):
try:
return f(inputs, llm_kwargs, history, sys_prompt, observe_window, console_slience)
except Exception as e:
from toolbox import get_conf
import traceback
proxies, = get_conf('proxies')
tb_str = '\n```\n' + traceback.format_exc() + '\n```\n'
observe_window[0] = tb_str
return tb_str
return decorated
def predict_no_ui_long_connection(inputs, llm_kwargs, history, sys_prompt, observe_window, console_slience=False):
"""
发送至LLM等待回复一次性完成不显示中间过程但内部用stream的方法避免中途网线被掐
inputs
是本次问询的输入
sys_prompt:
系统静默prompt
llm_kwargs
LLM的内部调优参数
history
是之前的对话列表
observe_window = None
用于负责跨越线程传递已经输出的部分大部分时候仅仅为了fancy的视觉效果留空即可observe_window[0]观测窗observe_window[1]看门狗
"""
import threading, time, copy
model = llm_kwargs['llm_model']
n_model = 1
if '&' not in model:
assert not model.startswith("tgui"), "TGUI不支持函数插件的实现"
# 如果只询问1个大语言模型
method = model_info[model]["fn_without_ui"]
return method(inputs, llm_kwargs, history, sys_prompt, observe_window, console_slience)
else:
# 如果同时询问多个大语言模型:
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]
futures = []
for i in range(n_model):
model = models[i]
method = model_info[model]["fn_without_ui"]
llm_kwargs_feedin = copy.deepcopy(llm_kwargs)
llm_kwargs_feedin['llm_model'] = model
future = executor.submit(LLM_CATCH_EXCEPTION(method), inputs, llm_kwargs_feedin, history, sys_prompt, window_mutex[i], console_slience)
futures.append(future)
def mutex_manager(window_mutex, observe_window):
while True:
time.sleep(0.5)
if not window_mutex[-1]: break
# 看门狗watchdog
for i in range(n_model):
window_mutex[i][1] = observe_window[1]
# 观察窗window
chat_string = []
for i in range(n_model):
chat_string.append( f"{str(models[i])} 说】: <font color=\"{colors[i]}\"> {window_mutex[i][0]} </font>" )
res = '<br/><br/>\n\n---\n\n'.join(chat_string)
# # # # # # # # # # #
observe_window[0] = res
t_model = threading.Thread(target=mutex_manager, args=(window_mutex, observe_window), daemon=True)
t_model.start()
return_string_collect = []
while True:
worker_done = [h.done() for h in futures]
if all(worker_done):
executor.shutdown()
break
time.sleep(1)
for i, future in enumerate(futures): # wait and get
return_string_collect.append( f"{str(models[i])} 说】: <font color=\"{colors[i]}\"> {future.result()} </font>" )
window_mutex[-1] = False # stop mutex thread
res = '<br/>\n\n---\n\n'.join(return_string_collect)
return res
def predict(inputs, llm_kwargs, *args, **kwargs):
"""
发送至LLM流式获取输出
用于基础的对话功能
inputs 是本次问询的输入
top_p, temperature是LLM的内部调优参数
history 是之前的对话列表注意无论是inputs还是history内容太长了都会触发token数量溢出的错误
chatbot 为WebUI中显示的对话列表修改它然后yeild出去可以直接修改对话界面内容
additional_fn代表点击的哪个按钮按钮见functional.py
"""
method = model_info[llm_kwargs['llm_model']]["fn_with_ui"]
yield from method(inputs, llm_kwargs, *args, **kwargs)

View File

@ -0,0 +1,140 @@
from transformers import AutoModel, AutoTokenizer
import time
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()
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
while True:
try:
if self.chatglm_model is None:
self.chatglm_tokenizer = AutoTokenizer.from_pretrained("THUDM/chatglm-6b", trust_remote_code=True)
device, = get_conf('LOCAL_MODEL_DEVICE')
if device=='cpu':
self.chatglm_model = AutoModel.from_pretrained("THUDM/chatglm-6b", trust_remote_code=True).float()
else:
self.chatglm_model = AutoModel.from_pretrained("THUDM/chatglm-6b", 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)
except:
self.child.send('[Local Message] Call ChatGLM fail.')
self.child.send('[Finish]')
def stream_chat(self, **kwargs):
self.parent.send(kwargs)
while True:
res = self.parent.recv()
if res != '[Finish]':
yield res
else:
break
return
global glm_handle
glm_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 glm_handle
if glm_handle is None:
glm_handle = GetGLMHandle()
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 = []
for i in range(len(history)//2):
history_feedin.append(["What can I do?", sys_prompt] )
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']):
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:
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(["What can I do?", system_prompt] )
history_feedin.append([history[2*i], history[2*i+1]] )
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)

View File

@ -21,9 +21,9 @@ import importlib
# config_private.py放自己的秘密如API和代理网址
# 读取时首先看是否存在私密的config_private配置文件不受git管控如果有则覆盖原config文件
from toolbox import get_conf, update_ui
proxies, API_URL, API_KEY, TIMEOUT_SECONDS, MAX_RETRY, LLM_MODEL = \
get_conf('proxies', 'API_URL', 'API_KEY', 'TIMEOUT_SECONDS', 'MAX_RETRY', 'LLM_MODEL')
from toolbox import get_conf, update_ui, is_any_api_key, select_api_key
proxies, API_KEY, TIMEOUT_SECONDS, MAX_RETRY = \
get_conf('proxies', 'API_KEY', 'TIMEOUT_SECONDS', 'MAX_RETRY')
timeout_bot_msg = '[Local Message] Request timeout. Network error. Please check proxy settings in config.py.' + \
'网络错误,检查代理服务器是否可用,以及代理设置的格式是否正确,格式须是[协议]://[地址]:[端口],缺一不可。'
@ -42,17 +42,17 @@ def get_full_error(chunk, stream_response):
def predict_no_ui_long_connection(inputs, llm_kwargs, history=[], sys_prompt="", observe_window=None, console_slience=False):
"""
发送至chatGPT等待回复一次性完成不显示中间过程但内部用stream的方法避免中途网线被掐
inputs
是本次问询的输入
sys_prompt:
系统静默prompt
llm_kwargs
chatGPT的内部调优参数
history
是之前的对话列表
observe_window = None
用于负责跨越线程传递已经输出的部分大部分时候仅仅为了fancy的视觉效果留空即可observe_window[0]观测窗observe_window[1]看门狗
发送至chatGPT等待回复一次性完成不显示中间过程但内部用stream的方法避免中途网线被掐
inputs
是本次问询的输入
sys_prompt:
系统静默prompt
llm_kwargs
chatGPT的内部调优参数
history
是之前的对话列表
observe_window = None
用于负责跨越线程传递已经输出的部分大部分时候仅仅为了fancy的视觉效果留空即可observe_window[0]观测窗observe_window[1]看门狗
"""
watch_dog_patience = 5 # 看门狗的耐心, 设置5秒即可
headers, payload = generate_payload(inputs, llm_kwargs, history, system_prompt=sys_prompt, stream=True)
@ -60,7 +60,9 @@ def predict_no_ui_long_connection(inputs, llm_kwargs, history=[], sys_prompt="",
while True:
try:
# make a POST request to the API endpoint, stream=False
response = requests.post(API_URL, headers=headers, proxies=proxies,
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 requests.exceptions.ReadTimeout as e:
retry += 1
@ -83,6 +85,7 @@ def predict_no_ui_long_connection(inputs, llm_kwargs, history=[], sys_prompt="",
raise ConnectionAbortedError("OpenAI拒绝了请求:" + error_msg)
else:
raise RuntimeError("OpenAI拒绝了请求" + error_msg)
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
@ -105,22 +108,22 @@ 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):
"""
发送至chatGPT流式获取输出
用于基础的对话功能
inputs 是本次问询的输入
top_p, temperature是chatGPT的内部调优参数
history 是之前的对话列表注意无论是inputs还是history内容太长了都会触发token数量溢出的错误
chatbot 为WebUI中显示的对话列表修改它然后yeild出去可以直接修改对话界面内容
additional_fn代表点击的哪个按钮按钮见functional.py
发送至chatGPT流式获取输出
用于基础的对话功能
inputs 是本次问询的输入
top_p, temperature是chatGPT的内部调优参数
history 是之前的对话列表注意无论是inputs还是history内容太长了都会触发token数量溢出的错误
chatbot 为WebUI中显示的对话列表修改它然后yeild出去可以直接修改对话界面内容
additional_fn代表点击的哪个按钮按钮见functional.py
"""
if inputs.startswith('sk-') and len(inputs) == 51:
if is_any_api_key(inputs):
chatbot._cookies['api_key'] = inputs
chatbot.append(("输入已识别为openai的api_key", "api_key已导入"))
yield from update_ui(chatbot=chatbot, history=history, msg="api_key已导入") # 刷新界面
return
elif len(chatbot._cookies['api_key']) != 51:
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已导入") # 刷新界面
yield from update_ui(chatbot=chatbot, history=history, msg="缺少api_key") # 刷新界面
return
if additional_fn is not None:
@ -130,20 +133,27 @@ def predict(inputs, llm_kwargs, plugin_kwargs, chatbot, history=[], system_promp
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 stream:
raw_input = inputs
logging.info(f'[raw_input] {raw_input}')
chatbot.append((inputs, ""))
yield from update_ui(chatbot=chatbot, history=history, msg="等待响应") # 刷新界面
raw_input = inputs
logging.info(f'[raw_input] {raw_input}')
chatbot.append((inputs, ""))
yield from update_ui(chatbot=chatbot, history=history, msg="等待响应") # 刷新界面
headers, payload = generate_payload(inputs, llm_kwargs, history, system_prompt, stream)
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。")
yield from update_ui(chatbot=chatbot, history=history, msg="api-key不满足要求") # 刷新界面
return
history.append(inputs); history.append(" ")
retry = 0
while True:
try:
# make a POST request to the API endpoint, stream=True
response = requests.post(API_URL, headers=headers, proxies=proxies,
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:
retry += 1
@ -160,21 +170,23 @@ def predict(inputs, llm_kwargs, plugin_kwargs, chatbot, history=[], system_promp
while True:
chunk = next(stream_response)
# print(chunk.decode()[6:])
if is_head_of_the_stream:
if is_head_of_the_stream and (r'"object":"error"' not in chunk.decode()):
# 数据流的第一帧不携带content
is_head_of_the_stream = False; continue
if chunk:
try:
if len(json.loads(chunk.decode()[6:])['choices'][0]["delta"]) == 0:
chunk_decoded = chunk.decode()
# 前者API2D的
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.decode()[6:])
chunkjson = json.loads(chunk_decoded[6:])
status_text = f"finish_reason: {chunkjson['choices'][0]['finish_reason']}"
# 如果这里抛出异常一般是文本过长详情见get_full_error的输出
gpt_replying_buffer = gpt_replying_buffer + json.loads(chunk.decode()[6:])['choices'][0]["delta"]["content"]
gpt_replying_buffer = gpt_replying_buffer + json.loads(chunk_decoded[6:])['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) # 刷新界面
@ -183,7 +195,7 @@ def predict(inputs, llm_kwargs, plugin_kwargs, chatbot, history=[], system_promp
traceback.print_exc()
yield from update_ui(chatbot=chatbot, history=history, msg="Json解析不合常规") # 刷新界面
chunk = get_full_error(chunk, stream_response)
error_msg = chunk.decode()
error_msg = chunk_decoded
if "reduce the length" in error_msg:
chatbot[-1] = (chatbot[-1][0], "[Local Message] Reduce the length. 本次输入过长,或历史数据过长. 历史缓存数据现已释放,您可以请再次尝试.")
history = [] # 清除历史
@ -191,23 +203,27 @@ def predict(inputs, llm_kwargs, plugin_kwargs, chatbot, history=[], system_promp
chatbot[-1] = (chatbot[-1][0], "[Local Message] Incorrect API key. OpenAI以提供了不正确的API_KEY为由拒绝服务.")
elif "exceeded your current quota" in error_msg:
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账户额度不足.")
else:
from toolbox import regular_txt_to_markdown
tb_str = '```\n' + traceback.format_exc() + '```'
chatbot[-1] = (chatbot[-1][0], f"[Local Message] 异常 \n\n{tb_str} \n\n{regular_txt_to_markdown(chunk.decode()[4:])}")
chatbot[-1] = (chatbot[-1][0], f"[Local Message] 异常 \n\n{tb_str} \n\n{regular_txt_to_markdown(chunk_decoded[4:])}")
yield from update_ui(chatbot=chatbot, history=history, msg="Json异常" + error_msg) # 刷新界面
return
def generate_payload(inputs, llm_kwargs, history, system_prompt, stream):
"""
整合所有信息选择LLM模型生成http请求为发送请求做准备
整合所有信息选择LLM模型生成http请求为发送请求做准备
"""
if len(llm_kwargs['api_key']) != 51:
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 {llm_kwargs['api_key']}"
"Authorization": f"Bearer {api_key}"
}
conversation_cnt = len(history) // 2
@ -235,7 +251,7 @@ def generate_payload(inputs, llm_kwargs, history, system_prompt, stream):
messages.append(what_i_ask_now)
payload = {
"model": llm_kwargs['llm_model'],
"model": llm_kwargs['llm_model'].strip('api2d-'),
"messages": messages,
"temperature": llm_kwargs['temperature'], # 1.0,
"top_p": llm_kwargs['top_p'], # 1.0,

View File

@ -13,23 +13,18 @@ import time
import threading
import importlib
from toolbox import get_conf, update_ui
LLM_MODEL, = get_conf('LLM_MODEL')
# "TGUI:galactica-1.3b@localhost:7860"
model_name, addr_port = LLM_MODEL.split('@')
assert ':' in addr_port, "LLM_MODEL 格式不正确!" + LLM_MODEL
addr, port = addr_port.split(':')
def random_hash():
letters = string.ascii_lowercase + string.digits
return ''.join(random.choice(letters) for i in range(9))
async def run(context, max_token=512):
async def run(context, max_token, temperature, top_p, addr, port):
params = {
'max_new_tokens': max_token,
'do_sample': True,
'temperature': 0.5,
'top_p': 0.9,
'temperature': temperature,
'top_p': top_p,
'typical_p': 1,
'repetition_penalty': 1.05,
'encoder_repetition_penalty': 1.0,
@ -90,7 +85,7 @@ async def run(context, max_token=512):
def predict_tgui(inputs, top_p, temperature, 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):
"""
发送至chatGPT流式获取输出
用于基础的对话功能
@ -108,18 +103,26 @@ def predict_tgui(inputs, top_p, temperature, chatbot, history=[], system_prompt=
inputs = core_functional[additional_fn]["Prefix"] + inputs + core_functional[additional_fn]["Suffix"]
raw_input = "What I would like to say is the following: " + inputs
logging.info(f'[raw_input] {raw_input}')
history.extend([inputs, ""])
chatbot.append([inputs, ""])
yield from update_ui(chatbot=chatbot, history=history, msg="等待响应") # 刷新界面
prompt = inputs
prompt = raw_input
tgui_say = ""
model_name, addr_port = llm_kwargs['llm_model'].split('@')
assert ':' in addr_port, "LLM_MODEL 格式不正确!" + llm_kwargs['llm_model']
addr, port = addr_port.split(':')
mutable = ["", time.time()]
def run_coorotine(mutable):
async def get_result(mutable):
async for response in run(prompt):
# "tgui:galactica-1.3b@localhost:7860"
async for response in run(context=prompt, max_token=llm_kwargs['max_length'],
temperature=llm_kwargs['temperature'],
top_p=llm_kwargs['top_p'], addr=addr, port=port):
print(response[len(mutable[0]):])
mutable[0] = response
if (time.time() - mutable[1]) > 3:
@ -140,28 +143,29 @@ def predict_tgui(inputs, top_p, temperature, chatbot, history=[], system_prompt=
chatbot[-1] = (history[-2], history[-1])
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
logging.info(f'[response] {tgui_say}')
def predict_tgui_no_ui(inputs, top_p, temperature, history=[], sys_prompt=""):
def predict_no_ui_long_connection(inputs, llm_kwargs, history, sys_prompt, observe_window, console_slience=False):
raw_input = "What I would like to say is the following: " + inputs
prompt = inputs
prompt = raw_input
tgui_say = ""
mutable = ["", time.time()]
def run_coorotine(mutable):
async def get_result(mutable):
async for response in run(prompt, max_token=20):
print(response[len(mutable[0]):])
mutable[0] = response
if (time.time() - mutable[1]) > 3:
model_name, addr_port = llm_kwargs['llm_model'].split('@')
assert ':' in addr_port, "LLM_MODEL 格式不正确!" + llm_kwargs['llm_model']
addr, port = addr_port.split(':')
def run_coorotine(observe_window):
async def get_result(observe_window):
async for response in run(context=prompt, max_token=llm_kwargs['max_length'],
temperature=llm_kwargs['temperature'],
top_p=llm_kwargs['top_p'], addr=addr, port=port):
print(response[len(observe_window[0]):])
observe_window[0] = response
if (time.time() - observe_window[1]) > 5:
print('exit when no listener')
break
asyncio.run(get_result(mutable))
thread_listen = threading.Thread(target=run_coorotine, args=(mutable,))
asyncio.run(get_result(observe_window))
thread_listen = threading.Thread(target=run_coorotine, args=(observe_window,))
thread_listen.start()
while thread_listen.is_alive():
time.sleep(1)
mutable[1] = time.time()
tgui_say = mutable[0]
return tgui_say
return observe_window[0]

View File

@ -0,0 +1,6 @@
protobuf
transformers==4.27.1
cpm_kernels
torch>=1.10
mdtex2html
sentencepiece

View File

@ -1,262 +0,0 @@
# chatgpt-academic项目自译解报告
Author补充以下分析均由本项目调用ChatGPT一键生成如果有不准确的地方全怪GPT😄
## 对程序的整体功能和构架做出概括。然后用一张markdown表格整理每个文件的功能包括'check_proxy.py', 'config.py'等)。
整体概括:
该程序是一个基于自然语言处理和机器学习的科学论文辅助工具主要功能包括聊天机器人、批量总结PDF文档、批量翻译PDF文档、生成函数注释、解析项目源代码等。程序基于 Gradio 构建 Web 服务,并集成了代理和自动更新功能,提高了用户的使用体验。
文件功能表格:
| 文件名称 | 功能 |
| ------------------------------------------------------------ | ------------------------------------------------------------ |
| .\check_proxy.py | 检查代理设置功能。 |
| .\config.py | 配置文件,存储程序的基本设置。 |
| .\config_private.py | 存储代理网络地址的文件。 |
| .\core_functional.py | 主要的程序逻辑,包括聊天机器人和文件处理。 |
| .\cradle.py | 程序入口,初始化程序和启动 Web 服务。 |
| .\crazy_functional.py | 辅助程序功能包括PDF文档处理、代码处理、函数注释生成等。 |
| .\main.py | 包含聊天机器人的具体实现。 |
| .\show_math.py | 处理 LaTeX 公式的函数。 |
| .\theme.py | 存储 Gradio Web 服务的 CSS 样式文件。 |
| .\toolbox.py | 提供了一系列工具函数,包括文件读写、网页抓取、解析函数参数、生成 HTML 等。 |
| ./crazy_functions/crazy_utils.py | 提供各种工具函数,如解析字符串、清洗文本、清理目录结构等。 |
| ./crazy_functions/\_\_init\_\_.py | crazy_functions 模块的入口文件。 |
| ./crazy_functions/下载arxiv论文翻译摘要.py | 对 arxiv.org 上的 PDF 论文进行下载和翻译。 |
| ./crazy_functions/代码重写为全英文_多线程.py | 将代码文件中的中文注释和字符串替换为英文。 |
| ./crazy_functions/总结word文档.py | 读取 Word 文档并生成摘要。 |
| ./crazy_functions/批量总结PDF文档.py | 批量读取 PDF 文件并生成摘要。 |
| ./crazy_functions/批量总结PDF文档pdfminer.py | 使用 pdfminer 库进行 PDF 文件处理。 |
| ./crazy_functions/批量翻译PDF文档_多线程.py | 使用多线程技术批量翻译 PDF 文件。 |
| ./crazy_functions/生成函数注释.py | 给 Python 函数自动生成说明文档。 |
| ./crazy_functions/解析项目源代码.py | 解析项目中的源代码,提取注释和函数名等信息。 |
| ./crazy_functions/读文章写摘要.py | 读取多个文本文件并生成对应的摘要。 |
| ./crazy_functions/高级功能函数模板.py | 使用 GPT 模型进行文本处理。 |
## [0/22] 程序概述: check_proxy.py
该程序的文件名是check_proxy.py主要有两个函数check_proxy和auto_update。
check_proxy函数中会借助requests库向一个IP查询API发送请求并返回该IP的地理位置信息。同时根据返回的数据来判断代理是否有效。
auto_update函数主要用于检查程序更新会从Github获取程序最新的版本信息如果当前版本和最新版本相差较大则会提示用户进行更新。该函数中也会依赖requests库进行网络请求。
在程序的开头还添加了一句防止代理网络影响的代码。程序使用了自己编写的toolbox模块中的get_conf函数来获取代理设置。
## [1/22] 程序概述: config.py
该程序文件是一个Python模块文件名为config.py。该模块包含了一些变量和配置选项用于配置一个OpenAI的聊天机器人。具体的配置选项如下
- API_KEY: 密钥用于连接OpenAI的API。需要填写有效的API密钥。
- USE_PROXY: 是否使用代理。如果需要使用代理需要将其改为True。
- proxies: 代理的协议、地址和端口。
- CHATBOT_HEIGHT: 聊天机器人对话框的高度。
- LAYOUT: 聊天机器人对话框的布局,默认为左右布局。
- TIMEOUT_SECONDS: 发送请求到OpenAI后等待多久判定为超时。
- WEB_PORT: 网页的端口,-1代表随机端口。
- MAX_RETRY: 如果OpenAI不响应网络卡顿、代理失败、KEY失效重试的次数限制。
- LLM_MODEL: OpenAI模型选择目前只对某些用户开放的gpt4。
- API_URL: OpenAI的API地址。
- CONCURRENT_COUNT: 使用的线程数。
- AUTHENTICATION: 用户名和密码,如果需要。
## [2/22] 程序概述: config_private.py
该程序文件名为config_private.py包含了API_KEY的设置和代理的配置。使用了一个名为API_KEY的常量来存储私人的API密钥。此外还有一个名为USE_PROXY的常量来标记是否需要使用代理。如果需要代理则使用了一个名为proxies的字典来存储代理网络的地址其中包括协议类型、地址和端口。
## [3/22] 程序概述: core_functional.py
该程序文件名为`core_functional.py`,主要是定义了一些核心功能函数,包括英语和中文学术润色、查找语法错误、中译英、学术中英互译、英译中、找图片和解释代码等。每个功能都有一个`Prefix`属性和`Suffix`属性,`Prefix`是指在用户输入的任务前面要显示的文本,`Suffix`是指在任务后面要显示的文本。此外,还有一个`Color`属性指示按钮的颜色,以及一个`PreProcess`函数表示对输入进行预处理的函数。
## [4/22] 程序概述: cradle.py
该程序文件名为cradle.py主要功能是检测当前版本与远程最新版本是否一致如果不一致则输出新版本信息并提示更新。其流程大致如下
1. 导入相关模块与自定义工具箱函数get_conf
2. 读取配置文件中的代理proxies
3. 使用requests模块请求远程版本信息url为https://raw.githubusercontent.com/binary-husky/chatgpt_academic/master/version并加载为json格式
4. 获取远程版本号、是否显示新功能信息、新功能内容
5. 读取本地版本文件version并加载为json格式
6. 获取当前版本号
7. 比较当前版本与远程版本如果远程版本号比当前版本号高0.05以上,则输出新版本信息并提示更新
8. 如果不需要更新,则直接返回
## [5/22] 程序概述: crazy_functional.py
该程序文件名为.\crazy_functional.py主要定义了一个名为get_crazy_functions()的函数该函数返回一个字典类型的变量function_plugins其中包含了一些函数插件。
一些重要的函数插件包括:
- 读文章写摘要可以自动读取Tex格式的论文并生成其摘要。
- 批量生成函数注释可以批量生成Python函数的文档注释。
- 解析项目源代码可以解析Python、C++、Golang、Java及React项目的源代码。
- 批量总结PDF文档可以对PDF文档进行批量总结以提取其中的关键信息。
- 一键下载arxiv论文并翻译摘要可以自动下载arxiv.org网站上的PDF论文并翻译生成其摘要。
- 批量翻译PDF文档多线程可以对PDF文档进行批量翻译并使用多线程方式提高翻译效率。
## [6/22] 程序概述: main.py
本程序为一个基于 Gradio 和 GPT-3 的交互式聊天机器人,文件名为 main.py。其中主要功能包括
1. 使用 Gradio 建立 Web 界面,实现用户与聊天机器人的交互;
2. 通过 bridge_chatgpt 模块,利用 GPT-3 模型实现聊天机器人的逻辑;
3. 提供一些基础功能和高级函数插件,用户可以通过按钮选择使用;
4. 提供文档格式转变、外观调整以及代理和自动更新等功能。
程序的主要流程为:
1. 导入所需的库和模块,并通过 get_conf 函数获取配置信息;
2. 设置 Gradio 界面的各个组件,包括聊天窗口、输入区、功能区、函数插件区等;
3. 注册各个组件的回调函数,包括用户输入、信号按钮等,实现机器人逻辑的交互;
4. 通过 Gradio 的 queue 函数和 launch 函数启动 Web 服务,并提供聊天机器人的功能。
此外,程序还提供了代理和自动更新功能,可以确保用户的使用体验。
## [7/22] 程序概述: show_math.py
该程序是一个Python脚本文件名为show_math.py。它转换Markdown和LaTeX混合语法到带MathML的HTML。程序使用latex2mathml模块来实现从LaTeX到MathML的转换将符号转换为HTML实体以批量处理。程序利用正则表达式和递归函数的方法处理不同形式的LaTeX语法支持以下四种情况$$形式、$形式、\[..]形式和\(...\)形式。如果无法转换某个公式则在该位置插入一条错误消息。最后程序输出HTML字符串。
## [8/22] 程序概述: theme.py
该程序文件为一个Python脚本其功能是调整Gradio应用的主题和样式包括字体、颜色、阴影、背景等等。在程序中使用了Gradio提供的默认颜色主题并针对不同元素设置了相应的样式属性以达到美化显示的效果。此外程序中还包含了一段高级CSS样式代码针对表格、列表、聊天气泡、行内代码等元素进行了样式设定。
## [9/22] 程序概述: toolbox.py
此程序文件主要包含了一系列用于聊天机器人开发的实用工具函数和装饰器函数。主要函数包括:
1. ArgsGeneralWrapper一个装饰器函数用于重组输入参数改变输入参数的顺序与结构。
2. get_reduce_token_percent一个函数用于计算自然语言处理时会出现的token溢出比例。
3. predict_no_ui_but_counting_down一个函数调用聊天接口并且保留了一定的界面心跳功能即当对话太长时会自动采用二分法截断。
4. write_results_to_file一个函数将对话记录history生成Markdown格式的文本并写入文件中。
5. regular_txt_to_markdown一个函数将普通文本转换为Markdown格式的文本。
6. CatchException一个装饰器函数捕捉函数调度中的异常并封装到一个生成器中返回并显示到聊天当中。
7. HotReload一个装饰器函数实现函数插件的热更新。
8. report_execption一个函数向chatbot中添加错误信息。
9. text_divide_paragraph一个函数将文本按照段落分隔符分割开生成带有段落标签的HTML代码。
10. markdown_convertion一个函数将Markdown格式的文本转换为HTML格式。如果包含数学公式则先将公式转换为HTML格式。
11. close_up_code_segment_during_stream一个函数用于在gpt输出代码的中途即输出了前面的```,但还没输出完后面的```,补上后面的```。
12. format_io一个函数将输入和输出解析为HTML格式。将输出部分的Markdown和数学公式转换为HTML格式。
13. find_free_port一个函数返回当前系统中可用的未使用端口。
14. extract_archive一个函数解压缩文件。
15. find_recent_files一个函数查找目录下一分钟内创建的文件。
16. on_file_uploaded一个函数响应用户上传的文件。
## [10/22] 程序概述: crazy_functions\crazy_utils.py
这是一个名为"crazy_utils.py"的Python程序文件包含了两个函数
1. `breakdown_txt_to_satisfy_token_limit()`:接受文本字符串、计算文本单词数量的函数和单词数量限制作为输入参数,将长文本拆分成合适的长度,以满足单词数量限制。这个函数使用一个递归方法去拆分长文本。
2. `breakdown_txt_to_satisfy_token_limit_for_pdf()`:类似于`breakdown_txt_to_satisfy_token_limit()`但是它使用一个不同的递归方法来拆分长文本以满足PDF文档中的需求。当出现无法继续拆分的情况时该函数将使用一个中文句号标记插入文本来截断长文本。如果还是无法拆分则会引发运行时异常。
## [11/22] 程序概述: crazy_functions\__init__.py
这个程序文件是一个 Python 的包,包名为 "crazy_functions",并且是其中的一个子模块 "__init__.py"。该包中可能包含多个函数或类,用于实现各种疯狂的功能。由于该文件的具体代码没有给出,因此无法进一步确定该包中的功能。通常情况下,一个包应该具有 __init__.py、__main__.py 和其它相关的模块文件,用于实现该包的各种功能。
## [12/22] 程序概述: crazy_functions\下载arxiv论文翻译摘要.py
这个程序实现的功能是下载arxiv论文并翻译摘要文件名为`下载arxiv论文翻译摘要.py`。这个程序引入了`requests``unicodedata``os``re`等Python标准库以及`pdfminer``bs4`等第三方库。其中`download_arxiv_`函数主要实现了从arxiv网站下载论文的功能包括解析链接、获取论文信息、下载论文和生成文件名等`get_name`函数则是为了从arxiv网站中获取论文信息创建的辅助函数。`下载arxiv论文并翻译摘要`函数则是实现了从下载好的PDF文件中提取摘要然后使用预先训练的GPT模型翻译为中文的功能。同时该函数还会将历史记录写入文件中。函数还会通过`CatchException`函数来捕获程序中出现的异常信息。
## [13/22] 程序概述: crazy_functions\代码重写为全英文_多线程.py
该程序文件为一个Python多线程程序文件名为"crazy_functions\代码重写为全英文_多线程.py"。该程序使用了多线程技术,将一个大任务拆成多个小任务,同时执行,提高运行效率。
程序的主要功能是将Python文件中的中文转换为英文同时将转换后的代码输出。程序先清空历史记录然后尝试导入openai和transformers等依赖库。程序接下来会读取当前路径下的.py文件和crazy_functions文件夹中的.py文件并将其整合成一个文件清单。随后程序会使用GPT2模型进行中英文的翻译并将结果保存在本地路径下的"gpt_log/generated_english_version"文件夹中。程序最终会生成一个任务执行报告。
需要注意的是,该程序依赖于"request_llm"和"toolbox"库以及本地的"crazy_utils"模块。
## [14/22] 程序概述: crazy_functions\总结word文档.py
该程序文件是一个 Python 脚本文件,文件名为 ./crazy_functions/总结word文档.py。该脚本是一个函数插件提供了名为“总结word文档”的函数。该函数的主要功能是批量读取给定文件夹下的 Word 文档文件,并使用 GPT 模型生成对每个文件的概述和意见建议。其中涉及到了读取 Word 文档、使用 GPT 模型等操作,依赖于许多第三方库。该文件也提供了导入依赖的方法,使用该脚本需要安装依赖库 python-docx 和 pywin32。函数功能实现的过程中使用了一些用于调试的变量如 fast_debug可在需要时设置为 True。该脚本文件也提供了对程序功能和贡献者的注释。
## [15/22] 程序概述: crazy_functions\批量总结PDF文档.py
该程序文件名为 `./crazy_functions\批量总结PDF文档.py`主要实现了批量处理PDF文档的功能。具体实现了以下几个函数
1. `is_paragraph_break(match)`:根据给定的匹配结果判断换行符是否表示段落分隔。
2. `normalize_text(text)`:通过将文本特殊符号转换为其基本形式来对文本进行归一化处理。
3. `clean_text(raw_text)`:对从 PDF 提取出的原始文本进行清洗和格式化处理。
4. `解析PDF(file_manifest, project_folder, top_p, temperature, chatbot, history, systemPromptTxt)`对给定的PDF文件进行分析并生成相应的概述。
5. `批量总结PDF文档(txt, top_p, temperature, chatbot, history, systemPromptTxt, WEB_PORT)`批量处理PDF文件对其进行摘要生成。
其中,主要用到了第三方库`pymupdf`对PDF文件进行处理。程序通过调用`fitz.open`函数打开PDF文件使用`page.get_text()`方法获取PDF文本内容。然后使用`clean_text`函数对文本进行清洗和格式化处理,生成最终的摘要。最后,调用`write_results_to_file`函数将历史记录写入文件并输出。
## [16/22] 程序概述: crazy_functions\批量总结PDF文档pdfminer.py
这个程序文件名是./crazy_functions\批量总结PDF文档pdfminer.py是一个用于批量读取PDF文件解析其中的内容并对其进行概括的程序。程序中引用了pdfminer和beautifulsoup4等Python库读取PDF文件并将其转化为文本内容然后利用GPT模型生成摘要语言最终输出一个中文和英文的摘要。程序还有一些错误处理的代码会输出错误信息。
## [17/22] 程序概述: crazy_functions\批量翻译PDF文档_多线程.py
这是一个 Python 程序文件,文件名为 `批量翻译PDF文档_多线程.py`,包含多个函数。主要功能是批量处理 PDF 文档,解析其中的文本,进行清洗和格式化处理,并使用 OpenAI 的 GPT 模型进行翻译。其中使用了多线程技术来提高程序的效率和并行度。
## [18/22] 程序概述: crazy_functions\生成函数注释.py
该程序文件名为./crazy_functions\生成函数注释.py。该文件包含两个函数分别为`生成函数注释``批量生成函数注释`
函数`生成函数注释`包含参数`file_manifest``project_folder``top_p``temperature``chatbot``history``systemPromptTxt`。其中,`file_manifest`为一个包含待处理文件路径的列表,`project_folder`表示项目文件夹路径,`top_p``temperature`是GPT模型参数`chatbot`为与用户交互的聊天机器人,`history`记录聊天机器人与用户的历史记录,`systemPromptTxt`为聊天机器人发送信息前的提示语。`生成函数注释`通过读取文件内容并调用GPT模型对文件中的所有函数生成注释最后使用markdown表格输出结果。函数中还包含一些条件判断和计时器以及调用其他自定义模块的函数。
函数`批量生成函数注释`包含参数`txt``top_p``temperature``chatbot``history``systemPromptTxt``WEB_PORT`。其中,`txt`表示用户输入的项目文件夹路径,其他参数含义与`生成函数注释`中相同。`批量生成函数注释`主要是通过解析项目文件夹,获取所有待处理文件的路径,并调用函数`生成函数注释`对每个文件进行处理,最终生成注释表格输出给用户。
## [19/22] 程序概述: crazy_functions\解析项目源代码.py
该程序文件包含了多个函数用于解析不同类型的项目如Python项目、C项目、Java项目等。其中最核心的函数是`解析源代码()`,它会对给定的一组文件进行分析,并返回对应的结果。具体流程如下:
1. 遍历所有待分析的文件,对每个文件进行如下处理:
1.1 从文件中读取代码内容,构造成一个字符串。
1.2 构造一条GPT请求`predict_no_ui_but_counting_down()`函数发送请求等待GPT回复。
1.3 将GPT回复添加到机器人会话列表中更新历史记录。
1.4 如果不是快速调试模式则等待2秒钟继续分析下一个文件。
2. 如果所有文件都分析完成,则向机器人会话列表中添加一条新消息,提示用户整个分析过程已经结束。
3. 返回机器人会话列表和历史记录。
除此之外,该程序文件还定义了若干个函数,用于针对不同类型的项目进行解析。这些函数会按照不同的方式调用`解析源代码()`函数。例如对于Python项目只需要分析.py文件对于C项目需要同时分析.h和.cpp文件等。每个函数中都会首先根据给定的项目路径读取相应的文件然后调用`解析源代码()`函数进行分析。
## [20/22] 程序概述: crazy_functions\读文章写摘要.py
该程序文件为一个名为“读文章写摘要”的Python函数用于解析项目文件夹中的.tex文件并使用GPT模型生成文章的中英文摘要。函数使用了request_llm.bridge_chatgpt和toolbox模块中的函数并包含两个子函数解析Paper和CatchException。函数参数包括txttop_ptemperaturechatbothistorysystemPromptTxt和WEB_PORT。执行过程中函数首先清空历史然后根据项目文件夹中的.tex文件列表对每个文件调用解析Paper函数生成中文摘要最后根据所有文件的中文摘要调用GPT模型生成英文摘要。函数运行过程中会将结果写入文件并返回聊天机器人和历史记录。
## [21/22] 程序概述: crazy_functions\高级功能函数模板.py
该程序文件为一个高级功能函数模板,文件名为"./crazy_functions\高级功能函数模板.py"。
该文件导入了两个模块,分别是"request_llm.bridge_chatgpt"和"toolbox"。其中"request_llm.bridge_chatgpt"模块包含了一个函数"predict_no_ui_long_connection"该函数用于请求GPT模型进行对话生成。"toolbox"模块包含了三个函数,分别是"catchException"、"report_exception"和"write_results_to_file"函数,这三个函数主要用于异常处理和日志记录等。
该文件定义了一个名为"高阶功能模板函数"的函数,并通过"decorator"装饰器将该函数装饰为一个异常处理函数,可以处理函数执行过程中出现的错误。该函数的作用是生成历史事件查询的问题,并向用户询问历史中哪些事件发生在指定日期,并索要相关图片。在查询完所有日期后,该函数返回所有历史事件及其相关图片的列表。其中,该函数的输入参数包括:
1. txt: 一个字符串,表示当前消息的文本内容。
2. top_p: 一个浮点数表示GPT模型生成文本时的"top_p"参数。
3. temperature: 一个浮点数表示GPT模型生成文本时的"temperature"参数。
4. chatbot: 一个列表,表示当前对话的记录列表。
5. history: 一个列表,表示当前对话的历史记录列表。
6. systemPromptTxt: 一个字符串,表示当前对话的系统提示信息。
7. WEB_PORT: 一个整数表示当前应用程序的WEB端口号。
该函数在执行过程中会先清空历史记录以免输入溢出。然后它会循环5次生成5个历史事件查询的问题并向用户请求输入相关信息。每次询问不携带之前的询问历史。在生成每个问题时该函数会向"chatbot"列表中添加一条消息记录,并设置该记录的初始状态为"[Local Message] waiting gpt response."。然后,该函数会调用"predict_no_ui_long_connection"函数向GPT模型请求生成一段文本并将生成的文本作为回答。如果请求过程中出现异常该函数会忽略异常。最后该函数将问题和回答添加到"chatbot"列表和"history"列表中,并将"chatbot"和"history"列表作为函数的返回值返回。

View File

@ -1,13 +1,10 @@
import markdown
import mdtex2html
import threading
import importlib
import traceback
import inspect
import re
from latex2mathml.converter import convert as tex2mathml
from functools import wraps, lru_cache
############################### 插件输入输出接驳区 #######################################
class ChatBotWithCookies(list):
def __init__(self, cookie):
@ -25,9 +22,9 @@ class ChatBotWithCookies(list):
def ArgsGeneralWrapper(f):
"""
装饰器函数用于重组输入参数改变输入参数的顺序与结构
装饰器函数用于重组输入参数改变输入参数的顺序与结构
"""
def decorated(cookies, txt, txt2, top_p, temperature, chatbot, history, system_prompt, *args):
def decorated(cookies, max_length, llm_model, txt, txt2, top_p, temperature, chatbot, history, system_prompt, *args):
txt_passon = txt
if txt == "" and txt2 != "": txt_passon = txt2
# 引入一个有cookie的chatbot
@ -37,8 +34,9 @@ def ArgsGeneralWrapper(f):
})
llm_kwargs = {
'api_key': cookies['api_key'],
'llm_model': cookies['llm_model'],
'llm_model': llm_model,
'top_p':top_p,
'max_length': max_length,
'temperature':temperature,
}
plugin_kwargs = {
@ -55,129 +53,10 @@ def update_ui(chatbot, history, msg='正常', **kwargs): # 刷新界面
"""
assert isinstance(chatbot, ChatBotWithCookies), "在传递chatbot的过程中不要将其丢弃。必要时可用clear将其清空然后用for+append循环重新赋值。"
yield chatbot.get_cookies(), chatbot, history, msg
############################### ################## #######################################
##########################################################################################
def get_reduce_token_percent(text):
"""
* 此函数未来将被弃用
"""
try:
# text = "maximum context length is 4097 tokens. However, your messages resulted in 4870 tokens"
pattern = r"(\d+)\s+tokens\b"
match = re.findall(pattern, text)
EXCEED_ALLO = 500 # 稍微留一点余地,否则在回复时会因余量太少出问题
max_limit = float(match[0]) - EXCEED_ALLO
current_tokens = float(match[1])
ratio = max_limit/current_tokens
assert ratio > 0 and ratio < 1
return ratio, str(int(current_tokens-max_limit))
except:
return 0.5, '不详'
def predict_no_ui_but_counting_down(i_say, i_say_show_user, chatbot, llm_kwargs, history=[], sys_prompt='', long_connection=True):
"""
* 此函数未来将被弃用替代函数 request_gpt_model_in_new_thread_with_ui_alive 文件 chatgpt_academic/crazy_functions/crazy_utils
调用简单的predict_no_ui接口但是依然保留了些许界面心跳功能当对话太长时会自动采用二分法截断
i_say: 当前输入
i_say_show_user: 显示到对话界面上的当前输入例如输入整个文件时你绝对不想把文件的内容都糊到对话界面上
chatbot: 对话界面句柄
top_p, temperature: gpt参数
history: gpt参数 对话历史
sys_prompt: gpt参数 sys_prompt
long_connection: 是否采用更稳定的连接方式推荐已弃用
"""
import time
from request_llm.bridge_chatgpt import predict_no_ui_long_connection
from toolbox import get_conf
TIMEOUT_SECONDS, MAX_RETRY = get_conf('TIMEOUT_SECONDS', 'MAX_RETRY')
# 多线程的时候需要一个mutable结构在不同线程之间传递信息
# list就是最简单的mutable结构我们第一个位置放gpt输出第二个位置传递报错信息
mutable = [None, '']
# multi-threading worker
def mt(i_say, history):
while True:
try:
mutable[0] = predict_no_ui_long_connection(
inputs=i_say, llm_kwargs=llm_kwargs, history=history, sys_prompt=sys_prompt)
except ConnectionAbortedError as token_exceeded_error:
# 尝试计算比例,尽可能多地保留文本
p_ratio, n_exceed = get_reduce_token_percent(
str(token_exceeded_error))
if len(history) > 0:
history = [his[int(len(his) * p_ratio):]
for his in history if his is not None]
else:
i_say = i_say[: int(len(i_say) * p_ratio)]
mutable[1] = f'警告文本过长将进行截断Token溢出数{n_exceed},截断比例:{(1-p_ratio):.0%}'
except TimeoutError as e:
mutable[0] = '[Local Message] 请求超时。'
raise TimeoutError
except Exception as e:
mutable[0] = f'[Local Message] 异常:{str(e)}.'
raise RuntimeError(f'[Local Message] 异常:{str(e)}.')
# 创建新线程发出http请求
thread_name = threading.Thread(target=mt, args=(i_say, history))
thread_name.start()
# 原来的线程则负责持续更新UI实现一个超时倒计时并等待新线程的任务完成
cnt = 0
while thread_name.is_alive():
cnt += 1
chatbot[-1] = (i_say_show_user,
f"[Local Message] {mutable[1]}waiting gpt response {cnt}/{TIMEOUT_SECONDS*2*(MAX_RETRY+1)}"+''.join(['.']*(cnt % 4)))
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
time.sleep(1)
# 把gpt的输出从mutable中取出来
gpt_say = mutable[0]
if gpt_say == '[Local Message] Failed with timeout.':
raise TimeoutError
return gpt_say
def write_results_to_file(history, file_name=None):
"""
将对话记录history以Markdown格式写入文件中如果没有指定文件名则使用当前时间生成文件名
"""
import os
import time
if file_name is None:
# file_name = time.strftime("chatGPT分析报告%Y-%m-%d-%H-%M-%S", time.localtime()) + '.md'
file_name = 'chatGPT分析报告' + \
time.strftime("%Y-%m-%d-%H-%M-%S", time.localtime()) + '.md'
os.makedirs('./gpt_log/', exist_ok=True)
with open(f'./gpt_log/{file_name}', 'w', encoding='utf8') as f:
f.write('# chatGPT 分析报告\n')
for i, content in enumerate(history):
try: # 这个bug没找到触发条件暂时先这样顶一下
if type(content) != str:
content = str(content)
except:
continue
if i % 2 == 0:
f.write('## ')
f.write(content)
f.write('\n\n')
res = '以上材料已经被写入' + os.path.abspath(f'./gpt_log/{file_name}')
print(res)
return res
def regular_txt_to_markdown(text):
"""
将普通文本转换为Markdown格式的文本
"""
text = text.replace('\n', '\n\n')
text = text.replace('\n\n\n', '\n\n')
text = text.replace('\n\n\n', '\n\n')
return text
def CatchException(f):
"""
装饰器函数捕捉函数f中的异常并封装到一个生成器中返回并显示到聊天当中
装饰器函数捕捉函数f中的异常并封装到一个生成器中返回并显示到聊天当中
"""
@wraps(f)
def decorated(txt, top_p, temperature, chatbot, history, systemPromptTxt, WEB_PORT):
@ -214,9 +93,70 @@ def HotReload(f):
return decorated
####################################### 其他小工具 #####################################
def get_reduce_token_percent(text):
"""
* 此函数未来将被弃用
"""
try:
# text = "maximum context length is 4097 tokens. However, your messages resulted in 4870 tokens"
pattern = r"(\d+)\s+tokens\b"
match = re.findall(pattern, text)
EXCEED_ALLO = 500 # 稍微留一点余地,否则在回复时会因余量太少出问题
max_limit = float(match[0]) - EXCEED_ALLO
current_tokens = float(match[1])
ratio = max_limit/current_tokens
assert ratio > 0 and ratio < 1
return ratio, str(int(current_tokens-max_limit))
except:
return 0.5, '不详'
def write_results_to_file(history, file_name=None):
"""
将对话记录history以Markdown格式写入文件中如果没有指定文件名则使用当前时间生成文件名
"""
import os
import time
if file_name is None:
# file_name = time.strftime("chatGPT分析报告%Y-%m-%d-%H-%M-%S", time.localtime()) + '.md'
file_name = 'chatGPT分析报告' + \
time.strftime("%Y-%m-%d-%H-%M-%S", time.localtime()) + '.md'
os.makedirs('./gpt_log/', exist_ok=True)
with open(f'./gpt_log/{file_name}', 'w', encoding='utf8') as f:
f.write('# chatGPT 分析报告\n')
for i, content in enumerate(history):
try: # 这个bug没找到触发条件暂时先这样顶一下
if type(content) != str:
content = str(content)
except:
continue
if i % 2 == 0:
f.write('## ')
f.write(content)
f.write('\n\n')
res = '以上材料已经被写入' + os.path.abspath(f'./gpt_log/{file_name}')
print(res)
return res
def regular_txt_to_markdown(text):
"""
将普通文本转换为Markdown格式的文本
"""
text = text.replace('\n', '\n\n')
text = text.replace('\n\n\n', '\n\n')
text = text.replace('\n\n\n', '\n\n')
return text
def report_execption(chatbot, history, a, b):
"""
向chatbot中添加错误信息
向chatbot中添加错误信息
"""
chatbot.append((a, b))
history.append(a)
@ -225,7 +165,7 @@ def report_execption(chatbot, history, a, b):
def text_divide_paragraph(text):
"""
将文本按照段落分隔符分割开生成带有段落标签的HTML代码
将文本按照段落分隔符分割开生成带有段落标签的HTML代码
"""
if '```' in text:
# careful input
@ -241,7 +181,7 @@ def text_divide_paragraph(text):
def markdown_convertion(txt):
"""
将Markdown格式的文本转换为HTML格式如果包含数学公式则先将公式转换为HTML格式
将Markdown格式的文本转换为HTML格式如果包含数学公式则先将公式转换为HTML格式
"""
pre = '<div class="markdown-body">'
suf = '</div>'
@ -333,7 +273,7 @@ def close_up_code_segment_during_stream(gpt_reply):
def format_io(self, y):
"""
将输入和输出解析为HTML格式将y中最后一项的输入部分段落化并将输出部分的Markdown和数学公式转换为HTML格式
将输入和输出解析为HTML格式将y中最后一项的输入部分段落化并将输出部分的Markdown和数学公式转换为HTML格式
"""
if y is None or y == []:
return []
@ -349,7 +289,7 @@ def format_io(self, y):
def find_free_port():
"""
返回当前系统中可用的未使用端口
返回当前系统中可用的未使用端口
"""
import socket
from contextlib import closing
@ -428,7 +368,7 @@ def find_recent_files(directory):
return recent_files
def on_file_uploaded(files, chatbot, txt):
def on_file_uploaded(files, chatbot, txt, txt2, checkboxes):
if len(files) == 0:
return chatbot, txt
import shutil
@ -450,13 +390,18 @@ def on_file_uploaded(files, chatbot, txt):
dest_dir=f'private_upload/{time_tag}/{file_origin_name}.extract')
moved_files = [fp for fp in glob.glob(
'private_upload/**/*', recursive=True)]
txt = f'private_upload/{time_tag}'
if "底部输入区" in checkboxes:
txt = ""
txt2 = f'private_upload/{time_tag}'
else:
txt = f'private_upload/{time_tag}'
txt2 = ""
moved_files_str = '\t\n\n'.join(moved_files)
chatbot.append(['我上传了文件,请查收',
f'[Local Message] 收到以下文件: \n\n{moved_files_str}' +
f'\n\n调用路径参数已自动修正到: \n\n{txt}' +
f'\n\n现在您点击任意“红颜色”标识的函数插件时,以上文件将被作为输入参数'+err_msg])
return chatbot, txt
return chatbot, txt, txt2
def on_report_generated(files, chatbot):
@ -469,9 +414,43 @@ def on_report_generated(files, chatbot):
return report_files, chatbot
def is_openai_api_key(key):
# 正确的 API_KEY 是 "sk-" + 48 位大小写字母数字的组合
API_MATCH = re.match(r"sk-[a-zA-Z0-9]{48}$", key)
return API_MATCH
return bool(API_MATCH)
def is_api2d_key(key):
if key.startswith('fk') and len(key) == 41:
return True
else:
return False
def is_any_api_key(key):
if ',' in key:
keys = key.split(',')
for k in keys:
if is_any_api_key(k): return True
return False
else:
return is_openai_api_key(key) or is_api2d_key(key)
def select_api_key(keys, llm_model):
import random
avail_key_list = []
key_list = keys.split(',')
if llm_model.startswith('gpt-'):
for k in key_list:
if is_openai_api_key(k): avail_key_list.append(k)
if llm_model.startswith('api2d-'):
for k in key_list:
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。")
api_key = random.choice(avail_key_list) # 随机负载均衡
return api_key
@lru_cache(maxsize=128)
def read_single_conf_with_lru_cache(arg):
@ -482,14 +461,13 @@ def read_single_conf_with_lru_cache(arg):
r = getattr(importlib.import_module('config'), arg)
# 在读取API_KEY时检查一下是不是忘了改config
if arg == 'API_KEY':
if is_openai_api_key(r):
if is_any_api_key(r):
print亮绿(f"[API_KEY] 您的 API_KEY 是: {r[:15]}*** API_KEY 导入成功")
else:
print亮红( "[API_KEY] 正确的 API_KEY 是 'sk-' + '48 位大小写字母数字' 的组合请在config文件中修改API密钥, 添加海外代理之后再运行。" + \
"如果您刚更新过代码请确保旧版config_private文件中没有遗留任何新增键值")
print亮红( "[API_KEY] 正确的 API_KEY 是'sk'开头的51位密钥OpenAI或者 'fk'开头的41位密钥请在config文件中修改API密钥之后再运行。")
if arg == 'proxies':
if r is None:
print亮红('[PROXY] 网络代理状态:未配置。无代理状态下很可能无法访问。建议检查USE_PROXY选项是否修改。')
print亮红('[PROXY] 网络代理状态:未配置。无代理状态下很可能无法访问OpenAI家族的模型。建议检查USE_PROXY选项是否修改。')
else:
print亮绿('[PROXY] 网络代理状态:已配置。配置信息如下:', r)
assert isinstance(r, dict), 'proxies格式错误请注意proxies选项的格式不要遗漏括号。'

View File

@ -1,5 +1,5 @@
{
"version": 2.7,
"version": 3.1,
"show_feature": true,
"new_feature": "修复BUG <-> 改善理解pdfchatpdf功能 <-> 如果一键更新失败可前往github手动更新"
"new_feature": "添加支持清华ChatGLM和GPT-4 <-> 改进架构支持与多个LLM模型同时对话 <-> 添加支持API2D国内可支持gpt4<-> 支持多API-KEY负载均衡并列填写逗号分割 <-> 添加输入区文本清除按键"
}