镜像自地址
https://github.com/binary-husky/gpt_academic.git
已同步 2025-12-06 22:46:48 +00:00
比较提交
46 次代码提交
version3.8
...
huggingfac
| 作者 | SHA1 | 提交日期 | |
|---|---|---|---|
|
|
7894e2f02d | ||
|
|
9e9bd7aa27 | ||
|
|
c534814363 | ||
|
|
8a525a4560 | ||
|
|
22f58d0953 | ||
|
|
59b4345945 | ||
|
|
72ba7e9738 | ||
|
|
d7f4b07fe4 | ||
|
|
df27843e51 | ||
|
|
e2fefec2e3 | ||
|
|
2bf71bd1a8 | ||
|
|
6a56fb7477 | ||
|
|
a2e7ea748c | ||
|
|
8153c1b49d | ||
|
|
2552126744 | ||
|
|
2475163337 | ||
|
|
a3bdb69e30 | ||
|
|
81874b380f | ||
|
|
96c1852abc | ||
|
|
cd145c0794 | ||
|
|
7a4d4ad956 | ||
|
|
9f9848c6e9 | ||
|
|
94425c49fd | ||
|
|
e874a16050 | ||
|
|
c28388c5fe | ||
|
|
b4a56d391b | ||
|
|
7075092f86 | ||
|
|
1086ff8092 | ||
|
|
3a22446b47 | ||
|
|
7842cf03cc | ||
|
|
54f55c32f2 | ||
|
|
94318ff0a2 | ||
|
|
5be6b83762 | ||
|
|
6f18d1716e | ||
|
|
90944bd744 | ||
|
|
752937cb70 | ||
|
|
c584cbac5b | ||
|
|
309d12b404 | ||
|
|
52ea0acd61 | ||
|
|
9f5e3e0fd5 | ||
|
|
315e78e5d9 | ||
|
|
b6b4ba684a | ||
|
|
2281a5ca7f | ||
|
|
49558686f2 | ||
|
|
b050ccedb5 | ||
|
|
ae56cab6f4 |
7
.gitignore
vendored
7
.gitignore
vendored
@@ -131,9 +131,6 @@ dmypy.json
|
|||||||
# Pyre type checker
|
# Pyre type checker
|
||||||
.pyre/
|
.pyre/
|
||||||
|
|
||||||
# macOS files
|
|
||||||
.DS_Store
|
|
||||||
|
|
||||||
.vscode
|
.vscode
|
||||||
.idea
|
.idea
|
||||||
|
|
||||||
@@ -156,7 +153,3 @@ media
|
|||||||
flagged
|
flagged
|
||||||
request_llms/ChatGLM-6b-onnx-u8s8
|
request_llms/ChatGLM-6b-onnx-u8s8
|
||||||
.pre-commit-config.yaml
|
.pre-commit-config.yaml
|
||||||
test.*
|
|
||||||
temp.*
|
|
||||||
objdump*
|
|
||||||
*.min.*.js
|
|
||||||
|
|||||||
@@ -12,16 +12,11 @@ RUN echo '[global]' > /etc/pip.conf && \
|
|||||||
echo 'trusted-host = mirrors.aliyun.com' >> /etc/pip.conf
|
echo 'trusted-host = mirrors.aliyun.com' >> /etc/pip.conf
|
||||||
|
|
||||||
|
|
||||||
# 语音输出功能(以下两行,第一行更换阿里源,第二行安装ffmpeg,都可以删除)
|
|
||||||
RUN UBUNTU_VERSION=$(awk -F= '/^VERSION_CODENAME=/{print $2}' /etc/os-release); echo "deb https://mirrors.aliyun.com/debian/ $UBUNTU_VERSION main non-free contrib" > /etc/apt/sources.list; apt-get update
|
|
||||||
RUN apt-get install ffmpeg -y
|
|
||||||
|
|
||||||
|
|
||||||
# 进入工作路径(必要)
|
# 进入工作路径(必要)
|
||||||
WORKDIR /gpt
|
WORKDIR /gpt
|
||||||
|
|
||||||
|
|
||||||
# 安装大部分依赖,利用Docker缓存加速以后的构建 (以下两行,可以删除)
|
# 安装大部分依赖,利用Docker缓存加速以后的构建 (以下三行,可以删除)
|
||||||
COPY requirements.txt ./
|
COPY requirements.txt ./
|
||||||
RUN pip3 install -r requirements.txt
|
RUN pip3 install -r requirements.txt
|
||||||
|
|
||||||
|
|||||||
31
README.md
31
README.md
@@ -1,8 +1,20 @@
|
|||||||
> [!IMPORTANT]
|
---
|
||||||
> 2024.6.1: 版本3.80加入插件二级菜单功能(详见wiki)
|
title: GPT-Academic
|
||||||
> 2024.5.1: 加入Doc2x翻译PDF论文的功能,[查看详情](https://github.com/binary-husky/gpt_academic/wiki/Doc2x)
|
emoji: 😻
|
||||||
> 2024.3.11: 全力支持Qwen、GLM、DeepseekCoder等中文大语言模型! SoVits语音克隆模块,[查看详情](https://www.bilibili.com/video/BV1Rp421S7tF/)
|
colorFrom: blue
|
||||||
> 2024.1.17: 安装依赖时,请选择`requirements.txt`中**指定的版本**。 安装命令:`pip install -r requirements.txt`。本项目完全开源免费,您可通过订阅[在线服务](https://github.com/binary-husky/gpt_academic/wiki/online)的方式鼓励本项目的发展。
|
colorTo: blue
|
||||||
|
sdk: gradio
|
||||||
|
sdk_version: 3.32.0
|
||||||
|
app_file: app.py
|
||||||
|
pinned: false
|
||||||
|
---
|
||||||
|
|
||||||
|
# ChatGPT 学术优化
|
||||||
|
> **Note**
|
||||||
|
>
|
||||||
|
> 2023.11.12: 某些依赖包尚不兼容python 3.12,推荐python 3.11。
|
||||||
|
>
|
||||||
|
> 2023.12.26: 安装依赖时,请选择`requirements.txt`中**指定的版本**。 安装命令:`pip install -r requirements.txt`。本项目完全开源免费,您可通过订阅[在线服务](https://github.com/binary-husky/gpt_academic/wiki/online)的方式鼓励本项目的发展。
|
||||||
|
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
@@ -67,7 +79,7 @@ Read this in [English](docs/README.English.md) | [日本語](docs/README.Japanes
|
|||||||
读论文、[翻译](https://www.bilibili.com/video/BV1KT411x7Wn)论文 | [插件] 一键解读latex/pdf论文全文并生成摘要
|
读论文、[翻译](https://www.bilibili.com/video/BV1KT411x7Wn)论文 | [插件] 一键解读latex/pdf论文全文并生成摘要
|
||||||
Latex全文[翻译](https://www.bilibili.com/video/BV1nk4y1Y7Js/)、[润色](https://www.bilibili.com/video/BV1FT411H7c5/) | [插件] 一键翻译或润色latex论文
|
Latex全文[翻译](https://www.bilibili.com/video/BV1nk4y1Y7Js/)、[润色](https://www.bilibili.com/video/BV1FT411H7c5/) | [插件] 一键翻译或润色latex论文
|
||||||
批量注释生成 | [插件] 一键批量生成函数注释
|
批量注释生成 | [插件] 一键批量生成函数注释
|
||||||
Markdown[中英互译](https://www.bilibili.com/video/BV1yo4y157jV/) | [插件] 看到上面5种语言的[README](https://github.com/binary-husky/gpt_academic/blob/master/docs/README.English.md)了吗?就是出自他的手笔
|
Markdown[中英互译](https://www.bilibili.com/video/BV1yo4y157jV/) | [插件] 看到上面5种语言的[README](https://github.com/binary-husky/gpt_academic/blob/master/docs/README_EN.md)了吗?就是出自他的手笔
|
||||||
[PDF论文全文翻译功能](https://www.bilibili.com/video/BV1KT411x7Wn) | [插件] PDF论文提取题目&摘要+翻译全文(多线程)
|
[PDF论文全文翻译功能](https://www.bilibili.com/video/BV1KT411x7Wn) | [插件] PDF论文提取题目&摘要+翻译全文(多线程)
|
||||||
[Arxiv小助手](https://www.bilibili.com/video/BV1LM4y1279X) | [插件] 输入arxiv文章url即可一键翻译摘要+下载PDF
|
[Arxiv小助手](https://www.bilibili.com/video/BV1LM4y1279X) | [插件] 输入arxiv文章url即可一键翻译摘要+下载PDF
|
||||||
Latex论文一键校对 | [插件] 仿Grammarly对Latex文章进行语法、拼写纠错+输出对照PDF
|
Latex论文一键校对 | [插件] 仿Grammarly对Latex文章进行语法、拼写纠错+输出对照PDF
|
||||||
@@ -87,10 +99,6 @@ Latex论文一键校对 | [插件] 仿Grammarly对Latex文章进行语法、拼
|
|||||||
<img src="https://user-images.githubusercontent.com/96192199/279702205-d81137c3-affd-4cd1-bb5e-b15610389762.gif" width="700" >
|
<img src="https://user-images.githubusercontent.com/96192199/279702205-d81137c3-affd-4cd1-bb5e-b15610389762.gif" width="700" >
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div align="center">
|
|
||||||
<img src="https://github.com/binary-husky/gpt_academic/assets/96192199/70ff1ec5-e589-4561-a29e-b831079b37fb.gif" width="700" >
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
- 所有按钮都通过读取functional.py动态生成,可随意加自定义功能,解放剪贴板
|
- 所有按钮都通过读取functional.py动态生成,可随意加自定义功能,解放剪贴板
|
||||||
<div align="center">
|
<div align="center">
|
||||||
@@ -257,7 +265,8 @@ P.S. 如果需要依赖Latex的插件功能,请见Wiki。另外,您也可以
|
|||||||
# Advanced Usage
|
# Advanced Usage
|
||||||
### I:自定义新的便捷按钮(学术快捷键)
|
### I:自定义新的便捷按钮(学术快捷键)
|
||||||
|
|
||||||
现在已可以通过UI中的`界面外观`菜单中的`自定义菜单`添加新的便捷按钮。如果需要在代码中定义,请使用任意文本编辑器打开`core_functional.py`,添加如下条目即可:
|
任意文本编辑器打开`core_functional.py`,添加如下条目,然后重启程序。(如果按钮已存在,那么可以直接修改(前缀、后缀都已支持热修改),无需重启程序即可生效。)
|
||||||
|
例如
|
||||||
|
|
||||||
```python
|
```python
|
||||||
"超级英译中": {
|
"超级英译中": {
|
||||||
|
|||||||
412
app.py
普通文件
412
app.py
普通文件
@@ -0,0 +1,412 @@
|
|||||||
|
import os; os.environ['no_proxy'] = '*' # 避免代理网络产生意外污染
|
||||||
|
|
||||||
|
help_menu_description = \
|
||||||
|
"""Github源代码开源和更新[地址🚀](https://github.com/binary-husky/gpt_academic),
|
||||||
|
感谢热情的[开发者们❤️](https://github.com/binary-husky/gpt_academic/graphs/contributors).
|
||||||
|
</br></br>常见问题请查阅[项目Wiki](https://github.com/binary-husky/gpt_academic/wiki),
|
||||||
|
如遇到Bug请前往[Bug反馈](https://github.com/binary-husky/gpt_academic/issues).
|
||||||
|
</br></br>普通对话使用说明: 1. 输入问题; 2. 点击提交
|
||||||
|
</br></br>基础功能区使用说明: 1. 输入文本; 2. 点击任意基础功能区按钮
|
||||||
|
</br></br>函数插件区使用说明: 1. 输入路径/问题, 或者上传文件; 2. 点击任意函数插件区按钮
|
||||||
|
</br></br>虚空终端使用说明: 点击虚空终端, 然后根据提示输入指令, 再次点击虚空终端
|
||||||
|
</br></br>如何保存对话: 点击保存当前的对话按钮
|
||||||
|
</br></br>如何语音对话: 请阅读Wiki
|
||||||
|
</br></br>如何临时更换API_KEY: 在输入区输入临时API_KEY后提交(网页刷新后失效)"""
|
||||||
|
|
||||||
|
def main():
|
||||||
|
import subprocess, sys
|
||||||
|
subprocess.check_call([sys.executable, '-m', 'pip', 'install', 'https://public.agent-matrix.com/publish/gradio-3.32.8-py3-none-any.whl'])
|
||||||
|
import gradio as gr
|
||||||
|
if gr.__version__ not in ['3.32.8']:
|
||||||
|
raise ModuleNotFoundError("使用项目内置Gradio获取最优体验! 请运行 `pip install -r requirements.txt` 指令安装内置Gradio及其他依赖, 详情信息见requirements.txt.")
|
||||||
|
from request_llms.bridge_all import predict
|
||||||
|
from toolbox import format_io, find_free_port, on_file_uploaded, on_report_generated, get_conf, ArgsGeneralWrapper, load_chat_cookies, DummyWith
|
||||||
|
# 建议您复制一个config_private.py放自己的秘密, 如API和代理网址
|
||||||
|
proxies, WEB_PORT, LLM_MODEL, CONCURRENT_COUNT, AUTHENTICATION = get_conf('proxies', 'WEB_PORT', 'LLM_MODEL', 'CONCURRENT_COUNT', 'AUTHENTICATION')
|
||||||
|
CHATBOT_HEIGHT, LAYOUT, AVAIL_LLM_MODELS, AUTO_CLEAR_TXT = get_conf('CHATBOT_HEIGHT', 'LAYOUT', 'AVAIL_LLM_MODELS', 'AUTO_CLEAR_TXT')
|
||||||
|
ENABLE_AUDIO, AUTO_CLEAR_TXT, PATH_LOGGING, AVAIL_THEMES, THEME, ADD_WAIFU = get_conf('ENABLE_AUDIO', 'AUTO_CLEAR_TXT', 'PATH_LOGGING', 'AVAIL_THEMES', 'THEME', 'ADD_WAIFU')
|
||||||
|
DARK_MODE, NUM_CUSTOM_BASIC_BTN, SSL_KEYFILE, SSL_CERTFILE = get_conf('DARK_MODE', 'NUM_CUSTOM_BASIC_BTN', 'SSL_KEYFILE', 'SSL_CERTFILE')
|
||||||
|
INIT_SYS_PROMPT = get_conf('INIT_SYS_PROMPT')
|
||||||
|
|
||||||
|
# 如果WEB_PORT是-1, 则随机选取WEB端口
|
||||||
|
PORT = find_free_port() if WEB_PORT <= 0 else WEB_PORT
|
||||||
|
from check_proxy import get_current_version
|
||||||
|
from themes.theme import adjust_theme, advanced_css, theme_declaration, js_code_clear, js_code_reset, js_code_show_or_hide, js_code_show_or_hide_group2
|
||||||
|
from themes.theme import js_code_for_css_changing, js_code_for_toggle_darkmode, js_code_for_persistent_cookie_init
|
||||||
|
from themes.theme import load_dynamic_theme, to_cookie_str, from_cookie_str, init_cookie
|
||||||
|
title_html = f"<h1 align=\"center\">GPT 学术优化 {get_current_version()}</h1>{theme_declaration}"
|
||||||
|
|
||||||
|
# 问询记录, python 版本建议3.9+(越新越好)
|
||||||
|
import logging, uuid
|
||||||
|
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
|
||||||
|
functional = get_core_functions()
|
||||||
|
|
||||||
|
# 高级函数插件
|
||||||
|
from crazy_functional import get_crazy_functions
|
||||||
|
DEFAULT_FN_GROUPS = get_conf('DEFAULT_FN_GROUPS')
|
||||||
|
plugins = get_crazy_functions()
|
||||||
|
all_plugin_groups = list(set([g for _, plugin in plugins.items() for g in plugin['Group'].split('|')]))
|
||||||
|
match_group = lambda tags, groups: any([g in groups for g in tags.split('|')])
|
||||||
|
|
||||||
|
# 处理markdown文本格式的转变
|
||||||
|
gr.Chatbot.postprocess = format_io
|
||||||
|
|
||||||
|
# 做一些外观色彩上的调整
|
||||||
|
set_theme = adjust_theme()
|
||||||
|
|
||||||
|
# 代理与自动更新
|
||||||
|
from check_proxy import check_proxy, auto_update, warm_up_modules
|
||||||
|
proxy_info = check_proxy(proxies)
|
||||||
|
|
||||||
|
gr_L1 = lambda: gr.Row().style()
|
||||||
|
gr_L2 = lambda scale, elem_id: gr.Column(scale=scale, elem_id=elem_id, min_width=400)
|
||||||
|
if LAYOUT == "TOP-DOWN":
|
||||||
|
gr_L1 = lambda: DummyWith()
|
||||||
|
gr_L2 = lambda scale, elem_id: gr.Row()
|
||||||
|
CHATBOT_HEIGHT /= 2
|
||||||
|
|
||||||
|
cancel_handles = []
|
||||||
|
customize_btns = {}
|
||||||
|
predefined_btns = {}
|
||||||
|
with gr.Blocks(title="GPT 学术优化", theme=set_theme, analytics_enabled=False, css=advanced_css) as demo:
|
||||||
|
gr.HTML(title_html)
|
||||||
|
gr.HTML('''<center><a href="https://huggingface.co/spaces/qingxu98/gpt-academic?duplicate=true"><img src="https://bit.ly/3gLdBN6" alt="Duplicate Space"></a>请您打开此页面后务必点击上方的“复制空间”(Duplicate Space)按钮!<font color="#FF00FF">使用时,先在输入框填入API-KEY然后回车。</font><br/>切忌在“复制空间”(Duplicate Space)之前填入API_KEY或进行提问,否则您的API_KEY将极可能被空间所有者攫取!<br/>支持任意数量的OpenAI的密钥和API2D的密钥共存,例如输入"OpenAI密钥1,API2D密钥2",然后提交,即可同时使用两种模型接口。</center>''')
|
||||||
|
secret_css, dark_mode, py_pickle_cookie = gr.Textbox(visible=False), gr.Textbox(DARK_MODE, visible=False), gr.Textbox(visible=False)
|
||||||
|
cookies = gr.State(load_chat_cookies())
|
||||||
|
with gr_L1():
|
||||||
|
with gr_L2(scale=2, elem_id="gpt-chat"):
|
||||||
|
chatbot = gr.Chatbot(label=f"当前模型:{LLM_MODEL}", elem_id="gpt-chatbot")
|
||||||
|
if LAYOUT == "TOP-DOWN": chatbot.style(height=CHATBOT_HEIGHT)
|
||||||
|
history = gr.State([])
|
||||||
|
with gr_L2(scale=1, elem_id="gpt-panel"):
|
||||||
|
with gr.Accordion("输入区", open=True, elem_id="input-panel") as area_input_primary:
|
||||||
|
with gr.Row():
|
||||||
|
txt = gr.Textbox(show_label=False, lines=2, placeholder="输入问题或API密钥,输入多个密钥时,用英文逗号间隔。支持多个OpenAI密钥共存。").style(container=False)
|
||||||
|
with gr.Row():
|
||||||
|
submitBtn = gr.Button("提交", elem_id="elem_submit", variant="primary")
|
||||||
|
with gr.Row():
|
||||||
|
resetBtn = gr.Button("重置", elem_id="elem_reset", variant="secondary"); resetBtn.style(size="sm")
|
||||||
|
stopBtn = gr.Button("停止", elem_id="elem_stop", variant="secondary"); stopBtn.style(size="sm")
|
||||||
|
clearBtn = gr.Button("清除", elem_id="elem_clear", variant="secondary", visible=False); clearBtn.style(size="sm")
|
||||||
|
if ENABLE_AUDIO:
|
||||||
|
with gr.Row():
|
||||||
|
audio_mic = gr.Audio(source="microphone", type="numpy", elem_id="elem_audio", streaming=True, show_label=False).style(container=False)
|
||||||
|
with gr.Row():
|
||||||
|
status = gr.Markdown(f"Tip: 按Enter提交, 按Shift+Enter换行。当前模型: {LLM_MODEL} \n {proxy_info}", elem_id="state-panel")
|
||||||
|
|
||||||
|
with gr.Accordion("基础功能区", open=True, elem_id="basic-panel") as area_basic_fn:
|
||||||
|
with gr.Row():
|
||||||
|
for k in range(NUM_CUSTOM_BASIC_BTN):
|
||||||
|
customize_btn = gr.Button("自定义按钮" + str(k+1), visible=False, variant="secondary", info_str=f'基础功能区: 自定义按钮')
|
||||||
|
customize_btn.style(size="sm")
|
||||||
|
customize_btns.update({"自定义按钮" + str(k+1): customize_btn})
|
||||||
|
for k in functional:
|
||||||
|
if ("Visible" in functional[k]) and (not functional[k]["Visible"]): continue
|
||||||
|
variant = functional[k]["Color"] if "Color" in functional[k] else "secondary"
|
||||||
|
functional[k]["Button"] = gr.Button(k, variant=variant, info_str=f'基础功能区: {k}')
|
||||||
|
functional[k]["Button"].style(size="sm")
|
||||||
|
predefined_btns.update({k: functional[k]["Button"]})
|
||||||
|
with gr.Accordion("函数插件区", open=True, elem_id="plugin-panel") as area_crazy_fn:
|
||||||
|
with gr.Row():
|
||||||
|
gr.Markdown("插件可读取“输入区”文本/路径作为参数(上传文件自动修正路径)")
|
||||||
|
with gr.Row(elem_id="input-plugin-group"):
|
||||||
|
plugin_group_sel = gr.Dropdown(choices=all_plugin_groups, label='', show_label=False, value=DEFAULT_FN_GROUPS,
|
||||||
|
multiselect=True, interactive=True, elem_classes='normal_mut_select').style(container=False)
|
||||||
|
with gr.Row():
|
||||||
|
for k, plugin in plugins.items():
|
||||||
|
if not plugin.get("AsButton", True): continue
|
||||||
|
visible = True if match_group(plugin['Group'], DEFAULT_FN_GROUPS) else False
|
||||||
|
variant = plugins[k]["Color"] if "Color" in plugin else "secondary"
|
||||||
|
info = plugins[k].get("Info", k)
|
||||||
|
plugin['Button'] = plugins[k]['Button'] = gr.Button(k, variant=variant,
|
||||||
|
visible=visible, info_str=f'函数插件区: {info}').style(size="sm")
|
||||||
|
with gr.Row():
|
||||||
|
with gr.Accordion("更多函数插件", open=True):
|
||||||
|
dropdown_fn_list = []
|
||||||
|
for k, plugin in plugins.items():
|
||||||
|
if not match_group(plugin['Group'], DEFAULT_FN_GROUPS): continue
|
||||||
|
if not plugin.get("AsButton", True): dropdown_fn_list.append(k) # 排除已经是按钮的插件
|
||||||
|
elif plugin.get('AdvancedArgs', False): dropdown_fn_list.append(k) # 对于需要高级参数的插件,亦在下拉菜单中显示
|
||||||
|
with gr.Row():
|
||||||
|
dropdown = gr.Dropdown(dropdown_fn_list, value=r"打开插件列表", label="", show_label=False).style(container=False)
|
||||||
|
with gr.Row():
|
||||||
|
plugin_advanced_arg = gr.Textbox(show_label=True, label="高级参数输入区", visible=False,
|
||||||
|
placeholder="这里是特殊函数插件的高级参数输入区").style(container=False)
|
||||||
|
with gr.Row():
|
||||||
|
switchy_bt = gr.Button(r"请先从插件列表中选择", variant="secondary").style(size="sm")
|
||||||
|
with gr.Row():
|
||||||
|
with gr.Accordion("点击展开“文件下载区”。", open=False) as area_file_up:
|
||||||
|
file_upload = gr.Files(label="任何文件, 推荐上传压缩文件(zip, tar)", file_count="multiple", elem_id="elem_upload")
|
||||||
|
|
||||||
|
with gr.Floating(init_x="0%", init_y="0%", visible=True, width=None, drag="forbidden", elem_id="tooltip"):
|
||||||
|
with gr.Row():
|
||||||
|
with gr.Tab("上传文件", elem_id="interact-panel"):
|
||||||
|
gr.Markdown("请上传本地文件/压缩包供“函数插件区”功能调用。请注意: 上传文件后会自动把输入区修改为相应路径。")
|
||||||
|
file_upload_2 = gr.Files(label="任何文件, 推荐上传压缩文件(zip, tar)", file_count="multiple", elem_id="elem_upload_float")
|
||||||
|
|
||||||
|
with gr.Tab("更换模型", elem_id="interact-panel"):
|
||||||
|
md_dropdown = gr.Dropdown(AVAIL_LLM_MODELS, value=LLM_MODEL, label="更换LLM模型/请求源").style(container=False)
|
||||||
|
top_p = gr.Slider(minimum=-0, maximum=1.0, value=1.0, step=0.01,interactive=True, label="Top-p (nucleus sampling)",)
|
||||||
|
temperature = gr.Slider(minimum=-0, maximum=2.0, value=1.0, step=0.01, interactive=True, label="Temperature",)
|
||||||
|
max_length_sl = gr.Slider(minimum=256, maximum=1024*32, value=4096, step=128, interactive=True, label="Local LLM MaxLength",)
|
||||||
|
system_prompt = gr.Textbox(show_label=True, lines=2, placeholder=f"System Prompt", label="System prompt", value=INIT_SYS_PROMPT)
|
||||||
|
|
||||||
|
with gr.Tab("界面外观", elem_id="interact-panel"):
|
||||||
|
theme_dropdown = gr.Dropdown(AVAIL_THEMES, value=THEME, label="更换UI主题").style(container=False)
|
||||||
|
checkboxes = gr.CheckboxGroup(["基础功能区", "函数插件区", "浮动输入区", "输入清除键", "插件参数区"], value=["基础功能区", "函数插件区"], label="显示/隐藏功能区", elem_id='cbs').style(container=False)
|
||||||
|
opt = ["自定义菜单"]
|
||||||
|
value=[]
|
||||||
|
if ADD_WAIFU: opt += ["添加Live2D形象"]; value += ["添加Live2D形象"]
|
||||||
|
checkboxes_2 = gr.CheckboxGroup(opt, value=value, label="显示/隐藏自定义菜单", elem_id='cbsc').style(container=False)
|
||||||
|
dark_mode_btn = gr.Button("切换界面明暗 ☀", variant="secondary").style(size="sm")
|
||||||
|
dark_mode_btn.click(None, None, None, _js=js_code_for_toggle_darkmode)
|
||||||
|
with gr.Tab("帮助", elem_id="interact-panel"):
|
||||||
|
gr.Markdown(help_menu_description)
|
||||||
|
|
||||||
|
with gr.Floating(init_x="20%", init_y="50%", visible=False, width="40%", drag="top") as area_input_secondary:
|
||||||
|
with gr.Accordion("浮动输入区", open=True, elem_id="input-panel2"):
|
||||||
|
with gr.Row() as row:
|
||||||
|
row.style(equal_height=True)
|
||||||
|
with gr.Column(scale=10):
|
||||||
|
txt2 = gr.Textbox(show_label=False, placeholder="Input question here.",
|
||||||
|
elem_id='user_input_float', lines=8, label="输入区2").style(container=False)
|
||||||
|
with gr.Column(scale=1, min_width=40):
|
||||||
|
submitBtn2 = gr.Button("提交", variant="primary"); submitBtn2.style(size="sm")
|
||||||
|
resetBtn2 = gr.Button("重置", variant="secondary"); resetBtn2.style(size="sm")
|
||||||
|
stopBtn2 = gr.Button("停止", variant="secondary"); stopBtn2.style(size="sm")
|
||||||
|
clearBtn2 = gr.Button("清除", elem_id="elem_clear2", variant="secondary", visible=False); clearBtn2.style(size="sm")
|
||||||
|
|
||||||
|
|
||||||
|
with gr.Floating(init_x="20%", init_y="50%", visible=False, width="40%", drag="top") as area_customize:
|
||||||
|
with gr.Accordion("自定义菜单", open=True, elem_id="edit-panel"):
|
||||||
|
with gr.Row() as row:
|
||||||
|
with gr.Column(scale=10):
|
||||||
|
AVAIL_BTN = [btn for btn in customize_btns.keys()] + [k for k in functional]
|
||||||
|
basic_btn_dropdown = gr.Dropdown(AVAIL_BTN, value="自定义按钮1", label="选择一个需要自定义基础功能区按钮").style(container=False)
|
||||||
|
basic_fn_title = gr.Textbox(show_label=False, placeholder="输入新按钮名称", lines=1).style(container=False)
|
||||||
|
basic_fn_prefix = gr.Textbox(show_label=False, placeholder="输入新提示前缀", lines=4).style(container=False)
|
||||||
|
basic_fn_suffix = gr.Textbox(show_label=False, placeholder="输入新提示后缀", lines=4).style(container=False)
|
||||||
|
with gr.Column(scale=1, min_width=70):
|
||||||
|
basic_fn_confirm = gr.Button("确认并保存", variant="primary"); basic_fn_confirm.style(size="sm")
|
||||||
|
basic_fn_clean = gr.Button("恢复默认", variant="primary"); basic_fn_clean.style(size="sm")
|
||||||
|
def assign_btn(persistent_cookie_, cookies_, basic_btn_dropdown_, basic_fn_title, basic_fn_prefix, basic_fn_suffix, clean_up=False):
|
||||||
|
ret = {}
|
||||||
|
# 读取之前的自定义按钮
|
||||||
|
customize_fn_overwrite_ = cookies_['customize_fn_overwrite']
|
||||||
|
# 更新新的自定义按钮
|
||||||
|
customize_fn_overwrite_.update({
|
||||||
|
basic_btn_dropdown_:
|
||||||
|
{
|
||||||
|
"Title":basic_fn_title,
|
||||||
|
"Prefix":basic_fn_prefix,
|
||||||
|
"Suffix":basic_fn_suffix,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
if clean_up:
|
||||||
|
customize_fn_overwrite_ = {}
|
||||||
|
cookies_.update(customize_fn_overwrite_) # 更新cookie
|
||||||
|
visible = (not clean_up) and (basic_fn_title != "")
|
||||||
|
if basic_btn_dropdown_ in customize_btns:
|
||||||
|
# 是自定义按钮,不是预定义按钮
|
||||||
|
ret.update({customize_btns[basic_btn_dropdown_]: gr.update(visible=visible, value=basic_fn_title)})
|
||||||
|
else:
|
||||||
|
# 是预定义按钮
|
||||||
|
ret.update({predefined_btns[basic_btn_dropdown_]: gr.update(visible=visible, value=basic_fn_title)})
|
||||||
|
ret.update({cookies: cookies_})
|
||||||
|
try: persistent_cookie_ = from_cookie_str(persistent_cookie_) # persistent cookie to dict
|
||||||
|
except: persistent_cookie_ = {}
|
||||||
|
persistent_cookie_["custom_bnt"] = customize_fn_overwrite_ # dict update new value
|
||||||
|
persistent_cookie_ = to_cookie_str(persistent_cookie_) # persistent cookie to dict
|
||||||
|
ret.update({py_pickle_cookie: persistent_cookie_}) # write persistent cookie
|
||||||
|
return ret
|
||||||
|
|
||||||
|
# update btn
|
||||||
|
h = basic_fn_confirm.click(assign_btn, [py_pickle_cookie, cookies, basic_btn_dropdown, basic_fn_title, basic_fn_prefix, basic_fn_suffix],
|
||||||
|
[py_pickle_cookie, cookies, *customize_btns.values(), *predefined_btns.values()])
|
||||||
|
h.then(None, [py_pickle_cookie], None, _js="""(py_pickle_cookie)=>{setCookie("py_pickle_cookie", py_pickle_cookie, 365);}""")
|
||||||
|
# clean up btn
|
||||||
|
h2 = basic_fn_clean.click(assign_btn, [py_pickle_cookie, cookies, basic_btn_dropdown, basic_fn_title, basic_fn_prefix, basic_fn_suffix, gr.State(True)],
|
||||||
|
[py_pickle_cookie, cookies, *customize_btns.values(), *predefined_btns.values()])
|
||||||
|
h2.then(None, [py_pickle_cookie], None, _js="""(py_pickle_cookie)=>{setCookie("py_pickle_cookie", py_pickle_cookie, 365);}""")
|
||||||
|
|
||||||
|
def persistent_cookie_reload(persistent_cookie_, cookies_):
|
||||||
|
ret = {}
|
||||||
|
for k in customize_btns:
|
||||||
|
ret.update({customize_btns[k]: gr.update(visible=False, value="")})
|
||||||
|
|
||||||
|
try: persistent_cookie_ = from_cookie_str(persistent_cookie_) # persistent cookie to dict
|
||||||
|
except: return ret
|
||||||
|
|
||||||
|
customize_fn_overwrite_ = persistent_cookie_.get("custom_bnt", {})
|
||||||
|
cookies_['customize_fn_overwrite'] = customize_fn_overwrite_
|
||||||
|
ret.update({cookies: cookies_})
|
||||||
|
|
||||||
|
for k,v in persistent_cookie_["custom_bnt"].items():
|
||||||
|
if v['Title'] == "": continue
|
||||||
|
if k in customize_btns: ret.update({customize_btns[k]: gr.update(visible=True, value=v['Title'])})
|
||||||
|
else: ret.update({predefined_btns[k]: gr.update(visible=True, value=v['Title'])})
|
||||||
|
return ret
|
||||||
|
|
||||||
|
# 功能区显示开关与功能区的互动
|
||||||
|
def fn_area_visibility(a):
|
||||||
|
ret = {}
|
||||||
|
ret.update({area_input_primary: gr.update(visible=("浮动输入区" not in a))})
|
||||||
|
ret.update({area_input_secondary: gr.update(visible=("浮动输入区" in a))})
|
||||||
|
ret.update({plugin_advanced_arg: gr.update(visible=("插件参数区" in a))})
|
||||||
|
if "浮动输入区" in a: ret.update({txt: gr.update(value="")})
|
||||||
|
return ret
|
||||||
|
checkboxes.select(fn_area_visibility, [checkboxes], [area_basic_fn, area_crazy_fn, area_input_primary, area_input_secondary, txt, txt2, plugin_advanced_arg] )
|
||||||
|
checkboxes.select(None, [checkboxes], None, _js=js_code_show_or_hide)
|
||||||
|
|
||||||
|
# 功能区显示开关与功能区的互动
|
||||||
|
def fn_area_visibility_2(a):
|
||||||
|
ret = {}
|
||||||
|
ret.update({area_customize: gr.update(visible=("自定义菜单" in a))})
|
||||||
|
return ret
|
||||||
|
checkboxes_2.select(fn_area_visibility_2, [checkboxes_2], [area_customize] )
|
||||||
|
checkboxes_2.select(None, [checkboxes_2], None, _js=js_code_show_or_hide_group2)
|
||||||
|
|
||||||
|
# 整理反复出现的控件句柄组合
|
||||||
|
input_combo = [cookies, max_length_sl, md_dropdown, txt, txt2, top_p, temperature, chatbot, history, system_prompt, plugin_advanced_arg]
|
||||||
|
output_combo = [cookies, chatbot, history, status]
|
||||||
|
predict_args = dict(fn=ArgsGeneralWrapper(predict), inputs=[*input_combo, gr.State(True)], outputs=output_combo)
|
||||||
|
# 提交按钮、重置按钮
|
||||||
|
cancel_handles.append(txt.submit(**predict_args))
|
||||||
|
cancel_handles.append(txt2.submit(**predict_args))
|
||||||
|
cancel_handles.append(submitBtn.click(**predict_args))
|
||||||
|
cancel_handles.append(submitBtn2.click(**predict_args))
|
||||||
|
resetBtn.click(None, None, [chatbot, history, status], _js=js_code_reset) # 先在前端快速清除chatbot&status
|
||||||
|
resetBtn2.click(None, None, [chatbot, history, status], _js=js_code_reset) # 先在前端快速清除chatbot&status
|
||||||
|
resetBtn.click(lambda: ([], [], "已重置"), None, [chatbot, history, status]) # 再在后端清除history
|
||||||
|
resetBtn2.click(lambda: ([], [], "已重置"), None, [chatbot, history, status]) # 再在后端清除history
|
||||||
|
clearBtn.click(None, None, [txt, txt2], _js=js_code_clear)
|
||||||
|
clearBtn2.click(None, None, [txt, txt2], _js=js_code_clear)
|
||||||
|
if AUTO_CLEAR_TXT:
|
||||||
|
submitBtn.click(None, None, [txt, txt2], _js=js_code_clear)
|
||||||
|
submitBtn2.click(None, None, [txt, txt2], _js=js_code_clear)
|
||||||
|
txt.submit(None, None, [txt, txt2], _js=js_code_clear)
|
||||||
|
txt2.submit(None, None, [txt, txt2], _js=js_code_clear)
|
||||||
|
# 基础功能区的回调函数注册
|
||||||
|
for k in functional:
|
||||||
|
if ("Visible" in functional[k]) and (not functional[k]["Visible"]): continue
|
||||||
|
click_handle = functional[k]["Button"].click(fn=ArgsGeneralWrapper(predict), inputs=[*input_combo, gr.State(True), gr.State(k)], outputs=output_combo)
|
||||||
|
cancel_handles.append(click_handle)
|
||||||
|
for btn in customize_btns.values():
|
||||||
|
click_handle = btn.click(fn=ArgsGeneralWrapper(predict), inputs=[*input_combo, gr.State(True), gr.State(btn.value)], outputs=output_combo)
|
||||||
|
cancel_handles.append(click_handle)
|
||||||
|
# 文件上传区,接收文件后与chatbot的互动
|
||||||
|
file_upload.upload(on_file_uploaded, [file_upload, chatbot, txt, txt2, checkboxes, cookies], [chatbot, txt, txt2, cookies]).then(None, None, None, _js=r"()=>{toast_push('上传完毕 ...'); cancel_loading_status();}")
|
||||||
|
file_upload_2.upload(on_file_uploaded, [file_upload_2, chatbot, txt, txt2, checkboxes, cookies], [chatbot, txt, txt2, cookies]).then(None, None, None, _js=r"()=>{toast_push('上传完毕 ...'); cancel_loading_status();}")
|
||||||
|
# 函数插件-固定按钮区
|
||||||
|
for k in plugins:
|
||||||
|
if not plugins[k].get("AsButton", True): continue
|
||||||
|
click_handle = plugins[k]["Button"].click(ArgsGeneralWrapper(plugins[k]["Function"]), [*input_combo], output_combo)
|
||||||
|
click_handle.then(on_report_generated, [cookies, file_upload, chatbot], [cookies, file_upload, chatbot])
|
||||||
|
cancel_handles.append(click_handle)
|
||||||
|
# 函数插件-下拉菜单与随变按钮的互动
|
||||||
|
def on_dropdown_changed(k):
|
||||||
|
variant = plugins[k]["Color"] if "Color" in plugins[k] else "secondary"
|
||||||
|
info = plugins[k].get("Info", k)
|
||||||
|
ret = {switchy_bt: gr.update(value=k, variant=variant, info_str=f'函数插件区: {info}')}
|
||||||
|
if plugins[k].get("AdvancedArgs", False): # 是否唤起高级插件参数区
|
||||||
|
ret.update({plugin_advanced_arg: gr.update(visible=True, label=f"插件[{k}]的高级参数说明:" + plugins[k].get("ArgsReminder", [f"没有提供高级参数功能说明"]))})
|
||||||
|
else:
|
||||||
|
ret.update({plugin_advanced_arg: gr.update(visible=False, label=f"插件[{k}]不需要高级参数。")})
|
||||||
|
return ret
|
||||||
|
dropdown.select(on_dropdown_changed, [dropdown], [switchy_bt, plugin_advanced_arg] )
|
||||||
|
|
||||||
|
def on_md_dropdown_changed(k):
|
||||||
|
return {chatbot: gr.update(label="当前模型:"+k)}
|
||||||
|
md_dropdown.select(on_md_dropdown_changed, [md_dropdown], [chatbot] )
|
||||||
|
|
||||||
|
def on_theme_dropdown_changed(theme, secret_css):
|
||||||
|
adjust_theme, css_part1, _, adjust_dynamic_theme = load_dynamic_theme(theme)
|
||||||
|
if adjust_dynamic_theme:
|
||||||
|
css_part2 = adjust_dynamic_theme._get_theme_css()
|
||||||
|
else:
|
||||||
|
css_part2 = adjust_theme()._get_theme_css()
|
||||||
|
return css_part2 + css_part1
|
||||||
|
|
||||||
|
theme_handle = theme_dropdown.select(on_theme_dropdown_changed, [theme_dropdown, secret_css], [secret_css])
|
||||||
|
theme_handle.then(
|
||||||
|
None,
|
||||||
|
[secret_css],
|
||||||
|
None,
|
||||||
|
_js=js_code_for_css_changing
|
||||||
|
)
|
||||||
|
# 随变按钮的回调函数注册
|
||||||
|
def route(request: gr.Request, k, *args, **kwargs):
|
||||||
|
if k in [r"打开插件列表", r"请先从插件列表中选择"]: return
|
||||||
|
yield from ArgsGeneralWrapper(plugins[k]["Function"])(request, *args, **kwargs)
|
||||||
|
click_handle = switchy_bt.click(route,[switchy_bt, *input_combo], output_combo)
|
||||||
|
click_handle.then(on_report_generated, [cookies, file_upload, chatbot], [cookies, file_upload, chatbot])
|
||||||
|
cancel_handles.append(click_handle)
|
||||||
|
# 终止按钮的回调函数注册
|
||||||
|
stopBtn.click(fn=None, inputs=None, outputs=None, cancels=cancel_handles)
|
||||||
|
stopBtn2.click(fn=None, inputs=None, outputs=None, cancels=cancel_handles)
|
||||||
|
plugins_as_btn = {name:plugin for name, plugin in plugins.items() if plugin.get('Button', None)}
|
||||||
|
def on_group_change(group_list):
|
||||||
|
btn_list = []
|
||||||
|
fns_list = []
|
||||||
|
if not group_list: # 处理特殊情况:没有选择任何插件组
|
||||||
|
return [*[plugin['Button'].update(visible=False) for _, plugin in plugins_as_btn.items()], gr.Dropdown.update(choices=[])]
|
||||||
|
for k, plugin in plugins.items():
|
||||||
|
if plugin.get("AsButton", True):
|
||||||
|
btn_list.append(plugin['Button'].update(visible=match_group(plugin['Group'], group_list))) # 刷新按钮
|
||||||
|
if plugin.get('AdvancedArgs', False): dropdown_fn_list.append(k) # 对于需要高级参数的插件,亦在下拉菜单中显示
|
||||||
|
elif match_group(plugin['Group'], group_list): fns_list.append(k) # 刷新下拉列表
|
||||||
|
return [*btn_list, gr.Dropdown.update(choices=fns_list)]
|
||||||
|
plugin_group_sel.select(fn=on_group_change, inputs=[plugin_group_sel], outputs=[*[plugin['Button'] for name, plugin in plugins_as_btn.items()], dropdown])
|
||||||
|
if ENABLE_AUDIO:
|
||||||
|
from crazy_functions.live_audio.audio_io import RealtimeAudioDistribution
|
||||||
|
rad = RealtimeAudioDistribution()
|
||||||
|
def deal_audio(audio, cookies):
|
||||||
|
rad.feed(cookies['uuid'].hex, audio)
|
||||||
|
audio_mic.stream(deal_audio, inputs=[audio_mic, cookies])
|
||||||
|
|
||||||
|
|
||||||
|
demo.load(init_cookie, inputs=[cookies], outputs=[cookies])
|
||||||
|
demo.load(persistent_cookie_reload, inputs = [py_pickle_cookie, cookies],
|
||||||
|
outputs = [py_pickle_cookie, cookies, *customize_btns.values(), *predefined_btns.values()], _js=js_code_for_persistent_cookie_init)
|
||||||
|
demo.load(None, inputs=[dark_mode], outputs=None, _js="""(dark_mode)=>{apply_cookie_for_checkbox(dark_mode);}""") # 配置暗色主题或亮色主题
|
||||||
|
demo.load(None, inputs=[gr.Textbox(LAYOUT, visible=False)], outputs=None, _js='(LAYOUT)=>{GptAcademicJavaScriptInit(LAYOUT);}')
|
||||||
|
|
||||||
|
# gradio的inbrowser触发不太稳定,回滚代码到原始的浏览器打开函数
|
||||||
|
def run_delayed_tasks():
|
||||||
|
import threading, webbrowser, time
|
||||||
|
print(f"如果浏览器没有自动打开,请复制并转到以下URL:")
|
||||||
|
if DARK_MODE: print(f"\t「暗色主题已启用(支持动态切换主题)」: http://localhost:{PORT}")
|
||||||
|
else: print(f"\t「亮色主题已启用(支持动态切换主题)」: http://localhost:{PORT}")
|
||||||
|
|
||||||
|
def auto_updates(): time.sleep(0); auto_update()
|
||||||
|
def open_browser(): time.sleep(2); webbrowser.open_new_tab(f"http://localhost:{PORT}")
|
||||||
|
def warm_up_mods(): time.sleep(6); warm_up_modules()
|
||||||
|
|
||||||
|
threading.Thread(target=auto_updates, name="self-upgrade", daemon=True).start() # 查看自动更新
|
||||||
|
threading.Thread(target=open_browser, name="open-browser", daemon=True).start() # 打开浏览器页面
|
||||||
|
threading.Thread(target=warm_up_mods, name="warm-up", daemon=True).start() # 预热tiktoken模块
|
||||||
|
|
||||||
|
run_delayed_tasks()
|
||||||
|
demo.queue(concurrency_count=CONCURRENT_COUNT).launch(server_name="0.0.0.0", share=False, favicon_path="docs/logo.png", blocked_paths=["config.py","config_private.py","docker-compose.yml","Dockerfile"])
|
||||||
|
|
||||||
|
|
||||||
|
# 如果需要在二级路径下运行
|
||||||
|
# CUSTOM_PATH = get_conf('CUSTOM_PATH')
|
||||||
|
# if CUSTOM_PATH != "/":
|
||||||
|
# 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__":
|
||||||
|
main()
|
||||||
@@ -1,44 +1,33 @@
|
|||||||
|
|
||||||
def check_proxy(proxies, return_ip=False):
|
def check_proxy(proxies):
|
||||||
import requests
|
import requests
|
||||||
proxies_https = proxies['https'] if proxies is not None else '无'
|
proxies_https = proxies['https'] if proxies is not None else '无'
|
||||||
ip = None
|
|
||||||
try:
|
try:
|
||||||
response = requests.get("https://ipapi.co/json/", proxies=proxies, timeout=4)
|
response = requests.get("https://ipapi.co/json/", proxies=proxies, timeout=4)
|
||||||
data = response.json()
|
data = response.json()
|
||||||
if 'country_name' in data:
|
if 'country_name' in data:
|
||||||
country = data['country_name']
|
country = data['country_name']
|
||||||
result = f"代理配置 {proxies_https}, 代理所在地:{country}"
|
result = f"代理配置 {proxies_https}, 代理所在地:{country}"
|
||||||
if 'ip' in data: ip = data['ip']
|
|
||||||
elif 'error' in data:
|
elif 'error' in data:
|
||||||
alternative, ip = _check_with_backup_source(proxies)
|
alternative = _check_with_backup_source(proxies)
|
||||||
if alternative is None:
|
if alternative is None:
|
||||||
result = f"代理配置 {proxies_https}, 代理所在地:未知,IP查询频率受限"
|
result = f"代理配置 {proxies_https}, 代理所在地:未知,IP查询频率受限"
|
||||||
else:
|
else:
|
||||||
result = f"代理配置 {proxies_https}, 代理所在地:{alternative}"
|
result = f"代理配置 {proxies_https}, 代理所在地:{alternative}"
|
||||||
else:
|
else:
|
||||||
result = f"代理配置 {proxies_https}, 代理数据解析失败:{data}"
|
result = f"代理配置 {proxies_https}, 代理数据解析失败:{data}"
|
||||||
if not return_ip:
|
|
||||||
print(result)
|
print(result)
|
||||||
return result
|
return result
|
||||||
else:
|
|
||||||
return ip
|
|
||||||
except:
|
except:
|
||||||
result = f"代理配置 {proxies_https}, 代理所在地查询超时,代理可能无效"
|
result = f"代理配置 {proxies_https}, 代理所在地查询超时,代理可能无效"
|
||||||
if not return_ip:
|
|
||||||
print(result)
|
print(result)
|
||||||
return result
|
return result
|
||||||
else:
|
|
||||||
return ip
|
|
||||||
|
|
||||||
def _check_with_backup_source(proxies):
|
def _check_with_backup_source(proxies):
|
||||||
import random, string, requests
|
import random, string, requests
|
||||||
random_string = ''.join(random.choices(string.ascii_letters + string.digits, k=32))
|
random_string = ''.join(random.choices(string.ascii_letters + string.digits, k=32))
|
||||||
try:
|
try: return requests.get(f"http://{random_string}.edns.ip-api.com/json", proxies=proxies, timeout=4).json()['dns']['geo']
|
||||||
res_json = requests.get(f"http://{random_string}.edns.ip-api.com/json", proxies=proxies, timeout=4).json()
|
except: return None
|
||||||
return res_json['dns']['geo'], res_json['dns']['ip']
|
|
||||||
except:
|
|
||||||
return None, None
|
|
||||||
|
|
||||||
def backup_and_download(current_version, remote_version):
|
def backup_and_download(current_version, remote_version):
|
||||||
"""
|
"""
|
||||||
@@ -58,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.agent-matrix.com/publish/master.zip', proxies=proxies, stream=True)
|
except: r = requests.get('https://public.gpt-academic.top/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)
|
||||||
@@ -82,7 +71,7 @@ def patch_and_restart(path):
|
|||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
import glob
|
import glob
|
||||||
from shared_utils.colorful import print亮黄, print亮绿, print亮红
|
from colorful import print亮黄, print亮绿, print亮红
|
||||||
# if not using config_private, move origin config.py as config_private.py
|
# if not using config_private, move origin config.py as config_private.py
|
||||||
if not os.path.exists('config_private.py'):
|
if not os.path.exists('config_private.py'):
|
||||||
print亮黄('由于您没有设置config_private.py私密配置,现将您的现有配置移动至config_private.py以防止配置丢失,',
|
print亮黄('由于您没有设置config_private.py私密配置,现将您的现有配置移动至config_private.py以防止配置丢失,',
|
||||||
@@ -124,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.agent-matrix.com/publish/version", proxies=proxies, timeout=5)
|
except: response = requests.get("https://public.gpt-academic.top/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"]:
|
||||||
@@ -135,7 +124,7 @@ def auto_update(raise_error=False):
|
|||||||
current_version = f.read()
|
current_version = f.read()
|
||||||
current_version = json.loads(current_version)['version']
|
current_version = json.loads(current_version)['version']
|
||||||
if (remote_version - current_version) >= 0.01-1e-5:
|
if (remote_version - current_version) >= 0.01-1e-5:
|
||||||
from shared_utils.colorful import print亮黄
|
from colorful import print亮黄
|
||||||
print亮黄(f'\n新版本可用。新版本:{remote_version},当前版本:{current_version}。{new_feature}')
|
print亮黄(f'\n新版本可用。新版本:{remote_version},当前版本:{current_version}。{new_feature}')
|
||||||
print('(1)Github更新地址:\nhttps://github.com/binary-husky/chatgpt_academic\n')
|
print('(1)Github更新地址:\nhttps://github.com/binary-husky/chatgpt_academic\n')
|
||||||
user_instruction = input('(2)是否一键更新代码(Y+回车=确认,输入其他/无输入+回车=不更新)?')
|
user_instruction = input('(2)是否一键更新代码(Y+回车=确认,输入其他/无输入+回车=不更新)?')
|
||||||
|
|||||||
149
config.py
149
config.py
@@ -11,6 +11,10 @@
|
|||||||
API_KEY = "此处填API密钥" # 可同时填写多个API-KEY,用英文逗号分割,例如API_KEY = "sk-openaikey1,sk-openaikey2,fkxxxx-api2dkey3,azure-apikey4"
|
API_KEY = "此处填API密钥" # 可同时填写多个API-KEY,用英文逗号分割,例如API_KEY = "sk-openaikey1,sk-openaikey2,fkxxxx-api2dkey3,azure-apikey4"
|
||||||
|
|
||||||
|
|
||||||
|
# [step 1]>> API_KEY = "sk-123456789xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx123456789"。极少数情况下,还需要填写组织(格式如org-123456789abcdefghijklmno的),请向下翻,找 API_ORG 设置项
|
||||||
|
API_KEY = "此处填API密钥" # 可同时填写多个API-KEY,用英文逗号分割,例如API_KEY = "sk-openaikey1,sk-openaikey2,fkxxxx-api2dkey3,azure-apikey4"
|
||||||
|
|
||||||
|
|
||||||
# [step 2]>> 改为True应用代理,如果直接在海外服务器部署,此处不修改;如果使用本地或无地域限制的大模型时,此处也不需要修改
|
# [step 2]>> 改为True应用代理,如果直接在海外服务器部署,此处不修改;如果使用本地或无地域限制的大模型时,此处也不需要修改
|
||||||
USE_PROXY = False
|
USE_PROXY = False
|
||||||
if USE_PROXY:
|
if USE_PROXY:
|
||||||
@@ -30,40 +34,11 @@ 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-4o", "gpt-4o-mini", "gpt-4-turbo", "gpt-4-turbo-2024-04-09",
|
|
||||||
"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-4v", "glm-3-turbo",
|
|
||||||
"gemini-pro", "chatglm3"
|
|
||||||
]
|
|
||||||
# --- --- --- ---
|
|
||||||
# P.S. 其他可用的模型还包括
|
|
||||||
# AVAIL_LLM_MODELS = [
|
|
||||||
# "glm-4-0520", "glm-4-air", "glm-4-airx", "glm-4-flash",
|
|
||||||
# "qianfan", "deepseekcoder",
|
|
||||||
# "spark", "sparkv2", "sparkv3", "sparkv3.5", "sparkv4",
|
|
||||||
# "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", "gpt-4o-2024-05-13"
|
|
||||||
# "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",
|
|
||||||
# "deepseek-chat" ,"deepseek-coder",
|
|
||||||
# "yi-34b-chat-0205","yi-34b-chat-200k","yi-large","yi-medium","yi-spark","yi-large-turbo","yi-large-preview",
|
|
||||||
# ]
|
|
||||||
# --- --- --- ---
|
|
||||||
# 此外,您还可以在接入one-api/vllm/ollama时,
|
|
||||||
# 使用"one-api-*","vllm-*","ollama-*"前缀直接使用非标准方式接入的模型,例如
|
|
||||||
# AVAIL_LLM_MODELS = ["one-api-claude-3-sonnet-20240229(max_token=100000)", "ollama-phi3(max_token=4096)"]
|
|
||||||
# --- --- --- ---
|
|
||||||
|
|
||||||
|
|
||||||
# --------------- 以下配置可以优化体验 ---------------
|
|
||||||
|
|
||||||
# 重新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"}
|
||||||
# 举例: API_URL_REDIRECT = {"https://api.openai.com/v1/chat/completions": "https://reverse-proxy-url/v1/chat/completions", "http://localhost:11434/api/chat": "在这里填写您ollama的URL"}
|
# 举例: API_URL_REDIRECT = {"https://api.openai.com/v1/chat/completions": "https://reverse-proxy-url/v1/chat/completions"}
|
||||||
API_URL_REDIRECT = {}
|
API_URL_REDIRECT = {}
|
||||||
|
|
||||||
|
|
||||||
@@ -74,7 +49,7 @@ DEFAULT_WORKER_NUM = 3
|
|||||||
|
|
||||||
# 色彩主题, 可选 ["Default", "Chuanhu-Small-and-Beautiful", "High-Contrast"]
|
# 色彩主题, 可选 ["Default", "Chuanhu-Small-and-Beautiful", "High-Contrast"]
|
||||||
# 更多主题, 请查阅Gradio主题商店: https://huggingface.co/spaces/gradio/theme-gallery 可选 ["Gstaff/Xkcd", "NoCrypt/Miku", ...]
|
# 更多主题, 请查阅Gradio主题商店: https://huggingface.co/spaces/gradio/theme-gallery 可选 ["Gstaff/Xkcd", "NoCrypt/Miku", ...]
|
||||||
THEME = "Default"
|
THEME = "Chuanhu-Small-and-Beautiful"
|
||||||
AVAIL_THEMES = ["Default", "Chuanhu-Small-and-Beautiful", "High-Contrast", "Gstaff/Xkcd", "NoCrypt/Miku"]
|
AVAIL_THEMES = ["Default", "Chuanhu-Small-and-Beautiful", "High-Contrast", "Gstaff/Xkcd", "NoCrypt/Miku"]
|
||||||
|
|
||||||
|
|
||||||
@@ -95,7 +70,7 @@ LAYOUT = "LEFT-RIGHT" # "LEFT-RIGHT"(左右布局) # "TOP-DOWN"(上下
|
|||||||
|
|
||||||
|
|
||||||
# 暗色模式 / 亮色模式
|
# 暗色模式 / 亮色模式
|
||||||
DARK_MODE = True
|
DARK_MODE = False
|
||||||
|
|
||||||
|
|
||||||
# 发送请求到OpenAI后,等待多久判定为超时
|
# 发送请求到OpenAI后,等待多久判定为超时
|
||||||
@@ -106,18 +81,31 @@ TIMEOUT_SECONDS = 30
|
|||||||
WEB_PORT = -1
|
WEB_PORT = -1
|
||||||
|
|
||||||
|
|
||||||
# 是否自动打开浏览器页面
|
|
||||||
AUTO_OPEN_BROWSER = True
|
|
||||||
|
|
||||||
|
|
||||||
# 如果OpenAI不响应(网络卡顿、代理失败、KEY失效),重试的次数限制
|
# 如果OpenAI不响应(网络卡顿、代理失败、KEY失效),重试的次数限制
|
||||||
MAX_RETRY = 2
|
MAX_RETRY = 2
|
||||||
|
|
||||||
|
# OpenAI模型选择是(gpt4现在只对申请成功的人开放)
|
||||||
|
LLM_MODEL = "gpt-3.5-turbo" # 可选 "chatglm"
|
||||||
|
AVAIL_LLM_MODELS = ["gpt-3.5-turbo", "gpt-4", "api2d-gpt-4", "api2d-gpt-3.5-turbo", "spark", "azure-gpt-3.5"]
|
||||||
|
|
||||||
# 插件分类默认选项
|
# 插件分类默认选项
|
||||||
DEFAULT_FN_GROUPS = ['对话', '编程', '学术', '智能体']
|
DEFAULT_FN_GROUPS = ['对话', '编程', '学术', '智能体']
|
||||||
|
|
||||||
|
|
||||||
|
# 模型选择是 (注意: LLM_MODEL是默认选中的模型, 它*必须*被包含在AVAIL_LLM_MODELS列表中 )
|
||||||
|
LLM_MODEL = "gpt-3.5-turbo-16k" # 可选 ↓↓↓
|
||||||
|
AVAIL_LLM_MODELS = ["gpt-4-1106-preview", "gpt-4-turbo-preview", "gpt-4-vision-preview",
|
||||||
|
"gpt-3.5-turbo-1106", "gpt-3.5-turbo-16k", "gpt-3.5-turbo", "azure-gpt-3.5",
|
||||||
|
"gpt-4", "gpt-4-32k", "azure-gpt-4", "glm-4", "glm-3-turbo",
|
||||||
|
"gemini-pro", "chatglm3", "claude-2"]
|
||||||
|
# P.S. 其他可用的模型还包括 [
|
||||||
|
# "moss", "qwen-turbo", "qwen-plus", "qwen-max"
|
||||||
|
# "zhipuai", "qianfan", "deepseekcoder", "llama2", "qwen-local", "gpt-3.5-turbo-0613",
|
||||||
|
# "gpt-3.5-turbo-16k-0613", "gpt-3.5-random", "api2d-gpt-3.5-turbo", 'api2d-gpt-3.5-turbo-16k',
|
||||||
|
# "spark", "sparkv2", "sparkv3", "chatglm_onnx", "claude-1-100k", "claude-2", "internlm", "jittorllms_pangualpha", "jittorllms_llama"
|
||||||
|
# ]
|
||||||
|
|
||||||
|
|
||||||
# 定义界面上“询问多个GPT模型”插件应该使用哪些模型,请从AVAIL_LLM_MODELS中选择,并在不同模型之间用`&`间隔,例如"gpt-3.5-turbo&chatglm3&azure-gpt-4"
|
# 定义界面上“询问多个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"
|
||||||
|
|
||||||
@@ -135,7 +123,7 @@ DASHSCOPE_API_KEY = "" # 阿里灵积云API_KEY
|
|||||||
# 百度千帆(LLM_MODEL="qianfan")
|
# 百度千帆(LLM_MODEL="qianfan")
|
||||||
BAIDU_CLOUD_API_KEY = ''
|
BAIDU_CLOUD_API_KEY = ''
|
||||||
BAIDU_CLOUD_SECRET_KEY = ''
|
BAIDU_CLOUD_SECRET_KEY = ''
|
||||||
BAIDU_CLOUD_QIANFAN_MODEL = 'ERNIE-Bot' # 可选 "ERNIE-Bot-4"(文心大模型4.0), "ERNIE-Bot"(文心一言), "ERNIE-Bot-turbo", "BLOOMZ-7B", "Llama-2-70B-Chat", "Llama-2-13B-Chat", "Llama-2-7B-Chat", "ERNIE-Speed-128K", "ERNIE-Speed-8K", "ERNIE-Lite-8K"
|
BAIDU_CLOUD_QIANFAN_MODEL = 'ERNIE-Bot' # 可选 "ERNIE-Bot-4"(文心大模型4.0), "ERNIE-Bot"(文心一言), "ERNIE-Bot-turbo", "BLOOMZ-7B", "Llama-2-70B-Chat", "Llama-2-13B-Chat", "Llama-2-7B-Chat"
|
||||||
|
|
||||||
|
|
||||||
# 如果使用ChatGLM2微调模型,请把 LLM_MODEL="chatglmft",并在此处指定模型路径
|
# 如果使用ChatGLM2微调模型,请把 LLM_MODEL="chatglmft",并在此处指定模型路径
|
||||||
@@ -146,7 +134,6 @@ 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
|
||||||
|
|
||||||
@@ -156,7 +143,7 @@ AUTO_CLEAR_TXT = False
|
|||||||
|
|
||||||
|
|
||||||
# 加一个live2d装饰
|
# 加一个live2d装饰
|
||||||
ADD_WAIFU = False
|
ADD_WAIFU = True
|
||||||
|
|
||||||
|
|
||||||
# 设置用户名和密码(不需要修改)(相关功能不稳定,与gradio版本和网络都相关,如果本地使用不建议加这个)
|
# 设置用户名和密码(不需要修改)(相关功能不稳定,与gradio版本和网络都相关,如果本地使用不建议加这个)
|
||||||
@@ -164,8 +151,7 @@ ADD_WAIFU = False
|
|||||||
AUTHENTICATION = []
|
AUTHENTICATION = []
|
||||||
|
|
||||||
|
|
||||||
# 如果需要在二级路径下运行(常规情况下,不要修改!!)
|
# 如果需要在二级路径下运行(常规情况下,不要修改!!)(需要配合修改main.py才能生效!)
|
||||||
# (举例 CUSTOM_PATH = "/gpt_academic",可以让软件运行在 http://ip:port/gpt_academic/ 下。)
|
|
||||||
CUSTOM_PATH = "/"
|
CUSTOM_PATH = "/"
|
||||||
|
|
||||||
|
|
||||||
@@ -193,8 +179,14 @@ AZURE_ENGINE = "填入你亲手写的部署名" # 读 docs\use_azure.
|
|||||||
AZURE_CFG_ARRAY = {}
|
AZURE_CFG_ARRAY = {}
|
||||||
|
|
||||||
|
|
||||||
# 阿里云实时语音识别 配置难度较高
|
# 使用Newbing (不推荐使用,未来将删除)
|
||||||
# 参考 https://github.com/binary-husky/gpt_academic/blob/master/docs/use_audio.md
|
NEWBING_STYLE = "creative" # ["creative", "balanced", "precise"]
|
||||||
|
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
|
||||||
@@ -202,12 +194,6 @@ ALIYUN_ACCESSKEY="" # (无需填写)
|
|||||||
ALIYUN_SECRET="" # (无需填写)
|
ALIYUN_SECRET="" # (无需填写)
|
||||||
|
|
||||||
|
|
||||||
# GPT-SOVITS 文本转语音服务的运行地址(将语言模型的生成文本朗读出来)
|
|
||||||
TTS_TYPE = "EDGE_TTS" # EDGE_TTS / LOCAL_SOVITS_API / DISABLE
|
|
||||||
GPT_SOVITS_URL = ""
|
|
||||||
EDGE_TTS_VOICE = "zh-CN-XiaoxiaoNeural"
|
|
||||||
|
|
||||||
|
|
||||||
# 接入讯飞星火大模型 https://console.xfyun.cn/services/iat
|
# 接入讯飞星火大模型 https://console.xfyun.cn/services/iat
|
||||||
XFYUN_APPID = "00000000"
|
XFYUN_APPID = "00000000"
|
||||||
XFYUN_API_SECRET = "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
|
XFYUN_API_SECRET = "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
|
||||||
@@ -219,35 +205,21 @@ 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 = ""
|
|
||||||
|
|
||||||
|
|
||||||
# 深度求索(DeepSeek) API KEY,默认请求地址为"https://api.deepseek.com/v1/chat/completions"
|
|
||||||
DEEPSEEK_API_KEY = ""
|
|
||||||
|
|
||||||
|
|
||||||
# 紫东太初大模型 https://ai-maas.wair.ac.cn
|
|
||||||
TAICHU_API_KEY = ""
|
|
||||||
|
|
||||||
|
|
||||||
# Mathpix 拥有执行PDF的OCR功能,但是需要注册账号
|
# Mathpix 拥有执行PDF的OCR功能,但是需要注册账号
|
||||||
MATHPIX_APPID = ""
|
MATHPIX_APPID = ""
|
||||||
MATHPIX_APPKEY = ""
|
MATHPIX_APPKEY = ""
|
||||||
|
|
||||||
|
|
||||||
# DOC2X的PDF解析服务,注册账号并获取API KEY: https://doc2x.noedgeai.com/login
|
|
||||||
DOC2X_API_KEY = ""
|
|
||||||
|
|
||||||
|
|
||||||
# 自定义API KEY格式
|
# 自定义API KEY格式
|
||||||
CUSTOM_API_KEY_PATTERN = ""
|
CUSTOM_API_KEY_PATTERN = ""
|
||||||
|
|
||||||
@@ -269,10 +241,6 @@ GROBID_URLS = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
# Searxng互联网检索服务
|
|
||||||
SEARXNG_URL = "https://cloud-1.agent-matrix.com/"
|
|
||||||
|
|
||||||
|
|
||||||
# 是否允许通过自然语言描述修改本页的配置,该功能具有一定的危险性,默认关闭
|
# 是否允许通过自然语言描述修改本页的配置,该功能具有一定的危险性,默认关闭
|
||||||
ALLOW_RESET_CONFIG = False
|
ALLOW_RESET_CONFIG = False
|
||||||
|
|
||||||
@@ -281,23 +249,23 @@ ALLOW_RESET_CONFIG = False
|
|||||||
AUTOGEN_USE_DOCKER = False
|
AUTOGEN_USE_DOCKER = False
|
||||||
|
|
||||||
|
|
||||||
# 临时的上传文件夹位置,请尽量不要修改
|
# 临时的上传文件夹位置,请勿修改
|
||||||
PATH_PRIVATE_UPLOAD = "private_upload"
|
PATH_PRIVATE_UPLOAD = "private_upload"
|
||||||
|
|
||||||
|
|
||||||
# 日志文件夹的位置,请尽量不要修改
|
# 日志文件夹的位置,请勿修改
|
||||||
PATH_LOGGING = "gpt_log"
|
PATH_LOGGING = "gpt_log"
|
||||||
|
|
||||||
|
|
||||||
# 存储翻译好的arxiv论文的路径,请尽量不要修改
|
# 除了连接OpenAI之外,还有哪些场合允许使用代理,请勿修改
|
||||||
ARXIV_CACHE_DIR = "gpt_log/arxiv_cache"
|
|
||||||
|
|
||||||
|
|
||||||
# 除了连接OpenAI之外,还有哪些场合允许使用代理,请尽量不要修改
|
|
||||||
WHEN_TO_USE_PROXY = ["Download_LLM", "Download_Gradio_Theme", "Connect_Grobid",
|
WHEN_TO_USE_PROXY = ["Download_LLM", "Download_Gradio_Theme", "Connect_Grobid",
|
||||||
"Warmup_Modules", "Nougat_Download", "AutoGen"]
|
"Warmup_Modules", "Nougat_Download", "AutoGen"]
|
||||||
|
|
||||||
|
|
||||||
|
# *实验性功能*: 自动检测并屏蔽失效的KEY,请勿使用
|
||||||
|
BLOCK_INVALID_APIKEY = False
|
||||||
|
|
||||||
|
|
||||||
# 启用插件热加载
|
# 启用插件热加载
|
||||||
PLUGIN_HOT_RELOAD = False
|
PLUGIN_HOT_RELOAD = False
|
||||||
|
|
||||||
@@ -305,11 +273,7 @@ PLUGIN_HOT_RELOAD = False
|
|||||||
# 自定义按钮的最大数量限制
|
# 自定义按钮的最大数量限制
|
||||||
NUM_CUSTOM_BASIC_BTN = 4
|
NUM_CUSTOM_BASIC_BTN = 4
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
--------------- 配置关联关系说明 ---------------
|
|
||||||
|
|
||||||
在线大模型配置关联关系示意图
|
在线大模型配置关联关系示意图
|
||||||
│
|
│
|
||||||
├── "gpt-3.5-turbo" 等openai模型
|
├── "gpt-3.5-turbo" 等openai模型
|
||||||
@@ -333,7 +297,7 @@ NUM_CUSTOM_BASIC_BTN = 4
|
|||||||
│ ├── XFYUN_API_SECRET
|
│ ├── XFYUN_API_SECRET
|
||||||
│ └── XFYUN_API_KEY
|
│ └── XFYUN_API_KEY
|
||||||
│
|
│
|
||||||
├── "claude-3-opus-20240229" 等claude模型
|
├── "claude-1-100k" 等claude模型
|
||||||
│ └── ANTHROPIC_API_KEY
|
│ └── ANTHROPIC_API_KEY
|
||||||
│
|
│
|
||||||
├── "stack-claude"
|
├── "stack-claude"
|
||||||
@@ -348,19 +312,15 @@ 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
|
||||||
│
|
│
|
||||||
└── "one-api-...(max_token=...)" 用一种更方便的方式接入one-api多模型管理界面
|
└── "newbing" Newbing接口不再稳定,不推荐使用
|
||||||
├── AVAIL_LLM_MODELS
|
├── NEWBING_STYLE
|
||||||
├── API_KEY
|
└── NEWBING_COOKIES
|
||||||
└── API_URL_REDIRECT
|
|
||||||
|
|
||||||
|
|
||||||
本地大模型示意图
|
本地大模型示意图
|
||||||
@@ -394,9 +354,6 @@ NUM_CUSTOM_BASIC_BTN = 4
|
|||||||
|
|
||||||
插件在线服务配置依赖关系示意图
|
插件在线服务配置依赖关系示意图
|
||||||
│
|
│
|
||||||
├── 互联网检索
|
|
||||||
│ └── SEARXNG_URL
|
|
||||||
│
|
|
||||||
├── 语音功能
|
├── 语音功能
|
||||||
│ ├── ENABLE_AUDIO
|
│ ├── ENABLE_AUDIO
|
||||||
│ ├── ALIYUN_TOKEN
|
│ ├── ALIYUN_TOKEN
|
||||||
|
|||||||
@@ -33,19 +33,17 @@ def get_core_functions():
|
|||||||
"AutoClearHistory": False,
|
"AutoClearHistory": False,
|
||||||
# [6] 文本预处理 (可选参数,默认 None,举例:写个函数移除所有的换行符)
|
# [6] 文本预处理 (可选参数,默认 None,举例:写个函数移除所有的换行符)
|
||||||
"PreProcess": None,
|
"PreProcess": None,
|
||||||
# [7] 模型选择 (可选参数。如不设置,则使用当前全局模型;如设置,则用指定模型覆盖全局模型。)
|
|
||||||
# "ModelOverride": "gpt-3.5-turbo", # 主要用途:强制点击此基础功能按钮时,使用指定的模型。
|
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
"总结绘制脑图": {
|
"总结绘制脑图": {
|
||||||
# 前缀,会被加在你的输入之前。例如,用来描述你的要求,例如翻译、解释代码、润色等等
|
# 前缀,会被加在你的输入之前。例如,用来描述你的要求,例如翻译、解释代码、润色等等
|
||||||
"Prefix": '''"""\n\n''',
|
"Prefix": r"",
|
||||||
# 后缀,会被加在你的输入之后。例如,配合前缀可以把你的输入内容用引号圈起来
|
# 后缀,会被加在你的输入之后。例如,配合前缀可以把你的输入内容用引号圈起来
|
||||||
"Suffix":
|
"Suffix":
|
||||||
# dedent() 函数用于去除多行字符串的缩进
|
# dedent() 函数用于去除多行字符串的缩进
|
||||||
dedent("\n\n"+r'''
|
dedent("\n"+r'''
|
||||||
"""
|
==============================
|
||||||
|
|
||||||
使用mermaid flowchart对以上文本进行总结,概括上述段落的内容以及内在逻辑关系,例如:
|
使用mermaid flowchart对以上文本进行总结,概括上述段落的内容以及内在逻辑关系,例如:
|
||||||
|
|
||||||
@@ -59,7 +57,7 @@ def get_core_functions():
|
|||||||
C --> |"箭头名2"| F["节点名6"]
|
C --> |"箭头名2"| F["节点名6"]
|
||||||
```
|
```
|
||||||
|
|
||||||
注意:
|
警告:
|
||||||
(1)使用中文
|
(1)使用中文
|
||||||
(2)节点名字使用引号包裹,如["Laptop"]
|
(2)节点名字使用引号包裹,如["Laptop"]
|
||||||
(3)`|` 和 `"`之间不要存在空格
|
(3)`|` 和 `"`之间不要存在空格
|
||||||
|
|||||||
@@ -5,56 +5,42 @@ from toolbox import trimmed_format_exc
|
|||||||
def get_crazy_functions():
|
def get_crazy_functions():
|
||||||
from crazy_functions.读文章写摘要 import 读文章写摘要
|
from crazy_functions.读文章写摘要 import 读文章写摘要
|
||||||
from crazy_functions.生成函数注释 import 批量生成函数注释
|
from crazy_functions.生成函数注释 import 批量生成函数注释
|
||||||
from crazy_functions.SourceCode_Analyse import 解析项目本身
|
from crazy_functions.解析项目源代码 import 解析项目本身
|
||||||
from crazy_functions.SourceCode_Analyse import 解析一个Python项目
|
from crazy_functions.解析项目源代码 import 解析一个Python项目
|
||||||
from crazy_functions.SourceCode_Analyse import 解析一个Matlab项目
|
from crazy_functions.解析项目源代码 import 解析一个Matlab项目
|
||||||
from crazy_functions.SourceCode_Analyse import 解析一个C项目的头文件
|
from crazy_functions.解析项目源代码 import 解析一个C项目的头文件
|
||||||
from crazy_functions.SourceCode_Analyse import 解析一个C项目
|
from crazy_functions.解析项目源代码 import 解析一个C项目
|
||||||
from crazy_functions.SourceCode_Analyse import 解析一个Golang项目
|
from crazy_functions.解析项目源代码 import 解析一个Golang项目
|
||||||
from crazy_functions.SourceCode_Analyse import 解析一个Rust项目
|
from crazy_functions.解析项目源代码 import 解析一个Rust项目
|
||||||
from crazy_functions.SourceCode_Analyse import 解析一个Java项目
|
from crazy_functions.解析项目源代码 import 解析一个Java项目
|
||||||
from crazy_functions.SourceCode_Analyse import 解析一个前端项目
|
from crazy_functions.解析项目源代码 import 解析一个前端项目
|
||||||
from crazy_functions.高级功能函数模板 import 高阶功能模板函数
|
from crazy_functions.高级功能函数模板 import 高阶功能模板函数
|
||||||
from crazy_functions.高级功能函数模板 import Demo_Wrap
|
|
||||||
from crazy_functions.Latex全文润色 import Latex英文润色
|
from crazy_functions.Latex全文润色 import Latex英文润色
|
||||||
from crazy_functions.询问多个大语言模型 import 同时问询
|
from crazy_functions.询问多个大语言模型 import 同时问询
|
||||||
from crazy_functions.SourceCode_Analyse import 解析一个Lua项目
|
from crazy_functions.解析项目源代码 import 解析一个Lua项目
|
||||||
from crazy_functions.SourceCode_Analyse import 解析一个CSharp项目
|
from crazy_functions.解析项目源代码 import 解析一个CSharp项目
|
||||||
from crazy_functions.总结word文档 import 总结word文档
|
from crazy_functions.总结word文档 import 总结word文档
|
||||||
from crazy_functions.解析JupyterNotebook import 解析ipynb文件
|
from crazy_functions.解析JupyterNotebook import 解析ipynb文件
|
||||||
from crazy_functions.Conversation_To_File import 载入对话历史存档
|
from crazy_functions.对话历史存档 import 对话历史存档
|
||||||
from crazy_functions.Conversation_To_File import 对话历史存档
|
from crazy_functions.对话历史存档 import 载入对话历史存档
|
||||||
from crazy_functions.Conversation_To_File import Conversation_To_File_Wrap
|
from crazy_functions.对话历史存档 import 删除所有本地对话历史记录
|
||||||
from crazy_functions.Conversation_To_File import 删除所有本地对话历史记录
|
|
||||||
from crazy_functions.辅助功能 import 清除缓存
|
from crazy_functions.辅助功能 import 清除缓存
|
||||||
from crazy_functions.Markdown_Translate import Markdown英译中
|
from crazy_functions.批量Markdown翻译 import Markdown英译中
|
||||||
from crazy_functions.批量总结PDF文档 import 批量总结PDF文档
|
from crazy_functions.批量总结PDF文档 import 批量总结PDF文档
|
||||||
from crazy_functions.PDF_Translate import 批量翻译PDF文档
|
from crazy_functions.批量翻译PDF文档_多线程 import 批量翻译PDF文档
|
||||||
from crazy_functions.谷歌检索小助手 import 谷歌检索小助手
|
from crazy_functions.谷歌检索小助手 import 谷歌检索小助手
|
||||||
from crazy_functions.理解PDF文档内容 import 理解PDF文档内容标准文件输入
|
from crazy_functions.理解PDF文档内容 import 理解PDF文档内容标准文件输入
|
||||||
from crazy_functions.Latex全文润色 import Latex中文润色
|
from crazy_functions.Latex全文润色 import Latex中文润色
|
||||||
from crazy_functions.Latex全文润色 import Latex英文纠错
|
from crazy_functions.Latex全文润色 import Latex英文纠错
|
||||||
from crazy_functions.Markdown_Translate import Markdown中译英
|
from crazy_functions.批量Markdown翻译 import Markdown中译英
|
||||||
from crazy_functions.虚空终端 import 虚空终端
|
from crazy_functions.虚空终端 import 虚空终端
|
||||||
from crazy_functions.生成多种Mermaid图表 import Mermaid_Gen
|
from crazy_functions.生成多种Mermaid图表 import 生成多种Mermaid图表
|
||||||
from crazy_functions.PDF_Translate_Wrap import PDF_Tran
|
|
||||||
from crazy_functions.Latex_Function import Latex英文纠错加PDF对比
|
|
||||||
from crazy_functions.Latex_Function import Latex翻译中文并重新编译PDF
|
|
||||||
from crazy_functions.Latex_Function import PDF翻译中文并重新编译PDF
|
|
||||||
from crazy_functions.Latex_Function_Wrap import Arxiv_Localize
|
|
||||||
from crazy_functions.Latex_Function_Wrap import PDF_Localize
|
|
||||||
from crazy_functions.Internet_GPT import 连接网络回答问题
|
|
||||||
from crazy_functions.Internet_GPT_Wrap import NetworkGPT_Wrap
|
|
||||||
from crazy_functions.Image_Generate import 图片生成_DALLE2, 图片生成_DALLE3, 图片修改_DALLE2
|
|
||||||
from crazy_functions.Image_Generate_Wrap import ImageGen_Wrap
|
|
||||||
from crazy_functions.SourceCode_Comment import 注释Python项目
|
|
||||||
|
|
||||||
function_plugins = {
|
function_plugins = {
|
||||||
"虚空终端": {
|
"虚空终端": {
|
||||||
"Group": "对话|编程|学术|智能体",
|
"Group": "对话|编程|学术|智能体",
|
||||||
"Color": "stop",
|
"Color": "stop",
|
||||||
"AsButton": True,
|
"AsButton": True,
|
||||||
"Info": "使用自然语言实现您的想法",
|
|
||||||
"Function": HotReload(虚空终端),
|
"Function": HotReload(虚空终端),
|
||||||
},
|
},
|
||||||
"解析整个Python项目": {
|
"解析整个Python项目": {
|
||||||
@@ -64,13 +50,6 @@ def get_crazy_functions():
|
|||||||
"Info": "解析一个Python项目的所有源文件(.py) | 输入参数为路径",
|
"Info": "解析一个Python项目的所有源文件(.py) | 输入参数为路径",
|
||||||
"Function": HotReload(解析一个Python项目),
|
"Function": HotReload(解析一个Python项目),
|
||||||
},
|
},
|
||||||
"注释Python项目": {
|
|
||||||
"Group": "编程",
|
|
||||||
"Color": "stop",
|
|
||||||
"AsButton": False,
|
|
||||||
"Info": "上传一系列python源文件(或者压缩包), 为这些代码添加docstring | 输入参数为路径",
|
|
||||||
"Function": HotReload(注释Python项目),
|
|
||||||
},
|
|
||||||
"载入对话历史存档(先上传存档或输入路径)": {
|
"载入对话历史存档(先上传存档或输入路径)": {
|
||||||
"Group": "对话",
|
"Group": "对话",
|
||||||
"Color": "stop",
|
"Color": "stop",
|
||||||
@@ -96,21 +75,14 @@ def get_crazy_functions():
|
|||||||
"Color": "stop",
|
"Color": "stop",
|
||||||
"AsButton": False,
|
"AsButton": False,
|
||||||
"Info" : "基于当前对话或文件生成多种Mermaid图表,图表类型由模型判断",
|
"Info" : "基于当前对话或文件生成多种Mermaid图表,图表类型由模型判断",
|
||||||
"Function": None,
|
"Function": HotReload(生成多种Mermaid图表),
|
||||||
"Class": Mermaid_Gen
|
"AdvancedArgs": True,
|
||||||
},
|
"ArgsReminder": "请输入图类型对应的数字,不输入则为模型自行判断:1-流程图,2-序列图,3-类图,4-饼图,5-甘特图,6-状态图,7-实体关系图,8-象限提示图,9-思维导图",
|
||||||
"Arxiv论文翻译": {
|
|
||||||
"Group": "学术",
|
|
||||||
"Color": "stop",
|
|
||||||
"AsButton": True,
|
|
||||||
"Info": "Arixv论文精细翻译 | 输入参数arxiv论文的ID,比如1812.10695",
|
|
||||||
"Function": HotReload(Latex翻译中文并重新编译PDF), # 当注册Class后,Function旧接口仅会在“虚空终端”中起作用
|
|
||||||
"Class": Arxiv_Localize, # 新一代插件需要注册Class
|
|
||||||
},
|
},
|
||||||
"批量总结Word文档": {
|
"批量总结Word文档": {
|
||||||
"Group": "学术",
|
"Group": "学术",
|
||||||
"Color": "stop",
|
"Color": "stop",
|
||||||
"AsButton": False,
|
"AsButton": True,
|
||||||
"Info": "批量总结word文档 | 输入参数为路径",
|
"Info": "批量总结word文档 | 输入参数为路径",
|
||||||
"Function": HotReload(总结word文档),
|
"Function": HotReload(总结word文档),
|
||||||
},
|
},
|
||||||
@@ -216,42 +188,28 @@ def get_crazy_functions():
|
|||||||
},
|
},
|
||||||
"保存当前的对话": {
|
"保存当前的对话": {
|
||||||
"Group": "对话",
|
"Group": "对话",
|
||||||
"Color": "stop",
|
|
||||||
"AsButton": True,
|
"AsButton": True,
|
||||||
"Info": "保存当前的对话 | 不需要输入参数",
|
"Info": "保存当前的对话 | 不需要输入参数",
|
||||||
"Function": HotReload(对话历史存档), # 当注册Class后,Function旧接口仅会在“虚空终端”中起作用
|
"Function": HotReload(对话历史存档),
|
||||||
"Class": Conversation_To_File_Wrap # 新一代插件需要注册Class
|
|
||||||
},
|
},
|
||||||
"[多线程Demo]解析此项目本身(源码自译解)": {
|
"[多线程Demo]解析此项目本身(源码自译解)": {
|
||||||
"Group": "对话|编程",
|
"Group": "对话|编程",
|
||||||
"Color": "stop",
|
|
||||||
"AsButton": False, # 加入下拉菜单中
|
"AsButton": False, # 加入下拉菜单中
|
||||||
"Info": "多线程解析并翻译此项目的源码 | 不需要输入参数",
|
"Info": "多线程解析并翻译此项目的源码 | 不需要输入参数",
|
||||||
"Function": HotReload(解析项目本身),
|
"Function": HotReload(解析项目本身),
|
||||||
},
|
},
|
||||||
"查互联网后回答": {
|
|
||||||
"Group": "对话",
|
|
||||||
"Color": "stop",
|
|
||||||
"AsButton": True, # 加入下拉菜单中
|
|
||||||
# "Info": "连接网络回答问题(需要访问谷歌)| 输入参数是一个问题",
|
|
||||||
"Function": HotReload(连接网络回答问题),
|
|
||||||
"Class": NetworkGPT_Wrap # 新一代插件需要注册Class
|
|
||||||
},
|
|
||||||
"历史上的今天": {
|
"历史上的今天": {
|
||||||
"Group": "对话",
|
"Group": "对话",
|
||||||
"Color": "stop",
|
"AsButton": True,
|
||||||
"AsButton": False,
|
|
||||||
"Info": "查看历史上的今天事件 (这是一个面向开发者的插件Demo) | 不需要输入参数",
|
"Info": "查看历史上的今天事件 (这是一个面向开发者的插件Demo) | 不需要输入参数",
|
||||||
"Function": None,
|
"Function": HotReload(高阶功能模板函数),
|
||||||
"Class": Demo_Wrap, # 新一代插件需要注册Class
|
|
||||||
},
|
},
|
||||||
"精准翻译PDF论文": {
|
"精准翻译PDF论文": {
|
||||||
"Group": "学术",
|
"Group": "学术",
|
||||||
"Color": "stop",
|
"Color": "stop",
|
||||||
"AsButton": True,
|
"AsButton": True,
|
||||||
"Info": "精准翻译PDF论文为中文 | 输入参数为路径",
|
"Info": "精准翻译PDF论文为中文 | 输入参数为路径",
|
||||||
"Function": HotReload(批量翻译PDF文档), # 当注册Class后,Function旧接口仅会在“虚空终端”中起作用
|
"Function": HotReload(批量翻译PDF文档),
|
||||||
"Class": PDF_Tran, # 新一代插件需要注册Class
|
|
||||||
},
|
},
|
||||||
"询问多个GPT模型": {
|
"询问多个GPT模型": {
|
||||||
"Group": "对话",
|
"Group": "对话",
|
||||||
@@ -326,84 +284,7 @@ def get_crazy_functions():
|
|||||||
"Info": "批量将Markdown文件中文翻译为英文 | 输入参数为路径或上传压缩包",
|
"Info": "批量将Markdown文件中文翻译为英文 | 输入参数为路径或上传压缩包",
|
||||||
"Function": HotReload(Markdown中译英),
|
"Function": HotReload(Markdown中译英),
|
||||||
},
|
},
|
||||||
"Latex英文纠错+高亮修正位置 [需Latex]": {
|
|
||||||
"Group": "学术",
|
|
||||||
"Color": "stop",
|
|
||||||
"AsButton": False,
|
|
||||||
"AdvancedArgs": True,
|
|
||||||
"ArgsReminder": "如果有必要, 请在此处追加更细致的矫错指令(使用英文)。",
|
|
||||||
"Function": HotReload(Latex英文纠错加PDF对比),
|
|
||||||
},
|
|
||||||
"📚Arxiv论文精细翻译(输入arxivID)[需Latex]": {
|
|
||||||
"Group": "学术",
|
|
||||||
"Color": "stop",
|
|
||||||
"AsButton": False,
|
|
||||||
"AdvancedArgs": True,
|
|
||||||
"ArgsReminder": r"如果有必要, 请在此处给出自定义翻译命令, 解决部分词汇翻译不准确的问题。 "
|
|
||||||
r"例如当单词'agent'翻译不准确时, 请尝试把以下指令复制到高级参数区: "
|
|
||||||
r'If the term "agent" is used in this section, it should be translated to "智能体". ',
|
|
||||||
"Info": "Arixv论文精细翻译 | 输入参数arxiv论文的ID,比如1812.10695",
|
|
||||||
"Function": HotReload(Latex翻译中文并重新编译PDF), # 当注册Class后,Function旧接口仅会在“虚空终端”中起作用
|
|
||||||
"Class": Arxiv_Localize, # 新一代插件需要注册Class
|
|
||||||
},
|
|
||||||
"📚本地Latex论文精细翻译(上传Latex项目)[需Latex]": {
|
|
||||||
"Group": "学术",
|
|
||||||
"Color": "stop",
|
|
||||||
"AsButton": False,
|
|
||||||
"AdvancedArgs": True,
|
|
||||||
"ArgsReminder": r"如果有必要, 请在此处给出自定义翻译命令, 解决部分词汇翻译不准确的问题。 "
|
|
||||||
r"例如当单词'agent'翻译不准确时, 请尝试把以下指令复制到高级参数区: "
|
|
||||||
r'If the term "agent" is used in this section, it should be translated to "智能体". ',
|
|
||||||
"Info": "本地Latex论文精细翻译 | 输入参数是路径",
|
|
||||||
"Function": HotReload(Latex翻译中文并重新编译PDF),
|
|
||||||
},
|
|
||||||
"PDF翻译中文并重新编译PDF(上传PDF)[需Latex]": {
|
|
||||||
"Group": "学术",
|
|
||||||
"Color": "stop",
|
|
||||||
"AsButton": False,
|
|
||||||
"AdvancedArgs": True,
|
|
||||||
"ArgsReminder": r"如果有必要, 请在此处给出自定义翻译命令, 解决部分词汇翻译不准确的问题。 "
|
|
||||||
r"例如当单词'agent'翻译不准确时, 请尝试把以下指令复制到高级参数区: "
|
|
||||||
r'If the term "agent" is used in this section, it should be translated to "智能体". ',
|
|
||||||
"Info": "PDF翻译中文,并重新编译PDF | 输入参数为路径",
|
|
||||||
"Function": HotReload(PDF翻译中文并重新编译PDF), # 当注册Class后,Function旧接口仅会在“虚空终端”中起作用
|
|
||||||
"Class": PDF_Localize # 新一代插件需要注册Class
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
function_plugins.update(
|
|
||||||
{
|
|
||||||
"🎨图片生成(DALLE2/DALLE3, 使用前切换到GPT系列模型)": {
|
|
||||||
"Group": "对话",
|
|
||||||
"Color": "stop",
|
|
||||||
"AsButton": False,
|
|
||||||
"Info": "使用 DALLE2/DALLE3 生成图片 | 输入参数字符串,提供图像的内容",
|
|
||||||
"Function": HotReload(图片生成_DALLE2), # 当注册Class后,Function旧接口仅会在“虚空终端”中起作用
|
|
||||||
"Class": ImageGen_Wrap # 新一代插件需要注册Class
|
|
||||||
},
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
function_plugins.update(
|
|
||||||
{
|
|
||||||
"🎨图片修改_DALLE2 (使用前请切换模型到GPT系列)": {
|
|
||||||
"Group": "对话",
|
|
||||||
"Color": "stop",
|
|
||||||
"AsButton": False,
|
|
||||||
"AdvancedArgs": False, # 调用时,唤起高级参数输入区(默认False)
|
|
||||||
# "Info": "使用DALLE2修改图片 | 输入参数字符串,提供图像的内容",
|
|
||||||
"Function": HotReload(图片修改_DALLE2),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# -=--=- 尚未充分测试的实验性插件 & 需要额外依赖的插件 -=--=-
|
# -=--=- 尚未充分测试的实验性插件 & 需要额外依赖的插件 -=--=-
|
||||||
try:
|
try:
|
||||||
@@ -424,39 +305,39 @@ def get_crazy_functions():
|
|||||||
print(trimmed_format_exc())
|
print(trimmed_format_exc())
|
||||||
print("Load function plugin failed")
|
print("Load function plugin failed")
|
||||||
|
|
||||||
# try:
|
try:
|
||||||
# from crazy_functions.联网的ChatGPT import 连接网络回答问题
|
from crazy_functions.联网的ChatGPT import 连接网络回答问题
|
||||||
|
|
||||||
# function_plugins.update(
|
function_plugins.update(
|
||||||
# {
|
{
|
||||||
# "连接网络回答问题(输入问题后点击该插件,需要访问谷歌)": {
|
"连接网络回答问题(输入问题后点击该插件,需要访问谷歌)": {
|
||||||
# "Group": "对话",
|
"Group": "对话",
|
||||||
# "Color": "stop",
|
"Color": "stop",
|
||||||
# "AsButton": False, # 加入下拉菜单中
|
"AsButton": False, # 加入下拉菜单中
|
||||||
# # "Info": "连接网络回答问题(需要访问谷歌)| 输入参数是一个问题",
|
# "Info": "连接网络回答问题(需要访问谷歌)| 输入参数是一个问题",
|
||||||
# "Function": HotReload(连接网络回答问题),
|
"Function": HotReload(连接网络回答问题),
|
||||||
# }
|
}
|
||||||
# }
|
}
|
||||||
# )
|
)
|
||||||
# from crazy_functions.联网的ChatGPT_bing版 import 连接bing搜索回答问题
|
from crazy_functions.联网的ChatGPT_bing版 import 连接bing搜索回答问题
|
||||||
|
|
||||||
# function_plugins.update(
|
function_plugins.update(
|
||||||
# {
|
{
|
||||||
# "连接网络回答问题(中文Bing版,输入问题后点击该插件)": {
|
"连接网络回答问题(中文Bing版,输入问题后点击该插件)": {
|
||||||
# "Group": "对话",
|
"Group": "对话",
|
||||||
# "Color": "stop",
|
"Color": "stop",
|
||||||
# "AsButton": False, # 加入下拉菜单中
|
"AsButton": False, # 加入下拉菜单中
|
||||||
# "Info": "连接网络回答问题(需要访问中文Bing)| 输入参数是一个问题",
|
"Info": "连接网络回答问题(需要访问中文Bing)| 输入参数是一个问题",
|
||||||
# "Function": HotReload(连接bing搜索回答问题),
|
"Function": HotReload(连接bing搜索回答问题),
|
||||||
# }
|
}
|
||||||
# }
|
}
|
||||||
# )
|
)
|
||||||
# except:
|
except:
|
||||||
# print(trimmed_format_exc())
|
print(trimmed_format_exc())
|
||||||
# print("Load function plugin failed")
|
print("Load function plugin failed")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from crazy_functions.SourceCode_Analyse import 解析任意code项目
|
from crazy_functions.解析项目源代码 import 解析任意code项目
|
||||||
|
|
||||||
function_plugins.update(
|
function_plugins.update(
|
||||||
{
|
{
|
||||||
@@ -493,7 +374,50 @@ def get_crazy_functions():
|
|||||||
print(trimmed_format_exc())
|
print(trimmed_format_exc())
|
||||||
print("Load function plugin failed")
|
print("Load function plugin failed")
|
||||||
|
|
||||||
|
try:
|
||||||
|
from crazy_functions.图片生成 import 图片生成_DALLE2, 图片生成_DALLE3, 图片修改_DALLE2
|
||||||
|
|
||||||
|
function_plugins.update(
|
||||||
|
{
|
||||||
|
"图片生成_DALLE2 (先切换模型到gpt-*)": {
|
||||||
|
"Group": "对话",
|
||||||
|
"Color": "stop",
|
||||||
|
"AsButton": False,
|
||||||
|
"AdvancedArgs": True, # 调用时,唤起高级参数输入区(默认False)
|
||||||
|
"ArgsReminder": "在这里输入分辨率, 如1024x1024(默认),支持 256x256, 512x512, 1024x1024", # 高级参数输入区的显示提示
|
||||||
|
"Info": "使用DALLE2生成图片 | 输入参数字符串,提供图像的内容",
|
||||||
|
"Function": HotReload(图片生成_DALLE2),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
function_plugins.update(
|
||||||
|
{
|
||||||
|
"图片生成_DALLE3 (先切换模型到gpt-*)": {
|
||||||
|
"Group": "对话",
|
||||||
|
"Color": "stop",
|
||||||
|
"AsButton": False,
|
||||||
|
"AdvancedArgs": True, # 调用时,唤起高级参数输入区(默认False)
|
||||||
|
"ArgsReminder": "在这里输入自定义参数「分辨率-质量(可选)-风格(可选)」, 参数示例「1024x1024-hd-vivid」 || 分辨率支持 「1024x1024」(默认) /「1792x1024」/「1024x1792」 || 质量支持 「-standard」(默认) /「-hd」 || 风格支持 「-vivid」(默认) /「-natural」", # 高级参数输入区的显示提示
|
||||||
|
"Info": "使用DALLE3生成图片 | 输入参数字符串,提供图像的内容",
|
||||||
|
"Function": HotReload(图片生成_DALLE3),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
function_plugins.update(
|
||||||
|
{
|
||||||
|
"图片修改_DALLE2 (先切换模型到gpt-*)": {
|
||||||
|
"Group": "对话",
|
||||||
|
"Color": "stop",
|
||||||
|
"AsButton": False,
|
||||||
|
"AdvancedArgs": False, # 调用时,唤起高级参数输入区(默认False)
|
||||||
|
# "Info": "使用DALLE2修改图片 | 输入参数字符串,提供图像的内容",
|
||||||
|
"Function": HotReload(图片修改_DALLE2),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
except:
|
||||||
|
print(trimmed_format_exc())
|
||||||
|
print("Load function plugin failed")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from crazy_functions.总结音视频 import 总结音视频
|
from crazy_functions.总结音视频 import 总结音视频
|
||||||
@@ -534,7 +458,7 @@ def get_crazy_functions():
|
|||||||
print("Load function plugin failed")
|
print("Load function plugin failed")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from crazy_functions.Markdown_Translate import Markdown翻译指定语言
|
from crazy_functions.批量Markdown翻译 import Markdown翻译指定语言
|
||||||
|
|
||||||
function_plugins.update(
|
function_plugins.update(
|
||||||
{
|
{
|
||||||
@@ -607,6 +531,59 @@ def get_crazy_functions():
|
|||||||
print(trimmed_format_exc())
|
print(trimmed_format_exc())
|
||||||
print("Load function plugin failed")
|
print("Load function plugin failed")
|
||||||
|
|
||||||
|
try:
|
||||||
|
from crazy_functions.Latex输出PDF import Latex英文纠错加PDF对比
|
||||||
|
from crazy_functions.Latex输出PDF import Latex翻译中文并重新编译PDF
|
||||||
|
from crazy_functions.Latex输出PDF import PDF翻译中文并重新编译PDF
|
||||||
|
|
||||||
|
function_plugins.update(
|
||||||
|
{
|
||||||
|
"Latex英文纠错+高亮修正位置 [需Latex]": {
|
||||||
|
"Group": "学术",
|
||||||
|
"Color": "stop",
|
||||||
|
"AsButton": False,
|
||||||
|
"AdvancedArgs": True,
|
||||||
|
"ArgsReminder": "如果有必要, 请在此处追加更细致的矫错指令(使用英文)。",
|
||||||
|
"Function": HotReload(Latex英文纠错加PDF对比),
|
||||||
|
},
|
||||||
|
"Arxiv论文精细翻译(输入arxivID)[需Latex]": {
|
||||||
|
"Group": "学术",
|
||||||
|
"Color": "stop",
|
||||||
|
"AsButton": False,
|
||||||
|
"AdvancedArgs": True,
|
||||||
|
"ArgsReminder": r"如果有必要, 请在此处给出自定义翻译命令, 解决部分词汇翻译不准确的问题。 "
|
||||||
|
r"例如当单词'agent'翻译不准确时, 请尝试把以下指令复制到高级参数区: "
|
||||||
|
r'If the term "agent" is used in this section, it should be translated to "智能体". ',
|
||||||
|
"Info": "Arixv论文精细翻译 | 输入参数arxiv论文的ID,比如1812.10695",
|
||||||
|
"Function": HotReload(Latex翻译中文并重新编译PDF),
|
||||||
|
},
|
||||||
|
"本地Latex论文精细翻译(上传Latex项目)[需Latex]": {
|
||||||
|
"Group": "学术",
|
||||||
|
"Color": "stop",
|
||||||
|
"AsButton": False,
|
||||||
|
"AdvancedArgs": True,
|
||||||
|
"ArgsReminder": r"如果有必要, 请在此处给出自定义翻译命令, 解决部分词汇翻译不准确的问题。 "
|
||||||
|
r"例如当单词'agent'翻译不准确时, 请尝试把以下指令复制到高级参数区: "
|
||||||
|
r'If the term "agent" is used in this section, it should be translated to "智能体". ',
|
||||||
|
"Info": "本地Latex论文精细翻译 | 输入参数是路径",
|
||||||
|
"Function": HotReload(Latex翻译中文并重新编译PDF),
|
||||||
|
},
|
||||||
|
"PDF翻译中文并重新编译PDF(上传PDF)[需Latex]": {
|
||||||
|
"Group": "学术",
|
||||||
|
"Color": "stop",
|
||||||
|
"AsButton": False,
|
||||||
|
"AdvancedArgs": True,
|
||||||
|
"ArgsReminder": r"如果有必要, 请在此处给出自定义翻译命令, 解决部分词汇翻译不准确的问题。 "
|
||||||
|
r"例如当单词'agent'翻译不准确时, 请尝试把以下指令复制到高级参数区: "
|
||||||
|
r'If the term "agent" is used in this section, it should be translated to "智能体". ',
|
||||||
|
"Info": "PDF翻译中文,并重新编译PDF | 输入参数为路径",
|
||||||
|
"Function": HotReload(PDF翻译中文并重新编译PDF)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
except:
|
||||||
|
print(trimmed_format_exc())
|
||||||
|
print("Load function plugin failed")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from toolbox import get_conf
|
from toolbox import get_conf
|
||||||
|
|||||||
@@ -1,56 +0,0 @@
|
|||||||
|
|
||||||
from toolbox import get_conf, update_ui
|
|
||||||
from crazy_functions.Image_Generate import 图片生成_DALLE2, 图片生成_DALLE3, 图片修改_DALLE2
|
|
||||||
from crazy_functions.plugin_template.plugin_class_template import GptAcademicPluginTemplate, ArgProperty
|
|
||||||
|
|
||||||
|
|
||||||
class ImageGen_Wrap(GptAcademicPluginTemplate):
|
|
||||||
def __init__(self):
|
|
||||||
"""
|
|
||||||
请注意`execute`会执行在不同的线程中,因此您在定义和使用类变量时,应当慎之又慎!
|
|
||||||
"""
|
|
||||||
pass
|
|
||||||
|
|
||||||
def define_arg_selection_menu(self):
|
|
||||||
"""
|
|
||||||
定义插件的二级选项菜单
|
|
||||||
|
|
||||||
第一个参数,名称`main_input`,参数`type`声明这是一个文本框,文本框上方显示`title`,文本框内部显示`description`,`default_value`为默认值;
|
|
||||||
第二个参数,名称`advanced_arg`,参数`type`声明这是一个文本框,文本框上方显示`title`,文本框内部显示`description`,`default_value`为默认值;
|
|
||||||
|
|
||||||
"""
|
|
||||||
gui_definition = {
|
|
||||||
"main_input":
|
|
||||||
ArgProperty(title="输入图片描述", description="需要生成图像的文本描述,尽量使用英文", default_value="", type="string").model_dump_json(), # 主输入,自动从输入框同步
|
|
||||||
"model_name":
|
|
||||||
ArgProperty(title="模型", options=["DALLE2", "DALLE3"], default_value="DALLE3", description="无", type="dropdown").model_dump_json(),
|
|
||||||
"resolution":
|
|
||||||
ArgProperty(title="分辨率", options=["256x256(限DALLE2)", "512x512(限DALLE2)", "1024x1024", "1792x1024(限DALLE3)", "1024x1792(限DALLE3)"], default_value="1024x1024", description="无", type="dropdown").model_dump_json(),
|
|
||||||
"quality (仅DALLE3生效)":
|
|
||||||
ArgProperty(title="质量", options=["standard", "hd"], default_value="standard", description="无", type="dropdown").model_dump_json(),
|
|
||||||
"style (仅DALLE3生效)":
|
|
||||||
ArgProperty(title="风格", options=["vivid", "natural"], default_value="vivid", description="无", type="dropdown").model_dump_json(),
|
|
||||||
|
|
||||||
}
|
|
||||||
return gui_definition
|
|
||||||
|
|
||||||
def execute(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request):
|
|
||||||
"""
|
|
||||||
执行插件
|
|
||||||
"""
|
|
||||||
# 分辨率
|
|
||||||
resolution = plugin_kwargs["resolution"].replace("(限DALLE2)", "").replace("(限DALLE3)", "")
|
|
||||||
|
|
||||||
if plugin_kwargs["model_name"] == "DALLE2":
|
|
||||||
plugin_kwargs["advanced_arg"] = resolution
|
|
||||||
yield from 图片生成_DALLE2(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request)
|
|
||||||
|
|
||||||
elif plugin_kwargs["model_name"] == "DALLE3":
|
|
||||||
quality = plugin_kwargs["quality (仅DALLE3生效)"]
|
|
||||||
style = plugin_kwargs["style (仅DALLE3生效)"]
|
|
||||||
plugin_kwargs["advanced_arg"] = f"{resolution}-{quality}-{style}"
|
|
||||||
yield from 图片生成_DALLE3(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request)
|
|
||||||
|
|
||||||
else:
|
|
||||||
chatbot.append([None, "抱歉,找不到该模型"])
|
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
|
||||||
@@ -1,278 +0,0 @@
|
|||||||
import requests
|
|
||||||
import random
|
|
||||||
import time
|
|
||||||
import re
|
|
||||||
import json
|
|
||||||
from bs4 import BeautifulSoup
|
|
||||||
from functools import lru_cache
|
|
||||||
from itertools import zip_longest
|
|
||||||
from check_proxy import check_proxy
|
|
||||||
from toolbox import CatchException, update_ui, get_conf
|
|
||||||
from crazy_functions.crazy_utils import request_gpt_model_in_new_thread_with_ui_alive, input_clipping
|
|
||||||
from request_llms.bridge_all import model_info
|
|
||||||
from request_llms.bridge_all import predict_no_ui_long_connection
|
|
||||||
from crazy_functions.prompts.internet import SearchOptimizerPrompt, SearchAcademicOptimizerPrompt
|
|
||||||
|
|
||||||
def search_optimizer(
|
|
||||||
query,
|
|
||||||
proxies,
|
|
||||||
history,
|
|
||||||
llm_kwargs,
|
|
||||||
optimizer=1,
|
|
||||||
categories="general",
|
|
||||||
searxng_url=None,
|
|
||||||
engines=None,
|
|
||||||
):
|
|
||||||
# ------------- < 第1步:尝试进行搜索优化 > -------------
|
|
||||||
# * 增强优化,会尝试结合历史记录进行搜索优化
|
|
||||||
if optimizer == 2:
|
|
||||||
his = " "
|
|
||||||
if len(history) == 0:
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
for i, h in enumerate(history):
|
|
||||||
if i % 2 == 0:
|
|
||||||
his += f"Q: {h}\n"
|
|
||||||
else:
|
|
||||||
his += f"A: {h}\n"
|
|
||||||
if categories == "general":
|
|
||||||
sys_prompt = SearchOptimizerPrompt.format(query=query, history=his, num=4)
|
|
||||||
elif categories == "science":
|
|
||||||
sys_prompt = SearchAcademicOptimizerPrompt.format(query=query, history=his, num=4)
|
|
||||||
else:
|
|
||||||
his = " "
|
|
||||||
if categories == "general":
|
|
||||||
sys_prompt = SearchOptimizerPrompt.format(query=query, history=his, num=3)
|
|
||||||
elif categories == "science":
|
|
||||||
sys_prompt = SearchAcademicOptimizerPrompt.format(query=query, history=his, num=3)
|
|
||||||
|
|
||||||
mutable = ["", time.time(), ""]
|
|
||||||
llm_kwargs["temperature"] = 0.8
|
|
||||||
try:
|
|
||||||
querys_json = predict_no_ui_long_connection(
|
|
||||||
inputs=query,
|
|
||||||
llm_kwargs=llm_kwargs,
|
|
||||||
history=[],
|
|
||||||
sys_prompt=sys_prompt,
|
|
||||||
observe_window=mutable,
|
|
||||||
)
|
|
||||||
except Exception:
|
|
||||||
querys_json = "1234"
|
|
||||||
#* 尝试解码优化后的搜索结果
|
|
||||||
querys_json = re.sub(r"```json|```", "", querys_json)
|
|
||||||
try:
|
|
||||||
querys = json.loads(querys_json)
|
|
||||||
except Exception:
|
|
||||||
#* 如果解码失败,降低温度再试一次
|
|
||||||
try:
|
|
||||||
llm_kwargs["temperature"] = 0.4
|
|
||||||
querys_json = predict_no_ui_long_connection(
|
|
||||||
inputs=query,
|
|
||||||
llm_kwargs=llm_kwargs,
|
|
||||||
history=[],
|
|
||||||
sys_prompt=sys_prompt,
|
|
||||||
observe_window=mutable,
|
|
||||||
)
|
|
||||||
querys_json = re.sub(r"```json|```", "", querys_json)
|
|
||||||
querys = json.loads(querys_json)
|
|
||||||
except Exception:
|
|
||||||
#* 如果再次失败,直接返回原始问题
|
|
||||||
querys = [query]
|
|
||||||
links = []
|
|
||||||
success = 0
|
|
||||||
Exceptions = ""
|
|
||||||
for q in querys:
|
|
||||||
try:
|
|
||||||
link = searxng_request(q, proxies, categories, searxng_url, engines=engines)
|
|
||||||
if len(link) > 0:
|
|
||||||
links.append(link[:-5])
|
|
||||||
success += 1
|
|
||||||
except Exception:
|
|
||||||
Exceptions = Exception
|
|
||||||
pass
|
|
||||||
if success == 0:
|
|
||||||
raise ValueError(f"在线搜索失败!\n{Exceptions}")
|
|
||||||
# * 清洗搜索结果,依次放入每组第一,第二个搜索结果,并清洗重复的搜索结果
|
|
||||||
seen_links = set()
|
|
||||||
result = []
|
|
||||||
for tuple in zip_longest(*links, fillvalue=None):
|
|
||||||
for item in tuple:
|
|
||||||
if item is not None:
|
|
||||||
link = item["link"]
|
|
||||||
if link not in seen_links:
|
|
||||||
seen_links.add(link)
|
|
||||||
result.append(item)
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
@lru_cache
|
|
||||||
def get_auth_ip():
|
|
||||||
ip = check_proxy(None, return_ip=True)
|
|
||||||
if ip is None:
|
|
||||||
return '114.114.114.' + str(random.randint(1, 10))
|
|
||||||
return ip
|
|
||||||
|
|
||||||
|
|
||||||
def searxng_request(query, proxies, categories='general', searxng_url=None, engines=None):
|
|
||||||
if searxng_url is None:
|
|
||||||
url = get_conf("SEARXNG_URL")
|
|
||||||
else:
|
|
||||||
url = searxng_url
|
|
||||||
|
|
||||||
if engines == "Mixed":
|
|
||||||
engines = None
|
|
||||||
|
|
||||||
if categories == 'general':
|
|
||||||
params = {
|
|
||||||
'q': query, # 搜索查询
|
|
||||||
'format': 'json', # 输出格式为JSON
|
|
||||||
'language': 'zh', # 搜索语言
|
|
||||||
'engines': engines,
|
|
||||||
}
|
|
||||||
elif categories == 'science':
|
|
||||||
params = {
|
|
||||||
'q': query, # 搜索查询
|
|
||||||
'format': 'json', # 输出格式为JSON
|
|
||||||
'language': 'zh', # 搜索语言
|
|
||||||
'categories': 'science'
|
|
||||||
}
|
|
||||||
else:
|
|
||||||
raise ValueError('不支持的检索类型')
|
|
||||||
|
|
||||||
headers = {
|
|
||||||
'Accept-Language': 'zh-CN,zh;q=0.9',
|
|
||||||
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36',
|
|
||||||
'X-Forwarded-For': get_auth_ip(),
|
|
||||||
'X-Real-IP': get_auth_ip()
|
|
||||||
}
|
|
||||||
results = []
|
|
||||||
response = requests.post(url, params=params, headers=headers, proxies=proxies, timeout=30)
|
|
||||||
if response.status_code == 200:
|
|
||||||
json_result = response.json()
|
|
||||||
for result in json_result['results']:
|
|
||||||
item = {
|
|
||||||
"title": result.get("title", ""),
|
|
||||||
"source": result.get("engines", "unknown"),
|
|
||||||
"content": result.get("content", ""),
|
|
||||||
"link": result["url"],
|
|
||||||
}
|
|
||||||
results.append(item)
|
|
||||||
return results
|
|
||||||
else:
|
|
||||||
if response.status_code == 429:
|
|
||||||
raise ValueError("Searxng(在线搜索服务)当前使用人数太多,请稍后。")
|
|
||||||
else:
|
|
||||||
raise ValueError("在线搜索失败,状态码: " + str(response.status_code) + '\t' + response.content.decode('utf-8'))
|
|
||||||
|
|
||||||
|
|
||||||
def scrape_text(url, proxies) -> str:
|
|
||||||
"""Scrape text from a webpage
|
|
||||||
|
|
||||||
Args:
|
|
||||||
url (str): The URL to scrape text from
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
str: The scraped text
|
|
||||||
"""
|
|
||||||
headers = {
|
|
||||||
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.61 Safari/537.36',
|
|
||||||
'Content-Type': 'text/plain',
|
|
||||||
}
|
|
||||||
try:
|
|
||||||
response = requests.get(url, headers=headers, proxies=proxies, timeout=8)
|
|
||||||
if response.encoding == "ISO-8859-1": response.encoding = response.apparent_encoding
|
|
||||||
except:
|
|
||||||
return "无法连接到该网页"
|
|
||||||
soup = BeautifulSoup(response.text, "html.parser")
|
|
||||||
for script in soup(["script", "style"]):
|
|
||||||
script.extract()
|
|
||||||
text = soup.get_text()
|
|
||||||
lines = (line.strip() for line in text.splitlines())
|
|
||||||
chunks = (phrase.strip() for line in lines for phrase in line.split(" "))
|
|
||||||
text = "\n".join(chunk for chunk in chunks if chunk)
|
|
||||||
return text
|
|
||||||
|
|
||||||
|
|
||||||
@CatchException
|
|
||||||
def 连接网络回答问题(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request):
|
|
||||||
optimizer_history = history[:-8]
|
|
||||||
history = [] # 清空历史,以免输入溢出
|
|
||||||
chatbot.append((f"请结合互联网信息回答以下问题:{txt}", "检索中..."))
|
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
|
||||||
|
|
||||||
# ------------- < 第1步:爬取搜索引擎的结果 > -------------
|
|
||||||
from toolbox import get_conf
|
|
||||||
proxies = get_conf('proxies')
|
|
||||||
categories = plugin_kwargs.get('categories', 'general')
|
|
||||||
searxng_url = plugin_kwargs.get('searxng_url', None)
|
|
||||||
engines = plugin_kwargs.get('engine', None)
|
|
||||||
optimizer = plugin_kwargs.get('optimizer', "关闭")
|
|
||||||
if optimizer == "关闭":
|
|
||||||
urls = searxng_request(txt, proxies, categories, searxng_url, engines=engines)
|
|
||||||
else:
|
|
||||||
urls = search_optimizer(txt, proxies, optimizer_history, llm_kwargs, optimizer, categories, searxng_url, engines)
|
|
||||||
history = []
|
|
||||||
if len(urls) == 0:
|
|
||||||
chatbot.append((f"结论:{txt}",
|
|
||||||
"[Local Message] 受到限制,无法从searxng获取信息!请尝试更换搜索引擎。"))
|
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
|
||||||
return
|
|
||||||
|
|
||||||
# ------------- < 第2步:依次访问网页 > -------------
|
|
||||||
max_search_result = 5 # 最多收纳多少个网页的结果
|
|
||||||
if optimizer == "开启(增强)":
|
|
||||||
max_search_result = 8
|
|
||||||
chatbot.append(["联网检索中 ...", None])
|
|
||||||
for index, url in enumerate(urls[:max_search_result]):
|
|
||||||
res = scrape_text(url['link'], proxies)
|
|
||||||
prefix = f"第{index}份搜索结果 [源自{url['source'][0]}搜索] ({url['title'][:25]}):"
|
|
||||||
history.extend([prefix, res])
|
|
||||||
res_squeeze = res.replace('\n', '...')
|
|
||||||
chatbot[-1] = [prefix + "\n\n" + res_squeeze[:500] + "......", None]
|
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
|
||||||
|
|
||||||
# ------------- < 第3步:ChatGPT综合 > -------------
|
|
||||||
if (optimizer != "开启(增强)"):
|
|
||||||
i_say = f"从以上搜索结果中抽取信息,然后回答问题:{txt}"
|
|
||||||
i_say, history = input_clipping( # 裁剪输入,从最长的条目开始裁剪,防止爆token
|
|
||||||
inputs=i_say,
|
|
||||||
history=history,
|
|
||||||
max_token_limit=min(model_info[llm_kwargs['llm_model']]['max_token']*3//4, 8192)
|
|
||||||
)
|
|
||||||
gpt_say = yield from request_gpt_model_in_new_thread_with_ui_alive(
|
|
||||||
inputs=i_say, inputs_show_user=i_say,
|
|
||||||
llm_kwargs=llm_kwargs, chatbot=chatbot, history=history,
|
|
||||||
sys_prompt="请从给定的若干条搜索结果中抽取信息,对最相关的两个搜索结果进行总结,然后回答问题。"
|
|
||||||
)
|
|
||||||
chatbot[-1] = (i_say, gpt_say)
|
|
||||||
history.append(i_say);history.append(gpt_say)
|
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 # 界面更新
|
|
||||||
|
|
||||||
#* 或者使用搜索优化器,这样可以保证后续问答能读取到有效的历史记录
|
|
||||||
else:
|
|
||||||
i_say = f"从以上搜索结果中抽取与问题:{txt} 相关的信息:"
|
|
||||||
i_say, history = input_clipping( # 裁剪输入,从最长的条目开始裁剪,防止爆token
|
|
||||||
inputs=i_say,
|
|
||||||
history=history,
|
|
||||||
max_token_limit=min(model_info[llm_kwargs['llm_model']]['max_token']*3//4, 8192)
|
|
||||||
)
|
|
||||||
gpt_say = yield from request_gpt_model_in_new_thread_with_ui_alive(
|
|
||||||
inputs=i_say, inputs_show_user=i_say,
|
|
||||||
llm_kwargs=llm_kwargs, chatbot=chatbot, history=history,
|
|
||||||
sys_prompt="请从给定的若干条搜索结果中抽取信息,对最相关的三个搜索结果进行总结"
|
|
||||||
)
|
|
||||||
chatbot[-1] = (i_say, gpt_say)
|
|
||||||
history = []
|
|
||||||
history.append(i_say);history.append(gpt_say)
|
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 # 界面更新
|
|
||||||
|
|
||||||
# ------------- < 第4步:根据综合回答问题 > -------------
|
|
||||||
i_say = f"请根据以上搜索结果回答问题:{txt}"
|
|
||||||
gpt_say = yield from request_gpt_model_in_new_thread_with_ui_alive(
|
|
||||||
inputs=i_say, inputs_show_user=i_say,
|
|
||||||
llm_kwargs=llm_kwargs, chatbot=chatbot, history=history,
|
|
||||||
sys_prompt="请根据给定的若干条搜索结果回答问题"
|
|
||||||
)
|
|
||||||
chatbot[-1] = (i_say, gpt_say)
|
|
||||||
history.append(i_say);history.append(gpt_say)
|
|
||||||
yield from update_ui(chatbot=chatbot, history=history)
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
|
|
||||||
from toolbox import get_conf
|
|
||||||
from crazy_functions.Internet_GPT import 连接网络回答问题
|
|
||||||
from crazy_functions.plugin_template.plugin_class_template import GptAcademicPluginTemplate, ArgProperty
|
|
||||||
|
|
||||||
|
|
||||||
class NetworkGPT_Wrap(GptAcademicPluginTemplate):
|
|
||||||
def __init__(self):
|
|
||||||
"""
|
|
||||||
请注意`execute`会执行在不同的线程中,因此您在定义和使用类变量时,应当慎之又慎!
|
|
||||||
"""
|
|
||||||
pass
|
|
||||||
|
|
||||||
def define_arg_selection_menu(self):
|
|
||||||
"""
|
|
||||||
定义插件的二级选项菜单
|
|
||||||
|
|
||||||
第一个参数,名称`main_input`,参数`type`声明这是一个文本框,文本框上方显示`title`,文本框内部显示`description`,`default_value`为默认值;
|
|
||||||
第二个参数,名称`advanced_arg`,参数`type`声明这是一个文本框,文本框上方显示`title`,文本框内部显示`description`,`default_value`为默认值;
|
|
||||||
第三个参数,名称`allow_cache`,参数`type`声明这是一个下拉菜单,下拉菜单上方显示`title`+`description`,下拉菜单的选项为`options`,`default_value`为下拉菜单默认值;
|
|
||||||
|
|
||||||
"""
|
|
||||||
gui_definition = {
|
|
||||||
"main_input":
|
|
||||||
ArgProperty(title="输入问题", description="待通过互联网检索的问题,会自动读取输入框内容", default_value="", type="string").model_dump_json(), # 主输入,自动从输入框同步
|
|
||||||
"categories":
|
|
||||||
ArgProperty(title="搜索分类", options=["网页", "学术论文"], default_value="网页", description="无", type="dropdown").model_dump_json(),
|
|
||||||
"engine":
|
|
||||||
ArgProperty(title="选择搜索引擎", options=["Mixed", "bing", "google", "duckduckgo"], default_value="google", description="无", type="dropdown").model_dump_json(),
|
|
||||||
"optimizer":
|
|
||||||
ArgProperty(title="搜索优化", options=["关闭", "开启", "开启(增强)"], default_value="关闭", description="是否使用搜索增强。注意这可能会消耗较多token", type="dropdown").model_dump_json(),
|
|
||||||
"searxng_url":
|
|
||||||
ArgProperty(title="Searxng服务地址", description="输入Searxng的地址", default_value=get_conf("SEARXNG_URL"), type="string").model_dump_json(), # 主输入,自动从输入框同步
|
|
||||||
|
|
||||||
}
|
|
||||||
return gui_definition
|
|
||||||
|
|
||||||
def execute(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request):
|
|
||||||
"""
|
|
||||||
执行插件
|
|
||||||
"""
|
|
||||||
if plugin_kwargs["categories"] == "网页": plugin_kwargs["categories"] = "general"
|
|
||||||
if plugin_kwargs["categories"] == "学术论文": plugin_kwargs["categories"] = "science"
|
|
||||||
yield from 连接网络回答问题(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request)
|
|
||||||
|
|
||||||
@@ -1,78 +0,0 @@
|
|||||||
|
|
||||||
from crazy_functions.Latex_Function import Latex翻译中文并重新编译PDF, PDF翻译中文并重新编译PDF
|
|
||||||
from crazy_functions.plugin_template.plugin_class_template import GptAcademicPluginTemplate, ArgProperty
|
|
||||||
|
|
||||||
|
|
||||||
class Arxiv_Localize(GptAcademicPluginTemplate):
|
|
||||||
def __init__(self):
|
|
||||||
"""
|
|
||||||
请注意`execute`会执行在不同的线程中,因此您在定义和使用类变量时,应当慎之又慎!
|
|
||||||
"""
|
|
||||||
pass
|
|
||||||
|
|
||||||
def define_arg_selection_menu(self):
|
|
||||||
"""
|
|
||||||
定义插件的二级选项菜单
|
|
||||||
|
|
||||||
第一个参数,名称`main_input`,参数`type`声明这是一个文本框,文本框上方显示`title`,文本框内部显示`description`,`default_value`为默认值;
|
|
||||||
第二个参数,名称`advanced_arg`,参数`type`声明这是一个文本框,文本框上方显示`title`,文本框内部显示`description`,`default_value`为默认值;
|
|
||||||
第三个参数,名称`allow_cache`,参数`type`声明这是一个下拉菜单,下拉菜单上方显示`title`+`description`,下拉菜单的选项为`options`,`default_value`为下拉菜单默认值;
|
|
||||||
|
|
||||||
"""
|
|
||||||
gui_definition = {
|
|
||||||
"main_input":
|
|
||||||
ArgProperty(title="ArxivID", description="输入Arxiv的ID或者网址", default_value="", type="string").model_dump_json(), # 主输入,自动从输入框同步
|
|
||||||
"advanced_arg":
|
|
||||||
ArgProperty(title="额外的翻译提示词",
|
|
||||||
description=r"如果有必要, 请在此处给出自定义翻译命令, 解决部分词汇翻译不准确的问题。 "
|
|
||||||
r"例如当单词'agent'翻译不准确时, 请尝试把以下指令复制到高级参数区: "
|
|
||||||
r'If the term "agent" is used in this section, it should be translated to "智能体". ',
|
|
||||||
default_value="", type="string").model_dump_json(), # 高级参数输入区,自动同步
|
|
||||||
"allow_cache":
|
|
||||||
ArgProperty(title="是否允许从缓存中调取结果", options=["允许缓存", "从头执行"], default_value="允许缓存", description="无", type="dropdown").model_dump_json(),
|
|
||||||
}
|
|
||||||
return gui_definition
|
|
||||||
|
|
||||||
def execute(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request):
|
|
||||||
"""
|
|
||||||
执行插件
|
|
||||||
"""
|
|
||||||
allow_cache = plugin_kwargs["allow_cache"]
|
|
||||||
advanced_arg = plugin_kwargs["advanced_arg"]
|
|
||||||
|
|
||||||
if allow_cache == "从头执行": plugin_kwargs["advanced_arg"] = "--no-cache " + plugin_kwargs["advanced_arg"]
|
|
||||||
yield from Latex翻译中文并重新编译PDF(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class PDF_Localize(GptAcademicPluginTemplate):
|
|
||||||
def __init__(self):
|
|
||||||
"""
|
|
||||||
请注意`execute`会执行在不同的线程中,因此您在定义和使用类变量时,应当慎之又慎!
|
|
||||||
"""
|
|
||||||
pass
|
|
||||||
|
|
||||||
def define_arg_selection_menu(self):
|
|
||||||
"""
|
|
||||||
定义插件的二级选项菜单
|
|
||||||
"""
|
|
||||||
gui_definition = {
|
|
||||||
"main_input":
|
|
||||||
ArgProperty(title="PDF文件路径", description="未指定路径,请上传文件后,再点击该插件", default_value="", type="string").model_dump_json(), # 主输入,自动从输入框同步
|
|
||||||
"advanced_arg":
|
|
||||||
ArgProperty(title="额外的翻译提示词",
|
|
||||||
description=r"如果有必要, 请在此处给出自定义翻译命令, 解决部分词汇翻译不准确的问题。 "
|
|
||||||
r"例如当单词'agent'翻译不准确时, 请尝试把以下指令复制到高级参数区: "
|
|
||||||
r'If the term "agent" is used in this section, it should be translated to "智能体". ',
|
|
||||||
default_value="", type="string").model_dump_json(), # 高级参数输入区,自动同步
|
|
||||||
"method":
|
|
||||||
ArgProperty(title="采用哪种方法执行转换", options=["MATHPIX", "DOC2X"], default_value="DOC2X", description="无", type="dropdown").model_dump_json(),
|
|
||||||
|
|
||||||
}
|
|
||||||
return gui_definition
|
|
||||||
|
|
||||||
def execute(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request):
|
|
||||||
"""
|
|
||||||
执行插件
|
|
||||||
"""
|
|
||||||
yield from PDF翻译中文并重新编译PDF(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request)
|
|
||||||
@@ -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 = [r"Below is a section from an academic paper, polish this section to meet the academic standard, " +
|
inputs_array = ["Below is a section from an academic paper, polish this section to meet the academic standard, " +
|
||||||
r"improve the grammar, clarity and overall readability, do not modify any latex command such as \section, \cite and equations:" +
|
"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 = [r"以下是一篇学术论文中的一段内容,请将此部分润色以满足学术标准,提高语法、清晰度和整体可读性,不要修改任何LaTeX命令,例如\section,\cite和方程式:" +
|
inputs_array = [f"以下是一篇学术论文中的一段内容,请将此部分润色以满足学术标准,提高语法、清晰度和整体可读性,不要修改任何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 = [r"以下是一篇学术论文中的一段内容,请对这部分内容进行语法矫正。不要修改任何LaTeX命令,例如\section,\cite和方程式:" +
|
inputs_array = [f"以下是一篇学术论文中的一段内容,请对这部分内容进行语法矫正。不要修改任何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,10 +1,10 @@
|
|||||||
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 update_ui, trimmed_format_exc, get_conf, get_log_folder, promote_file_to_downloadzone
|
||||||
from toolbox import CatchException, report_exception, update_ui_lastest_msg, zip_result, gen_time_str
|
from toolbox import CatchException, report_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
|
||||||
|
|
||||||
pj = os.path.join
|
pj = os.path.join
|
||||||
ARXIV_CACHE_DIR = get_conf("ARXIV_CACHE_DIR")
|
ARXIV_CACHE_DIR = os.path.expanduser(f"~/arxiv_cache/")
|
||||||
|
|
||||||
|
|
||||||
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 工具函数 =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 工具函数 =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
||||||
@@ -107,10 +107,6 @@ def arxiv_download(chatbot, history, txt, allow_cache=True):
|
|||||||
except ValueError:
|
except ValueError:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
if txt.startswith('https://arxiv.org/pdf/'):
|
|
||||||
arxiv_id = txt.split('/')[-1] # 2402.14207v2.pdf
|
|
||||||
txt = arxiv_id.split('v')[0] # 2402.14207
|
|
||||||
|
|
||||||
if ('.' in txt) and ('/' not in txt) and is_float(txt): # is arxiv ID
|
if ('.' in txt) and ('/' not in txt) and is_float(txt): # is arxiv ID
|
||||||
txt = 'https://arxiv.org/abs/' + txt.strip()
|
txt = 'https://arxiv.org/abs/' + txt.strip()
|
||||||
if ('.' in txt) and ('/' not in txt) and is_float(txt[:10]): # is arxiv ID
|
if ('.' in txt) and ('/' not in txt) and is_float(txt[:10]): # is arxiv ID
|
||||||
@@ -125,7 +121,6 @@ def arxiv_download(chatbot, history, txt, allow_cache=True):
|
|||||||
time.sleep(1) # 刷新界面
|
time.sleep(1) # 刷新界面
|
||||||
|
|
||||||
url_ = txt # https://arxiv.org/abs/1707.06690
|
url_ = txt # https://arxiv.org/abs/1707.06690
|
||||||
|
|
||||||
if not txt.startswith('https://arxiv.org/abs/'):
|
if not txt.startswith('https://arxiv.org/abs/'):
|
||||||
msg = f"解析arxiv网址失败, 期望格式例如: https://arxiv.org/abs/1707.06690。实际得到格式: {url_}。"
|
msg = f"解析arxiv网址失败, 期望格式例如: https://arxiv.org/abs/1707.06690。实际得到格式: {url_}。"
|
||||||
yield from update_ui_lastest_msg(msg, chatbot=chatbot, history=history) # 刷新界面
|
yield from update_ui_lastest_msg(msg, chatbot=chatbot, history=history) # 刷新界面
|
||||||
@@ -158,8 +153,7 @@ def arxiv_download(chatbot, history, txt, allow_cache=True):
|
|||||||
return extract_dst, arxiv_id
|
return extract_dst, arxiv_id
|
||||||
|
|
||||||
|
|
||||||
def pdf2tex_project(pdf_file_path, plugin_kwargs):
|
def pdf2tex_project(pdf_file_path):
|
||||||
if plugin_kwargs["method"] == "MATHPIX":
|
|
||||||
# Mathpix API credentials
|
# Mathpix API credentials
|
||||||
app_id, app_key = get_conf('MATHPIX_APPID', 'MATHPIX_APPKEY')
|
app_id, app_key = get_conf('MATHPIX_APPID', 'MATHPIX_APPKEY')
|
||||||
headers = {"app_id": app_id, "app_key": app_key}
|
headers = {"app_id": app_id, "app_key": app_key}
|
||||||
@@ -218,12 +212,6 @@ def pdf2tex_project(pdf_file_path, plugin_kwargs):
|
|||||||
else:
|
else:
|
||||||
print(f"Error sending PDF for processing. Status code: {response.status_code}")
|
print(f"Error sending PDF for processing. Status code: {response.status_code}")
|
||||||
return None
|
return None
|
||||||
else:
|
|
||||||
from crazy_functions.pdf_fns.parse_pdf_via_doc2x import 解析PDF_DOC2X_转Latex
|
|
||||||
unzip_dir = 解析PDF_DOC2X_转Latex(pdf_file_path)
|
|
||||||
return unzip_dir
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 插件主程序1 =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 插件主程序1 =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||||
@@ -233,7 +221,7 @@ def pdf2tex_project(pdf_file_path, plugin_kwargs):
|
|||||||
def Latex英文纠错加PDF对比(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request):
|
def Latex英文纠错加PDF对比(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request):
|
||||||
# <-------------- information about this plugin ------------->
|
# <-------------- information about this plugin ------------->
|
||||||
chatbot.append(["函数插件功能?",
|
chatbot.append(["函数插件功能?",
|
||||||
"对整个Latex项目进行纠错, 用latex编译为PDF对修正处做高亮。函数插件贡献者: Binary-Husky。注意事项: 目前对机器学习类文献转化效果最好,其他类型文献转化效果未知。仅在Windows系统进行了测试,其他操作系统表现未知。"])
|
"对整个Latex项目进行纠错, 用latex编译为PDF对修正处做高亮。函数插件贡献者: Binary-Husky。注意事项: 目前仅支持GPT3.5/GPT4,其他模型转化效果未知。目前对机器学习类文献转化效果最好,其他类型文献转化效果未知。仅在Windows系统进行了测试,其他操作系统表现未知。"])
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
||||||
|
|
||||||
# <-------------- more requirements ------------->
|
# <-------------- more requirements ------------->
|
||||||
@@ -271,8 +259,6 @@ def Latex英文纠错加PDF对比(txt, llm_kwargs, plugin_kwargs, chatbot, histo
|
|||||||
project_folder = desend_to_extracted_folder_if_exist(project_folder)
|
project_folder = desend_to_extracted_folder_if_exist(project_folder)
|
||||||
|
|
||||||
# <-------------- move latex project away from temp folder ------------->
|
# <-------------- move latex project away from temp folder ------------->
|
||||||
from shared_utils.fastapi_server import validate_path_safety
|
|
||||||
validate_path_safety(project_folder, chatbot.get_user())
|
|
||||||
project_folder = move_project(project_folder, arxiv_id=None)
|
project_folder = move_project(project_folder, arxiv_id=None)
|
||||||
|
|
||||||
# <-------------- if merge_translate_zh is already generated, skip gpt req ------------->
|
# <-------------- if merge_translate_zh is already generated, skip gpt req ------------->
|
||||||
@@ -296,7 +282,7 @@ def Latex英文纠错加PDF对比(txt, llm_kwargs, plugin_kwargs, chatbot, histo
|
|||||||
promote_file_to_downloadzone(file=zip_res, chatbot=chatbot)
|
promote_file_to_downloadzone(file=zip_res, chatbot=chatbot)
|
||||||
else:
|
else:
|
||||||
chatbot.append((f"失败了",
|
chatbot.append((f"失败了",
|
||||||
'虽然PDF生成失败了, 但请查收结果(压缩包), 内含已经翻译的Tex文档, 也是可读的, 您可以到Github Issue区, 用该压缩包+Conversation_To_File进行反馈 ...'))
|
'虽然PDF生成失败了, 但请查收结果(压缩包), 内含已经翻译的Tex文档, 也是可读的, 您可以到Github Issue区, 用该压缩包+对话历史存档进行反馈 ...'))
|
||||||
yield from update_ui(chatbot=chatbot, history=history);
|
yield from update_ui(chatbot=chatbot, history=history);
|
||||||
time.sleep(1) # 刷新界面
|
time.sleep(1) # 刷新界面
|
||||||
promote_file_to_downloadzone(file=zip_res, chatbot=chatbot)
|
promote_file_to_downloadzone(file=zip_res, chatbot=chatbot)
|
||||||
@@ -312,7 +298,7 @@ def Latex翻译中文并重新编译PDF(txt, llm_kwargs, plugin_kwargs, chatbot,
|
|||||||
# <-------------- information about this plugin ------------->
|
# <-------------- information about this plugin ------------->
|
||||||
chatbot.append([
|
chatbot.append([
|
||||||
"函数插件功能?",
|
"函数插件功能?",
|
||||||
"对整个Latex项目进行翻译, 生成中文PDF。函数插件贡献者: Binary-Husky。注意事项: 此插件Windows支持最佳,Linux下必须使用Docker安装,详见项目主README.md。目前对机器学习类文献转化效果最好,其他类型文献转化效果未知。"])
|
"对整个Latex项目进行翻译, 生成中文PDF。函数插件贡献者: Binary-Husky。注意事项: 此插件Windows支持最佳,Linux下必须使用Docker安装,详见项目主README.md。目前仅支持GPT3.5/GPT4,其他模型转化效果未知。目前对机器学习类文献转化效果最好,其他类型文献转化效果未知。"])
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
||||||
|
|
||||||
# <-------------- more requirements ------------->
|
# <-------------- more requirements ------------->
|
||||||
@@ -367,8 +353,6 @@ def Latex翻译中文并重新编译PDF(txt, llm_kwargs, plugin_kwargs, chatbot,
|
|||||||
project_folder = desend_to_extracted_folder_if_exist(project_folder)
|
project_folder = desend_to_extracted_folder_if_exist(project_folder)
|
||||||
|
|
||||||
# <-------------- move latex project away from temp folder ------------->
|
# <-------------- move latex project away from temp folder ------------->
|
||||||
from shared_utils.fastapi_server import validate_path_safety
|
|
||||||
validate_path_safety(project_folder, chatbot.get_user())
|
|
||||||
project_folder = move_project(project_folder, arxiv_id)
|
project_folder = move_project(project_folder, arxiv_id)
|
||||||
|
|
||||||
# <-------------- if merge_translate_zh is already generated, skip gpt req ------------->
|
# <-------------- if merge_translate_zh is already generated, skip gpt req ------------->
|
||||||
@@ -408,7 +392,7 @@ def PDF翻译中文并重新编译PDF(txt, llm_kwargs, plugin_kwargs, chatbot, h
|
|||||||
# <-------------- information about this plugin ------------->
|
# <-------------- information about this plugin ------------->
|
||||||
chatbot.append([
|
chatbot.append([
|
||||||
"函数插件功能?",
|
"函数插件功能?",
|
||||||
"将PDF转换为Latex项目,翻译为中文后重新编译为PDF。函数插件贡献者: Marroh。注意事项: 此插件Windows支持最佳,Linux下必须使用Docker安装,详见项目主README.md。目前对机器学习类文献转化效果最好,其他类型文献转化效果未知。"])
|
"将PDF转换为Latex项目,翻译为中文后重新编译为PDF。函数插件贡献者: Marroh。注意事项: 此插件Windows支持最佳,Linux下必须使用Docker安装,详见项目主README.md。目前仅支持GPT3.5/GPT4,其他模型转化效果未知。目前对机器学习类文献转化效果最好,其他类型文献转化效果未知。"])
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
||||||
|
|
||||||
# <-------------- more requirements ------------->
|
# <-------------- more requirements ------------->
|
||||||
@@ -448,55 +432,16 @@ def PDF翻译中文并重新编译PDF(txt, llm_kwargs, plugin_kwargs, chatbot, h
|
|||||||
report_exception(chatbot, history, a=f"解析项目: {txt}", b=f"不支持同时处理多个pdf文件: {txt}")
|
report_exception(chatbot, history, a=f"解析项目: {txt}", b=f"不支持同时处理多个pdf文件: {txt}")
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
||||||
return
|
return
|
||||||
|
|
||||||
if plugin_kwargs.get("method", "") == 'MATHPIX':
|
|
||||||
app_id, app_key = get_conf('MATHPIX_APPID', 'MATHPIX_APPKEY')
|
app_id, app_key = get_conf('MATHPIX_APPID', 'MATHPIX_APPKEY')
|
||||||
if len(app_id) == 0 or len(app_key) == 0:
|
if len(app_id) == 0 or len(app_key) == 0:
|
||||||
report_exception(chatbot, history, a="缺失 MATHPIX_APPID 和 MATHPIX_APPKEY。", b=f"请配置 MATHPIX_APPID 和 MATHPIX_APPKEY")
|
report_exception(chatbot, history, a="缺失 MATHPIX_APPID 和 MATHPIX_APPKEY。", b=f"请配置 MATHPIX_APPID 和 MATHPIX_APPKEY")
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
||||||
return
|
return
|
||||||
if plugin_kwargs.get("method", "") == 'DOC2X':
|
|
||||||
app_id, app_key = "", ""
|
|
||||||
DOC2X_API_KEY = get_conf('DOC2X_API_KEY')
|
|
||||||
if len(DOC2X_API_KEY) == 0:
|
|
||||||
report_exception(chatbot, history, a="缺失 DOC2X_API_KEY。", b=f"请配置 DOC2X_API_KEY")
|
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
|
||||||
return
|
|
||||||
|
|
||||||
hash_tag = map_file_to_sha256(file_manifest[0])
|
|
||||||
|
|
||||||
# # <-------------- check repeated pdf ------------->
|
|
||||||
# chatbot.append([f"检查PDF是否被重复上传", "正在检查..."])
|
|
||||||
# yield from update_ui(chatbot=chatbot, history=history)
|
|
||||||
# repeat, project_folder = check_repeat_upload(file_manifest[0], hash_tag)
|
|
||||||
|
|
||||||
# if repeat:
|
|
||||||
# yield from update_ui_lastest_msg(f"发现重复上传,请查收结果(压缩包)...", chatbot=chatbot, history=history)
|
|
||||||
# try:
|
|
||||||
# translate_pdf = [f for f in glob.glob(f'{project_folder}/**/merge_translate_zh.pdf', recursive=True)][0]
|
|
||||||
# promote_file_to_downloadzone(translate_pdf, rename_file=None, chatbot=chatbot)
|
|
||||||
# comparison_pdf = [f for f in glob.glob(f'{project_folder}/**/comparison.pdf', recursive=True)][0]
|
|
||||||
# promote_file_to_downloadzone(comparison_pdf, rename_file=None, chatbot=chatbot)
|
|
||||||
# zip_res = zip_result(project_folder)
|
|
||||||
# promote_file_to_downloadzone(file=zip_res, chatbot=chatbot)
|
|
||||||
# return
|
|
||||||
# except:
|
|
||||||
# report_exception(chatbot, history, a=f"解析项目: {txt}", b=f"发现重复上传,但是无法找到相关文件")
|
|
||||||
# yield from update_ui(chatbot=chatbot, history=history)
|
|
||||||
# else:
|
|
||||||
# yield from update_ui_lastest_msg(f"未发现重复上传", chatbot=chatbot, history=history)
|
|
||||||
|
|
||||||
# <-------------- convert pdf into tex ------------->
|
# <-------------- convert pdf into tex ------------->
|
||||||
chatbot.append([f"解析项目: {txt}", "正在将PDF转换为tex项目,请耐心等待..."])
|
project_folder = pdf2tex_project(file_manifest[0])
|
||||||
yield from update_ui(chatbot=chatbot, history=history)
|
|
||||||
project_folder = pdf2tex_project(file_manifest[0], plugin_kwargs)
|
|
||||||
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 ------------->
|
# Translate English Latex to Chinese Latex, and compile it
|
||||||
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)]
|
file_manifest = [f for f in glob.glob(f'{project_folder}/**/*.tex', recursive=True)]
|
||||||
if len(file_manifest) == 0:
|
if len(file_manifest) == 0:
|
||||||
report_exception(chatbot, history, a=f"解析项目: {txt}", b=f"找不到任何.tex文件: {txt}")
|
report_exception(chatbot, history, a=f"解析项目: {txt}", b=f"找不到任何.tex文件: {txt}")
|
||||||
@@ -507,16 +452,8 @@ def PDF翻译中文并重新编译PDF(txt, llm_kwargs, plugin_kwargs, chatbot, h
|
|||||||
project_folder = desend_to_extracted_folder_if_exist(project_folder)
|
project_folder = desend_to_extracted_folder_if_exist(project_folder)
|
||||||
|
|
||||||
# <-------------- move latex project away from temp folder ------------->
|
# <-------------- move latex project away from temp folder ------------->
|
||||||
from shared_utils.fastapi_server import validate_path_safety
|
|
||||||
validate_path_safety(project_folder, chatbot.get_user())
|
|
||||||
project_folder = move_project(project_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 merge_translate_zh is already generated, skip gpt req ------------->
|
||||||
if not os.path.exists(project_folder + '/merge_translate_zh.tex'):
|
if not os.path.exists(project_folder + '/merge_translate_zh.tex'):
|
||||||
yield from Latex精细分解与转化(file_manifest, project_folder, llm_kwargs, plugin_kwargs,
|
yield from Latex精细分解与转化(file_manifest, project_folder, llm_kwargs, plugin_kwargs,
|
||||||
@@ -524,7 +461,6 @@ def PDF翻译中文并重新编译PDF(txt, llm_kwargs, plugin_kwargs, chatbot, h
|
|||||||
switch_prompt=_switch_prompt_)
|
switch_prompt=_switch_prompt_)
|
||||||
|
|
||||||
# <-------------- compile PDF ------------->
|
# <-------------- compile PDF ------------->
|
||||||
yield from update_ui_lastest_msg("正在将翻译好的项目tex项目编译为PDF...", chatbot=chatbot, history=history)
|
|
||||||
success = yield from 编译Latex(chatbot, history, main_file_original='merge',
|
success = yield from 编译Latex(chatbot, history, main_file_original='merge',
|
||||||
main_file_modified='merge_translate_zh', mode='translate_zh',
|
main_file_modified='merge_translate_zh', mode='translate_zh',
|
||||||
work_folder_original=project_folder, work_folder_modified=project_folder,
|
work_folder_original=project_folder, work_folder_modified=project_folder,
|
||||||
@@ -1,83 +0,0 @@
|
|||||||
from toolbox import CatchException, check_packages, get_conf
|
|
||||||
from toolbox import update_ui, update_ui_lastest_msg, disable_auto_promotion
|
|
||||||
from toolbox import trimmed_format_exc_markdown
|
|
||||||
from crazy_functions.crazy_utils import get_files_from_everything
|
|
||||||
from crazy_functions.pdf_fns.parse_pdf import get_avail_grobid_url
|
|
||||||
from crazy_functions.pdf_fns.parse_pdf_via_doc2x import 解析PDF_基于DOC2X
|
|
||||||
from crazy_functions.pdf_fns.parse_pdf_legacy import 解析PDF_简单拆解
|
|
||||||
from crazy_functions.pdf_fns.parse_pdf_grobid import 解析PDF_基于GROBID
|
|
||||||
from shared_utils.colorful import *
|
|
||||||
|
|
||||||
@CatchException
|
|
||||||
def 批量翻译PDF文档(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request):
|
|
||||||
|
|
||||||
disable_auto_promotion(chatbot)
|
|
||||||
# 基本信息:功能、贡献者
|
|
||||||
chatbot.append([None, "插件功能:批量翻译PDF文档。函数插件贡献者: Binary-Husky"])
|
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
|
||||||
|
|
||||||
# 尝试导入依赖,如果缺少依赖,则给出安装建议
|
|
||||||
try:
|
|
||||||
check_packages(["fitz", "tiktoken", "scipdf"])
|
|
||||||
except:
|
|
||||||
chatbot.append([None, f"导入软件依赖失败。使用该模块需要额外依赖,安装方法```pip install --upgrade pymupdf tiktoken scipdf_parser```。"])
|
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
|
||||||
return
|
|
||||||
|
|
||||||
# 清空历史,以免输入溢出
|
|
||||||
history = []
|
|
||||||
success, file_manifest, project_folder = get_files_from_everything(txt, type='.pdf')
|
|
||||||
|
|
||||||
# 检测输入参数,如没有给定输入参数,直接退出
|
|
||||||
if (not success) and txt == "": txt = '空空如也的输入栏。提示:请先上传文件(把PDF文件拖入对话)。'
|
|
||||||
|
|
||||||
# 如果没找到任何文件
|
|
||||||
if len(file_manifest) == 0:
|
|
||||||
chatbot.append([None, f"找不到任何.pdf拓展名的文件: {txt}"])
|
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
|
||||||
return
|
|
||||||
|
|
||||||
# 开始正式执行任务
|
|
||||||
method = plugin_kwargs.get("pdf_parse_method", None)
|
|
||||||
if method == "DOC2X":
|
|
||||||
# ------- 第一种方法,效果最好,但是需要DOC2X服务 -------
|
|
||||||
DOC2X_API_KEY = get_conf("DOC2X_API_KEY")
|
|
||||||
if len(DOC2X_API_KEY) != 0:
|
|
||||||
try:
|
|
||||||
yield from 解析PDF_基于DOC2X(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, DOC2X_API_KEY, user_request)
|
|
||||||
return
|
|
||||||
except:
|
|
||||||
chatbot.append([None, f"DOC2X服务不可用,现在将执行效果稍差的旧版代码。{trimmed_format_exc_markdown()}"])
|
|
||||||
yield from update_ui(chatbot=chatbot, history=history)
|
|
||||||
|
|
||||||
if method == "GROBID":
|
|
||||||
# ------- 第二种方法,效果次优 -------
|
|
||||||
grobid_url = get_avail_grobid_url()
|
|
||||||
if grobid_url is not None:
|
|
||||||
yield from 解析PDF_基于GROBID(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, grobid_url)
|
|
||||||
return
|
|
||||||
|
|
||||||
if method == "ClASSIC":
|
|
||||||
# ------- 第三种方法,早期代码,效果不理想 -------
|
|
||||||
yield from update_ui_lastest_msg("GROBID服务不可用,请检查config中的GROBID_URL。作为替代,现在将执行效果稍差的旧版代码。", chatbot, history, delay=3)
|
|
||||||
yield from 解析PDF_简单拆解(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt)
|
|
||||||
return
|
|
||||||
|
|
||||||
if method is None:
|
|
||||||
# ------- 以上三种方法都试一遍 -------
|
|
||||||
DOC2X_API_KEY = get_conf("DOC2X_API_KEY")
|
|
||||||
if len(DOC2X_API_KEY) != 0:
|
|
||||||
try:
|
|
||||||
yield from 解析PDF_基于DOC2X(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, DOC2X_API_KEY, user_request)
|
|
||||||
return
|
|
||||||
except:
|
|
||||||
chatbot.append([None, f"DOC2X服务不可用,正在尝试GROBID。{trimmed_format_exc_markdown()}"])
|
|
||||||
yield from update_ui(chatbot=chatbot, history=history)
|
|
||||||
grobid_url = get_avail_grobid_url()
|
|
||||||
if grobid_url is not None:
|
|
||||||
yield from 解析PDF_基于GROBID(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, grobid_url)
|
|
||||||
return
|
|
||||||
yield from update_ui_lastest_msg("GROBID服务不可用,请检查config中的GROBID_URL。作为替代,现在将执行效果稍差的旧版代码。", chatbot, history, delay=3)
|
|
||||||
yield from 解析PDF_简单拆解(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt)
|
|
||||||
return
|
|
||||||
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
from crazy_functions.plugin_template.plugin_class_template import GptAcademicPluginTemplate, ArgProperty
|
|
||||||
from .PDF_Translate import 批量翻译PDF文档
|
|
||||||
|
|
||||||
|
|
||||||
class PDF_Tran(GptAcademicPluginTemplate):
|
|
||||||
def __init__(self):
|
|
||||||
"""
|
|
||||||
请注意`execute`会执行在不同的线程中,因此您在定义和使用类变量时,应当慎之又慎!
|
|
||||||
"""
|
|
||||||
pass
|
|
||||||
|
|
||||||
def define_arg_selection_menu(self):
|
|
||||||
"""
|
|
||||||
定义插件的二级选项菜单
|
|
||||||
"""
|
|
||||||
gui_definition = {
|
|
||||||
"main_input":
|
|
||||||
ArgProperty(title="PDF文件路径", description="未指定路径,请上传文件后,再点击该插件", default_value="", type="string").model_dump_json(), # 主输入,自动从输入框同步
|
|
||||||
"additional_prompt":
|
|
||||||
ArgProperty(title="额外提示词", description="例如:对专有名词、翻译语气等方面的要求", default_value="", type="string").model_dump_json(), # 高级参数输入区,自动同步
|
|
||||||
"pdf_parse_method":
|
|
||||||
ArgProperty(title="PDF解析方法", options=["DOC2X", "GROBID", "ClASSIC"], description="无", default_value="GROBID", type="dropdown").model_dump_json(),
|
|
||||||
}
|
|
||||||
return gui_definition
|
|
||||||
|
|
||||||
def execute(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request):
|
|
||||||
"""
|
|
||||||
执行插件
|
|
||||||
"""
|
|
||||||
main_input = plugin_kwargs["main_input"]
|
|
||||||
additional_prompt = plugin_kwargs["additional_prompt"]
|
|
||||||
pdf_parse_method = plugin_kwargs["pdf_parse_method"]
|
|
||||||
yield from 批量翻译PDF文档(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request)
|
|
||||||
@@ -1,138 +0,0 @@
|
|||||||
import os, copy, time
|
|
||||||
from toolbox import CatchException, report_exception, update_ui, zip_result, promote_file_to_downloadzone, update_ui_lastest_msg, get_conf, generate_file_link
|
|
||||||
from shared_utils.fastapi_server import validate_path_safety
|
|
||||||
from crazy_functions.crazy_utils import input_clipping
|
|
||||||
from crazy_functions.crazy_utils import request_gpt_model_multi_threads_with_very_awesome_ui_and_high_efficiency
|
|
||||||
from crazy_functions.crazy_utils import request_gpt_model_in_new_thread_with_ui_alive
|
|
||||||
from crazy_functions.agent_fns.python_comment_agent import PythonCodeComment
|
|
||||||
from crazy_functions.diagram_fns.file_tree import FileNode
|
|
||||||
from shared_utils.advanced_markdown_format import markdown_convertion_for_file
|
|
||||||
|
|
||||||
def 注释源代码(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt):
|
|
||||||
|
|
||||||
summary_batch_isolation = True
|
|
||||||
inputs_array = []
|
|
||||||
inputs_show_user_array = []
|
|
||||||
history_array = []
|
|
||||||
sys_prompt_array = []
|
|
||||||
|
|
||||||
assert len(file_manifest) <= 512, "源文件太多(超过512个), 请缩减输入文件的数量。或者,您也可以选择删除此行警告,并修改代码拆分file_manifest列表,从而实现分批次处理。"
|
|
||||||
|
|
||||||
# 建立文件树
|
|
||||||
file_tree_struct = FileNode("root", build_manifest=True)
|
|
||||||
for file_path in file_manifest:
|
|
||||||
file_tree_struct.add_file(file_path, file_path)
|
|
||||||
|
|
||||||
# <第一步,逐个文件分析,多线程>
|
|
||||||
for index, fp in enumerate(file_manifest):
|
|
||||||
# 读取文件
|
|
||||||
with open(fp, 'r', encoding='utf-8', errors='replace') as f:
|
|
||||||
file_content = f.read()
|
|
||||||
prefix = ""
|
|
||||||
i_say = prefix + f'Please conclude the following source code at {os.path.relpath(fp, project_folder)} with only one sentence, the code is:\n```{file_content}```'
|
|
||||||
i_say_show_user = prefix + f'[{index+1}/{len(file_manifest)}] 请用一句话对下面的程序文件做一个整体概述: {fp}'
|
|
||||||
# 装载请求内容
|
|
||||||
MAX_TOKEN_SINGLE_FILE = 2560
|
|
||||||
i_say, _ = input_clipping(inputs=i_say, history=[], max_token_limit=MAX_TOKEN_SINGLE_FILE)
|
|
||||||
inputs_array.append(i_say)
|
|
||||||
inputs_show_user_array.append(i_say_show_user)
|
|
||||||
history_array.append([])
|
|
||||||
sys_prompt_array.append("You are a software architecture analyst analyzing a source code project. Do not dig into details, tell me what the code is doing in general. Your answer must be short, simple and clear.")
|
|
||||||
# 文件读取完成,对每一个源代码文件,生成一个请求线程,发送到大模型进行分析
|
|
||||||
gpt_response_collection = yield from request_gpt_model_multi_threads_with_very_awesome_ui_and_high_efficiency(
|
|
||||||
inputs_array = inputs_array,
|
|
||||||
inputs_show_user_array = inputs_show_user_array,
|
|
||||||
history_array = history_array,
|
|
||||||
sys_prompt_array = sys_prompt_array,
|
|
||||||
llm_kwargs = llm_kwargs,
|
|
||||||
chatbot = chatbot,
|
|
||||||
show_user_at_complete = True
|
|
||||||
)
|
|
||||||
|
|
||||||
# <第二步,逐个文件分析,生成带注释文件>
|
|
||||||
from concurrent.futures import ThreadPoolExecutor
|
|
||||||
executor = ThreadPoolExecutor(max_workers=get_conf('DEFAULT_WORKER_NUM'))
|
|
||||||
def _task_multi_threading(i_say, gpt_say, fp, file_tree_struct):
|
|
||||||
pcc = PythonCodeComment(llm_kwargs, language='English')
|
|
||||||
pcc.read_file(path=fp, brief=gpt_say)
|
|
||||||
revised_path, revised_content = pcc.begin_comment_source_code(None, None)
|
|
||||||
file_tree_struct.manifest[fp].revised_path = revised_path
|
|
||||||
file_tree_struct.manifest[fp].revised_content = revised_content
|
|
||||||
# <将结果写回源文件>
|
|
||||||
with open(fp, 'w', encoding='utf-8') as f:
|
|
||||||
f.write(file_tree_struct.manifest[fp].revised_content)
|
|
||||||
# <生成对比html>
|
|
||||||
with open("crazy_functions/agent_fns/python_comment_compare.html", 'r', encoding='utf-8') as f:
|
|
||||||
html_template = f.read()
|
|
||||||
warp = lambda x: "```python\n\n" + x + "\n\n```"
|
|
||||||
from themes.theme import advanced_css
|
|
||||||
html_template = html_template.replace("ADVANCED_CSS", advanced_css)
|
|
||||||
html_template = html_template.replace("REPLACE_CODE_FILE_LEFT", pcc.get_markdown_block_in_html(markdown_convertion_for_file(warp(pcc.original_content))))
|
|
||||||
html_template = html_template.replace("REPLACE_CODE_FILE_RIGHT", pcc.get_markdown_block_in_html(markdown_convertion_for_file(warp(revised_content))))
|
|
||||||
compare_html_path = fp + '.compare.html'
|
|
||||||
file_tree_struct.manifest[fp].compare_html = compare_html_path
|
|
||||||
with open(compare_html_path, 'w', encoding='utf-8') as f:
|
|
||||||
f.write(html_template)
|
|
||||||
print('done 1')
|
|
||||||
|
|
||||||
chatbot.append([None, f"正在处理:"])
|
|
||||||
futures = []
|
|
||||||
for i_say, gpt_say, fp in zip(gpt_response_collection[0::2], gpt_response_collection[1::2], file_manifest):
|
|
||||||
future = executor.submit(_task_multi_threading, i_say, gpt_say, fp, file_tree_struct)
|
|
||||||
futures.append(future)
|
|
||||||
|
|
||||||
cnt = 0
|
|
||||||
while True:
|
|
||||||
cnt += 1
|
|
||||||
time.sleep(3)
|
|
||||||
worker_done = [h.done() for h in futures]
|
|
||||||
remain = len(worker_done) - sum(worker_done)
|
|
||||||
|
|
||||||
# <展示已经完成的部分>
|
|
||||||
preview_html_list = []
|
|
||||||
for done, fp in zip(worker_done, file_manifest):
|
|
||||||
if not done: continue
|
|
||||||
preview_html_list.append(file_tree_struct.manifest[fp].compare_html)
|
|
||||||
file_links = generate_file_link(preview_html_list)
|
|
||||||
|
|
||||||
yield from update_ui_lastest_msg(
|
|
||||||
f"剩余源文件数量: {remain}.\n\n" +
|
|
||||||
f"已完成的文件: {sum(worker_done)}.\n\n" +
|
|
||||||
file_links +
|
|
||||||
"\n\n" +
|
|
||||||
''.join(['.']*(cnt % 10 + 1)
|
|
||||||
), chatbot=chatbot, history=history, delay=0)
|
|
||||||
yield from update_ui(chatbot=chatbot, history=[]) # 刷新界面
|
|
||||||
if all(worker_done):
|
|
||||||
executor.shutdown()
|
|
||||||
break
|
|
||||||
|
|
||||||
# <第四步,压缩结果>
|
|
||||||
zip_res = zip_result(project_folder)
|
|
||||||
promote_file_to_downloadzone(file=zip_res, chatbot=chatbot)
|
|
||||||
|
|
||||||
# <END>
|
|
||||||
chatbot.append((None, "所有源文件均已处理完毕。"))
|
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@CatchException
|
|
||||||
def 注释Python项目(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request):
|
|
||||||
history = [] # 清空历史,以免输入溢出
|
|
||||||
import glob, os
|
|
||||||
if os.path.exists(txt):
|
|
||||||
project_folder = txt
|
|
||||||
validate_path_safety(project_folder, chatbot.get_user())
|
|
||||||
else:
|
|
||||||
if txt == "": txt = '空空如也的输入栏'
|
|
||||||
report_exception(chatbot, history, a = f"解析项目: {txt}", b = f"找不到本地项目或无权访问: {txt}")
|
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
|
||||||
return
|
|
||||||
file_manifest = [f for f in glob.glob(f'{project_folder}/**/*.py', recursive=True)]
|
|
||||||
if len(file_manifest) == 0:
|
|
||||||
report_exception(chatbot, history, a = f"解析项目: {txt}", b = f"找不到任何python文件: {txt}")
|
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
|
||||||
return
|
|
||||||
|
|
||||||
yield from 注释源代码(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt)
|
|
||||||
@@ -1,391 +0,0 @@
|
|||||||
from toolbox import CatchException, update_ui
|
|
||||||
from crazy_functions.crazy_utils import request_gpt_model_in_new_thread_with_ui_alive
|
|
||||||
from request_llms.bridge_all import predict_no_ui_long_connection
|
|
||||||
import datetime
|
|
||||||
import re
|
|
||||||
import os
|
|
||||||
from textwrap import dedent
|
|
||||||
# TODO: 解决缩进问题
|
|
||||||
|
|
||||||
find_function_end_prompt = '''
|
|
||||||
Below is a page of code that you need to read. This page may not yet complete, you job is to split this page to sperate functions, class functions etc.
|
|
||||||
- Provide the line number where the first visible function ends.
|
|
||||||
- Provide the line number where the next visible function begins.
|
|
||||||
- If there are no other functions in this page, you should simply return the line number of the last line.
|
|
||||||
- Only focus on functions declared by `def` keyword. Ignore inline functions. Ignore function calls.
|
|
||||||
|
|
||||||
------------------ Example ------------------
|
|
||||||
INPUT:
|
|
||||||
|
|
||||||
```
|
|
||||||
L0000 |import sys
|
|
||||||
L0001 |import re
|
|
||||||
L0002 |
|
|
||||||
L0003 |def trimmed_format_exc():
|
|
||||||
L0004 | import os
|
|
||||||
L0005 | import traceback
|
|
||||||
L0006 | str = traceback.format_exc()
|
|
||||||
L0007 | current_path = os.getcwd()
|
|
||||||
L0008 | replace_path = "."
|
|
||||||
L0009 | return str.replace(current_path, replace_path)
|
|
||||||
L0010 |
|
|
||||||
L0011 |
|
|
||||||
L0012 |def trimmed_format_exc_markdown():
|
|
||||||
L0013 | ...
|
|
||||||
L0014 | ...
|
|
||||||
```
|
|
||||||
|
|
||||||
OUTPUT:
|
|
||||||
|
|
||||||
```
|
|
||||||
<first_function_end_at>L0009</first_function_end_at>
|
|
||||||
<next_function_begin_from>L0012</next_function_begin_from>
|
|
||||||
```
|
|
||||||
|
|
||||||
------------------ End of Example ------------------
|
|
||||||
|
|
||||||
|
|
||||||
------------------ the real INPUT you need to process NOW ------------------
|
|
||||||
```
|
|
||||||
{THE_TAGGED_CODE}
|
|
||||||
```
|
|
||||||
'''
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
revise_funtion_prompt = '''
|
|
||||||
You need to read the following code, and revise the source code ({FILE_BASENAME}) according to following instructions:
|
|
||||||
1. You should analyze the purpose of the functions (if there are any).
|
|
||||||
2. You need to add docstring for the provided functions (if there are any).
|
|
||||||
|
|
||||||
Be aware:
|
|
||||||
1. You must NOT modify the indent of code.
|
|
||||||
2. You are NOT authorized to change or translate non-comment code, and you are NOT authorized to add empty lines either, toggle qu.
|
|
||||||
3. Use {LANG} to add comments and docstrings. Do NOT translate Chinese that is already in the code.
|
|
||||||
|
|
||||||
------------------ Example ------------------
|
|
||||||
INPUT:
|
|
||||||
```
|
|
||||||
L0000 |
|
|
||||||
L0001 |def zip_result(folder):
|
|
||||||
L0002 | t = gen_time_str()
|
|
||||||
L0003 | zip_folder(folder, get_log_folder(), f"result.zip")
|
|
||||||
L0004 | return os.path.join(get_log_folder(), f"result.zip")
|
|
||||||
L0005 |
|
|
||||||
L0006 |
|
|
||||||
```
|
|
||||||
|
|
||||||
OUTPUT:
|
|
||||||
|
|
||||||
<instruction_1_purpose>
|
|
||||||
This function compresses a given folder, and return the path of the resulting `zip` file.
|
|
||||||
</instruction_1_purpose>
|
|
||||||
<instruction_2_revised_code>
|
|
||||||
```
|
|
||||||
def zip_result(folder):
|
|
||||||
"""
|
|
||||||
Compresses the specified folder into a zip file and stores it in the log folder.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
folder (str): The path to the folder that needs to be compressed.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
str: The path to the created zip file in the log folder.
|
|
||||||
"""
|
|
||||||
t = gen_time_str()
|
|
||||||
zip_folder(folder, get_log_folder(), f"result.zip") # ⭐ Execute the zipping of folder
|
|
||||||
return os.path.join(get_log_folder(), f"result.zip")
|
|
||||||
```
|
|
||||||
</instruction_2_revised_code>
|
|
||||||
------------------ End of Example ------------------
|
|
||||||
|
|
||||||
|
|
||||||
------------------ the real INPUT you need to process NOW ({FILE_BASENAME}) ------------------
|
|
||||||
```
|
|
||||||
{THE_CODE}
|
|
||||||
```
|
|
||||||
{INDENT_REMINDER}
|
|
||||||
{BRIEF_REMINDER}
|
|
||||||
{HINT_REMINDER}
|
|
||||||
'''
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class PythonCodeComment():
|
|
||||||
|
|
||||||
def __init__(self, llm_kwargs, language) -> None:
|
|
||||||
self.original_content = ""
|
|
||||||
self.full_context = []
|
|
||||||
self.full_context_with_line_no = []
|
|
||||||
self.current_page_start = 0
|
|
||||||
self.page_limit = 100 # 100 lines of code each page
|
|
||||||
self.ignore_limit = 20
|
|
||||||
self.llm_kwargs = llm_kwargs
|
|
||||||
self.language = language
|
|
||||||
self.path = None
|
|
||||||
self.file_basename = None
|
|
||||||
self.file_brief = ""
|
|
||||||
|
|
||||||
def generate_tagged_code_from_full_context(self):
|
|
||||||
for i, code in enumerate(self.full_context):
|
|
||||||
number = i
|
|
||||||
padded_number = f"{number:04}"
|
|
||||||
result = f"L{padded_number}"
|
|
||||||
self.full_context_with_line_no.append(f"{result} | {code}")
|
|
||||||
return self.full_context_with_line_no
|
|
||||||
|
|
||||||
def read_file(self, path, brief):
|
|
||||||
with open(path, 'r', encoding='utf8') as f:
|
|
||||||
self.full_context = f.readlines()
|
|
||||||
self.original_content = ''.join(self.full_context)
|
|
||||||
self.file_basename = os.path.basename(path)
|
|
||||||
self.file_brief = brief
|
|
||||||
self.full_context_with_line_no = self.generate_tagged_code_from_full_context()
|
|
||||||
self.path = path
|
|
||||||
|
|
||||||
def find_next_function_begin(self, tagged_code:list, begin_and_end):
|
|
||||||
begin, end = begin_and_end
|
|
||||||
THE_TAGGED_CODE = ''.join(tagged_code)
|
|
||||||
self.llm_kwargs['temperature'] = 0
|
|
||||||
result = predict_no_ui_long_connection(
|
|
||||||
inputs=find_function_end_prompt.format(THE_TAGGED_CODE=THE_TAGGED_CODE),
|
|
||||||
llm_kwargs=self.llm_kwargs,
|
|
||||||
history=[],
|
|
||||||
sys_prompt="",
|
|
||||||
observe_window=[],
|
|
||||||
console_slience=True
|
|
||||||
)
|
|
||||||
|
|
||||||
def extract_number(text):
|
|
||||||
# 使用正则表达式匹配模式
|
|
||||||
match = re.search(r'<next_function_begin_from>L(\d+)</next_function_begin_from>', text)
|
|
||||||
if match:
|
|
||||||
# 提取匹配的数字部分并转换为整数
|
|
||||||
return int(match.group(1))
|
|
||||||
return None
|
|
||||||
|
|
||||||
line_no = extract_number(result)
|
|
||||||
if line_no is not None:
|
|
||||||
return line_no
|
|
||||||
else:
|
|
||||||
return end
|
|
||||||
|
|
||||||
def _get_next_window(self):
|
|
||||||
#
|
|
||||||
current_page_start = self.current_page_start
|
|
||||||
|
|
||||||
if self.current_page_start == len(self.full_context) + 1:
|
|
||||||
raise StopIteration
|
|
||||||
|
|
||||||
# 如果剩余的行数非常少,一鼓作气处理掉
|
|
||||||
if len(self.full_context) - self.current_page_start < self.ignore_limit:
|
|
||||||
future_page_start = len(self.full_context) + 1
|
|
||||||
self.current_page_start = future_page_start
|
|
||||||
return current_page_start, future_page_start
|
|
||||||
|
|
||||||
|
|
||||||
tagged_code = self.full_context_with_line_no[ self.current_page_start: self.current_page_start + self.page_limit]
|
|
||||||
line_no = self.find_next_function_begin(tagged_code, [self.current_page_start, self.current_page_start + self.page_limit])
|
|
||||||
|
|
||||||
if line_no > len(self.full_context) - 5:
|
|
||||||
line_no = len(self.full_context) + 1
|
|
||||||
|
|
||||||
future_page_start = line_no
|
|
||||||
self.current_page_start = future_page_start
|
|
||||||
|
|
||||||
# ! consider eof
|
|
||||||
return current_page_start, future_page_start
|
|
||||||
|
|
||||||
def dedent(self, text):
|
|
||||||
"""Remove any common leading whitespace from every line in `text`.
|
|
||||||
"""
|
|
||||||
# Look for the longest leading string of spaces and tabs common to
|
|
||||||
# all lines.
|
|
||||||
margin = None
|
|
||||||
_whitespace_only_re = re.compile('^[ \t]+$', re.MULTILINE)
|
|
||||||
_leading_whitespace_re = re.compile('(^[ \t]*)(?:[^ \t\n])', re.MULTILINE)
|
|
||||||
text = _whitespace_only_re.sub('', text)
|
|
||||||
indents = _leading_whitespace_re.findall(text)
|
|
||||||
for indent in indents:
|
|
||||||
if margin is None:
|
|
||||||
margin = indent
|
|
||||||
|
|
||||||
# Current line more deeply indented than previous winner:
|
|
||||||
# no change (previous winner is still on top).
|
|
||||||
elif indent.startswith(margin):
|
|
||||||
pass
|
|
||||||
|
|
||||||
# Current line consistent with and no deeper than previous winner:
|
|
||||||
# it's the new winner.
|
|
||||||
elif margin.startswith(indent):
|
|
||||||
margin = indent
|
|
||||||
|
|
||||||
# Find the largest common whitespace between current line and previous
|
|
||||||
# winner.
|
|
||||||
else:
|
|
||||||
for i, (x, y) in enumerate(zip(margin, indent)):
|
|
||||||
if x != y:
|
|
||||||
margin = margin[:i]
|
|
||||||
break
|
|
||||||
|
|
||||||
# sanity check (testing/debugging only)
|
|
||||||
if 0 and margin:
|
|
||||||
for line in text.split("\n"):
|
|
||||||
assert not line or line.startswith(margin), \
|
|
||||||
"line = %r, margin = %r" % (line, margin)
|
|
||||||
|
|
||||||
if margin:
|
|
||||||
text = re.sub(r'(?m)^' + margin, '', text)
|
|
||||||
return text, len(margin)
|
|
||||||
else:
|
|
||||||
return text, 0
|
|
||||||
|
|
||||||
def get_next_batch(self):
|
|
||||||
current_page_start, future_page_start = self._get_next_window()
|
|
||||||
return ''.join(self.full_context[current_page_start: future_page_start]), current_page_start, future_page_start
|
|
||||||
|
|
||||||
def tag_code(self, fn, hint):
|
|
||||||
code = fn
|
|
||||||
_, n_indent = self.dedent(code)
|
|
||||||
indent_reminder = "" if n_indent == 0 else "(Reminder: as you can see, this piece of code has indent made up with {n_indent} whitespace, please preseve them in the OUTPUT.)"
|
|
||||||
brief_reminder = "" if self.file_brief == "" else f"({self.file_basename} abstract: {self.file_brief})"
|
|
||||||
hint_reminder = "" if hint is None else f"(Reminder: do not ignore or modify code such as `{hint}`, provide complete code in the OUTPUT.)"
|
|
||||||
self.llm_kwargs['temperature'] = 0
|
|
||||||
result = predict_no_ui_long_connection(
|
|
||||||
inputs=revise_funtion_prompt.format(
|
|
||||||
LANG=self.language,
|
|
||||||
FILE_BASENAME=self.file_basename,
|
|
||||||
THE_CODE=code,
|
|
||||||
INDENT_REMINDER=indent_reminder,
|
|
||||||
BRIEF_REMINDER=brief_reminder,
|
|
||||||
HINT_REMINDER=hint_reminder
|
|
||||||
),
|
|
||||||
llm_kwargs=self.llm_kwargs,
|
|
||||||
history=[],
|
|
||||||
sys_prompt="",
|
|
||||||
observe_window=[],
|
|
||||||
console_slience=True
|
|
||||||
)
|
|
||||||
|
|
||||||
def get_code_block(reply):
|
|
||||||
import re
|
|
||||||
pattern = r"```([\s\S]*?)```" # regex pattern to match code blocks
|
|
||||||
matches = re.findall(pattern, reply) # find all code blocks in text
|
|
||||||
if len(matches) == 1:
|
|
||||||
return matches[0].strip('python') # code block
|
|
||||||
return None
|
|
||||||
|
|
||||||
code_block = get_code_block(result)
|
|
||||||
if code_block is not None:
|
|
||||||
code_block = self.sync_and_patch(original=code, revised=code_block)
|
|
||||||
return code_block
|
|
||||||
else:
|
|
||||||
return code
|
|
||||||
|
|
||||||
def get_markdown_block_in_html(self, html):
|
|
||||||
from bs4 import BeautifulSoup
|
|
||||||
soup = BeautifulSoup(html, 'lxml')
|
|
||||||
found_list = soup.find_all("div", class_="markdown-body")
|
|
||||||
if found_list:
|
|
||||||
res = found_list[0]
|
|
||||||
return res.prettify()
|
|
||||||
else:
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
def sync_and_patch(self, original, revised):
|
|
||||||
"""Ensure the number of pre-string empty lines in revised matches those in original."""
|
|
||||||
|
|
||||||
def count_leading_empty_lines(s, reverse=False):
|
|
||||||
"""Count the number of leading empty lines in a string."""
|
|
||||||
lines = s.split('\n')
|
|
||||||
if reverse: lines = list(reversed(lines))
|
|
||||||
count = 0
|
|
||||||
for line in lines:
|
|
||||||
if line.strip() == '':
|
|
||||||
count += 1
|
|
||||||
else:
|
|
||||||
break
|
|
||||||
return count
|
|
||||||
|
|
||||||
original_empty_lines = count_leading_empty_lines(original)
|
|
||||||
revised_empty_lines = count_leading_empty_lines(revised)
|
|
||||||
|
|
||||||
if original_empty_lines > revised_empty_lines:
|
|
||||||
additional_lines = '\n' * (original_empty_lines - revised_empty_lines)
|
|
||||||
revised = additional_lines + revised
|
|
||||||
elif original_empty_lines < revised_empty_lines:
|
|
||||||
lines = revised.split('\n')
|
|
||||||
revised = '\n'.join(lines[revised_empty_lines - original_empty_lines:])
|
|
||||||
|
|
||||||
original_empty_lines = count_leading_empty_lines(original, reverse=True)
|
|
||||||
revised_empty_lines = count_leading_empty_lines(revised, reverse=True)
|
|
||||||
|
|
||||||
if original_empty_lines > revised_empty_lines:
|
|
||||||
additional_lines = '\n' * (original_empty_lines - revised_empty_lines)
|
|
||||||
revised = revised + additional_lines
|
|
||||||
elif original_empty_lines < revised_empty_lines:
|
|
||||||
lines = revised.split('\n')
|
|
||||||
revised = '\n'.join(lines[:-(revised_empty_lines - original_empty_lines)])
|
|
||||||
|
|
||||||
return revised
|
|
||||||
|
|
||||||
def begin_comment_source_code(self, chatbot=None, history=None):
|
|
||||||
# from toolbox import update_ui_lastest_msg
|
|
||||||
assert self.path is not None
|
|
||||||
assert '.py' in self.path # must be python source code
|
|
||||||
# write_target = self.path + '.revised.py'
|
|
||||||
|
|
||||||
write_content = ""
|
|
||||||
# with open(self.path + '.revised.py', 'w+', encoding='utf8') as f:
|
|
||||||
while True:
|
|
||||||
try:
|
|
||||||
# yield from update_ui_lastest_msg(f"({self.file_basename}) 正在读取下一段代码片段:\n", chatbot=chatbot, history=history, delay=0)
|
|
||||||
next_batch, line_no_start, line_no_end = self.get_next_batch()
|
|
||||||
# yield from update_ui_lastest_msg(f"({self.file_basename}) 处理代码片段:\n\n{next_batch}", chatbot=chatbot, history=history, delay=0)
|
|
||||||
|
|
||||||
hint = None
|
|
||||||
MAX_ATTEMPT = 2
|
|
||||||
for attempt in range(MAX_ATTEMPT):
|
|
||||||
result = self.tag_code(next_batch, hint)
|
|
||||||
try:
|
|
||||||
successful, hint = self.verify_successful(next_batch, result)
|
|
||||||
except Exception as e:
|
|
||||||
print('ignored exception:\n' + str(e))
|
|
||||||
break
|
|
||||||
if successful:
|
|
||||||
break
|
|
||||||
if attempt == MAX_ATTEMPT - 1:
|
|
||||||
# cannot deal with this, give up
|
|
||||||
result = next_batch
|
|
||||||
break
|
|
||||||
|
|
||||||
# f.write(result)
|
|
||||||
write_content += result
|
|
||||||
except StopIteration:
|
|
||||||
next_batch, line_no_start, line_no_end = [], -1, -1
|
|
||||||
return None, write_content
|
|
||||||
|
|
||||||
def verify_successful(self, original, revised):
|
|
||||||
""" Determine whether the revised code contains every line that already exists
|
|
||||||
"""
|
|
||||||
from crazy_functions.ast_fns.comment_remove import remove_python_comments
|
|
||||||
original = remove_python_comments(original)
|
|
||||||
original_lines = original.split('\n')
|
|
||||||
revised_lines = revised.split('\n')
|
|
||||||
|
|
||||||
for l in original_lines:
|
|
||||||
l = l.strip()
|
|
||||||
if '\'' in l or '\"' in l: continue # ast sometimes toggle " to '
|
|
||||||
found = False
|
|
||||||
for lt in revised_lines:
|
|
||||||
if l in lt:
|
|
||||||
found = True
|
|
||||||
break
|
|
||||||
if not found:
|
|
||||||
return False, l
|
|
||||||
return True, None
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html lang="zh-CN">
|
|
||||||
<head>
|
|
||||||
<style>ADVANCED_CSS</style>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<title>源文件对比</title>
|
|
||||||
<style>
|
|
||||||
body {
|
|
||||||
font-family: Arial, sans-serif;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
height: 100vh;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
.container {
|
|
||||||
display: flex;
|
|
||||||
width: 95%;
|
|
||||||
height: -webkit-fill-available;
|
|
||||||
}
|
|
||||||
.code-container {
|
|
||||||
flex: 1;
|
|
||||||
margin: 0px;
|
|
||||||
padding: 0px;
|
|
||||||
border: 1px solid #ccc;
|
|
||||||
background-color: #f9f9f9;
|
|
||||||
overflow: auto;
|
|
||||||
}
|
|
||||||
pre {
|
|
||||||
white-space: pre-wrap;
|
|
||||||
word-wrap: break-word;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div class="container">
|
|
||||||
<div class="code-container">
|
|
||||||
REPLACE_CODE_FILE_LEFT
|
|
||||||
</div>
|
|
||||||
<div class="code-container">
|
|
||||||
REPLACE_CODE_FILE_RIGHT
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
import ast
|
|
||||||
|
|
||||||
class CommentRemover(ast.NodeTransformer):
|
|
||||||
def visit_FunctionDef(self, node):
|
|
||||||
# 移除函数的文档字符串
|
|
||||||
if (node.body and isinstance(node.body[0], ast.Expr) and
|
|
||||||
isinstance(node.body[0].value, ast.Str)):
|
|
||||||
node.body = node.body[1:]
|
|
||||||
self.generic_visit(node)
|
|
||||||
return node
|
|
||||||
|
|
||||||
def visit_ClassDef(self, node):
|
|
||||||
# 移除类的文档字符串
|
|
||||||
if (node.body and isinstance(node.body[0], ast.Expr) and
|
|
||||||
isinstance(node.body[0].value, ast.Str)):
|
|
||||||
node.body = node.body[1:]
|
|
||||||
self.generic_visit(node)
|
|
||||||
return node
|
|
||||||
|
|
||||||
def visit_Module(self, node):
|
|
||||||
# 移除模块的文档字符串
|
|
||||||
if (node.body and isinstance(node.body[0], ast.Expr) and
|
|
||||||
isinstance(node.body[0].value, ast.Str)):
|
|
||||||
node.body = node.body[1:]
|
|
||||||
self.generic_visit(node)
|
|
||||||
return node
|
|
||||||
|
|
||||||
|
|
||||||
def remove_python_comments(source_code):
|
|
||||||
# 解析源代码为 AST
|
|
||||||
tree = ast.parse(source_code)
|
|
||||||
# 移除注释
|
|
||||||
transformer = CommentRemover()
|
|
||||||
tree = transformer.visit(tree)
|
|
||||||
# 将处理后的 AST 转换回源代码
|
|
||||||
return ast.unparse(tree)
|
|
||||||
|
|
||||||
# 示例使用
|
|
||||||
if __name__ == "__main__":
|
|
||||||
with open("source.py", "r", encoding="utf-8") as f:
|
|
||||||
source_code = f.read()
|
|
||||||
|
|
||||||
cleaned_code = remove_python_comments(source_code)
|
|
||||||
|
|
||||||
with open("cleaned_source.py", "w", encoding="utf-8") as f:
|
|
||||||
f.write(cleaned_code)
|
|
||||||
@@ -1,20 +1,9 @@
|
|||||||
from toolbox import update_ui, get_conf, trimmed_format_exc, get_max_token, Singleton
|
from toolbox import update_ui, get_conf, trimmed_format_exc, get_max_token, Singleton
|
||||||
from shared_utils.char_visual_effect import scolling_visual_effect
|
|
||||||
import threading
|
import threading
|
||||||
import os
|
import os
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
def input_clipping(inputs, history, max_token_limit):
|
def input_clipping(inputs, history, max_token_limit):
|
||||||
"""
|
|
||||||
当输入文本 + 历史文本超出最大限制时,采取措施丢弃一部分文本。
|
|
||||||
输入:
|
|
||||||
- inputs 本次请求
|
|
||||||
- history 历史上下文
|
|
||||||
- max_token_limit 最大token限制
|
|
||||||
输出:
|
|
||||||
- inputs 本次请求(经过clip)
|
|
||||||
- history 历史上下文(经过clip)
|
|
||||||
"""
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from request_llms.bridge_all import model_info
|
from request_llms.bridge_all import model_info
|
||||||
enc = model_info["gpt-3.5-turbo"]['tokenizer']
|
enc = model_info["gpt-3.5-turbo"]['tokenizer']
|
||||||
@@ -146,11 +135,7 @@ 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) -> bool:
|
def can_multi_process(llm):
|
||||||
from request_llms.bridge_all import model_info
|
|
||||||
|
|
||||||
def default_condition(llm) -> bool:
|
|
||||||
# legacy condition
|
|
||||||
if llm.startswith('gpt-'): return True
|
if llm.startswith('gpt-'): return True
|
||||||
if llm.startswith('api2d-'): return True
|
if llm.startswith('api2d-'): return True
|
||||||
if llm.startswith('azure-'): return True
|
if llm.startswith('azure-'): return True
|
||||||
@@ -158,18 +143,10 @@ def can_multi_process(llm) -> bool:
|
|||||||
if llm.startswith('zhipuai') or llm.startswith('glm-'): return True
|
if llm.startswith('zhipuai') or llm.startswith('glm-'): return True
|
||||||
return False
|
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,
|
||||||
chatbot, history_array, sys_prompt_array,
|
chatbot, history_array, sys_prompt_array,
|
||||||
refresh_interval=0.2, max_workers=-1, scroller_max_len=75,
|
refresh_interval=0.2, max_workers=-1, scroller_max_len=30,
|
||||||
handle_token_exceed=True, show_user_at_complete=False,
|
handle_token_exceed=True, show_user_at_complete=False,
|
||||||
retry_times_at_unknown_error=2,
|
retry_times_at_unknown_error=2,
|
||||||
):
|
):
|
||||||
@@ -294,8 +271,6 @@ def request_gpt_model_multi_threads_with_very_awesome_ui_and_high_efficiency(
|
|||||||
futures = [executor.submit(_req_gpt, index, inputs, history, sys_prompt) for index, inputs, history, sys_prompt in zip(
|
futures = [executor.submit(_req_gpt, index, inputs, history, sys_prompt) for index, inputs, history, sys_prompt in zip(
|
||||||
range(len(inputs_array)), inputs_array, history_array, sys_prompt_array)]
|
range(len(inputs_array)), inputs_array, history_array, sys_prompt_array)]
|
||||||
cnt = 0
|
cnt = 0
|
||||||
|
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
# yield一次以刷新前端页面
|
# yield一次以刷新前端页面
|
||||||
time.sleep(refresh_interval)
|
time.sleep(refresh_interval)
|
||||||
@@ -308,7 +283,8 @@ def request_gpt_model_multi_threads_with_very_awesome_ui_and_high_efficiency(
|
|||||||
mutable[thread_index][1] = time.time()
|
mutable[thread_index][1] = time.time()
|
||||||
# 在前端打印些好玩的东西
|
# 在前端打印些好玩的东西
|
||||||
for thread_index, _ in enumerate(worker_done):
|
for thread_index, _ in enumerate(worker_done):
|
||||||
print_something_really_funny = f"[ ...`{scolling_visual_effect(mutable[thread_index][0], scroller_max_len)}`... ]"
|
print_something_really_funny = "[ ...`"+mutable[thread_index][0][-scroller_max_len:].\
|
||||||
|
replace('\n', '').replace('`', '.').replace(' ', '.').replace('<br/>', '.....').replace('$', '.')+"`... ]"
|
||||||
observe_win.append(print_something_really_funny)
|
observe_win.append(print_something_really_funny)
|
||||||
# 在前端打印些好玩的东西
|
# 在前端打印些好玩的东西
|
||||||
stat_str = ''.join([f'`{mutable[thread_index][2]}`: {obs}\n\n'
|
stat_str = ''.join([f'`{mutable[thread_index][2]}`: {obs}\n\n'
|
||||||
@@ -361,7 +337,7 @@ def read_and_clean_pdf_text(fp):
|
|||||||
import fitz, copy
|
import fitz, copy
|
||||||
import re
|
import re
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from shared_utils.colorful import print亮黄, print亮绿
|
from colorful import print亮黄, print亮绿
|
||||||
fc = 0 # Index 0 文本
|
fc = 0 # Index 0 文本
|
||||||
fs = 1 # Index 1 字体
|
fs = 1 # Index 1 字体
|
||||||
fb = 2 # Index 2 框框
|
fb = 2 # Index 2 框框
|
||||||
@@ -580,7 +556,7 @@ class nougat_interface():
|
|||||||
from toolbox import ProxyNetworkActivate
|
from toolbox import ProxyNetworkActivate
|
||||||
logging.info(f'正在执行命令 {command}')
|
logging.info(f'正在执行命令 {command}')
|
||||||
with ProxyNetworkActivate("Nougat_Download"):
|
with ProxyNetworkActivate("Nougat_Download"):
|
||||||
process = subprocess.Popen(command, shell=False, cwd=cwd, env=os.environ)
|
process = subprocess.Popen(command, shell=True, cwd=cwd, env=os.environ)
|
||||||
try:
|
try:
|
||||||
stdout, stderr = process.communicate(timeout=timeout)
|
stdout, stderr = process.communicate(timeout=timeout)
|
||||||
except subprocess.TimeoutExpired:
|
except subprocess.TimeoutExpired:
|
||||||
@@ -604,8 +580,7 @@ class nougat_interface():
|
|||||||
|
|
||||||
yield from update_ui_lastest_msg("正在解析论文, 请稍候。进度:正在加载NOUGAT... (提示:首次运行需要花费较长时间下载NOUGAT参数)",
|
yield from update_ui_lastest_msg("正在解析论文, 请稍候。进度:正在加载NOUGAT... (提示:首次运行需要花费较长时间下载NOUGAT参数)",
|
||||||
chatbot=chatbot, history=history, delay=0)
|
chatbot=chatbot, history=history, delay=0)
|
||||||
command = ['nougat', '--out', os.path.abspath(dst), os.path.abspath(fp)]
|
self.nougat_with_timeout(f'nougat --out "{os.path.abspath(dst)}" "{os.path.abspath(fp)}"', os.getcwd(), timeout=3600)
|
||||||
self.nougat_with_timeout(command, cwd=os.getcwd(), timeout=3600)
|
|
||||||
res = glob.glob(os.path.join(dst,'*.mmd'))
|
res = glob.glob(os.path.join(dst,'*.mmd'))
|
||||||
if len(res) == 0:
|
if len(res) == 0:
|
||||||
self.threadLock.release()
|
self.threadLock.release()
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import os
|
|||||||
from textwrap import indent
|
from textwrap import indent
|
||||||
|
|
||||||
class FileNode:
|
class FileNode:
|
||||||
def __init__(self, name, build_manifest=False):
|
def __init__(self, name):
|
||||||
self.name = name
|
self.name = name
|
||||||
self.children = []
|
self.children = []
|
||||||
self.is_leaf = False
|
self.is_leaf = False
|
||||||
@@ -10,8 +10,6 @@ class FileNode:
|
|||||||
self.parenting_ship = []
|
self.parenting_ship = []
|
||||||
self.comment = ""
|
self.comment = ""
|
||||||
self.comment_maxlen_show = 50
|
self.comment_maxlen_show = 50
|
||||||
self.build_manifest = build_manifest
|
|
||||||
self.manifest = {}
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def add_linebreaks_at_spaces(string, interval=10):
|
def add_linebreaks_at_spaces(string, interval=10):
|
||||||
@@ -31,7 +29,6 @@ class FileNode:
|
|||||||
level = 1
|
level = 1
|
||||||
if directory_names == "":
|
if directory_names == "":
|
||||||
new_node = FileNode(file_name)
|
new_node = FileNode(file_name)
|
||||||
self.manifest[file_path] = new_node
|
|
||||||
current_node.children.append(new_node)
|
current_node.children.append(new_node)
|
||||||
new_node.is_leaf = True
|
new_node.is_leaf = True
|
||||||
new_node.comment = self.sanitize_comment(file_comment)
|
new_node.comment = self.sanitize_comment(file_comment)
|
||||||
@@ -53,7 +50,6 @@ class FileNode:
|
|||||||
new_node.level = level - 1
|
new_node.level = level - 1
|
||||||
current_node = new_node
|
current_node = new_node
|
||||||
term = FileNode(file_name)
|
term = FileNode(file_name)
|
||||||
self.manifest[file_path] = term
|
|
||||||
term.level = level
|
term.level = level
|
||||||
term.comment = self.sanitize_comment(file_comment)
|
term.comment = self.sanitize_comment(file_comment)
|
||||||
term.is_leaf = True
|
term.is_leaf = True
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ class MiniGame_ResumeStory(GptAcademicGameBaseState):
|
|||||||
|
|
||||||
def generate_story_image(self, story_paragraph):
|
def generate_story_image(self, story_paragraph):
|
||||||
try:
|
try:
|
||||||
from crazy_functions.Image_Generate import gen_image
|
from crazy_functions.图片生成 import gen_image
|
||||||
prompt_ = predict_no_ui_long_connection(inputs=story_paragraph, llm_kwargs=self.llm_kwargs, history=[], sys_prompt='你需要根据用户给出的小说段落,进行简短的环境描写。要求:80字以内。')
|
prompt_ = predict_no_ui_long_connection(inputs=story_paragraph, llm_kwargs=self.llm_kwargs, history=[], sys_prompt='你需要根据用户给出的小说段落,进行简短的环境描写。要求:80字以内。')
|
||||||
image_url, image_path = gen_image(self.llm_kwargs, prompt_, '512x512', model="dall-e-2", quality='standard', style='natural')
|
image_url, image_path = gen_image(self.llm_kwargs, prompt_, '512x512', model="dall-e-2", quality='standard', style='natural')
|
||||||
return f'<br/><div align="center"><img src="file={image_path}"></div>'
|
return f'<br/><div align="center"><img src="file={image_path}"></div>'
|
||||||
|
|||||||
@@ -62,8 +62,8 @@ class GptJsonIO():
|
|||||||
if "type" in reduced_schema:
|
if "type" in reduced_schema:
|
||||||
del reduced_schema["type"]
|
del reduced_schema["type"]
|
||||||
# Ensure json in context is well-formed with double quotes.
|
# Ensure json in context is well-formed with double quotes.
|
||||||
schema_str = json.dumps(reduced_schema)
|
|
||||||
if self.example_instruction:
|
if self.example_instruction:
|
||||||
|
schema_str = json.dumps(reduced_schema)
|
||||||
return PYDANTIC_FORMAT_INSTRUCTIONS.format(schema=schema_str)
|
return PYDANTIC_FORMAT_INSTRUCTIONS.format(schema=schema_str)
|
||||||
else:
|
else:
|
||||||
return PYDANTIC_FORMAT_INSTRUCTIONS_SIMPLE.format(schema=schema_str)
|
return PYDANTIC_FORMAT_INSTRUCTIONS_SIMPLE.format(schema=schema_str)
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
from toolbox import update_ui, update_ui_lastest_msg, get_log_folder
|
from toolbox import update_ui, update_ui_lastest_msg, get_log_folder
|
||||||
from toolbox import get_conf, promote_file_to_downloadzone
|
from toolbox import get_conf, objdump, objload, promote_file_to_downloadzone
|
||||||
from .latex_toolbox import PRESERVE, TRANSFORM
|
from .latex_toolbox import PRESERVE, TRANSFORM
|
||||||
from .latex_toolbox import set_forbidden_text, set_forbidden_text_begin_end, set_forbidden_text_careful_brace
|
from .latex_toolbox import set_forbidden_text, set_forbidden_text_begin_end, set_forbidden_text_careful_brace
|
||||||
from .latex_toolbox import reverse_forbidden_text_careful_brace, reverse_forbidden_text, convert_to_linklist, post_process
|
from .latex_toolbox import reverse_forbidden_text_careful_brace, reverse_forbidden_text, convert_to_linklist, post_process
|
||||||
from .latex_toolbox import fix_content, find_main_tex_file, merge_tex_files, compile_latex_with_timeout
|
from .latex_toolbox import fix_content, find_main_tex_file, merge_tex_files, compile_latex_with_timeout
|
||||||
from .latex_toolbox import find_title_and_abs
|
from .latex_toolbox import find_title_and_abs
|
||||||
from .latex_pickle_io import objdump, objload
|
|
||||||
|
|
||||||
import os, shutil
|
import os, shutil
|
||||||
import re
|
import re
|
||||||
|
|||||||
@@ -1,46 +0,0 @@
|
|||||||
import pickle
|
|
||||||
|
|
||||||
|
|
||||||
class SafeUnpickler(pickle.Unpickler):
|
|
||||||
|
|
||||||
def get_safe_classes(self):
|
|
||||||
from crazy_functions.latex_fns.latex_actions import LatexPaperFileGroup, LatexPaperSplit
|
|
||||||
from crazy_functions.latex_fns.latex_toolbox import LinkedListNode
|
|
||||||
# 定义允许的安全类
|
|
||||||
safe_classes = {
|
|
||||||
# 在这里添加其他安全的类
|
|
||||||
'LatexPaperFileGroup': LatexPaperFileGroup,
|
|
||||||
'LatexPaperSplit': LatexPaperSplit,
|
|
||||||
'LinkedListNode': LinkedListNode,
|
|
||||||
}
|
|
||||||
return safe_classes
|
|
||||||
|
|
||||||
def find_class(self, module, name):
|
|
||||||
# 只允许特定的类进行反序列化
|
|
||||||
self.safe_classes = self.get_safe_classes()
|
|
||||||
match_class_name = None
|
|
||||||
for class_name in self.safe_classes.keys():
|
|
||||||
if (class_name in f'{module}.{name}'):
|
|
||||||
match_class_name = class_name
|
|
||||||
if module == 'numpy' or module.startswith('numpy.'):
|
|
||||||
return super().find_class(module, name)
|
|
||||||
if match_class_name is not None:
|
|
||||||
return self.safe_classes[match_class_name]
|
|
||||||
# 如果尝试加载未授权的类,则抛出异常
|
|
||||||
raise pickle.UnpicklingError(f"Attempted to deserialize unauthorized class '{name}' from module '{module}'")
|
|
||||||
|
|
||||||
def objdump(obj, file="objdump.tmp"):
|
|
||||||
|
|
||||||
with open(file, "wb+") as f:
|
|
||||||
pickle.dump(obj, f)
|
|
||||||
return
|
|
||||||
|
|
||||||
|
|
||||||
def objload(file="objdump.tmp"):
|
|
||||||
import os
|
|
||||||
|
|
||||||
if not os.path.exists(file):
|
|
||||||
return
|
|
||||||
with open(file, "rb") as f:
|
|
||||||
unpickler = SafeUnpickler(f)
|
|
||||||
return unpickler.load()
|
|
||||||
@@ -4,7 +4,7 @@ from toolbox import promote_file_to_downloadzone
|
|||||||
from toolbox import write_history_to_file, promote_file_to_downloadzone
|
from toolbox import write_history_to_file, promote_file_to_downloadzone
|
||||||
from toolbox import get_conf
|
from toolbox import get_conf
|
||||||
from toolbox import ProxyNetworkActivate
|
from toolbox import ProxyNetworkActivate
|
||||||
from shared_utils.colorful import *
|
from colorful import *
|
||||||
import requests
|
import requests
|
||||||
import random
|
import random
|
||||||
import copy
|
import copy
|
||||||
@@ -72,7 +72,7 @@ def produce_report_markdown(gpt_response_collection, meta, paper_meta_info, chat
|
|||||||
generated_conclusion_files.append(res_path)
|
generated_conclusion_files.append(res_path)
|
||||||
return res_path
|
return res_path
|
||||||
|
|
||||||
def translate_pdf(article_dict, llm_kwargs, chatbot, fp, generated_conclusion_files, TOKEN_LIMIT_PER_FRAGMENT, DST_LANG, plugin_kwargs={}):
|
def translate_pdf(article_dict, llm_kwargs, chatbot, fp, generated_conclusion_files, TOKEN_LIMIT_PER_FRAGMENT, DST_LANG):
|
||||||
from crazy_functions.pdf_fns.report_gen_html import construct_html
|
from crazy_functions.pdf_fns.report_gen_html import construct_html
|
||||||
from crazy_functions.pdf_fns.breakdown_txt import breakdown_text_to_satisfy_token_limit
|
from crazy_functions.pdf_fns.breakdown_txt import breakdown_text_to_satisfy_token_limit
|
||||||
from crazy_functions.crazy_utils import request_gpt_model_in_new_thread_with_ui_alive
|
from crazy_functions.crazy_utils import request_gpt_model_in_new_thread_with_ui_alive
|
||||||
@@ -138,7 +138,7 @@ def translate_pdf(article_dict, llm_kwargs, chatbot, fp, generated_conclusion_fi
|
|||||||
chatbot=chatbot,
|
chatbot=chatbot,
|
||||||
history_array=[meta for _ in inputs_array],
|
history_array=[meta for _ in inputs_array],
|
||||||
sys_prompt_array=[
|
sys_prompt_array=[
|
||||||
"请你作为一个学术翻译,负责把学术论文准确翻译成中文。注意文章中的每一句话都要翻译。" + plugin_kwargs.get("additional_prompt", "") for _ in inputs_array],
|
"请你作为一个学术翻译,负责把学术论文准确翻译成中文。注意文章中的每一句话都要翻译。" for _ in inputs_array],
|
||||||
)
|
)
|
||||||
# -=-=-=-=-=-=-=-= 写出Markdown文件 -=-=-=-=-=-=-=-=
|
# -=-=-=-=-=-=-=-= 写出Markdown文件 -=-=-=-=-=-=-=-=
|
||||||
produce_report_markdown(gpt_response_collection, meta, paper_meta_info, chatbot, fp, generated_conclusion_files)
|
produce_report_markdown(gpt_response_collection, meta, paper_meta_info, chatbot, fp, generated_conclusion_files)
|
||||||
|
|||||||
@@ -1,26 +0,0 @@
|
|||||||
import os
|
|
||||||
from toolbox import CatchException, report_exception, get_log_folder, gen_time_str, check_packages
|
|
||||||
from toolbox import update_ui, promote_file_to_downloadzone, update_ui_lastest_msg, disable_auto_promotion
|
|
||||||
from toolbox import write_history_to_file, promote_file_to_downloadzone, get_conf, extract_archive
|
|
||||||
from crazy_functions.pdf_fns.parse_pdf import parse_pdf, translate_pdf
|
|
||||||
|
|
||||||
def 解析PDF_基于GROBID(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, grobid_url):
|
|
||||||
import copy, json
|
|
||||||
TOKEN_LIMIT_PER_FRAGMENT = 1024
|
|
||||||
generated_conclusion_files = []
|
|
||||||
generated_html_files = []
|
|
||||||
DST_LANG = "中文"
|
|
||||||
from crazy_functions.pdf_fns.report_gen_html import construct_html
|
|
||||||
for index, fp in enumerate(file_manifest):
|
|
||||||
chatbot.append(["当前进度:", f"正在连接GROBID服务,请稍候: {grobid_url}\n如果等待时间过长,请修改config中的GROBID_URL,可修改成本地GROBID服务。"]); yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
|
||||||
article_dict = parse_pdf(fp, grobid_url)
|
|
||||||
grobid_json_res = os.path.join(get_log_folder(), gen_time_str() + "grobid.json")
|
|
||||||
with open(grobid_json_res, 'w+', encoding='utf8') as f:
|
|
||||||
f.write(json.dumps(article_dict, indent=4, ensure_ascii=False))
|
|
||||||
promote_file_to_downloadzone(grobid_json_res, chatbot=chatbot)
|
|
||||||
if article_dict is None: raise RuntimeError("解析PDF失败,请检查PDF是否损坏。")
|
|
||||||
yield from translate_pdf(article_dict, llm_kwargs, chatbot, fp, generated_conclusion_files, TOKEN_LIMIT_PER_FRAGMENT, DST_LANG, plugin_kwargs=plugin_kwargs)
|
|
||||||
chatbot.append(("给出输出文件清单", str(generated_conclusion_files + generated_html_files)))
|
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,213 +0,0 @@
|
|||||||
from toolbox import get_log_folder, gen_time_str, get_conf
|
|
||||||
from toolbox import update_ui, promote_file_to_downloadzone
|
|
||||||
from toolbox import promote_file_to_downloadzone, extract_archive
|
|
||||||
from toolbox import generate_file_link, zip_folder
|
|
||||||
from crazy_functions.crazy_utils import get_files_from_everything
|
|
||||||
from shared_utils.colorful import *
|
|
||||||
import os
|
|
||||||
|
|
||||||
def refresh_key(doc2x_api_key):
|
|
||||||
import requests, json
|
|
||||||
url = "https://api.doc2x.noedgeai.com/api/token/refresh"
|
|
||||||
res = requests.post(
|
|
||||||
url,
|
|
||||||
headers={"Authorization": "Bearer " + doc2x_api_key}
|
|
||||||
)
|
|
||||||
res_json = []
|
|
||||||
if res.status_code == 200:
|
|
||||||
decoded = res.content.decode("utf-8")
|
|
||||||
res_json = json.loads(decoded)
|
|
||||||
doc2x_api_key = res_json['data']['token']
|
|
||||||
else:
|
|
||||||
raise RuntimeError(format("[ERROR] status code: %d, body: %s" % (res.status_code, res.text)))
|
|
||||||
return doc2x_api_key
|
|
||||||
|
|
||||||
def 解析PDF_DOC2X_转Latex(pdf_file_path):
|
|
||||||
import requests, json, os
|
|
||||||
DOC2X_API_KEY = get_conf('DOC2X_API_KEY')
|
|
||||||
latex_dir = get_log_folder(plugin_name="pdf_ocr_latex")
|
|
||||||
doc2x_api_key = DOC2X_API_KEY
|
|
||||||
if doc2x_api_key.startswith('sk-'):
|
|
||||||
url = "https://api.doc2x.noedgeai.com/api/v1/pdf"
|
|
||||||
else:
|
|
||||||
doc2x_api_key = refresh_key(doc2x_api_key)
|
|
||||||
url = "https://api.doc2x.noedgeai.com/api/platform/pdf"
|
|
||||||
|
|
||||||
res = requests.post(
|
|
||||||
url,
|
|
||||||
files={"file": open(pdf_file_path, "rb")},
|
|
||||||
data={"ocr": "1"},
|
|
||||||
headers={"Authorization": "Bearer " + doc2x_api_key}
|
|
||||||
)
|
|
||||||
res_json = []
|
|
||||||
if res.status_code == 200:
|
|
||||||
decoded = res.content.decode("utf-8")
|
|
||||||
for z_decoded in decoded.split('\n'):
|
|
||||||
if len(z_decoded) == 0: continue
|
|
||||||
assert z_decoded.startswith("data: ")
|
|
||||||
z_decoded = z_decoded[len("data: "):]
|
|
||||||
decoded_json = json.loads(z_decoded)
|
|
||||||
res_json.append(decoded_json)
|
|
||||||
else:
|
|
||||||
raise RuntimeError(format("[ERROR] status code: %d, body: %s" % (res.status_code, res.text)))
|
|
||||||
|
|
||||||
uuid = res_json[0]['uuid']
|
|
||||||
to = "latex" # latex, md, docx
|
|
||||||
url = "https://api.doc2x.noedgeai.com/api/export"+"?request_id="+uuid+"&to="+to
|
|
||||||
|
|
||||||
res = requests.get(url, headers={"Authorization": "Bearer " + doc2x_api_key})
|
|
||||||
latex_zip_path = os.path.join(latex_dir, gen_time_str() + '.zip')
|
|
||||||
latex_unzip_path = os.path.join(latex_dir, gen_time_str())
|
|
||||||
if res.status_code == 200:
|
|
||||||
with open(latex_zip_path, "wb") as f: f.write(res.content)
|
|
||||||
else:
|
|
||||||
raise RuntimeError(format("[ERROR] status code: %d, body: %s" % (res.status_code, res.text)))
|
|
||||||
|
|
||||||
import zipfile
|
|
||||||
with zipfile.ZipFile(latex_zip_path, 'r') as zip_ref:
|
|
||||||
zip_ref.extractall(latex_unzip_path)
|
|
||||||
|
|
||||||
|
|
||||||
return latex_unzip_path
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def 解析PDF_DOC2X_单文件(fp, project_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, DOC2X_API_KEY, user_request):
|
|
||||||
|
|
||||||
|
|
||||||
def pdf2markdown(filepath):
|
|
||||||
import requests, json, os
|
|
||||||
markdown_dir = get_log_folder(plugin_name="pdf_ocr")
|
|
||||||
doc2x_api_key = DOC2X_API_KEY
|
|
||||||
if doc2x_api_key.startswith('sk-'):
|
|
||||||
url = "https://api.doc2x.noedgeai.com/api/v1/pdf"
|
|
||||||
else:
|
|
||||||
doc2x_api_key = refresh_key(doc2x_api_key)
|
|
||||||
url = "https://api.doc2x.noedgeai.com/api/platform/pdf"
|
|
||||||
|
|
||||||
chatbot.append((None, "加载PDF文件,发送至DOC2X解析..."))
|
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
|
||||||
|
|
||||||
res = requests.post(
|
|
||||||
url,
|
|
||||||
files={"file": open(filepath, "rb")},
|
|
||||||
data={"ocr": "1"},
|
|
||||||
headers={"Authorization": "Bearer " + doc2x_api_key}
|
|
||||||
)
|
|
||||||
res_json = []
|
|
||||||
if res.status_code == 200:
|
|
||||||
decoded = res.content.decode("utf-8")
|
|
||||||
for z_decoded in decoded.split('\n'):
|
|
||||||
if len(z_decoded) == 0: continue
|
|
||||||
assert z_decoded.startswith("data: ")
|
|
||||||
z_decoded = z_decoded[len("data: "):]
|
|
||||||
decoded_json = json.loads(z_decoded)
|
|
||||||
res_json.append(decoded_json)
|
|
||||||
if 'limit exceeded' in decoded_json.get('status', ''):
|
|
||||||
raise RuntimeError("Doc2x API 页数受限,请联系 Doc2x 方面,并更换新的 API 秘钥。")
|
|
||||||
else:
|
|
||||||
raise RuntimeError(format("[ERROR] status code: %d, body: %s" % (res.status_code, res.text)))
|
|
||||||
uuid = res_json[0]['uuid']
|
|
||||||
to = "md" # latex, md, docx
|
|
||||||
url = "https://api.doc2x.noedgeai.com/api/export"+"?request_id="+uuid+"&to="+to
|
|
||||||
|
|
||||||
chatbot.append((None, f"读取解析: {url} ..."))
|
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
|
||||||
|
|
||||||
res = requests.get(url, headers={"Authorization": "Bearer " + doc2x_api_key})
|
|
||||||
md_zip_path = os.path.join(markdown_dir, gen_time_str() + '.zip')
|
|
||||||
if res.status_code == 200:
|
|
||||||
with open(md_zip_path, "wb") as f: f.write(res.content)
|
|
||||||
else:
|
|
||||||
raise RuntimeError(format("[ERROR] status code: %d, body: %s" % (res.status_code, res.text)))
|
|
||||||
promote_file_to_downloadzone(md_zip_path, chatbot=chatbot)
|
|
||||||
chatbot.append((None, f"完成解析 {md_zip_path} ..."))
|
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
|
||||||
return md_zip_path
|
|
||||||
|
|
||||||
def deliver_to_markdown_plugin(md_zip_path, user_request):
|
|
||||||
from crazy_functions.Markdown_Translate import Markdown英译中
|
|
||||||
import shutil, re
|
|
||||||
|
|
||||||
time_tag = gen_time_str()
|
|
||||||
target_path_base = get_log_folder(chatbot.get_user())
|
|
||||||
file_origin_name = os.path.basename(md_zip_path)
|
|
||||||
this_file_path = os.path.join(target_path_base, file_origin_name)
|
|
||||||
os.makedirs(target_path_base, exist_ok=True)
|
|
||||||
shutil.copyfile(md_zip_path, this_file_path)
|
|
||||||
ex_folder = this_file_path + ".extract"
|
|
||||||
extract_archive(
|
|
||||||
file_path=this_file_path, dest_dir=ex_folder
|
|
||||||
)
|
|
||||||
|
|
||||||
# edit markdown files
|
|
||||||
success, file_manifest, project_folder = get_files_from_everything(ex_folder, type='.md')
|
|
||||||
for generated_fp in file_manifest:
|
|
||||||
# 修正一些公式问题
|
|
||||||
with open(generated_fp, 'r', encoding='utf8') as f:
|
|
||||||
content = f.read()
|
|
||||||
# 将公式中的\[ \]替换成$$
|
|
||||||
content = content.replace(r'\[', r'$$').replace(r'\]', r'$$')
|
|
||||||
# 将公式中的\( \)替换成$
|
|
||||||
content = content.replace(r'\(', r'$').replace(r'\)', r'$')
|
|
||||||
content = content.replace('```markdown', '\n').replace('```', '\n')
|
|
||||||
with open(generated_fp, 'w', encoding='utf8') as f:
|
|
||||||
f.write(content)
|
|
||||||
promote_file_to_downloadzone(generated_fp, chatbot=chatbot)
|
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
|
||||||
|
|
||||||
# 生成在线预览html
|
|
||||||
file_name = '在线预览翻译(原文)' + gen_time_str() + '.html'
|
|
||||||
preview_fp = os.path.join(ex_folder, file_name)
|
|
||||||
from shared_utils.advanced_markdown_format import markdown_convertion_for_file
|
|
||||||
with open(generated_fp, "r", encoding="utf-8") as f:
|
|
||||||
md = f.read()
|
|
||||||
# # Markdown中使用不标准的表格,需要在表格前加上一个emoji,以便公式渲染
|
|
||||||
# md = re.sub(r'^<table>', r'.<table>', md, flags=re.MULTILINE)
|
|
||||||
html = markdown_convertion_for_file(md)
|
|
||||||
with open(preview_fp, "w", encoding="utf-8") as f: f.write(html)
|
|
||||||
chatbot.append([None, f"生成在线预览:{generate_file_link([preview_fp])}"])
|
|
||||||
promote_file_to_downloadzone(preview_fp, chatbot=chatbot)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
chatbot.append((None, f"调用Markdown插件 {ex_folder} ..."))
|
|
||||||
plugin_kwargs['markdown_expected_output_dir'] = ex_folder
|
|
||||||
|
|
||||||
translated_f_name = 'translated_markdown.md'
|
|
||||||
generated_fp = plugin_kwargs['markdown_expected_output_path'] = os.path.join(ex_folder, translated_f_name)
|
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
|
||||||
yield from Markdown英译中(ex_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request)
|
|
||||||
if os.path.exists(generated_fp):
|
|
||||||
# 修正一些公式问题
|
|
||||||
with open(generated_fp, 'r', encoding='utf8') as f: content = f.read()
|
|
||||||
content = content.replace('```markdown', '\n').replace('```', '\n')
|
|
||||||
# Markdown中使用不标准的表格,需要在表格前加上一个emoji,以便公式渲染
|
|
||||||
# content = re.sub(r'^<table>', r'.<table>', content, flags=re.MULTILINE)
|
|
||||||
with open(generated_fp, 'w', encoding='utf8') as f: f.write(content)
|
|
||||||
# 生成在线预览html
|
|
||||||
file_name = '在线预览翻译' + gen_time_str() + '.html'
|
|
||||||
preview_fp = os.path.join(ex_folder, file_name)
|
|
||||||
from shared_utils.advanced_markdown_format import markdown_convertion_for_file
|
|
||||||
with open(generated_fp, "r", encoding="utf-8") as f:
|
|
||||||
md = f.read()
|
|
||||||
html = markdown_convertion_for_file(md)
|
|
||||||
with open(preview_fp, "w", encoding="utf-8") as f: f.write(html)
|
|
||||||
promote_file_to_downloadzone(preview_fp, chatbot=chatbot)
|
|
||||||
# 生成包含图片的压缩包
|
|
||||||
dest_folder = get_log_folder(chatbot.get_user())
|
|
||||||
zip_name = '翻译后的带图文档.zip'
|
|
||||||
zip_folder(source_folder=ex_folder, dest_folder=dest_folder, zip_name=zip_name)
|
|
||||||
zip_fp = os.path.join(dest_folder, zip_name)
|
|
||||||
promote_file_to_downloadzone(zip_fp, chatbot=chatbot)
|
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
|
||||||
md_zip_path = yield from pdf2markdown(fp)
|
|
||||||
yield from deliver_to_markdown_plugin(md_zip_path, user_request)
|
|
||||||
|
|
||||||
def 解析PDF_基于DOC2X(file_manifest, *args):
|
|
||||||
for index, fp in enumerate(file_manifest):
|
|
||||||
yield from 解析PDF_DOC2X_单文件(fp, *args)
|
|
||||||
return
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,73 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
|
||||||
|
|
||||||
<head>
|
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
|
||||||
<title>GPT-Academic 翻译报告书</title>
|
|
||||||
<style>
|
|
||||||
.centered-a {
|
|
||||||
color: red;
|
|
||||||
text-align: center;
|
|
||||||
margin-bottom: 2%;
|
|
||||||
font-size: 1.5em;
|
|
||||||
}
|
|
||||||
.centered-b {
|
|
||||||
color: red;
|
|
||||||
text-align: center;
|
|
||||||
margin-top: 10%;
|
|
||||||
margin-bottom: 20%;
|
|
||||||
font-size: 1.5em;
|
|
||||||
}
|
|
||||||
.centered-c {
|
|
||||||
color: rgba(255, 0, 0, 0);
|
|
||||||
text-align: center;
|
|
||||||
margin-top: 2%;
|
|
||||||
margin-bottom: 20%;
|
|
||||||
font-size: 7em;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<script>
|
|
||||||
// Configure MathJax settings
|
|
||||||
MathJax = {
|
|
||||||
tex: {
|
|
||||||
inlineMath: [
|
|
||||||
['$', '$'],
|
|
||||||
['\(', '\)']
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
addEventListener('zero-md-rendered', () => {MathJax.typeset(); console.log('MathJax typeset!');})
|
|
||||||
</script>
|
|
||||||
<!-- Load MathJax library -->
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-chtml.js"></script>
|
|
||||||
<script
|
|
||||||
type="module"
|
|
||||||
src="https://cdn.jsdelivr.net/gh/zerodevx/zero-md@2/dist/zero-md.min.js"
|
|
||||||
></script>
|
|
||||||
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
<div class="test_temp1" style="width:10%; height: 500px; float:left;">
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<div class="test_temp2" style="width:80%; height: 500px; float:left;">
|
|
||||||
<!-- Simply set the `src` attribute to your MD file and win -->
|
|
||||||
<div class="centered-a">
|
|
||||||
请按Ctrl+S保存此页面,否则该页面可能在几分钟后失效。
|
|
||||||
</div>
|
|
||||||
<zero-md src="translated_markdown.md" no-shadow>
|
|
||||||
</zero-md>
|
|
||||||
<div class="centered-b">
|
|
||||||
本报告由GPT-Academic开源项目生成,地址:https://github.com/binary-husky/gpt_academic。
|
|
||||||
</div>
|
|
||||||
<div class="centered-c">
|
|
||||||
本报告由GPT-Academic开源项目生成,地址:https://github.com/binary-husky/gpt_academic。
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="test_temp3" style="width:10%; height: 500px; float:left;">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</body>
|
|
||||||
|
|
||||||
</html>
|
|
||||||
@@ -1,52 +0,0 @@
|
|||||||
import os, json, base64
|
|
||||||
from pydantic import BaseModel, Field
|
|
||||||
from textwrap import dedent
|
|
||||||
from typing import List
|
|
||||||
|
|
||||||
class ArgProperty(BaseModel): # PLUGIN_ARG_MENU
|
|
||||||
title: str = Field(description="The title", default="")
|
|
||||||
description: str = Field(description="The description", default="")
|
|
||||||
default_value: str = Field(description="The default value", default="")
|
|
||||||
type: str = Field(description="The type", default="") # currently we support ['string', 'dropdown']
|
|
||||||
options: List[str] = Field(default=[], description="List of options available for the argument") # only used when type is 'dropdown'
|
|
||||||
|
|
||||||
class GptAcademicPluginTemplate():
|
|
||||||
def __init__(self):
|
|
||||||
# please note that `execute` method may run in different threads,
|
|
||||||
# thus you should not store any state in the plugin instance,
|
|
||||||
# which may be accessed by multiple threads
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
def define_arg_selection_menu(self):
|
|
||||||
"""
|
|
||||||
An example as below:
|
|
||||||
```
|
|
||||||
def define_arg_selection_menu(self):
|
|
||||||
gui_definition = {
|
|
||||||
"main_input":
|
|
||||||
ArgProperty(title="main input", description="description", default_value="default_value", type="string").model_dump_json(),
|
|
||||||
"advanced_arg":
|
|
||||||
ArgProperty(title="advanced arguments", description="description", default_value="default_value", type="string").model_dump_json(),
|
|
||||||
"additional_arg_01":
|
|
||||||
ArgProperty(title="additional", description="description", default_value="default_value", type="string").model_dump_json(),
|
|
||||||
}
|
|
||||||
return gui_definition
|
|
||||||
```
|
|
||||||
"""
|
|
||||||
raise NotImplementedError("You need to implement this method in your plugin class")
|
|
||||||
|
|
||||||
|
|
||||||
def get_js_code_for_generating_menu(self, btnName):
|
|
||||||
define_arg_selection = self.define_arg_selection_menu()
|
|
||||||
|
|
||||||
if len(define_arg_selection.keys()) > 8:
|
|
||||||
raise ValueError("You can only have up to 8 arguments in the define_arg_selection")
|
|
||||||
# if "main_input" not in define_arg_selection:
|
|
||||||
# raise ValueError("You must have a 'main_input' in the define_arg_selection")
|
|
||||||
|
|
||||||
DEFINE_ARG_INPUT_INTERFACE = json.dumps(define_arg_selection)
|
|
||||||
return base64.b64encode(DEFINE_ARG_INPUT_INTERFACE.encode('utf-8')).decode('utf-8')
|
|
||||||
|
|
||||||
def execute(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request):
|
|
||||||
raise NotImplementedError("You need to implement this method in your plugin class")
|
|
||||||
@@ -1,87 +0,0 @@
|
|||||||
SearchOptimizerPrompt="""作为一个网页搜索助手,你的任务是结合历史记录,从不同角度,为“原问题”生成个不同版本的“检索词”,从而提高网页检索的精度。生成的问题要求指向对象清晰明确,并与“原问题语言相同”。例如:
|
|
||||||
历史记录:
|
|
||||||
"
|
|
||||||
Q: 对话背景。
|
|
||||||
A: 当前对话是关于 Nginx 的介绍和在Ubuntu上的使用等。
|
|
||||||
"
|
|
||||||
原问题: 怎么下载
|
|
||||||
检索词: ["Nginx 下载","Ubuntu Nginx","Ubuntu安装Nginx"]
|
|
||||||
----------------
|
|
||||||
历史记录:
|
|
||||||
"
|
|
||||||
Q: 对话背景。
|
|
||||||
A: 当前对话是关于 Nginx 的介绍和使用等。
|
|
||||||
Q: 报错 "no connection"
|
|
||||||
A: 报错"no connection"可能是因为……
|
|
||||||
"
|
|
||||||
原问题: 怎么解决
|
|
||||||
检索词: ["Nginx报错"no connection" 解决","Nginx'no connection'报错 原因","Nginx提示'no connection'"]
|
|
||||||
----------------
|
|
||||||
历史记录:
|
|
||||||
"
|
|
||||||
|
|
||||||
"
|
|
||||||
原问题: 你知道 Python 么?
|
|
||||||
检索词: ["Python","Python 使用教程。","Python 特点和优势"]
|
|
||||||
----------------
|
|
||||||
历史记录:
|
|
||||||
"
|
|
||||||
Q: 列出Java的三种特点?
|
|
||||||
A: 1. Java 是一种编译型语言。
|
|
||||||
2. Java 是一种面向对象的编程语言。
|
|
||||||
3. Java 是一种跨平台的编程语言。
|
|
||||||
"
|
|
||||||
原问题: 介绍下第2点。
|
|
||||||
检索词: ["Java 面向对象特点","Java 面向对象编程优势。","Java 面向对象编程"]
|
|
||||||
----------------
|
|
||||||
现在有历史记录:
|
|
||||||
"
|
|
||||||
{history}
|
|
||||||
"
|
|
||||||
有其原问题: {query}
|
|
||||||
直接给出最多{num}个检索词,必须以json形式给出,不得有多余字符:
|
|
||||||
"""
|
|
||||||
|
|
||||||
SearchAcademicOptimizerPrompt="""作为一个学术论文搜索助手,你的任务是结合历史记录,从不同角度,为“原问题”生成个不同版本的“检索词”,从而提高学术论文检索的精度。生成的问题要求指向对象清晰明确,并与“原问题语言相同”。例如:
|
|
||||||
历史记录:
|
|
||||||
"
|
|
||||||
Q: 对话背景。
|
|
||||||
A: 当前对话是关于深度学习的介绍和在图像识别中的应用等。
|
|
||||||
"
|
|
||||||
原问题: 怎么下载相关论文
|
|
||||||
检索词: ["深度学习 图像识别 论文下载","图像识别 深度学习 研究论文","深度学习 图像识别 论文资源","Deep Learning Image Recognition Paper Download","Image Recognition Deep Learning Research Paper"]
|
|
||||||
----------------
|
|
||||||
历史记录:
|
|
||||||
"
|
|
||||||
Q: 对话背景。
|
|
||||||
A: 当前对话是关于深度学习的介绍和应用等。
|
|
||||||
Q: 报错 "模型不收敛"
|
|
||||||
A: 报错"模型不收敛"可能是因为……
|
|
||||||
"
|
|
||||||
原问题: 怎么解决
|
|
||||||
检索词: ["深度学习 模型不收敛 解决方案 论文","深度学习 模型不收敛 原因 研究","深度学习 模型不收敛 论文","Deep Learning Model Convergence Issue Solution Paper","Deep Learning Model Convergence Problem Research"]
|
|
||||||
----------------
|
|
||||||
历史记录:
|
|
||||||
"
|
|
||||||
|
|
||||||
"
|
|
||||||
原问题: 你知道 GAN 么?
|
|
||||||
检索词: ["生成对抗网络 论文","GAN 使用教程 论文","GAN 特点和优势 研究","Generative Adversarial Network Paper","GAN Usage Tutorial Paper"]
|
|
||||||
----------------
|
|
||||||
历史记录:
|
|
||||||
"
|
|
||||||
Q: 列出机器学习的三种应用?
|
|
||||||
A: 1. 机器学习在图像识别中的应用。
|
|
||||||
2. 机器学习在自然语言处理中的应用。
|
|
||||||
3. 机器学习在推荐系统中的应用。
|
|
||||||
"
|
|
||||||
原问题: 介绍下第2点。
|
|
||||||
检索词: ["机器学习 自然语言处理 应用 论文","机器学习 自然语言处理 研究","机器学习 NLP 应用 论文","Machine Learning Natural Language Processing Application Paper","Machine Learning NLP Research"]
|
|
||||||
----------------
|
|
||||||
现在有历史记录:
|
|
||||||
"
|
|
||||||
{history}
|
|
||||||
"
|
|
||||||
有其原问题: {query}
|
|
||||||
直接给出最多{num}个检索词,必须以json形式给出,不得有多余字符:
|
|
||||||
"""
|
|
||||||
@@ -10,7 +10,7 @@ def read_avail_plugin_enum():
|
|||||||
from crazy_functional import get_crazy_functions
|
from crazy_functional import get_crazy_functions
|
||||||
plugin_arr = get_crazy_functions()
|
plugin_arr = get_crazy_functions()
|
||||||
# remove plugins with out explaination
|
# remove plugins with out explaination
|
||||||
plugin_arr = {k:v for k, v in plugin_arr.items() if ('Info' in v) and ('Function' in v)}
|
plugin_arr = {k:v for k, v in plugin_arr.items() if 'Info' in v}
|
||||||
plugin_arr_info = {"F_{:04d}".format(i):v["Info"] for i, v in enumerate(plugin_arr.values(), start=1)}
|
plugin_arr_info = {"F_{:04d}".format(i):v["Info"] for i, v in enumerate(plugin_arr.values(), start=1)}
|
||||||
plugin_arr_dict = {"F_{:04d}".format(i):v for i, v in enumerate(plugin_arr.values(), start=1)}
|
plugin_arr_dict = {"F_{:04d}".format(i):v for i, v in enumerate(plugin_arr.values(), start=1)}
|
||||||
plugin_arr_dict_parse = {"F_{:04d}".format(i):v for i, v in enumerate(plugin_arr.values(), start=1)}
|
plugin_arr_dict_parse = {"F_{:04d}".format(i):v for i, v in enumerate(plugin_arr.values(), start=1)}
|
||||||
|
|||||||
@@ -108,7 +108,7 @@ def 图片生成_DALLE2(prompt, llm_kwargs, plugin_kwargs, chatbot, history, sys
|
|||||||
chatbot.append((prompt, "[Local Message] 图像生成提示为空白,请在“输入区”输入图像生成提示。"))
|
chatbot.append((prompt, "[Local Message] 图像生成提示为空白,请在“输入区”输入图像生成提示。"))
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 界面更新
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 界面更新
|
||||||
return
|
return
|
||||||
chatbot.append(("您正在调用“图像生成”插件。", "[Local Message] 生成图像, 使用前请切换模型到GPT系列。如果中文Prompt效果不理想, 请尝试英文Prompt。正在处理中 ....."))
|
chatbot.append(("您正在调用“图像生成”插件。", "[Local Message] 生成图像, 请先把模型切换至gpt-*。如果中文Prompt效果不理想, 请尝试英文Prompt。正在处理中 ....."))
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 由于请求gpt需要一段时间,我们先及时地做一次界面更新
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 由于请求gpt需要一段时间,我们先及时地做一次界面更新
|
||||||
if ("advanced_arg" in plugin_kwargs) and (plugin_kwargs["advanced_arg"] == ""): plugin_kwargs.pop("advanced_arg")
|
if ("advanced_arg" in plugin_kwargs) and (plugin_kwargs["advanced_arg"] == ""): plugin_kwargs.pop("advanced_arg")
|
||||||
resolution = plugin_kwargs.get("advanced_arg", '1024x1024')
|
resolution = plugin_kwargs.get("advanced_arg", '1024x1024')
|
||||||
@@ -129,7 +129,7 @@ def 图片生成_DALLE3(prompt, llm_kwargs, plugin_kwargs, chatbot, history, sys
|
|||||||
chatbot.append((prompt, "[Local Message] 图像生成提示为空白,请在“输入区”输入图像生成提示。"))
|
chatbot.append((prompt, "[Local Message] 图像生成提示为空白,请在“输入区”输入图像生成提示。"))
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 界面更新
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 界面更新
|
||||||
return
|
return
|
||||||
chatbot.append(("您正在调用“图像生成”插件。", "[Local Message] 生成图像, 使用前请切换模型到GPT系列。如果中文Prompt效果不理想, 请尝试英文Prompt。正在处理中 ....."))
|
chatbot.append(("您正在调用“图像生成”插件。", "[Local Message] 生成图像, 请先把模型切换至gpt-*。如果中文Prompt效果不理想, 请尝试英文Prompt。正在处理中 ....."))
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 由于请求gpt需要一段时间,我们先及时地做一次界面更新
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 由于请求gpt需要一段时间,我们先及时地做一次界面更新
|
||||||
if ("advanced_arg" in plugin_kwargs) and (plugin_kwargs["advanced_arg"] == ""): plugin_kwargs.pop("advanced_arg")
|
if ("advanced_arg" in plugin_kwargs) and (plugin_kwargs["advanced_arg"] == ""): plugin_kwargs.pop("advanced_arg")
|
||||||
resolution_arg = plugin_kwargs.get("advanced_arg", '1024x1024-standard-vivid').lower()
|
resolution_arg = plugin_kwargs.get("advanced_arg", '1024x1024-standard-vivid').lower()
|
||||||
@@ -166,7 +166,7 @@ class ImageEditState(GptAcademicState):
|
|||||||
return confirm, file
|
return confirm, file
|
||||||
|
|
||||||
def lock_plugin(self, chatbot):
|
def lock_plugin(self, chatbot):
|
||||||
chatbot._cookies['lock_plugin'] = 'crazy_functions.Image_Generate->图片修改_DALLE2'
|
chatbot._cookies['lock_plugin'] = 'crazy_functions.图片生成->图片修改_DALLE2'
|
||||||
self.dump_state(chatbot)
|
self.dump_state(chatbot)
|
||||||
|
|
||||||
def unlock_plugin(self, chatbot):
|
def unlock_plugin(self, chatbot):
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
from toolbox import CatchException, update_ui, promote_file_to_downloadzone, get_log_folder, get_user
|
from toolbox import CatchException, update_ui, promote_file_to_downloadzone, get_log_folder, get_user
|
||||||
from crazy_functions.plugin_template.plugin_class_template import GptAcademicPluginTemplate, ArgProperty
|
|
||||||
import re
|
import re
|
||||||
|
|
||||||
f_prefix = 'GPT-Academic对话存档'
|
f_prefix = 'GPT-Academic对话存档'
|
||||||
@@ -10,61 +9,27 @@ def write_chat_to_file(chatbot, history=None, file_name=None):
|
|||||||
"""
|
"""
|
||||||
import os
|
import os
|
||||||
import time
|
import time
|
||||||
from themes.theme import advanced_css
|
|
||||||
|
|
||||||
if file_name is None:
|
if file_name is None:
|
||||||
file_name = f_prefix + time.strftime("%Y-%m-%d-%H-%M-%S", time.localtime()) + '.html'
|
file_name = f_prefix + time.strftime("%Y-%m-%d-%H-%M-%S", time.localtime()) + '.html'
|
||||||
fp = os.path.join(get_log_folder(get_user(chatbot), plugin_name='chat_history'), file_name)
|
fp = os.path.join(get_log_folder(get_user(chatbot), plugin_name='chat_history'), file_name)
|
||||||
|
|
||||||
with open(fp, 'w', encoding='utf8') as f:
|
with open(fp, 'w', encoding='utf8') as f:
|
||||||
from textwrap import dedent
|
from themes.theme import advanced_css
|
||||||
form = dedent("""
|
f.write(f'<!DOCTYPE html><head><meta charset="utf-8"><title>对话历史</title><style>{advanced_css}</style></head>')
|
||||||
<!DOCTYPE html><head><meta charset="utf-8"><title>对话存档</title><style>{CSS}</style></head>
|
|
||||||
<body>
|
|
||||||
<div class="test_temp1" style="width:10%; height: 500px; float:left;"></div>
|
|
||||||
<div class="test_temp2" style="width:80%;padding: 40px;float:left;padding-left: 20px;padding-right: 20px;box-shadow: rgba(0, 0, 0, 0.2) 0px 0px 8px 8px;border-radius: 10px;">
|
|
||||||
<div class="chat-body" style="display: flex;justify-content: center;flex-direction: column;align-items: center;flex-wrap: nowrap;">
|
|
||||||
{CHAT_PREVIEW}
|
|
||||||
<div></div>
|
|
||||||
<div></div>
|
|
||||||
<div style="text-align: center;width:80%;padding: 0px;float:left;padding-left:20px;padding-right:20px;box-shadow: rgba(0, 0, 0, 0.05) 0px 0px 1px 2px;border-radius: 1px;">对话(原始数据)</div>
|
|
||||||
{HISTORY_PREVIEW}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="test_temp3" style="width:10%; height: 500px; float:left;"></div>
|
|
||||||
</body>
|
|
||||||
""")
|
|
||||||
|
|
||||||
qa_from = dedent("""
|
|
||||||
<div class="QaBox" style="width:80%;padding: 20px;margin-bottom: 20px;box-shadow: rgb(0 255 159 / 50%) 0px 0px 1px 2px;border-radius: 4px;">
|
|
||||||
<div class="Question" style="border-radius: 2px;">{QUESTION}</div>
|
|
||||||
<hr color="blue" style="border-top: dotted 2px #ccc;">
|
|
||||||
<div class="Answer" style="border-radius: 2px;">{ANSWER}</div>
|
|
||||||
</div>
|
|
||||||
""")
|
|
||||||
|
|
||||||
history_from = dedent("""
|
|
||||||
<div class="historyBox" style="width:80%;padding: 0px;float:left;padding-left:20px;padding-right:20px;box-shadow: rgba(0, 0, 0, 0.05) 0px 0px 1px 2px;border-radius: 1px;">
|
|
||||||
<div class="entry" style="border-radius: 2px;">{ENTRY}</div>
|
|
||||||
</div>
|
|
||||||
""")
|
|
||||||
CHAT_PREVIEW_BUF = ""
|
|
||||||
for i, contents in enumerate(chatbot):
|
for i, contents in enumerate(chatbot):
|
||||||
question, answer = contents[0], contents[1]
|
for j, content in enumerate(contents):
|
||||||
if question is None: question = ""
|
try: # 这个bug没找到触发条件,暂时先这样顶一下
|
||||||
try: question = str(question)
|
if type(content) != str: content = str(content)
|
||||||
except: question = ""
|
except:
|
||||||
if answer is None: answer = ""
|
continue
|
||||||
try: answer = str(answer)
|
f.write(content)
|
||||||
except: answer = ""
|
if j == 0:
|
||||||
CHAT_PREVIEW_BUF += qa_from.format(QUESTION=question, ANSWER=answer)
|
f.write('<hr style="border-top: dotted 3px #ccc;">')
|
||||||
|
f.write('<hr color="red"> \n\n')
|
||||||
HISTORY_PREVIEW_BUF = ""
|
f.write('<hr color="blue"> \n\n raw chat context:\n')
|
||||||
|
f.write('<code>')
|
||||||
for h in history:
|
for h in history:
|
||||||
HISTORY_PREVIEW_BUF += history_from.format(ENTRY=h)
|
f.write("\n>>>" + h)
|
||||||
html_content = form.format(CHAT_PREVIEW=CHAT_PREVIEW_BUF, HISTORY_PREVIEW=HISTORY_PREVIEW_BUF, CSS=advanced_css)
|
f.write('</code>')
|
||||||
f.write(html_content)
|
|
||||||
|
|
||||||
promote_file_to_downloadzone(fp, rename_file=file_name, chatbot=chatbot)
|
promote_file_to_downloadzone(fp, rename_file=file_name, chatbot=chatbot)
|
||||||
return '对话历史写入:' + fp
|
return '对话历史写入:' + fp
|
||||||
|
|
||||||
@@ -75,7 +40,7 @@ def gen_file_preview(file_name):
|
|||||||
# pattern to match the text between <head> and </head>
|
# pattern to match the text between <head> and </head>
|
||||||
pattern = re.compile(r'<head>.*?</head>', flags=re.DOTALL)
|
pattern = re.compile(r'<head>.*?</head>', flags=re.DOTALL)
|
||||||
file_content = re.sub(pattern, '', file_content)
|
file_content = re.sub(pattern, '', file_content)
|
||||||
html, history = file_content.split('<hr color="blue"> \n\n 对话数据 (无渲染):\n')
|
html, history = file_content.split('<hr color="blue"> \n\n raw chat context:\n')
|
||||||
history = history.strip('<code>')
|
history = history.strip('<code>')
|
||||||
history = history.strip('</code>')
|
history = history.strip('</code>')
|
||||||
history = history.split("\n>>>")
|
history = history.split("\n>>>")
|
||||||
@@ -86,25 +51,21 @@ def gen_file_preview(file_name):
|
|||||||
def read_file_to_chat(chatbot, history, file_name):
|
def read_file_to_chat(chatbot, history, file_name):
|
||||||
with open(file_name, 'r', encoding='utf8') as f:
|
with open(file_name, 'r', encoding='utf8') as f:
|
||||||
file_content = f.read()
|
file_content = f.read()
|
||||||
from bs4 import BeautifulSoup
|
# pattern to match the text between <head> and </head>
|
||||||
soup = BeautifulSoup(file_content, 'lxml')
|
pattern = re.compile(r'<head>.*?</head>', flags=re.DOTALL)
|
||||||
# 提取QaBox信息
|
file_content = re.sub(pattern, '', file_content)
|
||||||
|
html, history = file_content.split('<hr color="blue"> \n\n raw chat context:\n')
|
||||||
|
history = history.strip('<code>')
|
||||||
|
history = history.strip('</code>')
|
||||||
|
history = history.split("\n>>>")
|
||||||
|
history = list(filter(lambda x:x!="", history))
|
||||||
|
html = html.split('<hr color="red"> \n\n')
|
||||||
|
html = list(filter(lambda x:x!="", html))
|
||||||
chatbot.clear()
|
chatbot.clear()
|
||||||
qa_box_list = []
|
for i, h in enumerate(html):
|
||||||
qa_boxes = soup.find_all("div", class_="QaBox")
|
i_say, gpt_say = h.split('<hr style="border-top: dotted 3px #ccc;">')
|
||||||
for box in qa_boxes:
|
chatbot.append([i_say, gpt_say])
|
||||||
question = box.find("div", class_="Question").get_text(strip=False)
|
chatbot.append([f"存档文件详情?", f"[Local Message] 载入对话{len(html)}条,上下文{len(history)}条。"])
|
||||||
answer = box.find("div", class_="Answer").get_text(strip=False)
|
|
||||||
qa_box_list.append({"Question": question, "Answer": answer})
|
|
||||||
chatbot.append([question, answer])
|
|
||||||
# 提取historyBox信息
|
|
||||||
history_box_list = []
|
|
||||||
history_boxes = soup.find_all("div", class_="historyBox")
|
|
||||||
for box in history_boxes:
|
|
||||||
entry = box.find("div", class_="entry").get_text(strip=False)
|
|
||||||
history_box_list.append(entry)
|
|
||||||
history = history_box_list
|
|
||||||
chatbot.append([None, f"[Local Message] 载入对话{len(qa_box_list)}条,上下文{len(history)}条。"])
|
|
||||||
return chatbot, history
|
return chatbot, history
|
||||||
|
|
||||||
@CatchException
|
@CatchException
|
||||||
@@ -118,42 +79,11 @@ def 对话历史存档(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_
|
|||||||
system_prompt 给gpt的静默提醒
|
system_prompt 给gpt的静默提醒
|
||||||
user_request 当前用户的请求信息(IP地址等)
|
user_request 当前用户的请求信息(IP地址等)
|
||||||
"""
|
"""
|
||||||
file_name = plugin_kwargs.get("file_name", None)
|
|
||||||
if (file_name is not None) and (file_name != "") and (not file_name.endswith('.html')): file_name += '.html'
|
|
||||||
else: file_name = None
|
|
||||||
|
|
||||||
chatbot.append((None, f"[Local Message] {write_chat_to_file(chatbot, history, file_name)},您可以调用下拉菜单中的“载入对话历史存档”还原当下的对话。"))
|
chatbot.append(("保存当前对话",
|
||||||
|
f"[Local Message] {write_chat_to_file(chatbot, history)},您可以调用下拉菜单中的“载入对话历史存档”还原当下的对话。"))
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 # 由于请求gpt需要一段时间,我们先及时地做一次界面更新
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 # 由于请求gpt需要一段时间,我们先及时地做一次界面更新
|
||||||
|
|
||||||
|
|
||||||
class Conversation_To_File_Wrap(GptAcademicPluginTemplate):
|
|
||||||
def __init__(self):
|
|
||||||
"""
|
|
||||||
请注意`execute`会执行在不同的线程中,因此您在定义和使用类变量时,应当慎之又慎!
|
|
||||||
"""
|
|
||||||
pass
|
|
||||||
|
|
||||||
def define_arg_selection_menu(self):
|
|
||||||
"""
|
|
||||||
定义插件的二级选项菜单
|
|
||||||
|
|
||||||
第一个参数,名称`file_name`,参数`type`声明这是一个文本框,文本框上方显示`title`,文本框内部显示`description`,`default_value`为默认值;
|
|
||||||
"""
|
|
||||||
gui_definition = {
|
|
||||||
"file_name": ArgProperty(title="保存文件名", description="输入对话存档文件名,留空则使用时间作为文件名", default_value="", type="string").model_dump_json(), # 主输入,自动从输入框同步
|
|
||||||
}
|
|
||||||
return gui_definition
|
|
||||||
|
|
||||||
def execute(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request):
|
|
||||||
"""
|
|
||||||
执行插件
|
|
||||||
"""
|
|
||||||
yield from 对话历史存档(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def hide_cwd(str):
|
def hide_cwd(str):
|
||||||
import os
|
import os
|
||||||
current_path = os.getcwd()
|
current_path = os.getcwd()
|
||||||
@@ -218,3 +148,5 @@ def 删除所有本地对话历史记录(txt, llm_kwargs, plugin_kwargs, chatbot
|
|||||||
chatbot.append([f"删除所有历史对话文件", f"已删除<br/>{local_history}"])
|
chatbot.append([f"删除所有历史对话文件", f"已删除<br/>{local_history}"])
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import glob, shutil, os, re, logging
|
import glob, time, os, re, logging
|
||||||
from toolbox import update_ui, trimmed_format_exc, gen_time_str
|
from toolbox import update_ui, trimmed_format_exc, gen_time_str, disable_auto_promotion
|
||||||
from toolbox import CatchException, report_exception, get_log_folder
|
from toolbox import CatchException, report_exception, get_log_folder
|
||||||
from toolbox import write_history_to_file, promote_file_to_downloadzone
|
from toolbox import write_history_to_file, promote_file_to_downloadzone
|
||||||
fast_debug = False
|
fast_debug = False
|
||||||
@@ -18,7 +18,7 @@ class PaperFileGroup():
|
|||||||
def get_token_num(txt): return len(enc.encode(txt, disallowed_special=()))
|
def get_token_num(txt): return len(enc.encode(txt, disallowed_special=()))
|
||||||
self.get_token_num = get_token_num
|
self.get_token_num = get_token_num
|
||||||
|
|
||||||
def run_file_split(self, max_token_limit=2048):
|
def run_file_split(self, max_token_limit=1900):
|
||||||
"""
|
"""
|
||||||
将长文本分离开来
|
将长文本分离开来
|
||||||
"""
|
"""
|
||||||
@@ -64,25 +64,25 @@ def 多文件翻译(file_manifest, project_folder, llm_kwargs, plugin_kwargs, ch
|
|||||||
pfg.file_contents.append(file_content)
|
pfg.file_contents.append(file_content)
|
||||||
|
|
||||||
# <-------- 拆分过长的Markdown文件 ---------->
|
# <-------- 拆分过长的Markdown文件 ---------->
|
||||||
pfg.run_file_split(max_token_limit=2048)
|
pfg.run_file_split(max_token_limit=1500)
|
||||||
n_split = len(pfg.sp_file_contents)
|
n_split = len(pfg.sp_file_contents)
|
||||||
|
|
||||||
# <-------- 多线程翻译开始 ---------->
|
# <-------- 多线程翻译开始 ---------->
|
||||||
if language == 'en->zh':
|
if language == 'en->zh':
|
||||||
inputs_array = ["This is a Markdown file, translate it into Chinese, do NOT modify any existing Markdown commands, do NOT use code wrapper (```), ONLY answer me with translated results:" +
|
inputs_array = ["This is a Markdown file, translate it into Chinese, do not modify any existing Markdown commands:" +
|
||||||
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 = ["You are a professional academic paper translator." + plugin_kwargs.get("additional_prompt", "") for _ in range(n_split)]
|
sys_prompt_array = ["You are a professional academic paper translator." for _ in range(n_split)]
|
||||||
elif language == 'zh->en':
|
elif language == 'zh->en':
|
||||||
inputs_array = [f"This is a Markdown file, translate it into English, do NOT modify any existing Markdown commands, do NOT use code wrapper (```), ONLY answer me with translated results:" +
|
inputs_array = [f"This is a Markdown file, translate it into English, do not modify any existing Markdown commands:" +
|
||||||
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 = ["You are a professional academic paper translator." + plugin_kwargs.get("additional_prompt", "") for _ in range(n_split)]
|
sys_prompt_array = ["You are a professional academic paper translator." for _ in range(n_split)]
|
||||||
else:
|
else:
|
||||||
inputs_array = [f"This is a Markdown file, translate it into {language}, do NOT modify any existing Markdown commands, do NOT use code wrapper (```), ONLY answer me with translated results:" +
|
inputs_array = [f"This is a Markdown file, translate it into {language}, do not modify any existing Markdown commands, only answer me with translated results:" +
|
||||||
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 = ["You are a professional academic paper translator." + plugin_kwargs.get("additional_prompt", "") for _ in range(n_split)]
|
sys_prompt_array = ["You are a professional academic paper translator." for _ in range(n_split)]
|
||||||
|
|
||||||
gpt_response_collection = yield from request_gpt_model_multi_threads_with_very_awesome_ui_and_high_efficiency(
|
gpt_response_collection = yield from request_gpt_model_multi_threads_with_very_awesome_ui_and_high_efficiency(
|
||||||
inputs_array=inputs_array,
|
inputs_array=inputs_array,
|
||||||
@@ -99,12 +99,7 @@ def 多文件翻译(file_manifest, project_folder, llm_kwargs, plugin_kwargs, ch
|
|||||||
for i_say, gpt_say in zip(gpt_response_collection[0::2], gpt_response_collection[1::2]):
|
for i_say, gpt_say in zip(gpt_response_collection[0::2], gpt_response_collection[1::2]):
|
||||||
pfg.sp_file_result.append(gpt_say)
|
pfg.sp_file_result.append(gpt_say)
|
||||||
pfg.merge_result()
|
pfg.merge_result()
|
||||||
output_file_arr = pfg.write_result(language)
|
pfg.write_result(language)
|
||||||
for output_file in output_file_arr:
|
|
||||||
promote_file_to_downloadzone(output_file, chatbot=chatbot)
|
|
||||||
if 'markdown_expected_output_path' in plugin_kwargs:
|
|
||||||
expected_f_name = plugin_kwargs['markdown_expected_output_path']
|
|
||||||
shutil.copyfile(output_file, expected_f_name)
|
|
||||||
except:
|
except:
|
||||||
logging.error(trimmed_format_exc())
|
logging.error(trimmed_format_exc())
|
||||||
|
|
||||||
@@ -164,6 +159,7 @@ def Markdown英译中(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_p
|
|||||||
"函数插件功能?",
|
"函数插件功能?",
|
||||||
"对整个Markdown项目进行翻译。函数插件贡献者: Binary-Husky"])
|
"对整个Markdown项目进行翻译。函数插件贡献者: Binary-Husky"])
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
||||||
|
disable_auto_promotion(chatbot)
|
||||||
|
|
||||||
# 尝试导入依赖,如果缺少依赖,则给出安装建议
|
# 尝试导入依赖,如果缺少依赖,则给出安装建议
|
||||||
try:
|
try:
|
||||||
@@ -203,6 +199,7 @@ def Markdown中译英(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_p
|
|||||||
"函数插件功能?",
|
"函数插件功能?",
|
||||||
"对整个Markdown项目进行翻译。函数插件贡献者: Binary-Husky"])
|
"对整个Markdown项目进行翻译。函数插件贡献者: Binary-Husky"])
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
||||||
|
disable_auto_promotion(chatbot)
|
||||||
|
|
||||||
# 尝试导入依赖,如果缺少依赖,则给出安装建议
|
# 尝试导入依赖,如果缺少依赖,则给出安装建议
|
||||||
try:
|
try:
|
||||||
@@ -235,6 +232,7 @@ def Markdown翻译指定语言(txt, llm_kwargs, plugin_kwargs, chatbot, history,
|
|||||||
"函数插件功能?",
|
"函数插件功能?",
|
||||||
"对整个Markdown项目进行翻译。函数插件贡献者: Binary-Husky"])
|
"对整个Markdown项目进行翻译。函数插件贡献者: Binary-Husky"])
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
||||||
|
disable_auto_promotion(chatbot)
|
||||||
|
|
||||||
# 尝试导入依赖,如果缺少依赖,则给出安装建议
|
# 尝试导入依赖,如果缺少依赖,则给出安装建议
|
||||||
try:
|
try:
|
||||||
@@ -77,7 +77,7 @@ def 解析Paper(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbo
|
|||||||
|
|
||||||
prefix = "接下来请你逐文件分析下面的论文文件,概括其内容" if index==0 else ""
|
prefix = "接下来请你逐文件分析下面的论文文件,概括其内容" if index==0 else ""
|
||||||
i_say = prefix + f'请对下面的文章片段用中文做一个概述,文件名是{os.path.relpath(fp, project_folder)},文章内容是 ```{file_content}```'
|
i_say = prefix + f'请对下面的文章片段用中文做一个概述,文件名是{os.path.relpath(fp, project_folder)},文章内容是 ```{file_content}```'
|
||||||
i_say_show_user = prefix + f'[{index+1}/{len(file_manifest)}] 请对下面的文章片段做一个概述: {os.path.abspath(fp)}'
|
i_say_show_user = prefix + f'[{index}/{len(file_manifest)}] 请对下面的文章片段做一个概述: {os.path.abspath(fp)}'
|
||||||
chatbot.append((i_say_show_user, "[Local Message] waiting gpt response."))
|
chatbot.append((i_say_show_user, "[Local Message] waiting gpt response."))
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ from .crazy_utils import request_gpt_model_in_new_thread_with_ui_alive
|
|||||||
from .crazy_utils import request_gpt_model_multi_threads_with_very_awesome_ui_and_high_efficiency
|
from .crazy_utils import request_gpt_model_multi_threads_with_very_awesome_ui_and_high_efficiency
|
||||||
from .crazy_utils import read_and_clean_pdf_text
|
from .crazy_utils import read_and_clean_pdf_text
|
||||||
from .pdf_fns.parse_pdf import parse_pdf, get_avail_grobid_url, translate_pdf
|
from .pdf_fns.parse_pdf import parse_pdf, get_avail_grobid_url, translate_pdf
|
||||||
from shared_utils.colorful import *
|
from colorful import *
|
||||||
import copy
|
import copy
|
||||||
import os
|
import os
|
||||||
import math
|
import math
|
||||||
|
|||||||
@@ -1,15 +1,83 @@
|
|||||||
from toolbox import get_log_folder
|
from toolbox import CatchException, report_exception, get_log_folder, gen_time_str, check_packages
|
||||||
from toolbox import update_ui, promote_file_to_downloadzone
|
from toolbox import update_ui, promote_file_to_downloadzone, update_ui_lastest_msg, disable_auto_promotion
|
||||||
from toolbox import write_history_to_file, promote_file_to_downloadzone
|
from toolbox import write_history_to_file, promote_file_to_downloadzone
|
||||||
from crazy_functions.crazy_utils import request_gpt_model_in_new_thread_with_ui_alive
|
from .crazy_utils import request_gpt_model_in_new_thread_with_ui_alive
|
||||||
from crazy_functions.crazy_utils import request_gpt_model_multi_threads_with_very_awesome_ui_and_high_efficiency
|
from .crazy_utils import request_gpt_model_multi_threads_with_very_awesome_ui_and_high_efficiency
|
||||||
from crazy_functions.crazy_utils import read_and_clean_pdf_text
|
from .crazy_utils import read_and_clean_pdf_text
|
||||||
from shared_utils.colorful import *
|
from .pdf_fns.parse_pdf import parse_pdf, get_avail_grobid_url, translate_pdf
|
||||||
|
from colorful import *
|
||||||
import os
|
import os
|
||||||
|
|
||||||
def 解析PDF_简单拆解(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt):
|
|
||||||
|
@CatchException
|
||||||
|
def 批量翻译PDF文档(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request):
|
||||||
|
|
||||||
|
disable_auto_promotion(chatbot)
|
||||||
|
# 基本信息:功能、贡献者
|
||||||
|
chatbot.append([
|
||||||
|
"函数插件功能?",
|
||||||
|
"批量翻译PDF文档。函数插件贡献者: Binary-Husky"])
|
||||||
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
||||||
|
|
||||||
|
# 尝试导入依赖,如果缺少依赖,则给出安装建议
|
||||||
|
try:
|
||||||
|
check_packages(["fitz", "tiktoken", "scipdf"])
|
||||||
|
except:
|
||||||
|
report_exception(chatbot, history,
|
||||||
|
a=f"解析项目: {txt}",
|
||||||
|
b=f"导入软件依赖失败。使用该模块需要额外依赖,安装方法```pip install --upgrade pymupdf tiktoken scipdf_parser```。")
|
||||||
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
||||||
|
return
|
||||||
|
|
||||||
|
# 清空历史,以免输入溢出
|
||||||
|
history = []
|
||||||
|
|
||||||
|
from .crazy_utils import get_files_from_everything
|
||||||
|
success, file_manifest, project_folder = get_files_from_everything(txt, type='.pdf')
|
||||||
|
# 检测输入参数,如没有给定输入参数,直接退出
|
||||||
|
if not success:
|
||||||
|
if txt == "": txt = '空空如也的输入栏'
|
||||||
|
|
||||||
|
# 如果没找到任何文件
|
||||||
|
if len(file_manifest) == 0:
|
||||||
|
report_exception(chatbot, history,
|
||||||
|
a=f"解析项目: {txt}", b=f"找不到任何.pdf拓展名的文件: {txt}")
|
||||||
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
||||||
|
return
|
||||||
|
|
||||||
|
# 开始正式执行任务
|
||||||
|
grobid_url = get_avail_grobid_url()
|
||||||
|
if grobid_url is not None:
|
||||||
|
yield from 解析PDF_基于GROBID(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, grobid_url)
|
||||||
|
else:
|
||||||
|
yield from update_ui_lastest_msg("GROBID服务不可用,请检查config中的GROBID_URL。作为替代,现在将执行效果稍差的旧版代码。", chatbot, history, delay=3)
|
||||||
|
yield from 解析PDF(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt)
|
||||||
|
|
||||||
|
|
||||||
|
def 解析PDF_基于GROBID(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, grobid_url):
|
||||||
|
import copy, json
|
||||||
|
TOKEN_LIMIT_PER_FRAGMENT = 1024
|
||||||
|
generated_conclusion_files = []
|
||||||
|
generated_html_files = []
|
||||||
|
DST_LANG = "中文"
|
||||||
|
from crazy_functions.pdf_fns.report_gen_html import construct_html
|
||||||
|
for index, fp in enumerate(file_manifest):
|
||||||
|
chatbot.append(["当前进度:", f"正在连接GROBID服务,请稍候: {grobid_url}\n如果等待时间过长,请修改config中的GROBID_URL,可修改成本地GROBID服务。"]); yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
||||||
|
article_dict = parse_pdf(fp, grobid_url)
|
||||||
|
grobid_json_res = os.path.join(get_log_folder(), gen_time_str() + "grobid.json")
|
||||||
|
with open(grobid_json_res, 'w+', encoding='utf8') as f:
|
||||||
|
f.write(json.dumps(article_dict, indent=4, ensure_ascii=False))
|
||||||
|
promote_file_to_downloadzone(grobid_json_res, chatbot=chatbot)
|
||||||
|
|
||||||
|
if article_dict is None: raise RuntimeError("解析PDF失败,请检查PDF是否损坏。")
|
||||||
|
yield from translate_pdf(article_dict, llm_kwargs, chatbot, fp, generated_conclusion_files, TOKEN_LIMIT_PER_FRAGMENT, DST_LANG)
|
||||||
|
chatbot.append(("给出输出文件清单", str(generated_conclusion_files + generated_html_files)))
|
||||||
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
||||||
|
|
||||||
|
|
||||||
|
def 解析PDF(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt):
|
||||||
"""
|
"""
|
||||||
注意:此函数已经弃用!!新函数位于:crazy_functions/pdf_fns/parse_pdf.py
|
此函数已经弃用
|
||||||
"""
|
"""
|
||||||
import copy
|
import copy
|
||||||
TOKEN_LIMIT_PER_FRAGMENT = 1024
|
TOKEN_LIMIT_PER_FRAGMENT = 1024
|
||||||
@@ -48,8 +116,7 @@ def 解析PDF_简单拆解(file_manifest, project_folder, llm_kwargs, plugin_kwa
|
|||||||
chatbot=chatbot,
|
chatbot=chatbot,
|
||||||
history_array=[[paper_meta] for _ in paper_fragments],
|
history_array=[[paper_meta] for _ in paper_fragments],
|
||||||
sys_prompt_array=[
|
sys_prompt_array=[
|
||||||
"请你作为一个学术翻译,负责把学术论文准确翻译成中文。注意文章中的每一句话都要翻译。" + plugin_kwargs.get("additional_prompt", "")
|
"请你作为一个学术翻译,负责把学术论文准确翻译成中文。注意文章中的每一句话都要翻译。" for _ in paper_fragments],
|
||||||
for _ in paper_fragments],
|
|
||||||
# max_workers=5 # OpenAI所允许的最大并行过载
|
# max_workers=5 # OpenAI所允许的最大并行过载
|
||||||
)
|
)
|
||||||
gpt_response_collection_md = copy.deepcopy(gpt_response_collection)
|
gpt_response_collection_md = copy.deepcopy(gpt_response_collection)
|
||||||
@@ -12,7 +12,7 @@ def 生成函数注释(file_manifest, project_folder, llm_kwargs, plugin_kwargs,
|
|||||||
file_content = f.read()
|
file_content = f.read()
|
||||||
|
|
||||||
i_say = f'请对下面的程序文件做一个概述,并对文件中的所有函数生成注释,使用markdown表格输出结果,文件名是{os.path.relpath(fp, project_folder)},文件内容是 ```{file_content}```'
|
i_say = f'请对下面的程序文件做一个概述,并对文件中的所有函数生成注释,使用markdown表格输出结果,文件名是{os.path.relpath(fp, project_folder)},文件内容是 ```{file_content}```'
|
||||||
i_say_show_user = f'[{index+1}/{len(file_manifest)}] 请对下面的程序文件做一个概述,并对文件中的所有函数生成注释: {os.path.abspath(fp)}'
|
i_say_show_user = f'[{index}/{len(file_manifest)}] 请对下面的程序文件做一个概述,并对文件中的所有函数生成注释: {os.path.abspath(fp)}'
|
||||||
chatbot.append((i_say_show_user, "[Local Message] waiting gpt response."))
|
chatbot.append((i_say_show_user, "[Local Message] waiting gpt response."))
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,6 @@
|
|||||||
from toolbox import CatchException, update_ui, report_exception
|
from toolbox import CatchException, update_ui, report_exception
|
||||||
from .crazy_utils import request_gpt_model_in_new_thread_with_ui_alive
|
from .crazy_utils import request_gpt_model_in_new_thread_with_ui_alive
|
||||||
from crazy_functions.plugin_template.plugin_class_template import (
|
import datetime
|
||||||
GptAcademicPluginTemplate,
|
|
||||||
)
|
|
||||||
from crazy_functions.plugin_template.plugin_class_template import ArgProperty
|
|
||||||
|
|
||||||
#以下是每类图表的PROMPT
|
#以下是每类图表的PROMPT
|
||||||
SELECT_PROMPT = """
|
SELECT_PROMPT = """
|
||||||
@@ -23,21 +20,19 @@ SELECT_PROMPT = """
|
|||||||
#没有思维导图!!!测试发现模型始终会优先选择思维导图
|
#没有思维导图!!!测试发现模型始终会优先选择思维导图
|
||||||
#流程图
|
#流程图
|
||||||
PROMPT_1 = """
|
PROMPT_1 = """
|
||||||
请你给出围绕“{subject}”的逻辑关系图,使用mermaid语法,注意需要使用双引号将内容括起来。
|
请你给出围绕“{subject}”的逻辑关系图,使用mermaid语法,mermaid语法举例:
|
||||||
mermaid语法举例:
|
|
||||||
```mermaid
|
```mermaid
|
||||||
graph TD
|
graph TD
|
||||||
P("编程") --> L1("Python")
|
P(编程) --> L1(Python)
|
||||||
P("编程") --> L2("C")
|
P(编程) --> L2(C)
|
||||||
P("编程") --> L3("C++")
|
P(编程) --> L3(C++)
|
||||||
P("编程") --> L4("Javascipt")
|
P(编程) --> L4(Javascipt)
|
||||||
P("编程") --> L5("PHP")
|
P(编程) --> L5(PHP)
|
||||||
```
|
```
|
||||||
"""
|
"""
|
||||||
#序列图
|
#序列图
|
||||||
PROMPT_2 = """
|
PROMPT_2 = """
|
||||||
请你给出围绕“{subject}”的序列图,使用mermaid语法。
|
请你给出围绕“{subject}”的序列图,使用mermaid语法,mermaid语法举例:
|
||||||
mermaid语法举例:
|
|
||||||
```mermaid
|
```mermaid
|
||||||
sequenceDiagram
|
sequenceDiagram
|
||||||
participant A as 用户
|
participant A as 用户
|
||||||
@@ -50,8 +45,7 @@ sequenceDiagram
|
|||||||
"""
|
"""
|
||||||
#类图
|
#类图
|
||||||
PROMPT_3 = """
|
PROMPT_3 = """
|
||||||
请你给出围绕“{subject}”的类图,使用mermaid语法。
|
请你给出围绕“{subject}”的类图,使用mermaid语法,mermaid语法举例:
|
||||||
mermaid语法举例:
|
|
||||||
```mermaid
|
```mermaid
|
||||||
classDiagram
|
classDiagram
|
||||||
Class01 <|-- AveryLongClass : Cool
|
Class01 <|-- AveryLongClass : Cool
|
||||||
@@ -71,8 +65,7 @@ classDiagram
|
|||||||
"""
|
"""
|
||||||
#饼图
|
#饼图
|
||||||
PROMPT_4 = """
|
PROMPT_4 = """
|
||||||
请你给出围绕“{subject}”的饼图,使用mermaid语法,注意需要使用双引号将内容括起来。
|
请你给出围绕“{subject}”的饼图,使用mermaid语法,mermaid语法举例:
|
||||||
mermaid语法举例:
|
|
||||||
```mermaid
|
```mermaid
|
||||||
pie title Pets adopted by volunteers
|
pie title Pets adopted by volunteers
|
||||||
"狗" : 386
|
"狗" : 386
|
||||||
@@ -82,39 +75,36 @@ pie title Pets adopted by volunteers
|
|||||||
"""
|
"""
|
||||||
#甘特图
|
#甘特图
|
||||||
PROMPT_5 = """
|
PROMPT_5 = """
|
||||||
请你给出围绕“{subject}”的甘特图,使用mermaid语法,注意需要使用双引号将内容括起来。
|
请你给出围绕“{subject}”的甘特图,使用mermaid语法,mermaid语法举例:
|
||||||
mermaid语法举例:
|
|
||||||
```mermaid
|
```mermaid
|
||||||
gantt
|
gantt
|
||||||
title "项目开发流程"
|
title 项目开发流程
|
||||||
dateFormat YYYY-MM-DD
|
dateFormat YYYY-MM-DD
|
||||||
section "设计"
|
section 设计
|
||||||
"需求分析" :done, des1, 2024-01-06,2024-01-08
|
需求分析 :done, des1, 2024-01-06,2024-01-08
|
||||||
"原型设计" :active, des2, 2024-01-09, 3d
|
原型设计 :active, des2, 2024-01-09, 3d
|
||||||
"UI设计" : des3, after des2, 5d
|
UI设计 : des3, after des2, 5d
|
||||||
section "开发"
|
section 开发
|
||||||
"前端开发" :2024-01-20, 10d
|
前端开发 :2024-01-20, 10d
|
||||||
"后端开发" :2024-01-20, 10d
|
后端开发 :2024-01-20, 10d
|
||||||
```
|
```
|
||||||
"""
|
"""
|
||||||
#状态图
|
#状态图
|
||||||
PROMPT_6 = """
|
PROMPT_6 = """
|
||||||
请你给出围绕“{subject}”的状态图,使用mermaid语法,注意需要使用双引号将内容括起来。
|
请你给出围绕“{subject}”的状态图,使用mermaid语法,mermaid语法举例:
|
||||||
mermaid语法举例:
|
|
||||||
```mermaid
|
```mermaid
|
||||||
stateDiagram-v2
|
stateDiagram-v2
|
||||||
[*] --> "Still"
|
[*] --> Still
|
||||||
"Still" --> [*]
|
Still --> [*]
|
||||||
"Still" --> "Moving"
|
Still --> Moving
|
||||||
"Moving" --> "Still"
|
Moving --> Still
|
||||||
"Moving" --> "Crash"
|
Moving --> Crash
|
||||||
"Crash" --> [*]
|
Crash --> [*]
|
||||||
```
|
```
|
||||||
"""
|
"""
|
||||||
#实体关系图
|
#实体关系图
|
||||||
PROMPT_7 = """
|
PROMPT_7 = """
|
||||||
请你给出围绕“{subject}”的实体关系图,使用mermaid语法。
|
请你给出围绕“{subject}”的实体关系图,使用mermaid语法,mermaid语法举例:
|
||||||
mermaid语法举例:
|
|
||||||
```mermaid
|
```mermaid
|
||||||
erDiagram
|
erDiagram
|
||||||
CUSTOMER ||--o{ ORDER : places
|
CUSTOMER ||--o{ ORDER : places
|
||||||
@@ -136,171 +126,116 @@ erDiagram
|
|||||||
"""
|
"""
|
||||||
#象限提示图
|
#象限提示图
|
||||||
PROMPT_8 = """
|
PROMPT_8 = """
|
||||||
请你给出围绕“{subject}”的象限图,使用mermaid语法,注意需要使用双引号将内容括起来。
|
请你给出围绕“{subject}”的象限图,使用mermaid语法,mermaid语法举例:
|
||||||
mermaid语法举例:
|
|
||||||
```mermaid
|
```mermaid
|
||||||
graph LR
|
graph LR
|
||||||
A["Hard skill"] --> B("Programming")
|
A[Hard skill] --> B(Programming)
|
||||||
A["Hard skill"] --> C("Design")
|
A[Hard skill] --> C(Design)
|
||||||
D["Soft skill"] --> E("Coordination")
|
D[Soft skill] --> E(Coordination)
|
||||||
D["Soft skill"] --> F("Communication")
|
D[Soft skill] --> F(Communication)
|
||||||
```
|
```
|
||||||
"""
|
"""
|
||||||
#思维导图
|
#思维导图
|
||||||
PROMPT_9 = """
|
PROMPT_9 = """
|
||||||
{subject}
|
{subject}
|
||||||
==========
|
==========
|
||||||
请给出上方内容的思维导图,充分考虑其之间的逻辑,使用mermaid语法,注意需要使用双引号将内容括起来。
|
请给出上方内容的思维导图,充分考虑其之间的逻辑,使用mermaid语法,mermaid语法举例:
|
||||||
mermaid语法举例:
|
|
||||||
```mermaid
|
```mermaid
|
||||||
mindmap
|
mindmap
|
||||||
root((mindmap))
|
root((mindmap))
|
||||||
("Origins")
|
Origins
|
||||||
("Long history")
|
Long history
|
||||||
::icon(fa fa-book)
|
::icon(fa fa-book)
|
||||||
("Popularisation")
|
Popularisation
|
||||||
("British popular psychology author Tony Buzan")
|
British popular psychology author Tony Buzan
|
||||||
::icon(fa fa-user)
|
Research
|
||||||
("Research")
|
On effectiveness<br/>and features
|
||||||
("On effectiveness<br/>and features")
|
On Automatic creation
|
||||||
::icon(fa fa-search)
|
Uses
|
||||||
("On Automatic creation")
|
Creative techniques
|
||||||
::icon(fa fa-robot)
|
Strategic planning
|
||||||
("Uses")
|
Argument mapping
|
||||||
("Creative techniques")
|
Tools
|
||||||
::icon(fa fa-lightbulb-o)
|
Pen and paper
|
||||||
("Strategic planning")
|
Mermaid
|
||||||
::icon(fa fa-flag)
|
|
||||||
("Argument mapping")
|
|
||||||
::icon(fa fa-comments)
|
|
||||||
("Tools")
|
|
||||||
("Pen and paper")
|
|
||||||
::icon(fa fa-pencil)
|
|
||||||
("Mermaid")
|
|
||||||
::icon(fa fa-code)
|
|
||||||
```
|
```
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
def 解析历史输入(history,llm_kwargs,file_manifest,chatbot,plugin_kwargs):
|
def 解析历史输入(history,llm_kwargs,file_manifest,chatbot,plugin_kwargs):
|
||||||
############################## <第 0 步,切割输入> ##################################
|
############################## <第 0 步,切割输入> ##################################
|
||||||
# 借用PDF切割中的函数对文本进行切割
|
# 借用PDF切割中的函数对文本进行切割
|
||||||
TOKEN_LIMIT_PER_FRAGMENT = 2500
|
TOKEN_LIMIT_PER_FRAGMENT = 2500
|
||||||
txt = (
|
txt = str(history).encode('utf-8', 'ignore').decode() # avoid reading non-utf8 chars
|
||||||
str(history).encode("utf-8", "ignore").decode()
|
from crazy_functions.pdf_fns.breakdown_txt import breakdown_text_to_satisfy_token_limit
|
||||||
) # avoid reading non-utf8 chars
|
txt = breakdown_text_to_satisfy_token_limit(txt=txt, limit=TOKEN_LIMIT_PER_FRAGMENT, llm_model=llm_kwargs['llm_model'])
|
||||||
from crazy_functions.pdf_fns.breakdown_txt import (
|
|
||||||
breakdown_text_to_satisfy_token_limit,
|
|
||||||
)
|
|
||||||
|
|
||||||
txt = breakdown_text_to_satisfy_token_limit(
|
|
||||||
txt=txt, limit=TOKEN_LIMIT_PER_FRAGMENT, llm_model=llm_kwargs["llm_model"]
|
|
||||||
)
|
|
||||||
############################## <第 1 步,迭代地历遍整个文章,提取精炼信息> ##################################
|
############################## <第 1 步,迭代地历遍整个文章,提取精炼信息> ##################################
|
||||||
results = []
|
results = []
|
||||||
MAX_WORD_TOTAL = 4096
|
MAX_WORD_TOTAL = 4096
|
||||||
n_txt = len(txt)
|
n_txt = len(txt)
|
||||||
last_iteration_result = "从以下文本中提取摘要。"
|
last_iteration_result = "从以下文本中提取摘要。"
|
||||||
if n_txt >= 20:
|
if n_txt >= 20: print('文章极长,不能达到预期效果')
|
||||||
print("文章极长,不能达到预期效果")
|
|
||||||
for i in range(n_txt):
|
for i in range(n_txt):
|
||||||
NUM_OF_WORD = MAX_WORD_TOTAL // n_txt
|
NUM_OF_WORD = MAX_WORD_TOTAL // n_txt
|
||||||
i_say = f"Read this section, recapitulate the content of this section with less than {NUM_OF_WORD} words in Chinese: {txt[i]}"
|
i_say = f"Read this section, recapitulate the content of this section with less than {NUM_OF_WORD} words in Chinese: {txt[i]}"
|
||||||
i_say_show_user = f"[{i+1}/{n_txt}] Read this section, recapitulate the content of this section with less than {NUM_OF_WORD} words: {txt[i][:200]} ...."
|
i_say_show_user = f"[{i+1}/{n_txt}] Read this section, recapitulate the content of this section with less than {NUM_OF_WORD} words: {txt[i][:200]} ...."
|
||||||
gpt_say = yield from request_gpt_model_in_new_thread_with_ui_alive(
|
gpt_say = yield from request_gpt_model_in_new_thread_with_ui_alive(i_say, i_say_show_user, # i_say=真正给chatgpt的提问, i_say_show_user=给用户看的提问
|
||||||
i_say,
|
llm_kwargs, chatbot,
|
||||||
i_say_show_user, # i_say=真正给chatgpt的提问, i_say_show_user=给用户看的提问
|
history=["The main content of the previous section is?", last_iteration_result], # 迭代上一次的结果
|
||||||
llm_kwargs,
|
sys_prompt="Extracts the main content from the text section where it is located for graphing purposes, answer me with Chinese." # 提示
|
||||||
chatbot,
|
|
||||||
history=[
|
|
||||||
"The main content of the previous section is?",
|
|
||||||
last_iteration_result,
|
|
||||||
], # 迭代上一次的结果
|
|
||||||
sys_prompt="Extracts the main content from the text section where it is located for graphing purposes, answer me with Chinese.", # 提示
|
|
||||||
)
|
)
|
||||||
results.append(gpt_say)
|
results.append(gpt_say)
|
||||||
last_iteration_result = gpt_say
|
last_iteration_result = gpt_say
|
||||||
############################## <第 2 步,根据整理的摘要选择图表类型> ##################################
|
############################## <第 2 步,根据整理的摘要选择图表类型> ##################################
|
||||||
gpt_say = str(plugin_kwargs) # 将图表类型参数赋值为插件参数
|
if ("advanced_arg" in plugin_kwargs) and (plugin_kwargs["advanced_arg"] == ""): plugin_kwargs.pop("advanced_arg")
|
||||||
results_txt = "\n".join(results) # 合并摘要
|
gpt_say = plugin_kwargs.get("advanced_arg", "") #将图表类型参数赋值为插件参数
|
||||||
if gpt_say not in [
|
results_txt = '\n'.join(results) #合并摘要
|
||||||
"1",
|
if gpt_say not in ['1','2','3','4','5','6','7','8','9']: #如插件参数不正确则使用对话模型判断
|
||||||
"2",
|
i_say_show_user = f'接下来将判断适合的图表类型,如连续3次判断失败将会使用流程图进行绘制'; gpt_say = "[Local Message] 收到。" # 用户提示
|
||||||
"3",
|
chatbot.append([i_say_show_user, gpt_say]); yield from update_ui(chatbot=chatbot, history=[]) # 更新UI
|
||||||
"4",
|
|
||||||
"5",
|
|
||||||
"6",
|
|
||||||
"7",
|
|
||||||
"8",
|
|
||||||
"9",
|
|
||||||
]: # 如插件参数不正确则使用对话模型判断
|
|
||||||
i_say_show_user = (
|
|
||||||
f"接下来将判断适合的图表类型,如连续3次判断失败将会使用流程图进行绘制"
|
|
||||||
)
|
|
||||||
gpt_say = "[Local Message] 收到。" # 用户提示
|
|
||||||
chatbot.append([i_say_show_user, gpt_say])
|
|
||||||
yield from update_ui(chatbot=chatbot, history=[]) # 更新UI
|
|
||||||
i_say = SELECT_PROMPT.format(subject=results_txt)
|
i_say = SELECT_PROMPT.format(subject=results_txt)
|
||||||
i_say_show_user = f'请判断适合使用的流程图类型,其中数字对应关系为:1-流程图,2-序列图,3-类图,4-饼图,5-甘特图,6-状态图,7-实体关系图,8-象限提示图。由于不管提供文本是什么,模型大概率认为"思维导图"最合适,因此思维导图仅能通过参数调用。'
|
i_say_show_user = f'请判断适合使用的流程图类型,其中数字对应关系为:1-流程图,2-序列图,3-类图,4-饼图,5-甘特图,6-状态图,7-实体关系图,8-象限提示图。由于不管提供文本是什么,模型大概率认为"思维导图"最合适,因此思维导图仅能通过参数调用。'
|
||||||
for i in range(3):
|
for i in range(3):
|
||||||
gpt_say = yield from request_gpt_model_in_new_thread_with_ui_alive(
|
gpt_say = yield from request_gpt_model_in_new_thread_with_ui_alive(
|
||||||
inputs=i_say,
|
inputs=i_say,
|
||||||
inputs_show_user=i_say_show_user,
|
inputs_show_user=i_say_show_user,
|
||||||
llm_kwargs=llm_kwargs,
|
llm_kwargs=llm_kwargs, chatbot=chatbot, history=[],
|
||||||
chatbot=chatbot,
|
sys_prompt=""
|
||||||
history=[],
|
|
||||||
sys_prompt="",
|
|
||||||
)
|
)
|
||||||
if gpt_say in [
|
if gpt_say in ['1','2','3','4','5','6','7','8','9']: #判断返回是否正确
|
||||||
"1",
|
|
||||||
"2",
|
|
||||||
"3",
|
|
||||||
"4",
|
|
||||||
"5",
|
|
||||||
"6",
|
|
||||||
"7",
|
|
||||||
"8",
|
|
||||||
"9",
|
|
||||||
]: # 判断返回是否正确
|
|
||||||
break
|
break
|
||||||
if gpt_say not in ["1", "2", "3", "4", "5", "6", "7", "8", "9"]:
|
if gpt_say not in ['1','2','3','4','5','6','7','8','9']:
|
||||||
gpt_say = "1"
|
gpt_say = '1'
|
||||||
############################## <第 3 步,根据选择的图表类型绘制图表> ##################################
|
############################## <第 3 步,根据选择的图表类型绘制图表> ##################################
|
||||||
if gpt_say == "1":
|
if gpt_say == '1':
|
||||||
i_say = PROMPT_1.format(subject=results_txt)
|
i_say = PROMPT_1.format(subject=results_txt)
|
||||||
elif gpt_say == "2":
|
elif gpt_say == '2':
|
||||||
i_say = PROMPT_2.format(subject=results_txt)
|
i_say = PROMPT_2.format(subject=results_txt)
|
||||||
elif gpt_say == "3":
|
elif gpt_say == '3':
|
||||||
i_say = PROMPT_3.format(subject=results_txt)
|
i_say = PROMPT_3.format(subject=results_txt)
|
||||||
elif gpt_say == "4":
|
elif gpt_say == '4':
|
||||||
i_say = PROMPT_4.format(subject=results_txt)
|
i_say = PROMPT_4.format(subject=results_txt)
|
||||||
elif gpt_say == "5":
|
elif gpt_say == '5':
|
||||||
i_say = PROMPT_5.format(subject=results_txt)
|
i_say = PROMPT_5.format(subject=results_txt)
|
||||||
elif gpt_say == "6":
|
elif gpt_say == '6':
|
||||||
i_say = PROMPT_6.format(subject=results_txt)
|
i_say = PROMPT_6.format(subject=results_txt)
|
||||||
elif gpt_say == "7":
|
elif gpt_say == '7':
|
||||||
i_say = PROMPT_7.replace("{subject}", results_txt) #由于实体关系图用到了{}符号
|
i_say = PROMPT_7.replace("{subject}", results_txt) #由于实体关系图用到了{}符号
|
||||||
elif gpt_say == "8":
|
elif gpt_say == '8':
|
||||||
i_say = PROMPT_8.format(subject=results_txt)
|
i_say = PROMPT_8.format(subject=results_txt)
|
||||||
elif gpt_say == "9":
|
elif gpt_say == '9':
|
||||||
i_say = PROMPT_9.format(subject=results_txt)
|
i_say = PROMPT_9.format(subject=results_txt)
|
||||||
i_say_show_user = f"请根据判断结果绘制相应的图表。如需绘制思维导图请使用参数调用,同时过大的图表可能需要复制到在线编辑器中进行渲染。"
|
i_say_show_user = f'请根据判断结果绘制相应的图表。如需绘制思维导图请使用参数调用,同时过大的图表可能需要复制到在线编辑器中进行渲染。'
|
||||||
gpt_say = yield from request_gpt_model_in_new_thread_with_ui_alive(
|
gpt_say = yield from request_gpt_model_in_new_thread_with_ui_alive(
|
||||||
inputs=i_say,
|
inputs=i_say,
|
||||||
inputs_show_user=i_say_show_user,
|
inputs_show_user=i_say_show_user,
|
||||||
llm_kwargs=llm_kwargs,
|
llm_kwargs=llm_kwargs, chatbot=chatbot, history=[],
|
||||||
chatbot=chatbot,
|
sys_prompt=""
|
||||||
history=[],
|
|
||||||
sys_prompt="",
|
|
||||||
)
|
)
|
||||||
history.append(gpt_say)
|
history.append(gpt_say)
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 # 界面更新
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 # 界面更新
|
||||||
|
|
||||||
|
|
||||||
@CatchException
|
@CatchException
|
||||||
def 生成多种Mermaid图表(
|
def 生成多种Mermaid图表(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port):
|
||||||
txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port
|
|
||||||
):
|
|
||||||
"""
|
"""
|
||||||
txt 输入栏用户输入的文本,例如需要翻译的一段话,再例如一个包含了待处理文件的路径
|
txt 输入栏用户输入的文本,例如需要翻译的一段话,再例如一个包含了待处理文件的路径
|
||||||
llm_kwargs gpt模型参数,如温度和top_p等,一般原样传递下去就行
|
llm_kwargs gpt模型参数,如温度和top_p等,一般原样传递下去就行
|
||||||
@@ -313,21 +248,15 @@ def 生成多种Mermaid图表(
|
|||||||
import os
|
import os
|
||||||
|
|
||||||
# 基本信息:功能、贡献者
|
# 基本信息:功能、贡献者
|
||||||
chatbot.append(
|
chatbot.append([
|
||||||
[
|
|
||||||
"函数插件功能?",
|
"函数插件功能?",
|
||||||
"根据当前聊天历史或指定的路径文件(文件内容优先)绘制多种mermaid图表,将会由对话模型首先判断适合的图表类型,随后绘制图表。\
|
"根据当前聊天历史或指定的路径文件(文件内容优先)绘制多种mermaid图表,将会由对话模型首先判断适合的图表类型,随后绘制图表。\
|
||||||
\n您也可以使用插件参数指定绘制的图表类型,函数插件贡献者: Menghuan1918",
|
\n您也可以使用插件参数指定绘制的图表类型,函数插件贡献者: Menghuan1918"])
|
||||||
]
|
|
||||||
)
|
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
||||||
|
|
||||||
if os.path.exists(txt): #如输入区无内容则直接解析历史记录
|
if os.path.exists(txt): #如输入区无内容则直接解析历史记录
|
||||||
from crazy_functions.pdf_fns.parse_word import extract_text_from_files
|
from crazy_functions.pdf_fns.parse_word import extract_text_from_files
|
||||||
|
file_exist, final_result, page_one, file_manifest, excption = extract_text_from_files(txt, chatbot, history)
|
||||||
file_exist, final_result, page_one, file_manifest, excption = (
|
|
||||||
extract_text_from_files(txt, chatbot, history)
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
file_exist = False
|
file_exist = False
|
||||||
excption = ""
|
excption = ""
|
||||||
@@ -335,104 +264,33 @@ def 生成多种Mermaid图表(
|
|||||||
|
|
||||||
if excption != "":
|
if excption != "":
|
||||||
if excption == "word":
|
if excption == "word":
|
||||||
report_exception(
|
report_exception(chatbot, history,
|
||||||
chatbot,
|
|
||||||
history,
|
|
||||||
a = f"解析项目: {txt}",
|
a = f"解析项目: {txt}",
|
||||||
b=f"找到了.doc文件,但是该文件格式不被支持,请先转化为.docx格式。",
|
b = f"找到了.doc文件,但是该文件格式不被支持,请先转化为.docx格式。")
|
||||||
)
|
|
||||||
|
|
||||||
elif excption == "pdf":
|
elif excption == "pdf":
|
||||||
report_exception(
|
report_exception(chatbot, history,
|
||||||
chatbot,
|
|
||||||
history,
|
|
||||||
a = f"解析项目: {txt}",
|
a = f"解析项目: {txt}",
|
||||||
b=f"导入软件依赖失败。使用该模块需要额外依赖,安装方法```pip install --upgrade pymupdf```。",
|
b = f"导入软件依赖失败。使用该模块需要额外依赖,安装方法```pip install --upgrade pymupdf```。")
|
||||||
)
|
|
||||||
|
|
||||||
elif excption == "word_pip":
|
elif excption == "word_pip":
|
||||||
report_exception(
|
report_exception(chatbot, history,
|
||||||
chatbot,
|
|
||||||
history,
|
|
||||||
a=f"解析项目: {txt}",
|
a=f"解析项目: {txt}",
|
||||||
b=f"导入软件依赖失败。使用该模块需要额外依赖,安装方法```pip install --upgrade python-docx pywin32```。",
|
b=f"导入软件依赖失败。使用该模块需要额外依赖,安装方法```pip install --upgrade python-docx pywin32```。")
|
||||||
)
|
|
||||||
|
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
||||||
|
|
||||||
else:
|
else:
|
||||||
if not file_exist:
|
if not file_exist:
|
||||||
history.append(txt) #如输入区不是文件则将输入区内容加入历史记录
|
history.append(txt) #如输入区不是文件则将输入区内容加入历史记录
|
||||||
i_say_show_user = f"首先你从历史记录中提取摘要。"
|
i_say_show_user = f'首先你从历史记录中提取摘要。'; gpt_say = "[Local Message] 收到。" # 用户提示
|
||||||
gpt_say = "[Local Message] 收到。" # 用户提示
|
chatbot.append([i_say_show_user, gpt_say]); yield from update_ui(chatbot=chatbot, history=history) # 更新UI
|
||||||
chatbot.append([i_say_show_user, gpt_say])
|
yield from 解析历史输入(history,llm_kwargs,file_manifest,chatbot,plugin_kwargs)
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 更新UI
|
|
||||||
yield from 解析历史输入(
|
|
||||||
history, llm_kwargs, file_manifest, chatbot, plugin_kwargs
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
file_num = len(file_manifest)
|
file_num = len(file_manifest)
|
||||||
for i in range(file_num): #依次处理文件
|
for i in range(file_num): #依次处理文件
|
||||||
i_say_show_user = f"[{i+1}/{file_num}]处理文件{file_manifest[i]}"
|
i_say_show_user = f"[{i+1}/{file_num}]处理文件{file_manifest[i]}"; gpt_say = "[Local Message] 收到。" # 用户提示
|
||||||
gpt_say = "[Local Message] 收到。" # 用户提示
|
chatbot.append([i_say_show_user, gpt_say]); yield from update_ui(chatbot=chatbot, history=history) # 更新UI
|
||||||
chatbot.append([i_say_show_user, gpt_say])
|
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 更新UI
|
|
||||||
history = [] #如输入区内容为文件则清空历史记录
|
history = [] #如输入区内容为文件则清空历史记录
|
||||||
history.append(final_result[i])
|
history.append(final_result[i])
|
||||||
yield from 解析历史输入(
|
yield from 解析历史输入(history,llm_kwargs,file_manifest,chatbot,plugin_kwargs)
|
||||||
history, llm_kwargs, file_manifest, chatbot, plugin_kwargs
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class Mermaid_Gen(GptAcademicPluginTemplate):
|
|
||||||
def __init__(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def define_arg_selection_menu(self):
|
|
||||||
gui_definition = {
|
|
||||||
"Type_of_Mermaid": ArgProperty(
|
|
||||||
title="绘制的Mermaid图表类型",
|
|
||||||
options=[
|
|
||||||
"由LLM决定",
|
|
||||||
"流程图",
|
|
||||||
"序列图",
|
|
||||||
"类图",
|
|
||||||
"饼图",
|
|
||||||
"甘特图",
|
|
||||||
"状态图",
|
|
||||||
"实体关系图",
|
|
||||||
"象限提示图",
|
|
||||||
"思维导图",
|
|
||||||
],
|
|
||||||
default_value="由LLM决定",
|
|
||||||
description="选择'由LLM决定'时将由对话模型判断适合的图表类型(不包括思维导图),选择其他类型时将直接绘制指定的图表类型。",
|
|
||||||
type="dropdown",
|
|
||||||
).model_dump_json(),
|
|
||||||
}
|
|
||||||
return gui_definition
|
|
||||||
|
|
||||||
def execute(
|
|
||||||
txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request
|
|
||||||
):
|
|
||||||
options = [
|
|
||||||
"由LLM决定",
|
|
||||||
"流程图",
|
|
||||||
"序列图",
|
|
||||||
"类图",
|
|
||||||
"饼图",
|
|
||||||
"甘特图",
|
|
||||||
"状态图",
|
|
||||||
"实体关系图",
|
|
||||||
"象限提示图",
|
|
||||||
"思维导图",
|
|
||||||
]
|
|
||||||
plugin_kwargs = options.index(plugin_kwargs['Type_of_Mermaid'])
|
|
||||||
yield from 生成多种Mermaid图表(
|
|
||||||
txt,
|
|
||||||
llm_kwargs,
|
|
||||||
plugin_kwargs,
|
|
||||||
chatbot,
|
|
||||||
history,
|
|
||||||
system_prompt,
|
|
||||||
user_request,
|
|
||||||
)
|
|
||||||
@@ -1,12 +1,12 @@
|
|||||||
from toolbox import update_ui, promote_file_to_downloadzone
|
from toolbox import update_ui, promote_file_to_downloadzone, disable_auto_promotion
|
||||||
from toolbox import CatchException, report_exception, write_history_to_file
|
from toolbox import CatchException, report_exception, write_history_to_file
|
||||||
from shared_utils.fastapi_server import validate_path_safety
|
from .crazy_utils import input_clipping
|
||||||
from crazy_functions.crazy_utils import input_clipping
|
|
||||||
|
|
||||||
def 解析源代码新(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt):
|
def 解析源代码新(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt):
|
||||||
import os, copy
|
import os, copy
|
||||||
from .crazy_utils import request_gpt_model_multi_threads_with_very_awesome_ui_and_high_efficiency
|
from .crazy_utils import request_gpt_model_multi_threads_with_very_awesome_ui_and_high_efficiency
|
||||||
from .crazy_utils import request_gpt_model_in_new_thread_with_ui_alive
|
from .crazy_utils import request_gpt_model_in_new_thread_with_ui_alive
|
||||||
|
disable_auto_promotion(chatbot=chatbot)
|
||||||
|
|
||||||
summary_batch_isolation = True
|
summary_batch_isolation = True
|
||||||
inputs_array = []
|
inputs_array = []
|
||||||
@@ -23,7 +23,7 @@ def 解析源代码新(file_manifest, project_folder, llm_kwargs, plugin_kwargs,
|
|||||||
file_content = f.read()
|
file_content = f.read()
|
||||||
prefix = "接下来请你逐文件分析下面的工程" if index==0 else ""
|
prefix = "接下来请你逐文件分析下面的工程" if index==0 else ""
|
||||||
i_say = prefix + f'请对下面的程序文件做一个概述文件名是{os.path.relpath(fp, project_folder)},文件代码是 ```{file_content}```'
|
i_say = prefix + f'请对下面的程序文件做一个概述文件名是{os.path.relpath(fp, project_folder)},文件代码是 ```{file_content}```'
|
||||||
i_say_show_user = prefix + f'[{index+1}/{len(file_manifest)}] 请对下面的程序文件做一个概述: {fp}'
|
i_say_show_user = prefix + f'[{index}/{len(file_manifest)}] 请对下面的程序文件做一个概述: {fp}'
|
||||||
# 装载请求内容
|
# 装载请求内容
|
||||||
inputs_array.append(i_say)
|
inputs_array.append(i_say)
|
||||||
inputs_show_user_array.append(i_say_show_user)
|
inputs_show_user_array.append(i_say_show_user)
|
||||||
@@ -128,7 +128,6 @@ def 解析一个Python项目(txt, llm_kwargs, plugin_kwargs, chatbot, history, s
|
|||||||
import glob, os
|
import glob, os
|
||||||
if os.path.exists(txt):
|
if os.path.exists(txt):
|
||||||
project_folder = txt
|
project_folder = txt
|
||||||
validate_path_safety(project_folder, chatbot.get_user())
|
|
||||||
else:
|
else:
|
||||||
if txt == "": txt = '空空如也的输入栏'
|
if txt == "": txt = '空空如也的输入栏'
|
||||||
report_exception(chatbot, history, a = f"解析项目: {txt}", b = f"找不到本地项目或无权访问: {txt}")
|
report_exception(chatbot, history, a = f"解析项目: {txt}", b = f"找不到本地项目或无权访问: {txt}")
|
||||||
@@ -147,7 +146,6 @@ def 解析一个Matlab项目(txt, llm_kwargs, plugin_kwargs, chatbot, history, s
|
|||||||
import glob, os
|
import glob, os
|
||||||
if os.path.exists(txt):
|
if os.path.exists(txt):
|
||||||
project_folder = txt
|
project_folder = txt
|
||||||
validate_path_safety(project_folder, chatbot.get_user())
|
|
||||||
else:
|
else:
|
||||||
if txt == "": txt = '空空如也的输入栏'
|
if txt == "": txt = '空空如也的输入栏'
|
||||||
report_exception(chatbot, history, a = f"解析Matlab项目: {txt}", b = f"找不到本地项目或无权访问: {txt}")
|
report_exception(chatbot, history, a = f"解析Matlab项目: {txt}", b = f"找不到本地项目或无权访问: {txt}")
|
||||||
@@ -166,7 +164,6 @@ def 解析一个C项目的头文件(txt, llm_kwargs, plugin_kwargs, chatbot, his
|
|||||||
import glob, os
|
import glob, os
|
||||||
if os.path.exists(txt):
|
if os.path.exists(txt):
|
||||||
project_folder = txt
|
project_folder = txt
|
||||||
validate_path_safety(project_folder, chatbot.get_user())
|
|
||||||
else:
|
else:
|
||||||
if txt == "": txt = '空空如也的输入栏'
|
if txt == "": txt = '空空如也的输入栏'
|
||||||
report_exception(chatbot, history, a = f"解析项目: {txt}", b = f"找不到本地项目或无权访问: {txt}")
|
report_exception(chatbot, history, a = f"解析项目: {txt}", b = f"找不到本地项目或无权访问: {txt}")
|
||||||
@@ -187,7 +184,6 @@ def 解析一个C项目(txt, llm_kwargs, plugin_kwargs, chatbot, history, system
|
|||||||
import glob, os
|
import glob, os
|
||||||
if os.path.exists(txt):
|
if os.path.exists(txt):
|
||||||
project_folder = txt
|
project_folder = txt
|
||||||
validate_path_safety(project_folder, chatbot.get_user())
|
|
||||||
else:
|
else:
|
||||||
if txt == "": txt = '空空如也的输入栏'
|
if txt == "": txt = '空空如也的输入栏'
|
||||||
report_exception(chatbot, history, a = f"解析项目: {txt}", b = f"找不到本地项目或无权访问: {txt}")
|
report_exception(chatbot, history, a = f"解析项目: {txt}", b = f"找不到本地项目或无权访问: {txt}")
|
||||||
@@ -210,7 +206,6 @@ def 解析一个Java项目(txt, llm_kwargs, plugin_kwargs, chatbot, history, sys
|
|||||||
import glob, os
|
import glob, os
|
||||||
if os.path.exists(txt):
|
if os.path.exists(txt):
|
||||||
project_folder = txt
|
project_folder = txt
|
||||||
validate_path_safety(project_folder, chatbot.get_user())
|
|
||||||
else:
|
else:
|
||||||
if txt == "": txt = '空空如也的输入栏'
|
if txt == "": txt = '空空如也的输入栏'
|
||||||
report_exception(chatbot, history, a=f"解析项目: {txt}", b=f"找不到本地项目或无权访问: {txt}")
|
report_exception(chatbot, history, a=f"解析项目: {txt}", b=f"找不到本地项目或无权访问: {txt}")
|
||||||
@@ -233,7 +228,6 @@ def 解析一个前端项目(txt, llm_kwargs, plugin_kwargs, chatbot, history, s
|
|||||||
import glob, os
|
import glob, os
|
||||||
if os.path.exists(txt):
|
if os.path.exists(txt):
|
||||||
project_folder = txt
|
project_folder = txt
|
||||||
validate_path_safety(project_folder, chatbot.get_user())
|
|
||||||
else:
|
else:
|
||||||
if txt == "": txt = '空空如也的输入栏'
|
if txt == "": txt = '空空如也的输入栏'
|
||||||
report_exception(chatbot, history, a=f"解析项目: {txt}", b=f"找不到本地项目或无权访问: {txt}")
|
report_exception(chatbot, history, a=f"解析项目: {txt}", b=f"找不到本地项目或无权访问: {txt}")
|
||||||
@@ -263,7 +257,6 @@ def 解析一个Golang项目(txt, llm_kwargs, plugin_kwargs, chatbot, history, s
|
|||||||
import glob, os
|
import glob, os
|
||||||
if os.path.exists(txt):
|
if os.path.exists(txt):
|
||||||
project_folder = txt
|
project_folder = txt
|
||||||
validate_path_safety(project_folder, chatbot.get_user())
|
|
||||||
else:
|
else:
|
||||||
if txt == "": txt = '空空如也的输入栏'
|
if txt == "": txt = '空空如也的输入栏'
|
||||||
report_exception(chatbot, history, a=f"解析项目: {txt}", b=f"找不到本地项目或无权访问: {txt}")
|
report_exception(chatbot, history, a=f"解析项目: {txt}", b=f"找不到本地项目或无权访问: {txt}")
|
||||||
@@ -285,7 +278,6 @@ def 解析一个Rust项目(txt, llm_kwargs, plugin_kwargs, chatbot, history, sys
|
|||||||
import glob, os
|
import glob, os
|
||||||
if os.path.exists(txt):
|
if os.path.exists(txt):
|
||||||
project_folder = txt
|
project_folder = txt
|
||||||
validate_path_safety(project_folder, chatbot.get_user())
|
|
||||||
else:
|
else:
|
||||||
if txt == "": txt = '空空如也的输入栏'
|
if txt == "": txt = '空空如也的输入栏'
|
||||||
report_exception(chatbot, history, a=f"解析项目: {txt}", b=f"找不到本地项目或无权访问: {txt}")
|
report_exception(chatbot, history, a=f"解析项目: {txt}", b=f"找不到本地项目或无权访问: {txt}")
|
||||||
@@ -306,7 +298,6 @@ def 解析一个Lua项目(txt, llm_kwargs, plugin_kwargs, chatbot, history, syst
|
|||||||
import glob, os
|
import glob, os
|
||||||
if os.path.exists(txt):
|
if os.path.exists(txt):
|
||||||
project_folder = txt
|
project_folder = txt
|
||||||
validate_path_safety(project_folder, chatbot.get_user())
|
|
||||||
else:
|
else:
|
||||||
if txt == "": txt = '空空如也的输入栏'
|
if txt == "": txt = '空空如也的输入栏'
|
||||||
report_exception(chatbot, history, a = f"解析项目: {txt}", b = f"找不到本地项目或无权访问: {txt}")
|
report_exception(chatbot, history, a = f"解析项目: {txt}", b = f"找不到本地项目或无权访问: {txt}")
|
||||||
@@ -329,7 +320,6 @@ def 解析一个CSharp项目(txt, llm_kwargs, plugin_kwargs, chatbot, history, s
|
|||||||
import glob, os
|
import glob, os
|
||||||
if os.path.exists(txt):
|
if os.path.exists(txt):
|
||||||
project_folder = txt
|
project_folder = txt
|
||||||
validate_path_safety(project_folder, chatbot.get_user())
|
|
||||||
else:
|
else:
|
||||||
if txt == "": txt = '空空如也的输入栏'
|
if txt == "": txt = '空空如也的输入栏'
|
||||||
report_exception(chatbot, history, a = f"解析项目: {txt}", b = f"找不到本地项目或无权访问: {txt}")
|
report_exception(chatbot, history, a = f"解析项目: {txt}", b = f"找不到本地项目或无权访问: {txt}")
|
||||||
@@ -355,19 +345,15 @@ 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(".", r"\.") # 移除左边通配符,移除右侧逗号,转义点号
|
pattern_except_name = [_.lstrip(" ^*,").rstrip(" ,").replace(".", "\.") for _ in txt_pattern.split(" ") if _ != "" and _.strip().startswith("^") and not _.strip().startswith("^*.")]
|
||||||
for _ in txt_pattern.split(" ") # 以空格分割
|
|
||||||
if (_ != "" and _.strip().startswith("^") and not _.strip().startswith("^*.")) # ^开始,但不是^*.开始
|
|
||||||
]
|
|
||||||
# 生成正则表达式
|
# 生成正则表达式
|
||||||
pattern_except = r'/[^/]+\.(' + "|".join(pattern_except_suffix) + ')$'
|
pattern_except = '/[^/]+\.(' + "|".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()
|
||||||
import glob, os, re
|
import glob, os, re
|
||||||
if os.path.exists(txt):
|
if os.path.exists(txt):
|
||||||
project_folder = txt
|
project_folder = txt
|
||||||
validate_path_safety(project_folder, chatbot.get_user())
|
|
||||||
else:
|
else:
|
||||||
if txt == "": txt = '空空如也的输入栏'
|
if txt == "": txt = '空空如也的输入栏'
|
||||||
report_exception(chatbot, history, a = f"解析项目: {txt}", b = f"找不到本地项目或无权访问: {txt}")
|
report_exception(chatbot, history, a = f"解析项目: {txt}", b = f"找不到本地项目或无权访问: {txt}")
|
||||||
@@ -13,7 +13,7 @@ def 解析Paper(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbo
|
|||||||
|
|
||||||
prefix = "接下来请你逐文件分析下面的论文文件,概括其内容" if index==0 else ""
|
prefix = "接下来请你逐文件分析下面的论文文件,概括其内容" if index==0 else ""
|
||||||
i_say = prefix + f'请对下面的文章片段用中文做一个概述,文件名是{os.path.relpath(fp, project_folder)},文章内容是 ```{file_content}```'
|
i_say = prefix + f'请对下面的文章片段用中文做一个概述,文件名是{os.path.relpath(fp, project_folder)},文章内容是 ```{file_content}```'
|
||||||
i_say_show_user = prefix + f'[{index+1}/{len(file_manifest)}] 请对下面的文章片段做一个概述: {os.path.abspath(fp)}'
|
i_say_show_user = prefix + f'[{index}/{len(file_manifest)}] 请对下面的文章片段做一个概述: {os.path.abspath(fp)}'
|
||||||
chatbot.append((i_say_show_user, "[Local Message] waiting gpt response."))
|
chatbot.append((i_say_show_user, "[Local Message] waiting gpt response."))
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
||||||
|
|
||||||
|
|||||||
28
crazy_functions/辅助回答.py
普通文件
28
crazy_functions/辅助回答.py
普通文件
@@ -0,0 +1,28 @@
|
|||||||
|
# encoding: utf-8
|
||||||
|
# @Time : 2023/4/19
|
||||||
|
# @Author : Spike
|
||||||
|
# @Descr :
|
||||||
|
from toolbox import update_ui
|
||||||
|
from toolbox import CatchException, report_execption, write_results_to_file
|
||||||
|
from crazy_functions.crazy_utils import request_gpt_model_in_new_thread_with_ui_alive
|
||||||
|
|
||||||
|
|
||||||
|
@CatchException
|
||||||
|
def 猜你想问(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port):
|
||||||
|
if txt:
|
||||||
|
show_say = txt
|
||||||
|
prompt = txt+'\n回答完问题后,再列出用户可能提出的三个问题。'
|
||||||
|
else:
|
||||||
|
prompt = history[-1]+"\n分析上述回答,再列出用户可能提出的三个问题。"
|
||||||
|
show_say = '分析上述回答,再列出用户可能提出的三个问题。'
|
||||||
|
gpt_say = yield from request_gpt_model_in_new_thread_with_ui_alive(
|
||||||
|
inputs=prompt,
|
||||||
|
inputs_show_user=show_say,
|
||||||
|
llm_kwargs=llm_kwargs,
|
||||||
|
chatbot=chatbot,
|
||||||
|
history=history,
|
||||||
|
sys_prompt=system_prompt
|
||||||
|
)
|
||||||
|
chatbot[-1] = (show_say, gpt_say)
|
||||||
|
history.extend([show_say, gpt_say])
|
||||||
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
||||||
@@ -2,10 +2,6 @@ from toolbox import CatchException, update_ui
|
|||||||
from crazy_functions.crazy_utils import request_gpt_model_in_new_thread_with_ui_alive
|
from crazy_functions.crazy_utils import request_gpt_model_in_new_thread_with_ui_alive
|
||||||
import datetime
|
import datetime
|
||||||
|
|
||||||
####################################################################################################################
|
|
||||||
# Demo 1: 一个非常简单的插件 #########################################################################################
|
|
||||||
####################################################################################################################
|
|
||||||
|
|
||||||
高阶功能模板函数示意图 = f"""
|
高阶功能模板函数示意图 = f"""
|
||||||
```mermaid
|
```mermaid
|
||||||
flowchart TD
|
flowchart TD
|
||||||
@@ -30,7 +26,7 @@ flowchart TD
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
@CatchException
|
@CatchException
|
||||||
def 高阶功能模板函数(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request, num_day=5):
|
def 高阶功能模板函数(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request):
|
||||||
"""
|
"""
|
||||||
# 高阶功能模板函数示意图:https://mermaid.live/edit#pako:eNptk1tvEkEYhv8KmattQpvlvOyFCcdeeaVXuoYssBwie8gyhCIlqVoLhrbbtAWNUpEGUkyMEDW2Fmn_DDOL_8LZHdOwxrnamX3f7_3mmZk6yKhZCfAgV1KrmYKoQ9fDuKC4yChX0nld1Aou1JzjznQ5fWmejh8LYHW6vG2a47YAnlCLNSIRolnenKBXI_zRIBrcuqRT890u7jZx7zMDt-AaMbnW1--5olGiz2sQjwfoQxsZL0hxplSSU0-rop4vrzmKR6O2JxYjHmwcL2Y_HDatVMkXlf86YzHbGY9bO5j8XE7O8Nsbc3iNB3ukL2SMcH-XIQBgWoVOZzxuOxOJOyc63EPGV6ZQLENVrznViYStTiaJ2vw2M2d9bByRnOXkgCnXylCSU5quyto_IcmkbdvctELmJ-j1ASW3uB3g5xOmKqVTmqr_Na3AtuS_dtBFm8H90XJyHkDDT7S9xXWb4HGmRChx64AOL5HRpUm411rM5uh4H78Z4V7fCZzytjZz2seto9XaNPFue07clLaVZF8UNLygJ-VES8lah_n-O-5Ozc7-77NzJ0-K0yr0ZYrmHdqAk50t2RbA4qq9uNohBASw7YpSgaRkLWCCAtxAlnRZLGbJba9bPwUAC5IsCYAnn1kpJ1ZKUACC0iBSsQLVBzUlA3ioVyQ3qGhZEUrxokiehAz4nFgqk1VNVABfB1uAD_g2_AGPl-W8nMcbCvsDblADfNCz4feyobDPy3rYEMtxwYYbPFNVUoHdCPmDHBv2cP4AMfrCbiBli-Q-3afv0X6WdsIjW2-10fgDy1SAig
|
# 高阶功能模板函数示意图:https://mermaid.live/edit#pako:eNptk1tvEkEYhv8KmattQpvlvOyFCcdeeaVXuoYssBwie8gyhCIlqVoLhrbbtAWNUpEGUkyMEDW2Fmn_DDOL_8LZHdOwxrnamX3f7_3mmZk6yKhZCfAgV1KrmYKoQ9fDuKC4yChX0nld1Aou1JzjznQ5fWmejh8LYHW6vG2a47YAnlCLNSIRolnenKBXI_zRIBrcuqRT890u7jZx7zMDt-AaMbnW1--5olGiz2sQjwfoQxsZL0hxplSSU0-rop4vrzmKR6O2JxYjHmwcL2Y_HDatVMkXlf86YzHbGY9bO5j8XE7O8Nsbc3iNB3ukL2SMcH-XIQBgWoVOZzxuOxOJOyc63EPGV6ZQLENVrznViYStTiaJ2vw2M2d9bByRnOXkgCnXylCSU5quyto_IcmkbdvctELmJ-j1ASW3uB3g5xOmKqVTmqr_Na3AtuS_dtBFm8H90XJyHkDDT7S9xXWb4HGmRChx64AOL5HRpUm411rM5uh4H78Z4V7fCZzytjZz2seto9XaNPFue07clLaVZF8UNLygJ-VES8lah_n-O-5Ozc7-77NzJ0-K0yr0ZYrmHdqAk50t2RbA4qq9uNohBASw7YpSgaRkLWCCAtxAlnRZLGbJba9bPwUAC5IsCYAnn1kpJ1ZKUACC0iBSsQLVBzUlA3ioVyQ3qGhZEUrxokiehAz4nFgqk1VNVABfB1uAD_g2_AGPl-W8nMcbCvsDblADfNCz4feyobDPy3rYEMtxwYYbPFNVUoHdCPmDHBv2cP4AMfrCbiBli-Q-3afv0X6WdsIjW2-10fgDy1SAig
|
||||||
|
|
||||||
@@ -47,7 +43,7 @@ def 高阶功能模板函数(txt, llm_kwargs, plugin_kwargs, chatbot, history, s
|
|||||||
"您正在调用插件:历史上的今天",
|
"您正在调用插件:历史上的今天",
|
||||||
"[Local Message] 请注意,您正在调用一个[函数插件]的模板,该函数面向希望实现更多有趣功能的开发者,它可以作为创建新功能函数的模板(该函数只有20多行代码)。此外我们也提供可同步处理大量文件的多线程Demo供您参考。您若希望分享新的功能模组,请不吝PR!" + 高阶功能模板函数示意图))
|
"[Local Message] 请注意,您正在调用一个[函数插件]的模板,该函数面向希望实现更多有趣功能的开发者,它可以作为创建新功能函数的模板(该函数只有20多行代码)。此外我们也提供可同步处理大量文件的多线程Demo供您参考。您若希望分享新的功能模组,请不吝PR!" + 高阶功能模板函数示意图))
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 # 由于请求gpt需要一段时间,我们先及时地做一次界面更新
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 # 由于请求gpt需要一段时间,我们先及时地做一次界面更新
|
||||||
for i in range(int(num_day)):
|
for i in range(5):
|
||||||
currentMonth = (datetime.date.today() + datetime.timedelta(days=i)).month
|
currentMonth = (datetime.date.today() + datetime.timedelta(days=i)).month
|
||||||
currentDay = (datetime.date.today() + datetime.timedelta(days=i)).day
|
currentDay = (datetime.date.today() + datetime.timedelta(days=i)).day
|
||||||
i_say = f'历史中哪些事件发生在{currentMonth}月{currentDay}日?列举两条并发送相关图片。发送图片时,请使用Markdown,将Unsplash API中的PUT_YOUR_QUERY_HERE替换成描述该事件的一个最重要的单词。'
|
i_say = f'历史中哪些事件发生在{currentMonth}月{currentDay}日?列举两条并发送相关图片。发送图片时,请使用Markdown,将Unsplash API中的PUT_YOUR_QUERY_HERE替换成描述该事件的一个最重要的单词。'
|
||||||
@@ -63,56 +59,6 @@ def 高阶功能模板函数(txt, llm_kwargs, plugin_kwargs, chatbot, history, s
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
####################################################################################################################
|
|
||||||
# Demo 2: 一个带二级菜单的插件 #######################################################################################
|
|
||||||
####################################################################################################################
|
|
||||||
|
|
||||||
from crazy_functions.plugin_template.plugin_class_template import GptAcademicPluginTemplate, ArgProperty
|
|
||||||
class Demo_Wrap(GptAcademicPluginTemplate):
|
|
||||||
def __init__(self):
|
|
||||||
"""
|
|
||||||
请注意`execute`会执行在不同的线程中,因此您在定义和使用类变量时,应当慎之又慎!
|
|
||||||
"""
|
|
||||||
pass
|
|
||||||
|
|
||||||
def define_arg_selection_menu(self):
|
|
||||||
"""
|
|
||||||
定义插件的二级选项菜单
|
|
||||||
"""
|
|
||||||
gui_definition = {
|
|
||||||
"num_day":
|
|
||||||
ArgProperty(title="日期选择", options=["仅今天", "未来3天", "未来5天"], default_value="未来3天", description="无", type="dropdown").model_dump_json(),
|
|
||||||
}
|
|
||||||
return gui_definition
|
|
||||||
|
|
||||||
def execute(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request):
|
|
||||||
"""
|
|
||||||
执行插件
|
|
||||||
"""
|
|
||||||
num_day = plugin_kwargs["num_day"]
|
|
||||||
if num_day == "仅今天": num_day = 1
|
|
||||||
if num_day == "未来3天": num_day = 3
|
|
||||||
if num_day == "未来5天": num_day = 5
|
|
||||||
yield from 高阶功能模板函数(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request, num_day=num_day)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
####################################################################################################################
|
|
||||||
# Demo 3: 绘制脑图的Demo ############################################################################################
|
|
||||||
####################################################################################################################
|
|
||||||
|
|
||||||
PROMPT = """
|
PROMPT = """
|
||||||
请你给出围绕“{subject}”的逻辑关系图,使用mermaid语法,mermaid语法举例:
|
请你给出围绕“{subject}”的逻辑关系图,使用mermaid语法,mermaid语法举例:
|
||||||
```mermaid
|
```mermaid
|
||||||
|
|||||||
@@ -4,9 +4,9 @@
|
|||||||
# 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,8 +75,10 @@ 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:
|
||||||
@@ -95,16 +97,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:
|
||||||
@@ -128,10 +130,8 @@ 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,9 +139,8 @@ 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:
|
||||||
@@ -165,16 +164,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:
|
||||||
@@ -191,16 +190,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:
|
||||||
@@ -224,9 +223,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"
|
||||||
|
|||||||
@@ -3,9 +3,6 @@
|
|||||||
# 从NVIDIA源,从而支持显卡(检查宿主的nvidia-smi中的cuda版本必须>=11.3)
|
# 从NVIDIA源,从而支持显卡(检查宿主的nvidia-smi中的cuda版本必须>=11.3)
|
||||||
FROM fuqingxu/11.3.1-runtime-ubuntu20.04-with-texlive:latest
|
FROM fuqingxu/11.3.1-runtime-ubuntu20.04-with-texlive:latest
|
||||||
|
|
||||||
# edge-tts需要的依赖,某些pip包所需的依赖
|
|
||||||
RUN apt update && apt install ffmpeg build-essential -y
|
|
||||||
|
|
||||||
# use python3 as the system default python
|
# use python3 as the system default python
|
||||||
WORKDIR /gpt
|
WORKDIR /gpt
|
||||||
RUN curl -sS https://bootstrap.pypa.io/get-pip.py | python3.8
|
RUN curl -sS https://bootstrap.pypa.io/get-pip.py | python3.8
|
||||||
|
|||||||
@@ -5,9 +5,6 @@
|
|||||||
# 从NVIDIA源,从而支持显卡(检查宿主的nvidia-smi中的cuda版本必须>=11.3)
|
# 从NVIDIA源,从而支持显卡(检查宿主的nvidia-smi中的cuda版本必须>=11.3)
|
||||||
FROM fuqingxu/11.3.1-runtime-ubuntu20.04-with-texlive:latest
|
FROM fuqingxu/11.3.1-runtime-ubuntu20.04-with-texlive:latest
|
||||||
|
|
||||||
# edge-tts需要的依赖,某些pip包所需的依赖
|
|
||||||
RUN apt update && apt install ffmpeg build-essential -y
|
|
||||||
|
|
||||||
# use python3 as the system default python
|
# use python3 as the system default python
|
||||||
WORKDIR /gpt
|
WORKDIR /gpt
|
||||||
RUN curl -sS https://bootstrap.pypa.io/get-pip.py | python3.8
|
RUN curl -sS https://bootstrap.pypa.io/get-pip.py | python3.8
|
||||||
@@ -39,7 +36,6 @@ RUN python3 -m pip install -r request_llms/requirements_chatglm.txt
|
|||||||
RUN python3 -m pip install -r request_llms/requirements_newbing.txt
|
RUN python3 -m pip install -r request_llms/requirements_newbing.txt
|
||||||
RUN python3 -m pip install nougat-ocr
|
RUN python3 -m pip install nougat-ocr
|
||||||
|
|
||||||
|
|
||||||
# 预热Tiktoken模块
|
# 预热Tiktoken模块
|
||||||
RUN python3 -c 'from check_proxy import warm_up_modules; warm_up_modules()'
|
RUN python3 -c 'from check_proxy import warm_up_modules; warm_up_modules()'
|
||||||
|
|
||||||
|
|||||||
@@ -5,8 +5,6 @@ RUN apt-get update
|
|||||||
RUN apt-get install -y curl proxychains curl gcc
|
RUN apt-get install -y curl proxychains curl gcc
|
||||||
RUN apt-get install -y git python python3 python-dev python3-dev --fix-missing
|
RUN apt-get install -y git python python3 python-dev python3-dev --fix-missing
|
||||||
|
|
||||||
# edge-tts需要的依赖,某些pip包所需的依赖
|
|
||||||
RUN apt update && apt install ffmpeg build-essential -y
|
|
||||||
|
|
||||||
# use python3 as the system default python
|
# use python3 as the system default python
|
||||||
RUN curl -sS https://bootstrap.pypa.io/get-pip.py | python3.8
|
RUN curl -sS https://bootstrap.pypa.io/get-pip.py | python3.8
|
||||||
@@ -24,6 +22,7 @@ RUN python3 -m pip install -r request_llms/requirements_chatglm.txt
|
|||||||
RUN python3 -m pip install -r request_llms/requirements_newbing.txt
|
RUN python3 -m pip install -r request_llms/requirements_newbing.txt
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# 预热Tiktoken模块
|
# 预热Tiktoken模块
|
||||||
RUN python3 -c 'from check_proxy import warm_up_modules; warm_up_modules()'
|
RUN python3 -c 'from check_proxy import warm_up_modules; warm_up_modules()'
|
||||||
|
|
||||||
|
|||||||
@@ -23,9 +23,6 @@ RUN python3 -m pip install -r request_llms/requirements_jittorllms.txt -i https:
|
|||||||
# 下载JittorLLMs
|
# 下载JittorLLMs
|
||||||
RUN git clone https://github.com/binary-husky/JittorLLMs.git --depth 1 request_llms/jittorllms
|
RUN git clone https://github.com/binary-husky/JittorLLMs.git --depth 1 request_llms/jittorllms
|
||||||
|
|
||||||
# edge-tts需要的依赖
|
|
||||||
RUN apt update && apt install ffmpeg -y
|
|
||||||
|
|
||||||
# 禁用缓存,确保更新代码
|
# 禁用缓存,确保更新代码
|
||||||
ADD "https://www.random.org/cgi-bin/randbyte?nbytes=10&format=h" skipcache
|
ADD "https://www.random.org/cgi-bin/randbyte?nbytes=10&format=h" skipcache
|
||||||
RUN git pull
|
RUN git pull
|
||||||
|
|||||||
@@ -12,8 +12,6 @@ COPY . .
|
|||||||
# 安装依赖
|
# 安装依赖
|
||||||
RUN pip3 install -r requirements.txt
|
RUN pip3 install -r requirements.txt
|
||||||
|
|
||||||
# edge-tts需要的依赖
|
|
||||||
RUN apt update && apt install ffmpeg -y
|
|
||||||
|
|
||||||
# 可选步骤,用于预热模块
|
# 可选步骤,用于预热模块
|
||||||
RUN python3 -c 'from check_proxy import warm_up_modules; warm_up_modules()'
|
RUN python3 -c 'from check_proxy import warm_up_modules; warm_up_modules()'
|
||||||
|
|||||||
@@ -15,9 +15,6 @@ RUN pip3 install -r requirements.txt
|
|||||||
# 安装语音插件的额外依赖
|
# 安装语音插件的额外依赖
|
||||||
RUN pip3 install aliyun-python-sdk-core==2.13.3 pyOpenSSL webrtcvad scipy git+https://github.com/aliyun/alibabacloud-nls-python-sdk.git
|
RUN pip3 install aliyun-python-sdk-core==2.13.3 pyOpenSSL webrtcvad scipy git+https://github.com/aliyun/alibabacloud-nls-python-sdk.git
|
||||||
|
|
||||||
# edge-tts需要的依赖
|
|
||||||
RUN apt update && apt install ffmpeg -y
|
|
||||||
|
|
||||||
# 可选步骤,用于预热模块
|
# 可选步骤,用于预热模块
|
||||||
RUN python3 -c 'from check_proxy import warm_up_modules; warm_up_modules()'
|
RUN python3 -c 'from check_proxy import warm_up_modules; warm_up_modules()'
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,9 @@ ENV PATH "$PATH:/usr/local/texlive/2024/bin/x86_64-linux"
|
|||||||
ENV PATH "$PATH:/usr/local/texlive/2025/bin/x86_64-linux"
|
ENV PATH "$PATH:/usr/local/texlive/2025/bin/x86_64-linux"
|
||||||
ENV PATH "$PATH:/usr/local/texlive/2026/bin/x86_64-linux"
|
ENV PATH "$PATH:/usr/local/texlive/2026/bin/x86_64-linux"
|
||||||
|
|
||||||
|
# 删除文档文件以节约空间
|
||||||
|
RUN rm -rf /usr/local/texlive/2023/texmf-dist/doc
|
||||||
|
|
||||||
# 指定路径
|
# 指定路径
|
||||||
WORKDIR /gpt
|
WORKDIR /gpt
|
||||||
|
|
||||||
@@ -25,9 +28,6 @@ COPY . .
|
|||||||
# 安装依赖
|
# 安装依赖
|
||||||
RUN pip3 install -r requirements.txt
|
RUN pip3 install -r requirements.txt
|
||||||
|
|
||||||
# edge-tts需要的依赖
|
|
||||||
RUN apt update && apt install ffmpeg -y
|
|
||||||
|
|
||||||
# 可选步骤,用于预热模块
|
# 可选步骤,用于预热模块
|
||||||
RUN python3 -c 'from check_proxy import warm_up_modules; warm_up_modules()'
|
RUN python3 -c 'from check_proxy import warm_up_modules; warm_up_modules()'
|
||||||
|
|
||||||
|
|||||||
@@ -19,9 +19,6 @@ RUN pip3 install transformers protobuf langchain sentence-transformers faiss-cp
|
|||||||
RUN pip3 install unstructured[all-docs] --upgrade
|
RUN pip3 install unstructured[all-docs] --upgrade
|
||||||
RUN python3 -c 'from check_proxy import warm_up_vectordb; warm_up_vectordb()'
|
RUN python3 -c 'from check_proxy import warm_up_vectordb; warm_up_vectordb()'
|
||||||
|
|
||||||
# edge-tts需要的依赖
|
|
||||||
RUN apt update && apt install ffmpeg -y
|
|
||||||
|
|
||||||
# 可选步骤,用于预热模块
|
# 可选步骤,用于预热模块
|
||||||
RUN python3 -c 'from check_proxy import warm_up_modules; warm_up_modules()'
|
RUN python3 -c 'from check_proxy import warm_up_modules; warm_up_modules()'
|
||||||
|
|
||||||
|
|||||||
@@ -1,189 +0,0 @@
|
|||||||
# 实现带二级菜单的插件
|
|
||||||
|
|
||||||
## 一、如何写带有二级菜单的插件
|
|
||||||
|
|
||||||
1. 声明一个 `Class`,继承父类 `GptAcademicPluginTemplate`
|
|
||||||
|
|
||||||
```python
|
|
||||||
from crazy_functions.plugin_template.plugin_class_template import GptAcademicPluginTemplate
|
|
||||||
from crazy_functions.plugin_template.plugin_class_template import ArgProperty
|
|
||||||
|
|
||||||
class Demo_Wrap(GptAcademicPluginTemplate):
|
|
||||||
def __init__(self): ...
|
|
||||||
```
|
|
||||||
|
|
||||||
2. 声明二级菜单中需要的变量,覆盖父类的`define_arg_selection_menu`函数。
|
|
||||||
|
|
||||||
```python
|
|
||||||
class Demo_Wrap(GptAcademicPluginTemplate):
|
|
||||||
...
|
|
||||||
|
|
||||||
def define_arg_selection_menu(self):
|
|
||||||
"""
|
|
||||||
定义插件的二级选项菜单
|
|
||||||
|
|
||||||
第一个参数,名称`main_input`,参数`type`声明这是一个文本框,文本框上方显示`title`,文本框内部显示`description`,`default_value`为默认值;
|
|
||||||
第二个参数,名称`advanced_arg`,参数`type`声明这是一个文本框,文本框上方显示`title`,文本框内部显示`description`,`default_value`为默认值;
|
|
||||||
第三个参数,名称`allow_cache`,参数`type`声明这是一个下拉菜单,下拉菜单上方显示`title`+`description`,下拉菜单的选项为`options`,`default_value`为下拉菜单默认值;
|
|
||||||
"""
|
|
||||||
gui_definition = {
|
|
||||||
"main_input":
|
|
||||||
ArgProperty(title="ArxivID", description="输入Arxiv的ID或者网址", default_value="", type="string").model_dump_json(),
|
|
||||||
"advanced_arg":
|
|
||||||
ArgProperty(title="额外的翻译提示词",
|
|
||||||
description=r"如果有必要, 请在此处给出自定义翻译命令",
|
|
||||||
default_value="", type="string").model_dump_json(),
|
|
||||||
"allow_cache":
|
|
||||||
ArgProperty(title="是否允许从缓存中调取结果", options=["允许缓存", "从头执行"], default_value="允许缓存", description="无", type="dropdown").model_dump_json(),
|
|
||||||
}
|
|
||||||
return gui_definition
|
|
||||||
...
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
> [!IMPORTANT]
|
|
||||||
>
|
|
||||||
> ArgProperty 中每个条目对应一个参数,`type == "string"`时,使用文本块,`type == dropdown`时,使用下拉菜单。
|
|
||||||
>
|
|
||||||
> 注意:`main_input` 和 `advanced_arg`是两个特殊的参数。`main_input`会自动与界面右上角的`输入区`进行同步,而`advanced_arg`会自动与界面右下角的`高级参数输入区`同步。除此之外,参数名称可以任意选取。其他细节详见`crazy_functions/plugin_template/plugin_class_template.py`。
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
3. 编写插件程序,覆盖父类的`execute`函数。
|
|
||||||
|
|
||||||
例如:
|
|
||||||
|
|
||||||
```python
|
|
||||||
class Demo_Wrap(GptAcademicPluginTemplate):
|
|
||||||
...
|
|
||||||
...
|
|
||||||
|
|
||||||
def execute(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request):
|
|
||||||
"""
|
|
||||||
执行插件
|
|
||||||
|
|
||||||
plugin_kwargs字典中会包含用户的选择,与上述 `define_arg_selection_menu` 一一对应
|
|
||||||
"""
|
|
||||||
allow_cache = plugin_kwargs["allow_cache"]
|
|
||||||
advanced_arg = plugin_kwargs["advanced_arg"]
|
|
||||||
|
|
||||||
if allow_cache == "从头执行": plugin_kwargs["advanced_arg"] = "--no-cache " + plugin_kwargs["advanced_arg"]
|
|
||||||
yield from Latex翻译中文并重新编译PDF(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request)
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
4. 注册插件
|
|
||||||
|
|
||||||
将以下条目插入`crazy_functional.py`即可。注意,与旧插件不同的是,`Function`键值应该为None,而`Class`键值为上述插件的类名称(`Demo_Wrap`)。
|
|
||||||
```
|
|
||||||
"新插件": {
|
|
||||||
"Group": "学术",
|
|
||||||
"Color": "stop",
|
|
||||||
"AsButton": True,
|
|
||||||
"Info": "插件说明",
|
|
||||||
"Function": None,
|
|
||||||
"Class": Demo_Wrap,
|
|
||||||
},
|
|
||||||
```
|
|
||||||
|
|
||||||
5. 已经结束了,启动程序测试吧~!
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## 二、背后的原理(需要JavaScript的前置知识)
|
|
||||||
|
|
||||||
|
|
||||||
### (I) 首先介绍三个Gradio官方没有的重要前端函数
|
|
||||||
|
|
||||||
主javascript程序`common.js`中有三个Gradio官方没有的重要API
|
|
||||||
|
|
||||||
1. `get_data_from_gradio_component`
|
|
||||||
这个函数可以获取任意gradio组件的当前值,例如textbox中的字符,dropdown中的当前选项,chatbot当前的对话等等。调用方法举例:
|
|
||||||
```javascript
|
|
||||||
// 获取当前的对话
|
|
||||||
let chatbot = await get_data_from_gradio_component('gpt-chatbot');
|
|
||||||
```
|
|
||||||
|
|
||||||
2. `get_gradio_component`
|
|
||||||
有时候我们不仅需要gradio组件的当前值,还需要它的label值、是否隐藏、下拉菜单其他可选选项等等,而通过这个函数可以直接获取这个组件的句柄。举例:
|
|
||||||
```javascript
|
|
||||||
// 获取下拉菜单组件的句柄
|
|
||||||
var model_sel = await get_gradio_component("elem_model_sel");
|
|
||||||
// 获取它的所有属性,包括其所有可选选项
|
|
||||||
console.log(model_sel.props)
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
3. `push_data_to_gradio_component`
|
|
||||||
这个函数可以将数据推回gradio组件,例如textbox中的字符,dropdown中的当前选项等等。调用方法举例:
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
// 修改一个按钮上面的文本
|
|
||||||
push_data_to_gradio_component("btnName", "gradio_element_id", "string");
|
|
||||||
|
|
||||||
// 隐藏一个组件
|
|
||||||
push_data_to_gradio_component({ visible: false, __type__: 'update' }, "plugin_arg_menu", "obj");
|
|
||||||
|
|
||||||
// 修改组件label
|
|
||||||
push_data_to_gradio_component({ label: '新label的值', __type__: 'update' }, "gpt-chatbot", "obj")
|
|
||||||
|
|
||||||
// 第一个参数是value,
|
|
||||||
// - 可以是字符串(调整textbox的文本,按钮的文本);
|
|
||||||
// - 还可以是 { visible: false, __type__: 'update' } 这样的字典(调整visible, label, choices)
|
|
||||||
// 第二个参数是elem_id
|
|
||||||
// 第三个参数是"string" 或者 "obj"
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
### (II) 从点击插件到执行插件的逻辑过程
|
|
||||||
|
|
||||||
简述:程序启动时把每个插件的二级菜单编码为BASE64,存储在用户的浏览器前端,用户调用对应功能时,会按照插件的BASE64编码,将平时隐藏的菜单(有选择性地)显示出来。
|
|
||||||
|
|
||||||
1. 启动阶段(主函数 `main.py` 中),遍历每个插件,生成二级菜单的BASE64编码,存入变量`register_advanced_plugin_init_code_arr`。
|
|
||||||
```python
|
|
||||||
def get_js_code_for_generating_menu(self, btnName):
|
|
||||||
define_arg_selection = self.define_arg_selection_menu()
|
|
||||||
DEFINE_ARG_INPUT_INTERFACE = json.dumps(define_arg_selection)
|
|
||||||
return base64.b64encode(DEFINE_ARG_INPUT_INTERFACE.encode('utf-8')).decode('utf-8')
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
2. 用户加载阶段(主javascript程序`common.js`中),浏览器加载`register_advanced_plugin_init_code_arr`,存入本地的字典`advanced_plugin_init_code_lib`:
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
advanced_plugin_init_code_lib = {}
|
|
||||||
function register_advanced_plugin_init_code(key, code){
|
|
||||||
advanced_plugin_init_code_lib[key] = code;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
3. 用户点击插件按钮(主函数 `main.py` 中)时,仅执行以下javascript代码,唤醒隐藏的二级菜单(生成菜单的代码在`common.js`中的`generate_menu`函数上):
|
|
||||||
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
// 生成高级插件的选择菜单
|
|
||||||
function run_advanced_plugin_launch_code(key){
|
|
||||||
generate_menu(advanced_plugin_init_code_lib[key], key);
|
|
||||||
}
|
|
||||||
function on_flex_button_click(key){
|
|
||||||
run_advanced_plugin_launch_code(key);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
```python
|
|
||||||
click_handle = plugins[k]["Button"].click(None, inputs=[], outputs=None, _js=f"""()=>run_advanced_plugin_launch_code("{k}")""")
|
|
||||||
```
|
|
||||||
|
|
||||||
4. 当用户点击二级菜单的执行键时,通过javascript脚本模拟点击一个隐藏按钮,触发后续程序(`common.js`中的`execute_current_pop_up_plugin`,会把二级菜单中的参数缓存到`invisible_current_pop_up_plugin_arg_final`,然后模拟点击`invisible_callback_btn_for_plugin_exe`按钮)。隐藏按钮的定义在(主函数 `main.py` ),该隐藏按钮会最终触发`route_switchy_bt_with_arg`函数(定义于`themes/gui_advanced_plugin_class.py`):
|
|
||||||
|
|
||||||
```python
|
|
||||||
click_handle_ng = new_plugin_callback.click(route_switchy_bt_with_arg, [
|
|
||||||
gr.State(["new_plugin_callback", "usr_confirmed_arg"] + input_combo_order),
|
|
||||||
new_plugin_callback, usr_confirmed_arg, *input_combo
|
|
||||||
], output_combo)
|
|
||||||
```
|
|
||||||
|
|
||||||
5. 最后,`route_switchy_bt_with_arg`中,会搜集所有用户参数,统一集中到`plugin_kwargs`参数中,并执行对应插件的`execute`函数。
|
|
||||||
@@ -22,13 +22,13 @@
|
|||||||
| crazy_functions\下载arxiv论文翻译摘要.py | 下载 `arxiv` 论文的 PDF 文件,并提取摘要和翻译 |
|
| crazy_functions\下载arxiv论文翻译摘要.py | 下载 `arxiv` 论文的 PDF 文件,并提取摘要和翻译 |
|
||||||
| crazy_functions\代码重写为全英文_多线程.py | 将Python源代码文件中的中文内容转化为英文 |
|
| crazy_functions\代码重写为全英文_多线程.py | 将Python源代码文件中的中文内容转化为英文 |
|
||||||
| crazy_functions\图片生成.py | 根据激励文本使用GPT模型生成相应的图像 |
|
| crazy_functions\图片生成.py | 根据激励文本使用GPT模型生成相应的图像 |
|
||||||
| crazy_functions\Conversation_To_File.py | 将每次对话记录写入Markdown格式的文件中 |
|
| crazy_functions\对话历史存档.py | 将每次对话记录写入Markdown格式的文件中 |
|
||||||
| crazy_functions\总结word文档.py | 对输入的word文档进行摘要生成 |
|
| crazy_functions\总结word文档.py | 对输入的word文档进行摘要生成 |
|
||||||
| crazy_functions\总结音视频.py | 对输入的音视频文件进行摘要生成 |
|
| crazy_functions\总结音视频.py | 对输入的音视频文件进行摘要生成 |
|
||||||
| crazy_functions\Markdown_Translate.py | 将指定目录下的Markdown文件进行中英文翻译 |
|
| crazy_functions\批量Markdown翻译.py | 将指定目录下的Markdown文件进行中英文翻译 |
|
||||||
| crazy_functions\批量总结PDF文档.py | 对PDF文件进行切割和摘要生成 |
|
| crazy_functions\批量总结PDF文档.py | 对PDF文件进行切割和摘要生成 |
|
||||||
| crazy_functions\批量总结PDF文档pdfminer.py | 对PDF文件进行文本内容的提取和摘要生成 |
|
| crazy_functions\批量总结PDF文档pdfminer.py | 对PDF文件进行文本内容的提取和摘要生成 |
|
||||||
| crazy_functions\PDF_Translate.py | 将指定目录下的PDF文件进行中英文翻译 |
|
| crazy_functions\批量翻译PDF文档_多线程.py | 将指定目录下的PDF文件进行中英文翻译 |
|
||||||
| crazy_functions\理解PDF文档内容.py | 对PDF文件进行摘要生成和问题解答 |
|
| crazy_functions\理解PDF文档内容.py | 对PDF文件进行摘要生成和问题解答 |
|
||||||
| crazy_functions\生成函数注释.py | 自动生成Python函数的注释 |
|
| crazy_functions\生成函数注释.py | 自动生成Python函数的注释 |
|
||||||
| crazy_functions\联网的ChatGPT.py | 使用网络爬虫和ChatGPT模型进行聊天回答 |
|
| crazy_functions\联网的ChatGPT.py | 使用网络爬虫和ChatGPT模型进行聊天回答 |
|
||||||
@@ -155,9 +155,9 @@ toolbox.py是一个工具类库,其中主要包含了一些函数装饰器和
|
|||||||
|
|
||||||
该程序文件提供了一个用于生成图像的函数`图片生成`。函数实现的过程中,会调用`gen_image`函数来生成图像,并返回图像生成的网址和本地文件地址。函数有多个参数,包括`prompt`(激励文本)、`llm_kwargs`(GPT模型的参数)、`plugin_kwargs`(插件模型的参数)等。函数核心代码使用了`requests`库向OpenAI API请求图像,并做了简单的处理和保存。函数还更新了交互界面,清空聊天历史并显示正在生成图像的消息和最终的图像网址和预览。
|
该程序文件提供了一个用于生成图像的函数`图片生成`。函数实现的过程中,会调用`gen_image`函数来生成图像,并返回图像生成的网址和本地文件地址。函数有多个参数,包括`prompt`(激励文本)、`llm_kwargs`(GPT模型的参数)、`plugin_kwargs`(插件模型的参数)等。函数核心代码使用了`requests`库向OpenAI API请求图像,并做了简单的处理和保存。函数还更新了交互界面,清空聊天历史并显示正在生成图像的消息和最终的图像网址和预览。
|
||||||
|
|
||||||
## [18/48] 请对下面的程序文件做一个概述: crazy_functions\Conversation_To_File.py
|
## [18/48] 请对下面的程序文件做一个概述: crazy_functions\对话历史存档.py
|
||||||
|
|
||||||
这个文件是名为crazy_functions\Conversation_To_File.py的Python程序文件,包含了4个函数:
|
这个文件是名为crazy_functions\对话历史存档.py的Python程序文件,包含了4个函数:
|
||||||
|
|
||||||
1. write_chat_to_file(chatbot, history=None, file_name=None):用来将对话记录以Markdown格式写入文件中,并且生成文件名,如果没指定文件名则用当前时间。写入完成后将文件路径打印出来。
|
1. write_chat_to_file(chatbot, history=None, file_name=None):用来将对话记录以Markdown格式写入文件中,并且生成文件名,如果没指定文件名则用当前时间。写入完成后将文件路径打印出来。
|
||||||
|
|
||||||
@@ -165,7 +165,7 @@ toolbox.py是一个工具类库,其中主要包含了一些函数装饰器和
|
|||||||
|
|
||||||
3. read_file_to_chat(chatbot, history, file_name):从传入的文件中读取内容,解析出对话历史记录并更新聊天显示框。
|
3. read_file_to_chat(chatbot, history, file_name):从传入的文件中读取内容,解析出对话历史记录并更新聊天显示框。
|
||||||
|
|
||||||
4. Conversation_To_File(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request):一个主要函数,用于保存当前对话记录并提醒用户。如果用户希望加载历史记录,则调用read_file_to_chat()来更新聊天显示框。如果用户希望删除历史记录,调用删除所有本地对话历史记录()函数完成删除操作。
|
4. 对话历史存档(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request):一个主要函数,用于保存当前对话记录并提醒用户。如果用户希望加载历史记录,则调用read_file_to_chat()来更新聊天显示框。如果用户希望删除历史记录,调用删除所有本地对话历史记录()函数完成删除操作。
|
||||||
|
|
||||||
## [19/48] 请对下面的程序文件做一个概述: crazy_functions\总结word文档.py
|
## [19/48] 请对下面的程序文件做一个概述: crazy_functions\总结word文档.py
|
||||||
|
|
||||||
@@ -175,9 +175,9 @@ toolbox.py是一个工具类库,其中主要包含了一些函数装饰器和
|
|||||||
|
|
||||||
该程序文件包括两个函数:split_audio_file()和AnalyAudio(),并且导入了一些必要的库并定义了一些工具函数。split_audio_file用于将音频文件分割成多个时长相等的片段,返回一个包含所有切割音频片段文件路径的列表,而AnalyAudio用来分析音频文件,通过调用whisper模型进行音频转文字并使用GPT模型对音频内容进行概述,最终将所有总结结果写入结果文件中。
|
该程序文件包括两个函数:split_audio_file()和AnalyAudio(),并且导入了一些必要的库并定义了一些工具函数。split_audio_file用于将音频文件分割成多个时长相等的片段,返回一个包含所有切割音频片段文件路径的列表,而AnalyAudio用来分析音频文件,通过调用whisper模型进行音频转文字并使用GPT模型对音频内容进行概述,最终将所有总结结果写入结果文件中。
|
||||||
|
|
||||||
## [21/48] 请对下面的程序文件做一个概述: crazy_functions\Markdown_Translate.py
|
## [21/48] 请对下面的程序文件做一个概述: crazy_functions\批量Markdown翻译.py
|
||||||
|
|
||||||
该程序文件名为`Markdown_Translate.py`,包含了以下功能:读取Markdown文件,将长文本分离开来,将Markdown文件进行翻译(英译中和中译英),整理结果并退出。程序使用了多线程以提高效率。程序使用了`tiktoken`依赖库,可能需要额外安装。文件中还有一些其他的函数和类,但与文件名所描述的功能无关。
|
该程序文件名为`批量Markdown翻译.py`,包含了以下功能:读取Markdown文件,将长文本分离开来,将Markdown文件进行翻译(英译中和中译英),整理结果并退出。程序使用了多线程以提高效率。程序使用了`tiktoken`依赖库,可能需要额外安装。文件中还有一些其他的函数和类,但与文件名所描述的功能无关。
|
||||||
|
|
||||||
## [22/48] 请对下面的程序文件做一个概述: crazy_functions\批量总结PDF文档.py
|
## [22/48] 请对下面的程序文件做一个概述: crazy_functions\批量总结PDF文档.py
|
||||||
|
|
||||||
@@ -187,9 +187,9 @@ toolbox.py是一个工具类库,其中主要包含了一些函数装饰器和
|
|||||||
|
|
||||||
该程序文件是一个用于批量总结PDF文档的函数插件,使用了pdfminer插件和BeautifulSoup库来提取PDF文档的文本内容,对每个PDF文件分别进行处理并生成中英文摘要。同时,该程序文件还包括一些辅助工具函数和处理异常的装饰器。
|
该程序文件是一个用于批量总结PDF文档的函数插件,使用了pdfminer插件和BeautifulSoup库来提取PDF文档的文本内容,对每个PDF文件分别进行处理并生成中英文摘要。同时,该程序文件还包括一些辅助工具函数和处理异常的装饰器。
|
||||||
|
|
||||||
## [24/48] 请对下面的程序文件做一个概述: crazy_functions\PDF_Translate.py
|
## [24/48] 请对下面的程序文件做一个概述: crazy_functions\批量翻译PDF文档_多线程.py
|
||||||
|
|
||||||
这个程序文件是一个Python脚本,文件名为“PDF_Translate.py”。它主要使用了“toolbox”、“request_gpt_model_in_new_thread_with_ui_alive”、“request_gpt_model_multi_threads_with_very_awesome_ui_and_high_efficiency”、“colorful”等Python库和自定义的模块“crazy_utils”的一些函数。程序实现了一个批量翻译PDF文档的功能,可以自动解析PDF文件中的基础信息,递归地切割PDF文件,翻译和处理PDF论文中的所有内容,并生成相应的翻译结果文件(包括md文件和html文件)。功能比较复杂,其中需要调用多个函数和依赖库,涉及到多线程操作和UI更新。文件中有详细的注释和变量命名,代码比较清晰易读。
|
这个程序文件是一个Python脚本,文件名为“批量翻译PDF文档_多线程.py”。它主要使用了“toolbox”、“request_gpt_model_in_new_thread_with_ui_alive”、“request_gpt_model_multi_threads_with_very_awesome_ui_and_high_efficiency”、“colorful”等Python库和自定义的模块“crazy_utils”的一些函数。程序实现了一个批量翻译PDF文档的功能,可以自动解析PDF文件中的基础信息,递归地切割PDF文件,翻译和处理PDF论文中的所有内容,并生成相应的翻译结果文件(包括md文件和html文件)。功能比较复杂,其中需要调用多个函数和依赖库,涉及到多线程操作和UI更新。文件中有详细的注释和变量命名,代码比较清晰易读。
|
||||||
|
|
||||||
## [25/48] 请对下面的程序文件做一个概述: crazy_functions\理解PDF文档内容.py
|
## [25/48] 请对下面的程序文件做一个概述: crazy_functions\理解PDF文档内容.py
|
||||||
|
|
||||||
@@ -331,19 +331,19 @@ check_proxy.py, colorful.py, config.py, config_private.py, core_functional.py, c
|
|||||||
这些程序源文件提供了基础的文本和语言处理功能、工具函数和高级插件,使 Chatbot 能够处理各种复杂的学术文本问题,包括润色、翻译、搜索、下载、解析等。
|
这些程序源文件提供了基础的文本和语言处理功能、工具函数和高级插件,使 Chatbot 能够处理各种复杂的学术文本问题,包括润色、翻译、搜索、下载、解析等。
|
||||||
|
|
||||||
## 用一张Markdown表格简要描述以下文件的功能:
|
## 用一张Markdown表格简要描述以下文件的功能:
|
||||||
crazy_functions\代码重写为全英文_多线程.py, crazy_functions\图片生成.py, crazy_functions\Conversation_To_File.py, crazy_functions\总结word文档.py, crazy_functions\总结音视频.py, crazy_functions\Markdown_Translate.py, crazy_functions\批量总结PDF文档.py, crazy_functions\批量总结PDF文档pdfminer.py, crazy_functions\PDF_Translate.py, crazy_functions\理解PDF文档内容.py, crazy_functions\生成函数注释.py, crazy_functions\联网的ChatGPT.py, crazy_functions\解析JupyterNotebook.py, crazy_functions\解析项目源代码.py, crazy_functions\询问多个大语言模型.py, crazy_functions\读文章写摘要.py。根据以上分析,用一句话概括程序的整体功能。
|
crazy_functions\代码重写为全英文_多线程.py, crazy_functions\图片生成.py, crazy_functions\对话历史存档.py, crazy_functions\总结word文档.py, crazy_functions\总结音视频.py, crazy_functions\批量Markdown翻译.py, crazy_functions\批量总结PDF文档.py, crazy_functions\批量总结PDF文档pdfminer.py, crazy_functions\批量翻译PDF文档_多线程.py, crazy_functions\理解PDF文档内容.py, crazy_functions\生成函数注释.py, crazy_functions\联网的ChatGPT.py, crazy_functions\解析JupyterNotebook.py, crazy_functions\解析项目源代码.py, crazy_functions\询问多个大语言模型.py, crazy_functions\读文章写摘要.py。根据以上分析,用一句话概括程序的整体功能。
|
||||||
|
|
||||||
| 文件名 | 功能简述 |
|
| 文件名 | 功能简述 |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| 代码重写为全英文_多线程.py | 将Python源代码文件中的中文内容转化为英文 |
|
| 代码重写为全英文_多线程.py | 将Python源代码文件中的中文内容转化为英文 |
|
||||||
| 图片生成.py | 根据激励文本使用GPT模型生成相应的图像 |
|
| 图片生成.py | 根据激励文本使用GPT模型生成相应的图像 |
|
||||||
| Conversation_To_File.py | 将每次对话记录写入Markdown格式的文件中 |
|
| 对话历史存档.py | 将每次对话记录写入Markdown格式的文件中 |
|
||||||
| 总结word文档.py | 对输入的word文档进行摘要生成 |
|
| 总结word文档.py | 对输入的word文档进行摘要生成 |
|
||||||
| 总结音视频.py | 对输入的音视频文件进行摘要生成 |
|
| 总结音视频.py | 对输入的音视频文件进行摘要生成 |
|
||||||
| Markdown_Translate.py | 将指定目录下的Markdown文件进行中英文翻译 |
|
| 批量Markdown翻译.py | 将指定目录下的Markdown文件进行中英文翻译 |
|
||||||
| 批量总结PDF文档.py | 对PDF文件进行切割和摘要生成 |
|
| 批量总结PDF文档.py | 对PDF文件进行切割和摘要生成 |
|
||||||
| 批量总结PDF文档pdfminer.py | 对PDF文件进行文本内容的提取和摘要生成 |
|
| 批量总结PDF文档pdfminer.py | 对PDF文件进行文本内容的提取和摘要生成 |
|
||||||
| PDF_Translate.py | 将指定目录下的PDF文件进行中英文翻译 |
|
| 批量翻译PDF文档_多线程.py | 将指定目录下的PDF文件进行中英文翻译 |
|
||||||
| 理解PDF文档内容.py | 对PDF文件进行摘要生成和问题解答 |
|
| 理解PDF文档内容.py | 对PDF文件进行摘要生成和问题解答 |
|
||||||
| 生成函数注释.py | 自动生成Python函数的注释 |
|
| 生成函数注释.py | 自动生成Python函数的注释 |
|
||||||
| 联网的ChatGPT.py | 使用网络爬虫和ChatGPT模型进行聊天回答 |
|
| 联网的ChatGPT.py | 使用网络爬虫和ChatGPT模型进行聊天回答 |
|
||||||
|
|||||||
文件差异内容过多而无法显示
加载差异
@@ -36,15 +36,15 @@
|
|||||||
"总结word文档": "SummarizeWordDocument",
|
"总结word文档": "SummarizeWordDocument",
|
||||||
"解析ipynb文件": "ParseIpynbFile",
|
"解析ipynb文件": "ParseIpynbFile",
|
||||||
"解析JupyterNotebook": "ParseJupyterNotebook",
|
"解析JupyterNotebook": "ParseJupyterNotebook",
|
||||||
"Conversation_To_File": "ConversationHistoryArchive",
|
"对话历史存档": "ConversationHistoryArchive",
|
||||||
"载入Conversation_To_File": "LoadConversationHistoryArchive",
|
"载入对话历史存档": "LoadConversationHistoryArchive",
|
||||||
"删除所有本地对话历史记录": "DeleteAllLocalChatHistory",
|
"删除所有本地对话历史记录": "DeleteAllLocalChatHistory",
|
||||||
"Markdown英译中": "MarkdownTranslateFromEngToChi",
|
"Markdown英译中": "MarkdownTranslateFromEngToChi",
|
||||||
"Markdown_Translate": "BatchTranslateMarkdown",
|
"批量Markdown翻译": "BatchTranslateMarkdown",
|
||||||
"批量总结PDF文档": "BatchSummarizePDFDocuments",
|
"批量总结PDF文档": "BatchSummarizePDFDocuments",
|
||||||
"批量总结PDF文档pdfminer": "BatchSummarizePDFDocumentsUsingPDFMiner",
|
"批量总结PDF文档pdfminer": "BatchSummarizePDFDocumentsUsingPDFMiner",
|
||||||
"批量翻译PDF文档": "BatchTranslatePDFDocuments",
|
"批量翻译PDF文档": "BatchTranslatePDFDocuments",
|
||||||
"PDF_Translate": "BatchTranslatePDFDocumentsUsingMultiThreading",
|
"批量翻译PDF文档_多线程": "BatchTranslatePDFDocumentsUsingMultiThreading",
|
||||||
"谷歌检索小助手": "GoogleSearchAssistant",
|
"谷歌检索小助手": "GoogleSearchAssistant",
|
||||||
"理解PDF文档内容标准文件输入": "StandardFileInputForUnderstandingPDFDocumentContent",
|
"理解PDF文档内容标准文件输入": "StandardFileInputForUnderstandingPDFDocumentContent",
|
||||||
"理解PDF文档内容": "UnderstandingPDFDocumentContent",
|
"理解PDF文档内容": "UnderstandingPDFDocumentContent",
|
||||||
@@ -1492,7 +1492,7 @@
|
|||||||
"交互功能模板函数": "InteractiveFunctionTemplateFunction",
|
"交互功能模板函数": "InteractiveFunctionTemplateFunction",
|
||||||
"交互功能函数模板": "InteractiveFunctionFunctionTemplate",
|
"交互功能函数模板": "InteractiveFunctionFunctionTemplate",
|
||||||
"Latex英文纠错加PDF对比": "LatexEnglishErrorCorrectionWithPDFComparison",
|
"Latex英文纠错加PDF对比": "LatexEnglishErrorCorrectionWithPDFComparison",
|
||||||
"Latex_Function": "LatexOutputPDFResult",
|
"Latex输出PDF": "LatexOutputPDFResult",
|
||||||
"Latex翻译中文并重新编译PDF": "TranslateChineseAndRecompilePDF",
|
"Latex翻译中文并重新编译PDF": "TranslateChineseAndRecompilePDF",
|
||||||
"语音助手": "VoiceAssistant",
|
"语音助手": "VoiceAssistant",
|
||||||
"微调数据集生成": "FineTuneDatasetGeneration",
|
"微调数据集生成": "FineTuneDatasetGeneration",
|
||||||
|
|||||||
@@ -6,14 +6,17 @@
|
|||||||
"Latex英文纠错加PDF对比": "CorrectEnglishInLatexWithPDFComparison",
|
"Latex英文纠错加PDF对比": "CorrectEnglishInLatexWithPDFComparison",
|
||||||
"下载arxiv论文并翻译摘要": "DownloadArxivPaperAndTranslateAbstract",
|
"下载arxiv论文并翻译摘要": "DownloadArxivPaperAndTranslateAbstract",
|
||||||
"Markdown翻译指定语言": "TranslateMarkdownToSpecifiedLanguage",
|
"Markdown翻译指定语言": "TranslateMarkdownToSpecifiedLanguage",
|
||||||
|
"批量翻译PDF文档_多线程": "BatchTranslatePDFDocuments_MultiThreaded",
|
||||||
"下载arxiv论文翻译摘要": "DownloadArxivPaperTranslateAbstract",
|
"下载arxiv论文翻译摘要": "DownloadArxivPaperTranslateAbstract",
|
||||||
"解析一个Python项目": "ParsePythonProject",
|
"解析一个Python项目": "ParsePythonProject",
|
||||||
"解析一个Golang项目": "ParseGolangProject",
|
"解析一个Golang项目": "ParseGolangProject",
|
||||||
"代码重写为全英文_多线程": "RewriteCodeToEnglish_MultiThreaded",
|
"代码重写为全英文_多线程": "RewriteCodeToEnglish_MultiThreaded",
|
||||||
"解析一个CSharp项目": "ParsingCSharpProject",
|
"解析一个CSharp项目": "ParsingCSharpProject",
|
||||||
"删除所有本地对话历史记录": "DeleteAllLocalConversationHistoryRecords",
|
"删除所有本地对话历史记录": "DeleteAllLocalConversationHistoryRecords",
|
||||||
|
"批量Markdown翻译": "BatchTranslateMarkdown",
|
||||||
"连接bing搜索回答问题": "ConnectBingSearchAnswerQuestion",
|
"连接bing搜索回答问题": "ConnectBingSearchAnswerQuestion",
|
||||||
"Langchain知识库": "LangchainKnowledgeBase",
|
"Langchain知识库": "LangchainKnowledgeBase",
|
||||||
|
"Latex输出PDF": "OutputPDFFromLatex",
|
||||||
"把字符太少的块清除为回车": "ClearBlocksWithTooFewCharactersToNewline",
|
"把字符太少的块清除为回车": "ClearBlocksWithTooFewCharactersToNewline",
|
||||||
"Latex精细分解与转化": "DecomposeAndConvertLatex",
|
"Latex精细分解与转化": "DecomposeAndConvertLatex",
|
||||||
"解析一个C项目的头文件": "ParseCProjectHeaderFiles",
|
"解析一个C项目的头文件": "ParseCProjectHeaderFiles",
|
||||||
@@ -43,7 +46,7 @@
|
|||||||
"高阶功能模板函数": "HighOrderFunctionTemplateFunctions",
|
"高阶功能模板函数": "HighOrderFunctionTemplateFunctions",
|
||||||
"高级功能函数模板": "AdvancedFunctionTemplate",
|
"高级功能函数模板": "AdvancedFunctionTemplate",
|
||||||
"总结word文档": "SummarizingWordDocuments",
|
"总结word文档": "SummarizingWordDocuments",
|
||||||
"载入Conversation_To_File": "LoadConversationHistoryArchive",
|
"载入对话历史存档": "LoadConversationHistoryArchive",
|
||||||
"Latex中译英": "LatexChineseToEnglish",
|
"Latex中译英": "LatexChineseToEnglish",
|
||||||
"Latex英译中": "LatexEnglishToChinese",
|
"Latex英译中": "LatexEnglishToChinese",
|
||||||
"连接网络回答问题": "ConnectToNetworkToAnswerQuestions",
|
"连接网络回答问题": "ConnectToNetworkToAnswerQuestions",
|
||||||
@@ -67,6 +70,7 @@
|
|||||||
"读文章写摘要": "ReadArticleWriteSummary",
|
"读文章写摘要": "ReadArticleWriteSummary",
|
||||||
"生成函数注释": "GenerateFunctionComments",
|
"生成函数注释": "GenerateFunctionComments",
|
||||||
"解析项目本身": "ParseProjectItself",
|
"解析项目本身": "ParseProjectItself",
|
||||||
|
"对话历史存档": "ConversationHistoryArchive",
|
||||||
"专业词汇声明": "ProfessionalTerminologyDeclaration",
|
"专业词汇声明": "ProfessionalTerminologyDeclaration",
|
||||||
"解析docx": "ParseDocx",
|
"解析docx": "ParseDocx",
|
||||||
"解析源代码新": "ParsingSourceCodeNew",
|
"解析源代码新": "ParsingSourceCodeNew",
|
||||||
@@ -100,11 +104,5 @@
|
|||||||
"随机小游戏": "RandomMiniGame",
|
"随机小游戏": "RandomMiniGame",
|
||||||
"互动小游戏": "InteractiveMiniGame",
|
"互动小游戏": "InteractiveMiniGame",
|
||||||
"解析历史输入": "ParseHistoricalInput",
|
"解析历史输入": "ParseHistoricalInput",
|
||||||
"高阶功能模板函数示意图": "HighOrderFunctionTemplateDiagram",
|
"高阶功能模板函数示意图": "HighOrderFunctionTemplateDiagram"
|
||||||
"载入对话历史存档": "LoadChatHistoryArchive",
|
|
||||||
"对话历史存档": "ChatHistoryArchive",
|
|
||||||
"解析PDF_DOC2X_转Latex": "ParsePDF_DOC2X_toLatex",
|
|
||||||
"解析PDF_基于DOC2X": "ParsePDF_basedDOC2X",
|
|
||||||
"解析PDF_简单拆解": "ParsePDF_simpleDecomposition",
|
|
||||||
"解析PDF_DOC2X_单文件": "ParsePDF_DOC2X_singleFile"
|
|
||||||
}
|
}
|
||||||
@@ -35,15 +35,15 @@
|
|||||||
"总结word文档": "SummarizeWordDocument",
|
"总结word文档": "SummarizeWordDocument",
|
||||||
"解析ipynb文件": "ParseIpynbFile",
|
"解析ipynb文件": "ParseIpynbFile",
|
||||||
"解析JupyterNotebook": "ParseJupyterNotebook",
|
"解析JupyterNotebook": "ParseJupyterNotebook",
|
||||||
"Conversation_To_File": "ConversationHistoryArchive",
|
"对话历史存档": "ConversationHistoryArchive",
|
||||||
"载入Conversation_To_File": "LoadConversationHistoryArchive",
|
"载入对话历史存档": "LoadConversationHistoryArchive",
|
||||||
"删除所有本地对话历史记录": "DeleteAllLocalConversationHistoryRecords",
|
"删除所有本地对话历史记录": "DeleteAllLocalConversationHistoryRecords",
|
||||||
"Markdown英译中": "MarkdownEnglishToChinese",
|
"Markdown英译中": "MarkdownEnglishToChinese",
|
||||||
"Markdown_Translate": "BatchMarkdownTranslation",
|
"批量Markdown翻译": "BatchMarkdownTranslation",
|
||||||
"批量总结PDF文档": "BatchSummarizePDFDocuments",
|
"批量总结PDF文档": "BatchSummarizePDFDocuments",
|
||||||
"批量总结PDF文档pdfminer": "BatchSummarizePDFDocumentsPdfminer",
|
"批量总结PDF文档pdfminer": "BatchSummarizePDFDocumentsPdfminer",
|
||||||
"批量翻译PDF文档": "BatchTranslatePDFDocuments",
|
"批量翻译PDF文档": "BatchTranslatePDFDocuments",
|
||||||
"PDF_Translate": "BatchTranslatePdfDocumentsMultithreaded",
|
"批量翻译PDF文档_多线程": "BatchTranslatePdfDocumentsMultithreaded",
|
||||||
"谷歌检索小助手": "GoogleSearchAssistant",
|
"谷歌检索小助手": "GoogleSearchAssistant",
|
||||||
"理解PDF文档内容标准文件输入": "StandardFileInputForUnderstandingPdfDocumentContent",
|
"理解PDF文档内容标准文件输入": "StandardFileInputForUnderstandingPdfDocumentContent",
|
||||||
"理解PDF文档内容": "UnderstandingPdfDocumentContent",
|
"理解PDF文档内容": "UnderstandingPdfDocumentContent",
|
||||||
@@ -1468,7 +1468,7 @@
|
|||||||
"交互功能模板函数": "InteractiveFunctionTemplateFunctions",
|
"交互功能模板函数": "InteractiveFunctionTemplateFunctions",
|
||||||
"交互功能函数模板": "InteractiveFunctionFunctionTemplates",
|
"交互功能函数模板": "InteractiveFunctionFunctionTemplates",
|
||||||
"Latex英文纠错加PDF对比": "LatexEnglishCorrectionWithPDFComparison",
|
"Latex英文纠错加PDF对比": "LatexEnglishCorrectionWithPDFComparison",
|
||||||
"Latex_Function": "OutputPDFFromLatex",
|
"Latex输出PDF": "OutputPDFFromLatex",
|
||||||
"Latex翻译中文并重新编译PDF": "TranslateLatexToChineseAndRecompilePDF",
|
"Latex翻译中文并重新编译PDF": "TranslateLatexToChineseAndRecompilePDF",
|
||||||
"语音助手": "VoiceAssistant",
|
"语音助手": "VoiceAssistant",
|
||||||
"微调数据集生成": "FineTuneDatasetGeneration",
|
"微调数据集生成": "FineTuneDatasetGeneration",
|
||||||
|
|||||||
@@ -1,58 +0,0 @@
|
|||||||
# 使用TTS文字转语音
|
|
||||||
|
|
||||||
|
|
||||||
## 1. 使用EDGE-TTS(简单)
|
|
||||||
|
|
||||||
将本项目配置项修改如下即可
|
|
||||||
|
|
||||||
```
|
|
||||||
TTS_TYPE = "EDGE_TTS"
|
|
||||||
EDGE_TTS_VOICE = "zh-CN-XiaoxiaoNeural"
|
|
||||||
```
|
|
||||||
|
|
||||||
## 2. 使用SoVITS(需要有显卡)
|
|
||||||
|
|
||||||
使用以下docker-compose.yml文件,先启动SoVITS服务API
|
|
||||||
|
|
||||||
1. 创建以下文件夹结构
|
|
||||||
```shell
|
|
||||||
.
|
|
||||||
├── docker-compose.yml
|
|
||||||
└── reference
|
|
||||||
├── clone_target_txt.txt
|
|
||||||
└── clone_target_wave.mp3
|
|
||||||
```
|
|
||||||
2. 其中`docker-compose.yml`为
|
|
||||||
```yaml
|
|
||||||
version: '3.8'
|
|
||||||
services:
|
|
||||||
gpt-sovits:
|
|
||||||
image: fuqingxu/sovits_gptac_trim:latest
|
|
||||||
container_name: sovits_gptac_container
|
|
||||||
working_dir: /workspace/gpt_sovits_demo
|
|
||||||
environment:
|
|
||||||
- is_half=False
|
|
||||||
- is_share=False
|
|
||||||
volumes:
|
|
||||||
- ./reference:/reference
|
|
||||||
ports:
|
|
||||||
- "19880:9880" # 19880 为 sovits api 的暴露端口,记住它
|
|
||||||
shm_size: 16G
|
|
||||||
deploy:
|
|
||||||
resources:
|
|
||||||
reservations:
|
|
||||||
devices:
|
|
||||||
- driver: nvidia
|
|
||||||
count: "all"
|
|
||||||
capabilities: [gpu]
|
|
||||||
command: bash -c "python3 api.py"
|
|
||||||
```
|
|
||||||
3. 其中`clone_target_wave.mp3`为需要克隆的角色音频,`clone_target_txt.txt`为该音频对应的文字文本( https://wiki.biligame.com/ys/%E8%A7%92%E8%89%B2%E8%AF%AD%E9%9F%B3 )
|
|
||||||
4. 运行`docker-compose up`
|
|
||||||
5. 将本项目配置项修改如下即可
|
|
||||||
(19880 为 sovits api 的暴露端口,与docker-compose.yml中的端口对应)
|
|
||||||
```
|
|
||||||
TTS_TYPE = "LOCAL_SOVITS_API"
|
|
||||||
GPT_SOVITS_URL = "http://127.0.0.1:19880"
|
|
||||||
```
|
|
||||||
6. 启动本项目
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
# 使用VLLM
|
|
||||||
|
|
||||||
|
|
||||||
## 1. 首先启动 VLLM,自行选择模型
|
|
||||||
|
|
||||||
```
|
|
||||||
python -m vllm.entrypoints.openai.api_server --model /home/hmp/llm/cache/Qwen1___5-32B-Chat --tensor-parallel-size 2 --dtype=half
|
|
||||||
```
|
|
||||||
|
|
||||||
这里使用了存储在 `/home/hmp/llm/cache/Qwen1___5-32B-Chat` 的本地模型,可以根据自己的需求更改。
|
|
||||||
|
|
||||||
## 2. 测试 VLLM
|
|
||||||
|
|
||||||
```
|
|
||||||
curl http://localhost:8000/v1/chat/completions \
|
|
||||||
-H "Content-Type: application/json" \
|
|
||||||
-d '{
|
|
||||||
"model": "/home/hmp/llm/cache/Qwen1___5-32B-Chat",
|
|
||||||
"messages": [
|
|
||||||
{"role": "system", "content": "You are a helpful assistant."},
|
|
||||||
{"role": "user", "content": "怎么实现一个去中心化的控制器?"}
|
|
||||||
]
|
|
||||||
}'
|
|
||||||
```
|
|
||||||
|
|
||||||
## 3. 配置本项目
|
|
||||||
|
|
||||||
```
|
|
||||||
API_KEY = "sk-123456789xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx123456789"
|
|
||||||
LLM_MODEL = "vllm-/home/hmp/llm/cache/Qwen1___5-32B-Chat(max_token=4096)"
|
|
||||||
API_URL_REDIRECT = {"https://api.openai.com/v1/chat/completions": "http://localhost:8000/v1/chat/completions"}
|
|
||||||
```
|
|
||||||
|
|
||||||
```
|
|
||||||
"vllm-/home/hmp/llm/cache/Qwen1___5-32B-Chat(max_token=4096)"
|
|
||||||
其中
|
|
||||||
"vllm-" 是前缀(必要)
|
|
||||||
"/home/hmp/llm/cache/Qwen1___5-32B-Chat" 是模型名(必要)
|
|
||||||
"(max_token=6666)" 是配置(非必要)
|
|
||||||
```
|
|
||||||
|
|
||||||
## 4. 启动!
|
|
||||||
|
|
||||||
```
|
|
||||||
python main.py
|
|
||||||
```
|
|
||||||
364
main.py
364
main.py
@@ -1,364 +0,0 @@
|
|||||||
import os, json; os.environ['no_proxy'] = '*' # 避免代理网络产生意外污染
|
|
||||||
|
|
||||||
help_menu_description = \
|
|
||||||
"""Github源代码开源和更新[地址🚀](https://github.com/binary-husky/gpt_academic),
|
|
||||||
感谢热情的[开发者们❤️](https://github.com/binary-husky/gpt_academic/graphs/contributors).
|
|
||||||
</br></br>常见问题请查阅[项目Wiki](https://github.com/binary-husky/gpt_academic/wiki),
|
|
||||||
如遇到Bug请前往[Bug反馈](https://github.com/binary-husky/gpt_academic/issues).
|
|
||||||
</br></br>普通对话使用说明: 1. 输入问题; 2. 点击提交
|
|
||||||
</br></br>基础功能区使用说明: 1. 输入文本; 2. 点击任意基础功能区按钮
|
|
||||||
</br></br>函数插件区使用说明: 1. 输入路径/问题, 或者上传文件; 2. 点击任意函数插件区按钮
|
|
||||||
</br></br>虚空终端使用说明: 点击虚空终端, 然后根据提示输入指令, 再次点击虚空终端
|
|
||||||
</br></br>如何保存对话: 点击保存当前的对话按钮
|
|
||||||
</br></br>如何语音对话: 请阅读Wiki
|
|
||||||
</br></br>如何临时更换API_KEY: 在输入区输入临时API_KEY后提交(网页刷新后失效)"""
|
|
||||||
|
|
||||||
def enable_log(PATH_LOGGING):
|
|
||||||
import logging
|
|
||||||
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 encode_plugin_info(k, plugin)->str:
|
|
||||||
import copy
|
|
||||||
from themes.theme import to_cookie_str
|
|
||||||
plugin_ = copy.copy(plugin)
|
|
||||||
plugin_.pop("Function", None)
|
|
||||||
plugin_.pop("Class", None)
|
|
||||||
plugin_.pop("Button", None)
|
|
||||||
plugin_["Info"] = plugin.get("Info", k)
|
|
||||||
if plugin.get("AdvancedArgs", False):
|
|
||||||
plugin_["Label"] = f"插件[{k}]的高级参数说明:" + plugin.get("ArgsReminder", f"没有提供高级参数功能说明")
|
|
||||||
else:
|
|
||||||
plugin_["Label"] = f"插件[{k}]不需要高级参数。"
|
|
||||||
return to_cookie_str(plugin_)
|
|
||||||
|
|
||||||
def main():
|
|
||||||
import gradio as gr
|
|
||||||
if gr.__version__ not in ['3.32.9', '3.32.10', '3.32.11']:
|
|
||||||
raise ModuleNotFoundError("使用项目内置Gradio获取最优体验! 请运行 `pip install -r requirements.txt` 指令安装内置Gradio及其他依赖, 详情信息见requirements.txt.")
|
|
||||||
from request_llms.bridge_all import predict
|
|
||||||
from toolbox import format_io, find_free_port, on_file_uploaded, on_report_generated, get_conf, ArgsGeneralWrapper, DummyWith
|
|
||||||
|
|
||||||
# 读取配置
|
|
||||||
proxies, WEB_PORT, LLM_MODEL, CONCURRENT_COUNT, AUTHENTICATION = get_conf('proxies', 'WEB_PORT', 'LLM_MODEL', 'CONCURRENT_COUNT', 'AUTHENTICATION')
|
|
||||||
CHATBOT_HEIGHT, LAYOUT, AVAIL_LLM_MODELS, AUTO_CLEAR_TXT = get_conf('CHATBOT_HEIGHT', 'LAYOUT', 'AVAIL_LLM_MODELS', 'AUTO_CLEAR_TXT')
|
|
||||||
ENABLE_AUDIO, AUTO_CLEAR_TXT, PATH_LOGGING, AVAIL_THEMES, THEME, ADD_WAIFU = get_conf('ENABLE_AUDIO', 'AUTO_CLEAR_TXT', 'PATH_LOGGING', 'AVAIL_THEMES', 'THEME', 'ADD_WAIFU')
|
|
||||||
NUM_CUSTOM_BASIC_BTN, SSL_KEYFILE, SSL_CERTFILE = get_conf('NUM_CUSTOM_BASIC_BTN', 'SSL_KEYFILE', 'SSL_CERTFILE')
|
|
||||||
DARK_MODE, INIT_SYS_PROMPT, ADD_WAIFU, TTS_TYPE = get_conf('DARK_MODE', 'INIT_SYS_PROMPT', 'ADD_WAIFU', 'TTS_TYPE')
|
|
||||||
if LLM_MODEL not in AVAIL_LLM_MODELS: AVAIL_LLM_MODELS += [LLM_MODEL]
|
|
||||||
|
|
||||||
# 如果WEB_PORT是-1, 则随机选取WEB端口
|
|
||||||
PORT = find_free_port() if WEB_PORT <= 0 else WEB_PORT
|
|
||||||
from check_proxy import get_current_version
|
|
||||||
from themes.theme import adjust_theme, advanced_css, theme_declaration, js_code_clear, js_code_reset, js_code_show_or_hide, js_code_show_or_hide_group2
|
|
||||||
from themes.theme import js_code_for_toggle_darkmode, js_code_for_persistent_cookie_init
|
|
||||||
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}"
|
|
||||||
|
|
||||||
# 对话、日志记录
|
|
||||||
enable_log(PATH_LOGGING)
|
|
||||||
|
|
||||||
# 一些普通功能模块
|
|
||||||
from core_functional import get_core_functions
|
|
||||||
functional = get_core_functions()
|
|
||||||
|
|
||||||
# 高级函数插件
|
|
||||||
from crazy_functional import get_crazy_functions
|
|
||||||
DEFAULT_FN_GROUPS = get_conf('DEFAULT_FN_GROUPS')
|
|
||||||
plugins = get_crazy_functions()
|
|
||||||
all_plugin_groups = list(set([g for _, plugin in plugins.items() for g in plugin['Group'].split('|')]))
|
|
||||||
match_group = lambda tags, groups: any([g in groups for g in tags.split('|')])
|
|
||||||
|
|
||||||
# 处理markdown文本格式的转变
|
|
||||||
gr.Chatbot.postprocess = format_io
|
|
||||||
|
|
||||||
# 做一些外观色彩上的调整
|
|
||||||
set_theme = adjust_theme()
|
|
||||||
|
|
||||||
# 代理与自动更新
|
|
||||||
from check_proxy import check_proxy, auto_update, warm_up_modules
|
|
||||||
proxy_info = check_proxy(proxies)
|
|
||||||
|
|
||||||
# 切换布局
|
|
||||||
gr_L1 = lambda: gr.Row().style()
|
|
||||||
gr_L2 = lambda scale, elem_id: gr.Column(scale=scale, elem_id=elem_id, min_width=400)
|
|
||||||
if LAYOUT == "TOP-DOWN":
|
|
||||||
gr_L1 = lambda: DummyWith()
|
|
||||||
gr_L2 = lambda scale, elem_id: gr.Row()
|
|
||||||
CHATBOT_HEIGHT /= 2
|
|
||||||
|
|
||||||
cancel_handles = []
|
|
||||||
customize_btns = {}
|
|
||||||
predefined_btns = {}
|
|
||||||
from shared_utils.cookie_manager import make_cookie_cache, make_history_cache
|
|
||||||
with gr.Blocks(title="GPT 学术优化", theme=set_theme, analytics_enabled=False, css=advanced_css) as app_block:
|
|
||||||
gr.HTML(title_html)
|
|
||||||
secret_css = gr.Textbox(visible=False, elem_id="secret_css")
|
|
||||||
register_advanced_plugin_init_arr = ""
|
|
||||||
|
|
||||||
cookies, web_cookie_cache = make_cookie_cache() # 定义 后端state(cookies)、前端(web_cookie_cache)两兄弟
|
|
||||||
with gr_L1():
|
|
||||||
with gr_L2(scale=2, elem_id="gpt-chat"):
|
|
||||||
chatbot = gr.Chatbot(label=f"当前模型:{LLM_MODEL}", elem_id="gpt-chatbot")
|
|
||||||
if LAYOUT == "TOP-DOWN": chatbot.style(height=CHATBOT_HEIGHT)
|
|
||||||
history, history_cache, history_cache_update = make_history_cache() # 定义 后端state(history)、前端(history_cache)、后端setter(history_cache_update)三兄弟
|
|
||||||
with gr_L2(scale=1, elem_id="gpt-panel"):
|
|
||||||
with gr.Accordion("输入区", open=True, elem_id="input-panel") as area_input_primary:
|
|
||||||
with gr.Row():
|
|
||||||
txt = gr.Textbox(show_label=False, placeholder="Input question here.", elem_id='user_input_main').style(container=False)
|
|
||||||
with gr.Row(elem_id="gpt-submit-row"):
|
|
||||||
multiplex_submit_btn = gr.Button("提交", elem_id="elem_submit_visible", variant="primary")
|
|
||||||
multiplex_sel = gr.Dropdown(
|
|
||||||
choices=[
|
|
||||||
"常规对话",
|
|
||||||
"多模型对话",
|
|
||||||
# "智能上下文",
|
|
||||||
# "智能召回 RAG",
|
|
||||||
], value="常规对话",
|
|
||||||
interactive=True, label='', show_label=False,
|
|
||||||
elem_classes='normal_mut_select', elem_id="gpt-submit-dropdown").style(container=False)
|
|
||||||
submit_btn = gr.Button("提交", elem_id="elem_submit", variant="primary", visible=False)
|
|
||||||
with gr.Row():
|
|
||||||
resetBtn = gr.Button("重置", elem_id="elem_reset", variant="secondary"); resetBtn.style(size="sm")
|
|
||||||
stopBtn = gr.Button("停止", elem_id="elem_stop", variant="secondary"); stopBtn.style(size="sm")
|
|
||||||
clearBtn = gr.Button("清除", elem_id="elem_clear", variant="secondary", visible=False); clearBtn.style(size="sm")
|
|
||||||
if ENABLE_AUDIO:
|
|
||||||
with gr.Row():
|
|
||||||
audio_mic = gr.Audio(source="microphone", type="numpy", elem_id="elem_audio", streaming=True, show_label=False).style(container=False)
|
|
||||||
with gr.Row():
|
|
||||||
status = gr.Markdown(f"Tip: 按Enter提交, 按Shift+Enter换行。支持将文件直接粘贴到输入区。", elem_id="state-panel")
|
|
||||||
|
|
||||||
with gr.Accordion("基础功能区", open=True, elem_id="basic-panel") as area_basic_fn:
|
|
||||||
with gr.Row():
|
|
||||||
for k in range(NUM_CUSTOM_BASIC_BTN):
|
|
||||||
customize_btn = gr.Button("自定义按钮" + str(k+1), visible=False, variant="secondary", info_str=f'基础功能区: 自定义按钮')
|
|
||||||
customize_btn.style(size="sm")
|
|
||||||
customize_btns.update({"自定义按钮" + str(k+1): customize_btn})
|
|
||||||
for k in functional:
|
|
||||||
if ("Visible" in functional[k]) and (not functional[k]["Visible"]): continue
|
|
||||||
variant = functional[k]["Color"] if "Color" in functional[k] else "secondary"
|
|
||||||
functional[k]["Button"] = gr.Button(k, variant=variant, info_str=f'基础功能区: {k}')
|
|
||||||
functional[k]["Button"].style(size="sm")
|
|
||||||
predefined_btns.update({k: functional[k]["Button"]})
|
|
||||||
with gr.Accordion("函数插件区", open=True, elem_id="plugin-panel") as area_crazy_fn:
|
|
||||||
with gr.Row():
|
|
||||||
gr.Markdown("<small>插件可读取“输入区”文本/路径作为参数(上传文件自动修正路径)</small>")
|
|
||||||
with gr.Row(elem_id="input-plugin-group"):
|
|
||||||
plugin_group_sel = gr.Dropdown(choices=all_plugin_groups, label='', show_label=False, value=DEFAULT_FN_GROUPS,
|
|
||||||
multiselect=True, interactive=True, elem_classes='normal_mut_select').style(container=False)
|
|
||||||
with gr.Row():
|
|
||||||
for index, (k, plugin) in enumerate(plugins.items()):
|
|
||||||
if not plugin.get("AsButton", True): continue
|
|
||||||
visible = True if match_group(plugin['Group'], DEFAULT_FN_GROUPS) else False
|
|
||||||
variant = plugins[k]["Color"] if "Color" in plugin else "secondary"
|
|
||||||
info = plugins[k].get("Info", k)
|
|
||||||
btn_elem_id = f"plugin_btn_{index}"
|
|
||||||
plugin['Button'] = plugins[k]['Button'] = gr.Button(k, variant=variant,
|
|
||||||
visible=visible, info_str=f'函数插件区: {info}', elem_id=btn_elem_id).style(size="sm")
|
|
||||||
plugin['ButtonElemId'] = btn_elem_id
|
|
||||||
with gr.Row():
|
|
||||||
with gr.Accordion("更多函数插件", open=True):
|
|
||||||
dropdown_fn_list = []
|
|
||||||
for k, plugin in plugins.items():
|
|
||||||
if not match_group(plugin['Group'], DEFAULT_FN_GROUPS): continue
|
|
||||||
if not plugin.get("AsButton", True): dropdown_fn_list.append(k) # 排除已经是按钮的插件
|
|
||||||
elif plugin.get('AdvancedArgs', False): dropdown_fn_list.append(k) # 对于需要高级参数的插件,亦在下拉菜单中显示
|
|
||||||
with gr.Row():
|
|
||||||
dropdown = gr.Dropdown(dropdown_fn_list, value=r"点击这里输入「关键词」搜索插件", label="", show_label=False).style(container=False)
|
|
||||||
with gr.Row():
|
|
||||||
plugin_advanced_arg = gr.Textbox(show_label=True, label="高级参数输入区", visible=False, elem_id="advance_arg_input_legacy",
|
|
||||||
placeholder="这里是特殊函数插件的高级参数输入区").style(container=False)
|
|
||||||
with gr.Row():
|
|
||||||
switchy_bt = gr.Button(r"请先从插件列表中选择", variant="secondary", elem_id="elem_switchy_bt").style(size="sm")
|
|
||||||
with gr.Row():
|
|
||||||
with gr.Accordion("点击展开“文件下载区”。", open=False) as area_file_up:
|
|
||||||
file_upload = gr.Files(label="任何文件, 推荐上传压缩文件(zip, tar)", file_count="multiple", elem_id="elem_upload")
|
|
||||||
|
|
||||||
# 左上角工具栏定义
|
|
||||||
from themes.gui_toolbar import define_gui_toolbar
|
|
||||||
checkboxes, checkboxes_2, max_length_sl, theme_dropdown, system_prompt, file_upload_2, md_dropdown, top_p, temperature = \
|
|
||||||
define_gui_toolbar(AVAIL_LLM_MODELS, LLM_MODEL, INIT_SYS_PROMPT, THEME, AVAIL_THEMES, ADD_WAIFU, help_menu_description, js_code_for_toggle_darkmode)
|
|
||||||
|
|
||||||
# 浮动菜单定义
|
|
||||||
from themes.gui_floating_menu import define_gui_floating_menu
|
|
||||||
area_input_secondary, txt2, area_customize, _, resetBtn2, clearBtn2, stopBtn2 = \
|
|
||||||
define_gui_floating_menu(customize_btns, functional, predefined_btns, cookies, web_cookie_cache)
|
|
||||||
|
|
||||||
# 插件二级菜单的实现
|
|
||||||
from themes.gui_advanced_plugin_class import define_gui_advanced_plugin_class
|
|
||||||
new_plugin_callback, route_switchy_bt_with_arg, usr_confirmed_arg = \
|
|
||||||
define_gui_advanced_plugin_class(plugins)
|
|
||||||
|
|
||||||
# 功能区显示开关与功能区的互动
|
|
||||||
def fn_area_visibility(a):
|
|
||||||
ret = {}
|
|
||||||
ret.update({area_input_primary: gr.update(visible=("浮动输入区" not in a))})
|
|
||||||
ret.update({area_input_secondary: gr.update(visible=("浮动输入区" in a))})
|
|
||||||
ret.update({plugin_advanced_arg: gr.update(visible=("插件参数区" in a))})
|
|
||||||
if "浮动输入区" in a: ret.update({txt: gr.update(value="")})
|
|
||||||
return ret
|
|
||||||
checkboxes.select(fn_area_visibility, [checkboxes], [area_basic_fn, area_crazy_fn, area_input_primary, area_input_secondary, txt, txt2, plugin_advanced_arg] )
|
|
||||||
checkboxes.select(None, [checkboxes], None, _js=js_code_show_or_hide)
|
|
||||||
|
|
||||||
# 功能区显示开关与功能区的互动
|
|
||||||
def fn_area_visibility_2(a):
|
|
||||||
ret = {}
|
|
||||||
ret.update({area_customize: gr.update(visible=("自定义菜单" in a))})
|
|
||||||
return ret
|
|
||||||
checkboxes_2.select(fn_area_visibility_2, [checkboxes_2], [area_customize] )
|
|
||||||
checkboxes_2.select(None, [checkboxes_2], None, _js=js_code_show_or_hide_group2)
|
|
||||||
|
|
||||||
# 整理反复出现的控件句柄组合
|
|
||||||
input_combo = [cookies, max_length_sl, md_dropdown, txt, txt2, top_p, temperature, chatbot, history, system_prompt, plugin_advanced_arg]
|
|
||||||
input_combo_order = ["cookies", "max_length_sl", "md_dropdown", "txt", "txt2", "top_p", "temperature", "chatbot", "history", "system_prompt", "plugin_advanced_arg"]
|
|
||||||
output_combo = [cookies, chatbot, history, status]
|
|
||||||
predict_args = dict(fn=ArgsGeneralWrapper(predict), inputs=[*input_combo, gr.State(True)], outputs=output_combo)
|
|
||||||
|
|
||||||
# 提交按钮、重置按钮
|
|
||||||
multiplex_submit_btn.click(
|
|
||||||
None, [multiplex_sel], None, _js="""(multiplex_sel)=>multiplex_function_begin(multiplex_sel)""")
|
|
||||||
txt.submit(
|
|
||||||
None, [multiplex_sel], None, _js="""(multiplex_sel)=>multiplex_function_begin(multiplex_sel)""")
|
|
||||||
multiplex_sel.select(
|
|
||||||
None, [multiplex_sel], None, _js=f"""(multiplex_sel)=>run_multiplex_shift(multiplex_sel)""")
|
|
||||||
cancel_handles.append(submit_btn.click(**predict_args))
|
|
||||||
resetBtn.click(None, None, [chatbot, history, status], _js=js_code_reset) # 先在前端快速清除chatbot&status
|
|
||||||
resetBtn2.click(None, None, [chatbot, history, status], _js=js_code_reset) # 先在前端快速清除chatbot&status
|
|
||||||
reset_server_side_args = (lambda history: ([], [], "已重置", json.dumps(history)), [history], [chatbot, history, status, history_cache])
|
|
||||||
resetBtn.click(*reset_server_side_args) # 再在后端清除history,把history转存history_cache备用
|
|
||||||
resetBtn2.click(*reset_server_side_args) # 再在后端清除history,把history转存history_cache备用
|
|
||||||
clearBtn.click(None, None, [txt, txt2], _js=js_code_clear)
|
|
||||||
clearBtn2.click(None, None, [txt, txt2], _js=js_code_clear)
|
|
||||||
if AUTO_CLEAR_TXT:
|
|
||||||
submit_btn.click(None, None, [txt, txt2], _js=js_code_clear)
|
|
||||||
# 基础功能区的回调函数注册
|
|
||||||
for k in functional:
|
|
||||||
if ("Visible" in functional[k]) and (not functional[k]["Visible"]): continue
|
|
||||||
click_handle = functional[k]["Button"].click(fn=ArgsGeneralWrapper(predict), inputs=[*input_combo, gr.State(True), gr.State(k)], outputs=output_combo)
|
|
||||||
cancel_handles.append(click_handle)
|
|
||||||
for btn in customize_btns.values():
|
|
||||||
click_handle = btn.click(fn=ArgsGeneralWrapper(predict), inputs=[*input_combo, gr.State(True), gr.State(btn.value)], outputs=output_combo)
|
|
||||||
cancel_handles.append(click_handle)
|
|
||||||
# 文件上传区,接收文件后与chatbot的互动
|
|
||||||
file_upload.upload(on_file_uploaded, [file_upload, chatbot, txt, txt2, checkboxes, cookies], [chatbot, txt, txt2, cookies]).then(None, None, None, _js=r"()=>{toast_push('上传完毕 ...'); cancel_loading_status();}")
|
|
||||||
file_upload_2.upload(on_file_uploaded, [file_upload_2, chatbot, txt, txt2, checkboxes, cookies], [chatbot, txt, txt2, cookies]).then(None, None, None, _js=r"()=>{toast_push('上传完毕 ...'); cancel_loading_status();}")
|
|
||||||
# 函数插件-固定按钮区
|
|
||||||
for k in plugins:
|
|
||||||
register_advanced_plugin_init_arr += f"""register_plugin_init("{k}","{encode_plugin_info(k, plugins[k])}");"""
|
|
||||||
if plugins[k].get("Class", None):
|
|
||||||
plugins[k]["JsMenu"] = plugins[k]["Class"]().get_js_code_for_generating_menu(k)
|
|
||||||
register_advanced_plugin_init_arr += """register_advanced_plugin_init_code("{k}","{gui_js}");""".format(k=k, gui_js=plugins[k]["JsMenu"])
|
|
||||||
if not plugins[k].get("AsButton", True): continue
|
|
||||||
if plugins[k].get("Class", None) is None:
|
|
||||||
assert plugins[k].get("Function", None) is not None
|
|
||||||
click_handle = plugins[k]["Button"].click(None, inputs=[], outputs=None, _js=f"""()=>run_classic_plugin_via_id("{plugins[k]["ButtonElemId"]}")""")
|
|
||||||
else:
|
|
||||||
click_handle = plugins[k]["Button"].click(None, inputs=[], outputs=None, _js=f"""()=>run_advanced_plugin_launch_code("{k}")""")
|
|
||||||
|
|
||||||
# 函数插件-下拉菜单与随变按钮的互动(新版-更流畅)
|
|
||||||
dropdown.select(None, [dropdown], None, _js=f"""(dropdown)=>run_dropdown_shift(dropdown)""")
|
|
||||||
|
|
||||||
# 模型切换时的回调
|
|
||||||
def on_md_dropdown_changed(k):
|
|
||||||
return {chatbot: gr.update(label="当前模型:"+k)}
|
|
||||||
md_dropdown.select(on_md_dropdown_changed, [md_dropdown], [chatbot])
|
|
||||||
|
|
||||||
# 主题修改
|
|
||||||
def on_theme_dropdown_changed(theme, secret_css):
|
|
||||||
adjust_theme, css_part1, _, adjust_dynamic_theme = load_dynamic_theme(theme)
|
|
||||||
if adjust_dynamic_theme:
|
|
||||||
css_part2 = adjust_dynamic_theme._get_theme_css()
|
|
||||||
else:
|
|
||||||
css_part2 = adjust_theme()._get_theme_css()
|
|
||||||
return css_part2 + css_part1
|
|
||||||
theme_handle = theme_dropdown.select(on_theme_dropdown_changed, [theme_dropdown, secret_css], [secret_css]) # , _js="""change_theme_prepare""")
|
|
||||||
theme_handle.then(None, [theme_dropdown, secret_css], None, _js="""change_theme""")
|
|
||||||
|
|
||||||
switchy_bt.click(None, [switchy_bt], None, _js="(switchy_bt)=>on_flex_button_click(switchy_bt)")
|
|
||||||
# 随变按钮的回调函数注册
|
|
||||||
def route(request: gr.Request, k, *args, **kwargs):
|
|
||||||
if k not in [r"点击这里搜索插件列表", r"请先从插件列表中选择"]:
|
|
||||||
if plugins[k].get("Class", None) is None:
|
|
||||||
assert plugins[k].get("Function", None) is not None
|
|
||||||
yield from ArgsGeneralWrapper(plugins[k]["Function"])(request, *args, **kwargs)
|
|
||||||
# 旧插件的高级参数区确认按钮(隐藏)
|
|
||||||
old_plugin_callback = gr.Button(r"未选定任何插件", variant="secondary", visible=False, elem_id="old_callback_btn_for_plugin_exe")
|
|
||||||
click_handle_ng = old_plugin_callback.click(route, [switchy_bt, *input_combo], output_combo)
|
|
||||||
click_handle_ng.then(on_report_generated, [cookies, file_upload, chatbot], [cookies, file_upload, chatbot]).then(None, [switchy_bt], None, _js=r"(fn)=>on_plugin_exe_complete(fn)")
|
|
||||||
cancel_handles.append(click_handle_ng)
|
|
||||||
# 新一代插件的高级参数区确认按钮(隐藏)
|
|
||||||
click_handle_ng = new_plugin_callback.click(route_switchy_bt_with_arg,
|
|
||||||
[
|
|
||||||
gr.State(["new_plugin_callback", "usr_confirmed_arg"] + input_combo_order), # 第一个参数: 指定了后续参数的名称
|
|
||||||
new_plugin_callback, usr_confirmed_arg, *input_combo # 后续参数: 真正的参数
|
|
||||||
], output_combo)
|
|
||||||
click_handle_ng.then(on_report_generated, [cookies, file_upload, chatbot], [cookies, file_upload, chatbot]).then(None, [switchy_bt], None, _js=r"(fn)=>on_plugin_exe_complete(fn)")
|
|
||||||
cancel_handles.append(click_handle_ng)
|
|
||||||
# 终止按钮的回调函数注册
|
|
||||||
stopBtn.click(fn=None, inputs=None, outputs=None, cancels=cancel_handles)
|
|
||||||
stopBtn2.click(fn=None, inputs=None, outputs=None, cancels=cancel_handles)
|
|
||||||
plugins_as_btn = {name:plugin for name, plugin in plugins.items() if plugin.get('Button', None)}
|
|
||||||
def on_group_change(group_list):
|
|
||||||
btn_list = []
|
|
||||||
fns_list = []
|
|
||||||
if not group_list: # 处理特殊情况:没有选择任何插件组
|
|
||||||
return [*[plugin['Button'].update(visible=False) for _, plugin in plugins_as_btn.items()], gr.Dropdown.update(choices=[])]
|
|
||||||
for k, plugin in plugins.items():
|
|
||||||
if plugin.get("AsButton", True):
|
|
||||||
btn_list.append(plugin['Button'].update(visible=match_group(plugin['Group'], group_list))) # 刷新按钮
|
|
||||||
if plugin.get('AdvancedArgs', False): dropdown_fn_list.append(k) # 对于需要高级参数的插件,亦在下拉菜单中显示
|
|
||||||
elif match_group(plugin['Group'], group_list): fns_list.append(k) # 刷新下拉列表
|
|
||||||
return [*btn_list, gr.Dropdown.update(choices=fns_list)]
|
|
||||||
plugin_group_sel.select(fn=on_group_change, inputs=[plugin_group_sel], outputs=[*[plugin['Button'] for name, plugin in plugins_as_btn.items()], dropdown])
|
|
||||||
|
|
||||||
# 是否启动语音输入功能
|
|
||||||
if ENABLE_AUDIO:
|
|
||||||
from crazy_functions.live_audio.audio_io import RealtimeAudioDistribution
|
|
||||||
rad = RealtimeAudioDistribution()
|
|
||||||
def deal_audio(audio, cookies):
|
|
||||||
rad.feed(cookies['uuid'].hex, audio)
|
|
||||||
audio_mic.stream(deal_audio, inputs=[audio_mic, cookies])
|
|
||||||
|
|
||||||
# 生成当前浏览器窗口的uuid(刷新失效)
|
|
||||||
app_block.load(assign_user_uuid, inputs=[cookies], outputs=[cookies])
|
|
||||||
|
|
||||||
# 初始化(前端)
|
|
||||||
from shared_utils.cookie_manager import load_web_cookie_cache__fn_builder
|
|
||||||
load_web_cookie_cache = load_web_cookie_cache__fn_builder(customize_btns, cookies, predefined_btns)
|
|
||||||
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}","{TTS_TYPE}")""") # 配置暗色主题或亮色主题
|
|
||||||
app_block.load(None, inputs=[], outputs=None, _js="""()=>{REP}""".replace("REP", register_advanced_plugin_init_arr))
|
|
||||||
|
|
||||||
# Gradio的inbrowser触发不太稳定,回滚代码到原始的浏览器打开函数
|
|
||||||
def run_delayed_tasks():
|
|
||||||
import threading, webbrowser, time
|
|
||||||
print(f"如果浏览器没有自动打开,请复制并转到以下URL:")
|
|
||||||
if DARK_MODE: print(f"\t「暗色主题已启用(支持动态切换主题)」: http://localhost:{PORT}")
|
|
||||||
else: print(f"\t「亮色主题已启用(支持动态切换主题)」: http://localhost:{PORT}")
|
|
||||||
|
|
||||||
def auto_updates(): time.sleep(0); auto_update()
|
|
||||||
def open_browser(): time.sleep(2); webbrowser.open_new_tab(f"http://localhost:{PORT}")
|
|
||||||
def warm_up_mods(): time.sleep(6); warm_up_modules()
|
|
||||||
|
|
||||||
threading.Thread(target=auto_updates, name="self-upgrade", daemon=True).start() # 查看自动更新
|
|
||||||
threading.Thread(target=warm_up_mods, name="warm-up", daemon=True).start() # 预热tiktoken模块
|
|
||||||
if get_conf('AUTO_OPEN_BROWSER'):
|
|
||||||
threading.Thread(target=open_browser, name="open-browser", daemon=True).start() # 打开浏览器页面
|
|
||||||
|
|
||||||
# 运行一些异步任务:自动更新、打开浏览器页面、预热tiktoken模块
|
|
||||||
run_delayed_tasks()
|
|
||||||
|
|
||||||
# 最后,正式开始服务
|
|
||||||
from shared_utils.fastapi_server import start_app
|
|
||||||
start_app(app_block, CONCURRENT_COUNT, AUTHENTICATION, PORT, SSL_KEYFILE, SSL_CERTFILE)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
||||||
@@ -8,10 +8,10 @@
|
|||||||
具备多线程调用能力的函数:在函数插件中被调用,灵活而简洁
|
具备多线程调用能力的函数:在函数插件中被调用,灵活而简洁
|
||||||
2. predict_no_ui_long_connection(...)
|
2. predict_no_ui_long_connection(...)
|
||||||
"""
|
"""
|
||||||
import tiktoken, copy, re
|
import tiktoken, copy
|
||||||
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, read_one_api_model_name
|
from toolbox import get_conf, trimmed_format_exc, apply_gpt_academic_string_mask
|
||||||
|
|
||||||
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,14 +34,6 @@ 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_taichu import predict_no_ui_long_connection as taichu_noui
|
|
||||||
from .bridge_taichu import predict as taichu_ui
|
|
||||||
|
|
||||||
from .bridge_cohere import predict as cohere_ui
|
|
||||||
from .bridge_cohere import predict_no_ui_long_connection as cohere_noui
|
|
||||||
|
|
||||||
from .oai_std_model_template import get_predict_function
|
|
||||||
|
|
||||||
colors = ['#FF00FF', '#00FFFF', '#FF0000', '#990099', '#009999', '#990044']
|
colors = ['#FF00FF', '#00FFFF', '#FF0000', '#990099', '#009999', '#990044']
|
||||||
|
|
||||||
class LazyloadTiktoken(object):
|
class LazyloadTiktoken(object):
|
||||||
@@ -69,13 +61,6 @@ 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"
|
|
||||||
cohere_endpoint = "https://api.cohere.ai/v1/chat"
|
|
||||||
ollama_endpoint = "http://localhost:11434/api/chat"
|
|
||||||
yimodel_endpoint = "https://api.lingyiwanwu.com/v1/chat/completions"
|
|
||||||
deepseekapi_endpoint = "https://api.deepseek.com/v1/chat/completions"
|
|
||||||
|
|
||||||
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'
|
||||||
# 兼容旧版的配置
|
# 兼容旧版的配置
|
||||||
@@ -90,12 +75,7 @@ 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 cohere_endpoint in API_URL_REDIRECT: cohere_endpoint = API_URL_REDIRECT[cohere_endpoint]
|
|
||||||
if ollama_endpoint in API_URL_REDIRECT: ollama_endpoint = API_URL_REDIRECT[ollama_endpoint]
|
|
||||||
if yimodel_endpoint in API_URL_REDIRECT: yimodel_endpoint = API_URL_REDIRECT[yimodel_endpoint]
|
|
||||||
if deepseekapi_endpoint in API_URL_REDIRECT: deepseekapi_endpoint = API_URL_REDIRECT[deepseekapi_endpoint]
|
|
||||||
|
|
||||||
# 获取tokenizer
|
# 获取tokenizer
|
||||||
tokenizer_gpt35 = LazyloadTiktoken("gpt-3.5-turbo")
|
tokenizer_gpt35 = LazyloadTiktoken("gpt-3.5-turbo")
|
||||||
@@ -114,15 +94,6 @@ 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": 16385,
|
|
||||||
"tokenizer": tokenizer_gpt35,
|
|
||||||
"token_cnt": get_token_num_gpt35,
|
|
||||||
},
|
|
||||||
|
|
||||||
"taichu": {
|
|
||||||
"fn_with_ui": taichu_ui,
|
|
||||||
"fn_without_ui": taichu_noui,
|
|
||||||
"endpoint": openai_endpoint,
|
|
||||||
"max_token": 4096,
|
"max_token": 4096,
|
||||||
"tokenizer": tokenizer_gpt35,
|
"tokenizer": tokenizer_gpt35,
|
||||||
"token_cnt": get_token_num_gpt35,
|
"token_cnt": get_token_num_gpt35,
|
||||||
@@ -164,15 +135,6 @@ model_info = {
|
|||||||
"token_cnt": get_token_num_gpt35,
|
"token_cnt": get_token_num_gpt35,
|
||||||
},
|
},
|
||||||
|
|
||||||
"gpt-3.5-turbo-0125": { #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-4": {
|
"gpt-4": {
|
||||||
"fn_with_ui": chatgpt_ui,
|
"fn_with_ui": chatgpt_ui,
|
||||||
"fn_without_ui": chatgpt_noui,
|
"fn_without_ui": chatgpt_noui,
|
||||||
@@ -191,36 +153,6 @@ model_info = {
|
|||||||
"token_cnt": get_token_num_gpt4,
|
"token_cnt": get_token_num_gpt4,
|
||||||
},
|
},
|
||||||
|
|
||||||
"gpt-4o": {
|
|
||||||
"fn_with_ui": chatgpt_ui,
|
|
||||||
"fn_without_ui": chatgpt_noui,
|
|
||||||
"endpoint": openai_endpoint,
|
|
||||||
"has_multimodal_capacity": True,
|
|
||||||
"max_token": 128000,
|
|
||||||
"tokenizer": tokenizer_gpt4,
|
|
||||||
"token_cnt": get_token_num_gpt4,
|
|
||||||
},
|
|
||||||
|
|
||||||
"gpt-4o-mini": {
|
|
||||||
"fn_with_ui": chatgpt_ui,
|
|
||||||
"fn_without_ui": chatgpt_noui,
|
|
||||||
"endpoint": openai_endpoint,
|
|
||||||
"has_multimodal_capacity": True,
|
|
||||||
"max_token": 128000,
|
|
||||||
"tokenizer": tokenizer_gpt4,
|
|
||||||
"token_cnt": get_token_num_gpt4,
|
|
||||||
},
|
|
||||||
|
|
||||||
"gpt-4o-2024-05-13": {
|
|
||||||
"fn_with_ui": chatgpt_ui,
|
|
||||||
"fn_without_ui": chatgpt_noui,
|
|
||||||
"has_multimodal_capacity": True,
|
|
||||||
"endpoint": openai_endpoint,
|
|
||||||
"max_token": 128000,
|
|
||||||
"tokenizer": tokenizer_gpt4,
|
|
||||||
"token_cnt": get_token_num_gpt4,
|
|
||||||
},
|
|
||||||
|
|
||||||
"gpt-4-turbo-preview": {
|
"gpt-4-turbo-preview": {
|
||||||
"fn_with_ui": chatgpt_ui,
|
"fn_with_ui": chatgpt_ui,
|
||||||
"fn_without_ui": chatgpt_noui,
|
"fn_without_ui": chatgpt_noui,
|
||||||
@@ -248,26 +180,6 @@ model_info = {
|
|||||||
"token_cnt": get_token_num_gpt4,
|
"token_cnt": get_token_num_gpt4,
|
||||||
},
|
},
|
||||||
|
|
||||||
"gpt-4-turbo": {
|
|
||||||
"fn_with_ui": chatgpt_ui,
|
|
||||||
"fn_without_ui": chatgpt_noui,
|
|
||||||
"has_multimodal_capacity": True,
|
|
||||||
"endpoint": openai_endpoint,
|
|
||||||
"max_token": 128000,
|
|
||||||
"tokenizer": tokenizer_gpt4,
|
|
||||||
"token_cnt": get_token_num_gpt4,
|
|
||||||
},
|
|
||||||
|
|
||||||
"gpt-4-turbo-2024-04-09": {
|
|
||||||
"fn_with_ui": chatgpt_ui,
|
|
||||||
"fn_without_ui": chatgpt_noui,
|
|
||||||
"has_multimodal_capacity": True,
|
|
||||||
"endpoint": openai_endpoint,
|
|
||||||
"max_token": 128000,
|
|
||||||
"tokenizer": tokenizer_gpt4,
|
|
||||||
"token_cnt": get_token_num_gpt4,
|
|
||||||
},
|
|
||||||
|
|
||||||
"gpt-3.5-random": {
|
"gpt-3.5-random": {
|
||||||
"fn_with_ui": chatgpt_ui,
|
"fn_with_ui": chatgpt_ui,
|
||||||
"fn_without_ui": chatgpt_noui,
|
"fn_without_ui": chatgpt_noui,
|
||||||
@@ -315,46 +227,6 @@ model_info = {
|
|||||||
"tokenizer": tokenizer_gpt35,
|
"tokenizer": tokenizer_gpt35,
|
||||||
"token_cnt": get_token_num_gpt35,
|
"token_cnt": get_token_num_gpt35,
|
||||||
},
|
},
|
||||||
"glm-4-0520": {
|
|
||||||
"fn_with_ui": zhipu_ui,
|
|
||||||
"fn_without_ui": zhipu_noui,
|
|
||||||
"endpoint": None,
|
|
||||||
"max_token": 10124 * 8,
|
|
||||||
"tokenizer": tokenizer_gpt35,
|
|
||||||
"token_cnt": get_token_num_gpt35,
|
|
||||||
},
|
|
||||||
"glm-4-air": {
|
|
||||||
"fn_with_ui": zhipu_ui,
|
|
||||||
"fn_without_ui": zhipu_noui,
|
|
||||||
"endpoint": None,
|
|
||||||
"max_token": 10124 * 8,
|
|
||||||
"tokenizer": tokenizer_gpt35,
|
|
||||||
"token_cnt": get_token_num_gpt35,
|
|
||||||
},
|
|
||||||
"glm-4-airx": {
|
|
||||||
"fn_with_ui": zhipu_ui,
|
|
||||||
"fn_without_ui": zhipu_noui,
|
|
||||||
"endpoint": None,
|
|
||||||
"max_token": 10124 * 8,
|
|
||||||
"tokenizer": tokenizer_gpt35,
|
|
||||||
"token_cnt": get_token_num_gpt35,
|
|
||||||
},
|
|
||||||
"glm-4-flash": {
|
|
||||||
"fn_with_ui": zhipu_ui,
|
|
||||||
"fn_without_ui": zhipu_noui,
|
|
||||||
"endpoint": None,
|
|
||||||
"max_token": 10124 * 8,
|
|
||||||
"tokenizer": tokenizer_gpt35,
|
|
||||||
"token_cnt": get_token_num_gpt35,
|
|
||||||
},
|
|
||||||
"glm-4v": {
|
|
||||||
"fn_with_ui": zhipu_ui,
|
|
||||||
"fn_without_ui": zhipu_noui,
|
|
||||||
"endpoint": None,
|
|
||||||
"max_token": 1000,
|
|
||||||
"tokenizer": tokenizer_gpt35,
|
|
||||||
"token_cnt": get_token_num_gpt35,
|
|
||||||
},
|
|
||||||
"glm-3-turbo": {
|
"glm-3-turbo": {
|
||||||
"fn_with_ui": zhipu_ui,
|
"fn_with_ui": zhipu_ui,
|
||||||
"fn_without_ui": zhipu_noui,
|
"fn_without_ui": zhipu_noui,
|
||||||
@@ -410,7 +282,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": gemini_endpoint,
|
"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,
|
||||||
@@ -418,56 +290,13 @@ 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()):
|
||||||
@@ -483,77 +312,25 @@ for model in AVAIL_LLM_MODELS:
|
|||||||
model_info.update({model: mi})
|
model_info.update({model: mi})
|
||||||
|
|
||||||
# -=-=-=-=-=-=- 以下部分是新加入的模型,可能附带额外依赖 -=-=-=-=-=-=-
|
# -=-=-=-=-=-=- 以下部分是新加入的模型,可能附带额外依赖 -=-=-=-=-=-=-
|
||||||
# claude家族
|
if "claude-1-100k" in AVAIL_LLM_MODELS or "claude-2" in AVAIL_LLM_MODELS:
|
||||||
claude_models = ["claude-instant-1.2","claude-2.0","claude-2.1","claude-3-haiku-20240307","claude-3-sonnet-20240229","claude-3-opus-20240229","claude-3-5-sonnet-20240620"]
|
|
||||||
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-instant-1.2": {
|
"claude-1-100k": {
|
||||||
"fn_with_ui": claude_ui,
|
"fn_with_ui": claude_ui,
|
||||||
"fn_without_ui": claude_noui,
|
"fn_without_ui": claude_noui,
|
||||||
"endpoint": claude_endpoint,
|
"endpoint": None,
|
||||||
"max_token": 100000,
|
"max_token": 8196,
|
||||||
"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.0": {
|
"claude-2": {
|
||||||
"fn_with_ui": claude_ui,
|
"fn_with_ui": claude_ui,
|
||||||
"fn_without_ui": claude_noui,
|
"fn_without_ui": claude_noui,
|
||||||
"endpoint": claude_endpoint,
|
"endpoint": None,
|
||||||
"max_token": 100000,
|
"max_token": 8196,
|
||||||
"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,
|
|
||||||
"token_cnt": get_token_num_gpt35,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
model_info.update({
|
|
||||||
"claude-3-5-sonnet-20240620": {
|
|
||||||
"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,
|
||||||
},
|
},
|
||||||
@@ -623,6 +400,22 @@ 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
|
||||||
@@ -655,7 +448,6 @@ 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
|
||||||
@@ -688,7 +480,6 @@ 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
|
||||||
@@ -697,7 +488,6 @@ 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,
|
||||||
@@ -706,7 +496,6 @@ 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
|
||||||
@@ -715,7 +504,6 @@ 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,
|
||||||
@@ -724,7 +512,6 @@ 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,
|
||||||
@@ -733,7 +520,6 @@ 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,
|
||||||
@@ -742,88 +528,7 @@ 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: # 讯飞星火认知大模型
|
||||||
yi_models = ["yi-34b-chat-0205","yi-34b-chat-200k","yi-large","yi-medium","yi-spark","yi-large-turbo","yi-large-preview"]
|
|
||||||
if any(item in yi_models for item in AVAIL_LLM_MODELS):
|
|
||||||
try:
|
|
||||||
yimodel_4k_noui, yimodel_4k_ui = get_predict_function(
|
|
||||||
api_key_conf_name="YIMODEL_API_KEY", max_output_token=600, disable_proxy=False
|
|
||||||
)
|
|
||||||
yimodel_16k_noui, yimodel_16k_ui = get_predict_function(
|
|
||||||
api_key_conf_name="YIMODEL_API_KEY", max_output_token=4000, disable_proxy=False
|
|
||||||
)
|
|
||||||
yimodel_200k_noui, yimodel_200k_ui = get_predict_function(
|
|
||||||
api_key_conf_name="YIMODEL_API_KEY", max_output_token=4096, disable_proxy=False
|
|
||||||
)
|
|
||||||
model_info.update({
|
|
||||||
"yi-34b-chat-0205": {
|
|
||||||
"fn_with_ui": yimodel_4k_ui,
|
|
||||||
"fn_without_ui": yimodel_4k_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_200k_ui,
|
|
||||||
"fn_without_ui": yimodel_200k_noui,
|
|
||||||
"can_multi_thread": False, # 目前来说,默认情况下并发量极低,因此禁用
|
|
||||||
"endpoint": yimodel_endpoint,
|
|
||||||
"max_token": 200000,
|
|
||||||
"tokenizer": tokenizer_gpt35,
|
|
||||||
"token_cnt": get_token_num_gpt35,
|
|
||||||
},
|
|
||||||
"yi-large": {
|
|
||||||
"fn_with_ui": yimodel_16k_ui,
|
|
||||||
"fn_without_ui": yimodel_16k_noui,
|
|
||||||
"can_multi_thread": False, # 目前来说,默认情况下并发量极低,因此禁用
|
|
||||||
"endpoint": yimodel_endpoint,
|
|
||||||
"max_token": 16000,
|
|
||||||
"tokenizer": tokenizer_gpt35,
|
|
||||||
"token_cnt": get_token_num_gpt35,
|
|
||||||
},
|
|
||||||
"yi-medium": {
|
|
||||||
"fn_with_ui": yimodel_16k_ui,
|
|
||||||
"fn_without_ui": yimodel_16k_noui,
|
|
||||||
"can_multi_thread": True, # 这个并发量稍微大一点
|
|
||||||
"endpoint": yimodel_endpoint,
|
|
||||||
"max_token": 16000,
|
|
||||||
"tokenizer": tokenizer_gpt35,
|
|
||||||
"token_cnt": get_token_num_gpt35,
|
|
||||||
},
|
|
||||||
"yi-spark": {
|
|
||||||
"fn_with_ui": yimodel_16k_ui,
|
|
||||||
"fn_without_ui": yimodel_16k_noui,
|
|
||||||
"can_multi_thread": True, # 这个并发量稍微大一点
|
|
||||||
"endpoint": yimodel_endpoint,
|
|
||||||
"max_token": 16000,
|
|
||||||
"tokenizer": tokenizer_gpt35,
|
|
||||||
"token_cnt": get_token_num_gpt35,
|
|
||||||
},
|
|
||||||
"yi-large-turbo": {
|
|
||||||
"fn_with_ui": yimodel_16k_ui,
|
|
||||||
"fn_without_ui": yimodel_16k_noui,
|
|
||||||
"can_multi_thread": False, # 目前来说,默认情况下并发量极低,因此禁用
|
|
||||||
"endpoint": yimodel_endpoint,
|
|
||||||
"max_token": 16000,
|
|
||||||
"tokenizer": tokenizer_gpt35,
|
|
||||||
"token_cnt": get_token_num_gpt35,
|
|
||||||
},
|
|
||||||
"yi-large-preview": {
|
|
||||||
"fn_with_ui": yimodel_16k_ui,
|
|
||||||
"fn_without_ui": yimodel_16k_noui,
|
|
||||||
"can_multi_thread": False, # 目前来说,默认情况下并发量极低,因此禁用
|
|
||||||
"endpoint": yimodel_endpoint,
|
|
||||||
"max_token": 16000,
|
|
||||||
"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
|
||||||
@@ -831,7 +536,6 @@ 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,
|
||||||
@@ -848,7 +552,6 @@ 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,
|
||||||
@@ -865,7 +568,6 @@ 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,
|
||||||
@@ -874,16 +576,6 @@ 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,
|
|
||||||
"max_token": 4096,
|
|
||||||
"tokenizer": tokenizer_gpt35,
|
|
||||||
"token_cnt": get_token_num_gpt35,
|
|
||||||
},
|
|
||||||
"sparkv4":{
|
|
||||||
"fn_with_ui": spark_ui,
|
|
||||||
"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,
|
||||||
@@ -908,7 +600,6 @@ 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({
|
||||||
@@ -923,7 +614,6 @@ 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
|
||||||
@@ -940,119 +630,26 @@ if "deepseekcoder" in AVAIL_LLM_MODELS: # deepseekcoder
|
|||||||
})
|
})
|
||||||
except:
|
except:
|
||||||
print(trimmed_format_exc())
|
print(trimmed_format_exc())
|
||||||
# -=-=-=-=-=-=- 幻方-深度求索大模型在线API -=-=-=-=-=-=-
|
# if "skylark" in AVAIL_LLM_MODELS:
|
||||||
if "deepseek-chat" in AVAIL_LLM_MODELS or "deepseek-coder" in AVAIL_LLM_MODELS:
|
# try:
|
||||||
try:
|
# from .bridge_skylark2 import predict_no_ui_long_connection as skylark_noui
|
||||||
deepseekapi_noui, deepseekapi_ui = get_predict_function(
|
# from .bridge_skylark2 import predict as skylark_ui
|
||||||
api_key_conf_name="DEEPSEEK_API_KEY", max_output_token=4096, disable_proxy=False
|
# model_info.update({
|
||||||
)
|
# "skylark": {
|
||||||
model_info.update({
|
# "fn_with_ui": skylark_ui,
|
||||||
"deepseek-chat":{
|
# "fn_without_ui": skylark_noui,
|
||||||
"fn_with_ui": deepseekapi_ui,
|
# "endpoint": None,
|
||||||
"fn_without_ui": deepseekapi_noui,
|
# "max_token": 4096,
|
||||||
"endpoint": deepseekapi_endpoint,
|
# "tokenizer": tokenizer_gpt35,
|
||||||
"can_multi_thread": True,
|
# "token_cnt": get_token_num_gpt35,
|
||||||
"max_token": 32000,
|
# }
|
||||||
"tokenizer": tokenizer_gpt35,
|
# })
|
||||||
"token_cnt": get_token_num_gpt35,
|
# except:
|
||||||
},
|
# print(trimmed_format_exc())
|
||||||
"deepseek-coder":{
|
|
||||||
"fn_with_ui": deepseekapi_ui,
|
|
||||||
"fn_without_ui": deepseekapi_noui,
|
|
||||||
"endpoint": deepseekapi_endpoint,
|
|
||||||
"can_multi_thread": True,
|
|
||||||
"max_token": 16000,
|
|
||||||
"tokenizer": tokenizer_gpt35,
|
|
||||||
"token_cnt": get_token_num_gpt35,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
except:
|
|
||||||
print(trimmed_format_exc())
|
|
||||||
# -=-=-=-=-=-=- one-api 对齐支持 -=-=-=-=-=-=-
|
|
||||||
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:
|
|
||||||
origin_model_name, max_token_tmp = read_one_api_model_name(model)
|
|
||||||
# 如果是已知模型,则尝试获取其信息
|
|
||||||
original_model_info = model_info.get(origin_model_name.replace("one-api-", "", 1), None)
|
|
||||||
except:
|
|
||||||
print(f"one-api模型 {model} 的 max_token 配置不是整数,请检查配置文件。")
|
|
||||||
continue
|
|
||||||
this_model_info = {
|
|
||||||
"fn_with_ui": chatgpt_ui,
|
|
||||||
"fn_without_ui": chatgpt_noui,
|
|
||||||
"can_multi_thread": True,
|
|
||||||
"endpoint": openai_endpoint,
|
|
||||||
"max_token": max_token_tmp,
|
|
||||||
"tokenizer": tokenizer_gpt35,
|
|
||||||
"token_cnt": get_token_num_gpt35,
|
|
||||||
}
|
|
||||||
|
|
||||||
# 同步已知模型的其他信息
|
|
||||||
attribute = "has_multimodal_capacity"
|
|
||||||
if original_model_info is not None and original_model_info.get(attribute, None) is not None: this_model_info.update({attribute: original_model_info.get(attribute, None)})
|
|
||||||
# attribute = "attribute2"
|
|
||||||
# if original_model_info is not None and original_model_info.get(attribute, None) is not None: this_model_info.update({attribute: original_model_info.get(attribute, None)})
|
|
||||||
# attribute = "attribute3"
|
|
||||||
# if original_model_info is not None and original_model_info.get(attribute, None) is not None: this_model_info.update({attribute: original_model_info.get(attribute, None)})
|
|
||||||
model_info.update({model: this_model_info})
|
|
||||||
|
|
||||||
# -=-=-=-=-=-=- vllm 对齐支持 -=-=-=-=-=-=-
|
# <-- 用于定义和切换多个azure模型 -->
|
||||||
for model in [m for m in AVAIL_LLM_MODELS if m.startswith("vllm-")]:
|
AZURE_CFG_ARRAY = get_conf("AZURE_CFG_ARRAY")
|
||||||
# 为了更灵活地接入vllm多模型管理界面,设计了此接口,例子:AVAIL_LLM_MODELS = ["vllm-/home/hmp/llm/cache/Qwen1___5-32B-Chat(max_token=6666)"]
|
|
||||||
# 其中
|
|
||||||
# "vllm-" 是前缀(必要)
|
|
||||||
# "mixtral-8x7b" 是模型名(必要)
|
|
||||||
# "(max_token=6666)" 是配置(非必要)
|
|
||||||
try:
|
|
||||||
_, max_token_tmp = read_one_api_model_name(model)
|
|
||||||
except:
|
|
||||||
print(f"vllm模型 {model} 的 max_token 配置不是整数,请检查配置文件。")
|
|
||||||
continue
|
|
||||||
model_info.update({
|
|
||||||
model: {
|
|
||||||
"fn_with_ui": chatgpt_ui,
|
|
||||||
"fn_without_ui": chatgpt_noui,
|
|
||||||
"can_multi_thread": True,
|
|
||||||
"endpoint": openai_endpoint,
|
|
||||||
"max_token": max_token_tmp,
|
|
||||||
"tokenizer": tokenizer_gpt35,
|
|
||||||
"token_cnt": get_token_num_gpt35,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
# -=-=-=-=-=-=- ollama 对齐支持 -=-=-=-=-=-=-
|
|
||||||
for model in [m for m in AVAIL_LLM_MODELS if m.startswith("ollama-")]:
|
|
||||||
from .bridge_ollama import predict_no_ui_long_connection as ollama_noui
|
|
||||||
from .bridge_ollama import predict as ollama_ui
|
|
||||||
break
|
|
||||||
for model in [m for m in AVAIL_LLM_MODELS if m.startswith("ollama-")]:
|
|
||||||
# 为了更灵活地接入ollama多模型管理界面,设计了此接口,例子:AVAIL_LLM_MODELS = ["ollama-phi3(max_token=6666)"]
|
|
||||||
# 其中
|
|
||||||
# "ollama-" 是前缀(必要)
|
|
||||||
# "phi3" 是模型名(必要)
|
|
||||||
# "(max_token=6666)" 是配置(非必要)
|
|
||||||
try:
|
|
||||||
_, max_token_tmp = read_one_api_model_name(model)
|
|
||||||
except:
|
|
||||||
print(f"ollama模型 {model} 的 max_token 配置不是整数,请检查配置文件。")
|
|
||||||
continue
|
|
||||||
model_info.update({
|
|
||||||
model: {
|
|
||||||
"fn_with_ui": ollama_ui,
|
|
||||||
"fn_without_ui": ollama_noui,
|
|
||||||
"endpoint": ollama_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():
|
||||||
# 可能会覆盖之前的配置,但这是意料之中的
|
# 可能会覆盖之前的配置,但这是意料之中的
|
||||||
@@ -1075,20 +672,13 @@ if len(AZURE_CFG_ARRAY) > 0:
|
|||||||
AVAIL_LLM_MODELS += [azure_model_name]
|
AVAIL_LLM_MODELS += [azure_model_name]
|
||||||
|
|
||||||
|
|
||||||
# -=-=-=-=-=-=--=-=-=-=-=-=--=-=-=-=-=-=--=-=-=-=-=-=-=-=
|
|
||||||
# -=-=-=-=-=-=-=-=-=- ☝️ 以上是模型路由 -=-=-=-=-=-=-=-=-=
|
|
||||||
# -=-=-=-=-=-=--=-=-=-=-=-=--=-=-=-=-=-=--=-=-=-=-=-=-=-=
|
|
||||||
|
|
||||||
# -=-=-=-=-=-=--=-=-=-=-=-=--=-=-=-=-=-=--=-=-=-=-=-=-=-=
|
|
||||||
# -=-=-=-=-=-=-= 👇 以下是多模型路由切换函数 -=-=-=-=-=-=-=
|
|
||||||
# -=-=-=-=-=-=--=-=-=-=-=-=--=-=-=-=-=-=--=-=-=-=-=-=-=-=
|
|
||||||
|
|
||||||
|
|
||||||
def LLM_CATCH_EXCEPTION(f):
|
def LLM_CATCH_EXCEPTION(f):
|
||||||
"""
|
"""
|
||||||
装饰器函数,将错误显示出来
|
装饰器函数,将错误显示出来
|
||||||
"""
|
"""
|
||||||
def decorated(inputs:str, llm_kwargs:dict, history:list, sys_prompt:str, observe_window:list, console_slience:bool):
|
def decorated(inputs, llm_kwargs, history, sys_prompt, observe_window, console_slience):
|
||||||
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:
|
||||||
@@ -1098,9 +688,9 @@ def LLM_CATCH_EXCEPTION(f):
|
|||||||
return decorated
|
return decorated
|
||||||
|
|
||||||
|
|
||||||
def predict_no_ui_long_connection(inputs:str, llm_kwargs:dict, history:list, sys_prompt:str, observe_window:list=[], console_slience:bool=False):
|
def predict_no_ui_long_connection(inputs, llm_kwargs, history, sys_prompt, observe_window=[], console_slience=False):
|
||||||
"""
|
"""
|
||||||
发送至LLM,等待回复,一次性完成,不显示中间过程。但内部(尽可能地)用stream的方法避免中途网线被掐。
|
发送至LLM,等待回复,一次性完成,不显示中间过程。但内部用stream的方法避免中途网线被掐。
|
||||||
inputs:
|
inputs:
|
||||||
是本次问询的输入
|
是本次问询的输入
|
||||||
sys_prompt:
|
sys_prompt:
|
||||||
@@ -1118,11 +708,14 @@ def predict_no_ui_long_connection(inputs:str, llm_kwargs:dict, history:list, sys
|
|||||||
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个大语言模型:
|
||||||
method = model_info[model]["fn_without_ui"]
|
method = model_info[model]["fn_without_ui"]
|
||||||
return method(inputs, llm_kwargs, history, sys_prompt, observe_window, console_slience)
|
return method(inputs, llm_kwargs, history, sys_prompt, observe_window, console_slience)
|
||||||
else:
|
else:
|
||||||
# 如果同时询问“多个”大语言模型,这个稍微啰嗦一点,但思路相同,您不必读这个else分支
|
|
||||||
|
# 如果同时询问多个大语言模型,这个稍微啰嗦一点,但思路相同,您不必读这个else分支
|
||||||
executor = ThreadPoolExecutor(max_workers=4)
|
executor = ThreadPoolExecutor(max_workers=4)
|
||||||
models = model.split('&')
|
models = model.split('&')
|
||||||
n_model = len(models)
|
n_model = len(models)
|
||||||
@@ -1150,8 +743,7 @@ def predict_no_ui_long_connection(inputs:str, llm_kwargs:dict, history:list, sys
|
|||||||
# 观察窗(window)
|
# 观察窗(window)
|
||||||
chat_string = []
|
chat_string = []
|
||||||
for i in range(n_model):
|
for i in range(n_model):
|
||||||
color = colors[i%len(colors)]
|
chat_string.append( f"【{str(models[i])} 说】: <font color=\"{colors[i]}\"> {window_mutex[i][0]} </font>" )
|
||||||
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
|
||||||
@@ -1168,56 +760,25 @@ def predict_no_ui_long_connection(inputs:str, llm_kwargs:dict, history:list, sys
|
|||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
|
|
||||||
for i, future in enumerate(futures): # wait and get
|
for i, future in enumerate(futures): # wait and get
|
||||||
color = colors[i%len(colors)]
|
return_string_collect.append( f"【{str(models[i])} 说】: <font color=\"{colors[i]}\"> {future.result()} </font>" )
|
||||||
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
|
||||||
|
|
||||||
# 根据基础功能区 ModelOverride 参数调整模型类型,用于 `predict` 中
|
|
||||||
import importlib
|
|
||||||
import core_functional
|
|
||||||
def execute_model_override(llm_kwargs, additional_fn, method):
|
|
||||||
functional = core_functional.get_core_functions()
|
|
||||||
if (additional_fn in functional) and 'ModelOverride' in functional[additional_fn]:
|
|
||||||
# 热更新Prompt & ModelOverride
|
|
||||||
importlib.reload(core_functional)
|
|
||||||
functional = core_functional.get_core_functions()
|
|
||||||
model_override = functional[additional_fn]['ModelOverride']
|
|
||||||
if model_override not in model_info:
|
|
||||||
raise ValueError(f"模型覆盖参数 '{model_override}' 指向一个暂不支持的模型,请检查配置文件。")
|
|
||||||
method = model_info[model_override]["fn_with_ui"]
|
|
||||||
llm_kwargs['llm_model'] = model_override
|
|
||||||
return llm_kwargs, additional_fn, method
|
|
||||||
# 默认返回原参数
|
|
||||||
return llm_kwargs, additional_fn, method
|
|
||||||
|
|
||||||
def predict(inputs:str, llm_kwargs:dict, plugin_kwargs:dict, chatbot,
|
def predict(inputs, llm_kwargs, *args, **kwargs):
|
||||||
history:list=[], system_prompt:str='', stream:bool=True, additional_fn:str=None):
|
|
||||||
"""
|
"""
|
||||||
发送至LLM,流式获取输出。
|
发送至LLM,流式获取输出。
|
||||||
用于基础的对话功能。
|
用于基础的对话功能。
|
||||||
|
inputs 是本次问询的输入
|
||||||
完整参数列表:
|
top_p, temperature是LLM的内部调优参数
|
||||||
predict(
|
history 是之前的对话列表(注意无论是inputs还是history,内容太长了都会触发token数量溢出的错误)
|
||||||
inputs:str, # 是本次问询的输入
|
chatbot 为WebUI中显示的对话列表,修改它,然后yeild出去,可以直接修改对话界面内容
|
||||||
llm_kwargs:dict, # 是LLM的内部调优参数
|
additional_fn代表点击的哪个按钮,按钮见functional.py
|
||||||
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")
|
||||||
|
|
||||||
method = model_info[llm_kwargs['llm_model']]["fn_with_ui"] # 如果这里报错,检查config中的AVAIL_LLM_MODELS选项
|
method = model_info[llm_kwargs['llm_model']]["fn_with_ui"] # 如果这里报错,检查config中的AVAIL_LLM_MODELS选项
|
||||||
|
yield from method(inputs, llm_kwargs, *args, **kwargs)
|
||||||
if additional_fn: # 根据基础功能区 ModelOverride 参数调整模型类型
|
|
||||||
llm_kwargs, additional_fn, method = execute_model_override(llm_kwargs, additional_fn, method)
|
|
||||||
|
|
||||||
yield from method(inputs, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, stream, additional_fn)
|
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ from toolbox import get_conf, ProxyNetworkActivate
|
|||||||
from .local_llm_class import LocalLLMHandle, get_local_llm_predict_fns
|
from .local_llm_class import LocalLLMHandle, get_local_llm_predict_fns
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------------------------------------------------
|
||||||
# 🔌💻 Local Model
|
# 🔌💻 Local Model
|
||||||
# ------------------------------------------------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------------------------------------------------
|
||||||
@@ -22,45 +23,20 @@ class GetGLM3Handle(LocalLLMHandle):
|
|||||||
import os, glob
|
import os, glob
|
||||||
import os
|
import os
|
||||||
import platform
|
import platform
|
||||||
|
LOCAL_MODEL_QUANT, device = get_conf('LOCAL_MODEL_QUANT', 'LOCAL_MODEL_DEVICE')
|
||||||
|
|
||||||
LOCAL_MODEL_QUANT, device = get_conf("LOCAL_MODEL_QUANT", "LOCAL_MODEL_DEVICE")
|
if LOCAL_MODEL_QUANT == "INT4": # INT4
|
||||||
_model_name_ = "THUDM/chatglm3-6b"
|
_model_name_ = "THUDM/chatglm3-6b-int4"
|
||||||
# if LOCAL_MODEL_QUANT == "INT4": # INT4
|
|
||||||
# _model_name_ = "THUDM/chatglm3-6b-int4"
|
|
||||||
# elif LOCAL_MODEL_QUANT == "INT8": # INT8
|
|
||||||
# _model_name_ = "THUDM/chatglm3-6b-int8"
|
|
||||||
# else:
|
|
||||||
# _model_name_ = "THUDM/chatglm3-6b" # FP16
|
|
||||||
with ProxyNetworkActivate("Download_LLM"):
|
|
||||||
chatglm_tokenizer = AutoTokenizer.from_pretrained(
|
|
||||||
_model_name_, trust_remote_code=True
|
|
||||||
)
|
|
||||||
if device == "cpu":
|
|
||||||
chatglm_model = AutoModel.from_pretrained(
|
|
||||||
_model_name_,
|
|
||||||
trust_remote_code=True,
|
|
||||||
device="cpu",
|
|
||||||
).float()
|
|
||||||
elif LOCAL_MODEL_QUANT == "INT4": # INT4
|
|
||||||
chatglm_model = AutoModel.from_pretrained(
|
|
||||||
pretrained_model_name_or_path=_model_name_,
|
|
||||||
trust_remote_code=True,
|
|
||||||
device="cuda",
|
|
||||||
load_in_4bit=True,
|
|
||||||
)
|
|
||||||
elif LOCAL_MODEL_QUANT == "INT8": # INT8
|
elif LOCAL_MODEL_QUANT == "INT8": # INT8
|
||||||
chatglm_model = AutoModel.from_pretrained(
|
_model_name_ = "THUDM/chatglm3-6b-int8"
|
||||||
pretrained_model_name_or_path=_model_name_,
|
|
||||||
trust_remote_code=True,
|
|
||||||
device="cuda",
|
|
||||||
load_in_8bit=True,
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
chatglm_model = AutoModel.from_pretrained(
|
_model_name_ = "THUDM/chatglm3-6b" # FP16
|
||||||
pretrained_model_name_or_path=_model_name_,
|
with ProxyNetworkActivate('Download_LLM'):
|
||||||
trust_remote_code=True,
|
chatglm_tokenizer = AutoTokenizer.from_pretrained(_model_name_, trust_remote_code=True)
|
||||||
device="cuda",
|
if device=='cpu':
|
||||||
)
|
chatglm_model = AutoModel.from_pretrained(_model_name_, trust_remote_code=True, device='cpu').float()
|
||||||
|
else:
|
||||||
|
chatglm_model = AutoModel.from_pretrained(_model_name_, trust_remote_code=True, device='cuda')
|
||||||
chatglm_model = chatglm_model.eval()
|
chatglm_model = chatglm_model.eval()
|
||||||
|
|
||||||
self._model = chatglm_model
|
self._model = chatglm_model
|
||||||
@@ -70,17 +46,16 @@ class GetGLM3Handle(LocalLLMHandle):
|
|||||||
def llm_stream_generator(self, **kwargs):
|
def llm_stream_generator(self, **kwargs):
|
||||||
# 🏃♂️🏃♂️🏃♂️ 子进程执行
|
# 🏃♂️🏃♂️🏃♂️ 子进程执行
|
||||||
def adaptor(kwargs):
|
def adaptor(kwargs):
|
||||||
query = kwargs["query"]
|
query = kwargs['query']
|
||||||
max_length = kwargs["max_length"]
|
max_length = kwargs['max_length']
|
||||||
top_p = kwargs["top_p"]
|
top_p = kwargs['top_p']
|
||||||
temperature = kwargs["temperature"]
|
temperature = kwargs['temperature']
|
||||||
history = kwargs["history"]
|
history = kwargs['history']
|
||||||
return query, max_length, top_p, temperature, history
|
return query, max_length, top_p, temperature, history
|
||||||
|
|
||||||
query, max_length, top_p, temperature, history = adaptor(kwargs)
|
query, max_length, top_p, temperature, history = adaptor(kwargs)
|
||||||
|
|
||||||
for response, history in self._model.stream_chat(
|
for response, history in self._model.stream_chat(self._tokenizer,
|
||||||
self._tokenizer,
|
|
||||||
query,
|
query,
|
||||||
history,
|
history,
|
||||||
max_length=max_length,
|
max_length=max_length,
|
||||||
@@ -93,13 +68,10 @@ class GetGLM3Handle(LocalLLMHandle):
|
|||||||
# import something that will raise error if the user does not install requirement_*.txt
|
# import something that will raise error if the user does not install requirement_*.txt
|
||||||
# 🏃♂️🏃♂️🏃♂️ 主进程执行
|
# 🏃♂️🏃♂️🏃♂️ 主进程执行
|
||||||
import importlib
|
import importlib
|
||||||
|
|
||||||
# importlib.import_module('modelscope')
|
# importlib.import_module('modelscope')
|
||||||
|
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------------------------------------------------
|
||||||
# 🔌💻 GPT-Academic Interface
|
# 🔌💻 GPT-Academic Interface
|
||||||
# ------------------------------------------------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------------------------------------------------
|
||||||
predict_no_ui_long_connection, predict = get_local_llm_predict_fns(
|
predict_no_ui_long_connection, predict = get_local_llm_predict_fns(GetGLM3Handle, model_name, history_format='chatglm3')
|
||||||
GetGLM3Handle, model_name, history_format="chatglm3"
|
|
||||||
)
|
|
||||||
@@ -137,8 +137,7 @@ class GetGLMFTHandle(Process):
|
|||||||
global glmft_handle
|
global glmft_handle
|
||||||
glmft_handle = None
|
glmft_handle = None
|
||||||
#################################################################################
|
#################################################################################
|
||||||
def predict_no_ui_long_connection(inputs:str, llm_kwargs:dict, history:list=[], sys_prompt:str="",
|
def predict_no_ui_long_connection(inputs, llm_kwargs, history=[], sys_prompt="", observe_window=[], console_slience=False):
|
||||||
observe_window:list=[], console_slience:bool=False):
|
|
||||||
"""
|
"""
|
||||||
多线程方法
|
多线程方法
|
||||||
函数的说明请见 request_llms/bridge_all.py
|
函数的说明请见 request_llms/bridge_all.py
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# 借鉴了 https://github.com/GaiZhenbiao/ChuanhuChatGPT 项目
|
||||||
|
|
||||||
"""
|
"""
|
||||||
该文件中主要包含三个函数
|
该文件中主要包含三个函数
|
||||||
|
|
||||||
@@ -9,19 +11,17 @@
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import json
|
import json
|
||||||
import os
|
|
||||||
import re
|
|
||||||
import time
|
import time
|
||||||
|
import gradio as gr
|
||||||
import logging
|
import logging
|
||||||
import traceback
|
import traceback
|
||||||
import requests
|
import requests
|
||||||
|
import importlib
|
||||||
import random
|
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
|
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 trimmed_format_exc, is_the_upload_folder, read_one_api_model_name, log_chat
|
|
||||||
from toolbox import ChatBotWithCookies, have_any_recent_upload_image_files, encode_image
|
|
||||||
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')
|
||||||
|
|
||||||
@@ -39,57 +39,6 @@ def get_full_error(chunk, stream_response):
|
|||||||
break
|
break
|
||||||
return chunk
|
return chunk
|
||||||
|
|
||||||
def make_multimodal_input(inputs, image_paths):
|
|
||||||
image_base64_array = []
|
|
||||||
for image_path in image_paths:
|
|
||||||
path = os.path.abspath(image_path)
|
|
||||||
base64 = encode_image(path)
|
|
||||||
inputs = inputs + f'<br/><br/><div align="center"><img src="file={path}" base64="{base64}"></div>'
|
|
||||||
image_base64_array.append(base64)
|
|
||||||
return inputs, image_base64_array
|
|
||||||
|
|
||||||
def reverse_base64_from_input(inputs):
|
|
||||||
# 定义一个正则表达式来匹配 Base64 字符串(假设格式为 base64="<Base64编码>")
|
|
||||||
# pattern = re.compile(r'base64="([^"]+)"></div>')
|
|
||||||
pattern = re.compile(r'<br/><br/><div align="center"><img[^<>]+base64="([^"]+)"></div>')
|
|
||||||
# 使用 findall 方法查找所有匹配的 Base64 字符串
|
|
||||||
base64_strings = pattern.findall(inputs)
|
|
||||||
# 返回反转后的 Base64 字符串列表
|
|
||||||
return base64_strings
|
|
||||||
|
|
||||||
def contain_base64(inputs):
|
|
||||||
base64_strings = reverse_base64_from_input(inputs)
|
|
||||||
return len(base64_strings) > 0
|
|
||||||
|
|
||||||
def append_image_if_contain_base64(inputs):
|
|
||||||
if not contain_base64(inputs):
|
|
||||||
return inputs
|
|
||||||
else:
|
|
||||||
image_base64_array = reverse_base64_from_input(inputs)
|
|
||||||
pattern = re.compile(r'<br/><br/><div align="center"><img[^><]+></div>')
|
|
||||||
inputs = re.sub(pattern, '', inputs)
|
|
||||||
res = []
|
|
||||||
res.append({
|
|
||||||
"type": "text",
|
|
||||||
"text": inputs
|
|
||||||
})
|
|
||||||
for image_base64 in image_base64_array:
|
|
||||||
res.append({
|
|
||||||
"type": "image_url",
|
|
||||||
"image_url": {
|
|
||||||
"url": f"data:image/jpeg;base64,{image_base64}"
|
|
||||||
}
|
|
||||||
})
|
|
||||||
return res
|
|
||||||
|
|
||||||
def remove_image_if_contain_base64(inputs):
|
|
||||||
if not contain_base64(inputs):
|
|
||||||
return inputs
|
|
||||||
else:
|
|
||||||
pattern = re.compile(r'<br/><br/><div align="center"><img[^><]+></div>')
|
|
||||||
inputs = re.sub(pattern, '', inputs)
|
|
||||||
return inputs
|
|
||||||
|
|
||||||
def decode_chunk(chunk):
|
def decode_chunk(chunk):
|
||||||
# 提前读取一些信息 (用于判断异常)
|
# 提前读取一些信息 (用于判断异常)
|
||||||
chunk_decoded = chunk.decode()
|
chunk_decoded = chunk.decode()
|
||||||
@@ -119,7 +68,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:str, llm_kwargs:dict, history:list=[], sys_prompt:str="", observe_window:list=None, console_slience:bool=False):
|
def predict_no_ui_long_connection(inputs, llm_kwargs, history=[], sys_prompt="", observe_window=None, console_slience=False):
|
||||||
"""
|
"""
|
||||||
发送至chatGPT,等待回复,一次性完成,不显示中间过程。但内部用stream的方法避免中途网线被掐。
|
发送至chatGPT,等待回复,一次性完成,不显示中间过程。但内部用stream的方法避免中途网线被掐。
|
||||||
inputs:
|
inputs:
|
||||||
@@ -176,9 +125,8 @@ def predict_no_ui_long_connection(inputs:str, llm_kwargs:dict, history:list=[],
|
|||||||
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 (not has_content) and has_role: continue
|
if "role" in delta: continue
|
||||||
if (not has_content) and (not has_role): continue # raise RuntimeError("发现不标准的第三方接口:"+delta)
|
if "content" in 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:
|
||||||
@@ -197,8 +145,7 @@ def predict_no_ui_long_connection(inputs:str, llm_kwargs:dict, history:list=[],
|
|||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
def predict(inputs:str, llm_kwargs:dict, plugin_kwargs:dict, chatbot:ChatBotWithCookies,
|
def predict(inputs, llm_kwargs, plugin_kwargs, chatbot, history=[], system_prompt='', stream = True, additional_fn=None):
|
||||||
history:list=[], system_prompt:str='', stream:bool=True, additional_fn:str=None):
|
|
||||||
"""
|
"""
|
||||||
发送至chatGPT,流式获取输出。
|
发送至chatGPT,流式获取输出。
|
||||||
用于基础的对话功能。
|
用于基础的对话功能。
|
||||||
@@ -208,7 +155,6 @@ def predict(inputs:str, llm_kwargs:dict, plugin_kwargs:dict, chatbot:ChatBotWith
|
|||||||
chatbot 为WebUI中显示的对话列表,修改它,然后yeild出去,可以直接修改对话界面内容
|
chatbot 为WebUI中显示的对话列表,修改它,然后yeild出去,可以直接修改对话界面内容
|
||||||
additional_fn代表点击的哪个按钮,按钮见functional.py
|
additional_fn代表点击的哪个按钮,按钮见functional.py
|
||||||
"""
|
"""
|
||||||
from .bridge_all import model_info
|
|
||||||
if is_any_api_key(inputs):
|
if is_any_api_key(inputs):
|
||||||
chatbot._cookies['api_key'] = inputs
|
chatbot._cookies['api_key'] = inputs
|
||||||
chatbot.append(("输入已识别为openai的api_key", what_keys(inputs)))
|
chatbot.append(("输入已识别为openai的api_key", what_keys(inputs)))
|
||||||
@@ -224,17 +170,9 @@ def predict(inputs:str, llm_kwargs:dict, plugin_kwargs:dict, chatbot:ChatBotWith
|
|||||||
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
|
||||||
has_multimodal_capacity = model_info[llm_kwargs['llm_model']].get('has_multimodal_capacity', False)
|
logging.info(f'[raw_input] {raw_input}')
|
||||||
if has_multimodal_capacity:
|
chatbot.append((inputs, ""))
|
||||||
has_recent_image_upload, image_paths = have_any_recent_upload_image_files(chatbot, pop=True)
|
|
||||||
else:
|
|
||||||
has_recent_image_upload, image_paths = False, []
|
|
||||||
if has_recent_image_upload:
|
|
||||||
_inputs, image_base64_array = make_multimodal_input(inputs, image_paths)
|
|
||||||
else:
|
|
||||||
_inputs, image_base64_array = inputs, []
|
|
||||||
chatbot.append((_inputs, ""))
|
|
||||||
yield from update_ui(chatbot=chatbot, history=history, msg="等待响应") # 刷新界面
|
yield from update_ui(chatbot=chatbot, history=history, msg="等待响应") # 刷新界面
|
||||||
|
|
||||||
# check mis-behavior
|
# check mis-behavior
|
||||||
@@ -244,7 +182,7 @@ def predict(inputs:str, llm_kwargs:dict, plugin_kwargs:dict, chatbot:ChatBotWith
|
|||||||
time.sleep(2)
|
time.sleep(2)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
headers, payload = generate_payload(inputs, llm_kwargs, history, system_prompt, image_base64_array, has_multimodal_capacity, stream)
|
headers, payload = generate_payload(inputs, llm_kwargs, history, system_prompt, stream)
|
||||||
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不满足要求") # 刷新界面
|
||||||
@@ -252,6 +190,7 @@ def predict(inputs:str, llm_kwargs:dict, plugin_kwargs:dict, chatbot:ChatBotWith
|
|||||||
|
|
||||||
# 检查endpoint是否合法
|
# 检查endpoint是否合法
|
||||||
try:
|
try:
|
||||||
|
from .bridge_all import model_info
|
||||||
endpoint = verify_endpoint(model_info[llm_kwargs['llm_model']]['endpoint'])
|
endpoint = verify_endpoint(model_info[llm_kwargs['llm_model']]['endpoint'])
|
||||||
except:
|
except:
|
||||||
tb_str = '```\n' + trimmed_format_exc() + '```'
|
tb_str = '```\n' + trimmed_format_exc() + '```'
|
||||||
@@ -259,11 +198,7 @@ def predict(inputs:str, llm_kwargs:dict, plugin_kwargs:dict, chatbot:ChatBotWith
|
|||||||
yield from update_ui(chatbot=chatbot, history=history, msg="Endpoint不满足要求") # 刷新界面
|
yield from update_ui(chatbot=chatbot, history=history, msg="Endpoint不满足要求") # 刷新界面
|
||||||
return
|
return
|
||||||
|
|
||||||
# 加入历史
|
history.append(inputs); history.append("")
|
||||||
if has_recent_image_upload:
|
|
||||||
history.extend([_inputs, ""])
|
|
||||||
else:
|
|
||||||
history.extend([inputs, ""])
|
|
||||||
|
|
||||||
retry = 0
|
retry = 0
|
||||||
while True:
|
while True:
|
||||||
@@ -317,8 +252,7 @@ def predict(inputs:str, llm_kwargs:dict, plugin_kwargs:dict, chatbot:ChatBotWith
|
|||||||
# 前者是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')}"
|
||||||
@@ -330,8 +264,7 @@ def predict(inputs:str, llm_kwargs:dict, plugin_kwargs:dict, chatbot:ChatBotWith
|
|||||||
# 一些第三方接口的出现这样的错误,兼容一下吧
|
# 一些第三方接口的出现这样的错误,兼容一下吧
|
||||||
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
|
||||||
@@ -377,16 +310,13 @@ def handle_error(inputs, llm_kwargs, chatbot, history, chunk_decoded, error_msg)
|
|||||||
chatbot[-1] = (chatbot[-1][0], f"[Local Message] 异常 \n\n{tb_str} \n\n{regular_txt_to_markdown(chunk_decoded)}")
|
chatbot[-1] = (chatbot[-1][0], f"[Local Message] 异常 \n\n{tb_str} \n\n{regular_txt_to_markdown(chunk_decoded)}")
|
||||||
return chatbot, history
|
return chatbot, history
|
||||||
|
|
||||||
def generate_payload(inputs:str, llm_kwargs:dict, history:list, system_prompt:str, image_base64_array:list=[], has_multimodal_capacity:bool=False, stream:bool=True):
|
def generate_payload(inputs, llm_kwargs, history, system_prompt, stream):
|
||||||
"""
|
"""
|
||||||
整合所有信息,选择LLM模型,生成http请求,为发送请求做准备
|
整合所有信息,选择LLM模型,生成http请求,为发送请求做准备
|
||||||
"""
|
"""
|
||||||
if not is_any_api_key(llm_kwargs['api_key']):
|
if not is_any_api_key(llm_kwargs['api_key']):
|
||||||
raise AssertionError("你提供了错误的API_KEY。\n\n1. 临时解决方案:直接在输入区键入api_key,然后回车提交。\n\n2. 长效解决方案:在config.py中配置。")
|
raise AssertionError("你提供了错误的API_KEY。\n\n1. 临时解决方案:直接在输入区键入api_key,然后回车提交。\n\n2. 长效解决方案:在config.py中配置。")
|
||||||
|
|
||||||
if llm_kwargs['llm_model'].startswith('vllm-'):
|
|
||||||
api_key = 'no-api-key'
|
|
||||||
else:
|
|
||||||
api_key = select_api_key(llm_kwargs['api_key'], llm_kwargs['llm_model'])
|
api_key = select_api_key(llm_kwargs['api_key'], llm_kwargs['llm_model'])
|
||||||
|
|
||||||
headers = {
|
headers = {
|
||||||
@@ -400,27 +330,17 @@ def generate_payload(inputs:str, llm_kwargs:dict, history:list, system_prompt:st
|
|||||||
azure_api_key_unshared = AZURE_CFG_ARRAY[llm_kwargs['llm_model']]["AZURE_API_KEY"]
|
azure_api_key_unshared = AZURE_CFG_ARRAY[llm_kwargs['llm_model']]["AZURE_API_KEY"]
|
||||||
headers.update({"api-key": azure_api_key_unshared})
|
headers.update({"api-key": azure_api_key_unshared})
|
||||||
|
|
||||||
if has_multimodal_capacity:
|
|
||||||
# 当以下条件满足时,启用多模态能力:
|
|
||||||
# 1. 模型本身是多模态模型(has_multimodal_capacity)
|
|
||||||
# 2. 输入包含图像(len(image_base64_array) > 0)
|
|
||||||
# 3. 历史输入包含图像( any([contain_base64(h) for h in history]) )
|
|
||||||
enable_multimodal_capacity = (len(image_base64_array) > 0) or any([contain_base64(h) for h in history])
|
|
||||||
else:
|
|
||||||
enable_multimodal_capacity = False
|
|
||||||
|
|
||||||
if not enable_multimodal_capacity:
|
|
||||||
# 不使用多模态能力
|
|
||||||
conversation_cnt = len(history) // 2
|
conversation_cnt = len(history) // 2
|
||||||
|
|
||||||
messages = [{"role": "system", "content": system_prompt}]
|
messages = [{"role": "system", "content": system_prompt}]
|
||||||
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"] = remove_image_if_contain_base64(history[index])
|
what_i_have_asked["content"] = history[index]
|
||||||
what_gpt_answer = {}
|
what_gpt_answer = {}
|
||||||
what_gpt_answer["role"] = "assistant"
|
what_gpt_answer["role"] = "assistant"
|
||||||
what_gpt_answer["content"] = remove_image_if_contain_base64(history[index+1])
|
what_gpt_answer["content"] = history[index+1]
|
||||||
if what_i_have_asked["content"] != "":
|
if what_i_have_asked["content"] != "":
|
||||||
if what_gpt_answer["content"] == "": continue
|
if what_gpt_answer["content"] == "": continue
|
||||||
if what_gpt_answer["content"] == timeout_bot_msg: continue
|
if what_gpt_answer["content"] == timeout_bot_msg: continue
|
||||||
@@ -428,55 +348,15 @@ def generate_payload(inputs:str, llm_kwargs:dict, history:list, system_prompt:st
|
|||||||
messages.append(what_gpt_answer)
|
messages.append(what_gpt_answer)
|
||||||
else:
|
else:
|
||||||
messages[-1]['content'] = what_gpt_answer['content']
|
messages[-1]['content'] = what_gpt_answer['content']
|
||||||
|
|
||||||
what_i_ask_now = {}
|
what_i_ask_now = {}
|
||||||
what_i_ask_now["role"] = "user"
|
what_i_ask_now["role"] = "user"
|
||||||
what_i_ask_now["content"] = inputs
|
what_i_ask_now["content"] = inputs
|
||||||
messages.append(what_i_ask_now)
|
messages.append(what_i_ask_now)
|
||||||
else:
|
|
||||||
# 多模态能力
|
|
||||||
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"] = append_image_if_contain_base64(history[index])
|
|
||||||
what_gpt_answer = {}
|
|
||||||
what_gpt_answer["role"] = "assistant"
|
|
||||||
what_gpt_answer["content"] = append_image_if_contain_base64(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"] = []
|
|
||||||
what_i_ask_now["content"].append({
|
|
||||||
"type": "text",
|
|
||||||
"text": inputs
|
|
||||||
})
|
|
||||||
for image_base64 in image_base64_array:
|
|
||||||
what_i_ask_now["content"].append({
|
|
||||||
"type": "image_url",
|
|
||||||
"image_url": {
|
|
||||||
"url": f"data:image/jpeg;base64,{image_base64}"
|
|
||||||
}
|
|
||||||
})
|
|
||||||
messages.append(what_i_ask_now)
|
|
||||||
|
|
||||||
|
|
||||||
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 llm_kwargs['llm_model'].startswith('vllm-'):
|
|
||||||
model = llm_kwargs['llm_model'][len('vllm-'):]
|
|
||||||
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([
|
||||||
"gpt-3.5-turbo",
|
"gpt-3.5-turbo",
|
||||||
@@ -495,11 +375,13 @@ def generate_payload(inputs:str, llm_kwargs:dict, history:list, system_prompt:st
|
|||||||
"top_p": llm_kwargs['top_p'], # 1.0,
|
"top_p": llm_kwargs['top_p'], # 1.0,
|
||||||
"n": 1,
|
"n": 1,
|
||||||
"stream": stream,
|
"stream": stream,
|
||||||
|
"presence_penalty": 0,
|
||||||
|
"frequency_penalty": 0,
|
||||||
}
|
}
|
||||||
# try:
|
try:
|
||||||
# print(f" {llm_kwargs['llm_model']} : {conversation_cnt} : {inputs[:100]} ..........")
|
print(f" {llm_kwargs['llm_model']} : {conversation_cnt} : {inputs[:100]} ..........")
|
||||||
# except:
|
except:
|
||||||
# print('输入中可能存在乱码。')
|
print('输入中可能存在乱码。')
|
||||||
return headers,payload
|
return headers,payload
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -27,8 +27,10 @@ timeout_bot_msg = '[Local Message] Request timeout. Network error. Please check
|
|||||||
|
|
||||||
|
|
||||||
def report_invalid_key(key):
|
def report_invalid_key(key):
|
||||||
# 弃用功能
|
if get_conf("BLOCK_INVALID_APIKEY"):
|
||||||
return
|
# 实验性功能,自动检测并屏蔽失效的KEY,请勿使用
|
||||||
|
from request_llms.key_manager import ApiKeyManager
|
||||||
|
api_key = ApiKeyManager().add_key_to_blacklist(key)
|
||||||
|
|
||||||
def get_full_error(chunk, stream_response):
|
def get_full_error(chunk, stream_response):
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -9,15 +9,15 @@
|
|||||||
具备多线程调用能力的函数
|
具备多线程调用能力的函数
|
||||||
2. predict_no_ui_long_connection:支持多线程
|
2. predict_no_ui_long_connection:支持多线程
|
||||||
"""
|
"""
|
||||||
import logging
|
|
||||||
import os
|
import os
|
||||||
import time
|
|
||||||
import traceback
|
|
||||||
import json
|
import json
|
||||||
|
import time
|
||||||
|
import gradio as gr
|
||||||
|
import logging
|
||||||
|
import traceback
|
||||||
import requests
|
import requests
|
||||||
from toolbox import get_conf, update_ui, trimmed_format_exc, encode_image, every_image_file_in_path, log_chat
|
import importlib
|
||||||
picture_system_prompt = "\n当回复图像时,必须说明正在回复哪张图像。所有图像仅在最后一个问题中提供,即使它们在历史记录中被提及。请使用'这是第X张图像:'的格式来指明您正在描述的是哪张图像。"
|
|
||||||
Claude_3_Models = ["claude-3-haiku-20240307", "claude-3-sonnet-20240229", "claude-3-opus-20240229", "claude-3-5-sonnet-20240620"]
|
|
||||||
|
|
||||||
# config_private.py放自己的秘密如API和代理网址
|
# config_private.py放自己的秘密如API和代理网址
|
||||||
# 读取时首先看是否存在私密的config_private配置文件(不受git管控),如果有,则覆盖原config文件
|
# 读取时首先看是否存在私密的config_private配置文件(不受git管控),如果有,则覆盖原config文件
|
||||||
@@ -39,34 +39,6 @@ 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):
|
||||||
"""
|
"""
|
||||||
@@ -82,67 +54,50 @@ 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
|
||||||
endpoint = model_info[llm_kwargs['llm_model']]['endpoint']
|
anthropic = Anthropic(api_key=ANTHROPIC_API_KEY)
|
||||||
response = requests.post(endpoint, headers=headers, json=message,
|
# endpoint = model_info[llm_kwargs['llm_model']]['endpoint']
|
||||||
proxies=proxies, stream=True, timeout=TIMEOUT_SECONDS);break
|
# with ProxyNetworkActivate()
|
||||||
except requests.exceptions.ReadTimeout as e:
|
stream = anthropic.completions.create(
|
||||||
|
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 = ''
|
||||||
while True:
|
|
||||||
try: chunk = next(stream_response)
|
|
||||||
except StopIteration:
|
|
||||||
break
|
|
||||||
except requests.exceptions.ConnectionError:
|
|
||||||
chunk = next(stream_response) # 失败了,重试一次?再失败就没办法了。
|
|
||||||
need_to_pass, chunkjson, is_last_chunk = decode_chunk(chunk)
|
|
||||||
if chunk:
|
|
||||||
try:
|
try:
|
||||||
if need_to_pass:
|
for completion in stream:
|
||||||
pass
|
result += completion.completion
|
||||||
elif is_last_chunk:
|
if not console_slience: print(completion.completion, end='')
|
||||||
# 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 observe_window is not None:
|
||||||
# 观测窗,把已经获取的数据显示出去
|
# 观测窗,把已经获取的数据显示出去
|
||||||
if len(observe_window) >= 1:
|
if len(observe_window) >= 1: observe_window[0] += completion.completion
|
||||||
observe_window[0] += chunkjson['delta']['text']
|
|
||||||
# 看门狗,如果超过期限没有喂狗,则终止
|
# 看门狗,如果超过期限没有喂狗,则终止
|
||||||
if len(observe_window) >= 2:
|
if len(observe_window) >= 2:
|
||||||
if (time.time()-observe_window[1]) > watch_dog_patience:
|
if (time.time()-observe_window[1]) > watch_dog_patience:
|
||||||
raise RuntimeError("用户取消了程序。")
|
raise RuntimeError("用户取消了程序。")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
chunk = get_full_error(chunk, stream_response)
|
traceback.print_exc()
|
||||||
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):
|
||||||
"""
|
"""
|
||||||
@@ -154,7 +109,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
|
||||||
"""
|
"""
|
||||||
if inputs == "": inputs = "空空如也的输入栏"
|
from anthropic import Anthropic
|
||||||
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="等待响应") # 刷新界面
|
||||||
@@ -164,23 +119,13 @@ 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)
|
||||||
|
|
||||||
have_recent_file, image_paths = every_image_file_in_path(chatbot)
|
raw_input = inputs
|
||||||
if len(image_paths) > 20:
|
logging.info(f'[raw_input] {raw_input}')
|
||||||
chatbot.append((inputs, "图片数量超过api上限(20张)"))
|
|
||||||
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, ""))
|
chatbot.append((inputs, ""))
|
||||||
yield from update_ui(chatbot=chatbot, history=history, msg="等待响应") # 刷新界面
|
yield from update_ui(chatbot=chatbot, history=history, msg="等待响应") # 刷新界面
|
||||||
|
|
||||||
try:
|
try:
|
||||||
headers, message = generate_payload(inputs, llm_kwargs, history, system_prompt, image_paths)
|
prompt = generate_payload(inputs, llm_kwargs, history, system_prompt, stream)
|
||||||
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不满足要求") # 刷新界面
|
||||||
@@ -193,117 +138,91 @@ 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
|
||||||
endpoint = model_info[llm_kwargs['llm_model']]['endpoint']
|
anthropic = Anthropic(api_key=ANTHROPIC_API_KEY)
|
||||||
response = requests.post(endpoint, headers=headers, json=message,
|
# endpoint = model_info[llm_kwargs['llm_model']]['endpoint']
|
||||||
proxies=proxies, stream=True, timeout=TIMEOUT_SECONDS);break
|
# with ProxyNetworkActivate()
|
||||||
except requests.exceptions.ReadTimeout as e:
|
stream = anthropic.completions.create(
|
||||||
|
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
|
||||||
traceback.print_exc()
|
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
|
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 = ""
|
||||||
|
|
||||||
while True:
|
for completion in stream:
|
||||||
try: chunk = next(stream_response)
|
|
||||||
except StopIteration:
|
|
||||||
break
|
|
||||||
except requests.exceptions.ConnectionError:
|
|
||||||
chunk = next(stream_response) # 失败了,重试一次?再失败就没办法了。
|
|
||||||
need_to_pass, chunkjson, is_last_chunk = decode_chunk(chunk)
|
|
||||||
if chunk:
|
|
||||||
try:
|
try:
|
||||||
if need_to_pass:
|
gpt_replying_buffer = gpt_replying_buffer + completion.completion
|
||||||
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
|
history[-1] = gpt_replying_buffer
|
||||||
chatbot[-1] = (history[-2], history[-1])
|
chatbot[-1] = (history[-2], history[-1])
|
||||||
yield from update_ui(chatbot=chatbot, history=history, msg='正常') # 刷新界面
|
yield from update_ui(chatbot=chatbot, history=history, msg='正常') # 刷新界面
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
chunk = get_full_error(chunk, stream_response)
|
from toolbox import regular_txt_to_markdown
|
||||||
chunk_decoded = chunk.decode()
|
tb_str = '```\n' + trimmed_format_exc() + '```'
|
||||||
error_msg = chunk_decoded
|
chatbot[-1] = (chatbot[-1][0], f"[Local Message] 异常 \n\n{tb_str}")
|
||||||
print(error_msg)
|
yield from update_ui(chatbot=chatbot, history=history, msg="Json异常" + tb_str) # 刷新界面
|
||||||
raise RuntimeError("Json解析不合常规")
|
return
|
||||||
|
|
||||||
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 = []
|
messages = [{"role": "system", "content": system_prompt}]
|
||||||
|
|
||||||
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"] = [{"type": "text", "text": history[index]}]
|
what_i_have_asked["content"] = history[index]
|
||||||
what_gpt_answer = {}
|
what_gpt_answer = {}
|
||||||
what_gpt_answer["role"] = "assistant"
|
what_gpt_answer["role"] = "assistant"
|
||||||
what_gpt_answer["content"] = [{"type": "text", "text": history[index+1]}]
|
what_gpt_answer["content"] = history[index+1]
|
||||||
if what_i_have_asked["content"][0]["text"] != "":
|
if what_i_have_asked["content"] != "":
|
||||||
if what_i_have_asked["content"][0]["text"] == "": continue
|
if what_gpt_answer["content"] == "": continue
|
||||||
if what_i_have_asked["content"][0]["text"] == timeout_bot_msg: continue
|
if what_gpt_answer["content"] == 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'][0]['text'] = what_gpt_answer['content'][0]['text']
|
messages[-1]['content'] = what_gpt_answer['content']
|
||||||
|
|
||||||
if any([llm_kwargs['llm_model'] == model for model in Claude_3_Models]) and image_paths:
|
|
||||||
what_i_ask_now = {}
|
what_i_ask_now = {}
|
||||||
what_i_ask_now["role"] = "user"
|
what_i_ask_now["role"] = "user"
|
||||||
what_i_ask_now["content"] = []
|
what_i_ask_now["content"] = inputs
|
||||||
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)
|
||||||
# 开始整理headers与message
|
prompt = convert_messages_to_prompt(messages)
|
||||||
headers = {
|
|
||||||
'x-api-key': ANTHROPIC_API_KEY,
|
return prompt
|
||||||
'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
|
|
||||||
|
|||||||
@@ -1,328 +0,0 @@
|
|||||||
# 借鉴了 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,8 +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, log_chat
|
|
||||||
|
|
||||||
proxies, TIMEOUT_SECONDS, MAX_RETRY = get_conf('proxies', 'TIMEOUT_SECONDS', 'MAX_RETRY')
|
proxies, TIMEOUT_SECONDS, MAX_RETRY = get_conf('proxies', 'TIMEOUT_SECONDS', 'MAX_RETRY')
|
||||||
timeout_bot_msg = '[Local Message] Request timeout. Network error. Please check proxy settings in config.py.' + \
|
timeout_bot_msg = '[Local Message] Request timeout. Network error. Please check proxy settings in config.py.' + \
|
||||||
@@ -21,7 +20,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(llm_kwargs)
|
genai = GoogleChatInit()
|
||||||
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)
|
||||||
@@ -45,8 +44,7 @@ def predict_no_ui_long_connection(inputs, llm_kwargs, history=[], sys_prompt="",
|
|||||||
return gpt_replying_buffer
|
return gpt_replying_buffer
|
||||||
|
|
||||||
|
|
||||||
def predict(inputs:str, llm_kwargs:dict, plugin_kwargs:dict, chatbot:ChatBotWithCookies,
|
def predict(inputs, llm_kwargs, plugin_kwargs, chatbot, history=[], system_prompt='', stream=True, additional_fn=None):
|
||||||
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)
|
||||||
@@ -72,7 +70,7 @@ def predict(inputs:str, llm_kwargs:dict, plugin_kwargs:dict, chatbot:ChatBotWith
|
|||||||
|
|
||||||
chatbot.append((inputs, ""))
|
chatbot.append((inputs, ""))
|
||||||
yield from update_ui(chatbot=chatbot, history=history)
|
yield from update_ui(chatbot=chatbot, history=history)
|
||||||
genai = GoogleChatInit(llm_kwargs)
|
genai = GoogleChatInit()
|
||||||
retry = 0
|
retry = 0
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
@@ -99,7 +97,6 @@ def predict(inputs:str, llm_kwargs:dict, plugin_kwargs:dict, chatbot:ChatBotWith
|
|||||||
gpt_replying_buffer += paraphrase['text'] # 使用 json 解析库进行处理
|
gpt_replying_buffer += paraphrase['text'] # 使用 json 解析库进行处理
|
||||||
chatbot[-1] = (inputs, gpt_replying_buffer)
|
chatbot[-1] = (inputs, gpt_replying_buffer)
|
||||||
history[-1] = gpt_replying_buffer
|
history[-1] = gpt_replying_buffer
|
||||||
log_chat(llm_model=llm_kwargs["llm_model"], input_str=inputs, output_str=gpt_replying_buffer)
|
|
||||||
yield from update_ui(chatbot=chatbot, history=history)
|
yield from update_ui(chatbot=chatbot, history=history)
|
||||||
if error_match:
|
if error_match:
|
||||||
history = history[-2] # 错误的不纳入对话
|
history = history[-2] # 错误的不纳入对话
|
||||||
|
|||||||
@@ -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,8 +106,7 @@ 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:str, llm_kwargs:dict, history:list=[], sys_prompt:str="",
|
def predict_no_ui_long_connection(inputs, llm_kwargs, history=[], sys_prompt="", observe_window=[], console_slience=False):
|
||||||
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,8 +106,7 @@ 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:str, llm_kwargs:dict, history:list=[], sys_prompt:str="",
|
def predict_no_ui_long_connection(inputs, llm_kwargs, history=[], sys_prompt="", observe_window=[], console_slience=False):
|
||||||
observe_window:list=[], console_slience:bool=False):
|
|
||||||
"""
|
"""
|
||||||
多线程方法
|
多线程方法
|
||||||
函数的说明请见 request_llms/bridge_all.py
|
函数的说明请见 request_llms/bridge_all.py
|
||||||
|
|||||||
@@ -106,8 +106,7 @@ 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:str, llm_kwargs:dict, history:list=[], sys_prompt:str="",
|
def predict_no_ui_long_connection(inputs, llm_kwargs, history=[], sys_prompt="", observe_window=[], console_slience=False):
|
||||||
observe_window:list=[], console_slience:bool=False):
|
|
||||||
"""
|
"""
|
||||||
多线程方法
|
多线程方法
|
||||||
函数的说明请见 request_llms/bridge_all.py
|
函数的说明请见 request_llms/bridge_all.py
|
||||||
|
|||||||
@@ -1,197 +0,0 @@
|
|||||||
# 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,8 +171,7 @@ class GetGLMHandle(Process):
|
|||||||
global moss_handle
|
global moss_handle
|
||||||
moss_handle = None
|
moss_handle = None
|
||||||
#################################################################################
|
#################################################################################
|
||||||
def predict_no_ui_long_connection(inputs:str, llm_kwargs:dict, history:list=[], sys_prompt:str="",
|
def predict_no_ui_long_connection(inputs, llm_kwargs, history=[], sys_prompt="", observe_window=[], console_slience=False):
|
||||||
observe_window:list=[], console_slience:bool=False):
|
|
||||||
"""
|
"""
|
||||||
多线程方法
|
多线程方法
|
||||||
函数的说明请见 request_llms/bridge_all.py
|
函数的说明请见 request_llms/bridge_all.py
|
||||||
|
|||||||
@@ -1,272 +0,0 @@
|
|||||||
# 借鉴自同目录下的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 = get_conf(
|
|
||||||
"proxies", "TIMEOUT_SECONDS", "MAX_RETRY"
|
|
||||||
)
|
|
||||||
|
|
||||||
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)
|
|
||||||
is_last_chunk = chunkjson.get("done", 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 = ''
|
|
||||||
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 chunk:
|
|
||||||
try:
|
|
||||||
if is_last_chunk:
|
|
||||||
# 判定为数据流的结束,gpt_replying_buffer也写完了
|
|
||||||
logging.info(f'[response] {result}')
|
|
||||||
break
|
|
||||||
result += chunkjson['message']["content"]
|
|
||||||
if not console_slience: print(chunkjson['message']["content"], end='')
|
|
||||||
if observe_window is not None:
|
|
||||||
# 观测窗,把已经获取的数据显示出去
|
|
||||||
if len(observe_window) >= 1:
|
|
||||||
observe_window[0] += chunkjson['message']["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 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 = ""
|
|
||||||
|
|
||||||
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 chunk:
|
|
||||||
try:
|
|
||||||
if is_last_chunk:
|
|
||||||
# 判定为数据流的结束,gpt_replying_buffer也写完了
|
|
||||||
logging.info(f'[response] {gpt_replying_buffer}')
|
|
||||||
break
|
|
||||||
# 处理数据流的主体
|
|
||||||
try:
|
|
||||||
status_text = f"finish_reason: {chunkjson['error'].get('message', 'null')}"
|
|
||||||
except:
|
|
||||||
status_text = "finish_reason: null"
|
|
||||||
gpt_replying_buffer = gpt_replying_buffer + chunkjson['message']["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请求,为发送请求做准备
|
|
||||||
"""
|
|
||||||
|
|
||||||
headers = {
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
}
|
|
||||||
|
|
||||||
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('ollama-'):
|
|
||||||
model = llm_kwargs['llm_model'][len('ollama-'):]
|
|
||||||
model, _ = read_one_api_model_name(model)
|
|
||||||
options = {"temperature": llm_kwargs['temperature']}
|
|
||||||
payload = {
|
|
||||||
"model": model,
|
|
||||||
"messages": messages,
|
|
||||||
"options": options,
|
|
||||||
}
|
|
||||||
try:
|
|
||||||
print(f" {llm_kwargs['llm_model']} : {conversation_cnt} : {inputs[:100]} ..........")
|
|
||||||
except:
|
|
||||||
print('输入中可能存在乱码。')
|
|
||||||
return headers,payload
|
|
||||||
@@ -82,9 +82,6 @@ def generate_from_baidu_qianfan(inputs, llm_kwargs, history, system_prompt):
|
|||||||
"ERNIE-Bot": "https://aip.baidubce.com/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/completions",
|
"ERNIE-Bot": "https://aip.baidubce.com/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/completions",
|
||||||
"ERNIE-Bot-turbo": "https://aip.baidubce.com/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/eb-instant",
|
"ERNIE-Bot-turbo": "https://aip.baidubce.com/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/eb-instant",
|
||||||
"BLOOMZ-7B": "https://aip.baidubce.com/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/bloomz_7b1",
|
"BLOOMZ-7B": "https://aip.baidubce.com/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/bloomz_7b1",
|
||||||
"ERNIE-Speed-128K": "https://aip.baidubce.com/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/ernie-speed-128k",
|
|
||||||
"ERNIE-Speed-8K": "https://aip.baidubce.com/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/ernie_speed",
|
|
||||||
"ERNIE-Lite-8K": "https://aip.baidubce.com/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/ernie-lite-8k",
|
|
||||||
|
|
||||||
"Llama-2-70B-Chat": "https://aip.baidubce.com/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/llama_2_70b",
|
"Llama-2-70B-Chat": "https://aip.baidubce.com/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/llama_2_70b",
|
||||||
"Llama-2-13B-Chat": "https://aip.baidubce.com/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/llama_2_13b",
|
"Llama-2-13B-Chat": "https://aip.baidubce.com/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/llama_2_13b",
|
||||||
@@ -120,8 +117,7 @@ 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:str, llm_kwargs:dict, history:list=[], sys_prompt:str="",
|
def predict_no_ui_long_connection(inputs, llm_kwargs, history=[], sys_prompt="", observe_window=[], console_slience=False):
|
||||||
observe_window:list=[], console_slience:bool=False):
|
|
||||||
"""
|
"""
|
||||||
⭐多线程方法
|
⭐多线程方法
|
||||||
函数的说明请见 request_llms/bridge_all.py
|
函数的说明请见 request_llms/bridge_all.py
|
||||||
@@ -164,8 +160,3 @@ def predict(inputs, llm_kwargs, plugin_kwargs, chatbot, history=[], system_promp
|
|||||||
chatbot[-1] = (chatbot[-1][0], "[Local Message] Reduce the length. 本次输入过长, 或历史数据过长. 历史缓存数据已部分释放, 您可以请再次尝试. (若再次失败则更可能是因为输入过长.)")
|
chatbot[-1] = (chatbot[-1][0], "[Local Message] Reduce the length. 本次输入过长, 或历史数据过长. 历史缓存数据已部分释放, 您可以请再次尝试. (若再次失败则更可能是因为输入过长.)")
|
||||||
yield from update_ui(chatbot=chatbot, history=history, msg="异常") # 刷新界面
|
yield from update_ui(chatbot=chatbot, history=history, msg="异常") # 刷新界面
|
||||||
return
|
return
|
||||||
except RuntimeError as e:
|
|
||||||
tb_str = '```\n' + trimmed_format_exc() + '```'
|
|
||||||
chatbot[-1] = (chatbot[-1][0], tb_str)
|
|
||||||
yield from update_ui(chatbot=chatbot, history=history, msg="异常") # 刷新界面
|
|
||||||
return
|
|
||||||
|
|||||||
@@ -1,12 +1,11 @@
|
|||||||
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
|
||||||
from toolbox import check_packages, report_exception, log_chat
|
from toolbox import check_packages, report_exception
|
||||||
|
|
||||||
model_name = 'Qwen'
|
model_name = 'Qwen'
|
||||||
|
|
||||||
def predict_no_ui_long_connection(inputs:str, llm_kwargs:dict, history:list=[], sys_prompt:str="",
|
def predict_no_ui_long_connection(inputs, llm_kwargs, history=[], sys_prompt="", observe_window=[], console_slience=False):
|
||||||
observe_window:list=[], console_slience:bool=False):
|
|
||||||
"""
|
"""
|
||||||
⭐多线程方法
|
⭐多线程方法
|
||||||
函数的说明请见 request_llms/bridge_all.py
|
函数的说明请见 request_llms/bridge_all.py
|
||||||
@@ -48,8 +47,6 @@ 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
|
||||||
@@ -59,7 +56,6 @@ 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)
|
||||||
|
|
||||||
log_chat(llm_model=llm_kwargs["llm_model"], input_str=inputs, output_str=response)
|
|
||||||
# 总结输出
|
# 总结输出
|
||||||
if response == f"[Local Message] 等待{model_name}响应中 ...":
|
if response == f"[Local Message] 等待{model_name}响应中 ...":
|
||||||
response = f"[Local Message] {model_name}响应异常 ..."
|
response = f"[Local Message] {model_name}响应异常 ..."
|
||||||
|
|||||||
@@ -9,8 +9,7 @@ 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:str, llm_kwargs:dict, history:list=[], sys_prompt:str="",
|
def predict_no_ui_long_connection(inputs, llm_kwargs, history=[], sys_prompt="", observe_window=[], console_slience=False):
|
||||||
observe_window:list=[], console_slience:bool=False):
|
|
||||||
"""
|
"""
|
||||||
⭐ 多线程方法
|
⭐ 多线程方法
|
||||||
函数的说明请见 request_llms/bridge_all.py
|
函数的说明请见 request_llms/bridge_all.py
|
||||||
|
|||||||
@@ -13,8 +13,7 @@ def validate_key():
|
|||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def predict_no_ui_long_connection(inputs:str, llm_kwargs:dict, history:list=[], sys_prompt:str="",
|
def predict_no_ui_long_connection(inputs, llm_kwargs, history=[], sys_prompt="", observe_window=[], console_slience=False):
|
||||||
observe_window:list=[], console_slience:bool=False):
|
|
||||||
"""
|
"""
|
||||||
⭐多线程方法
|
⭐多线程方法
|
||||||
函数的说明请见 request_llms/bridge_all.py
|
函数的说明请见 request_llms/bridge_all.py
|
||||||
|
|||||||
@@ -1,72 +0,0 @@
|
|||||||
import time
|
|
||||||
import os
|
|
||||||
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 ChatBotWithCookies
|
|
||||||
|
|
||||||
# model_name = 'Taichu-2.0'
|
|
||||||
# taichu_default_model = 'taichu_llm'
|
|
||||||
|
|
||||||
def validate_key():
|
|
||||||
TAICHU_API_KEY = get_conf("TAICHU_API_KEY")
|
|
||||||
if TAICHU_API_KEY == '': return False
|
|
||||||
return True
|
|
||||||
|
|
||||||
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
|
|
||||||
"""
|
|
||||||
watch_dog_patience = 5
|
|
||||||
response = ""
|
|
||||||
|
|
||||||
# if llm_kwargs["llm_model"] == "taichu":
|
|
||||||
# llm_kwargs["llm_model"] = "taichu"
|
|
||||||
|
|
||||||
if validate_key() is False:
|
|
||||||
raise RuntimeError('请配置 TAICHU_API_KEY')
|
|
||||||
|
|
||||||
# 开始接收回复
|
|
||||||
from .com_taichu import TaichuChatInit
|
|
||||||
zhipu_bro_init = TaichuChatInit()
|
|
||||||
for chunk, response in zhipu_bro_init.generate_chat(inputs, llm_kwargs, history, sys_prompt):
|
|
||||||
if len(observe_window) >= 1:
|
|
||||||
observe_window[0] = response
|
|
||||||
if len(observe_window) >= 2:
|
|
||||||
if (time.time() - observe_window[1]) > watch_dog_patience:
|
|
||||||
raise RuntimeError("程序终止。")
|
|
||||||
return response
|
|
||||||
|
|
||||||
|
|
||||||
def predict(inputs: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
|
|
||||||
"""
|
|
||||||
chatbot.append([inputs, ""])
|
|
||||||
yield from update_ui(chatbot=chatbot, history=history)
|
|
||||||
|
|
||||||
if validate_key() is False:
|
|
||||||
yield from update_ui_lastest_msg(lastmsg="[Local Message] 请配置ZHIPUAI_API_KEY", chatbot=chatbot, history=history, delay=0)
|
|
||||||
return
|
|
||||||
|
|
||||||
if additional_fn is not None:
|
|
||||||
from core_functional import handle_core_functionality
|
|
||||||
inputs, history = handle_core_functionality(additional_fn, inputs, history, chatbot)
|
|
||||||
chatbot[-1] = [inputs, ""]
|
|
||||||
yield from update_ui(chatbot=chatbot, history=history)
|
|
||||||
|
|
||||||
# if llm_kwargs["llm_model"] == "taichu":
|
|
||||||
# llm_kwargs["llm_model"] = taichu_default_model
|
|
||||||
|
|
||||||
# 开始接收回复
|
|
||||||
from .com_taichu import TaichuChatInit
|
|
||||||
zhipu_bro_init = TaichuChatInit()
|
|
||||||
for chunk, response in zhipu_bro_init.generate_chat(inputs, llm_kwargs, history, system_prompt):
|
|
||||||
chatbot[-1] = [inputs, response]
|
|
||||||
yield from update_ui(chatbot=chatbot, history=history)
|
|
||||||
history.extend([inputs, response])
|
|
||||||
log_chat(llm_model=llm_kwargs["llm_model"], input_str=inputs, output_str=response)
|
|
||||||
yield from update_ui(chatbot=chatbot, history=history)
|
|
||||||
@@ -1,8 +1,7 @@
|
|||||||
import time
|
import time
|
||||||
import os
|
import os
|
||||||
from toolbox import update_ui, get_conf, update_ui_lastest_msg, log_chat
|
from toolbox import update_ui, get_conf, update_ui_lastest_msg
|
||||||
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'
|
||||||
@@ -17,8 +16,7 @@ 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:str, llm_kwargs:dict, history:list=[], sys_prompt:str="",
|
def predict_no_ui_long_connection(inputs, llm_kwargs, history=[], sys_prompt="", observe_window=[], console_slience=False):
|
||||||
observe_window:list=[], console_slience:bool=False):
|
|
||||||
"""
|
"""
|
||||||
⭐多线程方法
|
⭐多线程方法
|
||||||
函数的说明请见 request_llms/bridge_all.py
|
函数的说明请见 request_llms/bridge_all.py
|
||||||
@@ -44,8 +42,7 @@ def predict_no_ui_long_connection(inputs:str, llm_kwargs:dict, history:list=[],
|
|||||||
return response
|
return response
|
||||||
|
|
||||||
|
|
||||||
def predict(inputs:str, llm_kwargs:dict, plugin_kwargs:dict, chatbot:ChatBotWithCookies,
|
def predict(inputs, llm_kwargs, plugin_kwargs, chatbot, history=[], system_prompt='', stream=True, additional_fn=None):
|
||||||
history:list=[], system_prompt:str='', stream:bool=True, additional_fn:str=None):
|
|
||||||
"""
|
"""
|
||||||
⭐单线程方法
|
⭐单线程方法
|
||||||
函数的说明请见 request_llms/bridge_all.py
|
函数的说明请见 request_llms/bridge_all.py
|
||||||
@@ -75,10 +72,6 @@ def predict(inputs:str, llm_kwargs:dict, plugin_kwargs:dict, chatbot:ChatBotWith
|
|||||||
llm_kwargs["llm_model"] = zhipuai_default_model
|
llm_kwargs["llm_model"] = zhipuai_default_model
|
||||||
|
|
||||||
if llm_kwargs["llm_model"] in ["glm-4v"]:
|
if llm_kwargs["llm_model"] in ["glm-4v"]:
|
||||||
if (len(inputs) + sum(len(temp) for temp in history) + 1047) > 2000:
|
|
||||||
chatbot.append((inputs, "上下文长度超过glm-4v上限2000tokens,注意图片大约占用1,047个tokens"))
|
|
||||||
yield from update_ui(chatbot=chatbot, history=history)
|
|
||||||
return
|
|
||||||
have_recent_file, image_paths = have_any_recent_upload_image_files(chatbot)
|
have_recent_file, image_paths = have_any_recent_upload_image_files(chatbot)
|
||||||
if not have_recent_file:
|
if not have_recent_file:
|
||||||
chatbot.append((inputs, "没有检测到任何近期上传的图像文件,请上传jpg格式的图片,此外,请注意拓展名需要小写"))
|
chatbot.append((inputs, "没有检测到任何近期上传的图像文件,请上传jpg格式的图片,此外,请注意拓展名需要小写"))
|
||||||
@@ -97,5 +90,4 @@ def predict(inputs:str, llm_kwargs:dict, plugin_kwargs:dict, chatbot:ChatBotWith
|
|||||||
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,10 +114,8 @@ def html_local_img(__file, layout="left", max_width=None, max_height=None, md=Tr
|
|||||||
|
|
||||||
|
|
||||||
class GoogleChatInit:
|
class GoogleChatInit:
|
||||||
def __init__(self, llm_kwargs):
|
def __init__(self):
|
||||||
from .bridge_all import model_info
|
self.url_gemini = "https://generativelanguage.googleapis.com/v1beta/models/%m:streamGenerateContent?key=%k"
|
||||||
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,10 +48,6 @@ 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':
|
||||||
@@ -65,12 +61,8 @@ class QwenRequestInstance():
|
|||||||
self.result_buf += f"[Local Message] 请求错误:状态码:{response.status_code},错误码:{response.code},消息:{response.message}"
|
self.result_buf += f"[Local Message] 请求错误:状态码:{response.status_code},错误码:{response.code},消息:{response.message}"
|
||||||
yield self.result_buf
|
yield self.result_buf
|
||||||
break
|
break
|
||||||
|
logging.info(f'[raw_input] {inputs}')
|
||||||
# 耗尽generator避免报错
|
logging.info(f'[response] {self.result_buf}')
|
||||||
while True:
|
|
||||||
try: next(responses)
|
|
||||||
except: break
|
|
||||||
|
|
||||||
return self.result_buf
|
return self.result_buf
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -67,7 +67,6 @@ class SparkRequestInstance():
|
|||||||
self.gpt_url_v3 = "ws://spark-api.xf-yun.com/v3.1/chat"
|
self.gpt_url_v3 = "ws://spark-api.xf-yun.com/v3.1/chat"
|
||||||
self.gpt_url_v35 = "wss://spark-api.xf-yun.com/v3.5/chat"
|
self.gpt_url_v35 = "wss://spark-api.xf-yun.com/v3.5/chat"
|
||||||
self.gpt_url_img = "wss://spark-api.cn-huabei-1.xf-yun.com/v2.1/image"
|
self.gpt_url_img = "wss://spark-api.cn-huabei-1.xf-yun.com/v2.1/image"
|
||||||
self.gpt_url_v4 = "wss://spark-api.xf-yun.com/v4.0/chat"
|
|
||||||
|
|
||||||
self.time_to_yield_event = threading.Event()
|
self.time_to_yield_event = threading.Event()
|
||||||
self.time_to_exit_event = threading.Event()
|
self.time_to_exit_event = threading.Event()
|
||||||
@@ -95,8 +94,6 @@ class SparkRequestInstance():
|
|||||||
gpt_url = self.gpt_url_v3
|
gpt_url = self.gpt_url_v3
|
||||||
elif llm_kwargs['llm_model'] == 'sparkv3.5':
|
elif llm_kwargs['llm_model'] == 'sparkv3.5':
|
||||||
gpt_url = self.gpt_url_v35
|
gpt_url = self.gpt_url_v35
|
||||||
elif llm_kwargs['llm_model'] == 'sparkv4':
|
|
||||||
gpt_url = self.gpt_url_v4
|
|
||||||
else:
|
else:
|
||||||
gpt_url = self.gpt_url
|
gpt_url = self.gpt_url
|
||||||
file_manifest = []
|
file_manifest = []
|
||||||
@@ -197,7 +194,6 @@ def gen_params(appid, inputs, llm_kwargs, history, system_prompt, file_manifest)
|
|||||||
"sparkv2": "generalv2",
|
"sparkv2": "generalv2",
|
||||||
"sparkv3": "generalv3",
|
"sparkv3": "generalv3",
|
||||||
"sparkv3.5": "generalv3.5",
|
"sparkv3.5": "generalv3.5",
|
||||||
"sparkv4": "4.0Ultra"
|
|
||||||
}
|
}
|
||||||
domains_select = domains[llm_kwargs['llm_model']]
|
domains_select = domains[llm_kwargs['llm_model']]
|
||||||
if file_manifest: domains_select = 'image'
|
if file_manifest: domains_select = 'image'
|
||||||
|
|||||||
@@ -1,56 +0,0 @@
|
|||||||
# encoding: utf-8
|
|
||||||
# @Time : 2024/1/22
|
|
||||||
# @Author : Kilig947 & binary husky
|
|
||||||
# @Descr : 兼容最新的智谱Ai
|
|
||||||
from toolbox import get_conf
|
|
||||||
from toolbox import get_conf, encode_image, get_pictures_list
|
|
||||||
import logging, os, requests
|
|
||||||
import json
|
|
||||||
class TaichuChatInit:
|
|
||||||
def __init__(self): ...
|
|
||||||
|
|
||||||
def __conversation_user(self, user_input: str, llm_kwargs:dict):
|
|
||||||
return {"role": "user", "content": user_input}
|
|
||||||
|
|
||||||
def __conversation_history(self, history:list, llm_kwargs:dict):
|
|
||||||
messages = []
|
|
||||||
conversation_cnt = len(history) // 2
|
|
||||||
if conversation_cnt:
|
|
||||||
for index in range(0, 2 * conversation_cnt, 2):
|
|
||||||
what_i_have_asked = self.__conversation_user(history[index], llm_kwargs)
|
|
||||||
what_gpt_answer = {
|
|
||||||
"role": "assistant",
|
|
||||||
"content": history[index + 1]
|
|
||||||
}
|
|
||||||
messages.append(what_i_have_asked)
|
|
||||||
messages.append(what_gpt_answer)
|
|
||||||
return messages
|
|
||||||
|
|
||||||
def generate_chat(self, inputs:str, llm_kwargs:dict, history:list, system_prompt:str):
|
|
||||||
TAICHU_API_KEY = get_conf("TAICHU_API_KEY")
|
|
||||||
params = {
|
|
||||||
'api_key': TAICHU_API_KEY,
|
|
||||||
'model_code': 'taichu_llm',
|
|
||||||
'question': '\n\n'.join(history) + inputs,
|
|
||||||
'prefix': system_prompt,
|
|
||||||
'temperature': llm_kwargs.get('temperature', 0.95),
|
|
||||||
'stream_format': 'json'
|
|
||||||
}
|
|
||||||
|
|
||||||
api = 'https://ai-maas.wair.ac.cn/maas/v1/model_api/invoke'
|
|
||||||
response = requests.post(api, json=params, stream=True)
|
|
||||||
results = ""
|
|
||||||
if response.status_code == 200:
|
|
||||||
response.encoding = 'utf-8'
|
|
||||||
for line in response.iter_lines(decode_unicode=True):
|
|
||||||
try: delta = json.loads(line)['data']['content']
|
|
||||||
except: delta = json.loads(line)['choices'][0]['text']
|
|
||||||
results += delta
|
|
||||||
yield delta, results
|
|
||||||
else:
|
|
||||||
raise ValueError
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
zhipu = TaichuChatInit()
|
|
||||||
zhipu.generate_chat('你好', {'llm_model': 'glm-4'}, [], '你是WPSAi')
|
|
||||||
@@ -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:str, llm_kwargs:dict):
|
def input_encode_handler(inputs, llm_kwargs):
|
||||||
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:dict):
|
def __conversation_user(self, user_input: str, llm_kwargs):
|
||||||
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:
|
||||||
@@ -36,18 +36,12 @@ class ZhipuChatInit:
|
|||||||
what_i_have_asked = {"role": "user", "content": []}
|
what_i_have_asked = {"role": "user", "content": []}
|
||||||
what_i_have_asked['content'].append({"type": 'text', "text": user_input})
|
what_i_have_asked['content'].append({"type": 'text', "text": user_input})
|
||||||
if encode_img:
|
if encode_img:
|
||||||
if len(encode_img) > 1:
|
|
||||||
logging.warning("glm-4v只支持一张图片,将只取第一张图片进行处理")
|
|
||||||
print("glm-4v只支持一张图片,将只取第一张图片进行处理")
|
|
||||||
img_d = {"type": "image_url",
|
img_d = {"type": "image_url",
|
||||||
"image_url": {
|
"image_url": {'url': encode_img}}
|
||||||
"url": encode_img[0]['data']
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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:list, llm_kwargs:dict):
|
def __conversation_history(self, history, llm_kwargs):
|
||||||
messages = []
|
messages = []
|
||||||
conversation_cnt = len(history) // 2
|
conversation_cnt = len(history) // 2
|
||||||
if conversation_cnt:
|
if conversation_cnt:
|
||||||
@@ -61,67 +55,22 @@ class ZhipuChatInit:
|
|||||||
messages.append(what_gpt_answer)
|
messages.append(what_gpt_answer)
|
||||||
return messages
|
return messages
|
||||||
|
|
||||||
@staticmethod
|
def __conversation_message_payload(self, inputs, llm_kwargs, history, system_prompt):
|
||||||
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=temperature,
|
temperature=llm_kwargs.get('temperature', 0.95) * 0.95, # 只能传默认的 temperature 和 top_p
|
||||||
top_p=top_p,
|
top_p=llm_kwargs.get('top_p', 0.7) * 0.7,
|
||||||
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:str, llm_kwargs:dict, history:list, system_prompt:str):
|
def generate_chat(self, inputs, llm_kwargs, history, system_prompt):
|
||||||
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,7 +1,6 @@
|
|||||||
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
|
||||||
@@ -215,7 +214,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:str, llm_kwargs:dict, history:list=[], sys_prompt:str="", observe_window:list=[], console_slience:bool=False):
|
def predict_no_ui_long_connection(inputs, llm_kwargs, history=[], sys_prompt="", observe_window=[], console_slience=False):
|
||||||
"""
|
"""
|
||||||
refer to request_llms/bridge_all.py
|
refer to request_llms/bridge_all.py
|
||||||
"""
|
"""
|
||||||
@@ -261,8 +260,7 @@ def get_local_llm_predict_fns(LLMSingletonClass, model_name, history_format='cla
|
|||||||
raise RuntimeError("程序终止。")
|
raise RuntimeError("程序终止。")
|
||||||
return response
|
return response
|
||||||
|
|
||||||
def predict(inputs:str, llm_kwargs:dict, plugin_kwargs:dict, chatbot:ChatBotWithCookies,
|
def predict(inputs, llm_kwargs, plugin_kwargs, chatbot, history=[], system_prompt='', stream=True, additional_fn=None):
|
||||||
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,409 +0,0 @@
|
|||||||
import json
|
|
||||||
import time
|
|
||||||
import logging
|
|
||||||
import traceback
|
|
||||||
import requests
|
|
||||||
|
|
||||||
# config_private.py放自己的秘密如API和代理网址
|
|
||||||
# 读取时首先看是否存在私密的config_private配置文件(不受git管控),如果有,则覆盖原config文件
|
|
||||||
from toolbox import (
|
|
||||||
get_conf,
|
|
||||||
update_ui,
|
|
||||||
is_the_upload_folder,
|
|
||||||
)
|
|
||||||
|
|
||||||
proxies, TIMEOUT_SECONDS, MAX_RETRY = get_conf(
|
|
||||||
"proxies", "TIMEOUT_SECONDS", "MAX_RETRY"
|
|
||||||
)
|
|
||||||
|
|
||||||
timeout_bot_msg = (
|
|
||||||
"[Local Message] Request timeout. Network error. Please check proxy settings in config.py."
|
|
||||||
+ "网络错误,检查代理服务器是否可用,以及代理设置的格式是否正确,格式须是[协议]://[地址]:[端口],缺一不可。"
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def get_full_error(chunk, stream_response):
|
|
||||||
"""
|
|
||||||
尝试获取完整的错误信息
|
|
||||||
"""
|
|
||||||
while True:
|
|
||||||
try:
|
|
||||||
chunk += next(stream_response)
|
|
||||||
except:
|
|
||||||
break
|
|
||||||
return chunk
|
|
||||||
|
|
||||||
|
|
||||||
def decode_chunk(chunk):
|
|
||||||
"""
|
|
||||||
用于解读"content"和"finish_reason"的内容
|
|
||||||
"""
|
|
||||||
chunk = chunk.decode()
|
|
||||||
respose = ""
|
|
||||||
finish_reason = "False"
|
|
||||||
try:
|
|
||||||
chunk = json.loads(chunk[6:])
|
|
||||||
except:
|
|
||||||
respose = ""
|
|
||||||
finish_reason = chunk
|
|
||||||
# 错误处理部分
|
|
||||||
if "error" in chunk:
|
|
||||||
respose = "API_ERROR"
|
|
||||||
try:
|
|
||||||
chunk = json.loads(chunk)
|
|
||||||
finish_reason = chunk["error"]["code"]
|
|
||||||
except:
|
|
||||||
finish_reason = "API_ERROR"
|
|
||||||
return respose, finish_reason
|
|
||||||
|
|
||||||
try:
|
|
||||||
respose = chunk["choices"][0]["delta"]["content"]
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
try:
|
|
||||||
finish_reason = chunk["choices"][0]["finish_reason"]
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
return respose, finish_reason
|
|
||||||
|
|
||||||
|
|
||||||
def generate_message(input, model, key, history, max_output_token, system_prompt, temperature):
|
|
||||||
"""
|
|
||||||
整合所有信息,选择LLM模型,生成http请求,为发送请求做准备
|
|
||||||
"""
|
|
||||||
api_key = f"Bearer {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"] = input
|
|
||||||
messages.append(what_i_ask_now)
|
|
||||||
playload = {
|
|
||||||
"model": model,
|
|
||||||
"messages": messages,
|
|
||||||
"temperature": temperature,
|
|
||||||
"stream": True,
|
|
||||||
"max_tokens": max_output_token,
|
|
||||||
}
|
|
||||||
try:
|
|
||||||
print(f" {model} : {conversation_cnt} : {input[:100]} ..........")
|
|
||||||
except:
|
|
||||||
print("输入中可能存在乱码。")
|
|
||||||
return headers, playload
|
|
||||||
|
|
||||||
|
|
||||||
def get_predict_function(
|
|
||||||
api_key_conf_name,
|
|
||||||
max_output_token,
|
|
||||||
disable_proxy = False
|
|
||||||
):
|
|
||||||
"""
|
|
||||||
为openai格式的API生成响应函数,其中传入参数:
|
|
||||||
api_key_conf_name:
|
|
||||||
`config.py`中此模型的APIKEY的名字,例如"YIMODEL_API_KEY"
|
|
||||||
max_output_token:
|
|
||||||
每次请求的最大token数量,例如对于01万物的yi-34b-chat-200k,其最大请求数为4096
|
|
||||||
⚠️请不要与模型的最大token数量相混淆。
|
|
||||||
disable_proxy:
|
|
||||||
是否使用代理,True为不使用,False为使用。
|
|
||||||
"""
|
|
||||||
|
|
||||||
APIKEY = get_conf(api_key_conf_name)
|
|
||||||
|
|
||||||
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 len(APIKEY) == 0:
|
|
||||||
raise RuntimeError(f"APIKEY为空,请检查配置文件的{APIKEY}")
|
|
||||||
if inputs == "":
|
|
||||||
inputs = "你好👋"
|
|
||||||
headers, playload = generate_message(
|
|
||||||
input=inputs,
|
|
||||||
model=llm_kwargs["llm_model"],
|
|
||||||
key=APIKEY,
|
|
||||||
history=history,
|
|
||||||
max_output_token=max_output_token,
|
|
||||||
system_prompt=sys_prompt,
|
|
||||||
temperature=llm_kwargs["temperature"],
|
|
||||||
)
|
|
||||||
retry = 0
|
|
||||||
while True:
|
|
||||||
try:
|
|
||||||
from .bridge_all import model_info
|
|
||||||
|
|
||||||
endpoint = model_info[llm_kwargs["llm_model"]]["endpoint"]
|
|
||||||
if not disable_proxy:
|
|
||||||
response = requests.post(
|
|
||||||
endpoint,
|
|
||||||
headers=headers,
|
|
||||||
proxies=proxies,
|
|
||||||
json=playload,
|
|
||||||
stream=True,
|
|
||||||
timeout=TIMEOUT_SECONDS,
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
response = requests.post(
|
|
||||||
endpoint,
|
|
||||||
headers=headers,
|
|
||||||
json=playload,
|
|
||||||
stream=True,
|
|
||||||
timeout=TIMEOUT_SECONDS,
|
|
||||||
)
|
|
||||||
break
|
|
||||||
except:
|
|
||||||
retry += 1
|
|
||||||
traceback.print_exc()
|
|
||||||
if retry > MAX_RETRY:
|
|
||||||
raise TimeoutError
|
|
||||||
if MAX_RETRY != 0:
|
|
||||||
print(f"请求超时,正在重试 ({retry}/{MAX_RETRY}) ……")
|
|
||||||
|
|
||||||
stream_response = response.iter_lines()
|
|
||||||
result = ""
|
|
||||||
finish_reason = ""
|
|
||||||
while True:
|
|
||||||
try:
|
|
||||||
chunk = next(stream_response)
|
|
||||||
except StopIteration:
|
|
||||||
if result == "":
|
|
||||||
raise RuntimeError(f"获得空的回复,可能原因:{finish_reason}")
|
|
||||||
break
|
|
||||||
except requests.exceptions.ConnectionError:
|
|
||||||
chunk = next(stream_response) # 失败了,重试一次?再失败就没办法了。
|
|
||||||
response_text, finish_reason = decode_chunk(chunk)
|
|
||||||
# 返回的数据流第一次为空,继续等待
|
|
||||||
if response_text == "" and finish_reason != "False":
|
|
||||||
continue
|
|
||||||
if response_text == "API_ERROR" and (
|
|
||||||
finish_reason != "False" or finish_reason != "stop"
|
|
||||||
):
|
|
||||||
chunk = get_full_error(chunk, stream_response)
|
|
||||||
chunk_decoded = chunk.decode()
|
|
||||||
print(chunk_decoded)
|
|
||||||
raise RuntimeError(
|
|
||||||
f"API异常,请检测终端输出。可能的原因是:{finish_reason}"
|
|
||||||
)
|
|
||||||
if chunk:
|
|
||||||
try:
|
|
||||||
if finish_reason == "stop":
|
|
||||||
logging.info(f"[response] {result}")
|
|
||||||
break
|
|
||||||
result += response_text
|
|
||||||
if not console_slience:
|
|
||||||
print(response_text, end="")
|
|
||||||
if observe_window is not None:
|
|
||||||
# 观测窗,把已经获取的数据显示出去
|
|
||||||
if len(observe_window) >= 1:
|
|
||||||
observe_window[0] += response_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
|
|
||||||
|
|
||||||
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(APIKEY) == 0:
|
|
||||||
raise RuntimeError(f"APIKEY为空,请检查配置文件的{APIKEY}")
|
|
||||||
if inputs == "":
|
|
||||||
inputs = "你好👋"
|
|
||||||
if additional_fn is not None:
|
|
||||||
from core_functional import handle_core_functionality
|
|
||||||
|
|
||||||
inputs, history = handle_core_functionality(
|
|
||||||
additional_fn, inputs, history, chatbot
|
|
||||||
)
|
|
||||||
logging.info(f"[raw_input] {inputs}")
|
|
||||||
chatbot.append((inputs, ""))
|
|
||||||
yield from update_ui(
|
|
||||||
chatbot=chatbot, history=history, msg="等待响应"
|
|
||||||
) # 刷新界面
|
|
||||||
|
|
||||||
# check mis-behavior
|
|
||||||
if is_the_upload_folder(inputs):
|
|
||||||
chatbot[-1] = (
|
|
||||||
inputs,
|
|
||||||
f"[Local Message] 检测到操作错误!当您上传文档之后,需点击“**函数插件区**”按钮进行处理,请勿点击“提交”按钮或者“基础功能区”按钮。",
|
|
||||||
)
|
|
||||||
yield from update_ui(
|
|
||||||
chatbot=chatbot, history=history, msg="正常"
|
|
||||||
) # 刷新界面
|
|
||||||
time.sleep(2)
|
|
||||||
|
|
||||||
headers, playload = generate_message(
|
|
||||||
input=inputs,
|
|
||||||
model=llm_kwargs["llm_model"],
|
|
||||||
key=APIKEY,
|
|
||||||
history=history,
|
|
||||||
max_output_token=max_output_token,
|
|
||||||
system_prompt=system_prompt,
|
|
||||||
temperature=llm_kwargs["temperature"],
|
|
||||||
)
|
|
||||||
|
|
||||||
history.append(inputs)
|
|
||||||
history.append("")
|
|
||||||
retry = 0
|
|
||||||
while True:
|
|
||||||
try:
|
|
||||||
from .bridge_all import model_info
|
|
||||||
|
|
||||||
endpoint = model_info[llm_kwargs["llm_model"]]["endpoint"]
|
|
||||||
if not disable_proxy:
|
|
||||||
response = requests.post(
|
|
||||||
endpoint,
|
|
||||||
headers=headers,
|
|
||||||
proxies=proxies,
|
|
||||||
json=playload,
|
|
||||||
stream=True,
|
|
||||||
timeout=TIMEOUT_SECONDS,
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
response = requests.post(
|
|
||||||
endpoint,
|
|
||||||
headers=headers,
|
|
||||||
json=playload,
|
|
||||||
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 = ""
|
|
||||||
|
|
||||||
stream_response = response.iter_lines()
|
|
||||||
while True:
|
|
||||||
try:
|
|
||||||
chunk = next(stream_response)
|
|
||||||
except StopIteration:
|
|
||||||
break
|
|
||||||
except requests.exceptions.ConnectionError:
|
|
||||||
chunk = next(stream_response) # 失败了,重试一次?再失败就没办法了。
|
|
||||||
response_text, finish_reason = decode_chunk(chunk)
|
|
||||||
# 返回的数据流第一次为空,继续等待
|
|
||||||
if response_text == "" and finish_reason != "False":
|
|
||||||
status_text = f"finish_reason: {finish_reason}"
|
|
||||||
yield from update_ui(
|
|
||||||
chatbot=chatbot, history=history, msg=status_text
|
|
||||||
)
|
|
||||||
continue
|
|
||||||
if chunk:
|
|
||||||
try:
|
|
||||||
if response_text == "API_ERROR" and (
|
|
||||||
finish_reason != "False" or finish_reason != "stop"
|
|
||||||
):
|
|
||||||
chunk = get_full_error(chunk, stream_response)
|
|
||||||
chunk_decoded = chunk.decode()
|
|
||||||
chatbot[-1] = (
|
|
||||||
chatbot[-1][0],
|
|
||||||
"[Local Message] {finish_reason},获得以下报错信息:\n"
|
|
||||||
+ chunk_decoded,
|
|
||||||
)
|
|
||||||
yield from update_ui(
|
|
||||||
chatbot=chatbot,
|
|
||||||
history=history,
|
|
||||||
msg="API异常:" + chunk_decoded,
|
|
||||||
) # 刷新界面
|
|
||||||
print(chunk_decoded)
|
|
||||||
return
|
|
||||||
|
|
||||||
if finish_reason == "stop":
|
|
||||||
logging.info(f"[response] {gpt_replying_buffer}")
|
|
||||||
break
|
|
||||||
status_text = f"finish_reason: {finish_reason}"
|
|
||||||
gpt_replying_buffer += response_text
|
|
||||||
# 如果这里抛出异常,一般是文本过长,详情见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()
|
|
||||||
chatbot[-1] = (
|
|
||||||
chatbot[-1][0],
|
|
||||||
"[Local Message] 解析错误,获得以下报错信息:\n" + chunk_decoded,
|
|
||||||
)
|
|
||||||
yield from update_ui(
|
|
||||||
chatbot=chatbot, history=history, msg="Json异常" + chunk_decoded
|
|
||||||
) # 刷新界面
|
|
||||||
print(chunk_decoded)
|
|
||||||
return
|
|
||||||
|
|
||||||
return predict_no_ui_long_connection, predict
|
|
||||||
@@ -1,15 +1,13 @@
|
|||||||
https://public.agent-matrix.com/publish/gradio-3.32.10-py3-none-any.whl
|
https://public.agent-matrix.com/publish/gradio-3.32.8-py3-none-any.whl
|
||||||
fastapi==0.110
|
|
||||||
gradio-client==0.8
|
gradio-client==0.8
|
||||||
pypdf2==2.12.1
|
pypdf2==2.12.1
|
||||||
zhipuai==2.0.1
|
zhipuai>=2
|
||||||
tiktoken>=0.3.3
|
tiktoken>=0.3.3
|
||||||
requests[socks]
|
requests[socks]
|
||||||
pydantic==2.5.2
|
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
|
||||||
@@ -18,15 +16,13 @@ prompt_toolkit
|
|||||||
latex2mathml
|
latex2mathml
|
||||||
python-docx
|
python-docx
|
||||||
mdtex2html
|
mdtex2html
|
||||||
dashscope
|
anthropic
|
||||||
pyautogen
|
pyautogen
|
||||||
colorama
|
colorama
|
||||||
Markdown
|
Markdown
|
||||||
pygments
|
pygments
|
||||||
edge-tts
|
|
||||||
pymupdf
|
pymupdf
|
||||||
openai
|
openai
|
||||||
rjsmin
|
|
||||||
arxiv
|
arxiv
|
||||||
numpy
|
numpy
|
||||||
rich
|
rich
|
||||||
|
|||||||
@@ -46,16 +46,6 @@ code_highlight_configs_block_mermaid = {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
mathpatterns = {
|
|
||||||
r"(?<!\\|\$)(\$)([^\$]+)(\$)": {"allow_multi_lines": False}, # $...$
|
|
||||||
r"(?<!\\)(\$\$)([^\$]+)(\$\$)": {"allow_multi_lines": True}, # $$...$$
|
|
||||||
r"(?<!\\)(\\\[)(.+?)(\\\])": {"allow_multi_lines": False}, # \[...\]
|
|
||||||
r'(?<!\\)(\\\()(.+?)(\\\))': {'allow_multi_lines': False}, # \(...\)
|
|
||||||
# r'(?<!\\)(\\begin{([a-z]+?\*?)})(.+?)(\\end{\2})': {'allow_multi_lines': True}, # \begin...\end
|
|
||||||
# r'(?<!\\)(\$`)([^`]+)(`\$)': {'allow_multi_lines': False}, # $`...`$
|
|
||||||
}
|
|
||||||
|
|
||||||
def tex2mathml_catch_exception(content, *args, **kwargs):
|
def tex2mathml_catch_exception(content, *args, **kwargs):
|
||||||
try:
|
try:
|
||||||
content = tex2mathml(content, *args, **kwargs)
|
content = tex2mathml(content, *args, **kwargs)
|
||||||
@@ -106,7 +96,14 @@ def is_equation(txt):
|
|||||||
return False
|
return False
|
||||||
if "$" not in txt and "\\[" not in txt:
|
if "$" not in txt and "\\[" not in txt:
|
||||||
return False
|
return False
|
||||||
|
mathpatterns = {
|
||||||
|
r"(?<!\\|\$)(\$)([^\$]+)(\$)": {"allow_multi_lines": False}, # $...$
|
||||||
|
r"(?<!\\)(\$\$)([^\$]+)(\$\$)": {"allow_multi_lines": True}, # $$...$$
|
||||||
|
r"(?<!\\)(\\\[)(.+?)(\\\])": {"allow_multi_lines": False}, # \[...\]
|
||||||
|
# r'(?<!\\)(\\\()(.+?)(\\\))': {'allow_multi_lines': False}, # \(...\)
|
||||||
|
# r'(?<!\\)(\\begin{([a-z]+?\*?)})(.+?)(\\end{\2})': {'allow_multi_lines': True}, # \begin...\end
|
||||||
|
# r'(?<!\\)(\$`)([^`]+)(`\$)': {'allow_multi_lines': False}, # $`...`$
|
||||||
|
}
|
||||||
matches = []
|
matches = []
|
||||||
for pattern, property in mathpatterns.items():
|
for pattern, property in mathpatterns.items():
|
||||||
flags = re.ASCII | re.DOTALL if property["allow_multi_lines"] else re.ASCII
|
flags = re.ASCII | re.DOTALL if property["allow_multi_lines"] else re.ASCII
|
||||||
@@ -210,118 +207,6 @@ def fix_code_segment_indent(txt):
|
|||||||
return txt
|
return txt
|
||||||
|
|
||||||
|
|
||||||
def fix_dollar_sticking_bug(txt):
|
|
||||||
"""
|
|
||||||
修复不标准的dollar公式符号的问题
|
|
||||||
"""
|
|
||||||
txt_result = ""
|
|
||||||
single_stack_height = 0
|
|
||||||
double_stack_height = 0
|
|
||||||
while True:
|
|
||||||
while True:
|
|
||||||
index = txt.find('$')
|
|
||||||
|
|
||||||
if index == -1:
|
|
||||||
txt_result += txt
|
|
||||||
return txt_result
|
|
||||||
|
|
||||||
if single_stack_height > 0:
|
|
||||||
if txt[:(index+1)].find('\n') > 0 or txt[:(index+1)].find('<td>') > 0 or txt[:(index+1)].find('</td>') > 0:
|
|
||||||
print('公式之中出现了异常 (Unexpect element in equation)')
|
|
||||||
single_stack_height = 0
|
|
||||||
txt_result += ' $'
|
|
||||||
continue
|
|
||||||
|
|
||||||
if double_stack_height > 0:
|
|
||||||
if txt[:(index+1)].find('\n\n') > 0:
|
|
||||||
print('公式之中出现了异常 (Unexpect element in equation)')
|
|
||||||
double_stack_height = 0
|
|
||||||
txt_result += '$$'
|
|
||||||
continue
|
|
||||||
|
|
||||||
is_double = (txt[index+1] == '$')
|
|
||||||
if is_double:
|
|
||||||
if single_stack_height != 0:
|
|
||||||
# add a padding
|
|
||||||
txt = txt[:(index+1)] + " " + txt[(index+1):]
|
|
||||||
continue
|
|
||||||
if double_stack_height == 0:
|
|
||||||
double_stack_height = 1
|
|
||||||
else:
|
|
||||||
double_stack_height = 0
|
|
||||||
txt_result += txt[:(index+2)]
|
|
||||||
txt = txt[(index+2):]
|
|
||||||
else:
|
|
||||||
if double_stack_height != 0:
|
|
||||||
# print(txt[:(index)])
|
|
||||||
print('发现异常嵌套公式')
|
|
||||||
if single_stack_height == 0:
|
|
||||||
single_stack_height = 1
|
|
||||||
else:
|
|
||||||
single_stack_height = 0
|
|
||||||
# print(txt[:(index)])
|
|
||||||
txt_result += txt[:(index+1)]
|
|
||||||
txt = txt[(index+1):]
|
|
||||||
break
|
|
||||||
|
|
||||||
|
|
||||||
def markdown_convertion_for_file(txt):
|
|
||||||
"""
|
|
||||||
将Markdown格式的文本转换为HTML格式。如果包含数学公式,则先将公式转换为HTML格式。
|
|
||||||
"""
|
|
||||||
from themes.theme import advanced_css
|
|
||||||
pre = f"""
|
|
||||||
<!DOCTYPE html><head><meta charset="utf-8"><title>GPT-Academic输出文档</title><style>{advanced_css}</style></head>
|
|
||||||
<body>
|
|
||||||
<div class="test_temp1" style="width:10%; height: 500px; float:left;"></div>
|
|
||||||
<div class="test_temp2" style="width:80%;padding: 40px;float:left;padding-left: 20px;padding-right: 20px;box-shadow: rgba(0, 0, 0, 0.2) 0px 0px 8px 8px;border-radius: 10px;">
|
|
||||||
<div class="markdown-body">
|
|
||||||
"""
|
|
||||||
suf = """
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="test_temp3" style="width:10%; height: 500px; float:left;"></div>
|
|
||||||
</body>
|
|
||||||
"""
|
|
||||||
|
|
||||||
if txt.startswith(pre) and txt.endswith(suf):
|
|
||||||
# print('警告,输入了已经经过转化的字符串,二次转化可能出问题')
|
|
||||||
return txt # 已经被转化过,不需要再次转化
|
|
||||||
|
|
||||||
find_equation_pattern = r'<script type="math/tex(?:.*?)>(.*?)</script>'
|
|
||||||
txt = fix_markdown_indent(txt)
|
|
||||||
convert_stage_1 = fix_dollar_sticking_bug(txt)
|
|
||||||
# convert everything to html format
|
|
||||||
convert_stage_2 = markdown.markdown(
|
|
||||||
text=convert_stage_1,
|
|
||||||
extensions=[
|
|
||||||
"sane_lists",
|
|
||||||
"tables",
|
|
||||||
"mdx_math",
|
|
||||||
"pymdownx.superfences",
|
|
||||||
"pymdownx.highlight",
|
|
||||||
],
|
|
||||||
extension_configs={**markdown_extension_configs, **code_highlight_configs},
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def repl_fn(match):
|
|
||||||
content = match.group(2)
|
|
||||||
return f'<script type="math/tex">{content}</script>'
|
|
||||||
|
|
||||||
pattern = "|".join([pattern for pattern, property in mathpatterns.items() if not property["allow_multi_lines"]])
|
|
||||||
pattern = re.compile(pattern, flags=re.ASCII)
|
|
||||||
convert_stage_3 = pattern.sub(repl_fn, convert_stage_2)
|
|
||||||
|
|
||||||
convert_stage_4 = markdown_bug_hunt(convert_stage_3)
|
|
||||||
|
|
||||||
# 2. convert to rendered equation
|
|
||||||
convert_stage_5, n = re.subn(
|
|
||||||
find_equation_pattern, replace_math_render, convert_stage_4, flags=re.DOTALL
|
|
||||||
)
|
|
||||||
# cat them together
|
|
||||||
return pre + convert_stage_5 + suf
|
|
||||||
|
|
||||||
@lru_cache(maxsize=128) # 使用 lru缓存 加快转换速度
|
@lru_cache(maxsize=128) # 使用 lru缓存 加快转换速度
|
||||||
def markdown_convertion(txt):
|
def markdown_convertion(txt):
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -1,25 +0,0 @@
|
|||||||
def is_full_width_char(ch):
|
|
||||||
"""判断给定的单个字符是否是全角字符"""
|
|
||||||
if '\u4e00' <= ch <= '\u9fff':
|
|
||||||
return True # 中文字符
|
|
||||||
if '\uff01' <= ch <= '\uff5e':
|
|
||||||
return True # 全角符号
|
|
||||||
if '\u3000' <= ch <= '\u303f':
|
|
||||||
return True # CJK标点符号
|
|
||||||
return False
|
|
||||||
|
|
||||||
def scolling_visual_effect(text, scroller_max_len):
|
|
||||||
text = text.\
|
|
||||||
replace('\n', '').replace('`', '.').replace(' ', '.').replace('<br/>', '.....').replace('$', '.')
|
|
||||||
place_take_cnt = 0
|
|
||||||
pointer = len(text) - 1
|
|
||||||
|
|
||||||
if len(text) < scroller_max_len:
|
|
||||||
return text
|
|
||||||
|
|
||||||
while place_take_cnt < scroller_max_len and pointer > 0:
|
|
||||||
if is_full_width_char(text[pointer]): place_take_cnt += 2
|
|
||||||
else: place_take_cnt += 1
|
|
||||||
pointer -= 1
|
|
||||||
|
|
||||||
return text[pointer:]
|
|
||||||
@@ -2,7 +2,7 @@ import importlib
|
|||||||
import time
|
import time
|
||||||
import os
|
import os
|
||||||
from functools import lru_cache
|
from functools import lru_cache
|
||||||
from shared_utils.colorful import print亮红, print亮绿, print亮蓝
|
from colorful import print亮红, print亮绿, print亮蓝
|
||||||
|
|
||||||
pj = os.path.join
|
pj = os.path.join
|
||||||
default_user_name = 'default_user'
|
default_user_name = 'default_user'
|
||||||
|
|||||||
@@ -15,13 +15,13 @@ import os
|
|||||||
|
|
||||||
def get_plugin_handle(plugin_name):
|
def get_plugin_handle(plugin_name):
|
||||||
"""
|
"""
|
||||||
e.g. plugin_name = 'crazy_functions.Markdown_Translate->Markdown翻译指定语言'
|
e.g. plugin_name = 'crazy_functions.批量Markdown翻译->Markdown翻译指定语言'
|
||||||
"""
|
"""
|
||||||
import importlib
|
import importlib
|
||||||
|
|
||||||
assert (
|
assert (
|
||||||
"->" in plugin_name
|
"->" in plugin_name
|
||||||
), "Example of plugin_name: crazy_functions.Markdown_Translate->Markdown翻译指定语言"
|
), "Example of plugin_name: crazy_functions.批量Markdown翻译->Markdown翻译指定语言"
|
||||||
module, fn_name = plugin_name.split("->")
|
module, fn_name = plugin_name.split("->")
|
||||||
f_hot_reload = getattr(importlib.import_module(module, fn_name), fn_name)
|
f_hot_reload = getattr(importlib.import_module(module, fn_name), fn_name)
|
||||||
return f_hot_reload
|
return f_hot_reload
|
||||||
|
|||||||
@@ -1,144 +0,0 @@
|
|||||||
import json
|
|
||||||
import base64
|
|
||||||
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
|
|
||||||
|
|
||||||
# cookies, web_cookie_cache = make_cookie_cache()
|
|
||||||
def make_cookie_cache():
|
|
||||||
# 定义 后端state(cookies)、前端(web_cookie_cache)两兄弟
|
|
||||||
import gradio as gr
|
|
||||||
from toolbox import load_chat_cookies
|
|
||||||
# 定义cookies的后端state
|
|
||||||
cookies = gr.State(load_chat_cookies())
|
|
||||||
# 定义cookies的一个孪生的前端存储区(隐藏)
|
|
||||||
web_cookie_cache = gr.Textbox(visible=False, elem_id="web_cookie_cache")
|
|
||||||
return cookies, web_cookie_cache
|
|
||||||
|
|
||||||
# history, history_cache, history_cache_update = make_history_cache()
|
|
||||||
def make_history_cache():
|
|
||||||
# 定义 后端state(history)、前端(history_cache)、后端setter(history_cache_update)三兄弟
|
|
||||||
import gradio as gr
|
|
||||||
# 定义history的后端state
|
|
||||||
history = gr.State([])
|
|
||||||
# 定义history的一个孪生的前端存储区(隐藏)
|
|
||||||
history_cache = gr.Textbox(visible=False, elem_id="history_cache")
|
|
||||||
# 定义history_cache->history的更新方法(隐藏)。在触发这个按钮时,会先执行js代码更新history_cache,然后再执行python代码更新history
|
|
||||||
def process_history_cache(history_cache):
|
|
||||||
return json.loads(history_cache)
|
|
||||||
# 另一种更简单的setter方法
|
|
||||||
history_cache_update = gr.Button("", elem_id="elem_update_history", visible=False).click(
|
|
||||||
process_history_cache, inputs=[history_cache], outputs=[history])
|
|
||||||
return history, history_cache, history_cache_update
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# """
|
|
||||||
# with gr.Row():
|
|
||||||
# txt = gr.Textbox(show_label=False, placeholder="Input question here.", elem_id='user_input_main').style(container=False)
|
|
||||||
# txtx = gr.Textbox(show_label=False, placeholder="Input question here.", elem_id='user_input_main').style(container=False)
|
|
||||||
# with gr.Row():
|
|
||||||
# btn_value = "Test"
|
|
||||||
# elem_id = "TestCase"
|
|
||||||
# variant = "primary"
|
|
||||||
# input_list = [txt, txtx]
|
|
||||||
# output_list = [txt, txtx]
|
|
||||||
# input_name_list = ["txt(input)", "txtx(input)"]
|
|
||||||
# output_name_list = ["txt", "txtx"]
|
|
||||||
# js_callback = """(txt, txtx)=>{console.log(txt); console.log(txtx);}"""
|
|
||||||
# def function(txt, txtx):
|
|
||||||
# return "booo", "goooo"
|
|
||||||
# create_button_with_javascript_callback(btn_value, elem_id, variant, js_callback, input_list, output_list, function, input_name_list, output_name_list)
|
|
||||||
# """
|
|
||||||
def create_button_with_javascript_callback(btn_value, elem_id, variant, js_callback, input_list, output_list, function, input_name_list, output_name_list):
|
|
||||||
import gradio as gr
|
|
||||||
middle_ware_component = gr.Textbox(visible=False, elem_id=elem_id+'_buffer')
|
|
||||||
def get_fn_wrap():
|
|
||||||
def fn_wrap(*args):
|
|
||||||
summary_dict = {}
|
|
||||||
for name, value in zip(input_name_list, args):
|
|
||||||
summary_dict.update({name: value})
|
|
||||||
|
|
||||||
res = function(*args)
|
|
||||||
|
|
||||||
for name, value in zip(output_name_list, res):
|
|
||||||
summary_dict.update({name: value})
|
|
||||||
|
|
||||||
summary = base64.b64encode(json.dumps(summary_dict).encode('utf8')).decode("utf-8")
|
|
||||||
return (*res, summary)
|
|
||||||
return fn_wrap
|
|
||||||
|
|
||||||
btn = gr.Button(btn_value, elem_id=elem_id, variant=variant)
|
|
||||||
call_args = ""
|
|
||||||
for name in output_name_list:
|
|
||||||
call_args += f"""Data["{name}"],"""
|
|
||||||
call_args = call_args.rstrip(",")
|
|
||||||
_js_callback = """
|
|
||||||
(base64MiddleString)=>{
|
|
||||||
console.log('hello')
|
|
||||||
const stringData = atob(base64MiddleString);
|
|
||||||
let Data = JSON.parse(stringData);
|
|
||||||
call = JS_CALLBACK_GEN;
|
|
||||||
call(CALL_ARGS);
|
|
||||||
}
|
|
||||||
""".replace("JS_CALLBACK_GEN", js_callback).replace("CALL_ARGS", call_args)
|
|
||||||
|
|
||||||
btn.click(get_fn_wrap(), input_list, output_list+[middle_ware_component]).then(None, [middle_ware_component], None, _js=_js_callback)
|
|
||||||
return btn
|
|
||||||
@@ -1,296 +0,0 @@
|
|||||||
"""
|
|
||||||
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 validate_path_safety(path_or_url, user):
|
|
||||||
from toolbox import get_conf, default_user_name
|
|
||||||
from toolbox import FriendlyException
|
|
||||||
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
|
|
||||||
elif path_or_url.startswith(PATH_PRIVATE_UPLOAD): # 用户的上传目录(按用户划分)
|
|
||||||
sensitive_path = PATH_PRIVATE_UPLOAD
|
|
||||||
elif path_or_url.startswith('tests') or path_or_url.startswith('build'): # 一个常用的测试目录
|
|
||||||
return True
|
|
||||||
else:
|
|
||||||
raise FriendlyException(f"输入文件的路径 ({path_or_url}) 存在,但位置非法。请将文件上传后再执行该任务。") # return False
|
|
||||||
if sensitive_path:
|
|
||||||
allowed_users = [user, 'autogen', 'arxiv_cache', default_user_name] # three user path that can be accessed
|
|
||||||
for user_allowed in allowed_users:
|
|
||||||
if f"{os.sep}".join(path_or_url.split(os.sep)[:2]) == os.path.join(sensitive_path, user_allowed):
|
|
||||||
return True
|
|
||||||
raise FriendlyException(f"输入文件的路径 ({path_or_url}) 存在,但属于其他用户。请将文件上传后再执行该任务。") # return False
|
|
||||||
return True
|
|
||||||
|
|
||||||
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', 'arxiv_cache', 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(5e-2)
|
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
from fastapi import Request, status
|
|
||||||
from fastapi.responses import FileResponse, RedirectResponse
|
|
||||||
@gradio_app.get("/academic_logout")
|
|
||||||
async def logout():
|
|
||||||
response = RedirectResponse(url=CUSTOM_PATH, status_code=status.HTTP_302_FOUND)
|
|
||||||
response.delete_cookie('access-token')
|
|
||||||
response.delete_cookie('access-token-unsecure')
|
|
||||||
return response
|
|
||||||
|
|
||||||
# --- --- enable TTS (text-to-speech) functionality --- ---
|
|
||||||
TTS_TYPE = get_conf("TTS_TYPE")
|
|
||||||
if TTS_TYPE != "DISABLE":
|
|
||||||
# audio generation functionality
|
|
||||||
import httpx
|
|
||||||
from fastapi import FastAPI, Request, HTTPException
|
|
||||||
from starlette.responses import Response
|
|
||||||
async def forward_request(request: Request, method: str) -> Response:
|
|
||||||
async with httpx.AsyncClient() as client:
|
|
||||||
try:
|
|
||||||
# Forward the request to the target service
|
|
||||||
if TTS_TYPE == "EDGE_TTS":
|
|
||||||
import tempfile
|
|
||||||
import edge_tts
|
|
||||||
import wave
|
|
||||||
import uuid
|
|
||||||
from pydub import AudioSegment
|
|
||||||
json = await request.json()
|
|
||||||
voice = get_conf("EDGE_TTS_VOICE")
|
|
||||||
tts = edge_tts.Communicate(text=json['text'], voice=voice)
|
|
||||||
temp_folder = tempfile.gettempdir()
|
|
||||||
temp_file_name = str(uuid.uuid4().hex)
|
|
||||||
temp_file = os.path.join(temp_folder, f'{temp_file_name}.mp3')
|
|
||||||
await tts.save(temp_file)
|
|
||||||
try:
|
|
||||||
mp3_audio = AudioSegment.from_file(temp_file, format="mp3")
|
|
||||||
mp3_audio.export(temp_file, format="wav")
|
|
||||||
with open(temp_file, 'rb') as wav_file: t = wav_file.read()
|
|
||||||
os.remove(temp_file)
|
|
||||||
return Response(content=t)
|
|
||||||
except:
|
|
||||||
raise RuntimeError("ffmpeg未安装,无法处理EdgeTTS音频。安装方法见`https://github.com/jiaaro/pydub#getting-ffmpeg-set-up`")
|
|
||||||
if TTS_TYPE == "LOCAL_SOVITS_API":
|
|
||||||
# Forward the request to the target service
|
|
||||||
TARGET_URL = get_conf("GPT_SOVITS_URL")
|
|
||||||
body = await request.body()
|
|
||||||
resp = await client.post(TARGET_URL, content=body, timeout=60)
|
|
||||||
# Return the response from the target service
|
|
||||||
return Response(content=resp.content, status_code=resp.status_code, headers=dict(resp.headers))
|
|
||||||
except httpx.RequestError as e:
|
|
||||||
raise HTTPException(status_code=400, detail=f"Request to the target service failed: {str(e)}")
|
|
||||||
@gradio_app.post("/vits")
|
|
||||||
async def forward_post_request(request: Request):
|
|
||||||
return await forward_request(request, "POST")
|
|
||||||
|
|
||||||
# --- --- 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 and block fastapi api reference routes --- ---
|
|
||||||
from starlette.responses import JSONResponse
|
|
||||||
if CUSTOM_PATH != '/':
|
|
||||||
from fastapi.responses import FileResponse
|
|
||||||
@fastapi_app.get("/favicon.ico")
|
|
||||||
async def favicon():
|
|
||||||
return FileResponse(app_block.favicon_path)
|
|
||||||
|
|
||||||
@fastapi_app.middleware("http")
|
|
||||||
async def middleware(request: Request, call_next):
|
|
||||||
if request.scope['path'] in ["/docs", "/redoc", "/openapi.json"]:
|
|
||||||
return JSONResponse(status_code=404, content={"message": "Not Found"})
|
|
||||||
response = await call_next(request)
|
|
||||||
return response
|
|
||||||
|
|
||||||
|
|
||||||
# --- --- 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()
|
|
||||||
@@ -104,14 +104,6 @@ def extract_archive(file_path, dest_dir):
|
|||||||
|
|
||||||
elif file_extension in [".tar", ".gz", ".bz2"]:
|
elif file_extension in [".tar", ".gz", ".bz2"]:
|
||||||
with tarfile.open(file_path, "r:*") as tarobj:
|
with tarfile.open(file_path, "r:*") as tarobj:
|
||||||
# 清理提取路径,移除任何不安全的元素
|
|
||||||
for member in tarobj.getmembers():
|
|
||||||
member_path = os.path.normpath(member.name)
|
|
||||||
full_path = os.path.join(dest_dir, member_path)
|
|
||||||
full_path = os.path.abspath(full_path)
|
|
||||||
if not full_path.startswith(os.path.abspath(dest_dir) + os.sep):
|
|
||||||
raise Exception(f"Attempted Path Traversal in {member.name}")
|
|
||||||
|
|
||||||
tarobj.extractall(path=dest_dir)
|
tarobj.extractall(path=dest_dir)
|
||||||
print("Successfully extracted tar archive to {}".format(dest_dir))
|
print("Successfully extracted tar archive to {}".format(dest_dir))
|
||||||
|
|
||||||
|
|||||||
某些文件未显示,因为此 diff 中更改的文件太多 显示更多
在新工单中引用
屏蔽一个用户