Merge remote-tracking branch 'origin/master'
# Conflicts: # main.py # themes/welcome.js
This commit is contained in:
commit
dca6fbbeeb
18
README.md
18
README.md
|
|
@ -173,26 +173,32 @@ flowchart TD
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
<details><summary>如果需要支持清华ChatGLM2/复旦MOSS/RWKV作为后端,请点击展开此处</summary>
|
<details><summary>如果需要支持清华ChatGLM系列/复旦MOSS/RWKV作为后端,请点击展开此处</summary>
|
||||||
<p>
|
<p>
|
||||||
|
|
||||||
【可选步骤】如果需要支持清华ChatGLM3/复旦MOSS作为后端,需要额外安装更多依赖(前提条件:熟悉Python + 用过Pytorch + 电脑配置够强):
|
【可选步骤】如果需要支持清华ChatGLM系列/复旦MOSS作为后端,需要额外安装更多依赖(前提条件:熟悉Python + 用过Pytorch + 电脑配置够强):
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
# 【可选步骤I】支持清华ChatGLM3。清华ChatGLM备注:如果遇到"Call ChatGLM fail 不能正常加载ChatGLM的参数" 错误,参考如下: 1:以上默认安装的为torch+cpu版,使用cuda需要卸载torch重新安装torch+cuda; 2:如因本机配置不够无法加载模型,可以修改request_llm/bridge_chatglm.py中的模型精度, 将 AutoTokenizer.from_pretrained("THUDM/chatglm-6b", trust_remote_code=True) 都修改为 AutoTokenizer.from_pretrained("THUDM/chatglm-6b-int4", trust_remote_code=True)
|
# 【可选步骤I】支持清华ChatGLM3。清华ChatGLM备注:如果遇到"Call ChatGLM fail 不能正常加载ChatGLM的参数" 错误,参考如下: 1:以上默认安装的为torch+cpu版,使用cuda需要卸载torch重新安装torch+cuda; 2:如因本机配置不够无法加载模型,可以修改request_llm/bridge_chatglm.py中的模型精度, 将 AutoTokenizer.from_pretrained("THUDM/chatglm-6b", trust_remote_code=True) 都修改为 AutoTokenizer.from_pretrained("THUDM/chatglm-6b-int4", trust_remote_code=True)
|
||||||
python -m pip install -r request_llms/requirements_chatglm.txt
|
python -m pip install -r request_llms/requirements_chatglm.txt
|
||||||
|
|
||||||
# 【可选步骤II】支持复旦MOSS
|
# 【可选步骤II】支持清华ChatGLM4 注意:此模型至少需要24G显存
|
||||||
|
python -m pip install -r request_llms/requirements_chatglm4.txt
|
||||||
|
# 可使用modelscope下载ChatGLM4模型
|
||||||
|
# pip install modelscope
|
||||||
|
# modelscope download --model ZhipuAI/glm-4-9b-chat --local_dir ./THUDM/glm-4-9b-chat
|
||||||
|
|
||||||
|
# 【可选步骤III】支持复旦MOSS
|
||||||
python -m pip install -r request_llms/requirements_moss.txt
|
python -m pip install -r request_llms/requirements_moss.txt
|
||||||
git clone --depth=1 https://github.com/OpenLMLab/MOSS.git request_llms/moss # 注意执行此行代码时,必须处于项目根路径
|
git clone --depth=1 https://github.com/OpenLMLab/MOSS.git request_llms/moss # 注意执行此行代码时,必须处于项目根路径
|
||||||
|
|
||||||
# 【可选步骤III】支持RWKV Runner
|
# 【可选步骤IV】支持RWKV Runner
|
||||||
参考wiki:https://github.com/binary-husky/gpt_academic/wiki/%E9%80%82%E9%85%8DRWKV-Runner
|
参考wiki:https://github.com/binary-husky/gpt_academic/wiki/%E9%80%82%E9%85%8DRWKV-Runner
|
||||||
|
|
||||||
# 【可选步骤IV】确保config.py配置文件的AVAIL_LLM_MODELS包含了期望的模型,目前支持的全部模型如下(jittorllms系列目前仅支持docker方案):
|
# 【可选步骤V】确保config.py配置文件的AVAIL_LLM_MODELS包含了期望的模型,目前支持的全部模型如下(jittorllms系列目前仅支持docker方案):
|
||||||
AVAIL_LLM_MODELS = ["gpt-3.5-turbo", "api2d-gpt-3.5-turbo", "gpt-4", "api2d-gpt-4", "chatglm", "moss"] # + ["jittorllms_rwkv", "jittorllms_pangualpha", "jittorllms_llama"]
|
AVAIL_LLM_MODELS = ["gpt-3.5-turbo", "api2d-gpt-3.5-turbo", "gpt-4", "api2d-gpt-4", "chatglm", "moss"] # + ["jittorllms_rwkv", "jittorllms_pangualpha", "jittorllms_llama"]
|
||||||
|
|
||||||
# 【可选步骤V】支持本地模型INT8,INT4量化(这里所指的模型本身不是量化版本,目前deepseek-coder支持,后面测试后会加入更多模型量化选择)
|
# 【可选步骤VI】支持本地模型INT8,INT4量化(这里所指的模型本身不是量化版本,目前deepseek-coder支持,后面测试后会加入更多模型量化选择)
|
||||||
pip install bitsandbyte
|
pip install bitsandbyte
|
||||||
# windows用户安装bitsandbytes需要使用下面bitsandbytes-windows-webui
|
# windows用户安装bitsandbytes需要使用下面bitsandbytes-windows-webui
|
||||||
python -m pip install bitsandbytes --prefer-binary --extra-index-url=https://jllllll.github.io/bitsandbytes-windows-webui
|
python -m pip install bitsandbytes --prefer-binary --extra-index-url=https://jllllll.github.io/bitsandbytes-windows-webui
|
||||||
|
|
|
||||||
10
config.py
10
config.py
|
|
@ -36,7 +36,7 @@ AVAIL_LLM_MODELS = ["gpt-4-1106-preview", "gpt-4-turbo-preview", "gpt-4-vision-p
|
||||||
"gpt-4o", "gpt-4o-mini", "gpt-4-turbo", "gpt-4-turbo-2024-04-09",
|
"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-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",
|
"gpt-4", "gpt-4-32k", "azure-gpt-4", "glm-4", "glm-4v", "glm-3-turbo",
|
||||||
"gemini-1.5-pro", "chatglm3"
|
"gemini-1.5-pro", "chatglm3", "chatglm4"
|
||||||
]
|
]
|
||||||
|
|
||||||
EMBEDDING_MODEL = "text-embedding-3-small"
|
EMBEDDING_MODEL = "text-embedding-3-small"
|
||||||
|
|
@ -55,6 +55,7 @@ EMBEDDING_MODEL = "text-embedding-3-small"
|
||||||
# "deepseek-chat" ,"deepseek-coder",
|
# "deepseek-chat" ,"deepseek-coder",
|
||||||
# "gemini-1.5-flash",
|
# "gemini-1.5-flash",
|
||||||
# "yi-34b-chat-0205","yi-34b-chat-200k","yi-large","yi-medium","yi-spark","yi-large-turbo","yi-large-preview",
|
# "yi-34b-chat-0205","yi-34b-chat-200k","yi-large","yi-medium","yi-spark","yi-large-turbo","yi-large-preview",
|
||||||
|
# "grok-beta",
|
||||||
# ]
|
# ]
|
||||||
# --- --- --- ---
|
# --- --- --- ---
|
||||||
# 此外,您还可以在接入one-api/vllm/ollama/Openroute时,
|
# 此外,您还可以在接入one-api/vllm/ollama/Openroute时,
|
||||||
|
|
@ -142,6 +143,9 @@ 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", "ERNIE-Speed-128K", "ERNIE-Speed-8K", "ERNIE-Lite-8K"
|
||||||
|
|
||||||
|
|
||||||
|
# 如果使用ChatGLM3或ChatGLM4本地模型,请把 LLM_MODEL="chatglm3" 或LLM_MODEL="chatglm4",并在此处指定模型路径
|
||||||
|
CHATGLM_LOCAL_MODEL_PATH = "THUDM/glm-4-9b-chat" # 例如"/home/hmp/ChatGLM3-6B/"
|
||||||
|
|
||||||
# 如果使用ChatGLM2微调模型,请把 LLM_MODEL="chatglmft",并在此处指定模型路径
|
# 如果使用ChatGLM2微调模型,请把 LLM_MODEL="chatglmft",并在此处指定模型路径
|
||||||
CHATGLM_PTUNING_CHECKPOINT = "" # 例如"/home/hmp/ChatGLM2-6B/ptuning/output/6b-pt-128-1e-2/checkpoint-100"
|
CHATGLM_PTUNING_CHECKPOINT = "" # 例如"/home/hmp/ChatGLM2-6B/ptuning/output/6b-pt-128-1e-2/checkpoint-100"
|
||||||
|
|
||||||
|
|
@ -234,7 +238,6 @@ MOONSHOT_API_KEY = ""
|
||||||
# 零一万物(Yi Model) API KEY
|
# 零一万物(Yi Model) API KEY
|
||||||
YIMODEL_API_KEY = ""
|
YIMODEL_API_KEY = ""
|
||||||
|
|
||||||
|
|
||||||
# 深度求索(DeepSeek) API KEY,默认请求地址为"https://api.deepseek.com/v1/chat/completions"
|
# 深度求索(DeepSeek) API KEY,默认请求地址为"https://api.deepseek.com/v1/chat/completions"
|
||||||
DEEPSEEK_API_KEY = ""
|
DEEPSEEK_API_KEY = ""
|
||||||
|
|
||||||
|
|
@ -242,6 +245,8 @@ DEEPSEEK_API_KEY = ""
|
||||||
# 紫东太初大模型 https://ai-maas.wair.ac.cn
|
# 紫东太初大模型 https://ai-maas.wair.ac.cn
|
||||||
TAICHU_API_KEY = ""
|
TAICHU_API_KEY = ""
|
||||||
|
|
||||||
|
# Grok API KEY
|
||||||
|
GROK_API_KEY = ""
|
||||||
|
|
||||||
# Mathpix 拥有执行PDF的OCR功能,但是需要注册账号
|
# Mathpix 拥有执行PDF的OCR功能,但是需要注册账号
|
||||||
MATHPIX_APPID = ""
|
MATHPIX_APPID = ""
|
||||||
|
|
@ -373,6 +378,7 @@ DAAS_SERVER_URLS = [ f"https://niuziniu-biligpt{i}.hf.space/stream" for i in ran
|
||||||
|
|
||||||
本地大模型示意图
|
本地大模型示意图
|
||||||
│
|
│
|
||||||
|
├── "chatglm4"
|
||||||
├── "chatglm3"
|
├── "chatglm3"
|
||||||
├── "chatglm"
|
├── "chatglm"
|
||||||
├── "chatglm_onnx"
|
├── "chatglm_onnx"
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,7 @@ def 批量翻译PDF文档(txt, llm_kwargs, plugin_kwargs, chatbot, history, syst
|
||||||
yield from 解析PDF_基于DOC2X(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, DOC2X_API_KEY, user_request)
|
yield from 解析PDF_基于DOC2X(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, DOC2X_API_KEY, user_request)
|
||||||
return
|
return
|
||||||
except:
|
except:
|
||||||
chatbot.append([None, f"DOC2X服务不可用,现在将执行效果稍差的旧版代码。{trimmed_format_exc_markdown()}"])
|
chatbot.append([None, f"DOC2X服务不可用,请检查报错详细。{trimmed_format_exc_markdown()}"])
|
||||||
yield from update_ui(chatbot=chatbot, history=history)
|
yield from update_ui(chatbot=chatbot, history=history)
|
||||||
|
|
||||||
if method == "GROBID":
|
if method == "GROBID":
|
||||||
|
|
|
||||||
|
|
@ -300,7 +300,8 @@ def Latex精细分解与转化(file_manifest, project_folder, llm_kwargs, plugin
|
||||||
write_html(pfg.sp_file_contents, pfg.sp_file_result, chatbot=chatbot, project_folder=project_folder)
|
write_html(pfg.sp_file_contents, pfg.sp_file_result, chatbot=chatbot, project_folder=project_folder)
|
||||||
|
|
||||||
# <-------- 写出文件 ---------->
|
# <-------- 写出文件 ---------->
|
||||||
msg = f"当前大语言模型: {llm_kwargs['llm_model']},当前语言模型温度设定: {llm_kwargs['temperature']}。"
|
model_name = llm_kwargs['llm_model'].replace('_', '\\_') # 替换LLM模型名称中的下划线为转义字符
|
||||||
|
msg = f"当前大语言模型: {model_name},当前语言模型温度设定: {llm_kwargs['temperature']}。"
|
||||||
final_tex = lps.merge_result(pfg.file_result, mode, msg)
|
final_tex = lps.merge_result(pfg.file_result, mode, msg)
|
||||||
objdump((lps, pfg.file_result, mode, msg), file=pj(project_folder,'merge_result.pkl'))
|
objdump((lps, pfg.file_result, mode, msg), file=pj(project_folder,'merge_result.pkl'))
|
||||||
|
|
||||||
|
|
@ -351,6 +352,41 @@ def 编译Latex(chatbot, history, main_file_original, main_file_modified, work_f
|
||||||
chatbot.append([f"正在编译PDF文档", f'编译已经开始。当前工作路径为{work_folder},如果程序停顿5分钟以上,请直接去该路径下取回翻译结果,或者重启之后再度尝试 ...']); yield from update_ui(chatbot=chatbot, history=history)
|
chatbot.append([f"正在编译PDF文档", f'编译已经开始。当前工作路径为{work_folder},如果程序停顿5分钟以上,请直接去该路径下取回翻译结果,或者重启之后再度尝试 ...']); yield from update_ui(chatbot=chatbot, history=history)
|
||||||
chatbot.append([f"正在编译PDF文档", '...']); yield from update_ui(chatbot=chatbot, history=history); time.sleep(1); chatbot[-1] = list(chatbot[-1]) # 刷新界面
|
chatbot.append([f"正在编译PDF文档", '...']); yield from update_ui(chatbot=chatbot, history=history); time.sleep(1); chatbot[-1] = list(chatbot[-1]) # 刷新界面
|
||||||
yield from update_ui_lastest_msg('编译已经开始...', chatbot, history) # 刷新Gradio前端界面
|
yield from update_ui_lastest_msg('编译已经开始...', chatbot, history) # 刷新Gradio前端界面
|
||||||
|
# 检查是否需要使用xelatex
|
||||||
|
def check_if_need_xelatex(tex_path):
|
||||||
|
try:
|
||||||
|
with open(tex_path, 'r', encoding='utf-8', errors='replace') as f:
|
||||||
|
content = f.read(5000)
|
||||||
|
# 检查是否有使用xelatex的宏包
|
||||||
|
need_xelatex = any(
|
||||||
|
pkg in content
|
||||||
|
for pkg in ['fontspec', 'xeCJK', 'xetex', 'unicode-math', 'xltxtra', 'xunicode']
|
||||||
|
)
|
||||||
|
if need_xelatex:
|
||||||
|
logger.info(f"检测到宏包需要xelatex编译, 切换至xelatex编译")
|
||||||
|
else:
|
||||||
|
logger.info(f"未检测到宏包需要xelatex编译, 使用pdflatex编译")
|
||||||
|
return need_xelatex
|
||||||
|
except Exception:
|
||||||
|
return False
|
||||||
|
|
||||||
|
# 根据编译器类型返回编译命令
|
||||||
|
def get_compile_command(compiler, filename):
|
||||||
|
compile_command = f'{compiler} -interaction=batchmode -file-line-error {filename}.tex'
|
||||||
|
logger.info('Latex 编译指令: ', compile_command)
|
||||||
|
return compile_command
|
||||||
|
|
||||||
|
# 确定使用的编译器
|
||||||
|
compiler = 'pdflatex'
|
||||||
|
if check_if_need_xelatex(pj(work_folder_modified, f'{main_file_modified}.tex')):
|
||||||
|
logger.info("检测到宏包需要xelatex编译,切换至xelatex编译")
|
||||||
|
# Check if xelatex is installed
|
||||||
|
try:
|
||||||
|
import subprocess
|
||||||
|
subprocess.run(['xelatex', '--version'], capture_output=True, check=True)
|
||||||
|
compiler = 'xelatex'
|
||||||
|
except (subprocess.CalledProcessError, FileNotFoundError):
|
||||||
|
raise RuntimeError("检测到需要使用xelatex编译,但系统中未安装xelatex。请先安装texlive或其他提供xelatex的LaTeX发行版。")
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
import os
|
import os
|
||||||
|
|
@ -361,10 +397,10 @@ def 编译Latex(chatbot, history, main_file_original, main_file_modified, work_f
|
||||||
|
|
||||||
# https://stackoverflow.com/questions/738755/dont-make-me-manually-abort-a-latex-compile-when-theres-an-error
|
# https://stackoverflow.com/questions/738755/dont-make-me-manually-abort-a-latex-compile-when-theres-an-error
|
||||||
yield from update_ui_lastest_msg(f'尝试第 {n_fix}/{max_try} 次编译, 编译原始PDF ...', chatbot, history) # 刷新Gradio前端界面
|
yield from update_ui_lastest_msg(f'尝试第 {n_fix}/{max_try} 次编译, 编译原始PDF ...', chatbot, history) # 刷新Gradio前端界面
|
||||||
ok = compile_latex_with_timeout(f'pdflatex -interaction=batchmode -file-line-error {main_file_original}.tex', work_folder_original)
|
ok = compile_latex_with_timeout(get_compile_command(compiler, main_file_original), work_folder_original)
|
||||||
|
|
||||||
yield from update_ui_lastest_msg(f'尝试第 {n_fix}/{max_try} 次编译, 编译转化后的PDF ...', chatbot, history) # 刷新Gradio前端界面
|
yield from update_ui_lastest_msg(f'尝试第 {n_fix}/{max_try} 次编译, 编译转化后的PDF ...', chatbot, history) # 刷新Gradio前端界面
|
||||||
ok = compile_latex_with_timeout(f'pdflatex -interaction=batchmode -file-line-error {main_file_modified}.tex', work_folder_modified)
|
ok = compile_latex_with_timeout(get_compile_command(compiler, main_file_modified), work_folder_modified)
|
||||||
|
|
||||||
if ok and os.path.exists(pj(work_folder_modified, f'{main_file_modified}.pdf')):
|
if ok and os.path.exists(pj(work_folder_modified, f'{main_file_modified}.pdf')):
|
||||||
# 只有第二步成功,才能继续下面的步骤
|
# 只有第二步成功,才能继续下面的步骤
|
||||||
|
|
@ -375,10 +411,10 @@ def 编译Latex(chatbot, history, main_file_original, main_file_modified, work_f
|
||||||
ok = compile_latex_with_timeout(f'bibtex {main_file_modified}.aux', work_folder_modified)
|
ok = compile_latex_with_timeout(f'bibtex {main_file_modified}.aux', work_folder_modified)
|
||||||
|
|
||||||
yield from update_ui_lastest_msg(f'尝试第 {n_fix}/{max_try} 次编译, 编译文献交叉引用 ...', chatbot, history) # 刷新Gradio前端界面
|
yield from update_ui_lastest_msg(f'尝试第 {n_fix}/{max_try} 次编译, 编译文献交叉引用 ...', chatbot, history) # 刷新Gradio前端界面
|
||||||
ok = compile_latex_with_timeout(f'pdflatex -interaction=batchmode -file-line-error {main_file_original}.tex', work_folder_original)
|
ok = compile_latex_with_timeout(get_compile_command(compiler, main_file_original), work_folder_original)
|
||||||
ok = compile_latex_with_timeout(f'pdflatex -interaction=batchmode -file-line-error {main_file_modified}.tex', work_folder_modified)
|
ok = compile_latex_with_timeout(get_compile_command(compiler, main_file_modified), work_folder_modified)
|
||||||
ok = compile_latex_with_timeout(f'pdflatex -interaction=batchmode -file-line-error {main_file_original}.tex', work_folder_original)
|
ok = compile_latex_with_timeout(get_compile_command(compiler, main_file_original), work_folder_original)
|
||||||
ok = compile_latex_with_timeout(f'pdflatex -interaction=batchmode -file-line-error {main_file_modified}.tex', work_folder_modified)
|
ok = compile_latex_with_timeout(get_compile_command(compiler, main_file_modified), work_folder_modified)
|
||||||
|
|
||||||
if mode!='translate_zh':
|
if mode!='translate_zh':
|
||||||
yield from update_ui_lastest_msg(f'尝试第 {n_fix}/{max_try} 次编译, 使用latexdiff生成论文转化前后对比 ...', chatbot, history) # 刷新Gradio前端界面
|
yield from update_ui_lastest_msg(f'尝试第 {n_fix}/{max_try} 次编译, 使用latexdiff生成论文转化前后对比 ...', chatbot, history) # 刷新Gradio前端界面
|
||||||
|
|
@ -386,10 +422,10 @@ def 编译Latex(chatbot, history, main_file_original, main_file_modified, work_f
|
||||||
ok = compile_latex_with_timeout(f'latexdiff --encoding=utf8 --append-safecmd=subfile {work_folder_original}/{main_file_original}.tex {work_folder_modified}/{main_file_modified}.tex --flatten > {work_folder}/merge_diff.tex', os.getcwd())
|
ok = compile_latex_with_timeout(f'latexdiff --encoding=utf8 --append-safecmd=subfile {work_folder_original}/{main_file_original}.tex {work_folder_modified}/{main_file_modified}.tex --flatten > {work_folder}/merge_diff.tex', os.getcwd())
|
||||||
|
|
||||||
yield from update_ui_lastest_msg(f'尝试第 {n_fix}/{max_try} 次编译, 正在编译对比PDF ...', chatbot, history) # 刷新Gradio前端界面
|
yield from update_ui_lastest_msg(f'尝试第 {n_fix}/{max_try} 次编译, 正在编译对比PDF ...', chatbot, history) # 刷新Gradio前端界面
|
||||||
ok = compile_latex_with_timeout(f'pdflatex -interaction=batchmode -file-line-error merge_diff.tex', work_folder)
|
ok = compile_latex_with_timeout(get_compile_command(compiler, 'merge_diff'), work_folder)
|
||||||
ok = compile_latex_with_timeout(f'bibtex merge_diff.aux', work_folder)
|
ok = compile_latex_with_timeout(f'bibtex merge_diff.aux', work_folder)
|
||||||
ok = compile_latex_with_timeout(f'pdflatex -interaction=batchmode -file-line-error merge_diff.tex', work_folder)
|
ok = compile_latex_with_timeout(get_compile_command(compiler, 'merge_diff'), work_folder)
|
||||||
ok = compile_latex_with_timeout(f'pdflatex -interaction=batchmode -file-line-error merge_diff.tex', work_folder)
|
ok = compile_latex_with_timeout(get_compile_command(compiler, 'merge_diff'), work_folder)
|
||||||
|
|
||||||
# <---------- 检查结果 ----------->
|
# <---------- 检查结果 ----------->
|
||||||
results_ = ""
|
results_ = ""
|
||||||
|
|
|
||||||
|
|
@ -6,75 +6,128 @@ from crazy_functions.crazy_utils import get_files_from_everything
|
||||||
from shared_utils.colorful import *
|
from shared_utils.colorful import *
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
import os
|
import os
|
||||||
|
import requests
|
||||||
import time
|
import time
|
||||||
|
|
||||||
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 retry_request(max_retries=3, delay=3):
|
||||||
|
"""
|
||||||
|
Decorator for retrying HTTP requests
|
||||||
|
Args:
|
||||||
|
max_retries: Maximum number of retry attempts
|
||||||
|
delay: Delay between retries in seconds
|
||||||
|
"""
|
||||||
|
|
||||||
|
def decorator(func):
|
||||||
|
def wrapper(*args, **kwargs):
|
||||||
|
for attempt in range(max_retries):
|
||||||
|
try:
|
||||||
|
return func(*args, **kwargs)
|
||||||
|
except Exception as e:
|
||||||
|
if attempt < max_retries - 1:
|
||||||
|
logger.error(
|
||||||
|
f"Request failed, retrying... ({attempt + 1}/{max_retries}) Error: {e}"
|
||||||
|
)
|
||||||
|
time.sleep(delay)
|
||||||
|
continue
|
||||||
|
raise e
|
||||||
|
return None
|
||||||
|
|
||||||
|
return wrapper
|
||||||
|
|
||||||
|
return decorator
|
||||||
|
|
||||||
|
|
||||||
|
@retry_request()
|
||||||
|
def make_request(method, url, **kwargs):
|
||||||
|
"""
|
||||||
|
Make HTTP request with retry mechanism
|
||||||
|
"""
|
||||||
|
return requests.request(method, url, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
def doc2x_api_response_status(response, uid=""):
|
||||||
|
"""
|
||||||
|
Check the status of Doc2x API response
|
||||||
|
Args:
|
||||||
|
response_data: Response object from Doc2x API
|
||||||
|
"""
|
||||||
|
response_json = response.json()
|
||||||
|
response_data = response_json.get("data", {})
|
||||||
|
code = response_json.get("code", "Unknown")
|
||||||
|
meg = response_data.get("message", response_json)
|
||||||
|
trace_id = response.headers.get("trace-id", "Failed to get trace-id")
|
||||||
|
if response.status_code != 200:
|
||||||
|
raise RuntimeError(
|
||||||
|
f"Doc2x return an error:\nTrace ID: {trace_id} {uid}\n{response.status_code} - {response_json}"
|
||||||
|
)
|
||||||
|
if code in ["parse_page_limit_exceeded", "parse_concurrency_limit"]:
|
||||||
|
raise RuntimeError(
|
||||||
|
f"Reached the limit of Doc2x:\nTrace ID: {trace_id} {uid}\n{code} - {meg}"
|
||||||
|
)
|
||||||
|
if code not in ["ok", "success"]:
|
||||||
|
raise RuntimeError(
|
||||||
|
f"Doc2x return an error:\nTrace ID: {trace_id} {uid}\n{code} - {meg}"
|
||||||
|
)
|
||||||
|
return response_data
|
||||||
|
|
||||||
|
|
||||||
def 解析PDF_DOC2X_转Latex(pdf_file_path):
|
def 解析PDF_DOC2X_转Latex(pdf_file_path):
|
||||||
zip_file_path, unzipped_folder = 解析PDF_DOC2X(pdf_file_path, format='tex')
|
zip_file_path, unzipped_folder = 解析PDF_DOC2X(pdf_file_path, format="tex")
|
||||||
return unzipped_folder
|
return unzipped_folder
|
||||||
|
|
||||||
|
|
||||||
def 解析PDF_DOC2X(pdf_file_path, format='tex'):
|
def 解析PDF_DOC2X(pdf_file_path, format="tex"):
|
||||||
"""
|
"""
|
||||||
format: 'tex', 'md', 'docx'
|
format: 'tex', 'md', 'docx'
|
||||||
"""
|
"""
|
||||||
import requests, json, os
|
|
||||||
DOC2X_API_KEY = get_conf('DOC2X_API_KEY')
|
DOC2X_API_KEY = get_conf("DOC2X_API_KEY")
|
||||||
latex_dir = get_log_folder(plugin_name="pdf_ocr_latex")
|
latex_dir = get_log_folder(plugin_name="pdf_ocr_latex")
|
||||||
markdown_dir = get_log_folder(plugin_name="pdf_ocr")
|
markdown_dir = get_log_folder(plugin_name="pdf_ocr")
|
||||||
doc2x_api_key = DOC2X_API_KEY
|
doc2x_api_key = DOC2X_API_KEY
|
||||||
|
|
||||||
|
# < ------ 第1步:预上传获取URL,然后上传文件 ------ >
|
||||||
|
logger.info("Doc2x 上传文件:预上传获取URL")
|
||||||
|
res = make_request(
|
||||||
|
"POST",
|
||||||
|
"https://v2.doc2x.noedgeai.com/api/v2/parse/preupload",
|
||||||
|
headers={"Authorization": "Bearer " + doc2x_api_key},
|
||||||
|
timeout=15,
|
||||||
|
)
|
||||||
|
res_data = doc2x_api_response_status(res)
|
||||||
|
upload_url = res_data["url"]
|
||||||
|
uuid = res_data["uid"]
|
||||||
|
|
||||||
# < ------ 第1步:上传 ------ >
|
logger.info("Doc2x 上传文件:上传文件")
|
||||||
logger.info("Doc2x 第1步:上传")
|
with open(pdf_file_path, "rb") as file:
|
||||||
with open(pdf_file_path, 'rb') as file:
|
res = make_request("PUT", upload_url, data=file, timeout=60)
|
||||||
res = requests.post(
|
res.raise_for_status()
|
||||||
"https://v2.doc2x.noedgeai.com/api/v2/parse/pdf",
|
|
||||||
headers={"Authorization": "Bearer " + doc2x_api_key},
|
|
||||||
data=file
|
|
||||||
)
|
|
||||||
# res_json = []
|
|
||||||
if res.status_code == 200:
|
|
||||||
res_json = res.json()
|
|
||||||
else:
|
|
||||||
raise RuntimeError(f"Doc2x return an error: {res.json()}")
|
|
||||||
uuid = res_json['data']['uid']
|
|
||||||
|
|
||||||
# < ------ 第2步:轮询等待 ------ >
|
# < ------ 第2步:轮询等待 ------ >
|
||||||
logger.info("Doc2x 第2步:轮询等待")
|
logger.info("Doc2x 处理文件中:轮询等待")
|
||||||
params = {'uid': uuid}
|
params = {"uid": uuid}
|
||||||
while True:
|
max_attempts = 60
|
||||||
res = requests.get(
|
attempt = 0
|
||||||
'https://v2.doc2x.noedgeai.com/api/v2/parse/status',
|
while attempt < max_attempts:
|
||||||
|
res = make_request(
|
||||||
|
"GET",
|
||||||
|
"https://v2.doc2x.noedgeai.com/api/v2/parse/status",
|
||||||
headers={"Authorization": "Bearer " + doc2x_api_key},
|
headers={"Authorization": "Bearer " + doc2x_api_key},
|
||||||
params=params
|
params=params,
|
||||||
|
timeout=15,
|
||||||
)
|
)
|
||||||
res_json = res.json()
|
res_data = doc2x_api_response_status(res)
|
||||||
if res_json['data']['status'] == "success":
|
if res_data["status"] == "success":
|
||||||
break
|
break
|
||||||
elif res_json['data']['status'] == "processing":
|
elif res_data["status"] == "processing":
|
||||||
time.sleep(3)
|
time.sleep(5)
|
||||||
logger.info(f"Doc2x is processing at {res_json['data']['progress']}%")
|
logger.info(f"Doc2x is processing at {res_data['progress']}%")
|
||||||
elif res_json['data']['status'] == "failed":
|
attempt += 1
|
||||||
raise RuntimeError(f"Doc2x return an error: {res_json}")
|
else:
|
||||||
|
raise RuntimeError(f"Doc2x return an error: {res_data}")
|
||||||
|
if attempt >= max_attempts:
|
||||||
|
raise RuntimeError("Doc2x processing timeout after maximum attempts")
|
||||||
|
|
||||||
# < ------ 第3步:提交转化 ------ >
|
# < ------ 第3步:提交转化 ------ >
|
||||||
logger.info("Doc2x 第3步:提交转化")
|
logger.info("Doc2x 第3步:提交转化")
|
||||||
|
|
@ -84,42 +137,44 @@ def 解析PDF_DOC2X(pdf_file_path, format='tex'):
|
||||||
"formula_mode": "dollar",
|
"formula_mode": "dollar",
|
||||||
"filename": "output"
|
"filename": "output"
|
||||||
}
|
}
|
||||||
res = requests.post(
|
res = make_request(
|
||||||
'https://v2.doc2x.noedgeai.com/api/v2/convert/parse',
|
"POST",
|
||||||
|
"https://v2.doc2x.noedgeai.com/api/v2/convert/parse",
|
||||||
headers={"Authorization": "Bearer " + doc2x_api_key},
|
headers={"Authorization": "Bearer " + doc2x_api_key},
|
||||||
json=data
|
json=data,
|
||||||
|
timeout=15,
|
||||||
)
|
)
|
||||||
if res.status_code == 200:
|
doc2x_api_response_status(res, uid=f"uid: {uuid}")
|
||||||
res_json = res.json()
|
|
||||||
else:
|
|
||||||
raise RuntimeError(f"Doc2x return an error: {res.json()}")
|
|
||||||
|
|
||||||
|
|
||||||
# < ------ 第4步:等待结果 ------ >
|
# < ------ 第4步:等待结果 ------ >
|
||||||
logger.info("Doc2x 第4步:等待结果")
|
logger.info("Doc2x 第4步:等待结果")
|
||||||
params = {'uid': uuid}
|
params = {"uid": uuid}
|
||||||
while True:
|
max_attempts = 36
|
||||||
res = requests.get(
|
attempt = 0
|
||||||
'https://v2.doc2x.noedgeai.com/api/v2/convert/parse/result',
|
while attempt < max_attempts:
|
||||||
|
res = make_request(
|
||||||
|
"GET",
|
||||||
|
"https://v2.doc2x.noedgeai.com/api/v2/convert/parse/result",
|
||||||
headers={"Authorization": "Bearer " + doc2x_api_key},
|
headers={"Authorization": "Bearer " + doc2x_api_key},
|
||||||
params=params
|
params=params,
|
||||||
|
timeout=15,
|
||||||
)
|
)
|
||||||
res_json = res.json()
|
res_data = doc2x_api_response_status(res, uid=f"uid: {uuid}")
|
||||||
if res_json['data']['status'] == "success":
|
if res_data["status"] == "success":
|
||||||
break
|
break
|
||||||
elif res_json['data']['status'] == "processing":
|
elif res_data["status"] == "processing":
|
||||||
time.sleep(3)
|
time.sleep(3)
|
||||||
logger.info(f"Doc2x still processing")
|
logger.info("Doc2x still processing to convert file")
|
||||||
elif res_json['data']['status'] == "failed":
|
attempt += 1
|
||||||
raise RuntimeError(f"Doc2x return an error: {res_json}")
|
if attempt >= max_attempts:
|
||||||
|
raise RuntimeError("Doc2x conversion timeout after maximum attempts")
|
||||||
|
|
||||||
# < ------ 第5步:最后的处理 ------ >
|
# < ------ 第5步:最后的处理 ------ >
|
||||||
logger.info("Doc2x 第5步:最后的处理")
|
logger.info("Doc2x 第5步:下载转换后的文件")
|
||||||
|
|
||||||
if format=='tex':
|
if format == "tex":
|
||||||
target_path = latex_dir
|
target_path = latex_dir
|
||||||
if format=='md':
|
if format == "md":
|
||||||
target_path = markdown_dir
|
target_path = markdown_dir
|
||||||
os.makedirs(target_path, exist_ok=True)
|
os.makedirs(target_path, exist_ok=True)
|
||||||
|
|
||||||
|
|
@ -127,17 +182,18 @@ def 解析PDF_DOC2X(pdf_file_path, format='tex'):
|
||||||
# < ------ 下载 ------ >
|
# < ------ 下载 ------ >
|
||||||
for attempt in range(max_attempt):
|
for attempt in range(max_attempt):
|
||||||
try:
|
try:
|
||||||
result_url = res_json['data']['url']
|
result_url = res_data["url"]
|
||||||
res = requests.get(result_url)
|
res = make_request("GET", result_url, timeout=60)
|
||||||
zip_path = os.path.join(target_path, gen_time_str() + '.zip')
|
zip_path = os.path.join(target_path, gen_time_str() + ".zip")
|
||||||
unzip_path = os.path.join(target_path, gen_time_str())
|
unzip_path = os.path.join(target_path, gen_time_str())
|
||||||
if res.status_code == 200:
|
if res.status_code == 200:
|
||||||
with open(zip_path, "wb") as f: f.write(res.content)
|
with open(zip_path, "wb") as f:
|
||||||
|
f.write(res.content)
|
||||||
else:
|
else:
|
||||||
raise RuntimeError(f"Doc2x return an error: {res.json()}")
|
raise RuntimeError(f"Doc2x return an error: {res.json()}")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
if attempt < max_attempt - 1:
|
if attempt < max_attempt - 1:
|
||||||
logger.error(f"Failed to download latex file, retrying... {e}")
|
logger.error(f"Failed to download uid = {uuid} file, retrying... {e}")
|
||||||
time.sleep(3)
|
time.sleep(3)
|
||||||
continue
|
continue
|
||||||
else:
|
else:
|
||||||
|
|
@ -145,22 +201,31 @@ def 解析PDF_DOC2X(pdf_file_path, format='tex'):
|
||||||
|
|
||||||
# < ------ 解压 ------ >
|
# < ------ 解压 ------ >
|
||||||
import zipfile
|
import zipfile
|
||||||
with zipfile.ZipFile(zip_path, 'r') as zip_ref:
|
with zipfile.ZipFile(zip_path, "r") as zip_ref:
|
||||||
zip_ref.extractall(unzip_path)
|
zip_ref.extractall(unzip_path)
|
||||||
return zip_path, unzip_path
|
return zip_path, unzip_path
|
||||||
|
|
||||||
|
|
||||||
def 解析PDF_DOC2X_单文件(fp, project_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, DOC2X_API_KEY, user_request):
|
def 解析PDF_DOC2X_单文件(
|
||||||
|
fp,
|
||||||
|
project_folder,
|
||||||
|
llm_kwargs,
|
||||||
|
plugin_kwargs,
|
||||||
|
chatbot,
|
||||||
|
history,
|
||||||
|
system_prompt,
|
||||||
|
DOC2X_API_KEY,
|
||||||
|
user_request,
|
||||||
|
):
|
||||||
def pdf2markdown(filepath):
|
def pdf2markdown(filepath):
|
||||||
chatbot.append((None, f"Doc2x 解析中"))
|
chatbot.append((None, f"Doc2x 解析中"))
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
||||||
|
|
||||||
md_zip_path, unzipped_folder = 解析PDF_DOC2X(filepath, format='md')
|
md_zip_path, unzipped_folder = 解析PDF_DOC2X(filepath, format="md")
|
||||||
|
|
||||||
promote_file_to_downloadzone(md_zip_path, chatbot=chatbot)
|
promote_file_to_downloadzone(md_zip_path, chatbot=chatbot)
|
||||||
chatbot.append((None, f"完成解析 {md_zip_path} ..."))
|
chatbot.append((None, f"完成解析 {md_zip_path} ..."))
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
||||||
return md_zip_path
|
return md_zip_path
|
||||||
|
|
||||||
def deliver_to_markdown_plugin(md_zip_path, user_request):
|
def deliver_to_markdown_plugin(md_zip_path, user_request):
|
||||||
|
|
@ -174,77 +239,97 @@ def 解析PDF_DOC2X_单文件(fp, project_folder, llm_kwargs, plugin_kwargs, cha
|
||||||
os.makedirs(target_path_base, exist_ok=True)
|
os.makedirs(target_path_base, exist_ok=True)
|
||||||
shutil.copyfile(md_zip_path, this_file_path)
|
shutil.copyfile(md_zip_path, this_file_path)
|
||||||
ex_folder = this_file_path + ".extract"
|
ex_folder = this_file_path + ".extract"
|
||||||
extract_archive(
|
extract_archive(file_path=this_file_path, dest_dir=ex_folder)
|
||||||
file_path=this_file_path, dest_dir=ex_folder
|
|
||||||
)
|
|
||||||
|
|
||||||
# edit markdown files
|
# edit markdown files
|
||||||
success, file_manifest, project_folder = get_files_from_everything(ex_folder, type='.md')
|
success, file_manifest, project_folder = get_files_from_everything(
|
||||||
|
ex_folder, type=".md"
|
||||||
|
)
|
||||||
for generated_fp in file_manifest:
|
for generated_fp in file_manifest:
|
||||||
# 修正一些公式问题
|
# 修正一些公式问题
|
||||||
with open(generated_fp, 'r', encoding='utf8') as f:
|
with open(generated_fp, "r", encoding="utf8") as f:
|
||||||
content = f.read()
|
content = f.read()
|
||||||
# 将公式中的\[ \]替换成$$
|
# 将公式中的\[ \]替换成$$
|
||||||
content = content.replace(r'\[', r'$$').replace(r'\]', r'$$')
|
content = content.replace(r"\[", r"$$").replace(r"\]", r"$$")
|
||||||
# 将公式中的\( \)替换成$
|
# 将公式中的\( \)替换成$
|
||||||
content = content.replace(r'\(', r'$').replace(r'\)', r'$')
|
content = content.replace(r"\(", r"$").replace(r"\)", r"$")
|
||||||
content = content.replace('```markdown', '\n').replace('```', '\n')
|
content = content.replace("```markdown", "\n").replace("```", "\n")
|
||||||
with open(generated_fp, 'w', encoding='utf8') as f:
|
with open(generated_fp, "w", encoding="utf8") as f:
|
||||||
f.write(content)
|
f.write(content)
|
||||||
promote_file_to_downloadzone(generated_fp, chatbot=chatbot)
|
promote_file_to_downloadzone(generated_fp, chatbot=chatbot)
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
||||||
|
|
||||||
# 生成在线预览html
|
# 生成在线预览html
|
||||||
file_name = '在线预览翻译(原文)' + gen_time_str() + '.html'
|
file_name = "在线预览翻译(原文)" + gen_time_str() + ".html"
|
||||||
preview_fp = os.path.join(ex_folder, file_name)
|
preview_fp = os.path.join(ex_folder, file_name)
|
||||||
from shared_utils.advanced_markdown_format import markdown_convertion_for_file
|
from shared_utils.advanced_markdown_format import (
|
||||||
|
markdown_convertion_for_file,
|
||||||
|
)
|
||||||
|
|
||||||
with open(generated_fp, "r", encoding="utf-8") as f:
|
with open(generated_fp, "r", encoding="utf-8") as f:
|
||||||
md = f.read()
|
md = f.read()
|
||||||
# # Markdown中使用不标准的表格,需要在表格前加上一个emoji,以便公式渲染
|
# # Markdown中使用不标准的表格,需要在表格前加上一个emoji,以便公式渲染
|
||||||
# md = re.sub(r'^<table>', r'.<table>', md, flags=re.MULTILINE)
|
# md = re.sub(r'^<table>', r'.<table>', md, flags=re.MULTILINE)
|
||||||
html = markdown_convertion_for_file(md)
|
html = markdown_convertion_for_file(md)
|
||||||
with open(preview_fp, "w", encoding="utf-8") as f: f.write(html)
|
with open(preview_fp, "w", encoding="utf-8") as f:
|
||||||
|
f.write(html)
|
||||||
chatbot.append([None, f"生成在线预览:{generate_file_link([preview_fp])}"])
|
chatbot.append([None, f"生成在线预览:{generate_file_link([preview_fp])}"])
|
||||||
promote_file_to_downloadzone(preview_fp, chatbot=chatbot)
|
promote_file_to_downloadzone(preview_fp, chatbot=chatbot)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
chatbot.append((None, f"调用Markdown插件 {ex_folder} ..."))
|
chatbot.append((None, f"调用Markdown插件 {ex_folder} ..."))
|
||||||
plugin_kwargs['markdown_expected_output_dir'] = ex_folder
|
plugin_kwargs["markdown_expected_output_dir"] = ex_folder
|
||||||
|
|
||||||
translated_f_name = 'translated_markdown.md'
|
translated_f_name = "translated_markdown.md"
|
||||||
generated_fp = plugin_kwargs['markdown_expected_output_path'] = os.path.join(ex_folder, translated_f_name)
|
generated_fp = plugin_kwargs["markdown_expected_output_path"] = os.path.join(
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
ex_folder, translated_f_name
|
||||||
yield from Markdown英译中(ex_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request)
|
)
|
||||||
|
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):
|
if os.path.exists(generated_fp):
|
||||||
# 修正一些公式问题
|
# 修正一些公式问题
|
||||||
with open(generated_fp, 'r', encoding='utf8') as f: content = f.read()
|
with open(generated_fp, "r", encoding="utf8") as f:
|
||||||
content = content.replace('```markdown', '\n').replace('```', '\n')
|
content = f.read()
|
||||||
|
content = content.replace("```markdown", "\n").replace("```", "\n")
|
||||||
# Markdown中使用不标准的表格,需要在表格前加上一个emoji,以便公式渲染
|
# Markdown中使用不标准的表格,需要在表格前加上一个emoji,以便公式渲染
|
||||||
# content = re.sub(r'^<table>', r'.<table>', content, flags=re.MULTILINE)
|
# content = re.sub(r'^<table>', r'.<table>', content, flags=re.MULTILINE)
|
||||||
with open(generated_fp, 'w', encoding='utf8') as f: f.write(content)
|
with open(generated_fp, "w", encoding="utf8") as f:
|
||||||
|
f.write(content)
|
||||||
# 生成在线预览html
|
# 生成在线预览html
|
||||||
file_name = '在线预览翻译' + gen_time_str() + '.html'
|
file_name = "在线预览翻译" + gen_time_str() + ".html"
|
||||||
preview_fp = os.path.join(ex_folder, file_name)
|
preview_fp = os.path.join(ex_folder, file_name)
|
||||||
from shared_utils.advanced_markdown_format import markdown_convertion_for_file
|
from shared_utils.advanced_markdown_format import (
|
||||||
|
markdown_convertion_for_file,
|
||||||
|
)
|
||||||
|
|
||||||
with open(generated_fp, "r", encoding="utf-8") as f:
|
with open(generated_fp, "r", encoding="utf-8") as f:
|
||||||
md = f.read()
|
md = f.read()
|
||||||
html = markdown_convertion_for_file(md)
|
html = markdown_convertion_for_file(md)
|
||||||
with open(preview_fp, "w", encoding="utf-8") as f: f.write(html)
|
with open(preview_fp, "w", encoding="utf-8") as f:
|
||||||
|
f.write(html)
|
||||||
promote_file_to_downloadzone(preview_fp, chatbot=chatbot)
|
promote_file_to_downloadzone(preview_fp, chatbot=chatbot)
|
||||||
# 生成包含图片的压缩包
|
# 生成包含图片的压缩包
|
||||||
dest_folder = get_log_folder(chatbot.get_user())
|
dest_folder = get_log_folder(chatbot.get_user())
|
||||||
zip_name = '翻译后的带图文档.zip'
|
zip_name = "翻译后的带图文档.zip"
|
||||||
zip_folder(source_folder=ex_folder, dest_folder=dest_folder, zip_name=zip_name)
|
zip_folder(
|
||||||
|
source_folder=ex_folder, dest_folder=dest_folder, zip_name=zip_name
|
||||||
|
)
|
||||||
zip_fp = os.path.join(dest_folder, zip_name)
|
zip_fp = os.path.join(dest_folder, zip_name)
|
||||||
promote_file_to_downloadzone(zip_fp, chatbot=chatbot)
|
promote_file_to_downloadzone(zip_fp, chatbot=chatbot)
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
||||||
|
|
||||||
md_zip_path = yield from pdf2markdown(fp)
|
md_zip_path = yield from pdf2markdown(fp)
|
||||||
yield from deliver_to_markdown_plugin(md_zip_path, user_request)
|
yield from deliver_to_markdown_plugin(md_zip_path, user_request)
|
||||||
|
|
||||||
|
|
||||||
def 解析PDF_基于DOC2X(file_manifest, *args):
|
def 解析PDF_基于DOC2X(file_manifest, *args):
|
||||||
for index, fp in enumerate(file_manifest):
|
for index, fp in enumerate(file_manifest):
|
||||||
yield from 解析PDF_DOC2X_单文件(fp, *args)
|
yield from 解析PDF_DOC2X_单文件(fp, *args)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
24
main.py
24
main.py
|
|
@ -59,8 +59,8 @@ def main():
|
||||||
# 如果WEB_PORT是-1, 则随机选取WEB端口
|
# 如果WEB_PORT是-1, 则随机选取WEB端口
|
||||||
PORT = find_free_port() if WEB_PORT <= 0 else WEB_PORT
|
PORT = find_free_port() if WEB_PORT <= 0 else WEB_PORT
|
||||||
from check_proxy import get_current_version
|
from check_proxy import get_current_version
|
||||||
from themes.theme import adjust_theme, advanced_css, theme_declaration, js_code_clear, js_code_reset, js_code_show_or_hide, js_code_show_or_hide_group2
|
from themes.theme import adjust_theme, advanced_css, theme_declaration, js_code_clear, js_code_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 js_code_for_toggle_darkmode
|
||||||
from themes.theme import load_dynamic_theme, to_cookie_str, from_cookie_str, assign_user_uuid
|
from themes.theme import load_dynamic_theme, to_cookie_str, from_cookie_str, assign_user_uuid
|
||||||
title_html = f"""
|
title_html = f"""
|
||||||
<h1 align="center">GPT Academic {get_current_version()}</h1>
|
<h1 align="center">GPT Academic {get_current_version()}</h1>
|
||||||
|
|
@ -112,7 +112,7 @@ def main():
|
||||||
with gr_L2(scale=2, elem_id="gpt-chat"):
|
with gr_L2(scale=2, elem_id="gpt-chat"):
|
||||||
chatbot = gr.Chatbot(label=f"当前模型:{LLM_MODEL}", elem_id="gpt-chatbot")
|
chatbot = gr.Chatbot(label=f"当前模型:{LLM_MODEL}", elem_id="gpt-chatbot")
|
||||||
if LAYOUT == "TOP-DOWN": chatbot.style(height=CHATBOT_HEIGHT)
|
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)三兄弟
|
history, _, _ = make_history_cache() # 定义 后端state(history)、前端(history_cache)、后端setter(history_cache_update)三兄弟
|
||||||
with gr_L2(scale=1, elem_id="gpt-panel"):
|
with gr_L2(scale=1, elem_id="gpt-panel"):
|
||||||
with gr.Accordion("输入区", open=True, elem_id="input-panel") as area_input_primary:
|
with gr.Accordion("输入区", open=True, elem_id="input-panel") as area_input_primary:
|
||||||
with gr.Row():
|
with gr.Row():
|
||||||
|
|
@ -151,7 +151,7 @@ def main():
|
||||||
gr.Markdown("<small>插件可读取“输入区”文本/路径作为参数(上传文件自动修正路径)</small>")
|
gr.Markdown("<small>插件可读取“输入区”文本/路径作为参数(上传文件自动修正路径)</small>")
|
||||||
with gr.Row(elem_id="input-plugin-group"):
|
with gr.Row(elem_id="input-plugin-group"):
|
||||||
plugin_group_sel = gr.Dropdown(choices=all_plugin_groups, label='', show_label=False, value=DEFAULT_FN_GROUPS,
|
plugin_group_sel = gr.Dropdown(choices=all_plugin_groups, label='', show_label=False, value=DEFAULT_FN_GROUPS,
|
||||||
multiselect=True, interactive=True, elem_classes='normal_mut_select').style(container=False)
|
multiselect=True, interactive=True, elem_classes='normal_mut_select').style(container=False)
|
||||||
with gr.Row():
|
with gr.Row():
|
||||||
for index, (k, plugin) in enumerate(plugins.items()):
|
for index, (k, plugin) in enumerate(plugins.items()):
|
||||||
if not plugin.get("AsButton", True): continue
|
if not plugin.get("AsButton", True): continue
|
||||||
|
|
@ -180,6 +180,7 @@ def main():
|
||||||
with gr.Accordion("点击展开“文件下载区”。", open=False) as area_file_up:
|
with gr.Accordion("点击展开“文件下载区”。", open=False) as area_file_up:
|
||||||
file_upload = gr.Files(label="任何文件, 推荐上传压缩文件(zip, tar)", file_count="multiple", elem_id="elem_upload")
|
file_upload = gr.Files(label="任何文件, 推荐上传压缩文件(zip, tar)", file_count="multiple", elem_id="elem_upload")
|
||||||
|
|
||||||
|
|
||||||
# 左上角工具栏定义
|
# 左上角工具栏定义
|
||||||
from themes.gui_toolbar import define_gui_toolbar
|
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 = \
|
checkboxes, checkboxes_2, max_length_sl, theme_dropdown, system_prompt, file_upload_2, md_dropdown, top_p, temperature = \
|
||||||
|
|
@ -190,6 +191,9 @@ def main():
|
||||||
area_input_secondary, txt2, area_customize, _, resetBtn2, clearBtn2, stopBtn2 = \
|
area_input_secondary, txt2, area_customize, _, resetBtn2, clearBtn2, stopBtn2 = \
|
||||||
define_gui_floating_menu(customize_btns, functional, predefined_btns, cookies, web_cookie_cache)
|
define_gui_floating_menu(customize_btns, functional, predefined_btns, cookies, web_cookie_cache)
|
||||||
|
|
||||||
|
# 浮动时间线定义
|
||||||
|
gr.Spark()
|
||||||
|
|
||||||
# 插件二级菜单的实现
|
# 插件二级菜单的实现
|
||||||
from themes.gui_advanced_plugin_class import define_gui_advanced_plugin_class
|
from themes.gui_advanced_plugin_class import define_gui_advanced_plugin_class
|
||||||
new_plugin_callback, route_switchy_bt_with_arg, usr_confirmed_arg = \
|
new_plugin_callback, route_switchy_bt_with_arg, usr_confirmed_arg = \
|
||||||
|
|
@ -228,11 +232,11 @@ def main():
|
||||||
multiplex_sel.select(
|
multiplex_sel.select(
|
||||||
None, [multiplex_sel], None, _js=f"""(multiplex_sel)=>run_multiplex_shift(multiplex_sel)""")
|
None, [multiplex_sel], None, _js=f"""(multiplex_sel)=>run_multiplex_shift(multiplex_sel)""")
|
||||||
cancel_handles.append(submit_btn.click(**predict_args))
|
cancel_handles.append(submit_btn.click(**predict_args))
|
||||||
resetBtn.click(None, None, [chatbot, history, status], _js=js_code_reset) # 先在前端快速清除chatbot&status
|
resetBtn.click(None, None, [chatbot, history, status], _js="""(a,b,c)=>clear_conversation(a,b,c)""") # 先在前端快速清除chatbot&status
|
||||||
resetBtn2.click(None, None, [chatbot, history, status], _js=js_code_reset) # 先在前端快速清除chatbot&status
|
resetBtn2.click(None, None, [chatbot, history, status], _js="""(a,b,c)=>clear_conversation(a,b,c)""") # 先在前端快速清除chatbot&status
|
||||||
reset_server_side_args = (lambda history: ([], [], "已重置", json.dumps(history)), [history], [chatbot, history, status, history_cache])
|
# reset_server_side_args = (lambda history: ([], [], "已重置"), [history], [chatbot, history, status])
|
||||||
resetBtn.click(*reset_server_side_args) # 再在后端清除history,把history转存history_cache备用
|
# resetBtn.click(*reset_server_side_args) # 再在后端清除history
|
||||||
resetBtn2.click(*reset_server_side_args) # 再在后端清除history,把history转存history_cache备用
|
# resetBtn2.click(*reset_server_side_args) # 再在后端清除history
|
||||||
clearBtn.click(None, None, [txt, txt2], _js=js_code_clear)
|
clearBtn.click(None, None, [txt, txt2], _js=js_code_clear)
|
||||||
clearBtn2.click(None, None, [txt, txt2], _js=js_code_clear)
|
clearBtn2.click(None, None, [txt, txt2], _js=js_code_clear)
|
||||||
if AUTO_CLEAR_TXT:
|
if AUTO_CLEAR_TXT:
|
||||||
|
|
@ -332,7 +336,7 @@ def main():
|
||||||
from shared_utils.cookie_manager import load_web_cookie_cache__fn_builder
|
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)
|
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],
|
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)
|
outputs = [web_cookie_cache, cookies, *customize_btns.values(), *predefined_btns.values()], _js="""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=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))
|
app_block.load(None, inputs=[], outputs=None, _js="""()=>{REP}""".replace("REP", register_advanced_plugin_init_arr))
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,9 @@ from .bridge_chatglm import predict as chatglm_ui
|
||||||
from .bridge_chatglm3 import predict_no_ui_long_connection as chatglm3_noui
|
from .bridge_chatglm3 import predict_no_ui_long_connection as chatglm3_noui
|
||||||
from .bridge_chatglm3 import predict as chatglm3_ui
|
from .bridge_chatglm3 import predict as chatglm3_ui
|
||||||
|
|
||||||
|
from .bridge_chatglm4 import predict_no_ui_long_connection as chatglm4_noui
|
||||||
|
from .bridge_chatglm4 import predict as chatglm4_ui
|
||||||
|
|
||||||
from .bridge_qianfan import predict_no_ui_long_connection as qianfan_noui
|
from .bridge_qianfan import predict_no_ui_long_connection as qianfan_noui
|
||||||
from .bridge_qianfan import predict as qianfan_ui
|
from .bridge_qianfan import predict as qianfan_ui
|
||||||
|
|
||||||
|
|
@ -76,6 +79,7 @@ cohere_endpoint = "https://api.cohere.ai/v1/chat"
|
||||||
ollama_endpoint = "http://localhost:11434/api/chat"
|
ollama_endpoint = "http://localhost:11434/api/chat"
|
||||||
yimodel_endpoint = "https://api.lingyiwanwu.com/v1/chat/completions"
|
yimodel_endpoint = "https://api.lingyiwanwu.com/v1/chat/completions"
|
||||||
deepseekapi_endpoint = "https://api.deepseek.com/v1/chat/completions"
|
deepseekapi_endpoint = "https://api.deepseek.com/v1/chat/completions"
|
||||||
|
grok_model_endpoint = "https://api.x.ai/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'
|
||||||
|
|
@ -97,6 +101,7 @@ if cohere_endpoint in API_URL_REDIRECT: cohere_endpoint = API_URL_REDIRECT[coher
|
||||||
if ollama_endpoint in API_URL_REDIRECT: ollama_endpoint = API_URL_REDIRECT[ollama_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 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]
|
if deepseekapi_endpoint in API_URL_REDIRECT: deepseekapi_endpoint = API_URL_REDIRECT[deepseekapi_endpoint]
|
||||||
|
if grok_model_endpoint in API_URL_REDIRECT: grok_model_endpoint = API_URL_REDIRECT[grok_model_endpoint]
|
||||||
|
|
||||||
# 获取tokenizer
|
# 获取tokenizer
|
||||||
tokenizer_gpt35 = LazyloadTiktoken("gpt-3.5-turbo")
|
tokenizer_gpt35 = LazyloadTiktoken("gpt-3.5-turbo")
|
||||||
|
|
@ -414,6 +419,7 @@ model_info = {
|
||||||
"token_cnt": get_token_num_gpt4,
|
"token_cnt": get_token_num_gpt4,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
# ChatGLM本地模型
|
||||||
# 将 chatglm 直接对齐到 chatglm2
|
# 将 chatglm 直接对齐到 chatglm2
|
||||||
"chatglm": {
|
"chatglm": {
|
||||||
"fn_with_ui": chatglm_ui,
|
"fn_with_ui": chatglm_ui,
|
||||||
|
|
@ -439,6 +445,14 @@ model_info = {
|
||||||
"tokenizer": tokenizer_gpt35,
|
"tokenizer": tokenizer_gpt35,
|
||||||
"token_cnt": get_token_num_gpt35,
|
"token_cnt": get_token_num_gpt35,
|
||||||
},
|
},
|
||||||
|
"chatglm4": {
|
||||||
|
"fn_with_ui": chatglm4_ui,
|
||||||
|
"fn_without_ui": chatglm4_noui,
|
||||||
|
"endpoint": None,
|
||||||
|
"max_token": 8192,
|
||||||
|
"tokenizer": tokenizer_gpt35,
|
||||||
|
"token_cnt": get_token_num_gpt35,
|
||||||
|
},
|
||||||
"qianfan": {
|
"qianfan": {
|
||||||
"fn_with_ui": qianfan_ui,
|
"fn_with_ui": qianfan_ui,
|
||||||
"fn_without_ui": qianfan_noui,
|
"fn_without_ui": qianfan_noui,
|
||||||
|
|
@ -886,6 +900,31 @@ if any(item in yi_models for item in AVAIL_LLM_MODELS):
|
||||||
})
|
})
|
||||||
except:
|
except:
|
||||||
logger.error(trimmed_format_exc())
|
logger.error(trimmed_format_exc())
|
||||||
|
|
||||||
|
|
||||||
|
# -=-=-=-=-=-=- Grok model from x.ai -=-=-=-=-=-=-
|
||||||
|
grok_models = ["grok-beta"]
|
||||||
|
if any(item in grok_models for item in AVAIL_LLM_MODELS):
|
||||||
|
try:
|
||||||
|
grok_beta_128k_noui, grok_beta_128k_ui = get_predict_function(
|
||||||
|
api_key_conf_name="GROK_API_KEY", max_output_token=8192, disable_proxy=False
|
||||||
|
)
|
||||||
|
|
||||||
|
model_info.update({
|
||||||
|
"grok-beta": {
|
||||||
|
"fn_with_ui": grok_beta_128k_ui,
|
||||||
|
"fn_without_ui": grok_beta_128k_noui,
|
||||||
|
"can_multi_thread": True,
|
||||||
|
"endpoint": grok_model_endpoint,
|
||||||
|
"max_token": 128000,
|
||||||
|
"tokenizer": tokenizer_gpt35,
|
||||||
|
"token_cnt": get_token_num_gpt35,
|
||||||
|
},
|
||||||
|
|
||||||
|
})
|
||||||
|
except:
|
||||||
|
logger.error(trimmed_format_exc())
|
||||||
|
|
||||||
# -=-=-=-=-=-=- 讯飞星火认知大模型 -=-=-=-=-=-=-
|
# -=-=-=-=-=-=- 讯飞星火认知大模型 -=-=-=-=-=-=-
|
||||||
if "spark" in AVAIL_LLM_MODELS:
|
if "spark" in AVAIL_LLM_MODELS:
|
||||||
try:
|
try:
|
||||||
|
|
|
||||||
|
|
@ -23,39 +23,33 @@ class GetGLM3Handle(LocalLLMHandle):
|
||||||
import os
|
import os
|
||||||
import platform
|
import platform
|
||||||
|
|
||||||
LOCAL_MODEL_QUANT, device = get_conf("LOCAL_MODEL_QUANT", "LOCAL_MODEL_DEVICE")
|
LOCAL_MODEL_PATH, LOCAL_MODEL_QUANT, device = get_conf("CHATGLM_LOCAL_MODEL_PATH", "LOCAL_MODEL_QUANT", "LOCAL_MODEL_DEVICE")
|
||||||
_model_name_ = "THUDM/chatglm3-6b"
|
model_path = LOCAL_MODEL_PATH
|
||||||
# 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"):
|
with ProxyNetworkActivate("Download_LLM"):
|
||||||
chatglm_tokenizer = AutoTokenizer.from_pretrained(
|
chatglm_tokenizer = AutoTokenizer.from_pretrained(
|
||||||
_model_name_, trust_remote_code=True
|
model_path, trust_remote_code=True
|
||||||
)
|
)
|
||||||
if device == "cpu":
|
if device == "cpu":
|
||||||
chatglm_model = AutoModel.from_pretrained(
|
chatglm_model = AutoModel.from_pretrained(
|
||||||
_model_name_,
|
model_path,
|
||||||
trust_remote_code=True,
|
trust_remote_code=True,
|
||||||
device="cpu",
|
device="cpu",
|
||||||
).float()
|
).float()
|
||||||
elif LOCAL_MODEL_QUANT == "INT4": # INT4
|
elif LOCAL_MODEL_QUANT == "INT4": # INT4
|
||||||
chatglm_model = AutoModel.from_pretrained(
|
chatglm_model = AutoModel.from_pretrained(
|
||||||
pretrained_model_name_or_path=_model_name_,
|
pretrained_model_name_or_path=model_path,
|
||||||
trust_remote_code=True,
|
trust_remote_code=True,
|
||||||
quantization_config=BitsAndBytesConfig(load_in_4bit=True),
|
quantization_config=BitsAndBytesConfig(load_in_4bit=True),
|
||||||
)
|
)
|
||||||
elif LOCAL_MODEL_QUANT == "INT8": # INT8
|
elif LOCAL_MODEL_QUANT == "INT8": # INT8
|
||||||
chatglm_model = AutoModel.from_pretrained(
|
chatglm_model = AutoModel.from_pretrained(
|
||||||
pretrained_model_name_or_path=_model_name_,
|
pretrained_model_name_or_path=model_path,
|
||||||
trust_remote_code=True,
|
trust_remote_code=True,
|
||||||
quantization_config=BitsAndBytesConfig(load_in_8bit=True),
|
quantization_config=BitsAndBytesConfig(load_in_8bit=True),
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
chatglm_model = AutoModel.from_pretrained(
|
chatglm_model = AutoModel.from_pretrained(
|
||||||
pretrained_model_name_or_path=_model_name_,
|
pretrained_model_name_or_path=model_path,
|
||||||
trust_remote_code=True,
|
trust_remote_code=True,
|
||||||
device="cuda",
|
device="cuda",
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,81 @@
|
||||||
|
model_name = "ChatGLM4"
|
||||||
|
cmd_to_install = """
|
||||||
|
`pip install -r request_llms/requirements_chatglm4.txt`
|
||||||
|
`pip install modelscope`
|
||||||
|
`modelscope download --model ZhipuAI/glm-4-9b-chat --local_dir ./THUDM/glm-4-9b-chat`
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
from toolbox import get_conf, ProxyNetworkActivate
|
||||||
|
from .local_llm_class import LocalLLMHandle, get_local_llm_predict_fns
|
||||||
|
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------------------------------------------------
|
||||||
|
# 🔌💻 Local Model
|
||||||
|
# ------------------------------------------------------------------------------------------------------------------------
|
||||||
|
class GetGLM4Handle(LocalLLMHandle):
|
||||||
|
|
||||||
|
def load_model_info(self):
|
||||||
|
# 🏃♂️🏃♂️🏃♂️ 子进程执行
|
||||||
|
self.model_name = model_name
|
||||||
|
self.cmd_to_install = cmd_to_install
|
||||||
|
|
||||||
|
def load_model_and_tokenizer(self):
|
||||||
|
# 🏃♂️🏃♂️🏃♂️ 子进程执行
|
||||||
|
import torch
|
||||||
|
from transformers import AutoModel, AutoModelForCausalLM, AutoTokenizer
|
||||||
|
import os
|
||||||
|
|
||||||
|
LOCAL_MODEL_PATH, device = get_conf("CHATGLM_LOCAL_MODEL_PATH", "LOCAL_MODEL_DEVICE")
|
||||||
|
model_path = LOCAL_MODEL_PATH
|
||||||
|
chatglm_tokenizer = AutoTokenizer.from_pretrained(model_path, trust_remote_code=True)
|
||||||
|
chatglm_model = AutoModelForCausalLM.from_pretrained(
|
||||||
|
model_path,
|
||||||
|
torch_dtype=torch.bfloat16,
|
||||||
|
low_cpu_mem_usage=True,
|
||||||
|
trust_remote_code=True,
|
||||||
|
device=device
|
||||||
|
).eval().to(device)
|
||||||
|
self._model = chatglm_model
|
||||||
|
self._tokenizer = chatglm_tokenizer
|
||||||
|
return self._model, self._tokenizer
|
||||||
|
|
||||||
|
|
||||||
|
def llm_stream_generator(self, **kwargs):
|
||||||
|
# 🏃♂️🏃♂️🏃♂️ 子进程执行
|
||||||
|
def adaptor(kwargs):
|
||||||
|
query = kwargs["query"]
|
||||||
|
max_length = kwargs["max_length"]
|
||||||
|
top_p = kwargs["top_p"]
|
||||||
|
temperature = kwargs["temperature"]
|
||||||
|
history = kwargs["history"]
|
||||||
|
return query, max_length, top_p, temperature, history
|
||||||
|
|
||||||
|
query, max_length, top_p, temperature, history = adaptor(kwargs)
|
||||||
|
inputs = self._tokenizer.apply_chat_template([{"role": "user", "content": query}],
|
||||||
|
add_generation_prompt=True,
|
||||||
|
tokenize=True,
|
||||||
|
return_tensors="pt",
|
||||||
|
return_dict=True
|
||||||
|
).to(self._model.device)
|
||||||
|
gen_kwargs = {"max_length": max_length, "do_sample": True, "top_k": top_p}
|
||||||
|
|
||||||
|
outputs = self._model.generate(**inputs, **gen_kwargs)
|
||||||
|
outputs = outputs[:, inputs['input_ids'].shape[1]:]
|
||||||
|
response = self._tokenizer.decode(outputs[0], skip_special_tokens=True)
|
||||||
|
yield response
|
||||||
|
|
||||||
|
def try_to_import_special_deps(self, **kwargs):
|
||||||
|
# import something that will raise error if the user does not install requirement_*.txt
|
||||||
|
# 🏃♂️🏃♂️🏃♂️ 主进程执行
|
||||||
|
import importlib
|
||||||
|
|
||||||
|
# importlib.import_module('modelscope')
|
||||||
|
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------------------------------------------------
|
||||||
|
# 🔌💻 GPT-Academic Interface
|
||||||
|
# ------------------------------------------------------------------------------------------------------------------------
|
||||||
|
predict_no_ui_long_connection, predict = get_local_llm_predict_fns(
|
||||||
|
GetGLM4Handle, model_name, history_format="chatglm3"
|
||||||
|
)
|
||||||
|
|
@ -75,7 +75,7 @@ def predict_no_ui_long_connection(inputs, llm_kwargs, history=[], sys_prompt="",
|
||||||
# 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']
|
endpoint = model_info[llm_kwargs['llm_model']]['endpoint']
|
||||||
response = requests.post(endpoint, headers=headers, proxies=proxies,
|
response = requests.post(endpoint, headers=headers, proxies=None,
|
||||||
json=payload, stream=True, timeout=TIMEOUT_SECONDS); break
|
json=payload, stream=True, timeout=TIMEOUT_SECONDS); break
|
||||||
except requests.exceptions.ReadTimeout as e:
|
except requests.exceptions.ReadTimeout as e:
|
||||||
retry += 1
|
retry += 1
|
||||||
|
|
@ -152,10 +152,12 @@ def predict(inputs, llm_kwargs, plugin_kwargs, chatbot, history=[], system_promp
|
||||||
history.append(inputs); history.append("")
|
history.append(inputs); history.append("")
|
||||||
|
|
||||||
retry = 0
|
retry = 0
|
||||||
|
if proxies is not None:
|
||||||
|
logger.error("Ollama不会使用代理服务器, 忽略了proxies的设置。")
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
# make a POST request to the API endpoint, stream=True
|
# make a POST request to the API endpoint, stream=True
|
||||||
response = requests.post(endpoint, headers=headers, proxies=proxies,
|
response = requests.post(endpoint, headers=headers, proxies=None,
|
||||||
json=payload, stream=True, timeout=TIMEOUT_SECONDS);break
|
json=payload, stream=True, timeout=TIMEOUT_SECONDS);break
|
||||||
except:
|
except:
|
||||||
retry += 1
|
retry += 1
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
protobuf
|
||||||
|
cpm_kernels
|
||||||
|
torch>=1.10
|
||||||
|
transformers>=4.44
|
||||||
|
mdtex2html
|
||||||
|
sentencepiece
|
||||||
|
accelerate
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
https://public.agent-matrix.com/publish/gradio-3.32.11-py3-none-any.whl
|
https://public.agent-matrix.com/publish/gradio-3.32.12-py3-none-any.whl
|
||||||
fastapi==0.110
|
fastapi==0.110
|
||||||
gradio-client==0.8
|
gradio-client==0.8
|
||||||
pypdf2==2.12.1
|
pypdf2==2.12.1
|
||||||
|
|
@ -25,7 +25,7 @@ pyautogen
|
||||||
colorama
|
colorama
|
||||||
Markdown
|
Markdown
|
||||||
pygments
|
pygments
|
||||||
edge-tts
|
edge-tts>=7.0.0
|
||||||
pymupdf
|
pymupdf
|
||||||
openai
|
openai
|
||||||
rjsmin
|
rjsmin
|
||||||
|
|
|
||||||
|
|
@ -77,16 +77,28 @@ def make_history_cache():
|
||||||
# 定义 后端state(history)、前端(history_cache)、后端setter(history_cache_update)三兄弟
|
# 定义 后端state(history)、前端(history_cache)、后端setter(history_cache_update)三兄弟
|
||||||
import gradio as gr
|
import gradio as gr
|
||||||
# 定义history的后端state
|
# 定义history的后端state
|
||||||
history = gr.State([])
|
# history = gr.State([])
|
||||||
# 定义history的一个孪生的前端存储区(隐藏)
|
history = gr.Textbox(visible=False, elem_id="history-ng")
|
||||||
history_cache = gr.Textbox(visible=False, elem_id="history_cache")
|
# # 定义history的一个孪生的前端存储区(隐藏)
|
||||||
# 定义history_cache->history的更新方法(隐藏)。在触发这个按钮时,会先执行js代码更新history_cache,然后再执行python代码更新history
|
# history_cache = gr.Textbox(visible=False, elem_id="history_cache")
|
||||||
def process_history_cache(history_cache):
|
# # 定义history_cache->history的更新方法(隐藏)。在触发这个按钮时,会先执行js代码更新history_cache,然后再执行python代码更新history
|
||||||
return json.loads(history_cache)
|
# def process_history_cache(history_cache):
|
||||||
# 另一种更简单的setter方法
|
# return json.loads(history_cache)
|
||||||
history_cache_update = gr.Button("", elem_id="elem_update_history", visible=False).click(
|
# # 另一种更简单的setter方法
|
||||||
process_history_cache, inputs=[history_cache], outputs=[history])
|
# history_cache_update = gr.Button("", elem_id="elem_update_history", visible=False).click(
|
||||||
return history, history_cache, history_cache_update
|
# process_history_cache, inputs=[history_cache], outputs=[history])
|
||||||
|
# # save history to history_cache
|
||||||
|
# def process_history_cache(history_cache):
|
||||||
|
# return json.dumps(history_cache)
|
||||||
|
# # 定义history->history_cache的更新方法(隐藏)
|
||||||
|
# def sync_history_cache(history):
|
||||||
|
# print("sync_history_cache", history)
|
||||||
|
# return json.dumps(history)
|
||||||
|
# # history.change(sync_history_cache, inputs=[history], outputs=[history_cache])
|
||||||
|
|
||||||
|
# # history_cache_sync = gr.Button("", elem_id="elem_sync_history", visible=False).click(
|
||||||
|
# # lambda history: (json.dumps(history)), inputs=[history_cache], outputs=[history])
|
||||||
|
return history, None, None
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
import edge_tts
|
||||||
|
import os
|
||||||
|
import httpx
|
||||||
|
from toolbox import get_conf
|
||||||
|
|
||||||
|
|
||||||
|
async def test_tts():
|
||||||
|
async with httpx.AsyncClient() as client:
|
||||||
|
try:
|
||||||
|
# Forward the request to the target service
|
||||||
|
import tempfile
|
||||||
|
import edge_tts
|
||||||
|
import wave
|
||||||
|
import uuid
|
||||||
|
from pydub import AudioSegment
|
||||||
|
voice = get_conf("EDGE_TTS_VOICE")
|
||||||
|
tts = edge_tts.Communicate(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()
|
||||||
|
except:
|
||||||
|
raise RuntimeError("ffmpeg未安装,无法处理EdgeTTS音频。安装方法见`https://github.com/jiaaro/pydub#getting-ffmpeg-set-up`")
|
||||||
|
except httpx.RequestError as e:
|
||||||
|
raise RuntimeError(f"请求失败: {e}")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
import asyncio
|
||||||
|
asyncio.run(test_tts())
|
||||||
|
|
@ -270,4 +270,9 @@
|
||||||
}
|
}
|
||||||
#gpt-submit-row #gpt-submit-dropdown > *:hover {
|
#gpt-submit-row #gpt-submit-dropdown > *:hover {
|
||||||
cursor: context-menu;
|
cursor: context-menu;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tooltip.svelte-p2nen8.svelte-p2nen8 {
|
||||||
|
box-shadow: 10px 10px 15px rgba(0, 0, 0, 0.5);
|
||||||
|
left: 10px;
|
||||||
}
|
}
|
||||||
320
themes/common.js
320
themes/common.js
|
|
@ -318,7 +318,7 @@ function addCopyButton(botElement, index, is_last_in_arr) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (enable_tts){
|
if (enable_tts) {
|
||||||
var audioButton = document.createElement('button');
|
var audioButton = document.createElement('button');
|
||||||
audioButton.classList.add('audio-toggle-btn');
|
audioButton.classList.add('audio-toggle-btn');
|
||||||
audioButton.innerHTML = audioIcon;
|
audioButton.innerHTML = audioIcon;
|
||||||
|
|
@ -346,7 +346,7 @@ function addCopyButton(botElement, index, is_last_in_arr) {
|
||||||
var messageBtnColumn = document.createElement('div');
|
var messageBtnColumn = document.createElement('div');
|
||||||
messageBtnColumn.classList.add('message-btn-row');
|
messageBtnColumn.classList.add('message-btn-row');
|
||||||
messageBtnColumn.appendChild(copyButton);
|
messageBtnColumn.appendChild(copyButton);
|
||||||
if (enable_tts){
|
if (enable_tts) {
|
||||||
messageBtnColumn.appendChild(audioButton);
|
messageBtnColumn.appendChild(audioButton);
|
||||||
}
|
}
|
||||||
botElement.appendChild(messageBtnColumn);
|
botElement.appendChild(messageBtnColumn);
|
||||||
|
|
@ -391,6 +391,8 @@ function chatbotContentChanged(attempt = 1, force = false) {
|
||||||
|
|
||||||
// Now pass both the message element and the is_last_in_arr boolean to addCopyButton
|
// Now pass both the message element and the is_last_in_arr boolean to addCopyButton
|
||||||
addCopyButton(message, index, is_last_in_arr);
|
addCopyButton(message, index, is_last_in_arr);
|
||||||
|
|
||||||
|
save_conversation_history();
|
||||||
});
|
});
|
||||||
// gradioApp().querySelectorAll('#gpt-chatbot .message-wrap .message.bot').forEach(addCopyButton);
|
// gradioApp().querySelectorAll('#gpt-chatbot .message-wrap .message.bot').forEach(addCopyButton);
|
||||||
}, i === 0 ? 0 : 200);
|
}, i === 0 ? 0 : 200);
|
||||||
|
|
@ -854,8 +856,7 @@ function limit_scroll_position() {
|
||||||
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||||
|
|
||||||
function loadLive2D() {
|
function loadLive2D() {
|
||||||
if (document.querySelector(".waifu") )
|
if (document.querySelector(".waifu")) {
|
||||||
{
|
|
||||||
$('.waifu').show();
|
$('.waifu').show();
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
|
|
@ -922,12 +923,12 @@ function gpt_academic_gradio_saveload(
|
||||||
if (save_or_load === "load") {
|
if (save_or_load === "load") {
|
||||||
let value = getCookie(cookie_key);
|
let value = getCookie(cookie_key);
|
||||||
if (value) {
|
if (value) {
|
||||||
console.log('加载cookie', elem_id, value)
|
// console.log('加载cookie', elem_id, value)
|
||||||
push_data_to_gradio_component(value, elem_id, load_type);
|
push_data_to_gradio_component(value, elem_id, load_type);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (load_default) {
|
if (load_default) {
|
||||||
console.log('加载cookie的默认值', elem_id, load_default_value)
|
// console.log('加载cookie的默认值', elem_id, load_default_value)
|
||||||
push_data_to_gradio_component(load_default_value, elem_id, load_type);
|
push_data_to_gradio_component(load_default_value, elem_id, load_type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -937,113 +938,149 @@ function gpt_academic_gradio_saveload(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function update_conversation_metadata() {
|
||||||
|
// Create a conversation UUID and timestamp
|
||||||
|
const conversationId = crypto.randomUUID();
|
||||||
|
const timestamp = new Date().toISOString();
|
||||||
|
const conversationData = {
|
||||||
|
id: conversationId,
|
||||||
|
timestamp: timestamp
|
||||||
|
};
|
||||||
|
// Save to cookie
|
||||||
|
setCookie("conversation_metadata", JSON.stringify(conversationData), 2);
|
||||||
|
// read from cookie
|
||||||
|
let conversation_metadata = getCookie("conversation_metadata");
|
||||||
|
// console.log("conversation_metadata", conversation_metadata);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Helper function to generate conversation preview
|
||||||
|
function generatePreview(conversation, timestamp, maxLength = 100) {
|
||||||
|
if (!conversation || conversation.length === 0) return "";
|
||||||
|
// Join all messages with dash separator
|
||||||
|
let preview = conversation.join("\n");
|
||||||
|
const readableDate = new Date(timestamp).toLocaleString();
|
||||||
|
preview = readableDate + "\n" + preview;
|
||||||
|
if (preview.length <= maxLength) return preview;
|
||||||
|
return preview.substring(0, maxLength) + "...";
|
||||||
|
}
|
||||||
|
|
||||||
|
async function save_conversation_history() {
|
||||||
|
// 505030475
|
||||||
|
let chatbot = await get_data_from_gradio_component('gpt-chatbot');
|
||||||
|
let history = await get_data_from_gradio_component('history-ng');
|
||||||
|
let conversation_metadata = getCookie("conversation_metadata");
|
||||||
|
conversation_metadata = JSON.parse(conversation_metadata);
|
||||||
|
// console.log("conversation_metadata", conversation_metadata);
|
||||||
|
let conversation = {
|
||||||
|
timestamp: conversation_metadata.timestamp,
|
||||||
|
id: conversation_metadata.id,
|
||||||
|
metadata: conversation_metadata,
|
||||||
|
conversation: chatbot,
|
||||||
|
history: history,
|
||||||
|
preview: generatePreview(JSON.parse(history), conversation_metadata.timestamp)
|
||||||
|
};
|
||||||
|
|
||||||
|
// Get existing conversation history from local storage
|
||||||
|
let conversation_history = [];
|
||||||
|
try {
|
||||||
|
const stored = localStorage.getItem('conversation_history');
|
||||||
|
if (stored) {
|
||||||
|
conversation_history = JSON.parse(stored);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
// console.error('Error reading conversation history from localStorage:', e);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find existing conversation with same ID
|
||||||
|
const existingIndex = conversation_history.findIndex(c => c.id === conversation.id);
|
||||||
|
|
||||||
|
if (existingIndex >= 0) {
|
||||||
|
// Update existing conversation
|
||||||
|
conversation_history[existingIndex] = conversation;
|
||||||
|
} else {
|
||||||
|
// Add new conversation
|
||||||
|
conversation_history.push(conversation);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort conversations by timestamp, newest first
|
||||||
|
conversation_history.sort((a, b) => {
|
||||||
|
const timeA = new Date(a.timestamp).getTime();
|
||||||
|
const timeB = new Date(b.timestamp).getTime();
|
||||||
|
return timeB - timeA;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Save back to local storage
|
||||||
|
try {
|
||||||
|
localStorage.setItem('conversation_history', JSON.stringify(conversation_history));
|
||||||
|
const LOCAL_STORAGE_UPDATED = "gptac_conversation_history_updated";
|
||||||
|
window.dispatchEvent(
|
||||||
|
new CustomEvent(LOCAL_STORAGE_UPDATED, {
|
||||||
|
detail: conversation_history
|
||||||
|
})
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Error saving conversation history to localStorage:', e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function restore_chat_from_local_storage(event) {
|
||||||
|
let conversation = event.detail;
|
||||||
|
push_data_to_gradio_component(conversation.conversation, "gpt-chatbot", "obj");
|
||||||
|
push_data_to_gradio_component(conversation.history, "history-ng", "obj");
|
||||||
|
// console.log("restore_chat_from_local_storage", conversation);
|
||||||
|
|
||||||
|
// Create a conversation UUID and timestamp
|
||||||
|
const conversationId = conversation.id;
|
||||||
|
const timestamp = conversation.timestamp;
|
||||||
|
const conversationData = {
|
||||||
|
id: conversationId,
|
||||||
|
timestamp: timestamp
|
||||||
|
};
|
||||||
|
// Save to cookie
|
||||||
|
setCookie("conversation_metadata", JSON.stringify(conversationData), 2);
|
||||||
|
// read from cookie
|
||||||
|
let conversation_metadata = getCookie("conversation_metadata");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function clear_conversation(a, b, c) {
|
||||||
|
update_conversation_metadata();
|
||||||
|
let stopButton = document.getElementById("elem_stop");
|
||||||
|
stopButton.click();
|
||||||
|
// console.log("clear_conversation");
|
||||||
|
return reset_conversation(a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
function reset_conversation(a, b) {
|
function reset_conversation(a, b) {
|
||||||
// console.log("js_code_reset");
|
// console.log("js_code_reset");
|
||||||
a = btoa(unescape(encodeURIComponent(JSON.stringify(a))));
|
a = btoa(unescape(encodeURIComponent(JSON.stringify(a))));
|
||||||
setCookie("js_previous_chat_cookie", a, 1);
|
setCookie("js_previous_chat_cookie", a, 1);
|
||||||
gen_restore_btn();
|
b = btoa(unescape(encodeURIComponent(JSON.stringify(b))));
|
||||||
|
setCookie("js_previous_history_cookie", b, 1);
|
||||||
|
// gen_restore_btn();
|
||||||
return [[], [], "已重置"];
|
return [[], [], "已重置"];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// clear -> 将 history 缓存至 history_cache -> 点击复原 -> restore_previous_chat() -> 触发elem_update_history -> 读取 history_cache
|
// clear -> 将 history 缓存至 history_cache -> 点击复原 -> restore_previous_chat() -> 触发elem_update_history -> 读取 history_cache
|
||||||
function restore_previous_chat() {
|
function restore_previous_chat() {
|
||||||
console.log("restore_previous_chat");
|
// console.log("restore_previous_chat");
|
||||||
let chat = getCookie("js_previous_chat_cookie");
|
let chat = getCookie("js_previous_chat_cookie");
|
||||||
chat = JSON.parse(decodeURIComponent(escape(atob(chat))));
|
chat = JSON.parse(decodeURIComponent(escape(atob(chat))));
|
||||||
push_data_to_gradio_component(chat, "gpt-chatbot", "obj");
|
push_data_to_gradio_component(chat, "gpt-chatbot", "obj");
|
||||||
document.querySelector("#elem_update_history").click(); // in order to call set_history_gr_state, and send history state to server
|
let history = getCookie("js_previous_history_cookie");
|
||||||
|
history = JSON.parse(decodeURIComponent(escape(atob(history))));
|
||||||
|
push_data_to_gradio_component(history, "history-ng", "obj");
|
||||||
|
// document.querySelector("#elem_update_history").click(); // in order to call set_history_gr_state, and send history state to server
|
||||||
}
|
}
|
||||||
|
|
||||||
function gen_restore_btn() {
|
|
||||||
|
|
||||||
|
|
||||||
// 创建按钮元素
|
|
||||||
const button = document.createElement('div');
|
|
||||||
// const recvIcon = '<span><svg stroke="currentColor" fill="none" stroke-width="2" viewBox="0 0 24 24" stroke-linecap="round" stroke-linejoin="round" height=".8em" width=".8em" xmlns="http://www.w3.org/2000/svg"><polyline points="20 6 9 17 4 12"></polyline></svg></span>';
|
|
||||||
const rec_svg = '<svg t="1714361184567" style="transform:translate(1px, 2.5px)" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4389" width="35" height="35"><path d="M320 512h384v64H320zM320 384h384v64H320zM320 640h192v64H320z" p-id="4390" fill="#ffffff"></path><path d="M863.7 544c-1.9 44-11.4 86.8-28.5 127.2-18.5 43.8-45.1 83.2-78.9 117-33.8 33.8-73.2 60.4-117 78.9C593.9 886.3 545.7 896 496 896s-97.9-9.7-143.2-28.9c-43.8-18.5-83.2-45.1-117-78.9-33.8-33.8-60.4-73.2-78.9-117C137.7 625.9 128 577.7 128 528s9.7-97.9 28.9-143.2c18.5-43.8 45.1-83.2 78.9-117s73.2-60.4 117-78.9C398.1 169.7 446.3 160 496 160s97.9 9.7 143.2 28.9c23.5 9.9 45.8 22.2 66.5 36.7l-119.7 20 9.9 59.4 161.6-27 59.4-9.9-9.9-59.4-27-161.5-59.4 9.9 19 114.2C670.3 123.8 586.4 96 496 96 257.4 96 64 289.4 64 528s193.4 432 432 432c233.2 0 423.3-184.8 431.7-416h-64z" p-id="4391" fill="#ffffff"></path></svg>'
|
|
||||||
const recvIcon = '<span>' + rec_svg + '</span>';
|
|
||||||
|
|
||||||
// 设置按钮的样式和属性
|
|
||||||
button.id = 'floatingButton';
|
|
||||||
button.className = 'glow';
|
|
||||||
button.style.textAlign = 'center';
|
|
||||||
button.style.position = 'fixed';
|
|
||||||
button.style.bottom = '10px';
|
|
||||||
button.style.left = '10px';
|
|
||||||
button.style.width = '50px';
|
|
||||||
button.style.height = '50px';
|
|
||||||
button.style.borderRadius = '50%';
|
|
||||||
button.style.backgroundColor = '#007bff';
|
|
||||||
button.style.color = 'white';
|
|
||||||
button.style.display = 'flex';
|
|
||||||
button.style.alignItems = 'center';
|
|
||||||
button.style.justifyContent = 'center';
|
|
||||||
button.style.cursor = 'pointer';
|
|
||||||
button.style.transition = 'all 0.3s ease';
|
|
||||||
button.style.boxShadow = '0 0 10px rgba(0,0,0,0.2)';
|
|
||||||
|
|
||||||
button.innerHTML = recvIcon;
|
|
||||||
|
|
||||||
// 添加发光动画的关键帧
|
|
||||||
const styleSheet = document.createElement('style');
|
|
||||||
styleSheet.id = 'floatingButtonStyle';
|
|
||||||
styleSheet.innerText = `
|
|
||||||
@keyframes glow {
|
|
||||||
from {
|
|
||||||
box-shadow: 0 0 10px rgba(0,0,0,0.2);
|
|
||||||
}
|
|
||||||
to {
|
|
||||||
box-shadow: 0 0 13px rgba(0,0,0,0.5);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#floatingButton.glow {
|
|
||||||
animation: glow 1s infinite alternate;
|
|
||||||
}
|
|
||||||
#floatingButton:hover {
|
|
||||||
transform: scale(1.2);
|
|
||||||
box-shadow: 0 0 20px rgba(0,0,0,0.4);
|
|
||||||
}
|
|
||||||
#floatingButton.disappearing {
|
|
||||||
animation: shrinkAndDisappear 0.5s forwards;
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
// only add when not exist
|
|
||||||
if (!document.getElementById('recvButtonStyle'))
|
|
||||||
{
|
|
||||||
document.head.appendChild(styleSheet);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 鼠标悬停和移开的事件监听器
|
|
||||||
button.addEventListener('mouseover', function () {
|
|
||||||
this.textContent = "还原\n对话";
|
|
||||||
});
|
|
||||||
|
|
||||||
button.addEventListener('mouseout', function () {
|
|
||||||
this.innerHTML = recvIcon;
|
|
||||||
});
|
|
||||||
|
|
||||||
// 点击事件监听器
|
|
||||||
button.addEventListener('click', function () {
|
|
||||||
// 添加一个类来触发缩小和消失的动画
|
|
||||||
restore_previous_chat();
|
|
||||||
this.classList.add('disappearing');
|
|
||||||
// 在动画结束后移除按钮
|
|
||||||
document.body.removeChild(this);
|
|
||||||
});
|
|
||||||
// only add when not exist
|
|
||||||
if (!document.getElementById('recvButton'))
|
|
||||||
{
|
|
||||||
document.body.appendChild(button);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 将按钮添加到页面中
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
async function on_plugin_exe_complete(fn_name) {
|
async function on_plugin_exe_complete(fn_name) {
|
||||||
console.log(fn_name);
|
// console.log(fn_name);
|
||||||
if (fn_name === "保存当前的对话") {
|
if (fn_name === "保存当前的对话") {
|
||||||
// get chat profile path
|
// get chat profile path
|
||||||
let chatbot = await get_data_from_gradio_component('gpt-chatbot');
|
let chatbot = await get_data_from_gradio_component('gpt-chatbot');
|
||||||
|
|
@ -1062,15 +1099,15 @@ async function on_plugin_exe_complete(fn_name) {
|
||||||
}
|
}
|
||||||
let href = get_href(may_have_chat_profile_info);
|
let href = get_href(may_have_chat_profile_info);
|
||||||
if (href) {
|
if (href) {
|
||||||
const cleanedHref = href.replace('file=', ''); // /home/fuqingxu/chatgpt_academic/gpt_log/default_user/chat_history/GPT-Academic对话存档2024-04-12-00-35-06.html
|
const cleanedHref = href.replace('file=', ''); // gpt_log/default_user/chat_history/GPT-Academic对话存档2024-04-12-00-35-06.html
|
||||||
console.log(cleanedHref);
|
// console.log(cleanedHref);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
async function generate_menu(guiBase64String, btnName){
|
async function generate_menu(guiBase64String, btnName) {
|
||||||
// assign the button and menu data
|
// assign the button and menu data
|
||||||
push_data_to_gradio_component(guiBase64String, "invisible_current_pop_up_plugin_arg", "string");
|
push_data_to_gradio_component(guiBase64String, "invisible_current_pop_up_plugin_arg", "string");
|
||||||
push_data_to_gradio_component(btnName, "invisible_callback_btn_for_plugin_exe", "string");
|
push_data_to_gradio_component(btnName, "invisible_callback_btn_for_plugin_exe", "string");
|
||||||
|
|
@ -1104,22 +1141,22 @@ async function generate_menu(guiBase64String, btnName){
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
//////////////////////////////////// Textbox ////////////////////////////////////
|
//////////////////////////////////// Textbox ////////////////////////////////////
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
if (gui_args[key].type=='string'){ // PLUGIN_ARG_MENU
|
if (gui_args[key].type == 'string') { // PLUGIN_ARG_MENU
|
||||||
const component_name = "plugin_arg_txt_" + text_cnt;
|
const component_name = "plugin_arg_txt_" + text_cnt;
|
||||||
push_data_to_gradio_component({
|
push_data_to_gradio_component({
|
||||||
visible: true,
|
visible: true,
|
||||||
label: gui_args[key].title + "(" + gui_args[key].description + ")",
|
label: gui_args[key].title + "(" + gui_args[key].description + ")",
|
||||||
// label: gui_args[key].title,
|
// label: gui_args[key].title,
|
||||||
placeholder: gui_args[key].description,
|
placeholder: gui_args[key].description,
|
||||||
__type__: 'update'
|
__type__: 'update'
|
||||||
}, component_name, "obj");
|
}, component_name, "obj");
|
||||||
if (key === "main_input"){
|
if (key === "main_input") {
|
||||||
// 为了与旧插件兼容,生成菜单时,自动加载输入栏的值
|
// 为了与旧插件兼容,生成菜单时,自动加载输入栏的值
|
||||||
let current_main_input = await get_data_from_gradio_component('user_input_main');
|
let current_main_input = await get_data_from_gradio_component('user_input_main');
|
||||||
let current_main_input_2 = await get_data_from_gradio_component('user_input_float');
|
let current_main_input_2 = await get_data_from_gradio_component('user_input_float');
|
||||||
push_data_to_gradio_component(current_main_input + current_main_input_2, component_name, "obj");
|
push_data_to_gradio_component(current_main_input + current_main_input_2, component_name, "obj");
|
||||||
}
|
}
|
||||||
else if (key === "advanced_arg"){
|
else if (key === "advanced_arg") {
|
||||||
// 为了与旧插件兼容,生成菜单时,自动加载旧高级参数输入区的值
|
// 为了与旧插件兼容,生成菜单时,自动加载旧高级参数输入区的值
|
||||||
let advance_arg_input_legacy = await get_data_from_gradio_component('advance_arg_input_legacy');
|
let advance_arg_input_legacy = await get_data_from_gradio_component('advance_arg_input_legacy');
|
||||||
push_data_to_gradio_component(advance_arg_input_legacy, component_name, "obj");
|
push_data_to_gradio_component(advance_arg_input_legacy, component_name, "obj");
|
||||||
|
|
@ -1134,12 +1171,12 @@ async function generate_menu(guiBase64String, btnName){
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
//////////////////////////////////// Dropdown ////////////////////////////////////
|
//////////////////////////////////// Dropdown ////////////////////////////////////
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
if (gui_args[key].type=='dropdown'){ // PLUGIN_ARG_MENU
|
if (gui_args[key].type == 'dropdown') { // PLUGIN_ARG_MENU
|
||||||
const component_name = "plugin_arg_drop_" + dropdown_cnt;
|
const component_name = "plugin_arg_drop_" + dropdown_cnt;
|
||||||
push_data_to_gradio_component({
|
push_data_to_gradio_component({
|
||||||
visible: true,
|
visible: true,
|
||||||
choices: gui_args[key].options,
|
choices: gui_args[key].options,
|
||||||
label: gui_args[key].title + "(" + gui_args[key].description + ")",
|
label: gui_args[key].title + "(" + gui_args[key].description + ")",
|
||||||
// label: gui_args[key].title,
|
// label: gui_args[key].title,
|
||||||
placeholder: gui_args[key].description,
|
placeholder: gui_args[key].description,
|
||||||
__type__: 'update'
|
__type__: 'update'
|
||||||
|
|
@ -1154,7 +1191,7 @@ async function generate_menu(guiBase64String, btnName){
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function execute_current_pop_up_plugin(){
|
async function execute_current_pop_up_plugin() {
|
||||||
let guiBase64String = await get_data_from_gradio_component('invisible_current_pop_up_plugin_arg');
|
let guiBase64String = await get_data_from_gradio_component('invisible_current_pop_up_plugin_arg');
|
||||||
const stringData = atob(guiBase64String);
|
const stringData = atob(guiBase64String);
|
||||||
let guiJsonData = JSON.parse(stringData);
|
let guiJsonData = JSON.parse(stringData);
|
||||||
|
|
@ -1170,8 +1207,8 @@ async function execute_current_pop_up_plugin(){
|
||||||
let text_cnt = 0;
|
let text_cnt = 0;
|
||||||
for (const key in gui_args) {
|
for (const key in gui_args) {
|
||||||
if (gui_args.hasOwnProperty(key)) {
|
if (gui_args.hasOwnProperty(key)) {
|
||||||
if (gui_args[key].type=='string'){ // PLUGIN_ARG_MENU
|
if (gui_args[key].type == 'string') { // PLUGIN_ARG_MENU
|
||||||
corrisponding_elem_id = "plugin_arg_txt_"+text_cnt
|
corrisponding_elem_id = "plugin_arg_txt_" + text_cnt
|
||||||
gui_args[key].user_confirmed_value = await get_data_from_gradio_component(corrisponding_elem_id);
|
gui_args[key].user_confirmed_value = await get_data_from_gradio_component(corrisponding_elem_id);
|
||||||
text_cnt += 1;
|
text_cnt += 1;
|
||||||
}
|
}
|
||||||
|
|
@ -1180,8 +1217,8 @@ async function execute_current_pop_up_plugin(){
|
||||||
let dropdown_cnt = 0;
|
let dropdown_cnt = 0;
|
||||||
for (const key in gui_args) {
|
for (const key in gui_args) {
|
||||||
if (gui_args.hasOwnProperty(key)) {
|
if (gui_args.hasOwnProperty(key)) {
|
||||||
if (gui_args[key].type=='dropdown'){ // PLUGIN_ARG_MENU
|
if (gui_args[key].type == 'dropdown') { // PLUGIN_ARG_MENU
|
||||||
corrisponding_elem_id = "plugin_arg_drop_"+dropdown_cnt
|
corrisponding_elem_id = "plugin_arg_drop_" + dropdown_cnt
|
||||||
gui_args[key].user_confirmed_value = await get_data_from_gradio_component(corrisponding_elem_id);
|
gui_args[key].user_confirmed_value = await get_data_from_gradio_component(corrisponding_elem_id);
|
||||||
dropdown_cnt += 1;
|
dropdown_cnt += 1;
|
||||||
}
|
}
|
||||||
|
|
@ -1200,29 +1237,29 @@ async function execute_current_pop_up_plugin(){
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function hide_all_elem(){
|
function hide_all_elem() {
|
||||||
// PLUGIN_ARG_MENU
|
// PLUGIN_ARG_MENU
|
||||||
for (text_cnt = 0; text_cnt < 8; text_cnt++){
|
for (text_cnt = 0; text_cnt < 8; text_cnt++) {
|
||||||
push_data_to_gradio_component({
|
push_data_to_gradio_component({
|
||||||
visible: false,
|
visible: false,
|
||||||
label: "",
|
label: "",
|
||||||
__type__: 'update'
|
__type__: 'update'
|
||||||
}, "plugin_arg_txt_"+text_cnt, "obj");
|
}, "plugin_arg_txt_" + text_cnt, "obj");
|
||||||
document.getElementById("plugin_arg_txt_"+text_cnt).parentNode.parentNode.style.display = 'none';
|
document.getElementById("plugin_arg_txt_" + text_cnt).parentNode.parentNode.style.display = 'none';
|
||||||
}
|
}
|
||||||
for (dropdown_cnt = 0; dropdown_cnt < 8; dropdown_cnt++){
|
for (dropdown_cnt = 0; dropdown_cnt < 8; dropdown_cnt++) {
|
||||||
push_data_to_gradio_component({
|
push_data_to_gradio_component({
|
||||||
visible: false,
|
visible: false,
|
||||||
choices: [],
|
choices: [],
|
||||||
label: "",
|
label: "",
|
||||||
__type__: 'update'
|
__type__: 'update'
|
||||||
}, "plugin_arg_drop_"+dropdown_cnt, "obj");
|
}, "plugin_arg_drop_" + dropdown_cnt, "obj");
|
||||||
document.getElementById("plugin_arg_drop_"+dropdown_cnt).parentNode.style.display = 'none';
|
document.getElementById("plugin_arg_drop_" + dropdown_cnt).parentNode.style.display = 'none';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function close_current_pop_up_plugin(){
|
function close_current_pop_up_plugin() {
|
||||||
// PLUGIN_ARG_MENU
|
// PLUGIN_ARG_MENU
|
||||||
push_data_to_gradio_component({
|
push_data_to_gradio_component({
|
||||||
visible: false,
|
visible: false,
|
||||||
__type__: 'update'
|
__type__: 'update'
|
||||||
|
|
@ -1233,15 +1270,13 @@ function close_current_pop_up_plugin(){
|
||||||
|
|
||||||
// 生成高级插件的选择菜单
|
// 生成高级插件的选择菜单
|
||||||
plugin_init_info_lib = {}
|
plugin_init_info_lib = {}
|
||||||
function register_plugin_init(key, base64String){
|
function register_plugin_init(key, base64String) {
|
||||||
// console.log('x')
|
// console.log('x')
|
||||||
const stringData = atob(base64String);
|
const stringData = atob(base64String);
|
||||||
let guiJsonData = JSON.parse(stringData);
|
let guiJsonData = JSON.parse(stringData);
|
||||||
if (key in plugin_init_info_lib)
|
if (key in plugin_init_info_lib) {
|
||||||
{
|
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
|
||||||
plugin_init_info_lib[key] = {};
|
plugin_init_info_lib[key] = {};
|
||||||
}
|
}
|
||||||
plugin_init_info_lib[key].info = guiJsonData.Info;
|
plugin_init_info_lib[key].info = guiJsonData.Info;
|
||||||
|
|
@ -1251,28 +1286,26 @@ function register_plugin_init(key, base64String){
|
||||||
plugin_init_info_lib[key].enable_advanced_arg = guiJsonData.AdvancedArgs;
|
plugin_init_info_lib[key].enable_advanced_arg = guiJsonData.AdvancedArgs;
|
||||||
plugin_init_info_lib[key].arg_reminder = guiJsonData.ArgsReminder;
|
plugin_init_info_lib[key].arg_reminder = guiJsonData.ArgsReminder;
|
||||||
}
|
}
|
||||||
function register_advanced_plugin_init_code(key, code){
|
function register_advanced_plugin_init_code(key, code) {
|
||||||
if (key in plugin_init_info_lib)
|
if (key in plugin_init_info_lib) {
|
||||||
{
|
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
|
||||||
plugin_init_info_lib[key] = {};
|
plugin_init_info_lib[key] = {};
|
||||||
}
|
}
|
||||||
plugin_init_info_lib[key].secondary_menu_code = code;
|
plugin_init_info_lib[key].secondary_menu_code = code;
|
||||||
}
|
}
|
||||||
function run_advanced_plugin_launch_code(key){
|
function run_advanced_plugin_launch_code(key) {
|
||||||
// convert js code string to function
|
// convert js code string to function
|
||||||
generate_menu(plugin_init_info_lib[key].secondary_menu_code, key);
|
generate_menu(plugin_init_info_lib[key].secondary_menu_code, key);
|
||||||
}
|
}
|
||||||
function on_flex_button_click(key){
|
function on_flex_button_click(key) {
|
||||||
if (plugin_init_info_lib.hasOwnProperty(key) && plugin_init_info_lib[key].hasOwnProperty('secondary_menu_code')){
|
if (plugin_init_info_lib.hasOwnProperty(key) && plugin_init_info_lib[key].hasOwnProperty('secondary_menu_code')) {
|
||||||
run_advanced_plugin_launch_code(key);
|
run_advanced_plugin_launch_code(key);
|
||||||
}else{
|
} else {
|
||||||
document.getElementById("old_callback_btn_for_plugin_exe").click();
|
document.getElementById("old_callback_btn_for_plugin_exe").click();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
async function run_dropdown_shift(dropdown){
|
async function run_dropdown_shift(dropdown) {
|
||||||
let key = dropdown;
|
let key = dropdown;
|
||||||
push_data_to_gradio_component({
|
push_data_to_gradio_component({
|
||||||
value: key,
|
value: key,
|
||||||
|
|
@ -1281,7 +1314,7 @@ async function run_dropdown_shift(dropdown){
|
||||||
__type__: 'update'
|
__type__: 'update'
|
||||||
}, "elem_switchy_bt", "obj");
|
}, "elem_switchy_bt", "obj");
|
||||||
|
|
||||||
if (plugin_init_info_lib[key].enable_advanced_arg){
|
if (plugin_init_info_lib[key].enable_advanced_arg) {
|
||||||
push_data_to_gradio_component({
|
push_data_to_gradio_component({
|
||||||
visible: true,
|
visible: true,
|
||||||
label: plugin_init_info_lib[key].label,
|
label: plugin_init_info_lib[key].label,
|
||||||
|
|
@ -1303,9 +1336,9 @@ async function duplicate_in_new_window() {
|
||||||
window.open(url, '_blank');
|
window.open(url, '_blank');
|
||||||
}
|
}
|
||||||
|
|
||||||
async function run_classic_plugin_via_id(plugin_elem_id){
|
async function run_classic_plugin_via_id(plugin_elem_id) {
|
||||||
for (key in plugin_init_info_lib){
|
for (key in plugin_init_info_lib) {
|
||||||
if (plugin_init_info_lib[key].elem_id == plugin_elem_id){
|
if (plugin_init_info_lib[key].elem_id == plugin_elem_id) {
|
||||||
// 获取按钮名称
|
// 获取按钮名称
|
||||||
let current_btn_name = await get_data_from_gradio_component(plugin_elem_id);
|
let current_btn_name = await get_data_from_gradio_component(plugin_elem_id);
|
||||||
// 执行
|
// 执行
|
||||||
|
|
@ -1326,7 +1359,7 @@ async function call_plugin_via_name(current_btn_name) {
|
||||||
hide_all_elem();
|
hide_all_elem();
|
||||||
// 为了与旧插件兼容,生成菜单时,自动加载旧高级参数输入区的值
|
// 为了与旧插件兼容,生成菜单时,自动加载旧高级参数输入区的值
|
||||||
let advance_arg_input_legacy = await get_data_from_gradio_component('advance_arg_input_legacy');
|
let advance_arg_input_legacy = await get_data_from_gradio_component('advance_arg_input_legacy');
|
||||||
if (advance_arg_input_legacy.length != 0){
|
if (advance_arg_input_legacy.length != 0) {
|
||||||
gui_args["advanced_arg"] = {};
|
gui_args["advanced_arg"] = {};
|
||||||
gui_args["advanced_arg"].user_confirmed_value = advance_arg_input_legacy;
|
gui_args["advanced_arg"].user_confirmed_value = advance_arg_input_legacy;
|
||||||
}
|
}
|
||||||
|
|
@ -1353,7 +1386,7 @@ async function multiplex_function_begin(multiplex_sel) {
|
||||||
// do not delete `REPLACE_EXTENDED_MULTIPLEX_FUNCTIONS_HERE`! It will be read and replaced by Python code.
|
// do not delete `REPLACE_EXTENDED_MULTIPLEX_FUNCTIONS_HERE`! It will be read and replaced by Python code.
|
||||||
// REPLACE_EXTENDED_MULTIPLEX_FUNCTIONS_HERE
|
// REPLACE_EXTENDED_MULTIPLEX_FUNCTIONS_HERE
|
||||||
}
|
}
|
||||||
async function run_multiplex_shift(multiplex_sel){
|
async function run_multiplex_shift(multiplex_sel) {
|
||||||
let key = multiplex_sel;
|
let key = multiplex_sel;
|
||||||
if (multiplex_sel === "常规对话") {
|
if (multiplex_sel === "常规对话") {
|
||||||
key = "提交";
|
key = "提交";
|
||||||
|
|
@ -1365,3 +1398,8 @@ async function run_multiplex_shift(multiplex_sel){
|
||||||
__type__: 'update'
|
__type__: 'update'
|
||||||
}, "elem_submit_visible", "obj");
|
}, "elem_submit_visible", "obj");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async function persistent_cookie_init(web_cookie_cache, cookie) {
|
||||||
|
return [localStorage.getItem('web_cookie_cache'), cookie];
|
||||||
|
}
|
||||||
1177
themes/green.css
1177
themes/green.css
File diff suppressed because it is too large
Load Diff
|
|
@ -1,7 +1,7 @@
|
||||||
import gradio as gr
|
import gradio as gr
|
||||||
|
|
||||||
def define_gui_floating_menu(customize_btns, functional, predefined_btns, cookies, web_cookie_cache):
|
def define_gui_floating_menu(customize_btns, functional, predefined_btns, cookies, web_cookie_cache):
|
||||||
with gr.Floating(init_x="20%", init_y="50%", visible=False, width="40%", drag="top") as area_input_secondary:
|
with gr.Floating(init_x="20%", init_y="50%", visible=False, width="40%", drag="top", elem_id="f_area_input_secondary") as area_input_secondary:
|
||||||
with gr.Accordion("浮动输入区", open=True, elem_id="input-panel2"):
|
with gr.Accordion("浮动输入区", open=True, elem_id="input-panel2"):
|
||||||
with gr.Row() as row:
|
with gr.Row() as row:
|
||||||
row.style(equal_height=True)
|
row.style(equal_height=True)
|
||||||
|
|
@ -17,7 +17,7 @@ def define_gui_floating_menu(customize_btns, functional, predefined_btns, cookie
|
||||||
clearBtn2 = gr.Button("清除", elem_id="elem_clear2", variant="secondary", visible=False); clearBtn2.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.Floating(init_x="20%", init_y="50%", visible=False, width="40%", drag="top", elem_id="f_area_customize") as area_customize:
|
||||||
with gr.Accordion("自定义菜单", open=True, elem_id="edit-panel"):
|
with gr.Accordion("自定义菜单", open=True, elem_id="edit-panel"):
|
||||||
with gr.Row() as row:
|
with gr.Row() as row:
|
||||||
with gr.Column(scale=10):
|
with gr.Column(scale=10):
|
||||||
|
|
@ -35,9 +35,9 @@ def define_gui_floating_menu(customize_btns, functional, predefined_btns, cookie
|
||||||
# update btn
|
# update btn
|
||||||
h = basic_fn_confirm.click(assign_btn, [web_cookie_cache, cookies, basic_btn_dropdown, basic_fn_title, basic_fn_prefix, basic_fn_suffix],
|
h = basic_fn_confirm.click(assign_btn, [web_cookie_cache, cookies, basic_btn_dropdown, basic_fn_title, basic_fn_prefix, basic_fn_suffix],
|
||||||
[web_cookie_cache, cookies, *customize_btns.values(), *predefined_btns.values()])
|
[web_cookie_cache, cookies, *customize_btns.values(), *predefined_btns.values()])
|
||||||
h.then(None, [web_cookie_cache], None, _js="""(web_cookie_cache)=>{setCookie("web_cookie_cache", web_cookie_cache, 365);}""")
|
h.then(None, [web_cookie_cache], None, _js="""(web_cookie_cache)=>{localStorage.setItem("web_cookie_cache", web_cookie_cache);}""")
|
||||||
# clean up btn
|
# clean up btn
|
||||||
h2 = basic_fn_clean.click(assign_btn, [web_cookie_cache, cookies, basic_btn_dropdown, basic_fn_title, basic_fn_prefix, basic_fn_suffix, gr.State(True)],
|
h2 = basic_fn_clean.click(assign_btn, [web_cookie_cache, cookies, basic_btn_dropdown, basic_fn_title, basic_fn_prefix, basic_fn_suffix, gr.State(True)],
|
||||||
[web_cookie_cache, cookies, *customize_btns.values(), *predefined_btns.values()])
|
[web_cookie_cache, cookies, *customize_btns.values(), *predefined_btns.values()])
|
||||||
h2.then(None, [web_cookie_cache], None, _js="""(web_cookie_cache)=>{setCookie("web_cookie_cache", web_cookie_cache, 365);}""")
|
h2.then(None, [web_cookie_cache], None, _js="""(web_cookie_cache)=>{localStorage.setItem("web_cookie_cache", web_cookie_cache);}""")
|
||||||
return area_input_secondary, txt2, area_customize, submitBtn2, resetBtn2, clearBtn2, stopBtn2
|
return area_input_secondary, txt2, area_customize, submitBtn2, resetBtn2, clearBtn2, stopBtn2
|
||||||
|
|
@ -3,6 +3,8 @@ async function GptAcademicJavaScriptInit(dark, prompt, live2d, layout, tts) {
|
||||||
audio_fn_init();
|
audio_fn_init();
|
||||||
minor_ui_adjustment();
|
minor_ui_adjustment();
|
||||||
ButtonWithDropdown_init();
|
ButtonWithDropdown_init();
|
||||||
|
update_conversation_metadata();
|
||||||
|
window.addEventListener("gptac_restore_chat_from_local_storage", restore_chat_from_local_storage);
|
||||||
|
|
||||||
// 加载欢迎页面
|
// 加载欢迎页面
|
||||||
const welcomeMessage = new WelcomeMessage();
|
const welcomeMessage = new WelcomeMessage();
|
||||||
|
|
|
||||||
|
|
@ -87,21 +87,6 @@ js_code_for_toggle_darkmode = """() => {
|
||||||
}"""
|
}"""
|
||||||
|
|
||||||
|
|
||||||
js_code_for_persistent_cookie_init = """(web_cookie_cache, cookie) => {
|
|
||||||
return [getCookie("web_cookie_cache"), cookie];
|
|
||||||
}
|
|
||||||
"""
|
|
||||||
|
|
||||||
# 详见 themes/common.js
|
|
||||||
js_code_reset = """
|
|
||||||
(a,b,c)=>{
|
|
||||||
let stopButton = document.getElementById("elem_stop");
|
|
||||||
stopButton.click();
|
|
||||||
return reset_conversation(a,b);
|
|
||||||
}
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
js_code_clear = """
|
js_code_clear = """
|
||||||
(a,b)=>{
|
(a,b)=>{
|
||||||
return ["", ""];
|
return ["", ""];
|
||||||
|
|
|
||||||
12
toolbox.py
12
toolbox.py
|
|
@ -8,6 +8,7 @@ import base64
|
||||||
import gradio
|
import gradio
|
||||||
import shutil
|
import shutil
|
||||||
import glob
|
import glob
|
||||||
|
import json
|
||||||
import uuid
|
import uuid
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
|
|
@ -92,8 +93,9 @@ def ArgsGeneralWrapper(f):
|
||||||
"""
|
"""
|
||||||
def decorated(request: gradio.Request, cookies:dict, max_length:int, llm_model:str,
|
def decorated(request: gradio.Request, cookies:dict, max_length:int, llm_model:str,
|
||||||
txt:str, txt2:str, top_p:float, temperature:float, chatbot:list,
|
txt:str, txt2:str, top_p:float, temperature:float, chatbot:list,
|
||||||
history:list, system_prompt:str, plugin_advanced_arg:dict, *args):
|
json_history:str, system_prompt:str, plugin_advanced_arg:dict, *args):
|
||||||
txt_passon = txt
|
txt_passon = txt
|
||||||
|
history = json.loads(json_history) if json_history else []
|
||||||
if txt == "" and txt2 != "": txt_passon = txt2
|
if txt == "" and txt2 != "": txt_passon = txt2
|
||||||
# 引入一个有cookie的chatbot
|
# 引入一个有cookie的chatbot
|
||||||
if request.username is not None:
|
if request.username is not None:
|
||||||
|
|
@ -148,10 +150,11 @@ def ArgsGeneralWrapper(f):
|
||||||
return decorated
|
return decorated
|
||||||
|
|
||||||
|
|
||||||
def update_ui(chatbot:ChatBotWithCookies, history, msg="正常", **kwargs): # 刷新界面
|
def update_ui(chatbot:ChatBotWithCookies, history:list, msg:str="正常", **kwargs): # 刷新界面
|
||||||
"""
|
"""
|
||||||
刷新用户界面
|
刷新用户界面
|
||||||
"""
|
"""
|
||||||
|
assert isinstance(history, list), "history必须是一个list"
|
||||||
assert isinstance(
|
assert isinstance(
|
||||||
chatbot, ChatBotWithCookies
|
chatbot, ChatBotWithCookies
|
||||||
), "在传递chatbot的过程中不要将其丢弃。必要时, 可用clear将其清空, 然后用for+append循环重新赋值。"
|
), "在传递chatbot的过程中不要将其丢弃。必要时, 可用clear将其清空, 然后用for+append循环重新赋值。"
|
||||||
|
|
@ -175,10 +178,11 @@ def update_ui(chatbot:ChatBotWithCookies, history, msg="正常", **kwargs): #
|
||||||
else:
|
else:
|
||||||
chatbot_gr = chatbot
|
chatbot_gr = chatbot
|
||||||
|
|
||||||
yield cookies, chatbot_gr, history, msg
|
json_history = json.dumps(history, ensure_ascii=False)
|
||||||
|
yield cookies, chatbot_gr, json_history, msg
|
||||||
|
|
||||||
|
|
||||||
def update_ui_lastest_msg(lastmsg:str, chatbot:ChatBotWithCookies, history:list, delay=1, msg="正常"): # 刷新界面
|
def update_ui_lastest_msg(lastmsg:str, chatbot:ChatBotWithCookies, history:list, delay:float=1, msg:str="正常"): # 刷新界面
|
||||||
"""
|
"""
|
||||||
刷新用户界面
|
刷新用户界面
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue