比较提交

..

23 次代码提交

作者 SHA1 备注 提交日期
Yuki
163f12c533 # fix com_zhipuglm.py illegal temperature problem (#1687)
* Update com_zhipuglm.py

# fix 用户在使用 zhipuai 界面时遇到了关于温度参数的非法参数错误
2024-04-08 12:17:07 +08:00
binary-husky
bdd46c5dd1 Version 3.74: Merge latest updates on dev branch (frontier) (#1621)
* Update version to 3.74

* Add support for Yi Model API (#1635)

* 更新以支持零一万物模型

* 删除newbing

* 修改config

---------

Co-authored-by: binary-husky <qingxu.fu@outlook.com>

* Refactor function signatures in bridge files

* fix qwen api change

* rename and ref functions

* rename and move some cookie functions

* 增加haiku模型,新增endpoint配置说明 (#1626)

* haiku added

* 新增haiku,新增endpoint配置说明

* Haiku added

* 将说明同步至最新Endpoint

---------

Co-authored-by: binary-husky <qingxu.fu@outlook.com>

* private_upload目录下进行文件鉴权 (#1596)

* private_upload目录下进行文件鉴权

* minor fastapi adjustment

* Add logging functionality to enable saving
conversation records

* waiting to fix username retrieve

* support 2rd web path

* allow accessing default user dir

---------

Co-authored-by: binary-husky <qingxu.fu@outlook.com>

* remove yaml deps

* fix favicon

* fix abs path auth problem

* forget to write a return

* add `dashscope` to deps

* fix GHSA-v9q9-xj86-953p

* 用户名重叠越权访问patch (#1681)

* add cohere model api access

* cohere + can_multi_thread

* fix block user access(fail)

* fix fastapi bug

* change cohere api endpoint

* explain version

---------

Co-authored-by: Menghuan1918 <menghuan2003@outlook.com>
Co-authored-by: Skyzayre <120616113+Skyzayre@users.noreply.github.com>
Co-authored-by: XIao <46100050+Kilig947@users.noreply.github.com>
2024-04-08 11:49:30 +08:00
binary-husky
ae51a0e686 fix GHSA-v9q9-xj86-953p 2024-04-05 20:47:11 +08:00
binary-husky
f2582ea137 fix qwen api change 2024-04-03 12:17:41 +08:00
binary-husky
ddd2fd84da fix checkbox bugs 2024-04-02 19:42:55 +08:00
binary-husky
6c90ff80ea add prompt and temperature to cookie 2024-04-02 18:02:00 +08:00
binary-husky
cb7c0703be Update requirements.txt (#1668) 2024-04-01 11:30:50 +08:00
binary-husky
5181cd441d change pip install url due to server failure (#1667) 2024-04-01 11:20:14 +08:00
binary-husky
216d4374e7 fix color list overflow 2024-04-01 00:11:32 +08:00
iluem
8af6c0cab6 Qhaoduoyu patch 1: pickle to json to increase security (#1648)
* Update theme.py

fix bugs

* Update theme.py

fix bugs

* change var names

---------

Co-authored-by: binary-husky <qingxu.fu@outlook.com>
2024-03-25 09:54:30 +08:00
binary-husky
67ad041372 fix issue #1640 2024-03-20 18:09:37 +08:00
binary-husky
725c72229c update docker compose 2024-03-20 17:37:03 +08:00
Menghuan1918
e42ede512b Update Claude3 api request and fix some bugs (#1641)
* Update version to 3.74

* Add support for Yi Model API (#1635)

* 更新以支持零一万物模型

* 删除newbing

* 修改config

---------

Co-authored-by: binary-husky <qingxu.fu@outlook.com>

* Update claude requrest to http type

* Update for endpoint

* Add support for other tpyes of pictures

* Update pip packages

* Fix console_slience issue while error handling

* revert version changes

---------

Co-authored-by: binary-husky <qingxu.fu@outlook.com>
2024-03-20 17:22:23 +08:00
binary-husky
84ccc9e64c fix claude + oneapi error 2024-03-17 14:53:28 +08:00
binary-husky
c172847e19 add python annotations for toolbox functions 2024-03-16 22:54:33 +08:00
binary-husky
d166d25eb4 resolve invalid escape sequence warning
to support python3.12
2024-03-11 18:10:05 +08:00
binary-husky
516bbb1331 Update README.md 2024-03-11 17:40:16 +08:00
binary-husky
c3140ce344 merge frontier branch (#1620)
* Zhipu sdk update 适配最新的智谱SDK,支持GLM4v (#1502)

* 适配 google gemini 优化为从用户input中提取文件

* 适配最新的智谱SDK、支持glm-4v

* requirements.txt fix

* pending history check

---------

Co-authored-by: binary-husky <qingxu.fu@outlook.com>

* Update "生成多种Mermaid图表" plugin: Separate out the file reading function (#1520)

* Update crazy_functional.py with new functionality deal with PDF

* Update crazy_functional.py and Mermaid.py for plugin_kwargs

* Update crazy_functional.py with new chart type: mind map

* Update SELECT_PROMPT and i_say_show_user messages

* Update ArgsReminder message in get_crazy_functions() function

* Update with read md file and update PROMPTS

* Return the PROMPTS as the test found that the initial version worked best

* Update Mermaid chart generation function

* version 3.71

* 解决issues #1510

* Remove unnecessary text from sys_prompt in 解析历史输入 function

* Remove sys_prompt message in 解析历史输入 function

* Update bridge_all.py: supports gpt-4-turbo-preview (#1517)

* Update bridge_all.py: supports gpt-4-turbo-preview

supports gpt-4-turbo-preview

* Update bridge_all.py

---------

Co-authored-by: binary-husky <96192199+binary-husky@users.noreply.github.com>

* Update config.py: supports gpt-4-turbo-preview (#1516)

* Update config.py: supports gpt-4-turbo-preview

supports gpt-4-turbo-preview

* Update config.py

---------

Co-authored-by: binary-husky <96192199+binary-husky@users.noreply.github.com>

* Refactor 解析历史输入 function to handle file input

* Update Mermaid chart generation functionality

* rename files and functions

---------

Co-authored-by: binary-husky <qingxu.fu@outlook.com>
Co-authored-by: hongyi-zhao <hongyi.zhao@gmail.com>
Co-authored-by: binary-husky <96192199+binary-husky@users.noreply.github.com>

* 接入mathpix ocr功能 (#1468)

* Update Latex输出PDF结果.py

借助mathpix实现了PDF翻译中文并重新编译PDF

* Update config.py

add mathpix appid & appkey

* Add 'PDF翻译中文并重新编译PDF' feature to plugins.

---------

Co-authored-by: binary-husky <96192199+binary-husky@users.noreply.github.com>

* fix zhipuai

* check picture

* remove glm-4 due to bug

* 修改config

* 检查MATHPIX_APPID

* Remove unnecessary code and update
function_plugins dictionary

* capture non-standard token overflow

* bug fix #1524

* change mermaid style

* 支持mermaid 滚动放大缩小重置,鼠标滚动和拖拽 (#1530)

* 支持mermaid 滚动放大缩小重置,鼠标滚动和拖拽

* 微调未果 先stage一下

* update

---------

Co-authored-by: binary-husky <qingxu.fu@outlook.com>
Co-authored-by: binary-husky <96192199+binary-husky@users.noreply.github.com>

* ver 3.72

* change live2d

* save the status of ``clear btn` in cookie

* 前端选择保持

* js ui bug fix

* reset btn bug fix

* update live2d tips

* fix missing get_token_num method

* fix live2d toggle switch

* fix persistent custom btn with cookie

* fix zhipuai feedback with core functionality

* Refactor button update and clean up functions

* tailing space removal

* Fix missing MATHPIX_APPID and MATHPIX_APPKEY
configuration

* Prompt fix、脑图提示词优化 (#1537)

* 适配 google gemini 优化为从用户input中提取文件

* 脑图提示词优化

* Fix missing MATHPIX_APPID and MATHPIX_APPKEY
configuration

---------

Co-authored-by: binary-husky <qingxu.fu@outlook.com>

* 优化“PDF翻译中文并重新编译PDF”插件 (#1602)

* Add gemini_endpoint to API_URL_REDIRECT (#1560)

* Add gemini_endpoint to API_URL_REDIRECT

* Update gemini-pro and gemini-pro-vision model_info
endpoints

* Update to support new claude models (#1606)

* Add anthropic library and update claude models

* 更新bridge_claude.py文件,添加了对图片输入的支持。修复了一些bug。

* 添加Claude_3_Models变量以限制图片数量

* Refactor code to improve readability and
maintainability

* minor claude bug fix

* more flexible one-api support

* reformat config

* fix one-api new access bug

* dummy

* compat non-standard api

* version 3.73

---------

Co-authored-by: XIao <46100050+Kilig947@users.noreply.github.com>
Co-authored-by: Menghuan1918 <menghuan2003@outlook.com>
Co-authored-by: hongyi-zhao <hongyi.zhao@gmail.com>
Co-authored-by: Hao Ma <893017927@qq.com>
Co-authored-by: zeyuan huang <599012428@qq.com>
2024-03-11 17:26:09 +08:00
binary-husky
cd18663800 compat non-standard api - 2 2024-03-10 17:13:54 +08:00
binary-husky
dbf1322836 compat non-standard api 2024-03-10 17:07:59 +08:00
XIao
98dd3ae1c0 Moonshot- 在config.py中增加可用模型 (#1603)
* 支持月之暗面api

* fix文案

* 优化noui的返回值,对话历史文件继续上传到moonshat

* fix

* config 可用模型配置增加

* add `can_multi_thread` model attr (#1598)

---------

Co-authored-by: binary-husky <96192199+binary-husky@users.noreply.github.com>
Co-authored-by: binary-husky <qingxu.fu@outlook.com>
2024-03-05 16:07:05 +08:00
binary-husky
3036709496 add can_multi_thread model attr (#1598) 2024-03-05 15:58:18 +08:00
XIao
8e9c07644f 支持月之暗面api,文件对话 (#1597)
* 支持月之暗面api

* fix文案
2024-03-03 23:42:17 +08:00
共有 103 个文件被更改,包括 2685 次插入1043 次删除

查看文件

@@ -1,7 +1,6 @@
> [!IMPORTANT] > [!IMPORTANT]
> 2024.3.11: 恭迎Claude3和Moonshot,全力支持Qwen、GLM、DeepseekCoder等中文大语言模型
> 2024.1.18: 更新3.70版本,支持Mermaid绘图库让大模型绘制脑图 > 2024.1.18: 更新3.70版本,支持Mermaid绘图库让大模型绘制脑图
> 2024.1.17: 恭迎GLM4,全力支持Qwen、GLM、DeepseekCoder等国内中文大语言基座模型
> 2024.1.17: 某些依赖包尚不兼容python 3.12,推荐python 3.11。
> 2024.1.17: 安装依赖时,请选择`requirements.txt`中**指定的版本**。 安装命令:`pip install -r requirements.txt`。本项目完全开源免费,您可通过订阅[在线服务](https://github.com/binary-husky/gpt_academic/wiki/online)的方式鼓励本项目的发展。 > 2024.1.17: 安装依赖时,请选择`requirements.txt`中**指定的版本**。 安装命令:`pip install -r requirements.txt`。本项目完全开源免费,您可通过订阅[在线服务](https://github.com/binary-husky/gpt_academic/wiki/online)的方式鼓励本项目的发展。
<br> <br>

查看文件

@@ -47,7 +47,7 @@ def backup_and_download(current_version, remote_version):
shutil.copytree('./', backup_dir, ignore=lambda x, y: ['history']) shutil.copytree('./', backup_dir, ignore=lambda x, y: ['history'])
proxies = get_conf('proxies') proxies = get_conf('proxies')
try: r = requests.get('https://github.com/binary-husky/chatgpt_academic/archive/refs/heads/master.zip', proxies=proxies, stream=True) try: r = requests.get('https://github.com/binary-husky/chatgpt_academic/archive/refs/heads/master.zip', proxies=proxies, stream=True)
except: r = requests.get('https://public.gpt-academic.top/publish/master.zip', proxies=proxies, stream=True) except: r = requests.get('https://public.agent-matrix.com/publish/master.zip', proxies=proxies, stream=True)
zip_file_path = backup_dir+'/master.zip' zip_file_path = backup_dir+'/master.zip'
with open(zip_file_path, 'wb+') as f: with open(zip_file_path, 'wb+') as f:
f.write(r.content) f.write(r.content)
@@ -113,7 +113,7 @@ def auto_update(raise_error=False):
import json import json
proxies = get_conf('proxies') proxies = get_conf('proxies')
try: response = requests.get("https://raw.githubusercontent.com/binary-husky/chatgpt_academic/master/version", proxies=proxies, timeout=5) try: response = requests.get("https://raw.githubusercontent.com/binary-husky/chatgpt_academic/master/version", proxies=proxies, timeout=5)
except: response = requests.get("https://public.gpt-academic.top/publish/version", proxies=proxies, timeout=5) except: response = requests.get("https://public.agent-matrix.com/publish/version", proxies=proxies, timeout=5)
remote_json_data = json.loads(response.text) remote_json_data = json.loads(response.text)
remote_version = remote_json_data['version'] remote_version = remote_json_data['version']
if remote_json_data["show_feature"]: if remote_json_data["show_feature"]:

查看文件

@@ -30,7 +30,33 @@ if USE_PROXY:
else: else:
proxies = None proxies = None
# ------------------------------------ 以下配置可以优化体验, 但大部分场合下并不需要修改 ------------------------------------ # [step 3]>> 模型选择是 (注意: LLM_MODEL是默认选中的模型, 它*必须*被包含在AVAIL_LLM_MODELS列表中 )
LLM_MODEL = "gpt-3.5-turbo-16k" # 可选 ↓↓↓
AVAIL_LLM_MODELS = ["gpt-4-1106-preview", "gpt-4-turbo-preview", "gpt-4-vision-preview",
"gpt-3.5-turbo-1106", "gpt-3.5-turbo-16k", "gpt-3.5-turbo", "azure-gpt-3.5",
"gpt-4", "gpt-4-32k", "azure-gpt-4", "glm-4", "glm-3-turbo",
"gemini-pro", "chatglm3"
]
# --- --- --- ---
# P.S. 其他可用的模型还包括
# AVAIL_LLM_MODELS = [
# "qianfan", "deepseekcoder",
# "spark", "sparkv2", "sparkv3", "sparkv3.5",
# "qwen-turbo", "qwen-plus", "qwen-max", "qwen-local",
# "moonshot-v1-128k", "moonshot-v1-32k", "moonshot-v1-8k",
# "gpt-3.5-turbo-0613", "gpt-3.5-turbo-16k-0613", "gpt-3.5-turbo-0125"
# "claude-3-haiku-20240307","claude-3-sonnet-20240229","claude-3-opus-20240229", "claude-2.1", "claude-instant-1.2",
# "moss", "llama2", "chatglm_onnx", "internlm", "jittorllms_pangualpha", "jittorllms_llama",
# "yi-34b-chat-0205", "yi-34b-chat-200k"
# ]
# --- --- --- ---
# 此外,为了更灵活地接入one-api多模型管理界面,您还可以在接入one-api时,
# 使用"one-api-*"前缀直接使用非标准方式接入的模型,例如
# AVAIL_LLM_MODELS = ["one-api-claude-3-sonnet-20240229(max_token=100000)"]
# --- --- --- ---
# --------------- 以下配置可以优化体验 ---------------
# 重新URL重新定向,实现更换API_URL的作用高危设置! 常规情况下不要修改! 通过修改此设置,您将把您的API-KEY和对话隐私完全暴露给您设定的中间人 # 重新URL重新定向,实现更换API_URL的作用高危设置! 常规情况下不要修改! 通过修改此设置,您将把您的API-KEY和对话隐私完全暴露给您设定的中间人
# 格式: API_URL_REDIRECT = {"https://api.openai.com/v1/chat/completions": "在这里填写重定向的api.openai.com的URL"} # 格式: API_URL_REDIRECT = {"https://api.openai.com/v1/chat/completions": "在这里填写重定向的api.openai.com的URL"}
@@ -85,20 +111,6 @@ MAX_RETRY = 2
DEFAULT_FN_GROUPS = ['对话', '编程', '学术', '智能体'] DEFAULT_FN_GROUPS = ['对话', '编程', '学术', '智能体']
# 模型选择是 (注意: LLM_MODEL是默认选中的模型, 它*必须*被包含在AVAIL_LLM_MODELS列表中 )
LLM_MODEL = "gpt-3.5-turbo-16k" # 可选 ↓↓↓
AVAIL_LLM_MODELS = ["gpt-4-1106-preview", "gpt-4-turbo-preview", "gpt-4-vision-preview",
"gpt-3.5-turbo-1106", "gpt-3.5-turbo-16k", "gpt-3.5-turbo", "azure-gpt-3.5",
"gpt-4", "gpt-4-32k", "azure-gpt-4", "glm-4", "glm-3-turbo",
"gemini-pro", "chatglm3", "claude-2"]
# P.S. 其他可用的模型还包括 [
# "moss", "qwen-turbo", "qwen-plus", "qwen-max"
# "zhipuai", "qianfan", "deepseekcoder", "llama2", "qwen-local", "gpt-3.5-turbo-0613",
# "gpt-3.5-turbo-16k-0613", "gpt-3.5-random", "api2d-gpt-3.5-turbo", 'api2d-gpt-3.5-turbo-16k',
# "spark", "sparkv2", "sparkv3", "chatglm_onnx", "claude-1-100k", "claude-2", "internlm", "jittorllms_pangualpha", "jittorllms_llama"
# ]
# 定义界面上“询问多个GPT模型”插件应该使用哪些模型,请从AVAIL_LLM_MODELS中选择,并在不同模型之间用`&`间隔,例如"gpt-3.5-turbo&chatglm3&azure-gpt-4" # 定义界面上“询问多个GPT模型”插件应该使用哪些模型,请从AVAIL_LLM_MODELS中选择,并在不同模型之间用`&`间隔,例如"gpt-3.5-turbo&chatglm3&azure-gpt-4"
MULTI_QUERY_LLM_MODELS = "gpt-3.5-turbo&chatglm3" MULTI_QUERY_LLM_MODELS = "gpt-3.5-turbo&chatglm3"
@@ -127,6 +139,7 @@ CHATGLM_PTUNING_CHECKPOINT = "" # 例如"/home/hmp/ChatGLM2-6B/ptuning/output/6b
LOCAL_MODEL_DEVICE = "cpu" # 可选 "cuda" LOCAL_MODEL_DEVICE = "cpu" # 可选 "cuda"
LOCAL_MODEL_QUANT = "FP16" # 默认 "FP16" "INT4" 启用量化INT4版本 "INT8" 启用量化INT8版本 LOCAL_MODEL_QUANT = "FP16" # 默认 "FP16" "INT4" 启用量化INT4版本 "INT8" 启用量化INT8版本
# 设置gradio的并行线程数不需要修改 # 设置gradio的并行线程数不需要修改
CONCURRENT_COUNT = 100 CONCURRENT_COUNT = 100
@@ -144,7 +157,8 @@ ADD_WAIFU = False
AUTHENTICATION = [] AUTHENTICATION = []
# 如果需要在二级路径下运行(常规情况下,不要修改!!需要配合修改main.py才能生效! # 如果需要在二级路径下运行(常规情况下,不要修改!!
# (举例 CUSTOM_PATH = "/gpt_academic",可以让软件运行在 http://ip:port/gpt_academic/ 下。)
CUSTOM_PATH = "/" CUSTOM_PATH = "/"
@@ -172,14 +186,8 @@ AZURE_ENGINE = "填入你亲手写的部署名" # 读 docs\use_azure.
AZURE_CFG_ARRAY = {} AZURE_CFG_ARRAY = {}
# 使用Newbing (不推荐使用,未来将删除) # 阿里云实时语音识别 配置难度较高
NEWBING_STYLE = "creative" # ["creative", "balanced", "precise"] # 参考 https://github.com/binary-husky/gpt_academic/blob/master/docs/use_audio.md
NEWBING_COOKIES = """
put your new bing cookies here
"""
# 阿里云实时语音识别 配置难度较高 仅建议高手用户使用 参考 https://github.com/binary-husky/gpt_academic/blob/master/docs/use_audio.md
ENABLE_AUDIO = False ENABLE_AUDIO = False
ALIYUN_TOKEN="" # 例如 f37f30e0f9934c34a992f6f64f7eba4f ALIYUN_TOKEN="" # 例如 f37f30e0f9934c34a992f6f64f7eba4f
ALIYUN_APPKEY="" # 例如 RoPlZrM88DnAFkZK ALIYUN_APPKEY="" # 例如 RoPlZrM88DnAFkZK
@@ -198,16 +206,18 @@ ZHIPUAI_API_KEY = ""
ZHIPUAI_MODEL = "" # 此选项已废弃,不再需要填写 ZHIPUAI_MODEL = "" # 此选项已废弃,不再需要填写
# # 火山引擎YUNQUE大模型
# YUNQUE_SECRET_KEY = ""
# YUNQUE_ACCESS_KEY = ""
# YUNQUE_MODEL = ""
# Claude API KEY # Claude API KEY
ANTHROPIC_API_KEY = "" ANTHROPIC_API_KEY = ""
# 月之暗面 API KEY
MOONSHOT_API_KEY = ""
# 零一万物(Yi Model) API KEY
YIMODEL_API_KEY = ""
# Mathpix 拥有执行PDF的OCR功能,但是需要注册账号 # Mathpix 拥有执行PDF的OCR功能,但是需要注册账号
MATHPIX_APPID = "" MATHPIX_APPID = ""
MATHPIX_APPKEY = "" MATHPIX_APPKEY = ""
@@ -266,7 +276,11 @@ PLUGIN_HOT_RELOAD = False
# 自定义按钮的最大数量限制 # 自定义按钮的最大数量限制
NUM_CUSTOM_BASIC_BTN = 4 NUM_CUSTOM_BASIC_BTN = 4
""" """
--------------- 配置关联关系说明 ---------------
在线大模型配置关联关系示意图 在线大模型配置关联关系示意图
├── "gpt-3.5-turbo" 等openai模型 ├── "gpt-3.5-turbo" 等openai模型
@@ -290,7 +304,7 @@ NUM_CUSTOM_BASIC_BTN = 4
│ ├── XFYUN_API_SECRET │ ├── XFYUN_API_SECRET
│ └── XFYUN_API_KEY │ └── XFYUN_API_KEY
├── "claude-1-100k" 等claude模型 ├── "claude-3-opus-20240229" 等claude模型
│ └── ANTHROPIC_API_KEY │ └── ANTHROPIC_API_KEY
├── "stack-claude" ├── "stack-claude"
@@ -305,15 +319,19 @@ NUM_CUSTOM_BASIC_BTN = 4
├── "glm-4", "glm-3-turbo", "zhipuai" 智谱AI大模型 ├── "glm-4", "glm-3-turbo", "zhipuai" 智谱AI大模型
│ └── ZHIPUAI_API_KEY │ └── ZHIPUAI_API_KEY
├── "yi-34b-chat-0205", "yi-34b-chat-200k" 等零一万物(Yi Model)大模型
│ └── YIMODEL_API_KEY
├── "qwen-turbo" 等通义千问大模型 ├── "qwen-turbo" 等通义千问大模型
│ └── DASHSCOPE_API_KEY │ └── DASHSCOPE_API_KEY
├── "Gemini" ├── "Gemini"
│ └── GEMINI_API_KEY │ └── GEMINI_API_KEY
└── "newbing" Newbing接口不再稳定,不推荐使用 └── "one-api-...(max_token=...)" 用一种更方便的方式接入one-api多模型管理界面
├── NEWBING_STYLE ├── AVAIL_LLM_MODELS
── NEWBING_COOKIES ── API_KEY
└── API_URL_REDIRECT
本地大模型示意图 本地大模型示意图

查看文件

@@ -38,12 +38,12 @@ def get_core_functions():
"总结绘制脑图": { "总结绘制脑图": {
# 前缀,会被加在你的输入之前。例如,用来描述你的要求,例如翻译、解释代码、润色等等 # 前缀,会被加在你的输入之前。例如,用来描述你的要求,例如翻译、解释代码、润色等等
"Prefix": r"", "Prefix": '''"""\n\n''',
# 后缀,会被加在你的输入之后。例如,配合前缀可以把你的输入内容用引号圈起来 # 后缀,会被加在你的输入之后。例如,配合前缀可以把你的输入内容用引号圈起来
"Suffix": "Suffix":
# dedent() 函数用于去除多行字符串的缩进 # dedent() 函数用于去除多行字符串的缩进
dedent("\n"+r''' dedent("\n\n"+r'''
============================== """
使用mermaid flowchart对以上文本进行总结,概括上述段落的内容以及内在逻辑关系,例如 使用mermaid flowchart对以上文本进行总结,概括上述段落的内容以及内在逻辑关系,例如
@@ -57,7 +57,7 @@ def get_core_functions():
C --> |"箭头名2"| F["节点名6"] C --> |"箭头名2"| F["节点名6"]
``` ```
警告 注意
1使用中文 1使用中文
2节点名字使用引号包裹,如["Laptop"] 2节点名字使用引号包裹,如["Laptop"]
3`|` 和 `"`之间不要存在空格 3`|` 和 `"`之间不要存在空格

查看文件

@@ -81,8 +81,8 @@ def 多文件润色(file_manifest, project_folder, llm_kwargs, plugin_kwargs, ch
# <-------- 多线程润色开始 ----------> # <-------- 多线程润色开始 ---------->
if language == 'en': if language == 'en':
if mode == 'polish': if mode == 'polish':
inputs_array = ["Below is a section from an academic paper, polish this section to meet the academic standard, " + inputs_array = [r"Below is a section from an academic paper, polish this section to meet the academic standard, " +
"improve the grammar, clarity and overall readability, do not modify any latex command such as \section, \cite and equations:" + r"improve the grammar, clarity and overall readability, do not modify any latex command such as \section, \cite and equations:" +
f"\n\n{frag}" for frag in pfg.sp_file_contents] f"\n\n{frag}" for frag in pfg.sp_file_contents]
else: else:
inputs_array = [r"Below is a section from an academic paper, proofread this section." + inputs_array = [r"Below is a section from an academic paper, proofread this section." +
@@ -93,10 +93,10 @@ def 多文件润色(file_manifest, project_folder, llm_kwargs, plugin_kwargs, ch
sys_prompt_array = ["You are a professional academic paper writer." for _ in range(n_split)] sys_prompt_array = ["You are a professional academic paper writer." for _ in range(n_split)]
elif language == 'zh': elif language == 'zh':
if mode == 'polish': if mode == 'polish':
inputs_array = [f"以下是一篇学术论文中的一段内容,请将此部分润色以满足学术标准,提高语法、清晰度和整体可读性,不要修改任何LaTeX命令,例如\section,\cite和方程式" + inputs_array = [r"以下是一篇学术论文中的一段内容,请将此部分润色以满足学术标准,提高语法、清晰度和整体可读性,不要修改任何LaTeX命令,例如\section,\cite和方程式" +
f"\n\n{frag}" for frag in pfg.sp_file_contents] f"\n\n{frag}" for frag in pfg.sp_file_contents]
else: else:
inputs_array = [f"以下是一篇学术论文中的一段内容,请对这部分内容进行语法矫正。不要修改任何LaTeX命令,例如\section,\cite和方程式" + inputs_array = [r"以下是一篇学术论文中的一段内容,请对这部分内容进行语法矫正。不要修改任何LaTeX命令,例如\section,\cite和方程式" +
f"\n\n{frag}" for frag in pfg.sp_file_contents] f"\n\n{frag}" for frag in pfg.sp_file_contents]
inputs_show_user_array = [f"润色 {f}" for f in pfg.sp_file_tag] inputs_show_user_array = [f"润色 {f}" for f in pfg.sp_file_tag]
sys_prompt_array=["你是一位专业的中文学术论文作家。" for _ in range(n_split)] sys_prompt_array=["你是一位专业的中文学术论文作家。" for _ in range(n_split)]

查看文件

@@ -1,4 +1,4 @@
from toolbox import update_ui, trimmed_format_exc, get_conf, get_log_folder, promote_file_to_downloadzone from toolbox import update_ui, trimmed_format_exc, get_conf, get_log_folder, promote_file_to_downloadzone, check_repeat_upload, map_file_to_sha256
from toolbox import CatchException, report_exception, update_ui_lastest_msg, zip_result, gen_time_str from toolbox import CatchException, report_exception, update_ui_lastest_msg, zip_result, gen_time_str
from functools import partial from functools import partial
import glob, os, requests, time, json, tarfile import glob, os, requests, time, json, tarfile
@@ -438,47 +438,101 @@ def PDF翻译中文并重新编译PDF(txt, llm_kwargs, plugin_kwargs, chatbot, h
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
return return
# <-------------- convert pdf into tex -------------> hash_tag = map_file_to_sha256(file_manifest[0])
project_folder = pdf2tex_project(file_manifest[0])
# Translate English Latex to Chinese Latex, and compile it # <-------------- check repeated pdf ------------->
file_manifest = [f for f in glob.glob(f'{project_folder}/**/*.tex', recursive=True)] chatbot.append([f"检查PDF是否被重复上传", "正在检查..."])
if len(file_manifest) == 0: yield from update_ui(chatbot=chatbot, history=history)
report_exception(chatbot, history, a=f"解析项目: {txt}", b=f"找不到任何.tex文件: {txt}") repeat, project_folder = check_repeat_upload(file_manifest[0], hash_tag)
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
return
# <-------------- if is a zip/tar file -------------> except_flag = False
project_folder = desend_to_extracted_folder_if_exist(project_folder)
# <-------------- move latex project away from temp folder -------------> if repeat:
project_folder = move_project(project_folder) yield from update_ui_lastest_msg(f"发现重复上传,请查收结果(压缩包)...", chatbot=chatbot, history=history)
# <-------------- if merge_translate_zh is already generated, skip gpt req -------------> try:
if not os.path.exists(project_folder + '/merge_translate_zh.tex'): trans_html_file = [f for f in glob.glob(f'{project_folder}/**/*.trans.html', recursive=True)][0]
yield from Latex精细分解与转化(file_manifest, project_folder, llm_kwargs, plugin_kwargs, promote_file_to_downloadzone(trans_html_file, rename_file=None, chatbot=chatbot)
chatbot, history, system_prompt, mode='translate_zh',
switch_prompt=_switch_prompt_)
# <-------------- compile PDF -------------> translate_pdf = [f for f in glob.glob(f'{project_folder}/**/merge_translate_zh.pdf', recursive=True)][0]
success = yield from 编译Latex(chatbot, history, main_file_original='merge', promote_file_to_downloadzone(translate_pdf, rename_file=None, chatbot=chatbot)
main_file_modified='merge_translate_zh', mode='translate_zh',
work_folder_original=project_folder, work_folder_modified=project_folder,
work_folder=project_folder)
# <-------------- zip PDF -------------> comparison_pdf = [f for f in glob.glob(f'{project_folder}/**/comparison.pdf', recursive=True)][0]
zip_res = zip_result(project_folder) promote_file_to_downloadzone(comparison_pdf, rename_file=None, chatbot=chatbot)
if success:
chatbot.append((f"成功啦", '请查收结果(压缩包)...'))
yield from update_ui(chatbot=chatbot, history=history);
time.sleep(1) # 刷新界面
promote_file_to_downloadzone(file=zip_res, chatbot=chatbot)
else:
chatbot.append((f"失败了",
'虽然PDF生成失败了, 但请查收结果(压缩包), 内含已经翻译的Tex文档, 您可以到Github Issue区, 用该压缩包进行反馈。如系统是Linux,请检查系统字体见Github wiki ...'))
yield from update_ui(chatbot=chatbot, history=history);
time.sleep(1) # 刷新界面
promote_file_to_downloadzone(file=zip_res, chatbot=chatbot)
# <-------------- we are done -------------> zip_res = zip_result(project_folder)
return success promote_file_to_downloadzone(file=zip_res, chatbot=chatbot)
return True
except:
report_exception(chatbot, history, b=f"发现重复上传,但是无法找到相关文件")
yield from update_ui(chatbot=chatbot, history=history)
chatbot.append([f"没有相关文件", '尝试重新翻译PDF...'])
yield from update_ui(chatbot=chatbot, history=history)
except_flag = True
elif not repeat or except_flag:
yield from update_ui_lastest_msg(f"未发现重复上传", chatbot=chatbot, history=history)
# <-------------- convert pdf into tex ------------->
chatbot.append([f"解析项目: {txt}", "正在将PDF转换为tex项目,请耐心等待..."])
yield from update_ui(chatbot=chatbot, history=history)
project_folder = pdf2tex_project(file_manifest[0])
if project_folder is None:
report_exception(chatbot, history, a=f"解析项目: {txt}", b=f"PDF转换为tex项目失败")
yield from update_ui(chatbot=chatbot, history=history)
return False
# <-------------- translate latex file into Chinese ------------->
yield from update_ui_lastest_msg("正在tex项目将翻译为中文...", chatbot=chatbot, history=history)
file_manifest = [f for f in glob.glob(f'{project_folder}/**/*.tex', recursive=True)]
if len(file_manifest) == 0:
report_exception(chatbot, history, a=f"解析项目: {txt}", b=f"找不到任何.tex文件: {txt}")
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
return
# <-------------- if is a zip/tar file ------------->
project_folder = desend_to_extracted_folder_if_exist(project_folder)
# <-------------- move latex project away from temp folder ------------->
project_folder = move_project(project_folder)
# <-------------- set a hash tag for repeat-checking ------------->
with open(pj(project_folder, hash_tag + '.tag'), 'w') as f:
f.write(hash_tag)
f.close()
# <-------------- if merge_translate_zh is already generated, skip gpt req ------------->
if not os.path.exists(project_folder + '/merge_translate_zh.tex'):
yield from Latex精细分解与转化(file_manifest, project_folder, llm_kwargs, plugin_kwargs,
chatbot, history, system_prompt, mode='translate_zh',
switch_prompt=_switch_prompt_)
# <-------------- compile PDF ------------->
yield from update_ui_lastest_msg("正在将翻译好的项目tex项目编译为PDF...", chatbot=chatbot, history=history)
success = yield from 编译Latex(chatbot, history, main_file_original='merge',
main_file_modified='merge_translate_zh', mode='translate_zh',
work_folder_original=project_folder, work_folder_modified=project_folder,
work_folder=project_folder)
# <-------------- zip PDF ------------->
zip_res = zip_result(project_folder)
if success:
chatbot.append((f"成功啦", '请查收结果(压缩包)...'))
yield from update_ui(chatbot=chatbot, history=history);
time.sleep(1) # 刷新界面
promote_file_to_downloadzone(file=zip_res, chatbot=chatbot)
else:
chatbot.append((f"失败了",
'虽然PDF生成失败了, 但请查收结果(压缩包), 内含已经翻译的Tex文档, 您可以到Github Issue区, 用该压缩包进行反馈。如系统是Linux,请检查系统字体见Github wiki ...'))
yield from update_ui(chatbot=chatbot, history=history);
time.sleep(1) # 刷新界面
promote_file_to_downloadzone(file=zip_res, chatbot=chatbot)
# <-------------- we are done ------------->
return success

查看文件

@@ -135,13 +135,25 @@ def request_gpt_model_in_new_thread_with_ui_alive(
yield from update_ui(chatbot=chatbot, history=[]) # 如果最后成功了,则删除报错信息 yield from update_ui(chatbot=chatbot, history=[]) # 如果最后成功了,则删除报错信息
return final_result return final_result
def can_multi_process(llm): def can_multi_process(llm) -> bool:
if llm.startswith('gpt-'): return True from request_llms.bridge_all import model_info
if llm.startswith('api2d-'): return True
if llm.startswith('azure-'): return True def default_condition(llm) -> bool:
if llm.startswith('spark'): return True # legacy condition
if llm.startswith('zhipuai') or llm.startswith('glm-'): return True if llm.startswith('gpt-'): return True
return False if llm.startswith('api2d-'): return True
if llm.startswith('azure-'): return True
if llm.startswith('spark'): return True
if llm.startswith('zhipuai') or llm.startswith('glm-'): return True
return False
if llm in model_info:
if 'can_multi_thread' in model_info[llm]:
return model_info[llm]['can_multi_thread']
else:
return default_condition(llm)
else:
return default_condition(llm)
def request_gpt_model_multi_threads_with_very_awesome_ui_and_high_efficiency( def request_gpt_model_multi_threads_with_very_awesome_ui_and_high_efficiency(
inputs_array, inputs_show_user_array, llm_kwargs, inputs_array, inputs_show_user_array, llm_kwargs,

查看文件

@@ -345,9 +345,12 @@ def 解析任意code项目(txt, llm_kwargs, plugin_kwargs, chatbot, history, sys
pattern_except_suffix = [_.lstrip(" ^*.,").rstrip(" ,") for _ in txt_pattern.split(" ") if _ != "" and _.strip().startswith("^*.")] pattern_except_suffix = [_.lstrip(" ^*.,").rstrip(" ,") for _ in txt_pattern.split(" ") if _ != "" and _.strip().startswith("^*.")]
pattern_except_suffix += ['zip', 'rar', '7z', 'tar', 'gz'] # 避免解析压缩文件 pattern_except_suffix += ['zip', 'rar', '7z', 'tar', 'gz'] # 避免解析压缩文件
# 将要忽略匹配的文件名(例如: ^README.md) # 将要忽略匹配的文件名(例如: ^README.md)
pattern_except_name = [_.lstrip(" ^*,").rstrip(" ,").replace(".", "\.") for _ in txt_pattern.split(" ") if _ != "" and _.strip().startswith("^") and not _.strip().startswith("^*.")] pattern_except_name = [_.lstrip(" ^*,").rstrip(" ,").replace(".", r"\.") # 移除左边通配符,移除右侧逗号,转义点号
for _ in txt_pattern.split(" ") # 以空格分割
if (_ != "" and _.strip().startswith("^") and not _.strip().startswith("^*.")) # ^开始,但不是^*.开始
]
# 生成正则表达式 # 生成正则表达式
pattern_except = '/[^/]+\.(' + "|".join(pattern_except_suffix) + ')$' pattern_except = r'/[^/]+\.(' + "|".join(pattern_except_suffix) + ')$'
pattern_except += '|/(' + "|".join(pattern_except_name) + ')$' if pattern_except_name != [] else '' pattern_except += '|/(' + "|".join(pattern_except_name) + ')$' if pattern_except_name != [] else ''
history.clear() history.clear()

查看文件

@@ -1,12 +1,12 @@
## =================================================== ## ===================================================
# docker-compose.yml # docker-compose.yml
## =================================================== ## ===================================================
# 1. 请在以下方案中选择任意一种,然后删除其他的方案 # 1. 请在以下方案中选择任意一种,然后删除其他的方案
# 2. 修改你选择的方案中的environment环境变量,详情请见github wiki或者config.py # 2. 修改你选择的方案中的environment环境变量,详情请见github wiki或者config.py
# 3. 选择一种暴露服务端口的方法,并对相应的配置做出修改: # 3. 选择一种暴露服务端口的方法,并对相应的配置做出修改:
# 方法1: 适用于Linux,很方便,可惜windows不支持与宿主的网络融合为一体,这个是默认配置 # 方法1: 适用于Linux,很方便,可惜windows不支持与宿主的网络融合为一体,这个是默认配置
# network_mode: "host" # network_mode: "host"
# 方法2: 适用于所有系统包括Windows和MacOS端口映射,把容器的端口映射到宿主的端口注意您需要先删除network_mode: "host",再追加以下内容) # 方法2: 适用于所有系统包括Windows和MacOS端口映射,把容器的端口映射到宿主的端口注意您需要先删除network_mode: "host",再追加以下内容)
# ports: # ports:
# - "12345:12345" # 注意12345必须与WEB_PORT环境变量相互对应 # - "12345:12345" # 注意12345必须与WEB_PORT环境变量相互对应
# 4. 最后`docker-compose up`运行 # 4. 最后`docker-compose up`运行
@@ -25,7 +25,7 @@
## =================================================== ## ===================================================
## =================================================== ## ===================================================
## 方案零 部署项目的全部能力这个是包含cuda和latex的大型镜像。如果您网速慢、硬盘小或没有显卡,则不推荐使用这个 ## 方案零 部署项目的全部能力这个是包含cuda和latex的大型镜像。如果您网速慢、硬盘小或没有显卡,则不推荐使用这个
## =================================================== ## ===================================================
version: '3' version: '3'
services: services:
@@ -63,10 +63,10 @@ services:
# count: 1 # count: 1
# capabilities: [gpu] # capabilities: [gpu]
# WEB_PORT暴露方法1: 适用于Linux与宿主的网络融合 # WEB_PORT暴露方法1: 适用于Linux与宿主的网络融合
network_mode: "host" network_mode: "host"
# WEB_PORT暴露方法2: 适用于所有系统端口映射 # WEB_PORT暴露方法2: 适用于所有系统端口映射
# ports: # ports:
# - "12345:12345" # 12345必须与WEB_PORT相互对应 # - "12345:12345" # 12345必须与WEB_PORT相互对应
@@ -75,10 +75,8 @@ services:
bash -c "python3 -u main.py" bash -c "python3 -u main.py"
## =================================================== ## ===================================================
## 方案一 如果不需要运行本地模型(仅 chatgpt, azure, 星火, 千帆, claude 等在线大模型服务) ## 方案一 如果不需要运行本地模型(仅 chatgpt, azure, 星火, 千帆, claude 等在线大模型服务)
## =================================================== ## ===================================================
version: '3' version: '3'
services: services:
@@ -97,16 +95,16 @@ services:
# DEFAULT_WORKER_NUM: ' 10 ' # DEFAULT_WORKER_NUM: ' 10 '
# AUTHENTICATION: ' [("username", "passwd"), ("username2", "passwd2")] ' # AUTHENTICATION: ' [("username", "passwd"), ("username2", "passwd2")] '
# 与宿主的网络融合 # 「WEB_PORT暴露方法1: 适用于Linux」与宿主的网络融合
network_mode: "host" network_mode: "host"
# 不使用代理网络拉取最新代码 # 启动命令
command: > command: >
bash -c "python3 -u main.py" bash -c "python3 -u main.py"
### =================================================== ### ===================================================
### 方案二 如果需要运行ChatGLM + Qwen + MOSS等本地模型 ### 方案二 如果需要运行ChatGLM + Qwen + MOSS等本地模型
### =================================================== ### ===================================================
version: '3' version: '3'
services: services:
@@ -130,8 +128,10 @@ services:
devices: devices:
- /dev/nvidia0:/dev/nvidia0 - /dev/nvidia0:/dev/nvidia0
# 与宿主的网络融合 # 「WEB_PORT暴露方法1: 适用于Linux」与宿主的网络融合
network_mode: "host" network_mode: "host"
# 启动命令
command: > command: >
bash -c "python3 -u main.py" bash -c "python3 -u main.py"
@@ -139,8 +139,9 @@ services:
# command: > # command: >
# bash -c "pip install -r request_llms/requirements_qwen.txt && python3 -u main.py" # bash -c "pip install -r request_llms/requirements_qwen.txt && python3 -u main.py"
### =================================================== ### ===================================================
### 方案三 如果需要运行ChatGPT + LLAMA + 盘古 + RWKV本地模型 ### 方案三 如果需要运行ChatGPT + LLAMA + 盘古 + RWKV本地模型
### =================================================== ### ===================================================
version: '3' version: '3'
services: services:
@@ -164,16 +165,16 @@ services:
devices: devices:
- /dev/nvidia0:/dev/nvidia0 - /dev/nvidia0:/dev/nvidia0
# 与宿主的网络融合 # 「WEB_PORT暴露方法1: 适用于Linux」与宿主的网络融合
network_mode: "host" network_mode: "host"
# 不使用代理网络拉取最新代码 # 启动命令
command: > command: >
python3 -u main.py python3 -u main.py
## =================================================== ## ===================================================
## 方案四 ChatGPT + Latex ## 方案四 ChatGPT + Latex
## =================================================== ## ===================================================
version: '3' version: '3'
services: services:
@@ -190,16 +191,16 @@ services:
DEFAULT_WORKER_NUM: ' 10 ' DEFAULT_WORKER_NUM: ' 10 '
WEB_PORT: ' 12303 ' WEB_PORT: ' 12303 '
# 与宿主的网络融合 # 「WEB_PORT暴露方法1: 适用于Linux」与宿主的网络融合
network_mode: "host" network_mode: "host"
# 不使用代理网络拉取最新代码 # 启动命令
command: > command: >
bash -c "python3 -u main.py" bash -c "python3 -u main.py"
## =================================================== ## ===================================================
## 方案五 ChatGPT + 语音助手 (请先阅读 docs/use_audio.md ## 方案五 ChatGPT + 语音助手 (请先阅读 docs/use_audio.md
## =================================================== ## ===================================================
version: '3' version: '3'
services: services:
@@ -223,9 +224,9 @@ services:
# (无需填写) ALIYUN_ACCESSKEY: ' LTAI5q6BrFUzoRXVGUWnekh1 ' # (无需填写) ALIYUN_ACCESSKEY: ' LTAI5q6BrFUzoRXVGUWnekh1 '
# (无需填写) ALIYUN_SECRET: ' eHmI20AVWIaQZ0CiTD2bGQVsaP9i68 ' # (无需填写) ALIYUN_SECRET: ' eHmI20AVWIaQZ0CiTD2bGQVsaP9i68 '
# 与宿主的网络融合 # 「WEB_PORT暴露方法1: 适用于Linux」与宿主的网络融合
network_mode: "host" network_mode: "host"
# 不使用代理网络拉取最新代码 # 启动命令
command: > command: >
bash -c "python3 -u main.py" bash -c "python3 -u main.py"

140
main.py
查看文件

@@ -13,9 +13,20 @@ help_menu_description = \
</br></br>如何语音对话: 请阅读Wiki </br></br>如何语音对话: 请阅读Wiki
</br></br>如何临时更换API_KEY: 在输入区输入临时API_KEY后提交网页刷新后失效""" </br></br>如何临时更换API_KEY: 在输入区输入临时API_KEY后提交网页刷新后失效"""
def enable_log(PATH_LOGGING):
import logging, uuid
admin_log_path = os.path.join(PATH_LOGGING, "admin")
os.makedirs(admin_log_path, exist_ok=True)
log_dir = os.path.join(admin_log_path, "chat_secrets.log")
try:logging.basicConfig(filename=log_dir, level=logging.INFO, encoding="utf-8", format="%(asctime)s %(levelname)-8s %(message)s", datefmt="%Y-%m-%d %H:%M:%S")
except:logging.basicConfig(filename=log_dir, level=logging.INFO, format="%(asctime)s %(levelname)-8s %(message)s", datefmt="%Y-%m-%d %H:%M:%S")
# Disable logging output from the 'httpx' logger
logging.getLogger("httpx").setLevel(logging.WARNING)
print(f"所有对话记录将自动保存在本地目录{log_dir}, 请注意自我隐私保护哦!")
def main(): def main():
import gradio as gr import gradio as gr
if gr.__version__ not in ['3.32.8']: if gr.__version__ not in ['3.32.9']:
raise ModuleNotFoundError("使用项目内置Gradio获取最优体验! 请运行 `pip install -r requirements.txt` 指令安装内置Gradio及其他依赖, 详情信息见requirements.txt.") raise ModuleNotFoundError("使用项目内置Gradio获取最优体验! 请运行 `pip install -r requirements.txt` 指令安装内置Gradio及其他依赖, 详情信息见requirements.txt.")
from request_llms.bridge_all import predict from request_llms.bridge_all import predict
from toolbox import format_io, find_free_port, on_file_uploaded, on_report_generated, get_conf, ArgsGeneralWrapper, load_chat_cookies, DummyWith from toolbox import format_io, find_free_port, on_file_uploaded, on_report_generated, get_conf, ArgsGeneralWrapper, load_chat_cookies, DummyWith
@@ -23,25 +34,19 @@ def main():
proxies, WEB_PORT, LLM_MODEL, CONCURRENT_COUNT, AUTHENTICATION = get_conf('proxies', 'WEB_PORT', 'LLM_MODEL', 'CONCURRENT_COUNT', 'AUTHENTICATION') proxies, WEB_PORT, LLM_MODEL, CONCURRENT_COUNT, AUTHENTICATION = get_conf('proxies', 'WEB_PORT', 'LLM_MODEL', 'CONCURRENT_COUNT', 'AUTHENTICATION')
CHATBOT_HEIGHT, LAYOUT, AVAIL_LLM_MODELS, AUTO_CLEAR_TXT = get_conf('CHATBOT_HEIGHT', 'LAYOUT', 'AVAIL_LLM_MODELS', 'AUTO_CLEAR_TXT') CHATBOT_HEIGHT, LAYOUT, AVAIL_LLM_MODELS, AUTO_CLEAR_TXT = get_conf('CHATBOT_HEIGHT', 'LAYOUT', 'AVAIL_LLM_MODELS', 'AUTO_CLEAR_TXT')
ENABLE_AUDIO, AUTO_CLEAR_TXT, PATH_LOGGING, AVAIL_THEMES, THEME, ADD_WAIFU = get_conf('ENABLE_AUDIO', 'AUTO_CLEAR_TXT', 'PATH_LOGGING', 'AVAIL_THEMES', 'THEME', 'ADD_WAIFU') ENABLE_AUDIO, AUTO_CLEAR_TXT, PATH_LOGGING, AVAIL_THEMES, THEME, ADD_WAIFU = get_conf('ENABLE_AUDIO', 'AUTO_CLEAR_TXT', 'PATH_LOGGING', 'AVAIL_THEMES', 'THEME', 'ADD_WAIFU')
DARK_MODE, NUM_CUSTOM_BASIC_BTN, SSL_KEYFILE, SSL_CERTFILE = get_conf('DARK_MODE', 'NUM_CUSTOM_BASIC_BTN', 'SSL_KEYFILE', 'SSL_CERTFILE') NUM_CUSTOM_BASIC_BTN, SSL_KEYFILE, SSL_CERTFILE = get_conf('NUM_CUSTOM_BASIC_BTN', 'SSL_KEYFILE', 'SSL_CERTFILE')
INIT_SYS_PROMPT = get_conf('INIT_SYS_PROMPT') DARK_MODE, INIT_SYS_PROMPT, ADD_WAIFU = get_conf('DARK_MODE', 'INIT_SYS_PROMPT', 'ADD_WAIFU')
# 如果WEB_PORT是-1, 则随机选取WEB端口 # 如果WEB_PORT是-1, 则随机选取WEB端口
PORT = find_free_port() if WEB_PORT <= 0 else WEB_PORT PORT = find_free_port() if WEB_PORT <= 0 else WEB_PORT
from check_proxy import get_current_version from check_proxy import get_current_version
from themes.theme import adjust_theme, advanced_css, theme_declaration, js_code_clear, js_code_reset, js_code_show_or_hide, js_code_show_or_hide_group2 from themes.theme import adjust_theme, advanced_css, theme_declaration, js_code_clear, js_code_reset, js_code_show_or_hide, js_code_show_or_hide_group2
from themes.theme import js_code_for_css_changing, js_code_for_toggle_darkmode, js_code_for_persistent_cookie_init from themes.theme import js_code_for_css_changing, js_code_for_toggle_darkmode, js_code_for_persistent_cookie_init
from themes.theme import load_dynamic_theme, to_cookie_str, from_cookie_str, init_cookie from themes.theme import load_dynamic_theme, to_cookie_str, from_cookie_str, assign_user_uuid
title_html = f"<h1 align=\"center\">GPT 学术优化 {get_current_version()}</h1>{theme_declaration}" title_html = f"<h1 align=\"center\">GPT 学术优化 {get_current_version()}</h1>{theme_declaration}"
# 问询记录, python 版本建议3.9+(越新越好) # 对话、日志记录
import logging, uuid enable_log(PATH_LOGGING)
os.makedirs(PATH_LOGGING, exist_ok=True)
try:logging.basicConfig(filename=f"{PATH_LOGGING}/chat_secrets.log", level=logging.INFO, encoding="utf-8", format="%(asctime)s %(levelname)-8s %(message)s", datefmt="%Y-%m-%d %H:%M:%S")
except:logging.basicConfig(filename=f"{PATH_LOGGING}/chat_secrets.log", level=logging.INFO, format="%(asctime)s %(levelname)-8s %(message)s", datefmt="%Y-%m-%d %H:%M:%S")
# Disable logging output from the 'httpx' logger
logging.getLogger("httpx").setLevel(logging.WARNING)
print(f"所有问询记录将自动保存在本地目录./{PATH_LOGGING}/chat_secrets.log, 请注意自我隐私保护哦!")
# 一些普通功能模块 # 一些普通功能模块
from core_functional import get_core_functions from core_functional import get_core_functions
@@ -74,9 +79,9 @@ def main():
cancel_handles = [] cancel_handles = []
customize_btns = {} customize_btns = {}
predefined_btns = {} predefined_btns = {}
with gr.Blocks(title="GPT 学术优化", theme=set_theme, analytics_enabled=False, css=advanced_css) as demo: with gr.Blocks(title="GPT 学术优化", theme=set_theme, analytics_enabled=False, css=advanced_css) as app_block:
gr.HTML(title_html) gr.HTML(title_html)
secret_css, dark_mode, py_pickle_cookie = gr.Textbox(visible=False), gr.Textbox(DARK_MODE, visible=False), gr.Textbox(visible=False) secret_css, web_cookie_cache = gr.Textbox(visible=False), gr.Textbox(visible=False)
cookies = gr.State(load_chat_cookies()) cookies = gr.State(load_chat_cookies())
with gr_L1(): with gr_L1():
with gr_L2(scale=2, elem_id="gpt-chat"): with gr_L2(scale=2, elem_id="gpt-chat"):
@@ -152,9 +157,13 @@ def main():
with gr.Tab("更换模型", elem_id="interact-panel"): with gr.Tab("更换模型", elem_id="interact-panel"):
md_dropdown = gr.Dropdown(AVAIL_LLM_MODELS, value=LLM_MODEL, label="更换LLM模型/请求源").style(container=False) md_dropdown = gr.Dropdown(AVAIL_LLM_MODELS, value=LLM_MODEL, label="更换LLM模型/请求源").style(container=False)
top_p = gr.Slider(minimum=-0, maximum=1.0, value=1.0, step=0.01,interactive=True, label="Top-p (nucleus sampling)",) 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",) temperature = gr.Slider(minimum=-0, maximum=2.0, value=1.0, step=0.01, interactive=True, label="Temperature", elem_id="elem_temperature")
max_length_sl = gr.Slider(minimum=256, maximum=1024*32, value=4096, step=128, interactive=True, label="Local LLM MaxLength",) max_length_sl = gr.Slider(minimum=256, maximum=1024*32, value=4096, step=128, interactive=True, label="Local LLM MaxLength",)
system_prompt = gr.Textbox(show_label=True, lines=2, placeholder=f"System Prompt", label="System prompt", value=INIT_SYS_PROMPT) system_prompt = gr.Textbox(show_label=True, lines=2, placeholder=f"System Prompt", label="System prompt", value=INIT_SYS_PROMPT, elem_id="elem_prompt")
temperature.change(None, inputs=[temperature], outputs=None,
_js="""(temperature)=>gpt_academic_gradio_saveload("save", "elem_prompt", "js_temperature_cookie", temperature)""")
system_prompt.change(None, inputs=[system_prompt], outputs=None,
_js="""(system_prompt)=>gpt_academic_gradio_saveload("save", "elem_prompt", "js_system_prompt_cookie", system_prompt)""")
with gr.Tab("界面外观", elem_id="interact-panel"): with gr.Tab("界面外观", elem_id="interact-panel"):
theme_dropdown = gr.Dropdown(AVAIL_THEMES, value=THEME, label="更换UI主题").style(container=False) theme_dropdown = gr.Dropdown(AVAIL_THEMES, value=THEME, label="更换UI主题").style(container=False)
@@ -194,64 +203,19 @@ def main():
with gr.Column(scale=1, min_width=70): with gr.Column(scale=1, min_width=70):
basic_fn_confirm = gr.Button("确认并保存", variant="primary"); basic_fn_confirm.style(size="sm") basic_fn_confirm = gr.Button("确认并保存", variant="primary"); basic_fn_confirm.style(size="sm")
basic_fn_clean = gr.Button("恢复默认", variant="primary"); basic_fn_clean.style(size="sm") basic_fn_clean = gr.Button("恢复默认", variant="primary"); basic_fn_clean.style(size="sm")
def assign_btn(persistent_cookie_, cookies_, basic_btn_dropdown_, basic_fn_title, basic_fn_prefix, basic_fn_suffix, clean_up=False):
ret = {}
# 读取之前的自定义按钮
customize_fn_overwrite_ = cookies_['customize_fn_overwrite']
# 更新新的自定义按钮
customize_fn_overwrite_.update({
basic_btn_dropdown_:
{
"Title":basic_fn_title,
"Prefix":basic_fn_prefix,
"Suffix":basic_fn_suffix,
}
}
)
if clean_up:
customize_fn_overwrite_ = {}
cookies_.update(customize_fn_overwrite_) # 更新cookie
visible = (not clean_up) and (basic_fn_title != "")
if basic_btn_dropdown_ in customize_btns:
# 是自定义按钮,不是预定义按钮
ret.update({customize_btns[basic_btn_dropdown_]: gr.update(visible=visible, value=basic_fn_title)})
else:
# 是预定义按钮
ret.update({predefined_btns[basic_btn_dropdown_]: gr.update(visible=visible, value=basic_fn_title)})
ret.update({cookies: cookies_})
try: persistent_cookie_ = from_cookie_str(persistent_cookie_) # persistent cookie to dict
except: persistent_cookie_ = {}
persistent_cookie_["custom_bnt"] = customize_fn_overwrite_ # dict update new value
persistent_cookie_ = to_cookie_str(persistent_cookie_) # persistent cookie to dict
ret.update({py_pickle_cookie: persistent_cookie_}) # write persistent cookie
return ret
from shared_utils.cookie_manager import assign_btn__fn_builder
assign_btn = assign_btn__fn_builder(customize_btns, predefined_btns, cookies, web_cookie_cache)
# update btn # update btn
h = basic_fn_confirm.click(assign_btn, [py_pickle_cookie, cookies, basic_btn_dropdown, basic_fn_title, basic_fn_prefix, basic_fn_suffix], h = basic_fn_confirm.click(assign_btn, [web_cookie_cache, cookies, basic_btn_dropdown, basic_fn_title, basic_fn_prefix, basic_fn_suffix],
[py_pickle_cookie, cookies, *customize_btns.values(), *predefined_btns.values()]) [web_cookie_cache, cookies, *customize_btns.values(), *predefined_btns.values()])
h.then(None, [py_pickle_cookie], None, _js="""(py_pickle_cookie)=>{setCookie("py_pickle_cookie", py_pickle_cookie, 365);}""") h.then(None, [web_cookie_cache], None, _js="""(web_cookie_cache)=>{setCookie("web_cookie_cache", web_cookie_cache, 365);}""")
# clean up btn # clean up btn
h2 = basic_fn_clean.click(assign_btn, [py_pickle_cookie, cookies, basic_btn_dropdown, basic_fn_title, basic_fn_prefix, basic_fn_suffix, gr.State(True)], h2 = basic_fn_clean.click(assign_btn, [web_cookie_cache, cookies, basic_btn_dropdown, basic_fn_title, basic_fn_prefix, basic_fn_suffix, gr.State(True)],
[py_pickle_cookie, cookies, *customize_btns.values(), *predefined_btns.values()]) [web_cookie_cache, cookies, *customize_btns.values(), *predefined_btns.values()])
h2.then(None, [py_pickle_cookie], None, _js="""(py_pickle_cookie)=>{setCookie("py_pickle_cookie", py_pickle_cookie, 365);}""") h2.then(None, [web_cookie_cache], None, _js="""(web_cookie_cache)=>{setCookie("web_cookie_cache", web_cookie_cache, 365);}""")
def persistent_cookie_reload(persistent_cookie_, cookies_):
ret = {}
for k in customize_btns:
ret.update({customize_btns[k]: gr.update(visible=False, value="")})
try: persistent_cookie_ = from_cookie_str(persistent_cookie_) # persistent cookie to dict
except: return ret
customize_fn_overwrite_ = persistent_cookie_.get("custom_bnt", {})
cookies_['customize_fn_overwrite'] = customize_fn_overwrite_
ret.update({cookies: cookies_})
for k,v in persistent_cookie_["custom_bnt"].items():
if v['Title'] == "": continue
if k in customize_btns: ret.update({customize_btns[k]: gr.update(visible=True, value=v['Title'])})
else: ret.update({predefined_btns[k]: gr.update(visible=True, value=v['Title'])})
return ret
# 功能区显示开关与功能区的互动 # 功能区显示开关与功能区的互动
def fn_area_visibility(a): def fn_area_visibility(a):
@@ -371,11 +335,14 @@ def main():
audio_mic.stream(deal_audio, inputs=[audio_mic, cookies]) audio_mic.stream(deal_audio, inputs=[audio_mic, cookies])
demo.load(init_cookie, inputs=[cookies], outputs=[cookies]) app_block.load(assign_user_uuid, inputs=[cookies], outputs=[cookies])
demo.load(persistent_cookie_reload, inputs = [py_pickle_cookie, cookies],
outputs = [py_pickle_cookie, cookies, *customize_btns.values(), *predefined_btns.values()], _js=js_code_for_persistent_cookie_init) from shared_utils.cookie_manager import load_web_cookie_cache__fn_builder
demo.load(None, inputs=[dark_mode], outputs=None, _js="""(dark_mode)=>{apply_cookie_for_checkbox(dark_mode);}""") # 配置暗色主题或亮色主题 load_web_cookie_cache = load_web_cookie_cache__fn_builder(customize_btns, cookies, predefined_btns)
demo.load(None, inputs=[gr.Textbox(LAYOUT, visible=False)], outputs=None, _js='(LAYOUT)=>{GptAcademicJavaScriptInit(LAYOUT);}') app_block.load(load_web_cookie_cache, inputs = [web_cookie_cache, cookies],
outputs = [web_cookie_cache, cookies, *customize_btns.values(), *predefined_btns.values()], _js=js_code_for_persistent_cookie_init)
app_block.load(None, inputs=[], outputs=None, _js=f"""()=>GptAcademicJavaScriptInit("{DARK_MODE}","{INIT_SYS_PROMPT}","{ADD_WAIFU}","{LAYOUT}")""") # 配置暗色主题或亮色主题
# gradio的inbrowser触发不太稳定,回滚代码到原始的浏览器打开函数 # gradio的inbrowser触发不太稳定,回滚代码到原始的浏览器打开函数
def run_delayed_tasks(): def run_delayed_tasks():
@@ -390,28 +357,15 @@ def main():
threading.Thread(target=auto_updates, name="self-upgrade", daemon=True).start() # 查看自动更新 threading.Thread(target=auto_updates, name="self-upgrade", daemon=True).start() # 查看自动更新
threading.Thread(target=open_browser, name="open-browser", daemon=True).start() # 打开浏览器页面 threading.Thread(target=open_browser, name="open-browser", daemon=True).start() # 打开浏览器页面
threading.Thread(target=warm_up_mods, name="warm-up", daemon=True).start() # 预热tiktoken模块 threading.Thread(target=warm_up_mods, name="warm-up", daemon=True).start() # 预热tiktoken模块
# 运行一些异步任务自动更新、打开浏览器页面、预热tiktoken模块
run_delayed_tasks() run_delayed_tasks()
demo.queue(concurrency_count=CONCURRENT_COUNT).launch(
quiet=True,
server_name="0.0.0.0",
ssl_keyfile=None if SSL_KEYFILE == "" else SSL_KEYFILE,
ssl_certfile=None if SSL_CERTFILE == "" else SSL_CERTFILE,
ssl_verify=False,
server_port=PORT,
favicon_path=os.path.join(os.path.dirname(__file__), "docs/logo.png"),
auth=AUTHENTICATION if len(AUTHENTICATION) != 0 else None,
blocked_paths=["config.py","config_private.py","docker-compose.yml","Dockerfile",f"{PATH_LOGGING}/admin"])
# 如果需要在二级路径下运行 # 最后,正式开始服务
# CUSTOM_PATH = get_conf('CUSTOM_PATH') from shared_utils.fastapi_server import start_app
# if CUSTOM_PATH != "/": start_app(app_block, CONCURRENT_COUNT, AUTHENTICATION, PORT, SSL_KEYFILE, SSL_CERTFILE)
# from toolbox import run_gradio_in_subpath
# run_gradio_in_subpath(demo, auth=AUTHENTICATION, port=PORT, custom_path=CUSTOM_PATH)
# else:
# demo.launch(server_name="0.0.0.0", server_port=PORT, auth=AUTHENTICATION, favicon_path="docs/logo.png",
# blocked_paths=["config.py","config_private.py","docker-compose.yml","Dockerfile",f"{PATH_LOGGING}/admin"])
if __name__ == "__main__": if __name__ == "__main__":
main() main()

查看文件

@@ -8,10 +8,10 @@
具备多线程调用能力的函数:在函数插件中被调用,灵活而简洁 具备多线程调用能力的函数:在函数插件中被调用,灵活而简洁
2. predict_no_ui_long_connection(...) 2. predict_no_ui_long_connection(...)
""" """
import tiktoken, copy import tiktoken, copy, re
from functools import lru_cache from functools import lru_cache
from concurrent.futures import ThreadPoolExecutor from concurrent.futures import ThreadPoolExecutor
from toolbox import get_conf, trimmed_format_exc, apply_gpt_academic_string_mask from toolbox import get_conf, trimmed_format_exc, apply_gpt_academic_string_mask, read_one_api_model_name
from .bridge_chatgpt import predict_no_ui_long_connection as chatgpt_noui from .bridge_chatgpt import predict_no_ui_long_connection as chatgpt_noui
from .bridge_chatgpt import predict as chatgpt_ui from .bridge_chatgpt import predict as chatgpt_ui
@@ -34,6 +34,9 @@ from .bridge_google_gemini import predict_no_ui_long_connection as genai_noui
from .bridge_zhipu import predict_no_ui_long_connection as zhipu_noui from .bridge_zhipu import predict_no_ui_long_connection as zhipu_noui
from .bridge_zhipu import predict as zhipu_ui from .bridge_zhipu import predict as zhipu_ui
from .bridge_cohere import predict as cohere_ui
from .bridge_cohere import predict_no_ui_long_connection as cohere_noui
colors = ['#FF00FF', '#00FFFF', '#FF0000', '#990099', '#009999', '#990044'] colors = ['#FF00FF', '#00FFFF', '#FF0000', '#990099', '#009999', '#990044']
class LazyloadTiktoken(object): class LazyloadTiktoken(object):
@@ -61,6 +64,11 @@ API_URL_REDIRECT, AZURE_ENDPOINT, AZURE_ENGINE = get_conf("API_URL_REDIRECT", "A
openai_endpoint = "https://api.openai.com/v1/chat/completions" openai_endpoint = "https://api.openai.com/v1/chat/completions"
api2d_endpoint = "https://openai.api2d.net/v1/chat/completions" api2d_endpoint = "https://openai.api2d.net/v1/chat/completions"
newbing_endpoint = "wss://sydney.bing.com/sydney/ChatHub" newbing_endpoint = "wss://sydney.bing.com/sydney/ChatHub"
gemini_endpoint = "https://generativelanguage.googleapis.com/v1beta/models"
claude_endpoint = "https://api.anthropic.com/v1/messages"
yimodel_endpoint = "https://api.lingyiwanwu.com/v1/chat/completions"
cohere_endpoint = 'https://api.cohere.ai/v1/chat'
if not AZURE_ENDPOINT.endswith('/'): AZURE_ENDPOINT += '/' if not AZURE_ENDPOINT.endswith('/'): AZURE_ENDPOINT += '/'
azure_endpoint = AZURE_ENDPOINT + f'openai/deployments/{AZURE_ENGINE}/chat/completions?api-version=2023-05-15' azure_endpoint = AZURE_ENDPOINT + f'openai/deployments/{AZURE_ENGINE}/chat/completions?api-version=2023-05-15'
# 兼容旧版的配置 # 兼容旧版的配置
@@ -75,7 +83,10 @@ except:
if openai_endpoint in API_URL_REDIRECT: openai_endpoint = API_URL_REDIRECT[openai_endpoint] if openai_endpoint in API_URL_REDIRECT: openai_endpoint = API_URL_REDIRECT[openai_endpoint]
if api2d_endpoint in API_URL_REDIRECT: api2d_endpoint = API_URL_REDIRECT[api2d_endpoint] if api2d_endpoint in API_URL_REDIRECT: api2d_endpoint = API_URL_REDIRECT[api2d_endpoint]
if newbing_endpoint in API_URL_REDIRECT: newbing_endpoint = API_URL_REDIRECT[newbing_endpoint] if newbing_endpoint in API_URL_REDIRECT: newbing_endpoint = API_URL_REDIRECT[newbing_endpoint]
if gemini_endpoint in API_URL_REDIRECT: gemini_endpoint = API_URL_REDIRECT[gemini_endpoint]
if claude_endpoint in API_URL_REDIRECT: claude_endpoint = API_URL_REDIRECT[claude_endpoint]
if yimodel_endpoint in API_URL_REDIRECT: yimodel_endpoint = API_URL_REDIRECT[yimodel_endpoint]
if cohere_endpoint in API_URL_REDIRECT: cohere_endpoint = API_URL_REDIRECT[cohere_endpoint]
# 获取tokenizer # 获取tokenizer
tokenizer_gpt35 = LazyloadTiktoken("gpt-3.5-turbo") tokenizer_gpt35 = LazyloadTiktoken("gpt-3.5-turbo")
@@ -94,7 +105,7 @@ model_info = {
"fn_with_ui": chatgpt_ui, "fn_with_ui": chatgpt_ui,
"fn_without_ui": chatgpt_noui, "fn_without_ui": chatgpt_noui,
"endpoint": openai_endpoint, "endpoint": openai_endpoint,
"max_token": 4096, "max_token": 16385,
"tokenizer": tokenizer_gpt35, "tokenizer": tokenizer_gpt35,
"token_cnt": get_token_num_gpt35, "token_cnt": get_token_num_gpt35,
}, },
@@ -117,15 +128,6 @@ model_info = {
"token_cnt": get_token_num_gpt35, "token_cnt": get_token_num_gpt35,
}, },
"gpt-3.5-turbo-0125": {
"fn_with_ui": chatgpt_ui,
"fn_without_ui": chatgpt_noui,
"endpoint": openai_endpoint,
"max_token": 4096,
"tokenizer": tokenizer_gpt35,
"token_cnt": get_token_num_gpt35,
},
"gpt-3.5-turbo-16k-0613": { "gpt-3.5-turbo-16k-0613": {
"fn_with_ui": chatgpt_ui, "fn_with_ui": chatgpt_ui,
"fn_without_ui": chatgpt_noui, "fn_without_ui": chatgpt_noui,
@@ -135,7 +137,16 @@ model_info = {
"token_cnt": get_token_num_gpt35, "token_cnt": get_token_num_gpt35,
}, },
"gpt-3.5-turbo-1106": {#16k "gpt-3.5-turbo-1106": { #16k
"fn_with_ui": chatgpt_ui,
"fn_without_ui": chatgpt_noui,
"endpoint": openai_endpoint,
"max_token": 16385,
"tokenizer": tokenizer_gpt35,
"token_cnt": get_token_num_gpt35,
},
"gpt-3.5-turbo-0125": { #16k
"fn_with_ui": chatgpt_ui, "fn_with_ui": chatgpt_ui,
"fn_without_ui": chatgpt_noui, "fn_without_ui": chatgpt_noui,
"endpoint": openai_endpoint, "endpoint": openai_endpoint,
@@ -291,7 +302,7 @@ model_info = {
"gemini-pro": { "gemini-pro": {
"fn_with_ui": genai_ui, "fn_with_ui": genai_ui,
"fn_without_ui": genai_noui, "fn_without_ui": genai_noui,
"endpoint": None, "endpoint": gemini_endpoint,
"max_token": 1024 * 32, "max_token": 1024 * 32,
"tokenizer": tokenizer_gpt35, "tokenizer": tokenizer_gpt35,
"token_cnt": get_token_num_gpt35, "token_cnt": get_token_num_gpt35,
@@ -299,13 +310,56 @@ model_info = {
"gemini-pro-vision": { "gemini-pro-vision": {
"fn_with_ui": genai_ui, "fn_with_ui": genai_ui,
"fn_without_ui": genai_noui, "fn_without_ui": genai_noui,
"endpoint": gemini_endpoint,
"max_token": 1024 * 32,
"tokenizer": tokenizer_gpt35,
"token_cnt": get_token_num_gpt35,
},
# cohere
"cohere-command-r-plus": {
"fn_with_ui": cohere_ui,
"fn_without_ui": cohere_noui,
"can_multi_thread": True,
"endpoint": cohere_endpoint,
"max_token": 1024 * 4,
"tokenizer": tokenizer_gpt35,
"token_cnt": get_token_num_gpt35,
},
}
# -=-=-=-=-=-=- 月之暗面 -=-=-=-=-=-=-
from request_llms.bridge_moonshot import predict as moonshot_ui
from request_llms.bridge_moonshot import predict_no_ui_long_connection as moonshot_no_ui
model_info.update({
"moonshot-v1-8k": {
"fn_with_ui": moonshot_ui,
"fn_without_ui": moonshot_no_ui,
"can_multi_thread": True,
"endpoint": None,
"max_token": 1024 * 8,
"tokenizer": tokenizer_gpt35,
"token_cnt": get_token_num_gpt35,
},
"moonshot-v1-32k": {
"fn_with_ui": moonshot_ui,
"fn_without_ui": moonshot_no_ui,
"can_multi_thread": True,
"endpoint": None, "endpoint": None,
"max_token": 1024 * 32, "max_token": 1024 * 32,
"tokenizer": tokenizer_gpt35, "tokenizer": tokenizer_gpt35,
"token_cnt": get_token_num_gpt35, "token_cnt": get_token_num_gpt35,
}, },
} "moonshot-v1-128k": {
"fn_with_ui": moonshot_ui,
"fn_without_ui": moonshot_no_ui,
"can_multi_thread": True,
"endpoint": None,
"max_token": 1024 * 128,
"tokenizer": tokenizer_gpt35,
"token_cnt": get_token_num_gpt35,
}
})
# -=-=-=-=-=-=- api2d 对齐支持 -=-=-=-=-=-=- # -=-=-=-=-=-=- api2d 对齐支持 -=-=-=-=-=-=-
for model in AVAIL_LLM_MODELS: for model in AVAIL_LLM_MODELS:
if model.startswith('api2d-') and (model.replace('api2d-','') in model_info.keys()): if model.startswith('api2d-') and (model.replace('api2d-','') in model_info.keys()):
@@ -321,25 +375,67 @@ for model in AVAIL_LLM_MODELS:
model_info.update({model: mi}) model_info.update({model: mi})
# -=-=-=-=-=-=- 以下部分是新加入的模型,可能附带额外依赖 -=-=-=-=-=-=- # -=-=-=-=-=-=- 以下部分是新加入的模型,可能附带额外依赖 -=-=-=-=-=-=-
if "claude-1-100k" in AVAIL_LLM_MODELS or "claude-2" in AVAIL_LLM_MODELS: # claude家族
claude_models = ["claude-instant-1.2","claude-2.0","claude-2.1","claude-3-haiku-20240307","claude-3-sonnet-20240229","claude-3-opus-20240229"]
if any(item in claude_models for item in AVAIL_LLM_MODELS):
from .bridge_claude import predict_no_ui_long_connection as claude_noui from .bridge_claude import predict_no_ui_long_connection as claude_noui
from .bridge_claude import predict as claude_ui from .bridge_claude import predict as claude_ui
model_info.update({ model_info.update({
"claude-1-100k": { "claude-instant-1.2": {
"fn_with_ui": claude_ui, "fn_with_ui": claude_ui,
"fn_without_ui": claude_noui, "fn_without_ui": claude_noui,
"endpoint": None, "endpoint": claude_endpoint,
"max_token": 8196, "max_token": 100000,
"tokenizer": tokenizer_gpt35, "tokenizer": tokenizer_gpt35,
"token_cnt": get_token_num_gpt35, "token_cnt": get_token_num_gpt35,
}, },
}) })
model_info.update({ model_info.update({
"claude-2": { "claude-2.0": {
"fn_with_ui": claude_ui, "fn_with_ui": claude_ui,
"fn_without_ui": claude_noui, "fn_without_ui": claude_noui,
"endpoint": None, "endpoint": claude_endpoint,
"max_token": 8196, "max_token": 100000,
"tokenizer": tokenizer_gpt35,
"token_cnt": get_token_num_gpt35,
},
})
model_info.update({
"claude-2.1": {
"fn_with_ui": claude_ui,
"fn_without_ui": claude_noui,
"endpoint": claude_endpoint,
"max_token": 200000,
"tokenizer": tokenizer_gpt35,
"token_cnt": get_token_num_gpt35,
},
})
model_info.update({
"claude-3-haiku-20240307": {
"fn_with_ui": claude_ui,
"fn_without_ui": claude_noui,
"endpoint": claude_endpoint,
"max_token": 200000,
"tokenizer": tokenizer_gpt35,
"token_cnt": get_token_num_gpt35,
},
})
model_info.update({
"claude-3-sonnet-20240229": {
"fn_with_ui": claude_ui,
"fn_without_ui": claude_noui,
"endpoint": claude_endpoint,
"max_token": 200000,
"tokenizer": tokenizer_gpt35,
"token_cnt": get_token_num_gpt35,
},
})
model_info.update({
"claude-3-opus-20240229": {
"fn_with_ui": claude_ui,
"fn_without_ui": claude_noui,
"endpoint": claude_endpoint,
"max_token": 200000,
"tokenizer": tokenizer_gpt35, "tokenizer": tokenizer_gpt35,
"token_cnt": get_token_num_gpt35, "token_cnt": get_token_num_gpt35,
}, },
@@ -409,22 +505,6 @@ if "stack-claude" in AVAIL_LLM_MODELS:
"token_cnt": get_token_num_gpt35, "token_cnt": get_token_num_gpt35,
} }
}) })
if "newbing-free" in AVAIL_LLM_MODELS:
try:
from .bridge_newbingfree import predict_no_ui_long_connection as newbingfree_noui
from .bridge_newbingfree import predict as newbingfree_ui
model_info.update({
"newbing-free": {
"fn_with_ui": newbingfree_ui,
"fn_without_ui": newbingfree_noui,
"endpoint": newbing_endpoint,
"max_token": 4096,
"tokenizer": tokenizer_gpt35,
"token_cnt": get_token_num_gpt35,
}
})
except:
print(trimmed_format_exc())
if "newbing" in AVAIL_LLM_MODELS: # same with newbing-free if "newbing" in AVAIL_LLM_MODELS: # same with newbing-free
try: try:
from .bridge_newbingfree import predict_no_ui_long_connection as newbingfree_noui from .bridge_newbingfree import predict_no_ui_long_connection as newbingfree_noui
@@ -457,6 +537,7 @@ if "chatglmft" in AVAIL_LLM_MODELS: # same with newbing-free
}) })
except: except:
print(trimmed_format_exc()) print(trimmed_format_exc())
# -=-=-=-=-=-=- 上海AI-LAB书生大模型 -=-=-=-=-=-=-
if "internlm" in AVAIL_LLM_MODELS: if "internlm" in AVAIL_LLM_MODELS:
try: try:
from .bridge_internlm import predict_no_ui_long_connection as internlm_noui from .bridge_internlm import predict_no_ui_long_connection as internlm_noui
@@ -489,6 +570,7 @@ if "chatglm_onnx" in AVAIL_LLM_MODELS:
}) })
except: except:
print(trimmed_format_exc()) print(trimmed_format_exc())
# -=-=-=-=-=-=- 通义-本地模型 -=-=-=-=-=-=-
if "qwen-local" in AVAIL_LLM_MODELS: if "qwen-local" in AVAIL_LLM_MODELS:
try: try:
from .bridge_qwen_local import predict_no_ui_long_connection as qwen_local_noui from .bridge_qwen_local import predict_no_ui_long_connection as qwen_local_noui
@@ -497,6 +579,7 @@ if "qwen-local" in AVAIL_LLM_MODELS:
"qwen-local": { "qwen-local": {
"fn_with_ui": qwen_local_ui, "fn_with_ui": qwen_local_ui,
"fn_without_ui": qwen_local_noui, "fn_without_ui": qwen_local_noui,
"can_multi_thread": False,
"endpoint": None, "endpoint": None,
"max_token": 4096, "max_token": 4096,
"tokenizer": tokenizer_gpt35, "tokenizer": tokenizer_gpt35,
@@ -505,6 +588,7 @@ if "qwen-local" in AVAIL_LLM_MODELS:
}) })
except: except:
print(trimmed_format_exc()) print(trimmed_format_exc())
# -=-=-=-=-=-=- 通义-在线模型 -=-=-=-=-=-=-
if "qwen-turbo" in AVAIL_LLM_MODELS or "qwen-plus" in AVAIL_LLM_MODELS or "qwen-max" in AVAIL_LLM_MODELS: # zhipuai if "qwen-turbo" in AVAIL_LLM_MODELS or "qwen-plus" in AVAIL_LLM_MODELS or "qwen-max" in AVAIL_LLM_MODELS: # zhipuai
try: try:
from .bridge_qwen import predict_no_ui_long_connection as qwen_noui from .bridge_qwen import predict_no_ui_long_connection as qwen_noui
@@ -513,6 +597,7 @@ if "qwen-turbo" in AVAIL_LLM_MODELS or "qwen-plus" in AVAIL_LLM_MODELS or "qwen-
"qwen-turbo": { "qwen-turbo": {
"fn_with_ui": qwen_ui, "fn_with_ui": qwen_ui,
"fn_without_ui": qwen_noui, "fn_without_ui": qwen_noui,
"can_multi_thread": True,
"endpoint": None, "endpoint": None,
"max_token": 6144, "max_token": 6144,
"tokenizer": tokenizer_gpt35, "tokenizer": tokenizer_gpt35,
@@ -521,6 +606,7 @@ if "qwen-turbo" in AVAIL_LLM_MODELS or "qwen-plus" in AVAIL_LLM_MODELS or "qwen-
"qwen-plus": { "qwen-plus": {
"fn_with_ui": qwen_ui, "fn_with_ui": qwen_ui,
"fn_without_ui": qwen_noui, "fn_without_ui": qwen_noui,
"can_multi_thread": True,
"endpoint": None, "endpoint": None,
"max_token": 30720, "max_token": 30720,
"tokenizer": tokenizer_gpt35, "tokenizer": tokenizer_gpt35,
@@ -529,6 +615,7 @@ if "qwen-turbo" in AVAIL_LLM_MODELS or "qwen-plus" in AVAIL_LLM_MODELS or "qwen-
"qwen-max": { "qwen-max": {
"fn_with_ui": qwen_ui, "fn_with_ui": qwen_ui,
"fn_without_ui": qwen_noui, "fn_without_ui": qwen_noui,
"can_multi_thread": True,
"endpoint": None, "endpoint": None,
"max_token": 28672, "max_token": 28672,
"tokenizer": tokenizer_gpt35, "tokenizer": tokenizer_gpt35,
@@ -537,7 +624,35 @@ if "qwen-turbo" in AVAIL_LLM_MODELS or "qwen-plus" in AVAIL_LLM_MODELS or "qwen-
}) })
except: except:
print(trimmed_format_exc()) print(trimmed_format_exc())
if "spark" in AVAIL_LLM_MODELS: # 讯飞星火认知大模型 # -=-=-=-=-=-=- 零一万物模型 -=-=-=-=-=-=-
if "yi-34b-chat-0205" in AVAIL_LLM_MODELS or "yi-34b-chat-200k" in AVAIL_LLM_MODELS: # zhipuai
try:
from .bridge_yimodel import predict_no_ui_long_connection as yimodel_noui
from .bridge_yimodel import predict as yimodel_ui
model_info.update({
"yi-34b-chat-0205": {
"fn_with_ui": yimodel_ui,
"fn_without_ui": yimodel_noui,
"can_multi_thread": False, # 目前来说,默认情况下并发量极低,因此禁用
"endpoint": yimodel_endpoint,
"max_token": 4000,
"tokenizer": tokenizer_gpt35,
"token_cnt": get_token_num_gpt35,
},
"yi-34b-chat-200k": {
"fn_with_ui": yimodel_ui,
"fn_without_ui": yimodel_noui,
"can_multi_thread": False, # 目前来说,默认情况下并发量极低,因此禁用
"endpoint": yimodel_endpoint,
"max_token": 200000,
"tokenizer": tokenizer_gpt35,
"token_cnt": get_token_num_gpt35,
},
})
except:
print(trimmed_format_exc())
# -=-=-=-=-=-=- 讯飞星火认知大模型 -=-=-=-=-=-=-
if "spark" in AVAIL_LLM_MODELS:
try: try:
from .bridge_spark import predict_no_ui_long_connection as spark_noui from .bridge_spark import predict_no_ui_long_connection as spark_noui
from .bridge_spark import predict as spark_ui from .bridge_spark import predict as spark_ui
@@ -545,6 +660,7 @@ if "spark" in AVAIL_LLM_MODELS: # 讯飞星火认知大模型
"spark": { "spark": {
"fn_with_ui": spark_ui, "fn_with_ui": spark_ui,
"fn_without_ui": spark_noui, "fn_without_ui": spark_noui,
"can_multi_thread": True,
"endpoint": None, "endpoint": None,
"max_token": 4096, "max_token": 4096,
"tokenizer": tokenizer_gpt35, "tokenizer": tokenizer_gpt35,
@@ -561,6 +677,7 @@ if "sparkv2" in AVAIL_LLM_MODELS: # 讯飞星火认知大模型
"sparkv2": { "sparkv2": {
"fn_with_ui": spark_ui, "fn_with_ui": spark_ui,
"fn_without_ui": spark_noui, "fn_without_ui": spark_noui,
"can_multi_thread": True,
"endpoint": None, "endpoint": None,
"max_token": 4096, "max_token": 4096,
"tokenizer": tokenizer_gpt35, "tokenizer": tokenizer_gpt35,
@@ -577,6 +694,7 @@ if "sparkv3" in AVAIL_LLM_MODELS or "sparkv3.5" in AVAIL_LLM_MODELS: # 讯飞
"sparkv3": { "sparkv3": {
"fn_with_ui": spark_ui, "fn_with_ui": spark_ui,
"fn_without_ui": spark_noui, "fn_without_ui": spark_noui,
"can_multi_thread": True,
"endpoint": None, "endpoint": None,
"max_token": 4096, "max_token": 4096,
"tokenizer": tokenizer_gpt35, "tokenizer": tokenizer_gpt35,
@@ -585,6 +703,7 @@ if "sparkv3" in AVAIL_LLM_MODELS or "sparkv3.5" in AVAIL_LLM_MODELS: # 讯飞
"sparkv3.5": { "sparkv3.5": {
"fn_with_ui": spark_ui, "fn_with_ui": spark_ui,
"fn_without_ui": spark_noui, "fn_without_ui": spark_noui,
"can_multi_thread": True,
"endpoint": None, "endpoint": None,
"max_token": 4096, "max_token": 4096,
"tokenizer": tokenizer_gpt35, "tokenizer": tokenizer_gpt35,
@@ -609,6 +728,7 @@ if "llama2" in AVAIL_LLM_MODELS: # llama2
}) })
except: except:
print(trimmed_format_exc()) print(trimmed_format_exc())
# -=-=-=-=-=-=- 智谱 -=-=-=-=-=-=-
if "zhipuai" in AVAIL_LLM_MODELS: # zhipuai 是glm-4的别名,向后兼容配置 if "zhipuai" in AVAIL_LLM_MODELS: # zhipuai 是glm-4的别名,向后兼容配置
try: try:
model_info.update({ model_info.update({
@@ -623,6 +743,7 @@ if "zhipuai" in AVAIL_LLM_MODELS: # zhipuai 是glm-4的别名,向后兼容
}) })
except: except:
print(trimmed_format_exc()) print(trimmed_format_exc())
# -=-=-=-=-=-=- 幻方-深度求索大模型 -=-=-=-=-=-=-
if "deepseekcoder" in AVAIL_LLM_MODELS: # deepseekcoder if "deepseekcoder" in AVAIL_LLM_MODELS: # deepseekcoder
try: try:
from .bridge_deepseekcoder import predict_no_ui_long_connection as deepseekcoder_noui from .bridge_deepseekcoder import predict_no_ui_long_connection as deepseekcoder_noui
@@ -639,26 +760,34 @@ if "deepseekcoder" in AVAIL_LLM_MODELS: # deepseekcoder
}) })
except: except:
print(trimmed_format_exc()) print(trimmed_format_exc())
# if "skylark" in AVAIL_LLM_MODELS:
# try:
# from .bridge_skylark2 import predict_no_ui_long_connection as skylark_noui
# from .bridge_skylark2 import predict as skylark_ui
# model_info.update({
# "skylark": {
# "fn_with_ui": skylark_ui,
# "fn_without_ui": skylark_noui,
# "endpoint": None,
# "max_token": 4096,
# "tokenizer": tokenizer_gpt35,
# "token_cnt": get_token_num_gpt35,
# }
# })
# except:
# print(trimmed_format_exc())
# <-- 用于定义和切换多个azure模型 --> # -=-=-=-=-=-=- one-api 对齐支持 -=-=-=-=-=-=-
AZURE_CFG_ARRAY = get_conf("AZURE_CFG_ARRAY") for model in [m for m in AVAIL_LLM_MODELS if m.startswith("one-api-")]:
# 为了更灵活地接入one-api多模型管理界面,设计了此接口,例子AVAIL_LLM_MODELS = ["one-api-mixtral-8x7b(max_token=6666)"]
# 其中
# "one-api-" 是前缀(必要)
# "mixtral-8x7b" 是模型名(必要)
# "(max_token=6666)" 是配置(非必要)
try:
_, max_token_tmp = read_one_api_model_name(model)
except:
print(f"one-api模型 {model} 的 max_token 配置不是整数,请检查配置文件。")
continue
model_info.update({
model: {
"fn_with_ui": chatgpt_ui,
"fn_without_ui": chatgpt_noui,
"endpoint": openai_endpoint,
"max_token": max_token_tmp,
"tokenizer": tokenizer_gpt35,
"token_cnt": get_token_num_gpt35,
},
})
# -=-=-=-=-=-=- azure模型对齐支持 -=-=-=-=-=-=-
AZURE_CFG_ARRAY = get_conf("AZURE_CFG_ARRAY") # <-- 用于定义和切换多个azure模型 -->
if len(AZURE_CFG_ARRAY) > 0: if len(AZURE_CFG_ARRAY) > 0:
for azure_model_name, azure_cfg_dict in AZURE_CFG_ARRAY.items(): for azure_model_name, azure_cfg_dict in AZURE_CFG_ARRAY.items():
# 可能会覆盖之前的配置,但这是意料之中的 # 可能会覆盖之前的配置,但这是意料之中的
@@ -687,7 +816,7 @@ def LLM_CATCH_EXCEPTION(f):
""" """
装饰器函数,将错误显示出来 装饰器函数,将错误显示出来
""" """
def decorated(inputs, llm_kwargs, history, sys_prompt, observe_window, console_slience): def decorated(inputs:str, llm_kwargs:dict, history:list, sys_prompt:str, observe_window:list, console_slience:bool):
try: try:
return f(inputs, llm_kwargs, history, sys_prompt, observe_window, console_slience) return f(inputs, llm_kwargs, history, sys_prompt, observe_window, console_slience)
except Exception as e: except Exception as e:
@@ -697,9 +826,9 @@ def LLM_CATCH_EXCEPTION(f):
return decorated return decorated
def predict_no_ui_long_connection(inputs, llm_kwargs, history, sys_prompt, observe_window=[], console_slience=False): def predict_no_ui_long_connection(inputs:str, llm_kwargs:dict, history:list, sys_prompt:str, observe_window:list=[], console_slience:bool=False):
""" """
发送至LLM,等待回复,一次性完成,不显示中间过程。但内部用stream的方法避免中途网线被掐。 发送至LLM,等待回复,一次性完成,不显示中间过程。但内部(尽可能地)用stream的方法避免中途网线被掐。
inputs inputs
是本次问询的输入 是本次问询的输入
sys_prompt: sys_prompt:
@@ -717,7 +846,6 @@ def predict_no_ui_long_connection(inputs, llm_kwargs, history, sys_prompt, obser
model = llm_kwargs['llm_model'] model = llm_kwargs['llm_model']
n_model = 1 n_model = 1
if '&' not in model: if '&' not in model:
assert not model.startswith("tgui"), "TGUI不支持函数插件的实现"
# 如果只询问1个大语言模型 # 如果只询问1个大语言模型
method = model_info[model]["fn_without_ui"] method = model_info[model]["fn_without_ui"]
@@ -752,7 +880,8 @@ def predict_no_ui_long_connection(inputs, llm_kwargs, history, sys_prompt, obser
# 观察窗window # 观察窗window
chat_string = [] chat_string = []
for i in range(n_model): for i in range(n_model):
chat_string.append( f"{str(models[i])} 说】: <font color=\"{colors[i]}\"> {window_mutex[i][0]} </font>" ) color = colors[i%len(colors)]
chat_string.append( f"{str(models[i])} 说】: <font color=\"{color}\"> {window_mutex[i][0]} </font>" )
res = '<br/><br/>\n\n---\n\n'.join(chat_string) res = '<br/><br/>\n\n---\n\n'.join(chat_string)
# # # # # # # # # # # # # # # # # # # # # #
observe_window[0] = res observe_window[0] = res
@@ -769,22 +898,30 @@ def predict_no_ui_long_connection(inputs, llm_kwargs, history, sys_prompt, obser
time.sleep(1) time.sleep(1)
for i, future in enumerate(futures): # wait and get for i, future in enumerate(futures): # wait and get
return_string_collect.append( f"{str(models[i])} 说】: <font color=\"{colors[i]}\"> {future.result()} </font>" ) color = colors[i%len(colors)]
return_string_collect.append( f"{str(models[i])} 说】: <font color=\"{color}\"> {future.result()} </font>" )
window_mutex[-1] = False # stop mutex thread window_mutex[-1] = False # stop mutex thread
res = '<br/><br/>\n\n---\n\n'.join(return_string_collect) res = '<br/><br/>\n\n---\n\n'.join(return_string_collect)
return res return res
def predict(inputs, llm_kwargs, *args, **kwargs): def predict(inputs:str, llm_kwargs:dict, *args, **kwargs):
""" """
发送至LLM,流式获取输出。 发送至LLM,流式获取输出。
用于基础的对话功能。 用于基础的对话功能。
inputs 是本次问询的输入
top_p, temperature是LLM的内部调优参数 完整参数列表:
history 是之前的对话列表注意无论是inputs还是history,内容太长了都会触发token数量溢出的错误 predict(
chatbot 为WebUI中显示的对话列表,修改它,然后yeild出去,可以直接修改对话界面内容 inputs:str, # 是本次问询的输入
additional_fn代表点击的哪个按钮,按钮见functional.py llm_kwargs:dict, # 是LLM的内部调优参数
plugin_kwargs:dict, # 是插件的内部参数
chatbot:ChatBotWithCookies, # 原样传递,负责向用户前端展示对话,兼顾前端状态的功能
history:list=[], # 是之前的对话列表
system_prompt:str='', # 系统静默prompt
stream:bool=True, # 是否流式输出(已弃用)
additional_fn:str=None # 基础功能区按钮的附加功能
):
""" """
inputs = apply_gpt_academic_string_mask(inputs, mode="show_llm") inputs = apply_gpt_academic_string_mask(inputs, mode="show_llm")

查看文件

@@ -137,7 +137,8 @@ class GetGLMFTHandle(Process):
global glmft_handle global glmft_handle
glmft_handle = None glmft_handle = None
################################################################################# #################################################################################
def predict_no_ui_long_connection(inputs, llm_kwargs, history=[], sys_prompt="", observe_window=[], console_slience=False): def predict_no_ui_long_connection(inputs:str, llm_kwargs:dict, history:list=[], sys_prompt:str="",
observe_window:list=[], console_slience:bool=False):
""" """
多线程方法 多线程方法
函数的说明请见 request_llms/bridge_all.py 函数的说明请见 request_llms/bridge_all.py

查看文件

@@ -21,7 +21,9 @@ import random
# config_private.py放自己的秘密如API和代理网址 # config_private.py放自己的秘密如API和代理网址
# 读取时首先看是否存在私密的config_private配置文件不受git管控,如果有,则覆盖原config文件 # 读取时首先看是否存在私密的config_private配置文件不受git管控,如果有,则覆盖原config文件
from toolbox import get_conf, update_ui, is_any_api_key, select_api_key, what_keys, clip_history, trimmed_format_exc, is_the_upload_folder from toolbox import get_conf, update_ui, is_any_api_key, select_api_key, what_keys, clip_history
from toolbox import trimmed_format_exc, is_the_upload_folder, read_one_api_model_name, log_chat
from toolbox import ChatBotWithCookies
proxies, TIMEOUT_SECONDS, MAX_RETRY, API_ORG, AZURE_CFG_ARRAY = \ proxies, TIMEOUT_SECONDS, MAX_RETRY, API_ORG, AZURE_CFG_ARRAY = \
get_conf('proxies', 'TIMEOUT_SECONDS', 'MAX_RETRY', 'API_ORG', 'AZURE_CFG_ARRAY') get_conf('proxies', 'TIMEOUT_SECONDS', 'MAX_RETRY', 'API_ORG', 'AZURE_CFG_ARRAY')
@@ -68,7 +70,7 @@ def verify_endpoint(endpoint):
raise ValueError("Endpoint不正确, 请检查AZURE_ENDPOINT的配置! 当前的Endpoint为:" + endpoint) raise ValueError("Endpoint不正确, 请检查AZURE_ENDPOINT的配置! 当前的Endpoint为:" + endpoint)
return endpoint return endpoint
def predict_no_ui_long_connection(inputs, llm_kwargs, history=[], sys_prompt="", observe_window=None, console_slience=False): def predict_no_ui_long_connection(inputs:str, llm_kwargs:dict, history:list=[], sys_prompt:str="", observe_window:list=None, console_slience:bool=False):
""" """
发送至chatGPT,等待回复,一次性完成,不显示中间过程。但内部用stream的方法避免中途网线被掐。 发送至chatGPT,等待回复,一次性完成,不显示中间过程。但内部用stream的方法避免中途网线被掐。
inputs inputs
@@ -125,8 +127,9 @@ def predict_no_ui_long_connection(inputs, llm_kwargs, history=[], sys_prompt="",
json_data = chunkjson['choices'][0] json_data = chunkjson['choices'][0]
delta = json_data["delta"] delta = json_data["delta"]
if len(delta) == 0: break if len(delta) == 0: break
if "role" in delta: continue if (not has_content) and has_role: continue
if "content" in delta: if (not has_content) and (not has_role): continue # raise RuntimeError("发现不标准的第三方接口:"+delta)
if has_content: # has_role = True/False
result += delta["content"] result += delta["content"]
if not console_slience: print(delta["content"], end='') if not console_slience: print(delta["content"], end='')
if observe_window is not None: if observe_window is not None:
@@ -145,7 +148,8 @@ def predict_no_ui_long_connection(inputs, llm_kwargs, history=[], sys_prompt="",
return result return result
def predict(inputs, llm_kwargs, plugin_kwargs, chatbot, history=[], system_prompt='', stream = True, additional_fn=None): def predict(inputs:str, llm_kwargs:dict, plugin_kwargs:dict, chatbot:ChatBotWithCookies,
history:list=[], system_prompt:str='', stream:bool=True, additional_fn:str=None):
""" """
发送至chatGPT,流式获取输出。 发送至chatGPT,流式获取输出。
用于基础的对话功能。 用于基础的对话功能。
@@ -171,7 +175,7 @@ def predict(inputs, llm_kwargs, plugin_kwargs, chatbot, history=[], system_promp
inputs, history = handle_core_functionality(additional_fn, inputs, history, chatbot) inputs, history = handle_core_functionality(additional_fn, inputs, history, chatbot)
raw_input = inputs raw_input = inputs
logging.info(f'[raw_input] {raw_input}') # logging.info(f'[raw_input] {raw_input}')
chatbot.append((inputs, "")) chatbot.append((inputs, ""))
yield from update_ui(chatbot=chatbot, history=history, msg="等待响应") # 刷新界面 yield from update_ui(chatbot=chatbot, history=history, msg="等待响应") # 刷新界面
@@ -252,7 +256,8 @@ def predict(inputs, llm_kwargs, plugin_kwargs, chatbot, history=[], system_promp
# 前者是API2D的结束条件,后者是OPENAI的结束条件 # 前者是API2D的结束条件,后者是OPENAI的结束条件
if ('data: [DONE]' in chunk_decoded) or (len(chunkjson['choices'][0]["delta"]) == 0): if ('data: [DONE]' in chunk_decoded) or (len(chunkjson['choices'][0]["delta"]) == 0):
# 判定为数据流的结束,gpt_replying_buffer也写完了 # 判定为数据流的结束,gpt_replying_buffer也写完了
logging.info(f'[response] {gpt_replying_buffer}') # logging.info(f'[response] {gpt_replying_buffer}')
log_chat(llm_model=llm_kwargs["llm_model"], input_str=inputs, output_str=gpt_replying_buffer)
break break
# 处理数据流的主体 # 处理数据流的主体
status_text = f"finish_reason: {chunkjson['choices'][0].get('finish_reason', 'null')}" status_text = f"finish_reason: {chunkjson['choices'][0].get('finish_reason', 'null')}"
@@ -264,7 +269,8 @@ def predict(inputs, llm_kwargs, plugin_kwargs, chatbot, history=[], system_promp
# 一些第三方接口的出现这样的错误,兼容一下吧 # 一些第三方接口的出现这样的错误,兼容一下吧
continue continue
else: else:
# 一些垃圾第三方接口出现这样的错误 # 至此已经超出了正常接口应该进入的范围,一些垃圾第三方接口出现这样的错误
if chunkjson['choices'][0]["delta"]["content"] is None: continue # 一些垃圾第三方接口出现这样的错误,兼容一下吧
gpt_replying_buffer = gpt_replying_buffer + chunkjson['choices'][0]["delta"]["content"] gpt_replying_buffer = gpt_replying_buffer + chunkjson['choices'][0]["delta"]["content"]
history[-1] = gpt_replying_buffer history[-1] = gpt_replying_buffer
@@ -356,6 +362,9 @@ def generate_payload(inputs, llm_kwargs, history, system_prompt, stream):
model = llm_kwargs['llm_model'] model = llm_kwargs['llm_model']
if llm_kwargs['llm_model'].startswith('api2d-'): if llm_kwargs['llm_model'].startswith('api2d-'):
model = llm_kwargs['llm_model'][len('api2d-'):] model = llm_kwargs['llm_model'][len('api2d-'):]
if llm_kwargs['llm_model'].startswith('one-api-'):
model = llm_kwargs['llm_model'][len('one-api-'):]
model, _ = read_one_api_model_name(model)
if model == "gpt-3.5-random": # 随机选择, 绕过openai访问频率限制 if model == "gpt-3.5-random": # 随机选择, 绕过openai访问频率限制
model = random.choice([ model = random.choice([

查看文件

@@ -9,15 +9,15 @@
具备多线程调用能力的函数 具备多线程调用能力的函数
2. predict_no_ui_long_connection支持多线程 2. predict_no_ui_long_connection支持多线程
""" """
import os
import json
import time
import gradio as gr
import logging import logging
import os
import time
import traceback import traceback
import json
import requests import requests
import importlib from toolbox import get_conf, update_ui, trimmed_format_exc, encode_image, every_image_file_in_path, log_chat
picture_system_prompt = "\n当回复图像时,必须说明正在回复哪张图像。所有图像仅在最后一个问题中提供,即使它们在历史记录中被提及。请使用'这是第X张图像:'的格式来指明您正在描述的是哪张图像。"
Claude_3_Models = ["claude-3-haiku-20240307", "claude-3-sonnet-20240229", "claude-3-opus-20240229"]
# config_private.py放自己的秘密如API和代理网址 # config_private.py放自己的秘密如API和代理网址
# 读取时首先看是否存在私密的config_private配置文件不受git管控,如果有,则覆盖原config文件 # 读取时首先看是否存在私密的config_private配置文件不受git管控,如果有,则覆盖原config文件
@@ -39,6 +39,34 @@ def get_full_error(chunk, stream_response):
break break
return chunk return chunk
def decode_chunk(chunk):
# 提前读取一些信息(用于判断异常)
chunk_decoded = chunk.decode()
chunkjson = None
is_last_chunk = False
need_to_pass = False
if chunk_decoded.startswith('data:'):
try:
chunkjson = json.loads(chunk_decoded[6:])
except:
need_to_pass = True
pass
elif chunk_decoded.startswith('event:'):
try:
event_type = chunk_decoded.split(':')[1].strip()
if event_type == 'content_block_stop' or event_type == 'message_stop':
is_last_chunk = True
elif event_type == 'content_block_start' or event_type == 'message_start':
need_to_pass = True
pass
except:
need_to_pass = True
pass
else:
need_to_pass = True
pass
return need_to_pass, chunkjson, is_last_chunk
def predict_no_ui_long_connection(inputs, llm_kwargs, history=[], sys_prompt="", observe_window=None, console_slience=False): def predict_no_ui_long_connection(inputs, llm_kwargs, history=[], sys_prompt="", observe_window=None, console_slience=False):
""" """
@@ -54,50 +82,67 @@ def predict_no_ui_long_connection(inputs, llm_kwargs, history=[], sys_prompt="",
observe_window = None observe_window = None
用于负责跨越线程传递已经输出的部分,大部分时候仅仅为了fancy的视觉效果,留空即可。observe_window[0]观测窗。observe_window[1]:看门狗 用于负责跨越线程传递已经输出的部分,大部分时候仅仅为了fancy的视觉效果,留空即可。observe_window[0]观测窗。observe_window[1]:看门狗
""" """
from anthropic import Anthropic
watch_dog_patience = 5 # 看门狗的耐心, 设置5秒即可 watch_dog_patience = 5 # 看门狗的耐心, 设置5秒即可
prompt = generate_payload(inputs, llm_kwargs, history, system_prompt=sys_prompt, stream=True)
retry = 0
if len(ANTHROPIC_API_KEY) == 0: if len(ANTHROPIC_API_KEY) == 0:
raise RuntimeError("没有设置ANTHROPIC_API_KEY选项") raise RuntimeError("没有设置ANTHROPIC_API_KEY选项")
if inputs == "": inputs = "空空如也的输入栏"
headers, message = generate_payload(inputs, llm_kwargs, history, sys_prompt, image_paths=None)
retry = 0
while True: while True:
try: try:
# make a POST request to the API endpoint, stream=False # make a POST request to the API endpoint, stream=False
from .bridge_all import model_info from .bridge_all import model_info
anthropic = Anthropic(api_key=ANTHROPIC_API_KEY) endpoint = model_info[llm_kwargs['llm_model']]['endpoint']
# endpoint = model_info[llm_kwargs['llm_model']]['endpoint'] response = requests.post(endpoint, headers=headers, json=message,
# with ProxyNetworkActivate() proxies=proxies, stream=True, timeout=TIMEOUT_SECONDS);break
stream = anthropic.completions.create( except requests.exceptions.ReadTimeout as e:
prompt=prompt,
max_tokens_to_sample=4096, # The maximum number of tokens to generate before stopping.
model=llm_kwargs['llm_model'],
stream=True,
temperature = llm_kwargs['temperature']
)
break
except Exception as e:
retry += 1 retry += 1
traceback.print_exc() traceback.print_exc()
if retry > MAX_RETRY: raise TimeoutError if retry > MAX_RETRY: raise TimeoutError
if MAX_RETRY!=0: print(f'请求超时,正在重试 ({retry}/{MAX_RETRY}) ……') if MAX_RETRY!=0: print(f'请求超时,正在重试 ({retry}/{MAX_RETRY}) ……')
stream_response = response.iter_lines()
result = '' result = ''
try: while True:
for completion in stream: try: chunk = next(stream_response)
result += completion.completion except StopIteration:
if not console_slience: print(completion.completion, end='') break
if observe_window is not None: except requests.exceptions.ConnectionError:
# 观测窗,把已经获取的数据显示出去 chunk = next(stream_response) # 失败了,重试一次?再失败就没办法了。
if len(observe_window) >= 1: observe_window[0] += completion.completion need_to_pass, chunkjson, is_last_chunk = decode_chunk(chunk)
# 看门狗,如果超过期限没有喂狗,则终止 if chunk:
if len(observe_window) >= 2: try:
if (time.time()-observe_window[1]) > watch_dog_patience: if need_to_pass:
raise RuntimeError("用户取消了程序。") pass
except Exception as e: elif is_last_chunk:
traceback.print_exc() # logging.info(f'[response] {result}')
break
else:
if chunkjson and chunkjson['type'] == 'content_block_delta':
result += chunkjson['delta']['text']
print(chunkjson['delta']['text'], end='')
if observe_window is not None:
# 观测窗,把已经获取的数据显示出去
if len(observe_window) >= 1:
observe_window[0] += chunkjson['delta']['text']
# 看门狗,如果超过期限没有喂狗,则终止
if len(observe_window) >= 2:
if (time.time()-observe_window[1]) > watch_dog_patience:
raise RuntimeError("用户取消了程序。")
except Exception as e:
chunk = get_full_error(chunk, stream_response)
chunk_decoded = chunk.decode()
error_msg = chunk_decoded
print(error_msg)
raise RuntimeError("Json解析不合常规")
return result return result
def make_media_input(history,inputs,image_paths):
for image_path in image_paths:
inputs = inputs + f'<br/><br/><div align="center"><img src="file={os.path.abspath(image_path)}"></div>'
return inputs
def predict(inputs, llm_kwargs, plugin_kwargs, chatbot, history=[], system_prompt='', stream = True, additional_fn=None): def predict(inputs, llm_kwargs, plugin_kwargs, chatbot, history=[], system_prompt='', stream = True, additional_fn=None):
""" """
@@ -109,7 +154,7 @@ def predict(inputs, llm_kwargs, plugin_kwargs, chatbot, history=[], system_promp
chatbot 为WebUI中显示的对话列表,修改它,然后yeild出去,可以直接修改对话界面内容 chatbot 为WebUI中显示的对话列表,修改它,然后yeild出去,可以直接修改对话界面内容
additional_fn代表点击的哪个按钮,按钮见functional.py additional_fn代表点击的哪个按钮,按钮见functional.py
""" """
from anthropic import Anthropic if inputs == "": inputs = "空空如也的输入栏"
if len(ANTHROPIC_API_KEY) == 0: if len(ANTHROPIC_API_KEY) == 0:
chatbot.append((inputs, "没有设置ANTHROPIC_API_KEY")) chatbot.append((inputs, "没有设置ANTHROPIC_API_KEY"))
yield from update_ui(chatbot=chatbot, history=history, msg="等待响应") # 刷新界面 yield from update_ui(chatbot=chatbot, history=history, msg="等待响应") # 刷新界面
@@ -119,13 +164,23 @@ def predict(inputs, llm_kwargs, plugin_kwargs, chatbot, history=[], system_promp
from core_functional import handle_core_functionality from core_functional import handle_core_functionality
inputs, history = handle_core_functionality(additional_fn, inputs, history, chatbot) inputs, history = handle_core_functionality(additional_fn, inputs, history, chatbot)
raw_input = inputs have_recent_file, image_paths = every_image_file_in_path(chatbot)
logging.info(f'[raw_input] {raw_input}') if len(image_paths) > 20:
chatbot.append((inputs, "")) chatbot.append((inputs, "图片数量超过api上限(20张)"))
yield from update_ui(chatbot=chatbot, history=history, msg="等待响应") # 刷新界面 yield from update_ui(chatbot=chatbot, history=history, msg="等待响应")
return
if any([llm_kwargs['llm_model'] == model for model in Claude_3_Models]) and have_recent_file:
if inputs == "" or inputs == "空空如也的输入栏": inputs = "请描述给出的图片"
system_prompt += picture_system_prompt # 由于没有单独的参数保存包含图片的历史,所以只能通过提示词对第几张图片进行定位
chatbot.append((make_media_input(history,inputs, image_paths), ""))
yield from update_ui(chatbot=chatbot, history=history, msg="等待响应") # 刷新界面
else:
chatbot.append((inputs, ""))
yield from update_ui(chatbot=chatbot, history=history, msg="等待响应") # 刷新界面
try: try:
prompt = generate_payload(inputs, llm_kwargs, history, system_prompt, stream) headers, message = generate_payload(inputs, llm_kwargs, history, system_prompt, image_paths)
except RuntimeError as e: except RuntimeError as e:
chatbot[-1] = (inputs, f"您提供的api-key不满足要求,不包含任何可用于{llm_kwargs['llm_model']}的api-key。您可能选择了错误的模型或请求源。") chatbot[-1] = (inputs, f"您提供的api-key不满足要求,不包含任何可用于{llm_kwargs['llm_model']}的api-key。您可能选择了错误的模型或请求源。")
yield from update_ui(chatbot=chatbot, history=history, msg="api-key不满足要求") # 刷新界面 yield from update_ui(chatbot=chatbot, history=history, msg="api-key不满足要求") # 刷新界面
@@ -138,91 +193,117 @@ def predict(inputs, llm_kwargs, plugin_kwargs, chatbot, history=[], system_promp
try: try:
# make a POST request to the API endpoint, stream=True # make a POST request to the API endpoint, stream=True
from .bridge_all import model_info from .bridge_all import model_info
anthropic = Anthropic(api_key=ANTHROPIC_API_KEY) endpoint = model_info[llm_kwargs['llm_model']]['endpoint']
# endpoint = model_info[llm_kwargs['llm_model']]['endpoint'] response = requests.post(endpoint, headers=headers, json=message,
# with ProxyNetworkActivate() proxies=proxies, stream=True, timeout=TIMEOUT_SECONDS);break
stream = anthropic.completions.create( except requests.exceptions.ReadTimeout as e:
prompt=prompt,
max_tokens_to_sample=4096, # The maximum number of tokens to generate before stopping.
model=llm_kwargs['llm_model'],
stream=True,
temperature = llm_kwargs['temperature']
)
break
except:
retry += 1 retry += 1
chatbot[-1] = ((chatbot[-1][0], timeout_bot_msg)) traceback.print_exc()
retry_msg = f",正在重试 ({retry}/{MAX_RETRY}) ……" if MAX_RETRY > 0 else ""
yield from update_ui(chatbot=chatbot, history=history, msg="请求超时"+retry_msg) # 刷新界面
if retry > MAX_RETRY: raise TimeoutError if retry > MAX_RETRY: raise TimeoutError
if MAX_RETRY!=0: print(f'请求超时,正在重试 ({retry}/{MAX_RETRY}) ……')
stream_response = response.iter_lines()
gpt_replying_buffer = "" gpt_replying_buffer = ""
for completion in stream: while True:
try: try: chunk = next(stream_response)
gpt_replying_buffer = gpt_replying_buffer + completion.completion except StopIteration:
history[-1] = gpt_replying_buffer break
chatbot[-1] = (history[-2], history[-1]) except requests.exceptions.ConnectionError:
yield from update_ui(chatbot=chatbot, history=history, msg='正常') # 刷新界面 chunk = next(stream_response) # 失败了,重试一次?再失败就没办法了。
need_to_pass, chunkjson, is_last_chunk = decode_chunk(chunk)
if chunk:
try:
if need_to_pass:
pass
elif is_last_chunk:
log_chat(llm_model=llm_kwargs["llm_model"], input_str=inputs, output_str=gpt_replying_buffer)
# logging.info(f'[response] {gpt_replying_buffer}')
break
else:
if chunkjson and chunkjson['type'] == 'content_block_delta':
gpt_replying_buffer += chunkjson['delta']['text']
history[-1] = gpt_replying_buffer
chatbot[-1] = (history[-2], history[-1])
yield from update_ui(chatbot=chatbot, history=history, msg='正常') # 刷新界面
except Exception as e: except Exception as e:
from toolbox import regular_txt_to_markdown chunk = get_full_error(chunk, stream_response)
tb_str = '```\n' + trimmed_format_exc() + '```' chunk_decoded = chunk.decode()
chatbot[-1] = (chatbot[-1][0], f"[Local Message] 异常 \n\n{tb_str}") error_msg = chunk_decoded
yield from update_ui(chatbot=chatbot, history=history, msg="Json异常" + tb_str) # 刷新界面 print(error_msg)
return raise RuntimeError("Json解析不合常规")
def multiple_picture_types(image_paths):
"""
根据图片类型返回image/jpeg, image/png, image/gif, image/webp,无法判断则返回image/jpeg
"""
for image_path in image_paths:
if image_path.endswith('.jpeg') or image_path.endswith('.jpg'):
return 'image/jpeg'
elif image_path.endswith('.png'):
return 'image/png'
elif image_path.endswith('.gif'):
return 'image/gif'
elif image_path.endswith('.webp'):
return 'image/webp'
return 'image/jpeg'
def generate_payload(inputs, llm_kwargs, history, system_prompt, image_paths):
# https://github.com/jtsang4/claude-to-chatgpt/blob/main/claude_to_chatgpt/adapter.py
def convert_messages_to_prompt(messages):
prompt = ""
role_map = {
"system": "Human",
"user": "Human",
"assistant": "Assistant",
}
for message in messages:
role = message["role"]
content = message["content"]
transformed_role = role_map[role]
prompt += f"\n\n{transformed_role.capitalize()}: {content}"
prompt += "\n\nAssistant: "
return prompt
def generate_payload(inputs, llm_kwargs, history, system_prompt, stream):
""" """
整合所有信息,选择LLM模型,生成http请求,为发送请求做准备 整合所有信息,选择LLM模型,生成http请求,为发送请求做准备
""" """
from anthropic import Anthropic, HUMAN_PROMPT, AI_PROMPT
conversation_cnt = len(history) // 2 conversation_cnt = len(history) // 2
messages = [{"role": "system", "content": system_prompt}] messages = []
if conversation_cnt: if conversation_cnt:
for index in range(0, 2*conversation_cnt, 2): for index in range(0, 2*conversation_cnt, 2):
what_i_have_asked = {} what_i_have_asked = {}
what_i_have_asked["role"] = "user" what_i_have_asked["role"] = "user"
what_i_have_asked["content"] = history[index] what_i_have_asked["content"] = [{"type": "text", "text": history[index]}]
what_gpt_answer = {} what_gpt_answer = {}
what_gpt_answer["role"] = "assistant" what_gpt_answer["role"] = "assistant"
what_gpt_answer["content"] = history[index+1] what_gpt_answer["content"] = [{"type": "text", "text": history[index+1]}]
if what_i_have_asked["content"] != "": if what_i_have_asked["content"][0]["text"] != "":
if what_gpt_answer["content"] == "": continue if what_i_have_asked["content"][0]["text"] == "": continue
if what_gpt_answer["content"] == timeout_bot_msg: continue if what_i_have_asked["content"][0]["text"] == timeout_bot_msg: continue
messages.append(what_i_have_asked) messages.append(what_i_have_asked)
messages.append(what_gpt_answer) messages.append(what_gpt_answer)
else: else:
messages[-1]['content'] = what_gpt_answer['content'] messages[-1]['content'][0]['text'] = what_gpt_answer['content'][0]['text']
what_i_ask_now = {} if any([llm_kwargs['llm_model'] == model for model in Claude_3_Models]) and image_paths:
what_i_ask_now["role"] = "user" what_i_ask_now = {}
what_i_ask_now["content"] = inputs what_i_ask_now["role"] = "user"
what_i_ask_now["content"] = []
for image_path in image_paths:
what_i_ask_now["content"].append({
"type": "image",
"source": {
"type": "base64",
"media_type": multiple_picture_types(image_paths),
"data": encode_image(image_path),
}
})
what_i_ask_now["content"].append({"type": "text", "text": inputs})
else:
what_i_ask_now = {}
what_i_ask_now["role"] = "user"
what_i_ask_now["content"] = [{"type": "text", "text": inputs}]
messages.append(what_i_ask_now) messages.append(what_i_ask_now)
prompt = convert_messages_to_prompt(messages) # 开始整理headers与message
headers = {
return prompt 'x-api-key': ANTHROPIC_API_KEY,
'anthropic-version': '2023-06-01',
'content-type': 'application/json'
}
payload = {
'model': llm_kwargs['llm_model'],
'max_tokens': 4096,
'messages': messages,
'temperature': llm_kwargs['temperature'],
'stream': True,
'system': system_prompt
}
return headers, payload

查看文件

@@ -0,0 +1,328 @@
# 借鉴了 https://github.com/GaiZhenbiao/ChuanhuChatGPT 项目
"""
该文件中主要包含三个函数
不具备多线程能力的函数:
1. predict: 正常对话时使用,具备完备的交互功能,不可多线程
具备多线程调用能力的函数
2. predict_no_ui_long_connection支持多线程
"""
import json
import time
import gradio as gr
import logging
import traceback
import requests
import importlib
import random
# config_private.py放自己的秘密如API和代理网址
# 读取时首先看是否存在私密的config_private配置文件不受git管控,如果有,则覆盖原config文件
from toolbox import get_conf, update_ui, is_any_api_key, select_api_key, what_keys, clip_history
from toolbox import trimmed_format_exc, is_the_upload_folder, read_one_api_model_name, log_chat
from toolbox import ChatBotWithCookies
proxies, TIMEOUT_SECONDS, MAX_RETRY, API_ORG, AZURE_CFG_ARRAY = \
get_conf('proxies', 'TIMEOUT_SECONDS', 'MAX_RETRY', 'API_ORG', 'AZURE_CFG_ARRAY')
timeout_bot_msg = '[Local Message] Request timeout. Network error. Please check proxy settings in config.py.' + \
'网络错误,检查代理服务器是否可用,以及代理设置的格式是否正确,格式须是[协议]://[地址]:[端口],缺一不可。'
def get_full_error(chunk, stream_response):
"""
获取完整的从Cohere返回的报错
"""
while True:
try:
chunk += next(stream_response)
except:
break
return chunk
def decode_chunk(chunk):
# 提前读取一些信息 (用于判断异常)
chunk_decoded = chunk.decode()
chunkjson = None
has_choices = False
choice_valid = False
has_content = False
has_role = False
try:
chunkjson = json.loads(chunk_decoded)
has_choices = 'choices' in chunkjson
if has_choices: choice_valid = (len(chunkjson['choices']) > 0)
if has_choices and choice_valid: has_content = ("content" in chunkjson['choices'][0]["delta"])
if has_content: has_content = (chunkjson['choices'][0]["delta"]["content"] is not None)
if has_choices and choice_valid: has_role = "role" in chunkjson['choices'][0]["delta"]
except:
pass
return chunk_decoded, chunkjson, has_choices, choice_valid, has_content, has_role
from functools import lru_cache
@lru_cache(maxsize=32)
def verify_endpoint(endpoint):
"""
检查endpoint是否可用
"""
if "你亲手写的api名称" in endpoint:
raise ValueError("Endpoint不正确, 请检查AZURE_ENDPOINT的配置! 当前的Endpoint为:" + endpoint)
return endpoint
def predict_no_ui_long_connection(inputs:str, llm_kwargs:dict, history:list=[], sys_prompt:str="", observe_window:list=None, console_slience:bool=False):
"""
发送,等待回复,一次性完成,不显示中间过程。但内部用stream的方法避免中途网线被掐。
inputs
是本次问询的输入
sys_prompt:
系统静默prompt
llm_kwargs
内部调优参数
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)
retry = 0
while True:
try:
# make a POST request to the API endpoint, stream=False
from .bridge_all import model_info
endpoint = verify_endpoint(model_info[llm_kwargs['llm_model']]['endpoint'])
response = requests.post(endpoint, headers=headers, proxies=proxies,
json=payload, stream=True, timeout=TIMEOUT_SECONDS); break
except requests.exceptions.ReadTimeout as e:
retry += 1
traceback.print_exc()
if retry > MAX_RETRY: raise TimeoutError
if MAX_RETRY!=0: print(f'请求超时,正在重试 ({retry}/{MAX_RETRY}) ……')
stream_response = response.iter_lines()
result = ''
json_data = None
while True:
try: chunk = next(stream_response)
except StopIteration:
break
except requests.exceptions.ConnectionError:
chunk = next(stream_response) # 失败了,重试一次?再失败就没办法了。
chunk_decoded, chunkjson, has_choices, choice_valid, has_content, has_role = decode_chunk(chunk)
if chunkjson['event_type'] == 'stream-start': continue
if chunkjson['event_type'] == 'text-generation':
result += chunkjson["text"]
if not console_slience: print(chunkjson["text"], end='')
if observe_window is not None:
# 观测窗,把已经获取的数据显示出去
if len(observe_window) >= 1:
observe_window[0] += chunkjson["text"]
# 看门狗,如果超过期限没有喂狗,则终止
if len(observe_window) >= 2:
if (time.time()-observe_window[1]) > watch_dog_patience:
raise RuntimeError("用户取消了程序。")
if chunkjson['event_type'] == 'stream-end': break
return result
def predict(inputs:str, llm_kwargs:dict, plugin_kwargs:dict, chatbot:ChatBotWithCookies,
history:list=[], system_prompt:str='', stream:bool=True, additional_fn:str=None):
"""
发送至chatGPT,流式获取输出。
用于基础的对话功能。
inputs 是本次问询的输入
top_p, temperature是chatGPT的内部调优参数
history 是之前的对话列表注意无论是inputs还是history,内容太长了都会触发token数量溢出的错误
chatbot 为WebUI中显示的对话列表,修改它,然后yeild出去,可以直接修改对话界面内容
additional_fn代表点击的哪个按钮,按钮见functional.py
"""
# if is_any_api_key(inputs):
# chatbot._cookies['api_key'] = inputs
# chatbot.append(("输入已识别为Cohere的api_key", what_keys(inputs)))
# yield from update_ui(chatbot=chatbot, history=history, msg="api_key已导入") # 刷新界面
# return
# elif not is_any_api_key(chatbot._cookies['api_key']):
# chatbot.append((inputs, "缺少api_key。\n\n1. 临时解决方案直接在输入区键入api_key,然后回车提交。\n\n2. 长效解决方案在config.py中配置。"))
# yield from update_ui(chatbot=chatbot, history=history, msg="缺少api_key") # 刷新界面
# return
user_input = inputs
if additional_fn is not None:
from core_functional import handle_core_functionality
inputs, history = handle_core_functionality(additional_fn, inputs, history, chatbot)
raw_input = inputs
# logging.info(f'[raw_input] {raw_input}')
chatbot.append((inputs, ""))
yield from update_ui(chatbot=chatbot, history=history, msg="等待响应") # 刷新界面
# check mis-behavior
if is_the_upload_folder(user_input):
chatbot[-1] = (inputs, f"[Local Message] 检测到操作错误!当您上传文档之后,需点击“**函数插件区**”按钮进行处理,请勿点击“提交”按钮或者“基础功能区”按钮。")
yield from update_ui(chatbot=chatbot, history=history, msg="正常") # 刷新界面
time.sleep(2)
try:
headers, payload = 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
# 检查endpoint是否合法
try:
from .bridge_all import model_info
endpoint = verify_endpoint(model_info[llm_kwargs['llm_model']]['endpoint'])
except:
tb_str = '```\n' + trimmed_format_exc() + '```'
chatbot[-1] = (inputs, tb_str)
yield from update_ui(chatbot=chatbot, history=history, msg="Endpoint不满足要求") # 刷新界面
return
history.append(inputs); history.append("")
retry = 0
while True:
try:
# make a POST request to the API endpoint, stream=True
response = requests.post(endpoint, headers=headers, proxies=proxies,
json=payload, stream=True, timeout=TIMEOUT_SECONDS);break
except:
retry += 1
chatbot[-1] = ((chatbot[-1][0], timeout_bot_msg))
retry_msg = f",正在重试 ({retry}/{MAX_RETRY}) ……" if MAX_RETRY > 0 else ""
yield from update_ui(chatbot=chatbot, history=history, msg="请求超时"+retry_msg) # 刷新界面
if retry > MAX_RETRY: raise TimeoutError
gpt_replying_buffer = ""
is_head_of_the_stream = True
if stream:
stream_response = response.iter_lines()
while True:
try:
chunk = next(stream_response)
except StopIteration:
# 非Cohere官方接口的出现这样的报错,Cohere和API2D不会走这里
chunk_decoded = chunk.decode()
error_msg = chunk_decoded
# 其他情况,直接返回报错
chatbot, history = handle_error(inputs, llm_kwargs, chatbot, history, chunk_decoded, error_msg)
yield from update_ui(chatbot=chatbot, history=history, msg="非Cohere官方接口返回了错误:" + chunk.decode()) # 刷新界面
return
# 提前读取一些信息 (用于判断异常)
chunk_decoded, chunkjson, has_choices, choice_valid, has_content, has_role = decode_chunk(chunk)
if chunkjson:
try:
if chunkjson['event_type'] == 'stream-start':
continue
if chunkjson['event_type'] == 'text-generation':
gpt_replying_buffer = gpt_replying_buffer + chunkjson["text"]
history[-1] = gpt_replying_buffer
chatbot[-1] = (history[-2], history[-1])
yield from update_ui(chatbot=chatbot, history=history, msg="正常") # 刷新界面
if chunkjson['event_type'] == 'stream-end':
log_chat(llm_model=llm_kwargs["llm_model"], input_str=inputs, output_str=gpt_replying_buffer)
history[-1] = gpt_replying_buffer
chatbot[-1] = (history[-2], history[-1])
yield from update_ui(chatbot=chatbot, history=history, msg="正常") # 刷新界面
break
except Exception as e:
yield from update_ui(chatbot=chatbot, history=history, msg="Json解析不合常规") # 刷新界面
chunk = get_full_error(chunk, stream_response)
chunk_decoded = chunk.decode()
error_msg = chunk_decoded
chatbot, history = handle_error(inputs, llm_kwargs, chatbot, history, chunk_decoded, error_msg)
yield from update_ui(chatbot=chatbot, history=history, msg="Json异常" + error_msg) # 刷新界面
print(error_msg)
return
def handle_error(inputs, llm_kwargs, chatbot, history, chunk_decoded, error_msg):
from .bridge_all import model_info
Cohere_website = ' 请登录Cohere查看详情 https://platform.Cohere.com/signup'
if "reduce the length" in error_msg:
if len(history) >= 2: history[-1] = ""; history[-2] = "" # 清除当前溢出的输入history[-2] 是本次输入, history[-1] 是本次输出
history = clip_history(inputs=inputs, history=history, tokenizer=model_info[llm_kwargs['llm_model']]['tokenizer'],
max_token_limit=(model_info[llm_kwargs['llm_model']]['max_token'])) # history至少释放二分之一
chatbot[-1] = (chatbot[-1][0], "[Local Message] Reduce the length. 本次输入过长, 或历史数据过长. 历史缓存数据已部分释放, 您可以请再次尝试. (若再次失败则更可能是因为输入过长.)")
elif "does not exist" in error_msg:
chatbot[-1] = (chatbot[-1][0], f"[Local Message] Model {llm_kwargs['llm_model']} does not exist. 模型不存在, 或者您没有获得体验资格.")
elif "Incorrect API key" in error_msg:
chatbot[-1] = (chatbot[-1][0], "[Local Message] Incorrect API key. Cohere以提供了不正确的API_KEY为由, 拒绝服务. " + Cohere_website)
elif "exceeded your current quota" in error_msg:
chatbot[-1] = (chatbot[-1][0], "[Local Message] You exceeded your current quota. Cohere以账户额度不足为由, 拒绝服务." + Cohere_website)
elif "account is not active" in error_msg:
chatbot[-1] = (chatbot[-1][0], "[Local Message] Your account is not active. Cohere以账户失效为由, 拒绝服务." + Cohere_website)
elif "associated with a deactivated account" in error_msg:
chatbot[-1] = (chatbot[-1][0], "[Local Message] You are associated with a deactivated account. Cohere以账户失效为由, 拒绝服务." + Cohere_website)
elif "API key has been deactivated" in error_msg:
chatbot[-1] = (chatbot[-1][0], "[Local Message] API key has been deactivated. Cohere以账户失效为由, 拒绝服务." + Cohere_website)
elif "bad forward key" in error_msg:
chatbot[-1] = (chatbot[-1][0], "[Local Message] Bad forward key. API2D账户额度不足.")
elif "Not enough point" in error_msg:
chatbot[-1] = (chatbot[-1][0], "[Local Message] Not enough point. API2D账户点数不足.")
else:
from toolbox import regular_txt_to_markdown
tb_str = '```\n' + trimmed_format_exc() + '```'
chatbot[-1] = (chatbot[-1][0], f"[Local Message] 异常 \n\n{tb_str} \n\n{regular_txt_to_markdown(chunk_decoded)}")
return chatbot, history
def generate_payload(inputs, llm_kwargs, history, system_prompt, stream):
"""
整合所有信息,选择LLM模型,生成http请求,为发送请求做准备
"""
# if not is_any_api_key(llm_kwargs['api_key']):
# raise AssertionError("你提供了错误的API_KEY。\n\n1. 临时解决方案直接在输入区键入api_key,然后回车提交。\n\n2. 长效解决方案在config.py中配置。")
api_key = select_api_key(llm_kwargs['api_key'], llm_kwargs['llm_model'])
headers = {
"Content-Type": "application/json",
"Authorization": f"Bearer {api_key}"
}
if API_ORG.startswith('org-'): headers.update({"Cohere-Organization": API_ORG})
if llm_kwargs['llm_model'].startswith('azure-'):
headers.update({"api-key": api_key})
if llm_kwargs['llm_model'] in AZURE_CFG_ARRAY.keys():
azure_api_key_unshared = AZURE_CFG_ARRAY[llm_kwargs['llm_model']]["AZURE_API_KEY"]
headers.update({"api-key": azure_api_key_unshared})
conversation_cnt = len(history) // 2
messages = [{"role": "SYSTEM", "message": system_prompt}]
if conversation_cnt:
for index in range(0, 2*conversation_cnt, 2):
what_i_have_asked = {}
what_i_have_asked["role"] = "USER"
what_i_have_asked["message"] = history[index]
what_gpt_answer = {}
what_gpt_answer["role"] = "CHATBOT"
what_gpt_answer["message"] = history[index+1]
if what_i_have_asked["message"] != "":
if what_gpt_answer["message"] == "": continue
if what_gpt_answer["message"] == timeout_bot_msg: continue
messages.append(what_i_have_asked)
messages.append(what_gpt_answer)
else:
messages[-1]['message'] = what_gpt_answer['message']
model = llm_kwargs['llm_model']
if model.startswith('cohere-'): model = model[len('cohere-'):]
payload = {
"model": model,
"message": inputs,
"chat_history": messages,
"temperature": llm_kwargs['temperature'], # 1.0,
"top_p": llm_kwargs['top_p'], # 1.0,
"n": 1,
"stream": stream,
"presence_penalty": 0,
"frequency_penalty": 0,
}
return headers,payload

查看文件

@@ -7,6 +7,7 @@ import re
import os import os
import time import time
from request_llms.com_google import GoogleChatInit from request_llms.com_google import GoogleChatInit
from toolbox import ChatBotWithCookies
from toolbox import get_conf, update_ui, update_ui_lastest_msg, have_any_recent_upload_image_files, trimmed_format_exc from toolbox import get_conf, update_ui, update_ui_lastest_msg, have_any_recent_upload_image_files, trimmed_format_exc
proxies, TIMEOUT_SECONDS, MAX_RETRY = get_conf('proxies', 'TIMEOUT_SECONDS', 'MAX_RETRY') proxies, TIMEOUT_SECONDS, MAX_RETRY = get_conf('proxies', 'TIMEOUT_SECONDS', 'MAX_RETRY')
@@ -20,7 +21,7 @@ def predict_no_ui_long_connection(inputs, llm_kwargs, history=[], sys_prompt="",
if get_conf("GEMINI_API_KEY") == "": if get_conf("GEMINI_API_KEY") == "":
raise ValueError(f"请配置 GEMINI_API_KEY。") raise ValueError(f"请配置 GEMINI_API_KEY。")
genai = GoogleChatInit() genai = GoogleChatInit(llm_kwargs)
watch_dog_patience = 5 # 看门狗的耐心, 设置5秒即可 watch_dog_patience = 5 # 看门狗的耐心, 设置5秒即可
gpt_replying_buffer = '' gpt_replying_buffer = ''
stream_response = genai.generate_chat(inputs, llm_kwargs, history, sys_prompt) stream_response = genai.generate_chat(inputs, llm_kwargs, history, sys_prompt)
@@ -44,7 +45,8 @@ def predict_no_ui_long_connection(inputs, llm_kwargs, history=[], sys_prompt="",
return gpt_replying_buffer return gpt_replying_buffer
def predict(inputs, llm_kwargs, plugin_kwargs, chatbot, history=[], system_prompt='', stream=True, additional_fn=None): def predict(inputs:str, llm_kwargs:dict, plugin_kwargs:dict, chatbot:ChatBotWithCookies,
history:list=[], system_prompt:str='', stream:bool=True, additional_fn:str=None):
# 检查API_KEY # 检查API_KEY
if get_conf("GEMINI_API_KEY") == "": if get_conf("GEMINI_API_KEY") == "":
yield from update_ui_lastest_msg(f"请配置 GEMINI_API_KEY。", chatbot=chatbot, history=history, delay=0) yield from update_ui_lastest_msg(f"请配置 GEMINI_API_KEY。", chatbot=chatbot, history=history, delay=0)
@@ -70,7 +72,7 @@ def predict(inputs, llm_kwargs, plugin_kwargs, chatbot, history=[], system_promp
chatbot.append((inputs, "")) chatbot.append((inputs, ""))
yield from update_ui(chatbot=chatbot, history=history) yield from update_ui(chatbot=chatbot, history=history)
genai = GoogleChatInit() genai = GoogleChatInit(llm_kwargs)
retry = 0 retry = 0
while True: while True:
try: try:

查看文件

@@ -1,10 +1,10 @@
from transformers import AutoModel, AutoTokenizer
import time import time
import threading import threading
import importlib import importlib
from toolbox import update_ui, get_conf from toolbox import update_ui, get_conf
from multiprocessing import Process, Pipe from multiprocessing import Process, Pipe
from transformers import AutoModel, AutoTokenizer
load_message = "jittorllms尚未加载,加载需要一段时间。注意,请避免混用多种jittor模型,否则可能导致显存溢出而造成卡顿,取决于`config.py`的配置,jittorllms消耗大量的内存CPU或显存GPU,也许会导致低配计算机卡死 ……" load_message = "jittorllms尚未加载,加载需要一段时间。注意,请避免混用多种jittor模型,否则可能导致显存溢出而造成卡顿,取决于`config.py`的配置,jittorllms消耗大量的内存CPU或显存GPU,也许会导致低配计算机卡死 ……"
@@ -106,7 +106,8 @@ class GetGLMHandle(Process):
global llama_glm_handle global llama_glm_handle
llama_glm_handle = None llama_glm_handle = None
################################################################################# #################################################################################
def predict_no_ui_long_connection(inputs, llm_kwargs, history=[], sys_prompt="", observe_window=[], console_slience=False): def predict_no_ui_long_connection(inputs:str, llm_kwargs:dict, history:list=[], sys_prompt:str="",
observe_window:list=[], console_slience:bool=False):
""" """
多线程方法 多线程方法
函数的说明请见 request_llms/bridge_all.py 函数的说明请见 request_llms/bridge_all.py

查看文件

@@ -1,10 +1,10 @@
from transformers import AutoModel, AutoTokenizer
import time import time
import threading import threading
import importlib import importlib
from toolbox import update_ui, get_conf from toolbox import update_ui, get_conf
from multiprocessing import Process, Pipe from multiprocessing import Process, Pipe
from transformers import AutoModel, AutoTokenizer
load_message = "jittorllms尚未加载,加载需要一段时间。注意,请避免混用多种jittor模型,否则可能导致显存溢出而造成卡顿,取决于`config.py`的配置,jittorllms消耗大量的内存CPU或显存GPU,也许会导致低配计算机卡死 ……" load_message = "jittorllms尚未加载,加载需要一段时间。注意,请避免混用多种jittor模型,否则可能导致显存溢出而造成卡顿,取决于`config.py`的配置,jittorllms消耗大量的内存CPU或显存GPU,也许会导致低配计算机卡死 ……"
@@ -106,7 +106,8 @@ class GetGLMHandle(Process):
global pangu_glm_handle global pangu_glm_handle
pangu_glm_handle = None pangu_glm_handle = None
################################################################################# #################################################################################
def predict_no_ui_long_connection(inputs, llm_kwargs, history=[], sys_prompt="", observe_window=[], console_slience=False): def predict_no_ui_long_connection(inputs:str, llm_kwargs:dict, history:list=[], sys_prompt:str="",
observe_window:list=[], console_slience:bool=False):
""" """
多线程方法 多线程方法
函数的说明请见 request_llms/bridge_all.py 函数的说明请见 request_llms/bridge_all.py

查看文件

@@ -106,7 +106,8 @@ class GetGLMHandle(Process):
global rwkv_glm_handle global rwkv_glm_handle
rwkv_glm_handle = None rwkv_glm_handle = None
################################################################################# #################################################################################
def predict_no_ui_long_connection(inputs, llm_kwargs, history=[], sys_prompt="", observe_window=[], console_slience=False): def predict_no_ui_long_connection(inputs:str, llm_kwargs:dict, history:list=[], sys_prompt:str="",
observe_window:list=[], console_slience:bool=False):
""" """
多线程方法 多线程方法
函数的说明请见 request_llms/bridge_all.py 函数的说明请见 request_llms/bridge_all.py

查看文件

@@ -0,0 +1,197 @@
# encoding: utf-8
# @Time : 2024/3/3
# @Author : Spike
# @Descr :
import json
import os
import time
import logging
from toolbox import get_conf, update_ui, log_chat
from toolbox import ChatBotWithCookies
import requests
class MoonShotInit:
def __init__(self):
self.llm_model = None
self.url = 'https://api.moonshot.cn/v1/chat/completions'
self.api_key = get_conf('MOONSHOT_API_KEY')
def __converter_file(self, user_input: str):
what_ask = []
for f in user_input.splitlines():
if os.path.exists(f):
files = []
if os.path.isdir(f):
file_list = os.listdir(f)
files.extend([os.path.join(f, file) for file in file_list])
else:
files.append(f)
for file in files:
if file.split('.')[-1] in ['pdf']:
with open(file, 'r') as fp:
from crazy_functions.crazy_utils import read_and_clean_pdf_text
file_content, _ = read_and_clean_pdf_text(fp)
what_ask.append({"role": "system", "content": file_content})
return what_ask
def __converter_user(self, user_input: str):
what_i_ask_now = {"role": "user", "content": user_input}
return what_i_ask_now
def __conversation_history(self, history):
conversation_cnt = len(history) // 2
messages = []
if conversation_cnt:
for index in range(0, 2 * conversation_cnt, 2):
what_i_have_asked = {
"role": "user",
"content": str(history[index])
}
what_gpt_answer = {
"role": "assistant",
"content": str(history[index + 1])
}
if what_i_have_asked["content"] != "":
if what_gpt_answer["content"] == "": continue
messages.append(what_i_have_asked)
messages.append(what_gpt_answer)
else:
messages[-1]['content'] = what_gpt_answer['content']
return messages
def _analysis_content(self, chuck):
chunk_decoded = chuck.decode("utf-8")
chunk_json = {}
content = ""
try:
chunk_json = json.loads(chunk_decoded[6:])
content = chunk_json['choices'][0]["delta"].get("content", "")
except:
pass
return chunk_decoded, chunk_json, content
def generate_payload(self, inputs, llm_kwargs, history, system_prompt, stream):
self.llm_model = llm_kwargs['llm_model']
llm_kwargs.update({'use-key': self.api_key})
messages = []
if system_prompt:
messages.append({"role": "system", "content": system_prompt})
messages.extend(self.__converter_file(inputs))
for i in history[0::2]: # 历史文件继续上传
messages.extend(self.__converter_file(i))
messages.extend(self.__conversation_history(history))
messages.append(self.__converter_user(inputs))
header = {
"Content-Type": "application/json",
"Authorization": f"Bearer {self.api_key}",
}
payload = {
"model": self.llm_model,
"messages": messages,
"temperature": llm_kwargs.get('temperature', 0.3), # 1.0,
"top_p": llm_kwargs.get('top_p', 1.0), # 1.0,
"n": llm_kwargs.get('n_choices', 1),
"stream": stream
}
return payload, header
def generate_messages(self, inputs, llm_kwargs, history, system_prompt, stream):
payload, headers = self.generate_payload(inputs, llm_kwargs, history, system_prompt, stream)
response = requests.post(self.url, headers=headers, json=payload, stream=stream)
chunk_content = ""
gpt_bro_result = ""
for chuck in response.iter_lines():
chunk_decoded, check_json, content = self._analysis_content(chuck)
chunk_content += chunk_decoded
if content:
gpt_bro_result += content
yield content, gpt_bro_result, ''
else:
error_msg = msg_handle_error(llm_kwargs, chunk_decoded)
if error_msg:
yield error_msg, gpt_bro_result, error_msg
break
def msg_handle_error(llm_kwargs, chunk_decoded):
use_ket = llm_kwargs.get('use-key', '')
api_key_encryption = use_ket[:8] + '****' + use_ket[-5:]
openai_website = f' 请登录OpenAI查看详情 https://platform.openai.com/signup api-key: `{api_key_encryption}`'
error_msg = ''
if "does not exist" in chunk_decoded:
error_msg = f"[Local Message] Model {llm_kwargs['llm_model']} does not exist. 模型不存在, 或者您没有获得体验资格."
elif "Incorrect API key" in chunk_decoded:
error_msg = f"[Local Message] Incorrect API key. OpenAI以提供了不正确的API_KEY为由, 拒绝服务." + openai_website
elif "exceeded your current quota" in chunk_decoded:
error_msg = "[Local Message] You exceeded your current quota. OpenAI以账户额度不足为由, 拒绝服务." + openai_website
elif "account is not active" in chunk_decoded:
error_msg = "[Local Message] Your account is not active. OpenAI以账户失效为由, 拒绝服务." + openai_website
elif "associated with a deactivated account" in chunk_decoded:
error_msg = "[Local Message] You are associated with a deactivated account. OpenAI以账户失效为由, 拒绝服务." + openai_website
elif "API key has been deactivated" in chunk_decoded:
error_msg = "[Local Message] API key has been deactivated. OpenAI以账户失效为由, 拒绝服务." + openai_website
elif "bad forward key" in chunk_decoded:
error_msg = "[Local Message] Bad forward key. API2D账户额度不足."
elif "Not enough point" in chunk_decoded:
error_msg = "[Local Message] Not enough point. API2D账户点数不足."
elif 'error' in str(chunk_decoded).lower():
try:
error_msg = json.dumps(json.loads(chunk_decoded[:6]), indent=4, ensure_ascii=False)
except:
error_msg = chunk_decoded
return error_msg
def predict(inputs:str, llm_kwargs:dict, plugin_kwargs:dict, chatbot:ChatBotWithCookies,
history:list=[], system_prompt:str='', stream:bool=True, additional_fn:str=None):
chatbot.append([inputs, ""])
if additional_fn is not None:
from core_functional import handle_core_functionality
inputs, history = handle_core_functionality(additional_fn, inputs, history, chatbot)
yield from update_ui(chatbot=chatbot, history=history, msg="等待响应") # 刷新界面
gpt_bro_init = MoonShotInit()
history.extend([inputs, ''])
stream_response = gpt_bro_init.generate_messages(inputs, llm_kwargs, history, system_prompt, stream)
for content, gpt_bro_result, error_bro_meg in stream_response:
chatbot[-1] = [inputs, gpt_bro_result]
history[-1] = gpt_bro_result
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
if error_bro_meg:
chatbot[-1] = [inputs, error_bro_meg]
history = history[:-2]
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
break
log_chat(llm_model=llm_kwargs["llm_model"], input_str=inputs, output_str=gpt_bro_result)
def predict_no_ui_long_connection(inputs, llm_kwargs, history=[], sys_prompt="", observe_window=None,
console_slience=False):
gpt_bro_init = MoonShotInit()
watch_dog_patience = 60 # 看门狗的耐心, 设置10秒即可
stream_response = gpt_bro_init.generate_messages(inputs, llm_kwargs, history, sys_prompt, True)
moonshot_bro_result = ''
for content, moonshot_bro_result, error_bro_meg in stream_response:
moonshot_bro_result = moonshot_bro_result
if error_bro_meg:
if len(observe_window) >= 3:
observe_window[2] = error_bro_meg
return f'{moonshot_bro_result} 对话错误'
# 观测窗
if len(observe_window) >= 1:
observe_window[0] = moonshot_bro_result
if len(observe_window) >= 2:
if (time.time() - observe_window[1]) > watch_dog_patience:
observe_window[2] = "请求超时,程序终止。"
raise RuntimeError(f"{moonshot_bro_result} 程序终止。")
return moonshot_bro_result
if __name__ == '__main__':
moon_ai = MoonShotInit()
for g in moon_ai.generate_messages('hello', {'llm_model': 'moonshot-v1-8k'},
[], '', True):
print(g)

查看文件

@@ -171,7 +171,8 @@ class GetGLMHandle(Process):
global moss_handle global moss_handle
moss_handle = None moss_handle = None
################################################################################# #################################################################################
def predict_no_ui_long_connection(inputs, llm_kwargs, history=[], sys_prompt="", observe_window=[], console_slience=False): def predict_no_ui_long_connection(inputs:str, llm_kwargs:dict, history:list=[], sys_prompt:str="",
observe_window:list=[], console_slience:bool=False):
""" """
多线程方法 多线程方法
函数的说明请见 request_llms/bridge_all.py 函数的说明请见 request_llms/bridge_all.py

查看文件

@@ -117,7 +117,8 @@ def generate_from_baidu_qianfan(inputs, llm_kwargs, history, system_prompt):
raise RuntimeError(dec['error_msg']) raise RuntimeError(dec['error_msg'])
def predict_no_ui_long_connection(inputs, llm_kwargs, history=[], sys_prompt="", observe_window=[], console_slience=False): def predict_no_ui_long_connection(inputs:str, llm_kwargs:dict, history:list=[], sys_prompt:str="",
observe_window:list=[], console_slience:bool=False):
""" """
⭐多线程方法 ⭐多线程方法
函数的说明请见 request_llms/bridge_all.py 函数的说明请见 request_llms/bridge_all.py

查看文件

@@ -5,7 +5,8 @@ from toolbox import check_packages, report_exception
model_name = 'Qwen' model_name = 'Qwen'
def predict_no_ui_long_connection(inputs, llm_kwargs, history=[], sys_prompt="", observe_window=[], console_slience=False): def predict_no_ui_long_connection(inputs:str, llm_kwargs:dict, history:list=[], sys_prompt:str="",
observe_window:list=[], console_slience:bool=False):
""" """
⭐多线程方法 ⭐多线程方法
函数的说明请见 request_llms/bridge_all.py 函数的说明请见 request_llms/bridge_all.py
@@ -47,6 +48,8 @@ def predict(inputs, llm_kwargs, plugin_kwargs, chatbot, history=[], system_promp
if additional_fn is not None: if additional_fn is not None:
from core_functional import handle_core_functionality from core_functional import handle_core_functionality
inputs, history = handle_core_functionality(additional_fn, inputs, history, chatbot) inputs, history = handle_core_functionality(additional_fn, inputs, history, chatbot)
chatbot[-1] = (inputs, "")
yield from update_ui(chatbot=chatbot, history=history)
# 开始接收回复 # 开始接收回复
from .com_qwenapi import QwenRequestInstance from .com_qwenapi import QwenRequestInstance

查看文件

@@ -9,7 +9,8 @@ def validate_key():
if YUNQUE_SECRET_KEY == '': return False if YUNQUE_SECRET_KEY == '': return False
return True return True
def predict_no_ui_long_connection(inputs, llm_kwargs, history=[], sys_prompt="", observe_window=[], console_slience=False): def predict_no_ui_long_connection(inputs:str, llm_kwargs:dict, history:list=[], sys_prompt:str="",
observe_window:list=[], console_slience:bool=False):
""" """
⭐ 多线程方法 ⭐ 多线程方法
函数的说明请见 request_llms/bridge_all.py 函数的说明请见 request_llms/bridge_all.py

查看文件

@@ -13,7 +13,8 @@ def validate_key():
return False return False
return True return True
def predict_no_ui_long_connection(inputs, llm_kwargs, history=[], sys_prompt="", observe_window=[], console_slience=False): def predict_no_ui_long_connection(inputs:str, llm_kwargs:dict, history:list=[], sys_prompt:str="",
observe_window:list=[], console_slience:bool=False):
""" """
⭐多线程方法 ⭐多线程方法
函数的说明请见 request_llms/bridge_all.py 函数的说明请见 request_llms/bridge_all.py

查看文件

@@ -0,0 +1,283 @@
# 借鉴自同目录下的bridge_chatgpt.py
"""
该文件中主要包含三个函数
不具备多线程能力的函数:
1. predict: 正常对话时使用,具备完备的交互功能,不可多线程
具备多线程调用能力的函数
2. predict_no_ui_long_connection支持多线程
"""
import json
import time
import gradio as gr
import logging
import traceback
import requests
import importlib
import random
# config_private.py放自己的秘密如API和代理网址
# 读取时首先看是否存在私密的config_private配置文件不受git管控,如果有,则覆盖原config文件
from toolbox import get_conf, update_ui, trimmed_format_exc, is_the_upload_folder, read_one_api_model_name
proxies, TIMEOUT_SECONDS, MAX_RETRY, YIMODEL_API_KEY = \
get_conf('proxies', 'TIMEOUT_SECONDS', 'MAX_RETRY', 'YIMODEL_API_KEY')
timeout_bot_msg = '[Local Message] Request timeout. Network error. Please check proxy settings in config.py.' + \
'网络错误,检查代理服务器是否可用,以及代理设置的格式是否正确,格式须是[协议]://[地址]:[端口],缺一不可。'
def get_full_error(chunk, stream_response):
"""
获取完整的从Openai返回的报错
"""
while True:
try:
chunk += next(stream_response)
except:
break
return chunk
def decode_chunk(chunk):
# 提前读取一些信息(用于判断异常)
chunk_decoded = chunk.decode()
chunkjson = None
is_last_chunk = False
try:
chunkjson = json.loads(chunk_decoded[6:])
is_last_chunk = chunkjson.get("lastOne", False)
except:
pass
return chunk_decoded, chunkjson, is_last_chunk
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]:看门狗
"""
watch_dog_patience = 5 # 看门狗的耐心, 设置5秒即可
if inputs == "": inputs = "空空如也的输入栏"
headers, payload = generate_payload(inputs, llm_kwargs, history, system_prompt=sys_prompt, stream=True)
retry = 0
while True:
try:
# make a POST request to the API endpoint, stream=False
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
traceback.print_exc()
if retry > MAX_RETRY: raise TimeoutError
if MAX_RETRY!=0: print(f'请求超时,正在重试 ({retry}/{MAX_RETRY}) ……')
stream_response = response.iter_lines()
result = ''
is_head_of_the_stream = True
while True:
try: chunk = next(stream_response)
except StopIteration:
break
except requests.exceptions.ConnectionError:
chunk = next(stream_response) # 失败了,重试一次?再失败就没办法了。
chunk_decoded, chunkjson, is_last_chunk = decode_chunk(chunk)
if is_head_of_the_stream and (r'"object":"error"' not in chunk_decoded) and (r'"role":"assistant"' in chunk_decoded):
# 数据流的第一帧不携带content
is_head_of_the_stream = False; continue
if chunk:
try:
if is_last_chunk:
# 判定为数据流的结束,gpt_replying_buffer也写完了
logging.info(f'[response] {result}')
break
result += chunkjson['choices'][0]["delta"]["content"]
if not console_slience: print(chunkjson['choices'][0]["delta"]["content"], end='')
if observe_window is not None:
# 观测窗,把已经获取的数据显示出去
if len(observe_window) >= 1:
observe_window[0] += chunkjson['choices'][0]["delta"]["content"]
# 看门狗,如果超过期限没有喂狗,则终止
if len(observe_window) >= 2:
if (time.time()-observe_window[1]) > watch_dog_patience:
raise RuntimeError("用户取消了程序。")
except Exception as e:
chunk = get_full_error(chunk, stream_response)
chunk_decoded = chunk.decode()
error_msg = chunk_decoded
print(error_msg)
raise RuntimeError("Json解析不合常规")
return result
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
"""
if len(YIMODEL_API_KEY) == 0:
raise RuntimeError("没有设置YIMODEL_API_KEY选项")
if inputs == "": inputs = "空空如也的输入栏"
user_input = inputs
if additional_fn is not None:
from core_functional import handle_core_functionality
inputs, history = handle_core_functionality(additional_fn, inputs, history, chatbot)
raw_input = inputs
logging.info(f'[raw_input] {raw_input}')
chatbot.append((inputs, ""))
yield from update_ui(chatbot=chatbot, history=history, msg="等待响应") # 刷新界面
# check mis-behavior
if is_the_upload_folder(user_input):
chatbot[-1] = (inputs, f"[Local Message] 检测到操作错误!当您上传文档之后,需点击“**函数插件区**”按钮进行处理,请勿点击“提交”按钮或者“基础功能区”按钮。")
yield from update_ui(chatbot=chatbot, history=history, msg="正常") # 刷新界面
time.sleep(2)
headers, payload = generate_payload(inputs, llm_kwargs, history, system_prompt, stream)
from .bridge_all import model_info
endpoint = model_info[llm_kwargs['llm_model']]['endpoint']
history.append(inputs); history.append("")
retry = 0
while True:
try:
# make a POST request to the API endpoint, stream=True
response = requests.post(endpoint, headers=headers, proxies=proxies,
json=payload, stream=True, timeout=TIMEOUT_SECONDS);break
except:
retry += 1
chatbot[-1] = ((chatbot[-1][0], timeout_bot_msg))
retry_msg = f",正在重试 ({retry}/{MAX_RETRY}) ……" if MAX_RETRY > 0 else ""
yield from update_ui(chatbot=chatbot, history=history, msg="请求超时"+retry_msg) # 刷新界面
if retry > MAX_RETRY: raise TimeoutError
gpt_replying_buffer = ""
is_head_of_the_stream = True
if stream:
stream_response = response.iter_lines()
while True:
try:
chunk = next(stream_response)
except StopIteration:
break
except requests.exceptions.ConnectionError:
chunk = next(stream_response) # 失败了,重试一次?再失败就没办法了。
# 提前读取一些信息 (用于判断异常)
chunk_decoded, chunkjson, is_last_chunk = decode_chunk(chunk)
if is_head_of_the_stream and (r'"object":"error"' not in chunk_decoded) and (r'"role":"assistant"' in chunk_decoded):
# 数据流的第一帧不携带content
is_head_of_the_stream = False; continue
if chunk:
try:
if is_last_chunk:
# 判定为数据流的结束,gpt_replying_buffer也写完了
logging.info(f'[response] {gpt_replying_buffer}')
break
# 处理数据流的主体
status_text = f"finish_reason: {chunkjson['choices'][0].get('finish_reason', 'null')}"
gpt_replying_buffer = gpt_replying_buffer + chunkjson['choices'][0]["delta"]["content"]
# 如果这里抛出异常,一般是文本过长,详情见get_full_error的输出
history[-1] = gpt_replying_buffer
chatbot[-1] = (history[-2], history[-1])
yield from update_ui(chatbot=chatbot, history=history, msg=status_text) # 刷新界面
except Exception as e:
yield from update_ui(chatbot=chatbot, history=history, msg="Json解析不合常规") # 刷新界面
chunk = get_full_error(chunk, stream_response)
chunk_decoded = chunk.decode()
error_msg = chunk_decoded
chatbot, history = handle_error(inputs, llm_kwargs, chatbot, history, chunk_decoded, error_msg)
yield from update_ui(chatbot=chatbot, history=history, msg="Json异常" + error_msg) # 刷新界面
print(error_msg)
return
def handle_error(inputs, llm_kwargs, chatbot, history, chunk_decoded, error_msg):
from .bridge_all import model_info
if "bad_request" in error_msg:
chatbot[-1] = (chatbot[-1][0], "[Local Message] 已经超过了模型的最大上下文或是模型格式错误,请尝试削减单次输入的文本量。")
elif "authentication_error" in error_msg:
chatbot[-1] = (chatbot[-1][0], "[Local Message] Incorrect API key. 请确保API key有效。")
elif "not_found" in error_msg:
chatbot[-1] = (chatbot[-1][0], f"[Local Message] {llm_kwargs['llm_model']} 无效,请确保使用小写的模型名称。")
elif "rate_limit" in error_msg:
chatbot[-1] = (chatbot[-1][0], "[Local Message] 遇到了控制请求速率限制,请一分钟后重试。")
elif "system_busy" in error_msg:
chatbot[-1] = (chatbot[-1][0], "[Local Message] 系统繁忙,请一分钟后重试。")
else:
from toolbox import regular_txt_to_markdown
tb_str = '```\n' + trimmed_format_exc() + '```'
chatbot[-1] = (chatbot[-1][0], f"[Local Message] 异常 \n\n{tb_str} \n\n{regular_txt_to_markdown(chunk_decoded)}")
return chatbot, history
def generate_payload(inputs, llm_kwargs, history, system_prompt, stream):
"""
整合所有信息,选择LLM模型,生成http请求,为发送请求做准备
"""
api_key = f"Bearer {YIMODEL_API_KEY}"
headers = {
"Content-Type": "application/json",
"Authorization": api_key
}
conversation_cnt = len(history) // 2
messages = [{"role": "system", "content": system_prompt}]
if conversation_cnt:
for index in range(0, 2*conversation_cnt, 2):
what_i_have_asked = {}
what_i_have_asked["role"] = "user"
what_i_have_asked["content"] = history[index]
what_gpt_answer = {}
what_gpt_answer["role"] = "assistant"
what_gpt_answer["content"] = history[index+1]
if what_i_have_asked["content"] != "":
if what_gpt_answer["content"] == "": continue
if what_gpt_answer["content"] == timeout_bot_msg: continue
messages.append(what_i_have_asked)
messages.append(what_gpt_answer)
else:
messages[-1]['content'] = what_gpt_answer['content']
what_i_ask_now = {}
what_i_ask_now["role"] = "user"
what_i_ask_now["content"] = inputs
messages.append(what_i_ask_now)
model = llm_kwargs['llm_model']
if llm_kwargs['llm_model'].startswith('one-api-'):
model = llm_kwargs['llm_model'][len('one-api-'):]
model, _ = read_one_api_model_name(model)
tokens = 600 if llm_kwargs['llm_model'] == 'yi-34b-chat-0205' else 4096 #yi-34b-chat-0205只有4k上下文...
payload = {
"model": model,
"messages": messages,
"temperature": llm_kwargs['temperature'], # 1.0,
"stream": stream,
"max_tokens": tokens
}
try:
print(f" {llm_kwargs['llm_model']} : {conversation_cnt} : {inputs[:100]} ..........")
except:
print('输入中可能存在乱码。')
return headers,payload

查看文件

@@ -1,7 +1,8 @@
import time import time
import os import os
from toolbox import update_ui, get_conf, update_ui_lastest_msg from toolbox import update_ui, get_conf, update_ui_lastest_msg, log_chat
from toolbox import check_packages, report_exception, have_any_recent_upload_image_files from toolbox import check_packages, report_exception, have_any_recent_upload_image_files
from toolbox import ChatBotWithCookies
model_name = '智谱AI大模型' model_name = '智谱AI大模型'
zhipuai_default_model = 'glm-4' zhipuai_default_model = 'glm-4'
@@ -16,7 +17,8 @@ def make_media_input(inputs, image_paths):
inputs = inputs + f'<br/><br/><div align="center"><img src="file={os.path.abspath(image_path)}"></div>' inputs = inputs + f'<br/><br/><div align="center"><img src="file={os.path.abspath(image_path)}"></div>'
return inputs return inputs
def predict_no_ui_long_connection(inputs, llm_kwargs, history=[], sys_prompt="", observe_window=[], console_slience=False): def predict_no_ui_long_connection(inputs:str, llm_kwargs:dict, history:list=[], sys_prompt:str="",
observe_window:list=[], console_slience:bool=False):
""" """
⭐多线程方法 ⭐多线程方法
函数的说明请见 request_llms/bridge_all.py 函数的说明请见 request_llms/bridge_all.py
@@ -42,7 +44,8 @@ def predict_no_ui_long_connection(inputs, llm_kwargs, history=[], sys_prompt="",
return response return response
def predict(inputs, llm_kwargs, plugin_kwargs, chatbot, history=[], system_prompt='', stream=True, additional_fn=None): def predict(inputs:str, llm_kwargs:dict, plugin_kwargs:dict, chatbot:ChatBotWithCookies,
history:list=[], system_prompt:str='', stream:bool=True, additional_fn:str=None):
""" """
⭐单线程方法 ⭐单线程方法
函数的说明请见 request_llms/bridge_all.py 函数的说明请见 request_llms/bridge_all.py
@@ -90,4 +93,5 @@ def predict(inputs, llm_kwargs, plugin_kwargs, chatbot, history=[], system_promp
chatbot[-1] = [inputs, response] chatbot[-1] = [inputs, response]
yield from update_ui(chatbot=chatbot, history=history) yield from update_ui(chatbot=chatbot, history=history)
history.extend([inputs, response]) history.extend([inputs, response])
log_chat(llm_model=llm_kwargs["llm_model"], input_str=inputs, output_str=response)
yield from update_ui(chatbot=chatbot, history=history) yield from update_ui(chatbot=chatbot, history=history)

查看文件

@@ -114,8 +114,10 @@ def html_local_img(__file, layout="left", max_width=None, max_height=None, md=Tr
class GoogleChatInit: class GoogleChatInit:
def __init__(self): def __init__(self, llm_kwargs):
self.url_gemini = "https://generativelanguage.googleapis.com/v1beta/models/%m:streamGenerateContent?key=%k" from .bridge_all import model_info
endpoint = model_info[llm_kwargs['llm_model']]['endpoint']
self.url_gemini = endpoint + "/%m:streamGenerateContent?key=%k"
def generate_chat(self, inputs, llm_kwargs, history, system_prompt): def generate_chat(self, inputs, llm_kwargs, history, system_prompt):
headers, payload = self.generate_message_payload( headers, payload = self.generate_message_payload(

查看文件

@@ -48,6 +48,10 @@ class QwenRequestInstance():
for response in responses: for response in responses:
if response.status_code == HTTPStatus.OK: if response.status_code == HTTPStatus.OK:
if response.output.choices[0].finish_reason == 'stop': if response.output.choices[0].finish_reason == 'stop':
try:
self.result_buf += response.output.choices[0].message.content
except:
pass
yield self.result_buf yield self.result_buf
break break
elif response.output.choices[0].finish_reason == 'length': elif response.output.choices[0].finish_reason == 'length':

查看文件

@@ -8,7 +8,7 @@ from toolbox import get_conf, encode_image, get_pictures_list
import logging, os import logging, os
def input_encode_handler(inputs, llm_kwargs): def input_encode_handler(inputs:str, llm_kwargs:dict):
if llm_kwargs["most_recent_uploaded"].get("path"): if llm_kwargs["most_recent_uploaded"].get("path"):
image_paths = get_pictures_list(llm_kwargs["most_recent_uploaded"]["path"]) image_paths = get_pictures_list(llm_kwargs["most_recent_uploaded"]["path"])
md_encode = [] md_encode = []
@@ -28,7 +28,7 @@ class ZhipuChatInit:
self.zhipu_bro = ZhipuAI(api_key=ZHIPUAI_API_KEY) self.zhipu_bro = ZhipuAI(api_key=ZHIPUAI_API_KEY)
self.model = '' self.model = ''
def __conversation_user(self, user_input: str, llm_kwargs): def __conversation_user(self, user_input: str, llm_kwargs:dict):
if self.model not in ["glm-4v"]: if self.model not in ["glm-4v"]:
return {"role": "user", "content": user_input} return {"role": "user", "content": user_input}
else: else:
@@ -41,7 +41,7 @@ class ZhipuChatInit:
what_i_have_asked['content'].append(img_d) what_i_have_asked['content'].append(img_d)
return what_i_have_asked return what_i_have_asked
def __conversation_history(self, history, llm_kwargs): def __conversation_history(self, history:list, llm_kwargs:dict):
messages = [] messages = []
conversation_cnt = len(history) // 2 conversation_cnt = len(history) // 2
if conversation_cnt: if conversation_cnt:
@@ -55,22 +55,67 @@ class ZhipuChatInit:
messages.append(what_gpt_answer) messages.append(what_gpt_answer)
return messages return messages
def __conversation_message_payload(self, inputs, llm_kwargs, history, system_prompt): @staticmethod
def preprocess_param(param, default=0.95, min_val=0.01, max_val=0.99):
"""预处理参数,保证其在允许范围内,并处理精度问题"""
try:
param = float(param)
except ValueError:
return default
if param <= min_val:
return min_val
elif param >= max_val:
return max_val
else:
return round(param, 2) # 可挑选精度,目前是两位小数
def __conversation_message_payload(self, inputs:str, llm_kwargs:dict, history:list, system_prompt:str):
messages = [] messages = []
if system_prompt: if system_prompt:
messages.append({"role": "system", "content": system_prompt}) messages.append({"role": "system", "content": system_prompt})
self.model = llm_kwargs['llm_model'] self.model = llm_kwargs['llm_model']
messages.extend(self.__conversation_history(history, llm_kwargs)) # 处理 history messages.extend(self.__conversation_history(history, llm_kwargs)) # 处理 history
if inputs.strip() == "": # 处理空输入导致报错的问题 https://github.com/binary-husky/gpt_academic/issues/1640 提示 {"error":{"code":"1214","message":"messages[1]:content和tool_calls 字段不能同时为空"}
inputs = "." # 空格、换行、空字符串都会报错,所以用最没有意义的一个点代替
messages.append(self.__conversation_user(inputs, llm_kwargs)) # 处理用户对话 messages.append(self.__conversation_user(inputs, llm_kwargs)) # 处理用户对话
"""
采样温度,控制输出的随机性,必须为正数
取值范围是:(0.0, 1.0),不能等于 0,默认值为 0.95,
值越大,会使输出更随机,更具创造性;
值越小,输出会更加稳定或确定
建议您根据应用场景调整 top_p 或 temperature 参数,但不要同时调整两个参数
"""
temperature = self.preprocess_param(
param=llm_kwargs.get('temperature', 0.95),
default=0.95,
min_val=0.01,
max_val=0.99
)
"""
用温度取样的另一种方法,称为核取样
取值范围是:(0.0, 1.0) 开区间,
不能等于 0 或 1,默认值为 0.7
模型考虑具有 top_p 概率质量 tokens 的结果
例如0.1 意味着模型解码器只考虑从前 10% 的概率的候选集中取 tokens
建议您根据应用场景调整 top_p 或 temperature 参数,
但不要同时调整两个参数
"""
top_p = self.preprocess_param(
param=llm_kwargs.get('top_p', 0.70),
default=0.70,
min_val=0.01,
max_val=0.99
)
response = self.zhipu_bro.chat.completions.create( response = self.zhipu_bro.chat.completions.create(
model=self.model, messages=messages, stream=True, model=self.model, messages=messages, stream=True,
temperature=llm_kwargs.get('temperature', 0.95) * 0.95, # 只能传默认的 temperature 和 top_p temperature=temperature,
top_p=llm_kwargs.get('top_p', 0.7) * 0.7, top_p=top_p,
max_tokens=llm_kwargs.get('max_tokens', 1024 * 4), # 最大输出模型的一半 max_tokens=llm_kwargs.get('max_tokens', 1024 * 4),
) )
return response return response
def generate_chat(self, inputs, llm_kwargs, history, system_prompt): def generate_chat(self, inputs:str, llm_kwargs:dict, history:list, system_prompt:str):
self.model = llm_kwargs['llm_model'] self.model = llm_kwargs['llm_model']
response = self.__conversation_message_payload(inputs, llm_kwargs, history, system_prompt) response = self.__conversation_message_payload(inputs, llm_kwargs, history, system_prompt)
bro_results = '' bro_results = ''

查看文件

@@ -1,6 +1,7 @@
import time import time
import threading import threading
from toolbox import update_ui, Singleton from toolbox import update_ui, Singleton
from toolbox import ChatBotWithCookies
from multiprocessing import Process, Pipe from multiprocessing import Process, Pipe
from contextlib import redirect_stdout from contextlib import redirect_stdout
from request_llms.queued_pipe import create_queue_pipe from request_llms.queued_pipe import create_queue_pipe
@@ -214,7 +215,7 @@ class LocalLLMHandle(Process):
def get_local_llm_predict_fns(LLMSingletonClass, model_name, history_format='classic'): def get_local_llm_predict_fns(LLMSingletonClass, model_name, history_format='classic'):
load_message = f"{model_name}尚未加载,加载需要一段时间。注意,取决于`config.py`的配置,{model_name}消耗大量的内存CPU或显存GPU,也许会导致低配计算机卡死 ……" load_message = f"{model_name}尚未加载,加载需要一段时间。注意,取决于`config.py`的配置,{model_name}消耗大量的内存CPU或显存GPU,也许会导致低配计算机卡死 ……"
def predict_no_ui_long_connection(inputs, llm_kwargs, history=[], sys_prompt="", observe_window=[], console_slience=False): def predict_no_ui_long_connection(inputs:str, llm_kwargs:dict, history:list=[], sys_prompt:str="", observe_window:list=[], console_slience:bool=False):
""" """
refer to request_llms/bridge_all.py refer to request_llms/bridge_all.py
""" """
@@ -260,7 +261,8 @@ def get_local_llm_predict_fns(LLMSingletonClass, model_name, history_format='cla
raise RuntimeError("程序终止。") raise RuntimeError("程序终止。")
return response return response
def predict(inputs, llm_kwargs, plugin_kwargs, chatbot, history=[], system_prompt='', stream=True, additional_fn=None): def predict(inputs:str, llm_kwargs:dict, plugin_kwargs:dict, chatbot:ChatBotWithCookies,
history:list=[], system_prompt:str='', stream:bool=True, additional_fn:str=None):
""" """
refer to request_llms/bridge_all.py refer to request_llms/bridge_all.py
""" """

查看文件

@@ -1,4 +1,4 @@
https://public.agent-matrix.com/publish/gradio-3.32.8-py3-none-any.whl https://public.agent-matrix.com/publish/gradio-3.32.9-py3-none-any.whl
gradio-client==0.8 gradio-client==0.8
pypdf2==2.12.1 pypdf2==2.12.1
zhipuai>=2 zhipuai>=2
@@ -8,6 +8,7 @@ pydantic==2.5.2
protobuf==3.18 protobuf==3.18
transformers>=4.27.1 transformers>=4.27.1
scipdf_parser>=0.52 scipdf_parser>=0.52
anthropic>=0.18.1
python-markdown-math python-markdown-math
pymdown-extensions pymdown-extensions
websocket-client websocket-client
@@ -16,7 +17,7 @@ prompt_toolkit
latex2mathml latex2mathml
python-docx python-docx
mdtex2html mdtex2html
anthropic dashscope
pyautogen pyautogen
colorama colorama
Markdown Markdown

查看文件

@@ -0,0 +1,61 @@
from typing import Callable
def load_web_cookie_cache__fn_builder(customize_btns, cookies, predefined_btns)->Callable:
def load_web_cookie_cache(persistent_cookie_, cookies_):
import gradio as gr
from themes.theme import load_dynamic_theme, to_cookie_str, from_cookie_str, assign_user_uuid
ret = {}
for k in customize_btns:
ret.update({customize_btns[k]: gr.update(visible=False, value="")})
try: persistent_cookie_ = from_cookie_str(persistent_cookie_) # persistent cookie to dict
except: return ret
customize_fn_overwrite_ = persistent_cookie_.get("custom_bnt", {})
cookies_['customize_fn_overwrite'] = customize_fn_overwrite_
ret.update({cookies: cookies_})
for k,v in persistent_cookie_["custom_bnt"].items():
if v['Title'] == "": continue
if k in customize_btns: ret.update({customize_btns[k]: gr.update(visible=True, value=v['Title'])})
else: ret.update({predefined_btns[k]: gr.update(visible=True, value=v['Title'])})
return ret
return load_web_cookie_cache
def assign_btn__fn_builder(customize_btns, predefined_btns, cookies, web_cookie_cache)->Callable:
def assign_btn(persistent_cookie_, cookies_, basic_btn_dropdown_, basic_fn_title, basic_fn_prefix, basic_fn_suffix, clean_up=False):
import gradio as gr
from themes.theme import load_dynamic_theme, to_cookie_str, from_cookie_str, assign_user_uuid
ret = {}
# 读取之前的自定义按钮
customize_fn_overwrite_ = cookies_['customize_fn_overwrite']
# 更新新的自定义按钮
customize_fn_overwrite_.update({
basic_btn_dropdown_:
{
"Title":basic_fn_title,
"Prefix":basic_fn_prefix,
"Suffix":basic_fn_suffix,
}
}
)
if clean_up:
customize_fn_overwrite_ = {}
cookies_.update(customize_fn_overwrite_) # 更新cookie
visible = (not clean_up) and (basic_fn_title != "")
if basic_btn_dropdown_ in customize_btns:
# 是自定义按钮,不是预定义按钮
ret.update({customize_btns[basic_btn_dropdown_]: gr.update(visible=visible, value=basic_fn_title)})
else:
# 是预定义按钮
ret.update({predefined_btns[basic_btn_dropdown_]: gr.update(visible=visible, value=basic_fn_title)})
ret.update({cookies: cookies_})
try: persistent_cookie_ = from_cookie_str(persistent_cookie_) # persistent cookie to dict
except: persistent_cookie_ = {}
persistent_cookie_["custom_bnt"] = customize_fn_overwrite_ # dict update new value
persistent_cookie_ = to_cookie_str(persistent_cookie_) # persistent cookie to dict
ret.update({web_cookie_cache: persistent_cookie_}) # write persistent cookie
return ret
return assign_btn

查看文件

@@ -0,0 +1,211 @@
"""
Tests:
- custom_path false / no user auth:
-- upload file(yes)
-- download file(yes)
-- websocket(yes)
-- block __pycache__ access(yes)
-- rel (yes)
-- abs (yes)
-- block user access(fail) http://localhost:45013/file=gpt_log/admin/chat_secrets.log
-- fix(commit f6bf05048c08f5cd84593f7fdc01e64dec1f584a)-> block successful
- custom_path yes("/cc/gptac") / no user auth:
-- upload file(yes)
-- download file(yes)
-- websocket(yes)
-- block __pycache__ access(yes)
-- block user access(yes)
- custom_path yes("/cc/gptac/") / no user auth:
-- upload file(yes)
-- download file(yes)
-- websocket(yes)
-- block user access(yes)
- custom_path yes("/cc/gptac/") / + user auth:
-- upload file(yes)
-- download file(yes)
-- websocket(yes)
-- block user access(yes)
-- block user-wise access (yes)
- custom_path no + user auth:
-- upload file(yes)
-- download file(yes)
-- websocket(yes)
-- block user access(yes)
-- block user-wise access (yes)
queue cocurrent effectiveness
-- upload file(yes)
-- download file(yes)
-- websocket(yes)
"""
import os, requests, threading, time
import uvicorn
def _authorize_user(path_or_url, request, gradio_app):
from toolbox import get_conf, default_user_name
PATH_PRIVATE_UPLOAD, PATH_LOGGING = get_conf('PATH_PRIVATE_UPLOAD', 'PATH_LOGGING')
sensitive_path = None
path_or_url = os.path.relpath(path_or_url)
if path_or_url.startswith(PATH_LOGGING):
sensitive_path = PATH_LOGGING
if path_or_url.startswith(PATH_PRIVATE_UPLOAD):
sensitive_path = PATH_PRIVATE_UPLOAD
if sensitive_path:
token = request.cookies.get("access-token") or request.cookies.get("access-token-unsecure")
user = gradio_app.tokens.get(token) # get user
allowed_users = [user, 'autogen', default_user_name] # three user path that can be accessed
for user_allowed in allowed_users:
# exact match
if f"{os.sep}".join(path_or_url.split(os.sep)[:2]) == os.path.join(sensitive_path, user_allowed):
return True
return False # "越权访问!"
return True
class Server(uvicorn.Server):
# A server that runs in a separate thread
def install_signal_handlers(self):
pass
def run_in_thread(self):
self.thread = threading.Thread(target=self.run, daemon=True)
self.thread.start()
while not self.started:
time.sleep(1e-3)
def close(self):
self.should_exit = True
self.thread.join()
def start_app(app_block, CONCURRENT_COUNT, AUTHENTICATION, PORT, SSL_KEYFILE, SSL_CERTFILE):
import uvicorn
import fastapi
import gradio as gr
from fastapi import FastAPI
from gradio.routes import App
from toolbox import get_conf
CUSTOM_PATH, PATH_LOGGING = get_conf('CUSTOM_PATH', 'PATH_LOGGING')
# --- --- configurate gradio app block --- ---
app_block:gr.Blocks
app_block.ssl_verify = False
app_block.auth_message = '请登录'
app_block.favicon_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), "docs/logo.png")
app_block.auth = AUTHENTICATION if len(AUTHENTICATION) != 0 else None
app_block.blocked_paths = ["config.py", "__pycache__", "config_private.py", "docker-compose.yml", "Dockerfile", f"{PATH_LOGGING}/admin"]
app_block.dev_mode = False
app_block.config = app_block.get_config_file()
app_block.enable_queue = True
app_block.queue(concurrency_count=CONCURRENT_COUNT)
app_block.validate_queue_settings()
app_block.show_api = False
app_block.config = app_block.get_config_file()
max_threads = 40
app_block.max_threads = max(
app_block._queue.max_thread_count if app_block.enable_queue else 0, max_threads
)
app_block.is_colab = False
app_block.is_kaggle = False
app_block.is_sagemaker = False
gradio_app = App.create_app(app_block)
# --- --- replace gradio endpoint to forbid access to sensitive files --- ---
if len(AUTHENTICATION) > 0:
dependencies = []
endpoint = None
for route in list(gradio_app.router.routes):
if route.path == "/file/{path:path}":
gradio_app.router.routes.remove(route)
if route.path == "/file={path_or_url:path}":
dependencies = route.dependencies
endpoint = route.endpoint
gradio_app.router.routes.remove(route)
@gradio_app.get("/file/{path:path}", dependencies=dependencies)
@gradio_app.head("/file={path_or_url:path}", dependencies=dependencies)
@gradio_app.get("/file={path_or_url:path}", dependencies=dependencies)
async def file(path_or_url: str, request: fastapi.Request):
if len(AUTHENTICATION) > 0:
if not _authorize_user(path_or_url, request, gradio_app):
return "越权访问!"
return await endpoint(path_or_url, request)
# --- --- app_lifespan --- ---
from contextlib import asynccontextmanager
@asynccontextmanager
async def app_lifespan(app):
async def startup_gradio_app():
if gradio_app.get_blocks().enable_queue:
gradio_app.get_blocks().startup_events()
async def shutdown_gradio_app():
pass
await startup_gradio_app() # startup logic here
yield # The application will serve requests after this point
await shutdown_gradio_app() # cleanup/shutdown logic here
# --- --- FastAPI --- ---
fastapi_app = FastAPI(lifespan=app_lifespan)
fastapi_app.mount(CUSTOM_PATH, gradio_app)
# --- --- favicon --- ---
if CUSTOM_PATH != '/':
from fastapi.responses import FileResponse
@fastapi_app.get("/favicon.ico")
async def favicon():
return FileResponse(app_block.favicon_path)
# --- --- uvicorn.Config --- ---
ssl_keyfile = None if SSL_KEYFILE == "" else SSL_KEYFILE
ssl_certfile = None if SSL_CERTFILE == "" else SSL_CERTFILE
server_name = "0.0.0.0"
config = uvicorn.Config(
fastapi_app,
host=server_name,
port=PORT,
reload=False,
log_level="warning",
ssl_keyfile=ssl_keyfile,
ssl_certfile=ssl_certfile,
)
server = Server(config)
url_host_name = "localhost" if server_name == "0.0.0.0" else server_name
if ssl_keyfile is not None:
if ssl_certfile is None:
raise ValueError(
"ssl_certfile must be provided if ssl_keyfile is provided."
)
path_to_local_server = f"https://{url_host_name}:{PORT}/"
else:
path_to_local_server = f"http://{url_host_name}:{PORT}/"
if CUSTOM_PATH != '/':
path_to_local_server += CUSTOM_PATH.lstrip('/').rstrip('/') + '/'
# --- --- begin --- ---
server.run_in_thread()
# --- --- after server launch --- ---
app_block.server = server
app_block.server_name = server_name
app_block.local_url = path_to_local_server
app_block.protocol = (
"https"
if app_block.local_url.startswith("https") or app_block.is_colab
else "http"
)
if app_block.enable_queue:
app_block._queue.set_url(path_to_local_server)
forbid_proxies = {
"http": "",
"https": "",
}
requests.get(f"{app_block.local_url}startup-events", verify=app_block.ssl_verify, proxies=forbid_proxies)
app_block.is_running = True
app_block.block_thread()

查看文件

@@ -28,6 +28,11 @@ def is_api2d_key(key):
return bool(API_MATCH_API2D) return bool(API_MATCH_API2D)
def is_cohere_api_key(key):
API_MATCH_AZURE = re.match(r"[a-zA-Z0-9]{40}$", key)
return bool(API_MATCH_AZURE)
def is_any_api_key(key): def is_any_api_key(key):
if ',' in key: if ',' in key:
keys = key.split(',') keys = key.split(',')
@@ -35,7 +40,7 @@ def is_any_api_key(key):
if is_any_api_key(k): return True if is_any_api_key(k): return True
return False return False
else: else:
return is_openai_api_key(key) or is_api2d_key(key) or is_azure_api_key(key) return is_openai_api_key(key) or is_api2d_key(key) or is_azure_api_key(key) or is_cohere_api_key(key)
def what_keys(keys): def what_keys(keys):
@@ -62,7 +67,7 @@ def select_api_key(keys, llm_model):
avail_key_list = [] avail_key_list = []
key_list = keys.split(',') key_list = keys.split(',')
if llm_model.startswith('gpt-'): if llm_model.startswith('gpt-') or llm_model.startswith('one-api-'):
for k in key_list: for k in key_list:
if is_openai_api_key(k): avail_key_list.append(k) if is_openai_api_key(k): avail_key_list.append(k)
@@ -74,8 +79,12 @@ def select_api_key(keys, llm_model):
for k in key_list: for k in key_list:
if is_azure_api_key(k): avail_key_list.append(k) if is_azure_api_key(k): avail_key_list.append(k)
if llm_model.startswith('cohere-'):
for k in key_list:
if is_cohere_api_key(k): avail_key_list.append(k)
if len(avail_key_list) == 0: if len(avail_key_list) == 0:
raise RuntimeError(f"您提供的api-key不满足要求,不包含任何可用于{llm_model}的api-key。您可能选择了错误的模型或请求源右下角更换模型菜单中可切换openai,azure,claude,api2d等请求源)。") raise RuntimeError(f"您提供的api-key不满足要求,不包含任何可用于{llm_model}的api-key。您可能选择了错误的模型或请求源左上角更换模型菜单中可切换openai,azure,claude,cohere等请求源)。")
api_key = random.choice(avail_key_list) # 随机负载均衡 api_key = random.choice(avail_key_list) # 随机负载均衡
return api_key return api_key

34
shared_utils/map_names.py 普通文件
查看文件

@@ -0,0 +1,34 @@
import re
mapping_dic = {
# "qianfan": "qianfan文心一言大模型",
# "zhipuai": "zhipuai智谱GLM4超级模型🔥",
# "gpt-4-1106-preview": "gpt-4-1106-preview新调优版本GPT-4🔥",
# "gpt-4-vision-preview": "gpt-4-vision-preview识图模型GPT-4V",
}
rev_mapping_dic = {}
for k, v in mapping_dic.items():
rev_mapping_dic[v] = k
def map_model_to_friendly_names(m):
if m in mapping_dic:
return mapping_dic[m]
return m
def map_friendly_names_to_model(m):
if m in rev_mapping_dic:
return rev_mapping_dic[m]
return m
def read_one_api_model_name(model: str):
"""return real model name and max_token.
"""
max_token_pattern = r"\(max_token=(\d+)\)"
match = re.search(max_token_pattern, model)
if match:
max_token_tmp = match.group(1) # 获取 max_token 的值
max_token_tmp = int(max_token_tmp)
model = re.sub(max_token_pattern, "", model) # 从原字符串中删除 "(max_token=...)"
else:
max_token_tmp = 4096
return model, max_token_tmp

查看文件

@@ -11,28 +11,45 @@ def validate_path():
validate_path() # validate path so you can run from base directory validate_path() # validate path so you can run from base directory
if __name__ == "__main__":
# from request_llms.bridge_newbingfree import predict_no_ui_long_connection
# from request_llms.bridge_moss import predict_no_ui_long_connection
# from request_llms.bridge_jittorllms_pangualpha import predict_no_ui_long_connection
# from request_llms.bridge_jittorllms_llama import predict_no_ui_long_connection
# from request_llms.bridge_claude import predict_no_ui_long_connection
# from request_llms.bridge_internlm import predict_no_ui_long_connection
# from request_llms.bridge_deepseekcoder import predict_no_ui_long_connection
# from request_llms.bridge_qwen_7B import predict_no_ui_long_connection
from request_llms.bridge_qwen_local import predict_no_ui_long_connection
# from request_llms.bridge_spark import predict_no_ui_long_connection if "在线模型":
# from request_llms.bridge_zhipu import predict_no_ui_long_connection if __name__ == "__main__":
# from request_llms.bridge_chatglm3 import predict_no_ui_long_connection from request_llms.bridge_cohere import predict_no_ui_long_connection
# from request_llms.bridge_spark import predict_no_ui_long_connection
# from request_llms.bridge_zhipu import predict_no_ui_long_connection
# from request_llms.bridge_chatglm3 import predict_no_ui_long_connection
llm_kwargs = {
"llm_model": "command-r-plus",
"max_length": 4096,
"top_p": 1,
"temperature": 1,
}
llm_kwargs = { result = predict_no_ui_long_connection(
"max_length": 4096, inputs="请问什么是质子?", llm_kwargs=llm_kwargs, history=["你好", "我好!"], sys_prompt="系统"
"top_p": 1, )
"temperature": 1, print("final result:", result)
} print("final result:", result)
if "本地模型":
if __name__ == "__main__":
# from request_llms.bridge_newbingfree import predict_no_ui_long_connection
# from request_llms.bridge_moss import predict_no_ui_long_connection
# from request_llms.bridge_jittorllms_pangualpha import predict_no_ui_long_connection
# from request_llms.bridge_jittorllms_llama import predict_no_ui_long_connection
# from request_llms.bridge_claude import predict_no_ui_long_connection
# from request_llms.bridge_internlm import predict_no_ui_long_connection
# from request_llms.bridge_deepseekcoder import predict_no_ui_long_connection
# from request_llms.bridge_qwen_7B import predict_no_ui_long_connection
# from request_llms.bridge_qwen_local import predict_no_ui_long_connection
llm_kwargs = {
"max_length": 4096,
"top_p": 1,
"temperature": 1,
}
result = predict_no_ui_long_connection(
inputs="请问什么是质子?", llm_kwargs=llm_kwargs, history=["你好", "我好!"], sys_prompt=""
)
print("final result:", result)
result = predict_no_ui_long_connection(
inputs="请问什么是质子?", llm_kwargs=llm_kwargs, history=["你好", "我好!"], sys_prompt=""
)
print("final result:", result)

查看文件

@@ -2,6 +2,76 @@
// 第 1 部分: 工具函数 // 第 1 部分: 工具函数
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
function push_data_to_gradio_component(DAT, ELEM_ID, TYPE) {
// type, // type==="str" / type==="float"
if (TYPE == "str") {
// convert dat to string: do nothing
}
else if (TYPE == "no_conversion") {
// no nothing
}
else if (TYPE == "float") {
// convert dat to float
DAT = parseFloat(DAT);
}
const myEvent = new CustomEvent('gpt_academic_update_gradio_component', {
detail: {
data: DAT,
elem_id: ELEM_ID,
}
});
window.dispatchEvent(myEvent);
}
async function get_gradio_component(ELEM_ID) {
function waitFor(ELEM_ID) {
return new Promise((resolve) => {
const myEvent = new CustomEvent('gpt_academic_get_gradio_component_value', {
detail: {
elem_id: ELEM_ID,
resolve,
}
});
window.dispatchEvent(myEvent);
});
}
result = await waitFor(ELEM_ID);
return result;
}
async function get_data_from_gradio_component(ELEM_ID) {
let comp = await get_gradio_component(ELEM_ID);
return comp.props.value;
}
function update_array(arr, item, mode) {
// // Remove "输入清除键"
// p = updateArray(p, "输入清除键", "remove");
// console.log(p); // Should log: ["基础功能区", "函数插件区"]
// // Add "输入清除键"
// p = updateArray(p, "输入清除键", "add");
// console.log(p); // Should log: ["基础功能区", "函数插件区", "输入清除键"]
const index = arr.indexOf(item);
if (mode === "remove") {
if (index !== -1) {
// Item found, remove it
arr.splice(index, 1);
}
} else if (mode === "add") {
if (index === -1) {
// Item not found, add it
arr.push(item);
}
}
return arr;
}
function gradioApp() { function gradioApp() {
// https://github.com/GaiZhenbiao/ChuanhuChatGPT/tree/main/web_assets/javascript // https://github.com/GaiZhenbiao/ChuanhuChatGPT/tree/main/web_assets/javascript
const elems = document.getElementsByTagName('gradio-app'); const elems = document.getElementsByTagName('gradio-app');
@@ -14,6 +84,7 @@ function gradioApp() {
return elem.shadowRoot ? elem.shadowRoot : elem; return elem.shadowRoot ? elem.shadowRoot : elem;
} }
function setCookie(name, value, days) { function setCookie(name, value, days) {
var expires = ""; var expires = "";
@@ -26,6 +97,7 @@ function setCookie(name, value, days) {
document.cookie = name + "=" + value + expires + "; path=/"; document.cookie = name + "=" + value + expires + "; path=/";
} }
function getCookie(name) { function getCookie(name) {
var decodedCookie = decodeURIComponent(document.cookie); var decodedCookie = decodeURIComponent(document.cookie);
var cookies = decodedCookie.split(';'); var cookies = decodedCookie.split(';');
@@ -41,6 +113,7 @@ function getCookie(name) {
return null; return null;
} }
let toastCount = 0; let toastCount = 0;
function toast_push(msg, duration) { function toast_push(msg, duration) {
duration = isNaN(duration) ? 3000 : duration; duration = isNaN(duration) ? 3000 : duration;
@@ -63,6 +136,7 @@ function toast_push(msg, duration) {
toastCount++; toastCount++;
} }
function toast_up(msg) { function toast_up(msg) {
var m = document.getElementById('toast_up'); var m = document.getElementById('toast_up');
if (m) { if (m) {
@@ -75,6 +149,7 @@ function toast_up(msg) {
document.body.appendChild(m); document.body.appendChild(m);
} }
function toast_down() { function toast_down() {
var m = document.getElementById('toast_up'); var m = document.getElementById('toast_up');
if (m) { if (m) {
@@ -82,6 +157,7 @@ function toast_down() {
} }
} }
function begin_loading_status() { function begin_loading_status() {
// Create the loader div and add styling // Create the loader div and add styling
var loader = document.createElement('div'); var loader = document.createElement('div');
@@ -256,6 +332,7 @@ function do_something_but_not_too_frequently(min_interval, func) {
} }
} }
function chatbotContentChanged(attempt = 1, force = false) { function chatbotContentChanged(attempt = 1, force = false) {
// https://github.com/GaiZhenbiao/ChuanhuChatGPT/tree/main/web_assets/javascript // https://github.com/GaiZhenbiao/ChuanhuChatGPT/tree/main/web_assets/javascript
for (var i = 0; i < attempt; i++) { for (var i = 0; i < attempt; i++) {
@@ -272,7 +349,6 @@ function chatbotContentChanged(attempt = 1, force = false) {
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// 第 3 部分: chatbot动态高度调整 // 第 3 部分: chatbot动态高度调整
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
function chatbotAutoHeight() { function chatbotAutoHeight() {
// 自动调整高度:立即 // 自动调整高度:立即
function update_height() { function update_height() {
@@ -304,6 +380,7 @@ function chatbotAutoHeight() {
setInterval(function () { update_height_slow() }, 50); // 每50毫秒执行一次 setInterval(function () { update_height_slow() }, 50); // 每50毫秒执行一次
} }
swapped = false; swapped = false;
function swap_input_area() { function swap_input_area() {
// Get the elements to be swapped // Get the elements to be swapped
@@ -323,6 +400,7 @@ function swap_input_area() {
else { swapped = true; } else { swapped = true; }
} }
function get_elements(consider_state_panel = false) { function get_elements(consider_state_panel = false) {
var chatbot = document.querySelector('#gpt-chatbot > div.wrap.svelte-18telvq'); var chatbot = document.querySelector('#gpt-chatbot > div.wrap.svelte-18telvq');
if (!chatbot) { if (!chatbot) {
@@ -420,6 +498,7 @@ async function upload_files(files) {
} }
} }
function register_func_paste(input) { function register_func_paste(input) {
let paste_files = []; let paste_files = [];
if (input) { if (input) {
@@ -446,6 +525,7 @@ function register_func_paste(input) {
} }
} }
function register_func_drag(elem) { function register_func_drag(elem) {
if (elem) { if (elem) {
const dragEvents = ["dragover"]; const dragEvents = ["dragover"];
@@ -482,6 +562,7 @@ function register_func_drag(elem) {
} }
} }
function elem_upload_component_pop_message(elem) { function elem_upload_component_pop_message(elem) {
if (elem) { if (elem) {
const dragEvents = ["dragover"]; const dragEvents = ["dragover"];
@@ -511,6 +592,7 @@ function elem_upload_component_pop_message(elem) {
} }
} }
function register_upload_event() { function register_upload_event() {
locate_upload_elems(); locate_upload_elems();
if (elem_upload_float) { if (elem_upload_float) {
@@ -533,6 +615,7 @@ function register_upload_event() {
} }
} }
function monitoring_input_box() { function monitoring_input_box() {
register_upload_event(); register_upload_event();
@@ -566,7 +649,6 @@ window.addEventListener("DOMContentLoaded", function () {
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// 第 5 部分: 音频按钮样式变化 // 第 5 部分: 音频按钮样式变化
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
function audio_fn_init() { function audio_fn_init() {
let audio_component = document.getElementById('elem_audio'); let audio_component = document.getElementById('elem_audio');
if (audio_component) { if (audio_component) {
@@ -603,6 +685,7 @@ function audio_fn_init() {
} }
} }
function minor_ui_adjustment() { function minor_ui_adjustment() {
let cbsc_area = document.getElementById('cbsc'); let cbsc_area = document.getElementById('cbsc');
cbsc_area.style.paddingTop = '15px'; cbsc_area.style.paddingTop = '15px';
@@ -695,21 +778,6 @@ function limit_scroll_position() {
// 第 7 部分: JS初始化函数 // 第 7 部分: JS初始化函数
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
function GptAcademicJavaScriptInit(LAYOUT = "LEFT-RIGHT") {
audio_fn_init();
minor_ui_adjustment();
chatbotIndicator = gradioApp().querySelector('#gpt-chatbot > div.wrap');
var chatbotObserver = new MutationObserver(() => {
chatbotContentChanged(1);
});
chatbotObserver.observe(chatbotIndicator, { attributes: true, childList: true, subtree: true });
if (LAYOUT === "LEFT-RIGHT") { chatbotAutoHeight(); }
if (LAYOUT === "LEFT-RIGHT") { limit_scroll_position(); }
// setInterval(function () { uml("mermaid") }, 5000); // 每50毫秒执行一次
}
function loadLive2D() { function loadLive2D() {
try { try {
$("<link>").attr({ href: "file=themes/waifu_plugin/waifu.css", rel: "stylesheet", type: "text/css" }).appendTo('head'); $("<link>").attr({ href: "file=themes/waifu_plugin/waifu.css", rel: "stylesheet", type: "text/css" }).appendTo('head');
@@ -731,12 +799,12 @@ function loadLive2D() {
live2d_settings['canTakeScreenshot'] = false; live2d_settings['canTakeScreenshot'] = false;
live2d_settings['canTurnToHomePage'] = false; live2d_settings['canTurnToHomePage'] = false;
live2d_settings['canTurnToAboutPage'] = false; live2d_settings['canTurnToAboutPage'] = false;
live2d_settings['showHitokoto'] = false; // 显示一言 live2d_settings['showHitokoto'] = false; // 显示一言
live2d_settings['showF12Status'] = false; // 显示加载状态 live2d_settings['showF12Status'] = false; // 显示加载状态
live2d_settings['showF12Message'] = false; // 显示看板娘消息 live2d_settings['showF12Message'] = false; // 显示看板娘消息
live2d_settings['showF12OpenMsg'] = false; // 显示控制台打开提示 live2d_settings['showF12OpenMsg'] = false; // 显示控制台打开提示
live2d_settings['showCopyMessage'] = false; // 显示 复制内容 提示 live2d_settings['showCopyMessage'] = false; // 显示 复制内容 提示
live2d_settings['showWelcomeMessage'] = true; // 显示进入面页欢迎词 live2d_settings['showWelcomeMessage'] = true; // 显示进入面页欢迎词
/* 在 initModel 前添加 */ /* 在 initModel 前添加 */
initModel("file=themes/waifu_plugin/waifu-tips.json"); initModel("file=themes/waifu_plugin/waifu-tips.json");
} }
@@ -746,7 +814,8 @@ function loadLive2D() {
} catch (err) { console.log("[Error] JQuery is not defined.") } } catch (err) { console.log("[Error] JQuery is not defined.") }
} }
function get_checkbox_selected_items(elem_id){
function get_checkbox_selected_items(elem_id) {
display_panel_arr = []; display_panel_arr = [];
document.getElementById(elem_id).querySelector('[data-testid="checkbox-group"]').querySelectorAll('label').forEach(label => { document.getElementById(elem_id).querySelector('[data-testid="checkbox-group"]').querySelectorAll('label').forEach(label => {
// Get the span text // Get the span text
@@ -760,51 +829,52 @@ function get_checkbox_selected_items(elem_id){
return display_panel_arr; return display_panel_arr;
} }
function set_checkbox(key, bool, set_twice=false) {
set_success = false;
elem_ids = ["cbsc", "cbs"]
elem_ids.forEach(id => {
document.getElementById(id).querySelector('[data-testid="checkbox-group"]').querySelectorAll('label').forEach(label => {
// Get the span text
const spanText = label.querySelector('span').textContent;
if (spanText === key) {
if (bool){
label.classList.add('selected');
} else {
if (label.classList.contains('selected')) {
label.classList.remove('selected');
}
}
if (set_twice){
setTimeout(() => {
if (bool){
label.classList.add('selected');
} else {
if (label.classList.contains('selected')) {
label.classList.remove('selected');
}
}
}, 5000);
}
label.querySelector('input').checked = bool; function gpt_academic_gradio_saveload(
set_success = true; save_or_load, // save_or_load==="save" / save_or_load==="load"
return elem_id, // element id
cookie_key, // cookie key
save_value = "", // save value
load_type = "str", // type==="str" / type==="float"
load_default = false, // load default value
load_default_value = ""
) {
if (save_or_load === "load") {
let value = getCookie(cookie_key);
if (value) {
console.log('加载cookie', elem_id, value)
push_data_to_gradio_component(value, elem_id, load_type);
}
else {
if (load_default) {
console.log('加载cookie的默认值', elem_id, load_default_value)
push_data_to_gradio_component(load_default_value, elem_id, load_type);
} }
}); }
}); }
if (save_or_load === "save") {
if (!set_success){ setCookie(cookie_key, save_value, 365);
console.log("设置checkbox失败,没有找到对应的key")
} }
} }
function apply_cookie_for_checkbox(dark) {
// console.log("apply_cookie_for_checkboxes")
let searchString = "输入清除键";
let bool_value = "False";
////////////////// darkmode /////////////////// async function GptAcademicJavaScriptInit(dark, prompt, live2d, layout) {
// 第一部分,布局初始化
audio_fn_init();
minor_ui_adjustment();
chatbotIndicator = gradioApp().querySelector('#gpt-chatbot > div.wrap');
var chatbotObserver = new MutationObserver(() => {
chatbotContentChanged(1);
});
chatbotObserver.observe(chatbotIndicator, { attributes: true, childList: true, subtree: true });
if (layout === "LEFT-RIGHT") { chatbotAutoHeight(); }
if (layout === "LEFT-RIGHT") { limit_scroll_position(); }
// 第二部分,读取Cookie,初始话界面
let searchString = "";
let bool_value = "";
// darkmode 深色模式
if (getCookie("js_darkmode_cookie")) { if (getCookie("js_darkmode_cookie")) {
dark = getCookie("js_darkmode_cookie") dark = getCookie("js_darkmode_cookie")
} }
@@ -819,29 +889,41 @@ function apply_cookie_for_checkbox(dark) {
} }
} }
////////////////////// clearButton /////////////////////////// // SysPrompt 系统静默提示词
gpt_academic_gradio_saveload("load", "elem_prompt", "js_system_prompt_cookie", null, "str");
// Temperature 大模型温度参数
gpt_academic_gradio_saveload("load", "elem_temperature", "js_temperature_cookie", null, "float");
// clearButton 自动清除按钮
if (getCookie("js_clearbtn_show_cookie")) { if (getCookie("js_clearbtn_show_cookie")) {
// have cookie // have cookie
bool_value = getCookie("js_clearbtn_show_cookie") bool_value = getCookie("js_clearbtn_show_cookie")
bool_value = bool_value == "True"; bool_value = bool_value == "True";
searchString = "输入清除键"; searchString = "输入清除键";
if (bool_value) { if (bool_value) {
let clearButton = document.getElementById("elem_clear"); // make btns appear
let clearButton2 = document.getElementById("elem_clear2"); let clearButton = document.getElementById("elem_clear"); clearButton.style.display = "block";
clearButton.style.display = "block"; let clearButton2 = document.getElementById("elem_clear2"); clearButton2.style.display = "block";
clearButton2.style.display = "block"; // deal with checkboxes
set_checkbox(searchString, true); let arr_with_clear_btn = update_array(
await get_data_from_gradio_component('cbs'), "输入清除键", "add"
)
push_data_to_gradio_component(arr_with_clear_btn, "cbs", "no_conversion");
} else { } else {
let clearButton = document.getElementById("elem_clear"); // make btns disappear
let clearButton2 = document.getElementById("elem_clear2"); let clearButton = document.getElementById("elem_clear"); clearButton.style.display = "none";
clearButton.style.display = "none"; let clearButton2 = document.getElementById("elem_clear2"); clearButton2.style.display = "none";
clearButton2.style.display = "none"; // deal with checkboxes
set_checkbox(searchString, false); let arr_without_clear_btn = update_array(
await get_data_from_gradio_component('cbs'), "输入清除键", "remove"
)
push_data_to_gradio_component(arr_without_clear_btn, "cbs", "no_conversion");
} }
} }
////////////////////// live2d /////////////////////////// // live2d 显示
if (getCookie("js_live2d_show_cookie")) { if (getCookie("js_live2d_show_cookie")) {
// have cookie // have cookie
searchString = "添加Live2D形象"; searchString = "添加Live2D形象";
@@ -849,17 +931,23 @@ function apply_cookie_for_checkbox(dark) {
bool_value = bool_value == "True"; bool_value = bool_value == "True";
if (bool_value) { if (bool_value) {
loadLive2D(); loadLive2D();
set_checkbox(searchString, true); let arr_with_live2d = update_array(
await get_data_from_gradio_component('cbsc'), "添加Live2D形象", "add"
)
push_data_to_gradio_component(arr_with_live2d, "cbsc", "no_conversion");
} else { } else {
$('.waifu').hide(); try {
set_checkbox(searchString, false); $('.waifu').hide();
let arr_without_live2d = update_array(
await get_data_from_gradio_component('cbsc'), "添加Live2D形象", "remove"
)
push_data_to_gradio_component(arr_without_live2d, "cbsc", "no_conversion");
} catch (error) {
}
} }
} else { } else {
// do not have cookie // do not have cookie
// get conf if (live2d) {
display_panel_arr = get_checkbox_selected_items("cbsc");
searchString = "添加Live2D形象";
if (display_panel_arr.includes(searchString)) {
loadLive2D(); loadLive2D();
} else { } else {
} }

查看文件

@@ -1,7 +1,10 @@
import pickle import pickle
import base64 import base64
import uuid import uuid
import json
from toolbox import get_conf from toolbox import get_conf
import json
""" """
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
@@ -45,24 +48,24 @@ adjust_theme, advanced_css, theme_declaration, _ = load_dynamic_theme(get_conf("
cookie相关工具函数 cookie相关工具函数
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
""" """
def assign_user_uuid(cookies):
def init_cookie(cookies):
# 为每一位访问的用户赋予一个独一无二的uuid编码 # 为每一位访问的用户赋予一个独一无二的uuid编码
cookies.update({"uuid": uuid.uuid4()}) cookies.update({"uuid": uuid.uuid4()})
return cookies return cookies
def to_cookie_str(d): def to_cookie_str(d):
# Pickle the dictionary and encode it as a string # serialize the dictionary and encode it as a string
pickled_dict = pickle.dumps(d) serialized_dict = json.dumps(d)
cookie_value = base64.b64encode(pickled_dict).decode("utf-8") cookie_value = base64.b64encode(serialized_dict.encode('utf8')).decode("utf-8")
return cookie_value return cookie_value
def from_cookie_str(c): def from_cookie_str(c):
# Decode the base64-encoded string and unpickle it into a dictionary # Decode the base64-encoded string and unserialize it into a dictionary
pickled_dict = base64.b64decode(c.encode("utf-8")) serialized_dict = base64.b64decode(c.encode("utf-8"))
return pickle.loads(pickled_dict) serialized_dict.decode("utf-8")
return json.loads(serialized_dict)
""" """
@@ -103,8 +106,8 @@ js_code_for_toggle_darkmode = """() => {
}""" }"""
js_code_for_persistent_cookie_init = """(py_pickle_cookie, cookie) => { js_code_for_persistent_cookie_init = """(web_cookie_cache, cookie) => {
return [getCookie("py_pickle_cookie"), cookie]; return [getCookie("web_cookie_cache"), cookie];
} }
""" """
@@ -175,11 +178,8 @@ setTimeout(() => {
js_code_show_or_hide_group2 = """ js_code_show_or_hide_group2 = """
(display_panel_arr)=>{ (display_panel_arr)=>{
setTimeout(() => { setTimeout(() => {
// console.log("display_panel_arr");
// get conf
display_panel_arr = get_checkbox_selected_items("cbsc"); display_panel_arr = get_checkbox_selected_items("cbsc");
////////////////////// 添加Live2D形象 ///////////////////////////
let searchString = "添加Live2D形象"; let searchString = "添加Live2D形象";
let ele = "none"; let ele = "none";
if (display_panel_arr.includes(searchString)) { if (display_panel_arr.includes(searchString)) {
@@ -190,7 +190,6 @@ setTimeout(() => {
$('.waifu').hide(); $('.waifu').hide();
} }
}, 50); }, 50);
} }
""" """

查看文件

@@ -7,6 +7,8 @@ import base64
import gradio import gradio
import shutil import shutil
import glob import glob
import logging
import uuid
from functools import wraps from functools import wraps
from shared_utils.config_loader import get_conf from shared_utils.config_loader import get_conf
from shared_utils.config_loader import set_conf from shared_utils.config_loader import set_conf
@@ -25,11 +27,14 @@ from shared_utils.text_mask import apply_gpt_academic_string_mask
from shared_utils.text_mask import build_gpt_academic_masked_string from shared_utils.text_mask import build_gpt_academic_masked_string
from shared_utils.text_mask import apply_gpt_academic_string_mask_langbased from shared_utils.text_mask import apply_gpt_academic_string_mask_langbased
from shared_utils.text_mask import build_gpt_academic_masked_string_langbased from shared_utils.text_mask import build_gpt_academic_masked_string_langbased
from shared_utils.map_names import map_friendly_names_to_model
from shared_utils.map_names import map_model_to_friendly_names
from shared_utils.map_names import read_one_api_model_name
from shared_utils.handle_upload import html_local_file from shared_utils.handle_upload import html_local_file
from shared_utils.handle_upload import html_local_img from shared_utils.handle_upload import html_local_img
from shared_utils.handle_upload import file_manifest_filter_type from shared_utils.handle_upload import file_manifest_filter_type
from shared_utils.handle_upload import extract_archive from shared_utils.handle_upload import extract_archive
from typing import List
pj = os.path.join pj = os.path.join
default_user_name = "default_user" default_user_name = "default_user"
@@ -81,7 +86,9 @@ def ArgsGeneralWrapper(f):
该装饰器是大多数功能调用的入口。 该装饰器是大多数功能调用的入口。
函数示意图https://mermaid.live/edit#pako:eNqNVFtPGkEY_StkntoEDQtLoTw0sWqapjQxVWPabmOm7AiEZZcsQ9QiiW012qixqdeqqIn10geBh6ZR8PJnmAWe-hc6l3VhrWnLEzNzzvnO953ZyYOYoSIQAWOaMR5LQBN7hvoU3UN_g5iu7imAXEyT4wUF3Pd0dT3y9KGYYUJsmK8V0GPGs0-QjkyojZgwk0Fm82C2dVghX08U8EaoOHjOfoEMU0XmADRhOksVWnNLjdpM82qFzB6S5Q_WWsUhuqCc3JtAsVR_OoMnhyZwXgHWwbS1d4gnsLVZJp-P6mfVxveqAgqC70Jz_pQCOGDKM5xFdNNPDdilF6uSU_hOYqu4a3MHYDZLDzq5fodrC3PWcEaFGPUaRiqJWK_W9g9rvRITa4dhy_0nw67SiePMp3oSR6PPn41DGgllkvkizYwsrmtaejTFd8V4yekGmT1zqrt4XGlAy8WTuiPULF01LksZvukSajfQQRAxmYi5S0D81sDcyzapVdn6sYFHkjhhGyel3frVQnvsnbR23lEjlhIlaOJiFPWzU5G4tfNJo8ejwp47-TbvJkKKZvmxA6SKo16oaazJysfG6klr9T0pbTW2ZqzlL_XaT8fYbQLXe4mSmvoCZXMaa7FePW6s7jVqK9bujvse3WFjY5_Z4KfsA4oiPY4T7Drvn1tLJTbG1to1qR79ulgk89-oJbvZzbIwJty6u20LOReWa9BvwserUd9s9MIKc3x5TUWEoAhUyJK5y85w_yG-dFu_R9waoU7K581y8W_qLle35-rG9Nxcrz8QHRsc0K-r9NViYRT36KsFvCCNzDRMqvSVyzOKAnACpZECIvSvCs2UAhS9QHEwh43BST0GItjMIS_I8e-sLwnj9A262cxA_ZVh0OUY1LJiDSJ5MAEiUijYLUtBORR6KElyQPaCSRDpksNSd8AfluSgHPaFC17wjrOlbgbzyyFf4IFPDvoD_sJvnkdK-g 函数示意图https://mermaid.live/edit#pako:eNqNVFtPGkEY_StkntoEDQtLoTw0sWqapjQxVWPabmOm7AiEZZcsQ9QiiW012qixqdeqqIn10geBh6ZR8PJnmAWe-hc6l3VhrWnLEzNzzvnO953ZyYOYoSIQAWOaMR5LQBN7hvoU3UN_g5iu7imAXEyT4wUF3Pd0dT3y9KGYYUJsmK8V0GPGs0-QjkyojZgwk0Fm82C2dVghX08U8EaoOHjOfoEMU0XmADRhOksVWnNLjdpM82qFzB6S5Q_WWsUhuqCc3JtAsVR_OoMnhyZwXgHWwbS1d4gnsLVZJp-P6mfVxveqAgqC70Jz_pQCOGDKM5xFdNNPDdilF6uSU_hOYqu4a3MHYDZLDzq5fodrC3PWcEaFGPUaRiqJWK_W9g9rvRITa4dhy_0nw67SiePMp3oSR6PPn41DGgllkvkizYwsrmtaejTFd8V4yekGmT1zqrt4XGlAy8WTuiPULF01LksZvukSajfQQRAxmYi5S0D81sDcyzapVdn6sYFHkjhhGyel3frVQnvsnbR23lEjlhIlaOJiFPWzU5G4tfNJo8ejwp47-TbvJkKKZvmxA6SKo16oaazJysfG6klr9T0pbTW2ZqzlL_XaT8fYbQLXe4mSmvoCZXMaa7FePW6s7jVqK9bujvse3WFjY5_Z4KfsA4oiPY4T7Drvn1tLJTbG1to1qR79ulgk89-oJbvZzbIwJty6u20LOReWa9BvwserUd9s9MIKc3x5TUWEoAhUyJK5y85w_yG-dFu_R9waoU7K581y8W_qLle35-rG9Nxcrz8QHRsc0K-r9NViYRT36KsFvCCNzDRMqvSVyzOKAnACpZECIvSvCs2UAhS9QHEwh43BST0GItjMIS_I8e-sLwnj9A262cxA_ZVh0OUY1LJiDSJ5MAEiUijYLUtBORR6KElyQPaCSRDpksNSd8AfluSgHPaFC17wjrOlbgbzyyFf4IFPDvoD_sJvnkdK-g
""" """
def decorated(request: gradio.Request, cookies, max_length, llm_model, txt, txt2, top_p, temperature, chatbot, history, system_prompt, plugin_advanced_arg, *args): def decorated(request: gradio.Request, cookies:dict, max_length:int, llm_model:str,
txt:str, txt2:str, top_p:float, temperature:float, chatbot:list,
history:list, system_prompt:str, plugin_advanced_arg:str, *args):
txt_passon = txt txt_passon = txt
if txt == "" and txt2 != "": txt_passon = txt2 if txt == "" and txt2 != "": txt_passon = txt2
# 引入一个有cookie的chatbot # 引入一个有cookie的chatbot
@@ -133,7 +140,7 @@ def ArgsGeneralWrapper(f):
return decorated return decorated
def update_ui(chatbot, history, msg="正常", **kwargs): # 刷新界面 def update_ui(chatbot:ChatBotWithCookies, history, msg="正常", **kwargs): # 刷新界面
""" """
刷新用户界面 刷新用户界面
""" """
@@ -163,7 +170,7 @@ def update_ui(chatbot, history, msg="正常", **kwargs): # 刷新界面
yield cookies, chatbot_gr, history, msg yield cookies, chatbot_gr, history, msg
def update_ui_lastest_msg(lastmsg, chatbot, history, delay=1): # 刷新界面 def update_ui_lastest_msg(lastmsg:str, chatbot:ChatBotWithCookies, history:list, delay=1): # 刷新界面
""" """
刷新用户界面 刷新用户界面
""" """
@@ -190,13 +197,12 @@ def CatchException(f):
""" """
@wraps(f) @wraps(f)
def decorated(main_input, llm_kwargs, plugin_kwargs, chatbot_with_cookie, history, *args, **kwargs): def decorated(main_input:str, llm_kwargs:dict, plugin_kwargs:dict,
chatbot_with_cookie:ChatBotWithCookies, history:list, *args, **kwargs):
try: try:
yield from f(main_input, llm_kwargs, plugin_kwargs, chatbot_with_cookie, history, *args, **kwargs) yield from f(main_input, llm_kwargs, plugin_kwargs, chatbot_with_cookie, history, *args, **kwargs)
except Exception as e: except Exception as e:
from check_proxy import check_proxy
from toolbox import get_conf from toolbox import get_conf
proxies = get_conf('proxies')
tb_str = '```\n' + trimmed_format_exc() + '```' tb_str = '```\n' + trimmed_format_exc() + '```'
if len(chatbot_with_cookie) == 0: if len(chatbot_with_cookie) == 0:
chatbot_with_cookie.clear() chatbot_with_cookie.clear()
@@ -249,7 +255,7 @@ def HotReload(f):
""" """
def get_reduce_token_percent(text): def get_reduce_token_percent(text:str):
""" """
* 此函数未来将被弃用 * 此函数未来将被弃用
""" """
@@ -268,7 +274,7 @@ def get_reduce_token_percent(text):
def write_history_to_file( def write_history_to_file(
history, file_basename=None, file_fullname=None, auto_caption=True history:list, file_basename:str=None, file_fullname:str=None, auto_caption:bool=True
): ):
""" """
将对话记录history以Markdown格式写入文件中。如果没有指定文件名,则使用当前时间生成文件名。 将对话记录history以Markdown格式写入文件中。如果没有指定文件名,则使用当前时间生成文件名。
@@ -302,7 +308,7 @@ def write_history_to_file(
return res return res
def regular_txt_to_markdown(text): def regular_txt_to_markdown(text:str):
""" """
将普通文本转换为Markdown格式的文本。 将普通文本转换为Markdown格式的文本。
""" """
@@ -312,7 +318,7 @@ def regular_txt_to_markdown(text):
return text return text
def report_exception(chatbot, history, a, b): def report_exception(chatbot:ChatBotWithCookies, history:list, a:str, b:str):
""" """
向chatbot中添加错误信息 向chatbot中添加错误信息
""" """
@@ -320,7 +326,7 @@ def report_exception(chatbot, history, a, b):
history.extend([a, b]) history.extend([a, b])
def find_free_port(): def find_free_port()->int:
""" """
返回当前系统中可用的未使用端口。 返回当前系统中可用的未使用端口。
""" """
@@ -333,10 +339,9 @@ def find_free_port():
return s.getsockname()[1] return s.getsockname()[1]
def find_recent_files(directory): def find_recent_files(directory:str)->List[str]:
""" """
me: find files that is created with in one minutes under a directory with python, write a function Find files that is created with in one minutes under a directory with python, write a function
gpt: here it is!
""" """
import os import os
import time import time
@@ -359,7 +364,7 @@ def find_recent_files(directory):
return recent_files return recent_files
def file_already_in_downloadzone(file, user_path): def file_already_in_downloadzone(file:str, user_path:str):
try: try:
parent_path = os.path.abspath(user_path) parent_path = os.path.abspath(user_path)
child_path = os.path.abspath(file) child_path = os.path.abspath(file)
@@ -371,7 +376,7 @@ def file_already_in_downloadzone(file, user_path):
return False return False
def promote_file_to_downloadzone(file, rename_file=None, chatbot=None): def promote_file_to_downloadzone(file:str, rename_file:str=None, chatbot:ChatBotWithCookies=None):
# 将文件复制一份到下载区 # 将文件复制一份到下载区
import shutil import shutil
@@ -406,12 +411,12 @@ def promote_file_to_downloadzone(file, rename_file=None, chatbot=None):
return new_path return new_path
def disable_auto_promotion(chatbot): def disable_auto_promotion(chatbot:ChatBotWithCookies):
chatbot._cookies.update({"files_to_promote": []}) chatbot._cookies.update({"files_to_promote": []})
return return
def del_outdated_uploads(outdate_time_seconds, target_path_base=None): def del_outdated_uploads(outdate_time_seconds:float, target_path_base:str=None):
if target_path_base is None: if target_path_base is None:
user_upload_dir = get_conf("PATH_PRIVATE_UPLOAD") user_upload_dir = get_conf("PATH_PRIVATE_UPLOAD")
else: else:
@@ -464,7 +469,8 @@ def to_markdown_tabs(head: list, tabs: list, alignment=":---:", column=False, om
def on_file_uploaded( def on_file_uploaded(
request: gradio.Request, files, chatbot, txt, txt2, checkboxes, cookies request: gradio.Request, files:List[str], chatbot:ChatBotWithCookies,
txt:str, txt2:str, checkboxes:List[str], cookies:dict
): ):
""" """
当文件被上传时的回调函数 当文件被上传时的回调函数
@@ -528,18 +534,14 @@ def on_file_uploaded(
return chatbot, txt, txt2, cookies return chatbot, txt, txt2, cookies
def on_report_generated(cookies, files, chatbot): def on_report_generated(cookies:dict, files:List[str], chatbot:ChatBotWithCookies):
# from toolbox import find_recent_files
# PATH_LOGGING = get_conf('PATH_LOGGING')
if "files_to_promote" in cookies: if "files_to_promote" in cookies:
report_files = cookies["files_to_promote"] report_files = cookies["files_to_promote"]
cookies.pop("files_to_promote") cookies.pop("files_to_promote")
else: else:
report_files = [] report_files = []
# report_files = find_recent_files(PATH_LOGGING)
if len(report_files) == 0: if len(report_files) == 0:
return cookies, None, chatbot return cookies, None, chatbot
# files.extend(report_files)
file_links = "" file_links = ""
for f in report_files: for f in report_files:
file_links += ( file_links += (
@@ -819,7 +821,7 @@ def is_the_upload_folder(string):
return False return False
def get_user(chatbotwithcookies): def get_user(chatbotwithcookies:ChatBotWithCookies):
return chatbotwithcookies._cookies.get("user_name", default_user_name) return chatbotwithcookies._cookies.get("user_name", default_user_name)
@@ -902,7 +904,7 @@ def get_pictures_list(path):
return file_manifest return file_manifest
def have_any_recent_upload_image_files(chatbot): def have_any_recent_upload_image_files(chatbot:ChatBotWithCookies):
_5min = 5 * 60 _5min = 5 * 60
if chatbot is None: if chatbot is None:
return False, None # chatbot is None return False, None # chatbot is None
@@ -919,6 +921,18 @@ def have_any_recent_upload_image_files(chatbot):
else: else:
return False, None # most_recent_uploaded is too old return False, None # most_recent_uploaded is too old
# Claude3 model supports graphic context dialogue, reads all images
def every_image_file_in_path(chatbot:ChatBotWithCookies):
if chatbot is None:
return False, [] # chatbot is None
most_recent_uploaded = chatbot._cookies.get("most_recent_uploaded", None)
if not most_recent_uploaded:
return False, [] # most_recent_uploaded is None
path = most_recent_uploaded["path"]
file_manifest = get_pictures_list(path)
if len(file_manifest) == 0:
return False, []
return True, file_manifest
# Function to encode the image # Function to encode the image
def encode_image(image_path): def encode_image(image_path):
@@ -939,3 +953,65 @@ def check_packages(packages=[]):
spam_spec = importlib.util.find_spec(p) spam_spec = importlib.util.find_spec(p)
if spam_spec is None: if spam_spec is None:
raise ModuleNotFoundError raise ModuleNotFoundError
def map_file_to_sha256(file_path):
import hashlib
with open(file_path, 'rb') as file:
content = file.read()
# Calculate the SHA-256 hash of the file contents
sha_hash = hashlib.sha256(content).hexdigest()
return sha_hash
def check_repeat_upload(new_pdf_path, pdf_hash):
'''
检查历史上传的文件是否与新上传的文件相同,如果相同则返回(True, 重复文件路径),否则返回(False,None)
'''
from toolbox import get_conf
import PyPDF2
user_upload_dir = os.path.dirname(os.path.dirname(new_pdf_path))
file_name = os.path.basename(new_pdf_path)
file_manifest = [f for f in glob.glob(f'{user_upload_dir}/**/{file_name}', recursive=True)]
for saved_file in file_manifest:
with open(new_pdf_path, 'rb') as file1, open(saved_file, 'rb') as file2:
reader1 = PyPDF2.PdfFileReader(file1)
reader2 = PyPDF2.PdfFileReader(file2)
# 比较页数是否相同
if reader1.getNumPages() != reader2.getNumPages():
continue
# 比较每一页的内容是否相同
for page_num in range(reader1.getNumPages()):
page1 = reader1.getPage(page_num).extractText()
page2 = reader2.getPage(page_num).extractText()
if page1 != page2:
continue
maybe_project_dir = glob.glob('{}/**/{}'.format(get_log_folder(), pdf_hash + ".tag"), recursive=True)
if len(maybe_project_dir) > 0:
return True, os.path.dirname(maybe_project_dir[0])
# 如果所有页的内容都相同,返回 True
return False, None
def log_chat(llm_model: str, input_str: str, output_str: str):
try:
if output_str and input_str and llm_model:
uid = str(uuid.uuid4().hex)
logging.info(f"[Model({uid})] {llm_model}")
input_str = input_str.rstrip('\n')
logging.info(f"[Query({uid})]\n{input_str}")
output_str = output_str.rstrip('\n')
logging.info(f"[Response({uid})]\n{output_str}\n\n")
except:
print(trimmed_format_exc())

查看文件

@@ -1,5 +1,5 @@
{ {
"version": 3.72, "version": 3.74,
"show_feature": true, "show_feature": true,
"new_feature": "支持切换多个智谱ai模型 <-> 用绘图功能增强部分插件 <-> 基础功能区支持自动切换中英提示词 <-> 支持Mermaid绘图库让大模型绘制脑图 <-> 支持Gemini-pro <-> 支持直接拖拽文件到上传区 <-> 支持将图片粘贴到输入区" "new_feature": "增加多用户文件鉴权验证提高安全性 <-> 优化oneapi接入方法 <-> 接入Cohere和月之暗面模型 <-> 简化挂载二级目录的步骤 <-> 支持Mermaid绘图库让大模型绘制脑图"
} }