比较提交

..

27 次代码提交

作者 SHA1 备注 提交日期
binary-husky
43ed8cb8a8 Fix fastapi version compat 2024-05-04 16:43:42 +08:00
binary-husky
3eff964424 Update README.md 2024-05-01 17:59:25 +08:00
OREEkE
ebde98b34b Update requirements.txt (#1753)
TTS_TYPE = "EDGE_TTS"需要的依赖
2024-05-01 14:55:04 +08:00
binary-husky
6f883031c0 Update config.py 2024-05-01 14:54:36 +08:00
binary-husky
5fcd02506c version 3.75 (#1702)
* Update version to 3.74

* Add support for Yi Model API (#1635)

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

* 删除newbing

* 修改config

---------

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

* Refactor function signatures in bridge files

* fix qwen api change

* rename and ref functions

* rename and move some cookie functions

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

* haiku added

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

* Haiku added

* 将说明同步至最新Endpoint

---------

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

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

* private_upload目录下进行文件鉴权

* minor fastapi adjustment

* Add logging functionality to enable saving
conversation records

* waiting to fix username retrieve

* support 2rd web path

* allow accessing default user dir

---------

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

* remove yaml deps

* fix favicon

* fix abs path auth problem

* forget to write a return

* add `dashscope` to deps

* fix GHSA-v9q9-xj86-953p

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

* add cohere model api access

* cohere + can_multi_thread

* fix block user access(fail)

* fix fastapi bug

* change cohere api endpoint

* explain version

* # fix com_zhipuglm.py illegal temperature problem (#1687)

* Update com_zhipuglm.py

# fix 用户在使用 zhipuai 界面时遇到了关于温度参数的非法参数错误

* allow store lm model dropdown

* add a btn to reverse previous reset

* remove extra fns

* Add support for glm-4v model (#1700)

* 修改chatglm3量化加载方式 (#1688)

Co-authored-by: zym9804 <ren990603@gmail.com>

* save chat stage 1

* consider null cookie situation

* 在点击复制按钮时激活语音

* miss some parts

* move all to js

* done first stage

* add edge tts

* bug fix

* bug fix

* remove console log

* bug fix

* bug fix

* bug fix

* audio switch

* update tts readme

* remove tempfile when done

* disable auto audio follow

* avoid play queue update after shut up

* feat: minimizing common.js

* improve tts functionality

* deterine whether the cached model is in choices

* Add support for Ollama (#1740)

* print err when doc2x not successful

* add icon

* adjust url for doc2x key version

* prepare merge

---------

Co-authored-by: Menghuan1918 <menghuan2003@outlook.com>
Co-authored-by: Skyzayre <120616113+Skyzayre@users.noreply.github.com>
Co-authored-by: XIao <46100050+Kilig947@users.noreply.github.com>
Co-authored-by: Yuki <903728862@qq.com>
Co-authored-by: zyren123 <91042213+zyren123@users.noreply.github.com>
Co-authored-by: zym9804 <ren990603@gmail.com>
2024-04-30 20:37:41 +08:00
binary-husky
bd5280df1b minor pdf translation adjustment 2024-04-30 00:52:36 +08:00
binary-husky
744759704d allow personal docx api access 2024-04-29 23:53:41 +08:00
WFS
81df0aa210 fix the issue of when using google Gemini pro, don't have chat histor… (#1743)
* fix the issue of when using google Gemini pro, don't have chat history record

just add chat_log in bridge_google_gmini.py

* Update bridge_google_gemini.py

---------

Co-authored-by: binary-husky <96192199+binary-husky@users.noreply.github.com>
2024-04-25 22:26:32 +08:00
Menghuan1918
cadaa81030 Fix the bug cause Nougat can not use (#1738)
* Bug fix for nougat require pdf

* Fixing bugs in a simpler and safer way
2024-04-24 12:13:44 +08:00
binary-husky
3b6cbbdcb0 Update README.md (#1736) 2024-04-24 11:41:56 +08:00
binary-husky
52e49c48b8 the latest zhipuai whl is broken 2024-04-23 18:20:36 +08:00
binary-husky
6ad15a6129 fix equation showing problem 2024-04-22 01:54:03 +08:00
binary-husky
09990d44d3 merge to resolve multiple pickle security issues (#1728)
* 注释调试if分支

* support pdf url for latex translation

* Merge pull request from GHSA-mvrw-h7rc-22r8

* 注释调试if分支

* Improve objload security

* Update README.md

* support pdf url for latex translation

---------

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

* fix import

---------

Co-authored-by: Longtaotao <longtaotao@bupt.edu.cn>
Co-authored-by: iluem <57590186+Qhaoduoyu@users.noreply.github.com>
2024-04-21 19:37:05 +08:00
binary-husky
eac5191815 Update README.md 2024-04-21 02:12:15 +08:00
owo
ae4407135d fix: 添加report_exception中缺失的a参数 (#1720)
在report_exception函数的定义中,参数a未包含默认值,因此应提供相应的值传入。
2024-04-18 16:27:00 +08:00
owo
f0e15bd710 fix: 修复了在else语句中调用'schema_str'之前未定义的问题 (#1719)
重新排列了方法中的条件返回语句,以确保在使用之前始终定义了'schema_str'。
2024-04-18 16:26:13 +08:00
jiangfy-ihep
5c5f442649 Fix: openai project API key pattern (#1721)
Co-authored-by: Fayu Jiang <jiangfayu@hotmail.com>
2024-04-18 16:24:29 +08:00
binary-husky
160552cc5f introduce doc2x 2024-04-15 01:57:31 +08:00
binary-husky
c131ec0b20 rename pdf plugin file name 2024-04-14 22:46:31 +08:00
iluem
2f3aeb7976 Merge pull request from GHSA-23cr-v6pm-j89p
* Update crazy_utils.py

Improve security

* add a white space

---------

Co-authored-by: binary-husky <96192199+binary-husky@users.noreply.github.com>
2024-04-14 21:51:03 +08:00
binary-husky
eff5b89b98 scan first, then extract 2024-04-14 21:36:57 +08:00
iluem
f77ab27bc9 Merge pull request from GHSA-rh7j-jfvq-857j
Prevent path traversal for improved security
2024-04-14 21:33:37 +08:00
awwaawwa
ba0a8b7072 integrate gpt-4-turbo-2024-04-09 (#1698)
* 接入 gpt-4-turbo-2024-04-09 模型

* add gpt-4-turbo and change to vision

* add gpt-4-turbo to avail llm models

* 暂时将gpt-4-turbo接入至普通版本
2024-04-11 22:02:40 +08:00
hmp
2406022c2a access vllm 2024-04-11 22:00:07 +08:00
OREEkE
02b6f26b05 remove logging in gradios.py (#1699)
如果初始主题是HF社区主题,这里使用logging会导致程序不再写入日志(包括对话内容在内的任何记录),下载主题的日志输出和程序启动时的日志初始化有冲突。
2024-04-11 14:15:12 +08:00
OREEkE
2a003e8d49 add loadLive2D() when ADD_WAIFU = False (#1693)
ADD_WAIFU = False,浏览器会抛出错误:[Error] JQuery is not defined. 因为这时候没有jQuery库可用,却依然使用了loadLive2D()函数。现在加一个判断,如果ADD_WAIFU = False,禁用jQuery库的同时也禁用loadLive2D()函数,除非ADD_WAIFU = True
2024-04-10 00:10:53 +08:00
binary-husky
21891b0f6d update translate matrix 2024-04-08 12:43:24 +08:00
共有 44 个文件被更改,包括 2430 次插入157 次删除

1
.gitignore vendored
查看文件

@@ -153,3 +153,4 @@ media
flagged
request_llms/ChatGLM-6b-onnx-u8s8
.pre-commit-config.yaml
themes/common.js.min.*.js

查看文件

@@ -1,6 +1,7 @@
> [!IMPORTANT]
> 2024.5.1: 加入Doc2x翻译PDF论文的功能,[查看详情](https://github.com/binary-husky/gpt_academic/wiki/Doc2x)
> 2024.4.30: 3.75版本引入Edge-TTS和SoVits语音克隆模块,[查看详情](https://www.bilibili.com/video/BV1Rp421S7tF/)
> 2024.3.11: 恭迎Claude3和Moonshot,全力支持Qwen、GLM、DeepseekCoder等中文大语言模型
> 2024.1.18: 更新3.70版本,支持Mermaid绘图库让大模型绘制脑图
> 2024.1.17: 安装依赖时,请选择`requirements.txt`中**指定的版本**。 安装命令:`pip install -r requirements.txt`。本项目完全开源免费,您可通过订阅[在线服务](https://github.com/binary-husky/gpt_academic/wiki/online)的方式鼓励本项目的发展。
<br>
@@ -86,6 +87,10 @@ Latex论文一键校对 | [插件] 仿Grammarly对Latex文章进行语法、拼
<img src="https://user-images.githubusercontent.com/96192199/279702205-d81137c3-affd-4cd1-bb5e-b15610389762.gif" width="700" >
</div>
<div align="center">
<img src="https://github.com/binary-husky/gpt_academic/assets/96192199/70ff1ec5-e589-4561-a29e-b831079b37fb.gif" width="700" >
</div>
- 所有按钮都通过读取functional.py动态生成,可随意加自定义功能,解放剪贴板
<div align="center">

查看文件

@@ -32,9 +32,9 @@ else:
# [step 3]>> 模型选择是 (注意: LLM_MODEL是默认选中的模型, 它*必须*被包含在AVAIL_LLM_MODELS列表中 )
LLM_MODEL = "gpt-3.5-turbo-16k" # 可选 ↓↓↓
AVAIL_LLM_MODELS = ["gpt-4-1106-preview", "gpt-4-turbo-preview", "gpt-4-vision-preview",
AVAIL_LLM_MODELS = ["gpt-4-1106-preview", "gpt-4-turbo-preview", "gpt-4-vision-preview", "gpt-4-turbo", "gpt-4-turbo-2024-04-09",
"gpt-3.5-turbo-1106", "gpt-3.5-turbo-16k", "gpt-3.5-turbo", "azure-gpt-3.5",
"gpt-4", "gpt-4-32k", "azure-gpt-4", "glm-4", "glm-3-turbo",
"gpt-4", "gpt-4-32k", "azure-gpt-4", "glm-4", "glm-4v", "glm-3-turbo",
"gemini-pro", "chatglm3"
]
# --- --- --- ---
@@ -50,9 +50,9 @@ AVAIL_LLM_MODELS = ["gpt-4-1106-preview", "gpt-4-turbo-preview", "gpt-4-vision-p
# "yi-34b-chat-0205", "yi-34b-chat-200k"
# ]
# --- --- --- ---
# 此外,为了更灵活地接入one-api多模型管理界面,您还可以在接入one-api时,
# 使用"one-api-*"前缀直接使用非标准方式接入的模型,例如
# AVAIL_LLM_MODELS = ["one-api-claude-3-sonnet-20240229(max_token=100000)"]
# 此外,您还可以在接入one-api/vllm/ollama时,
# 使用"one-api-*","vllm-*","ollama-*"前缀直接使用非标准方式接入的模型,例如
# AVAIL_LLM_MODELS = ["one-api-claude-3-sonnet-20240229(max_token=100000)", "ollama-phi3(max_token=4096)"]
# --- --- --- ---
@@ -60,7 +60,7 @@ AVAIL_LLM_MODELS = ["gpt-4-1106-preview", "gpt-4-turbo-preview", "gpt-4-vision-p
# 重新URL重新定向,实现更换API_URL的作用高危设置! 常规情况下不要修改! 通过修改此设置,您将把您的API-KEY和对话隐私完全暴露给您设定的中间人
# 格式: API_URL_REDIRECT = {"https://api.openai.com/v1/chat/completions": "在这里填写重定向的api.openai.com的URL"}
# 举例: API_URL_REDIRECT = {"https://api.openai.com/v1/chat/completions": "https://reverse-proxy-url/v1/chat/completions"}
# 举例: API_URL_REDIRECT = {"https://api.openai.com/v1/chat/completions": "https://reverse-proxy-url/v1/chat/completions", "http://localhost:11434/api/chat": "在这里填写您ollama的URL"}
API_URL_REDIRECT = {}
@@ -195,6 +195,12 @@ ALIYUN_ACCESSKEY="" # (无需填写)
ALIYUN_SECRET="" # (无需填写)
# GPT-SOVITS 文本转语音服务的运行地址(将语言模型的生成文本朗读出来)
TTS_TYPE = "DISABLE" # LOCAL / LOCAL_SOVITS_API / DISABLE
GPT_SOVITS_URL = ""
EDGE_TTS_VOICE = "zh-CN-XiaoxiaoNeural"
# 接入讯飞星火大模型 https://console.xfyun.cn/services/iat
XFYUN_APPID = "00000000"
XFYUN_API_SECRET = "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
@@ -223,6 +229,10 @@ MATHPIX_APPID = ""
MATHPIX_APPKEY = ""
# DOC2X的PDF解析服务,注册账号并获取API KEY: https://doc2x.noedgeai.com/login
DOC2X_API_KEY = ""
# 自定义API KEY格式
CUSTOM_API_KEY_PATTERN = ""

查看文件

@@ -27,7 +27,7 @@ def get_crazy_functions():
from crazy_functions.辅助功能 import 清除缓存
from crazy_functions.批量Markdown翻译 import Markdown英译中
from crazy_functions.批量总结PDF文档 import 批量总结PDF文档
from crazy_functions.批量翻译PDF文档_多线程 import 批量翻译PDF文档
from crazy_functions.PDF批量翻译 import 批量翻译PDF文档
from crazy_functions.谷歌检索小助手 import 谷歌检索小助手
from crazy_functions.理解PDF文档内容 import 理解PDF文档内容标准文件输入
from crazy_functions.Latex全文润色 import Latex中文润色

查看文件

@@ -107,6 +107,10 @@ def arxiv_download(chatbot, history, txt, allow_cache=True):
except ValueError:
return False
if txt.startswith('https://arxiv.org/pdf/'):
arxiv_id = txt.split('/')[-1] # 2402.14207v2.pdf
txt = arxiv_id.split('v')[0] # 2402.14207
if ('.' in txt) and ('/' not in txt) and is_float(txt): # is arxiv ID
txt = 'https://arxiv.org/abs/' + txt.strip()
if ('.' in txt) and ('/' not in txt) and is_float(txt[:10]): # is arxiv ID
@@ -121,6 +125,7 @@ def arxiv_download(chatbot, history, txt, allow_cache=True):
time.sleep(1) # 刷新界面
url_ = txt # https://arxiv.org/abs/1707.06690
if not txt.startswith('https://arxiv.org/abs/'):
msg = f"解析arxiv网址失败, 期望格式例如: https://arxiv.org/abs/1707.06690。实际得到格式: {url_}"
yield from update_ui_lastest_msg(msg, chatbot=chatbot, history=history) # 刷新界面
@@ -458,23 +463,23 @@ def PDF翻译中文并重新编译PDF(txt, llm_kwargs, plugin_kwargs, chatbot, h
promote_file_to_downloadzone(translate_pdf, rename_file=None, chatbot=chatbot)
comparison_pdf = [f for f in glob.glob(f'{project_folder}/**/comparison.pdf', recursive=True)][0]
promote_file_to_downloadzone(comparison_pdf, rename_file=None, chatbot=chatbot)
promote_file_to_downloadzone(comparison_pdf, rename_file=None, chatbot=chatbot)
zip_res = zip_result(project_folder)
promote_file_to_downloadzone(file=zip_res, chatbot=chatbot)
return True
except:
report_exception(chatbot, history, b=f"发现重复上传,但是无法找到相关文件")
report_exception(chatbot, history, a=f"解析项目: {txt}", b=f"发现重复上传,但是无法找到相关文件")
yield from update_ui(chatbot=chatbot, history=history)
chatbot.append([f"没有相关文件", '尝试重新翻译PDF...'])
yield from update_ui(chatbot=chatbot, history=history)
except_flag = True
elif not repeat or except_flag:
yield from update_ui_lastest_msg(f"未发现重复上传", chatbot=chatbot, history=history)

查看文件

@@ -1,9 +1,11 @@
from toolbox import CatchException, report_exception, get_log_folder, gen_time_str, check_packages
from toolbox import update_ui, promote_file_to_downloadzone, update_ui_lastest_msg, disable_auto_promotion
from toolbox import write_history_to_file, promote_file_to_downloadzone
from toolbox import write_history_to_file, promote_file_to_downloadzone, get_conf, extract_archive
from toolbox import generate_file_link, zip_folder, trimmed_format_exc, trimmed_format_exc_markdown
from .crazy_utils import request_gpt_model_in_new_thread_with_ui_alive
from .crazy_utils import request_gpt_model_multi_threads_with_very_awesome_ui_and_high_efficiency
from .crazy_utils import read_and_clean_pdf_text
from .crazy_utils import get_files_from_everything
from .pdf_fns.parse_pdf import parse_pdf, get_avail_grobid_url, translate_pdf
from colorful import *
import os
@@ -14,9 +16,7 @@ def 批量翻译PDF文档(txt, llm_kwargs, plugin_kwargs, chatbot, history, syst
disable_auto_promotion(chatbot)
# 基本信息:功能、贡献者
chatbot.append([
"函数插件功能?",
"批量翻译PDF文档。函数插件贡献者: Binary-Husky"])
chatbot.append([None, "插件功能批量翻译PDF文档。函数插件贡献者: Binary-Husky"])
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
# 尝试导入依赖,如果缺少依赖,则给出安装建议
@@ -32,7 +32,6 @@ def 批量翻译PDF文档(txt, llm_kwargs, plugin_kwargs, chatbot, history, syst
# 清空历史,以免输入溢出
history = []
from .crazy_utils import get_files_from_everything
success, file_manifest, project_folder = get_files_from_everything(txt, type='.pdf')
# 检测输入参数,如没有给定输入参数,直接退出
if not success:
@@ -46,13 +45,161 @@ def 批量翻译PDF文档(txt, llm_kwargs, plugin_kwargs, chatbot, history, syst
return
# 开始正式执行任务
DOC2X_API_KEY = get_conf("DOC2X_API_KEY")
# ------- 第一种方法,效果最好,但是需要DOC2X服务 -------
if len(DOC2X_API_KEY) != 0:
try:
yield from 解析PDF_DOC2X(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, DOC2X_API_KEY, user_request)
return
except:
chatbot.append([None, f"DOC2X服务不可用,现在将执行效果稍差的旧版代码。{trimmed_format_exc_markdown()}"])
yield from update_ui(chatbot=chatbot, history=history)
# ------- 第二种方法,效果次优 -------
grobid_url = get_avail_grobid_url()
if grobid_url is not None:
yield from 解析PDF_基于GROBID(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, grobid_url)
else:
yield from update_ui_lastest_msg("GROBID服务不可用,请检查config中的GROBID_URL。作为替代,现在将执行效果稍差的旧版代码。", chatbot, history, delay=3)
yield from 解析PDF(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt)
return
# ------- 第三种方法,早期代码,效果不理想 -------
yield from update_ui_lastest_msg("GROBID服务不可用,请检查config中的GROBID_URL。作为替代,现在将执行效果稍差的旧版代码。", chatbot, history, delay=3)
yield from 解析PDF(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt)
return
def 解析PDF_DOC2X_单文件(fp, project_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, DOC2X_API_KEY, user_request):
def pdf2markdown(filepath):
import requests, json, os
markdown_dir = get_log_folder(plugin_name="pdf_ocr")
doc2x_api_key = DOC2X_API_KEY
if doc2x_api_key.startswith('sk-'):
url = "https://api.doc2x.noedgeai.com/api/v1/pdf"
else:
url = "https://api.doc2x.noedgeai.com/api/platform/pdf"
chatbot.append((None, "加载PDF文件,发送至DOC2X解析..."))
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
res = requests.post(
url,
files={"file": open(filepath, "rb")},
data={"ocr": "1"},
headers={"Authorization": "Bearer " + doc2x_api_key}
)
res_json = []
if res.status_code == 200:
decoded = res.content.decode("utf-8")
for z_decoded in decoded.split('\n'):
if len(z_decoded) == 0: continue
assert z_decoded.startswith("data: ")
z_decoded = z_decoded[len("data: "):]
decoded_json = json.loads(z_decoded)
res_json.append(decoded_json)
else:
raise RuntimeError(format("[ERROR] status code: %d, body: %s" % (res.status_code, res.text)))
uuid = res_json[0]['uuid']
to = "md" # latex, md, docx
url = "https://api.doc2x.noedgeai.com/api/export"+"?request_id="+uuid+"&to="+to
chatbot.append((None, f"读取解析: {url} ..."))
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
res = requests.get(url, headers={"Authorization": "Bearer " + doc2x_api_key})
md_zip_path = os.path.join(markdown_dir, gen_time_str() + '.zip')
if res.status_code == 200:
with open(md_zip_path, "wb") as f: f.write(res.content)
else:
raise RuntimeError(format("[ERROR] status code: %d, body: %s" % (res.status_code, res.text)))
promote_file_to_downloadzone(md_zip_path, chatbot=chatbot)
chatbot.append((None, f"完成解析 {md_zip_path} ..."))
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
return md_zip_path
def deliver_to_markdown_plugin(md_zip_path, user_request):
from crazy_functions.批量Markdown翻译 import Markdown英译中
import shutil, re
time_tag = gen_time_str()
target_path_base = get_log_folder(chatbot.get_user())
file_origin_name = os.path.basename(md_zip_path)
this_file_path = os.path.join(target_path_base, file_origin_name)
os.makedirs(target_path_base, exist_ok=True)
shutil.copyfile(md_zip_path, this_file_path)
ex_folder = this_file_path + ".extract"
extract_archive(
file_path=this_file_path, dest_dir=ex_folder
)
# edit markdown files
success, file_manifest, project_folder = get_files_from_everything(ex_folder, type='.md')
for generated_fp in file_manifest:
# 修正一些公式问题
with open(generated_fp, 'r', encoding='utf8') as f:
content = f.read()
# 将公式中的\[ \]替换成$$
content = content.replace(r'\[', r'$$').replace(r'\]', r'$$')
# 将公式中的\( \)替换成$
content = content.replace(r'\(', r'$').replace(r'\)', r'$')
content = content.replace('```markdown', '\n').replace('```', '\n')
with open(generated_fp, 'w', encoding='utf8') as f:
f.write(content)
promote_file_to_downloadzone(generated_fp, chatbot=chatbot)
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
# 生成在线预览html
file_name = '在线预览翻译(原文)' + gen_time_str() + '.html'
preview_fp = os.path.join(ex_folder, file_name)
from shared_utils.advanced_markdown_format import markdown_convertion_for_file
with open(generated_fp, "r", encoding="utf-8") as f:
md = f.read()
# Markdown中使用不标准的表格,需要在表格前加上一个emoji,以便公式渲染
md = re.sub(r'^<table>', r'😃<table>', md, flags=re.MULTILINE)
html = markdown_convertion_for_file(md)
with open(preview_fp, "w", encoding="utf-8") as f: f.write(html)
chatbot.append([None, f"生成在线预览:{generate_file_link([preview_fp])}"])
promote_file_to_downloadzone(preview_fp, chatbot=chatbot)
chatbot.append((None, f"调用Markdown插件 {ex_folder} ..."))
plugin_kwargs['markdown_expected_output_dir'] = ex_folder
translated_f_name = 'translated_markdown.md'
generated_fp = plugin_kwargs['markdown_expected_output_path'] = os.path.join(ex_folder, translated_f_name)
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
yield from Markdown英译中(ex_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request)
if os.path.exists(generated_fp):
# 修正一些公式问题
with open(generated_fp, 'r', encoding='utf8') as f: content = f.read()
content = content.replace('```markdown', '\n').replace('```', '\n')
# Markdown中使用不标准的表格,需要在表格前加上一个emoji,以便公式渲染
content = re.sub(r'^<table>', r'😃<table>', content, flags=re.MULTILINE)
with open(generated_fp, 'w', encoding='utf8') as f: f.write(content)
# 生成在线预览html
file_name = '在线预览翻译' + gen_time_str() + '.html'
preview_fp = os.path.join(ex_folder, file_name)
from shared_utils.advanced_markdown_format import markdown_convertion_for_file
with open(generated_fp, "r", encoding="utf-8") as f:
md = f.read()
html = markdown_convertion_for_file(md)
with open(preview_fp, "w", encoding="utf-8") as f: f.write(html)
promote_file_to_downloadzone(preview_fp, chatbot=chatbot)
# 生成包含图片的压缩包
dest_folder = get_log_folder(chatbot.get_user())
zip_name = '翻译后的带图文档.zip'
zip_folder(source_folder=ex_folder, dest_folder=dest_folder, zip_name=zip_name)
zip_fp = os.path.join(dest_folder, zip_name)
promote_file_to_downloadzone(zip_fp, chatbot=chatbot)
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
md_zip_path = yield from pdf2markdown(fp)
yield from deliver_to_markdown_plugin(md_zip_path, user_request)
def 解析PDF_DOC2X(file_manifest, *args):
for index, fp in enumerate(file_manifest):
yield from 解析PDF_DOC2X_单文件(fp, *args)
return
def 解析PDF_基于GROBID(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, grobid_url):
import copy, json

查看文件

@@ -568,7 +568,7 @@ class nougat_interface():
from toolbox import ProxyNetworkActivate
logging.info(f'正在执行命令 {command}')
with ProxyNetworkActivate("Nougat_Download"):
process = subprocess.Popen(command, shell=True, cwd=cwd, env=os.environ)
process = subprocess.Popen(command, shell=False, cwd=cwd, env=os.environ)
try:
stdout, stderr = process.communicate(timeout=timeout)
except subprocess.TimeoutExpired:
@@ -592,7 +592,8 @@ class nougat_interface():
yield from update_ui_lastest_msg("正在解析论文, 请稍候。进度正在加载NOUGAT... 提示首次运行需要花费较长时间下载NOUGAT参数",
chatbot=chatbot, history=history, delay=0)
self.nougat_with_timeout(f'nougat --out "{os.path.abspath(dst)}" "{os.path.abspath(fp)}"', os.getcwd(), timeout=3600)
command = ['nougat', '--out', os.path.abspath(dst), os.path.abspath(fp)]
self.nougat_with_timeout(command, cwd=os.getcwd(), timeout=3600)
res = glob.glob(os.path.join(dst,'*.mmd'))
if len(res) == 0:
self.threadLock.release()

查看文件

@@ -62,8 +62,8 @@ class GptJsonIO():
if "type" in reduced_schema:
del reduced_schema["type"]
# Ensure json in context is well-formed with double quotes.
schema_str = json.dumps(reduced_schema)
if self.example_instruction:
schema_str = json.dumps(reduced_schema)
return PYDANTIC_FORMAT_INSTRUCTIONS.format(schema=schema_str)
else:
return PYDANTIC_FORMAT_INSTRUCTIONS_SIMPLE.format(schema=schema_str)

查看文件

@@ -1,10 +1,11 @@
from toolbox import update_ui, update_ui_lastest_msg, get_log_folder
from toolbox import get_conf, objdump, objload, promote_file_to_downloadzone
from toolbox import get_conf, promote_file_to_downloadzone
from .latex_toolbox import PRESERVE, TRANSFORM
from .latex_toolbox import set_forbidden_text, set_forbidden_text_begin_end, set_forbidden_text_careful_brace
from .latex_toolbox import reverse_forbidden_text_careful_brace, reverse_forbidden_text, convert_to_linklist, post_process
from .latex_toolbox import fix_content, find_main_tex_file, merge_tex_files, compile_latex_with_timeout
from .latex_toolbox import find_title_and_abs
from .latex_pickle_io import objdump, objload
import os, shutil
import re

查看文件

@@ -0,0 +1,38 @@
import pickle
class SafeUnpickler(pickle.Unpickler):
def get_safe_classes(self):
from .latex_actions import LatexPaperFileGroup, LatexPaperSplit
# 定义允许的安全类
safe_classes = {
# 在这里添加其他安全的类
'LatexPaperFileGroup': LatexPaperFileGroup,
'LatexPaperSplit' : LatexPaperSplit,
}
return safe_classes
def find_class(self, module, name):
# 只允许特定的类进行反序列化
self.safe_classes = self.get_safe_classes()
if f'{module}.{name}' in self.safe_classes:
return self.safe_classes[f'{module}.{name}']
# 如果尝试加载未授权的类,则抛出异常
raise pickle.UnpicklingError(f"Attempted to deserialize unauthorized class '{name}' from module '{module}'")
def objdump(obj, file="objdump.tmp"):
with open(file, "wb+") as f:
pickle.dump(obj, f)
return
def objload(file="objdump.tmp"):
import os
if not os.path.exists(file):
return
with open(file, "rb") as f:
unpickler = SafeUnpickler(f)
return unpickler.load()

查看文件

@@ -0,0 +1,73 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>GPT-Academic 翻译报告书</title>
<style>
.centered-a {
color: red;
text-align: center;
margin-bottom: 2%;
font-size: 1.5em;
}
.centered-b {
color: red;
text-align: center;
margin-top: 10%;
margin-bottom: 20%;
font-size: 1.5em;
}
.centered-c {
color: rgba(255, 0, 0, 0);
text-align: center;
margin-top: 2%;
margin-bottom: 20%;
font-size: 7em;
}
</style>
<script>
// Configure MathJax settings
MathJax = {
tex: {
inlineMath: [
['$', '$'],
['\(', '\)']
]
}
}
addEventListener('zero-md-rendered', () => {MathJax.typeset(); console.log('MathJax typeset!');})
</script>
<!-- Load MathJax library -->
<script src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-chtml.js"></script>
<script
type="module"
src="https://cdn.jsdelivr.net/gh/zerodevx/zero-md@2/dist/zero-md.min.js"
></script>
</head>
<body>
<div class="test_temp1" style="width:10%; height: 500px; float:left;">
</div>
<div class="test_temp2" style="width:80%; height: 500px; float:left;">
<!-- Simply set the `src` attribute to your MD file and win -->
<div class="centered-a">
请按Ctrl+S保存此页面,否则该页面可能在几分钟后失效。
</div>
<zero-md src="translated_markdown.md" no-shadow>
</zero-md>
<div class="centered-b">
本报告由GPT-Academic开源项目生成,地址https://github.com/binary-husky/gpt_academic。
</div>
<div class="centered-c">
本报告由GPT-Academic开源项目生成,地址https://github.com/binary-husky/gpt_academic。
</div>
</div>
<div class="test_temp3" style="width:10%; height: 500px; float:left;">
</div>
</body>
</html>

查看文件

@@ -1,5 +1,5 @@
import glob, time, os, re, logging
from toolbox import update_ui, trimmed_format_exc, gen_time_str, disable_auto_promotion
import glob, shutil, os, re, logging
from toolbox import update_ui, trimmed_format_exc, gen_time_str
from toolbox import CatchException, report_exception, get_log_folder
from toolbox import write_history_to_file, promote_file_to_downloadzone
fast_debug = False
@@ -18,7 +18,7 @@ class PaperFileGroup():
def get_token_num(txt): return len(enc.encode(txt, disallowed_special=()))
self.get_token_num = get_token_num
def run_file_split(self, max_token_limit=1900):
def run_file_split(self, max_token_limit=2048):
"""
将长文本分离开来
"""
@@ -64,22 +64,22 @@ def 多文件翻译(file_manifest, project_folder, llm_kwargs, plugin_kwargs, ch
pfg.file_contents.append(file_content)
# <-------- 拆分过长的Markdown文件 ---------->
pfg.run_file_split(max_token_limit=1500)
pfg.run_file_split(max_token_limit=2048)
n_split = len(pfg.sp_file_contents)
# <-------- 多线程翻译开始 ---------->
if language == 'en->zh':
inputs_array = ["This is a Markdown file, translate it into Chinese, do not modify any existing Markdown commands:" +
inputs_array = ["This is a Markdown file, translate it into Chinese, do NOT modify any existing Markdown commands, do NOT use code wrapper (```), ONLY answer me with translated results:" +
f"\n\n{frag}" for frag in pfg.sp_file_contents]
inputs_show_user_array = [f"翻译 {f}" for f in pfg.sp_file_tag]
sys_prompt_array = ["You are a professional academic paper translator." for _ in range(n_split)]
elif language == 'zh->en':
inputs_array = [f"This is a Markdown file, translate it into English, do not modify any existing Markdown commands:" +
inputs_array = [f"This is a Markdown file, translate it into English, do NOT modify any existing Markdown commands, do NOT use code wrapper (```), ONLY answer me with translated results:" +
f"\n\n{frag}" for frag in pfg.sp_file_contents]
inputs_show_user_array = [f"翻译 {f}" for f in pfg.sp_file_tag]
sys_prompt_array = ["You are a professional academic paper translator." for _ in range(n_split)]
else:
inputs_array = [f"This is a Markdown file, translate it into {language}, do not modify any existing Markdown commands, only answer me with translated results:" +
inputs_array = [f"This is a Markdown file, translate it into {language}, do NOT modify any existing Markdown commands, do NOT use code wrapper (```), ONLY answer me with translated results:" +
f"\n\n{frag}" for frag in pfg.sp_file_contents]
inputs_show_user_array = [f"翻译 {f}" for f in pfg.sp_file_tag]
sys_prompt_array = ["You are a professional academic paper translator." for _ in range(n_split)]
@@ -99,7 +99,12 @@ def 多文件翻译(file_manifest, project_folder, llm_kwargs, plugin_kwargs, ch
for i_say, gpt_say in zip(gpt_response_collection[0::2], gpt_response_collection[1::2]):
pfg.sp_file_result.append(gpt_say)
pfg.merge_result()
pfg.write_result(language)
output_file_arr = pfg.write_result(language)
for output_file in output_file_arr:
promote_file_to_downloadzone(output_file, chatbot=chatbot)
if 'markdown_expected_output_path' in plugin_kwargs:
expected_f_name = plugin_kwargs['markdown_expected_output_path']
shutil.copyfile(output_file, expected_f_name)
except:
logging.error(trimmed_format_exc())
@@ -159,7 +164,6 @@ def Markdown英译中(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_p
"函数插件功能?",
"对整个Markdown项目进行翻译。函数插件贡献者: Binary-Husky"])
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
disable_auto_promotion(chatbot)
# 尝试导入依赖,如果缺少依赖,则给出安装建议
try:
@@ -199,7 +203,6 @@ def Markdown中译英(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_p
"函数插件功能?",
"对整个Markdown项目进行翻译。函数插件贡献者: Binary-Husky"])
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
disable_auto_promotion(chatbot)
# 尝试导入依赖,如果缺少依赖,则给出安装建议
try:
@@ -232,7 +235,6 @@ def Markdown翻译指定语言(txt, llm_kwargs, plugin_kwargs, chatbot, history,
"函数插件功能?",
"对整个Markdown项目进行翻译。函数插件贡献者: Binary-Husky"])
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
disable_auto_promotion(chatbot)
# 尝试导入依赖,如果缺少依赖,则给出安装建议
try:

查看文件

@@ -28,7 +28,7 @@
| crazy_functions\批量Markdown翻译.py | 将指定目录下的Markdown文件进行中英文翻译 |
| crazy_functions\批量总结PDF文档.py | 对PDF文件进行切割和摘要生成 |
| crazy_functions\批量总结PDF文档pdfminer.py | 对PDF文件进行文本内容的提取和摘要生成 |
| crazy_functions\批量翻译PDF文档_多线程.py | 将指定目录下的PDF文件进行中英文翻译 |
| crazy_functions\PDF批量翻译.py | 将指定目录下的PDF文件进行中英文翻译 |
| crazy_functions\理解PDF文档内容.py | 对PDF文件进行摘要生成和问题解答 |
| crazy_functions\生成函数注释.py | 自动生成Python函数的注释 |
| crazy_functions\联网的ChatGPT.py | 使用网络爬虫和ChatGPT模型进行聊天回答 |
@@ -187,9 +187,9 @@ toolbox.py是一个工具类库,其中主要包含了一些函数装饰器和
该程序文件是一个用于批量总结PDF文档的函数插件,使用了pdfminer插件和BeautifulSoup库来提取PDF文档的文本内容,对每个PDF文件分别进行处理并生成中英文摘要。同时,该程序文件还包括一些辅助工具函数和处理异常的装饰器。
## [24/48] 请对下面的程序文件做一个概述: crazy_functions\批量翻译PDF文档_多线程.py
## [24/48] 请对下面的程序文件做一个概述: crazy_functions\PDF批量翻译.py
这个程序文件是一个Python脚本,文件名为“批量翻译PDF文档_多线程.py”。它主要使用了“toolbox”、“request_gpt_model_in_new_thread_with_ui_alive”、“request_gpt_model_multi_threads_with_very_awesome_ui_and_high_efficiency”、“colorful”等Python库和自定义的模块“crazy_utils”的一些函数。程序实现了一个批量翻译PDF文档的功能,可以自动解析PDF文件中的基础信息,递归地切割PDF文件,翻译和处理PDF论文中的所有内容,并生成相应的翻译结果文件包括md文件和html文件。功能比较复杂,其中需要调用多个函数和依赖库,涉及到多线程操作和UI更新。文件中有详细的注释和变量命名,代码比较清晰易读。
这个程序文件是一个Python脚本,文件名为“PDF批量翻译.py”。它主要使用了“toolbox”、“request_gpt_model_in_new_thread_with_ui_alive”、“request_gpt_model_multi_threads_with_very_awesome_ui_and_high_efficiency”、“colorful”等Python库和自定义的模块“crazy_utils”的一些函数。程序实现了一个批量翻译PDF文档的功能,可以自动解析PDF文件中的基础信息,递归地切割PDF文件,翻译和处理PDF论文中的所有内容,并生成相应的翻译结果文件包括md文件和html文件。功能比较复杂,其中需要调用多个函数和依赖库,涉及到多线程操作和UI更新。文件中有详细的注释和变量命名,代码比较清晰易读。
## [25/48] 请对下面的程序文件做一个概述: crazy_functions\理解PDF文档内容.py
@@ -331,7 +331,7 @@ check_proxy.py, colorful.py, config.py, config_private.py, core_functional.py, c
这些程序源文件提供了基础的文本和语言处理功能、工具函数和高级插件,使 Chatbot 能够处理各种复杂的学术文本问题,包括润色、翻译、搜索、下载、解析等。
## 用一张Markdown表格简要描述以下文件的功能
crazy_functions\代码重写为全英文_多线程.py, crazy_functions\图片生成.py, crazy_functions\对话历史存档.py, crazy_functions\总结word文档.py, crazy_functions\总结音视频.py, crazy_functions\批量Markdown翻译.py, crazy_functions\批量总结PDF文档.py, crazy_functions\批量总结PDF文档pdfminer.py, crazy_functions\批量翻译PDF文档_多线程.py, crazy_functions\理解PDF文档内容.py, crazy_functions\生成函数注释.py, crazy_functions\联网的ChatGPT.py, crazy_functions\解析JupyterNotebook.py, crazy_functions\解析项目源代码.py, crazy_functions\询问多个大语言模型.py, crazy_functions\读文章写摘要.py。根据以上分析,用一句话概括程序的整体功能。
crazy_functions\代码重写为全英文_多线程.py, crazy_functions\图片生成.py, crazy_functions\对话历史存档.py, crazy_functions\总结word文档.py, crazy_functions\总结音视频.py, crazy_functions\批量Markdown翻译.py, crazy_functions\批量总结PDF文档.py, crazy_functions\批量总结PDF文档pdfminer.py, crazy_functions\PDF批量翻译.py, crazy_functions\理解PDF文档内容.py, crazy_functions\生成函数注释.py, crazy_functions\联网的ChatGPT.py, crazy_functions\解析JupyterNotebook.py, crazy_functions\解析项目源代码.py, crazy_functions\询问多个大语言模型.py, crazy_functions\读文章写摘要.py。根据以上分析,用一句话概括程序的整体功能。
| 文件名 | 功能简述 |
| --- | --- |
@@ -343,7 +343,7 @@ crazy_functions\代码重写为全英文_多线程.py, crazy_functions\图片生
| 批量Markdown翻译.py | 将指定目录下的Markdown文件进行中英文翻译 |
| 批量总结PDF文档.py | 对PDF文件进行切割和摘要生成 |
| 批量总结PDF文档pdfminer.py | 对PDF文件进行文本内容的提取和摘要生成 |
| 批量翻译PDF文档_多线程.py | 将指定目录下的PDF文件进行中英文翻译 |
| PDF批量翻译.py | 将指定目录下的PDF文件进行中英文翻译 |
| 理解PDF文档内容.py | 对PDF文件进行摘要生成和问题解答 |
| 生成函数注释.py | 自动生成Python函数的注释 |
| 联网的ChatGPT.py | 使用网络爬虫和ChatGPT模型进行聊天回答 |

查看文件

@@ -44,7 +44,7 @@
"批量总结PDF文档": "BatchSummarizePDFDocuments",
"批量总结PDF文档pdfminer": "BatchSummarizePDFDocumentsUsingPdfminer",
"批量翻译PDF文档": "BatchTranslatePDFDocuments",
"批量翻译PDF文档_多线程": "BatchTranslatePDFDocuments_MultiThreaded",
"PDF批量翻译": "BatchTranslatePDFDocuments_MultiThreaded",
"谷歌检索小助手": "GoogleSearchAssistant",
"理解PDF文档内容标准文件输入": "UnderstandPdfDocumentContentStandardFileInput",
"理解PDF文档内容": "UnderstandPdfDocumentContent",
@@ -1392,7 +1392,7 @@
"1. 临时解决方案": "1. Temporary Solution",
"直接在输入区键入api_key": "Enter the api_key Directly in the Input Area",
"然后回车提交": "Submit after pressing Enter",
"2. 长效解决方案": "Long-term solution",
"2. 长效解决方案": "2. Long-term solution",
"在config.py中配置": "Configure in config.py",
"等待响应": "Waiting for response",
"api-key不满足要求": "API key does not meet requirements",
@@ -2184,7 +2184,8 @@
"接驳VoidTerminal": "Connect to VoidTerminal",
"**很好": "**Very good",
"对话|编程": "Conversation&ImageGenerating|Programming",
"对话|编程|学术": "Conversation&ImageGenerating|Programming|Academic", "4. 建议使用 GPT3.5 或更强的模型": "4. It is recommended to use GPT3.5 or a stronger model",
"对话|编程|学术": "Conversation|Programming|Academic",
"4. 建议使用 GPT3.5 或更强的模型": "4. It is recommended to use GPT3.5 or a stronger model",
"「请调用插件翻译PDF论文": "Please call the plugin to translate the PDF paper",
"3. 如果您使用「调用插件xxx」、「修改配置xxx」、「请问」等关键词": "3. If you use keywords such as 'call plugin xxx', 'modify configuration xxx', 'please', etc.",
"以下是一篇学术论文的基本信息": "The following is the basic information of an academic paper",
@@ -3006,5 +3007,746 @@
"GPT-Academic对话存档": "TranslatedText",
"Arxiv论文精细翻译": "TranslatedText",
"from crazy_functions.AdvancedFunctionTemplate import 测试图表渲染": "from crazy_functions.AdvancedFunctionTemplate import test_chart_rendering",
"测试图表渲染": "test_chart_rendering"
}
"测试图表渲染": "test_chart_rendering",
"请使用「LatexEnglishCorrection+高亮修正位置": "Please use 'LatexEnglishCorrection+highlight corrected positions",
"输出代码片段中!": "Output code snippet!",
"使用多种方式尝试切分文本": "Attempt to split the text in various ways",
"你是一个作家": "You are a writer",
"如果无法从中得到答案": "If unable to get an answer from it",
"无法读取以下数据": "Unable to read the following data",
"不允许直接报错": "Direct error reporting is not allowed",
"您也可以使用插件参数指定绘制的图表类型": "You can also specify the type of chart to be drawn using plugin parameters",
"不要包含太多情节": "Do not include too many plots",
"翻译为中文后重新编译为PDF": "Recompile into PDF after translating into Chinese",
"采样温度": "Sampling temperature",
"直接修改config.py": "Directly modify config.py",
"处理文件": "Handle file",
"判断返回是否正确": "Determine if the return is correct",
"gemini 不允许对话轮次为偶数": "Gemini does not allow the number of dialogue rounds to be even",
"8 象限提示图": "8-quadrant prompt diagram",
"基于上下文的prompt模版": "Context-based prompt template",
"^开始": "^Start",
"输出文本的最大tokens限制": "Maximum tokens limit for output text",
"在这个例子中": "In this example",
"以及处理PDF文件的示例代码": "And example code for handling PDF files",
"更新cookie": "Update cookie",
"获取公共缩进": "Get public indentation",
"请你给出围绕“{subject}”的序列图": "Please provide a sequence diagram around '{subject}'",
"请确保使用小写的模型名称": "Please ensure the use of lowercase model names",
"出现人物时": "When characters appear",
"azure模型对齐支持 -=-=-=-=-=-=-": "Azure model alignment support -=-=-=-=-=-=-",
"请一分钟后重试": "Please try again in one minute",
"解析GEMINI消息出错": "Error parsing GEMINI message",
"选择提示词": "Select prompt words",
"取值范围是": "The value range is",
"它会在": "It will be",
"加载文件": "Load file",
"是预定义按钮": "Is a predefined button",
"消息": "Message",
"默认搜索5条结果": "Default search for 5 results",
"第 2 部分": "Part 2",
"我们采样一个特殊的手段": "We sample a special method",
"后端开发": "Backend development",
"接下来提取md中的一级/二级标题作为摘要": "Next, extract the first/second-level headings in md as summaries",
"一个年轻人穿过天安门广场向纪念堂走去": "A young person walks through Tiananmen Square towards the Memorial Hall",
"将会使用这些摘要绘制图表": "Will use these summaries to draw charts",
"8-象限提示图": "8-quadrant prompt diagram",
"首先": "First",
"设计了此接口": "Designed this interface",
"本地模型": "Local model",
"所有图像仅在最后一个问题中提供": "All images are provided only in the last question",
"如连续3次判断失败将会使用流程图进行绘制": "If there are 3 consecutive failures, a flowchart will be used to draw",
"为了更灵活地接入one-api多模型管理界面": "To access the one-api multi-model management interface more flexibly",
"UI设计": "UI design",
"不允许在答案中添加编造成分": "Fabrication is not allowed in the answer",
"尽可能地": "As much as possible",
"先在前端快速清除chatbot&status": "First, quickly clear chatbot & status in the frontend",
"You exceeded your current quota. Cohere以账户额度不足为由": "You exceeded your current quota. Cohere due to insufficient account quota",
"合并所有的标题": "Merge all headings",
"跳过下载": "Skip download",
"中生产图表": "Production Chart",
"如输入区内容不是文件则直接返回输入区内容": "Return the content of the input area directly if it is not a file",
"用温度取样的另一种方法": "Another method of temperature sampling",
"不需要解释原因": "No need to explain the reason",
"一场延续了两万年的星际战争已接近尾声": "An interstellar war that has lasted for 20,000 years is drawing to a close",
"依次处理文件": "Process files in order",
"第一幕的字数少于300字": "The first act has fewer than 300 characters",
"已成功加载": "Successfully loaded",
"还是web渲染": "Web rendering",
"解析分辨率": "Resolution parsing",
"如果剩余文本的token数大于限制": "If the number of remaining text tokens exceeds the limit",
"你可以修改整个句子的顺序以确保翻译后的段落符合中文的语言习惯": "You can change the order of the whole sentence to ensure that the translated paragraph is in line with Chinese language habits",
"并同时充分考虑中文的语法、清晰、简洁和整体可读性": "And at the same time, fully consider Chinese grammar, clarity, conciseness, and overall readability",
"否则返回": "Otherwise return",
"一个特殊标记": "A special mark",
"4. 后续剧情发展4": "4. Plot development",
"恢复默认": "Restore default",
"转义点号": "Escape period",
"检查DASHSCOPE_API_KEY": "Check DASHSCOPE_API_KEY",
"阿里灵积云API_KEY": "Aliyun API_KEY",
"文件是否存在": "Check if the file exists",
"您的选择是": "Your choice is",
"处理用户对话": "Handle user dialogue",
"即": "That is",
"将会由对话模型首先判断适合的图表类型": "The dialogue model will first determine the appropriate chart type",
"以查看所有的配置信息": "To view all configuration information",
"用于初始化包的属性和导入模块": "For initializing package properties and importing modules",
"to_markdown_tabs 文件list 转换为 md tab": "to_markdown_tabs Convert file list to MD tab",
"更换模型": "Replace Model",
"从以下文本中提取摘要": "Extract Summary from the Following Text",
"表示捕获任意长度的文本": "Indicates Capturing Text of Arbitrary Length",
"可能是一个模块的初始化文件": "May Be an Initialization File for a Module",
"处理提问与输出": "Handle Questions and Outputs",
"需要的再做些简单调整即可": "Some Simple Adjustments Needed",
"所以这个没有用": "So This Is Not Useful",
"请配置 DASHSCOPE_API_KEY": "Please Configure DASHSCOPE_API_KEY",
"不是预定义按钮": "Not a Predefined Button",
"让读者能够感受到你的故事世界": "Let Readers Feel Your Story World",
"开始整理headers与message": "Start Organizing Headers and Messages",
"兼容最新的智谱Ai": "Compatible with the Latest ZhiPu AI",
"对于某些PDF会有第一个段落就以小写字母开头": "For Some PDFs, the First Paragraph May Start with a Lowercase Letter",
"问题是": "The Issue Is",
"也就是说它会匹配尽可能少的字符": "That Is, It Will Match the Least Amount of Characters Possible",
"未能成功加载": "Failed to Load Successfully",
"接入通义千问在线大模型 https": "Access TongYi QianWen Online Large Model HTTPS",
"用不太优雅的方式处理一个core_functional.py中出现的mermaid渲染特例": "Handle a Mermaid Rendering Special Case in core_functional.py in an Ugly Way",
"您也可以选择给出其他故事走向": "You Can Also Choose to Provide Alternative Storylines",
"改善非markdown输入的显示效果": "Improve Display Effects for Non-Markdown Input",
"在二十二世纪编年史中": "In the Chronicle of the 22nd Century",
"docs 为Document列表": "docs Are a List of Documents",
"互动写故事": "Interactive Story Writing",
"4 饼图": "Pie Chart",
"正在生成插图中": "Generating Illustration",
"路径不存在": "Path Does Not Exist",
"PDF翻译中文": "PDF Translation to Chinese",
"进行简短的环境描写": "Conduct a Brief Environmental Description",
"学术英中互译": "Academic English-Chinese Translation",
"且少于2个段落": "And less than 2 paragraphs",
"html_view_blank 超链接": "HTML View Blank Hyperlink",
"处理 history": "Handle History",
"非Cohere官方接口返回了错误": "Non-Cohere Official Interface Returned an Error",
"缺失 MATHPIX_APPID 和 MATHPIX_APPKEY": "Missing MATHPIX_APPID and MATHPIX_APPKEY",
"搜索知识库内容条数": "Search Knowledge Base Content Count",
"返回数据": "Return Data",
"没有相关文件": "No Relevant Files",
"知识库路径": "Knowledge Base Path",
"质量与风格默认值": "Quality and Style Defaults",
"包含了用于文本切分的函数": "Contains Functions for Text Segmentation",
"请你给出围绕“{subject}”的逻辑关系图": "Please Provide a Logic Diagram Surrounding '{subject}'",
"官方Pro服务器🧪": "Official Pro Server",
"不支持同时处理多个pdf文件": "Does Not Support Processing Multiple PDF Files Simultaneously",
"查询5天历史事件": "Query 5-Day Historical Events",
"你是经验丰富的翻译": "You Are an Experienced Translator",
"html输入": "HTML Input",
"输入文件不存在": "Input File Does Not Exist",
"很多人生来就会莫名其妙地迷上一样东西": "Many People Are Born with an Unexplained Attraction to Something",
"默认值为 0.7": "Default Value is 0.7",
"值越大": "The Larger the Value",
"以下文件未能成功加载": "The Following Files Failed to Load",
"在线模型": "Online Model",
"切割输入": "Cut Input",
"修改docker-compose.yml等价于修改容器内部的环境变量": "Modifying docker-compose.yml is Equivalent to Modifying the Internal Environment Variables of the Container",
"以换行符分割": "Split by Line Break",
"修复中文乱码的问题": "Fix Chinese Character Encoding Issues",
"zhipuai 是glm-4的别名": "zhipuai is an alias for glm-4",
"保证其在允许范围内": "Ensure it is within the permissible range",
"段尾如果有多余的\\n就去掉它": "Remove any extra \\n at the end of the paragraph",
"是否流式输出": "Whether to stream output",
"1-流程图": "1-Flowchart",
"学术语料润色": "Academic text polishing",
"已经超过了模型的最大上下文或是模型格式错误": "Has exceeded the model's maximum context or there is a model format error",
"英文省略号": "English ellipsis",
"登录成功": "Login successful",
"随便切一下吧": "Just cut it randomly",
"PDF转换为tex项目失败": "PDF conversion to TeX project failed",
"的 max_token 配置不是整数": "The max_token configuration is not an integer",
"根据当前聊天历史或指定的路径文件": "According to the current chat history or specified path file",
"你必须利用以下文档中包含的信息回答这个问题": "You must use the information contained in the following document to answer this question",
"对话、日志记录": "Dialogue, logging",
"内容至知识库": "Content to knowledge base",
"在银河系的中心": "At the center of the Milky Way",
"检查PDF是否被重复上传": "Check if the PDF has been uploaded multiple times",
"取最后 max_prompt_tokens 个 token 输入模型": "Take the last max_prompt_tokens tokens as input to the model",
"请输入图类型对应的数字": "Please enter the corresponding number for the graph type",
"插件主程序3 =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=": "Plugin main program 3 -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=",
"正在tex项目将翻译为中文": "The TeX project is being translated into Chinese",
"适配润色区域": "Adapter polishing area",
"首先你从历史记录中提取摘要": "First, you extract an abstract from the history",
"讯飞星火认知大模型 -=-=-=-=-=-=-": "iFLYTEK Spark Cognitive Model -=-=-=-=-=-=-=-=-=-",
"包含了用于构建和管理向量数据库的函数和类包含了用于构建和管理向量数据库的函数和类包含了用于构建和管理向量数据库的函数和类": "Contains functions and classes for building and managing vector databases",
"另外": "Additionally",
"内部调优参数": "Internal tuning parameters",
"输出格式例如": "Example of Output Format",
"当回复图像时": "When Responding with an Image",
"越权访问!": "Unauthorized Access!",
"如果给出的 prompt 的 token 长度超过此限制": "If the Given Prompt's Token Length Exceeds This Limit",
"因此你每次写的故事段落应少于300字": "Therefore, Each Story Paragraph You Write Should Be Less Than 300 Words",
"尽量短": "As Concise as Possible",
"中文提示词就不显示了": "Chinese Keywords Will Not Be Displayed",
"请在前文的基础上": "Please Based on the Previous Text",
"20张": "20 Sheets",
"文件内容优先": "File Content Takes Priority",
"状态图": "State Diagram",
"开始查找合适切分点的偏移": "Start Looking for the Offset of an Appropriate Split Point",
"已知信息": "Known Information",
"文心一言大模型": "Wenxin Yanyan Large Model",
"传递进来一些奇怪的东西": "Passing in Some Weird Things",
"很多规则中会考虑分号": "Many Rules Consider the Semicolon",
"请配置YUNQUE_SECRET_KEY": "Please Configure YUNQUE_SECRET_KEY",
"6-状态图": "6-State Diagram",
"输出文本的最小tokens限制": "Minimum Tokens Limit for Output Text",
"服务节点": "Service Node",
"云雀大模型": "Lark Large Model",
"请配置 GEMINI_API_KEY": "Please Configure GEMINI_API_KEY",
"可以让软件运行在 http": "Can Run the Software Over HTTP",
"基于当前对话或文件GenerateMultipleMermaidCharts": "Generate Multiple Mermaid Charts Based on the Current Conversation or File",
"剧情收尾": "Plot Conclusion",
"请开始提问": "Please Begin Your Question",
"第一页内容/摘要": "First Page Content/Summary",
"无法判断则返回image/jpeg": "Return image/jpeg If Unable to Determine",
"仅需要输出单个不带任何标点符号的数字": "Single digit without any punctuation",
"以下是每类图表的PROMPT": "Here are the PROMPTS for each type of chart",
"状态码": "Status code",
"TopP值越大输出的tokens类型越丰富": "The larger the TopP value, the richer the types of output tokens",
"files_filter_handler 根据type过滤文件": "files_filter_handler filters files by type",
"比较每一页的内容是否相同": "Compare whether each page's content is the same",
"前往": "Go to",
"请输入剧情走向": "Please enter the plot direction",
"故事收尾": "Story ending",
"必须说明正在回复哪张图像": "Must specify which image is being replied to",
"历史文件继续上传": "Continue uploading historical files",
"因此禁用": "Therefore disabled",
"使用lru缓存": "Use LRU caching",
"该装饰器是大多数功能调用的入口": "This decorator is the entry point for most function calls",
"如果需要开启": "If needed to enable",
"使用 json 解析库进行处理": "Process using JSON parsing library",
"将PDF转换为Latex项目": "Convert PDF to LaTeX project",
"7-实体关系图": "7-Entity relationship diagram",
"根据用户的提示": "According to the user's prompt",
"当前用户的请求信息": "Current user's request information",
"配置关联关系说明": "Configuration relationship description",
"这段代码是使用Python编程语言中的re模块": "This code uses the re module in the Python programming language",
"link_mtime_to_md 文件增加本地时间参数": "link_mtime_to_md adds local time parameter to the file",
"从当前对话或路径": "From the current conversation or path",
"一起写故事": "Write a story together",
"前端开发": "Front-end development",
"开区间": "Open interval",
"如插件参数不正确则使用对话模型判断": "If the plugin parameters are incorrect, use the dialogue model for judgment",
"对字符串进行处理": "Process the string",
"简洁和专业的来回答用户的问题": "Answer user questions concisely and professionally",
"如输入区不是文件则将输入区内容加入历史记录": "If the input area is not a file, add the content of the input area to the history",
"编写一个小说的第一幕": "Write the first act of a novel",
"更具创造性;": "More creative;",
"用于解析和翻译PDF文件的功能和相关辅助函数用于解析和翻译PDF文件的功能和相关辅助函数用于解析和翻译PDF文件的功能和相关辅助函数": "Functions and related auxiliary functions for parsing and translating PDF files",
"月之暗面 -=-=-=-=-=-=-": "The Dark Side of the Moon -=-=-=-=-=-=-",
"2. 后续剧情发展2": "2. Subsequent plot development 2",
"请先提供文本的更正版本": "Please provide the corrected version of the text first",
"修改环境变量": "Modify environment variables",
"读取之前的自定义按钮": "Read previous custom buttons",
"如果为0": "If it is 0",
"函数用于去除多行字符串的缩进": "Function to remove indentation from multiline strings",
"请绘制有关“": "Please draw something about \"",
"给出4种不同的后续剧情发展方向": "Provide 4 different directions for subsequent plot development",
"新调优版本GPT-4🔥": "Newly tuned version GPT-4🔥",
"已弃用": "Deprecated",
"参考 https": "Refer to https",
"发现重复上传": "Duplicate upload detected",
"本项目的所有配置都集中在config.py中": "All configurations for this project are centralized in config.py",
"默认值为 0.95": "Default value is 0.95",
"请查阅": "Please refer to",
"此选项已废弃": "This option is deprecated",
"找到了.doc文件": ".doc file found",
"他们的目的地是南极": "Their destination is Antarctica",
"lang_reference这段文字是": "The lang_reference text is",
"正在尝试生成对比PDF": "Attempting to generate a comparative PDF",
"input_encode_handler 提取input中的文件": "input_encode_handler Extracts files from input",
"使用中文": "Use Chinese",
"一些垃圾第三方接口会出现这样的错误": "Some crappy third-party interfaces may produce such errors",
"例如将空格转换为&nbsp": "For example, converting spaces to &nbsp",
"请你给出围绕“{subject}”的类图": "Please provide a class diagram around '{subject}'",
"是插件的内部参数": "Is an internal parameter of the plugin",
"网络波动时可选其他": "Alternative options when network fluctuates",
"非Cohere官方接口的出现这样的报错": "Such errors occur in non-Cohere official interfaces",
"是前缀": "Is a prefix",
"默认 None": "Default None",
"如果几天后能顺利到达那里": "If we can smoothly arrive there in a few days",
"输出1": "Output 1",
"3-类图": "3-Class Diagram",
"如需绘制思维导图请使用参数调用": "Please use parameters to call if you need to draw a mind map",
"正在将PDF转换为tex项目": "Converting PDF to TeX project",
"列出10个经典名著": "List 10 classic masterpieces",
"? 在这里用作非贪婪匹配": "? Used here as a non-greedy match",
"左上角更换模型菜单中可切换openai": "Switch to OpenAI in the model change menu in the top left corner",
"原样返回": "Return as is",
"请配置 MATHPIX_APPID 和 MATHPIX_APPKEY": "Please configure MATHPIX_APPID and MATHPIX_APPKEY",
"概括上述段落的内容以及内在逻辑关系": "Summarize the content of the above paragraph and its inherent logical relationship",
"cookie相关工具函数": "Cookie-related utility functions",
"请你给出围绕“{subject}”的饼图": "Please provide a pie chart around '{subject}'",
"原型设计": "Prototype design",
"必须为正数": "Must be a positive number",
"又一阵剧痛从肝部袭来": "Another wave of severe pain strikes from the liver",
"智谱AI": "Zhipu AI",
"基础功能区按钮的附加功能": "Additional functions of the basic functional area buttons",
"one-api 对齐支持 -=-=-=-=-=-=-": "one-api alignment support -=-=-=-=-=-=-",
"5 甘特图": "5 Gantt chart",
"用于初始化包的属性和导入模块是一个包的初始化文件": "The file used for initializing package properties and importing modules is an initialization file for the package",
"创建并修改config_private.py": "Create and modify config_private.py",
"会使输出更随机": "Would make the output more random",
"已添加": "Added",
"估计一个切分点": "Estimate a split point",
"\\n\\n1. 临时解决方案": "\\n\\n1. Temporary solution",
"没有回答": "No answer",
"尝试重新翻译PDF": "Try to retranslate the PDF",
"被这个解码给耍了": "Fooled by this decoding",
"再在后端清除history": "Clear history on the backend again",
"根据情况选择flowchart LR": "Choose flowchart LR based on the situation",
"幻方-深度求索大模型 -=-=-=-=-=-=-": "Deep Seek Large Model -=-=-=-=-=-=-",
"即使它们在历史记录中被提及": "Even if they are mentioned in the history",
"此处需要进一步优化逻辑": "Further logic optimization is needed here",
"借鉴自同目录下的bridge_ChatGPT.py": "Derived from the bridge_ChatGPT.py in the same directory",
"正是这样": "That's exactly right",
"您也可以给出您心中的其他故事走向": "You can also provide other story directions in your mind",
"文本预处理": "Text preprocessing",
"请登录": "Please log in",
"请修改docker-compose": "Please modify docker-compose",
"运行一些异步任务": "Run some asynchronous tasks",
"5-甘特图": "5-Gantt chart",
"3 类图": "3-Class diagram",
"因为你接下来将会与用户互动续写下面的情节": "Because you will interact with the user to continue writing the plot below",
"避免把同一个文件添加多次": "Avoid adding the same file multiple times",
"可挑选精度": "Selectable precision",
"调皮一下": "Play a joke",
"并解析": "And parse",
"您可以在输入框中输入一些关键词": "You can enter some keywords in the input box",
"文件加载失败": "File loading failed",
"请你给出围绕“{subject}”的甘特图": "Please provide a Gantt chart around \"{subject}\"",
"上传PDF": "Upload PDF",
"请判断适合使用的流程图类型": "Please determine the suitable flowchart type",
"错误码": "Error code",
"非markdown输入": "Non-markdown input",
"所以只能通过提示词对第几张图片进行定位": "So can only locate the image by the prompt",
"避免下载到缓存文件": "Avoid downloading cached files",
"没有思维导图!!!测试发现模型始终会优先选择思维导图": "No mind map!!! Testing found that the model always prioritizes mind maps",
"请登录Cohere查看详情 https": "Please log in to Cohere for details https",
"检查历史上传的文件是否与新上传的文件相同": "Check if the previously uploaded file is the same as the newly uploaded file",
"加载主题相关的工具函数": "Load theme-related utility functions",
"图表类型由模型判断": "Chart type is determined by the model",
"⭐ 多线程方法": "Multi-threading method",
"获取 max_token 的值": "Get the value of max_token",
"空白的输入栏": "Blank input field",
"根据整理的摘要选择图表类型": "Select chart type based on the organized summary",
"返回 True": "Return True",
"这里为了区分中英文情景搞复杂了一点": "Here it's a bit complicated to distinguish between Chinese and English contexts",
"ZHIPUAI_MODEL 配置项选项已经弃用": "ZHIPUAI_MODEL configuration option is deprecated",
"但是这里我把它忽略不计": "But here I ignore it",
"非必要": "Not necessary",
"思维导图": "Mind map",
"插件」": "Plugin",
"重复文件路径": "Duplicate file path",
"之间不要存在空格": "No spaces between fields",
"破折号、英文双引号等同样忽略": "Ignore dashes, English quotes, etc.",
"填写 VOLC_ACCESSKEY": "Enter VOLC_ACCESSKEY",
"称为核取样": "Called nuclear sampling",
"Incorrect API key. 请确保API key有效": "Incorrect API key. Please ensure the API key is valid",
"如输入区内容为文件则清空历史记录": "If the input area content is a file, clear the history",
"并处理精度问题": "And handle precision issues",
"并给出修改的理由": "And provide reasons for the changes",
"至此已经超出了正常接口应该进入的范围": "This has exceeded the scope that a normal interface should enter",
"并已加载知识库": "And the knowledge base has been loaded",
"file_manifest_filter_html 根据type过滤文件": "file_manifest_filter_html filters files by type",
"participant B as 系统": "participant B as System",
"要留出足够的互动空间": "Leave enough interaction space",
"请你给出围绕“{subject}”的实体关系图": "Please provide an entity relationship diagram around '{subject}'",
"答案请使用中文": "Please answer in Chinese",
"输出会更加稳定或确定": "The output will be more stable or certain",
"是一个包的初始化文件": "Is an initialization file for a package",
"用于加载和分割文件中的文本的通用文件加载器用于加载和分割文件中的文本的通用文件加载器用于加载和分割文件中的文本的通用文件加载器": "A universal file loader for loading and splitting text in files",
"围绕我选定的剧情情节": "Around the plot I have chosen",
"Mathpix 拥有执行PDF的OCR功能": "Mathpix has OCR functionality for PDFs",
"是否允许暴力切分": "Whether to allow violent segmentation",
"清空 txt_tmp 对应的位置方便下次搜索": "Clear the location corresponding to txt_tmp for easier next search",
"编写小说的最后一幕": "Write the last scene of the novel",
"可能是一个模块的初始化文件根据位置和名称": "May be an initialization file for a module based on position and name",
"更新新的自定义按钮": "Update new custom button",
"把分句符\\n放到双引号后": "Put the sentence separator \\n after the double quotes",
"序列图": "Sequence diagram",
"兼容非markdown输入": "Compatible with non-markdown input",
"那么就切": "Then cut",
"4-饼图": "4-Pie chart",
"结束剧情": "End of the plot",
"字数要求": "Word count requirement",
"以下是对以上文本的总结": "Below is a summary of the above text",
"但不要同时调整两个参数": "But do not adjust two parameters at the same time",
"📌省略": "Omit",
"请查看message": "Please check the message",
"如果所有页的内容都相同": "If all pages have the same content",
"我将在这4个选择中": "I will choose from these 4 options",
"请设置为True": "Please set to True",
"当 remain_txt_to_cut": "When remain_txt_to_cut",
"后续输出被截断": "Subsequent output is truncated",
"检查API_KEY": "Check API_KEY",
"阿里云实时语音识别 配置难度较高": "Alibaba Cloud real-time speech recognition has a higher configuration difficulty",
"图像生成提示为空白": "Image generation prompt is blank",
"由于实体关系图用到了{}符号": "Because the entity relationship diagram uses the {} symbol",
"系统繁忙": "System busy",
"月之暗面 API KEY": "Dark side of the moon API KEY",
"编写小说的下一幕": "Write the next scene of the novel",
"选择一种": "Choose one",
"或者flowchart TD": "Or flowchart TD",
"请把以下学术文章段落翻译成中文": "Please translate the following academic article paragraph into Chinese",
"7 实体关系图": "7 Entity relationship diagram",
"处理游戏的主体逻辑": "Handle the main logic of the game",
"请以“{headstart}”为开头": "Please start with \"{headstart}\"",
"匹配后单段上下文长度": "Length of single segment context after matching",
"先行者知道": "The pioneer knows",
"以及处理PDF文件的示例代码包含了用于文本切分的函数": "Example code for processing PDF files includes functions for text segmentation",
"未发现重复上传": "No duplicate uploads found",
"那么就不用切了": "Then there's no need to split",
"目前来说": "Currently",
"请在LLM_MODEL中配置": "Please configure in LLM_MODEL",
"是否启用上下文关联": "Whether to enable context association",
"为了加速计算": "To speed up calculations",
"登录请求": "Login request",
"这里解释一下正则表达式中的几个特殊字符": "Explanation of some special characters in regular expressions",
"其中数字对应关系为": "The corresponding relationship of the numbers is",
"修改配置有三种方法": "There are three ways to modify the configuration",
"请前往arxiv打开此论文下载页面": "Please go to arXiv and open the paper download page",
"然后download source手动下载latex源码包": "Then manually download the LaTeX source package by downloading the source",
"功能单元": "Functional unit",
"你需要翻译的文本如下": "The text you need to translate is as follows",
"以便于后续快速的匹配和查找操作": "To facilitate rapid matching and search operations later",
"文本内容": "Text content",
"自动更新、打开浏览器页面、预热tiktoken模块": "Auto-update, open browser page, warm up tiktoken module",
"原样传递": "Pass through as is",
"但是该文件格式不被支持": "But the file format is not supported",
"他现在是全宇宙中唯一的一个人了": "He is now the only person in the entire universe",
"取值范围0~1": "Value range 0~1",
"搜索匹配score阈值": "Search match score threshold",
"当字符串中有掩码tag时": "When there is a mask tag in the string",
"错误的不纳入对话": "Errors are not included in the conversation",
"英语": "English",
"象限提示图": "Quadrant prompt diagram",
"由于不管提供文本是什么": "Because regardless of what the provided text is",
"确定后续剧情的发展": "Determine the development of the subsequent plot",
"处理空输入导致报错的问题 https": "Handle the error caused by empty input",
"第 3 部分": "Part 3",
"不能等于 0 或 1": "Cannot be equal to 0 or 1",
"同时过大的图表可能需要复制到在线编辑器中进行渲染": "Large charts may need to be copied to an online editor for rendering",
"装饰器函数ArgsGeneralWrapper": "Decorator function ArgsGeneralWrapper",
"写个函数移除所有的换行符": "Write a function to remove all line breaks",
"默认为False": "Default is False",
"实例化BaiduSpider": "Instantiate BaiduSpider",
"9-思维导图": "Mind Map 9",
"是否开启跨域": "Whether to enable cross-domain",
"随机InteractiveMiniGame": "Random InteractiveMiniGame",
"用于构建HTML报告的类和方法用于构建HTML报告的类和方法用于构建HTML报告的类和方法": "Classes and methods for building HTML reports",
"这里填一个提示词字符串就行了": "Just fill in a prompt string here",
"文本切分": "Text segmentation",
"用于在生成mermaid图表时隐藏代码块": "Used to hide code blocks when generating mermaid charts",
"如果剩余文本的token数小于限制": "If the number of tokens in the remaining text is less than the limit",
"未能在规定时间内完成任务": "Failed to complete the task within the specified time",
"API key has been deactivated. Cohere以账户失效为由": "API key has been deactivated. Cohere cited account expiration as the reason",
"正在使用讯飞图片理解API": "Using the Xunfei Image Understanding API",
"如果您使用docker-compose部署": "If you deploy using docker-compose",
"最大输入 token 数": "Maximum input token count",
"遇到了控制请求速率限制": "Encountered control request rate limit",
"数值范围约为0-1100": "The numerical range is approximately 0-1100",
"几乎使他晕厥过去": "Almost made him faint",
"识图模型GPT-4V": "Image recognition model GPT-4V",
"零一万物模型 -=-=-=-=-=-=-": "Zero-One Universe Model",
"所有对话记录将自动保存在本地目录": "All conversation records will be saved automatically in the local directory",
"饼图": "Pie Chart",
"添加Live2D": "Add Live2D",
"⭐ 单线程方法": "Single-threaded Method",
"配图": "Illustration",
"根据上述已知信息": "Based on the Above Known Information",
"1. 后续剧情发展1": "1. Subsequent Plot Development 1",
"2-序列图": "Sequence Diagram",
"流程图": "Flowchart",
"需求分析": "Requirement Analysis",
"我认为更合理的是": "I Think a More Reasonable Approach Is",
"claude家族": "Claude Family",
"”的逻辑关系图": "Logic Relationship Diagram",
"给出人物的名字": "Provide the Names of Characters",
"无法自动下载该论文的Latex源码": "Unable to Automatically Download the LaTeX Source Code of the Paper",
"需要用户手动处理的信息": "Information That Requires Manual Processing by Users",
"点击展开“文件下载区”": "Click to Expand 'File Download Area'",
"生成长度过长": "Excessive Length Generated",
"\\n\\n2. 长效解决方案": "2. Long-term Solution",
"=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 插件主程序2 =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=": "=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= Plugin Main Program 2 =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=",
"title 项目开发流程": "Title Project Development Process",
"如果您希望剧情立即收尾": "If You Want the Plot to End Immediately",
"空格转换为&nbsp": "Space Converted to &nbsp;",
"图片数量超过api上限": "Number of Images Exceeds API Limit",
"他知道": "He Knows",
"在这里输入自定义参数「分辨率-质量": "Enter Custom Parameters Here 'Resolution-Quality",
"例如ChatGLM&gpt-3.5-turbo&gpt-4": "For example ChatGLM, gpt-3.5-turbo, and gpt-4",
"账户管理": "Account Management",
"正在将翻译好的项目tex项目编译为PDF": "Compiling the Translated Project .tex Project into PDF",
"我们把 _max 后的文字转存至 remain_txt_to_cut_storage": "We save the text after _max to the remain_txt_to_cut_storage",
"标签之前停止匹配": "Stop matching before the label",
"例子": "Example",
"遍历检查是否有额外参数": "Iterate to check for extra parameters",
"文本分句长度": "Length of text segmentation",
"请你给出围绕“{subject}”的状态图": "Please provide a state diagram surrounding \"{subject}\"",
"用stream的方法避免中途网线被掐": "Use the stream method to avoid the cable being disconnected midway",
"然后在markdown表格中列出修改的内容": "Then list the changes in a Markdown table",
"以上是从文章中提取的摘要": "The above is an abstract extracted from the article",
"但是无法找到相关文件": "But unable to find the relevant file",
"上海AI-LAB书生大模型 -=-=-=-=-=-=-": "Shanghai AI-LAB Shu Sheng Large Model -=-=-=-=-=-=-",
"遇到第一个": "Meet the first",
"存储在名为const_extract_exp的变量中": "Stored in a variable named const_extract_exp",
"括号在正则表达式中表示捕获组": "Parentheses represent capture groups in regular expressions",
"那里的太空中渐渐隐现出一个方形区域": "A square area gradually appears in the space there",
"智谱GLM4超级模型🔥": "Zhipu GLM4 Super Model🔥",
"故事开头": "Beginning of the story",
"请检查文件格式是否正确": "Please check if the file format is correct",
"这个模式被编译成一个正则表达式对象": "This pattern is compiled into a regular expression object",
"单字符断句符": "Single character sentence break",
"看后续支持吧": "Let's see the follow-up support",
"markdown输入": "Markdown input",
"系统": "System",
"80字以内": "Within 80 characters",
"一个测试mermaid绘制图表的功能": "A function to test the Mermaid chart drawing",
"输入部分": "Input section",
"移除右侧逗号": "Remove the comma on the right",
"因此思维导图仅能通过参数调用": "Therefore, the mind map can only be invoked through parameters",
"6 状态图": "State Diagram",
"类图": "Class Diagram",
"不要重复前文": "Do not repeat the previous text",
"但内部": "But internally",
"小说的下一幕字数少于300字": "The next scene of the novel has fewer than 300 words",
"每个发展方向都精明扼要地用一句话说明": "Each development direction is concisely described in one sentence",
"充分考虑其之间的逻辑": "Fully consider the logic between them",
"兼顾前端状态的功能": "Take into account the functionality of the frontend state",
"1 流程图": "Flowchart",
"用户QQ群925365219": "User QQ Group 925365219",
"通义-本地模型 -=-=-=-=-=-=-": "Tongyi - Local Model",
"取值范围0-1000": "Value range 0-1000",
"但不是^*.开始": "But not ^*. Start",
"他们将钻出地壳去看诗云": "They will emerge from the crust to see the poetry cloud",
"我们正在互相讨论": "We are discussing with each other",
"值越小": "The smaller the value",
"请在以下几种故事走向中": "Please choose from the following story directions",
"请先把模型切换至gpt-*": "Please switch the model to gpt-* first",
"不再需要填写": "No longer needs to be filled out",
"深夜": "Late at night",
"小说的前文回顾": "Review of the previous text of the novel",
"项目文件树": "Project file tree",
"如果双引号前有终止符": "If there is a terminator before the double quotes",
"participant A as 用户": "Participant A as User",
"处理游戏初始化等特殊情况": "Handle special cases like game initialization",
"然后使用mermaid+llm绘制图表": "Then use mermaid+llm to draw charts",
"0表示不生效": "0 means not effective",
"在以下的剧情发展中": "In the following plot development",
"模型考虑具有 top_p 概率质量 tokens 的结果": "Model considering results with top_p probability quality tokens",
"根据字符串要给谁看": "Depending on who is intended to view the string",
"没有设置YIMODEL_API_KEY选项": "YIMODEL_API_KEY option is not set",
"换行符转换为": "Convert line breaks to",
"-风格": "-style",
"默认情况下并发量极低": "Default to a very low level of concurrency",
"为字符串加上上面定义的前缀和后缀": "Add the defined prefix and suffix to the string",
"先切换模型到gpt-*": "Switch the model to gpt-* first",
"它确保我们匹配的任意文本是尽可能短的": "It ensures that any text we match is as short as possible",
"积极地运用环境描写、人物描写等手法": "Actively use techniques such as environmental and character descriptions",
"零一万物": "Zero One Universe",
"html_local_file 本地文件取相对路径": "html_local_file takes the relative path of the local file",
"伊依一行三人乘坐一艘游艇在南太平洋上做吟诗航行": "Yi Yi and three others set sail on a yacht to recite poetry in the South Pacific",
"移除左边通配符": "Remove left wildcard characters",
"随后绘制图表": "Draw a chart subsequently",
"输入2": "Input 2",
"所以用最没有意义的一个点代替": "Therefore, replace it with the most meaningless point",
"等": "etc.",
"是本地文件": "Is a local file",
"正在文本切分": "Text segmentation in progress",
"等价于修改容器内部的环境变量": "Equivalent to modifying the environment variables inside the container",
"cohere等请求源": "Cohere and other request sources",
"我们再把 remain_txt_to_cut_storage 中的部分文字取出": "Then we extract part of the text from remain_txt_to_cut_storage",
"生成带掩码tag的字符串": "Generate a string with masked tags",
"智谱 -=-=-=-=-=-=-": "ZhiPu -=-=-=-=-=-=-",
"前缀字符串": "Prefix string",
"Temperature值越大随机性越大": "The larger the Temperature value, the greater the randomness",
"借用PDF切割中的函数对文本进行切割": "Use functions from PDF cutting to segment the text",
"挑选一种剧情发展": "Choose a plot development",
"将换行符转换为": "Convert line breaks to",
"0.1 意味着模型解码器只考虑从前 10% 的概率的候选集中取 tokens": "0.1 means the model decoder only considers taking tokens from the top 10% probability candidates",
"确定故事的下一步": "Determine the next step of the story",
"个文件的显示": "Display of a file",
"用于控制输出tokens的多样性": "Used to control the diversity of output tokens",
"导入BaiduSpider": "Import BaiduSpider",
"不输入则为模型自行判断": "If not entered, the model will judge on its own",
"准备下一次迭代": "Prepare for the next iteration",
"包含一些用于文本处理和模型微调的函数和装饰器包含一些用于文本处理和模型微调的函数和装饰器包含一些用于文本处理和模型微调的函数和装饰器": "Contains functions and decorators for text processing and model fine-tuning",
"由于没有单独的参数保存包含图片的历史": "Since there is no separate parameter to save the history with images",
"section 开发": "section development",
"注意这里没有掩码tag": "Note that there is no mask tag here",
"section 设计": "section design",
"对话|编程|学术|智能体": "Dialogue | Programming | Academic | Intelligent Agent",
"您只需要选择其中一种即可": "You only need to choose one of them",
"添加Live2D形象": "Add Live2D image",
"请用以下命令安装": "Please install with the following command",
"触发了Google的安全访问策略": "Triggered Google's safe access policy",
"参数示例「1024x1024-hd-vivid」 || 分辨率支持 「1024x1024」": "Parameter example '1024x1024-hd-vivid' || Resolution support '1024x1024'",
"结局除外": "Excluding the ending",
"subgraph 函数调用": "subgraph function call",
"项目示意图": "Project diagram",
"实体关系图": "Entity relationship diagram",
"计算机把他的代号定为M102": "The computer named his code M102",
"首先尝试用双空行": "Try using double empty lines first",
"接下来将判断适合的图表类型": "Next, determine the appropriate chart type",
"注意前面的几句都小心保留了双引号": "Note that the previous sentences have carefully preserved double quotes",
"您正在调用插件": "You are calling a plugin",
"从上到下": "From top to bottom",
"请配置HUOSHAN_API_KEY": "Please configure HUOSHAN_API_KEY",
"知识检索内容相关度 Score": "Knowledge retrieval content relevance score",
"所以不会被处理": "So it will not be processed",
"设置10秒即可": "Set to 10 seconds",
"以空格分割": "Separated by space",
"根据位置和名称": "According to position and name",
"一些垃圾第三方接口出现这样的错误": "Some crappy third-party interfaces have this error",
"////////////////////// 输入清除键 ///////////////////////////": "////////////////////// Input Clear Key ///////////////////////////",
"并解析为html or md 文本": "And parse as HTML or MD text",
"匹配单段内容的连接上下文长度": "Matching single section content connection context length",
"控制输出的随机性": "Control the randomness of output",
"是模型名": "Is model name",
"请检查配置文件": "Please check the configuration file",
"如何使用one-api快速接入": "How to quickly access using one-api",
"请求失败": "Request failed",
"追加列表": "Append list",
"////////////////////// 函数插件区 ///////////////////////////": "////////////////////// Function Plugin Area ///////////////////////////",
"你是WPSAi": "You are WPSAi",
"第五部分 一些文件处理方法": "Part Five Some file processing methods",
"圆圆迷上了肥皂泡": "Yuan Yuan is fascinated by soap bubbles",
"可选参数": "Optional parameters",
"one-api模型": "one-api model",
"port/gpt_academic/ 下": "Under port/gpt_academic/",
"下一段故事": "Next part of the story",
"* 表示前一个字符可以出现0次或多次": "* means the previous character can appear 0 or more times",
"向后兼容配置": "Backward compatible configuration",
"输出部分": "Output section",
"稍后": "Later",
"比如比喻、拟人、排比、对偶、夸张等等": "For example, similes, personification, parallelism, antithesis, hyperbole, etc.",
"是自定义按钮": "Is a custom button",
"你需要根据用户给出的小说段落": "You need to based on the novel paragraph given by the user",
"以mermaid flowchart的形式展示": "Display in the form of a mermaid flowchart",
"最后一幕的字数少于1000字": "The last scene has fewer than 1000 words",
"如没出错则保持为空": "Keep it empty if there are no errors",
"建议您根据应用场景调整 top_p 或 temperature 参数": "It is recommended to adjust the top_p or temperature parameters according to the application scenario",
"仿佛他的出生就是要和这东西约会似的": "As if his birth was meant to date this thing",
"处理特殊的渲染问题": "Handle special rendering issues",
"我认为最合理的故事结局是": "I think the most reasonable ending for the story is",
"请给出上方内容的思维导图": "Please provide a mind map of the content above",
"点other Formats": "Click on other Formats",
"文件加载完毕": "File loaded",
"Your account is not active. Cohere以账户失效为由": "Your account is not active. Cohere cites the account's inactivation as the reason",
"找不到任何.pdf文件": "Cannot find any .pdf files",
"请根据判断结果绘制相应的图表": "Please draw the corresponding chart based on the judgment result",
"积极地运用修辞手法": "Actively use rhetorical devices",
"工具函数 =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-": "Utility function -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=",
"=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 插件主程序1 =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=": "=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= Plugin Main Program 1 =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=",
"在": "In",
"即正则表达式库": "That is, the regular expression library",
"////////////////////// 基础功能区 ///////////////////////////": "////////////////////// Basic Function Area ///////////////////////////",
"并重新编译PDF | 输入参数为路径": "And recompile PDF | Input parameter is the path",
"甘特图": "Gantt Chart",
"但是需要注册账号": "But registration is required",
"获取完整的从Cohere返回的报错": "Get the complete error message returned from Cohere",
"合并摘要": "Merge Summary",
"这最后一课要提前讲了": "The last lesson will be taught ahead of schedule",
"大模型": "Large Model",
"查找输入区内容中的文件": "Find files in the input area content",
"预处理参数": "Preprocessing Parameters",
"这段代码定义了一个名为ProxyNetworkActivate的空上下文管理器": "This code defines an empty context manager named ProxyNetworkActivate",
"对话错误": "Dialogue Error",
"确定故事的结局": "Determine the ending of the story",
"第 1 部分": "Part 1",
"直到遇到括号外部最近的限定符": "Until the nearest qualifier outside the parentheses is encountered",
"负责向用户前端展示对话": "Responsible for displaying dialogue to the user frontend",
"查询内容": "Query Content",
"匹配结果更精准": "More accurate matching results",
"根据选择的图表类型绘制图表": "Draw a chart based on the selected chart type",
"空格、换行、空字符串都会报错": "Spaces, line breaks, and empty strings will all result in errors",
"请尝试削减单次输入的文本量": "Please try to reduce the amount of text in a single input",
"上传到路径": "Upload to path",
"中": "In",
"后缀字符串": "Suffix string",
"您还可以在接入one-api时": "You can also when accessing one-api",
"请说 “根据已知信息无法回答该问题” 或 “没有提供足够的相关信息”": "Please say 'Cannot answer the question based on available information' or 'Not enough relevant information is provided'",
"Cohere和API2D不会走这里": "Cohere and API2D will not go here",
"节点名字使用引号包裹": "Node names should be enclosed in quotes",
"这次的故事开头是": "The beginning of this story is",
"你是一个想象力丰富的杰出作家": "You are a brilliant writer with a rich imagination",
"正在与你的朋友互动": "Interacting with your friends",
"/「-hd」 || 风格支持 「-vivid」": "/ '-hd' || Style supports '-vivid'",
"如输入区无内容则直接解析历史记录": "If the input area is empty, parse the history directly",
"根据以上的情节": "Based on the above plot",
"将图表类型参数赋值为插件参数": "Set the chart type parameter to the plugin parameter",
"根据图片类型返回image/jpeg": "Return image/jpeg based on image type",
"如果lang_reference是英文": "If lang_reference is English",
"示意图": "Schematic diagram",
"完整参数列表": "Complete parameter list",
"仿佛灿烂的群星的背景被剪出一个方口": "As if the brilliant background of stars has been cut out into a square",
"如果没有找到合适的切分点": "If no suitable splitting point is found",
"获取数据": "Get data",
"内嵌的javascript代码": "Embedded JavaScript code",
"绘制多种mermaid图表": "Draw various mermaid charts",
"无效": "Invalid",
"查找pdf/md/word并获取文本内容并返回状态以及文本": "Search for pdf/md/word, retrieve text content, and return status and text",
"总结绘制脑图": "Summarize mind mapping",
"禁止杜撰不符合我选择的剧情": "Prohibit making up plots that do not match my choice",
"正在生成向量库": "Generating vector library",
"是LLM的内部调优参数": "Is an internal tuning parameter of LLM",
"请你选择一个合适的图表类型": "Please choose an appropriate chart type",
"请在“输入区”输入图像生成提示": "Please enter image generation prompts in the 'input area'",
"经测试设置为小于500时": "After testing, set it to less than 500",
"当然": "Certainly",
"必要": "Necessary",
"从左到右": "From left to right",
"接下来调用本地Latex翻译插件即可": "Next, call the local Latex translation plugin",
"如果相同则返回": "If the same, return",
"根据语言": "According to the language",
"使用mermaid语法": "Use mermaid syntax",
"这是游戏的第一步": "This is the first step of the game",
"构建后续剧情引导": "Building subsequent plot guidance",
"以满足 token 限制": "To meet the token limit",
"也就是说": "That is to say",
"mermaid语法举例": "Mermaid syntax example",
"发送": "Send",
"那么就只显示英文提示词": "Then only display English prompts",
"正在检查": "Checking",
"返回处理后的字符串": "Return the processed string",
"2 序列图": "Sequence diagram 2",
"yi-34b-chat-0205只有4k上下文": "yi-34b-chat-0205 has only 4k context",
"请检查配置": "Please check the configuration",
"请你给出围绕“{subject}”的象限图": "Please provide a quadrant diagram around '{subject}'",
"故事该结束了": "The story should end",
"修复缩进": "Fix indentation",
"请描述给出的图片": "Please describe the given image",
"启用插件热加载": "Enable plugin hot reload",
"通义-在线模型 -=-=-=-=-=-=-": "Tongyi - Online Model",
"比较页数是否相同": "Compare if the number of pages is the same",
"正式开始服务": "Officially start the service",
"使用mermaid flowchart对以上文本进行总结": "Summarize the above text using a mermaid flowchart",
"不是vision 才处理history": "Not only vision but also handle history",
"来定义了一个正则表达式模式": "Defined a regular expression pattern",
"IP地址等": "IP addresses, etc.",
"那么双引号才是句子的终点": "Then the double quotes mark the end of the sentence",
"输入1": "Input 1",
"/「1792x1024」/「1024x1792」 || 质量支持 「-standard」": "/'1792x1024'/ '1024x1792' || Quality support '-standard'",
"为了避免索引错误将其更改为大写": "To avoid indexing errors, change it to uppercase",
"搜索网页": "Search the web",
"用于控制生成文本的随机性和创造性": "Used to control the randomness and creativity of generated text",
"不能等于 0": "Cannot equal 0",
"在距地球五万光年的远方": "At a distance of fifty thousand light-years from Earth",
". 表示任意单一字符": ". represents any single character",
"选择预测值最大的k个token进行采样": "Select the k tokens with the largest predicted values for sampling",
"输出2": "Output 2",
"函数示意图": "Function Diagram",
"You are associated with a deactivated account. Cohere以账户失效为由": "You are associated with a deactivated account. Cohere due to account deactivation",
"3. 后续剧情发展3": "3. Subsequent Plot Development",
"并以“剧情收尾”四个字提示程序": "And use the four characters 'Plot Conclusion' as a prompt for the program",
"中文省略号": "Chinese Ellipsis",
"则不生效": "Will not take effect",
"目前是两位小数": "Currently is two decimal places",
"Incorrect API key. Cohere以提供了不正确的API_KEY为由": "Incorrect API key. Cohere reports an incorrect API_KEY."
}

查看文件

@@ -44,7 +44,7 @@
"批量总结PDF文档": "BatchSummarizePDFDocuments",
"批量总结PDF文档pdfminer": "BatchSummarizePDFDocumentsUsingPDFMiner",
"批量翻译PDF文档": "BatchTranslatePDFDocuments",
"批量翻译PDF文档_多线程": "BatchTranslatePDFDocumentsUsingMultiThreading",
"PDF批量翻译": "BatchTranslatePDFDocumentsUsingMultiThreading",
"谷歌检索小助手": "GoogleSearchAssistant",
"理解PDF文档内容标准文件输入": "StandardFileInputForUnderstandingPDFDocumentContent",
"理解PDF文档内容": "UnderstandingPDFDocumentContent",

查看文件

@@ -6,7 +6,7 @@
"Latex英文纠错加PDF对比": "CorrectEnglishInLatexWithPDFComparison",
"下载arxiv论文并翻译摘要": "DownloadArxivPaperAndTranslateAbstract",
"Markdown翻译指定语言": "TranslateMarkdownToSpecifiedLanguage",
"批量翻译PDF文档_多线程": "BatchTranslatePDFDocuments_MultiThreaded",
"PDF批量翻译": "BatchTranslatePDFDocuments_MultiThreaded",
"下载arxiv论文翻译摘要": "DownloadArxivPaperTranslateAbstract",
"解析一个Python项目": "ParsePythonProject",
"解析一个Golang项目": "ParseGolangProject",

查看文件

@@ -43,7 +43,7 @@
"批量总结PDF文档": "BatchSummarizePDFDocuments",
"批量总结PDF文档pdfminer": "BatchSummarizePDFDocumentsPdfminer",
"批量翻译PDF文档": "BatchTranslatePDFDocuments",
"批量翻译PDF文档_多线程": "BatchTranslatePdfDocumentsMultithreaded",
"PDF批量翻译": "BatchTranslatePdfDocumentsMultithreaded",
"谷歌检索小助手": "GoogleSearchAssistant",
"理解PDF文档内容标准文件输入": "StandardFileInputForUnderstandingPdfDocumentContent",
"理解PDF文档内容": "UnderstandingPdfDocumentContent",

58
docs/use_tts.md 普通文件
查看文件

@@ -0,0 +1,58 @@
# 使用TTS文字转语音
## 1. 使用EDGE-TTS简单
将本项目配置项修改如下即可
```
TTS_TYPE = "EDGE_TTS"
EDGE_TTS_VOICE = "zh-CN-XiaoxiaoNeural"
```
## 2. 使用SoVITS需要有显卡
使用以下docker-compose.yml文件,先启动SoVITS服务API
1. 创建以下文件夹结构
```shell
.
├── docker-compose.yml
└── reference
├── clone_target_txt.txt
└── clone_target_wave.mp3
```
2. 其中`docker-compose.yml`为
```yaml
version: '3.8'
services:
gpt-sovits:
image: fuqingxu/sovits_gptac_trim:latest
container_name: sovits_gptac_container
working_dir: /workspace/gpt_sovits_demo
environment:
- is_half=False
- is_share=False
volumes:
- ./reference:/reference
ports:
- "19880:9880" # 19880 为 sovits api 的暴露端口,记住它
shm_size: 16G
deploy:
resources:
reservations:
devices:
- driver: nvidia
count: "all"
capabilities: [gpu]
command: bash -c "python3 api.py"
```
3. 其中`clone_target_wave.mp3`为需要克隆的角色音频,`clone_target_txt.txt`为该音频对应的文字文本( https://wiki.biligame.com/ys/%E8%A7%92%E8%89%B2%E8%AF%AD%E9%9F%B3
4. 运行`docker-compose up`
5. 将本项目配置项修改如下即可
(19880 为 sovits api 的暴露端口,与docker-compose.yml中的端口对应)
```
TTS_TYPE = "LOCAL_SOVITS_API"
GPT_SOVITS_URL = "http://127.0.0.1:19880"
```
6. 启动本项目

46
docs/use_vllm.md 普通文件
查看文件

@@ -0,0 +1,46 @@
# 使用VLLM
## 1. 首先启动 VLLM,自行选择模型
```
python -m vllm.entrypoints.openai.api_server --model /home/hmp/llm/cache/Qwen1___5-32B-Chat --tensor-parallel-size 2 --dtype=half
```
这里使用了存储在 `/home/hmp/llm/cache/Qwen1___5-32B-Chat` 的本地模型,可以根据自己的需求更改。
## 2. 测试 VLLM
```
curl http://localhost:8000/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "/home/hmp/llm/cache/Qwen1___5-32B-Chat",
"messages": [
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "怎么实现一个去中心化的控制器?"}
]
}'
```
## 3. 配置本项目
```
API_KEY = "sk-123456789xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx123456789"
LLM_MODEL = "vllm-/home/hmp/llm/cache/Qwen1___5-32B-Chat(max_token=4096)"
API_URL_REDIRECT = {"https://api.openai.com/v1/chat/completions": "http://localhost:8000/v1/chat/completions"}
```
```
"vllm-/home/hmp/llm/cache/Qwen1___5-32B-Chat(max_token=4096)"
其中
"vllm-" 是前缀(必要)
"/home/hmp/llm/cache/Qwen1___5-32B-Chat" 是模型名(必要)
"(max_token=6666)" 是配置(非必要)
```
## 4. 启动!
```
python main.py
```

34
main.py
查看文件

@@ -1,4 +1,4 @@
import os; os.environ['no_proxy'] = '*' # 避免代理网络产生意外污染
import os, json; os.environ['no_proxy'] = '*' # 避免代理网络产生意外污染
help_menu_description = \
"""Github源代码开源和更新[地址🚀](https://github.com/binary-husky/gpt_academic),
@@ -14,7 +14,7 @@ help_menu_description = \
</br></br>如何临时更换API_KEY: 在输入区输入临时API_KEY后提交网页刷新后失效"""
def enable_log(PATH_LOGGING):
import logging, uuid
import logging
admin_log_path = os.path.join(PATH_LOGGING, "admin")
os.makedirs(admin_log_path, exist_ok=True)
log_dir = os.path.join(admin_log_path, "chat_secrets.log")
@@ -29,13 +29,14 @@ def main():
if gr.__version__ not in ['3.32.9']:
raise ModuleNotFoundError("使用项目内置Gradio获取最优体验! 请运行 `pip install -r requirements.txt` 指令安装内置Gradio及其他依赖, 详情信息见requirements.txt.")
from request_llms.bridge_all import predict
from toolbox import format_io, find_free_port, on_file_uploaded, on_report_generated, get_conf, ArgsGeneralWrapper, load_chat_cookies, DummyWith
from toolbox import format_io, find_free_port, on_file_uploaded, on_report_generated, get_conf, ArgsGeneralWrapper, DummyWith
# 建议您复制一个config_private.py放自己的秘密, 如API和代理网址
proxies, WEB_PORT, LLM_MODEL, CONCURRENT_COUNT, AUTHENTICATION = get_conf('proxies', 'WEB_PORT', 'LLM_MODEL', 'CONCURRENT_COUNT', 'AUTHENTICATION')
CHATBOT_HEIGHT, LAYOUT, AVAIL_LLM_MODELS, AUTO_CLEAR_TXT = get_conf('CHATBOT_HEIGHT', 'LAYOUT', 'AVAIL_LLM_MODELS', 'AUTO_CLEAR_TXT')
ENABLE_AUDIO, AUTO_CLEAR_TXT, PATH_LOGGING, AVAIL_THEMES, THEME, ADD_WAIFU = get_conf('ENABLE_AUDIO', 'AUTO_CLEAR_TXT', 'PATH_LOGGING', 'AVAIL_THEMES', 'THEME', 'ADD_WAIFU')
NUM_CUSTOM_BASIC_BTN, SSL_KEYFILE, SSL_CERTFILE = get_conf('NUM_CUSTOM_BASIC_BTN', 'SSL_KEYFILE', 'SSL_CERTFILE')
DARK_MODE, INIT_SYS_PROMPT, ADD_WAIFU = get_conf('DARK_MODE', 'INIT_SYS_PROMPT', 'ADD_WAIFU')
DARK_MODE, INIT_SYS_PROMPT, ADD_WAIFU, TTS_TYPE = get_conf('DARK_MODE', 'INIT_SYS_PROMPT', 'ADD_WAIFU', 'TTS_TYPE')
if LLM_MODEL not in AVAIL_LLM_MODELS: AVAIL_LLM_MODELS += [LLM_MODEL]
# 如果WEB_PORT是-1, 则随机选取WEB端口
PORT = find_free_port() if WEB_PORT <= 0 else WEB_PORT
@@ -79,15 +80,18 @@ def main():
cancel_handles = []
customize_btns = {}
predefined_btns = {}
from shared_utils.cookie_manager import make_cookie_cache, make_history_cache
with gr.Blocks(title="GPT 学术优化", theme=set_theme, analytics_enabled=False, css=advanced_css) as app_block:
gr.HTML(title_html)
secret_css, web_cookie_cache = gr.Textbox(visible=False), gr.Textbox(visible=False)
cookies = gr.State(load_chat_cookies())
secret_css = gr.Textbox(visible=False, elem_id="secret_css")
cookies, web_cookie_cache = make_cookie_cache() # 定义 后端statecookies、前端web_cookie_cache两兄弟
with gr_L1():
with gr_L2(scale=2, elem_id="gpt-chat"):
chatbot = gr.Chatbot(label=f"当前模型:{LLM_MODEL}", elem_id="gpt-chatbot")
if LAYOUT == "TOP-DOWN": chatbot.style(height=CHATBOT_HEIGHT)
history = gr.State([])
history, history_cache, history_cache_update = make_history_cache() # 定义 后端statehistory、前端history_cache、后端setterhistory_cache_update三兄弟
with gr_L2(scale=1, elem_id="gpt-panel"):
with gr.Accordion("输入区", open=True, elem_id="input-panel") as area_input_primary:
with gr.Row():
@@ -155,7 +159,7 @@ def main():
file_upload_2 = gr.Files(label="任何文件, 推荐上传压缩文件(zip, tar)", file_count="multiple", elem_id="elem_upload_float")
with gr.Tab("更换模型", elem_id="interact-panel"):
md_dropdown = gr.Dropdown(AVAIL_LLM_MODELS, value=LLM_MODEL, label="更换LLM模型/请求源").style(container=False)
md_dropdown = gr.Dropdown(AVAIL_LLM_MODELS, value=LLM_MODEL, elem_id="elem_model_sel", label="更换LLM模型/请求源").style(container=False)
top_p = gr.Slider(minimum=-0, maximum=1.0, value=1.0, step=0.01,interactive=True, label="Top-p (nucleus sampling)",)
temperature = gr.Slider(minimum=-0, maximum=2.0, value=1.0, step=0.01, interactive=True, label="Temperature", elem_id="elem_temperature")
max_length_sl = gr.Slider(minimum=256, maximum=1024*32, value=4096, step=128, interactive=True, label="Local LLM MaxLength",)
@@ -164,6 +168,8 @@ def main():
_js="""(temperature)=>gpt_academic_gradio_saveload("save", "elem_prompt", "js_temperature_cookie", temperature)""")
system_prompt.change(None, inputs=[system_prompt], outputs=None,
_js="""(system_prompt)=>gpt_academic_gradio_saveload("save", "elem_prompt", "js_system_prompt_cookie", system_prompt)""")
md_dropdown.change(None, inputs=[md_dropdown], outputs=None,
_js="""(md_dropdown)=>gpt_academic_gradio_saveload("save", "elem_model_sel", "js_md_dropdown_cookie", md_dropdown)""")
with gr.Tab("界面外观", elem_id="interact-panel"):
theme_dropdown = gr.Dropdown(AVAIL_THEMES, value=THEME, label="更换UI主题").style(container=False)
@@ -247,8 +253,10 @@ def main():
cancel_handles.append(submitBtn2.click(**predict_args))
resetBtn.click(None, None, [chatbot, history, status], _js=js_code_reset) # 先在前端快速清除chatbot&status
resetBtn2.click(None, None, [chatbot, history, status], _js=js_code_reset) # 先在前端快速清除chatbot&status
resetBtn.click(lambda: ([], [], "已重置"), None, [chatbot, history, status]) # 再在后端清除history
resetBtn2.click(lambda: ([], [], "已重置"), None, [chatbot, history, status]) # 再在后端清除history
reset_server_side_args = (lambda history: ([], [], "已重置", json.dumps(history)),
[history], [chatbot, history, status, history_cache])
resetBtn.click(*reset_server_side_args) # 再在后端清除history,把history转存history_cache备用
resetBtn2.click(*reset_server_side_args) # 再在后端清除history,把history转存history_cache备用
clearBtn.click(None, None, [txt, txt2], _js=js_code_clear)
clearBtn2.click(None, None, [txt, txt2], _js=js_code_clear)
if AUTO_CLEAR_TXT:
@@ -271,7 +279,7 @@ def main():
for k in plugins:
if not plugins[k].get("AsButton", True): continue
click_handle = plugins[k]["Button"].click(ArgsGeneralWrapper(plugins[k]["Function"]), [*input_combo], output_combo)
click_handle.then(on_report_generated, [cookies, file_upload, chatbot], [cookies, file_upload, chatbot])
click_handle.then(on_report_generated, [cookies, file_upload, chatbot], [cookies, file_upload, chatbot]).then(None, [plugins[k]["Button"]], None, _js=r"(fn)=>on_plugin_exe_complete(fn)")
cancel_handles.append(click_handle)
# 函数插件-下拉菜单与随变按钮的互动
def on_dropdown_changed(k):
@@ -309,7 +317,7 @@ def main():
if k in [r"打开插件列表", r"请先从插件列表中选择"]: return
yield from ArgsGeneralWrapper(plugins[k]["Function"])(request, *args, **kwargs)
click_handle = switchy_bt.click(route,[switchy_bt, *input_combo], output_combo)
click_handle.then(on_report_generated, [cookies, file_upload, chatbot], [cookies, file_upload, chatbot])
click_handle.then(on_report_generated, [cookies, file_upload, chatbot], [cookies, file_upload, chatbot]).then(None, [switchy_bt], None, _js=r"(fn)=>on_plugin_exe_complete(fn)")
cancel_handles.append(click_handle)
# 终止按钮的回调函数注册
stopBtn.click(fn=None, inputs=None, outputs=None, cancels=cancel_handles)
@@ -342,7 +350,7 @@ def main():
app_block.load(load_web_cookie_cache, inputs = [web_cookie_cache, cookies],
outputs = [web_cookie_cache, cookies, *customize_btns.values(), *predefined_btns.values()], _js=js_code_for_persistent_cookie_init)
app_block.load(None, inputs=[], outputs=None, _js=f"""()=>GptAcademicJavaScriptInit("{DARK_MODE}","{INIT_SYS_PROMPT}","{ADD_WAIFU}","{LAYOUT}")""") # 配置暗色主题或亮色主题
app_block.load(None, inputs=[], outputs=None, _js=f"""()=>GptAcademicJavaScriptInit("{DARK_MODE}","{INIT_SYS_PROMPT}","{ADD_WAIFU}","{LAYOUT}","{TTS_TYPE}")""") # 配置暗色主题或亮色主题
# gradio的inbrowser触发不太稳定,回滚代码到原始的浏览器打开函数
def run_delayed_tasks():

查看文件

@@ -67,7 +67,8 @@ newbing_endpoint = "wss://sydney.bing.com/sydney/ChatHub"
gemini_endpoint = "https://generativelanguage.googleapis.com/v1beta/models"
claude_endpoint = "https://api.anthropic.com/v1/messages"
yimodel_endpoint = "https://api.lingyiwanwu.com/v1/chat/completions"
cohere_endpoint = 'https://api.cohere.ai/v1/chat'
cohere_endpoint = "https://api.cohere.ai/v1/chat"
ollama_endpoint = "http://localhost:11434/api/chat"
if not AZURE_ENDPOINT.endswith('/'): AZURE_ENDPOINT += '/'
azure_endpoint = AZURE_ENDPOINT + f'openai/deployments/{AZURE_ENGINE}/chat/completions?api-version=2023-05-15'
@@ -87,6 +88,7 @@ if gemini_endpoint in API_URL_REDIRECT: gemini_endpoint = API_URL_REDIRECT[gemin
if claude_endpoint in API_URL_REDIRECT: claude_endpoint = API_URL_REDIRECT[claude_endpoint]
if yimodel_endpoint in API_URL_REDIRECT: yimodel_endpoint = API_URL_REDIRECT[yimodel_endpoint]
if cohere_endpoint in API_URL_REDIRECT: cohere_endpoint = API_URL_REDIRECT[cohere_endpoint]
if ollama_endpoint in API_URL_REDIRECT: ollama_endpoint = API_URL_REDIRECT[ollama_endpoint]
# 获取tokenizer
tokenizer_gpt35 = LazyloadTiktoken("gpt-3.5-turbo")
@@ -200,6 +202,25 @@ model_info = {
"token_cnt": get_token_num_gpt4,
},
"gpt-4-turbo": {
"fn_with_ui": chatgpt_ui,
"fn_without_ui": chatgpt_noui,
"endpoint": openai_endpoint,
"max_token": 128000,
"tokenizer": tokenizer_gpt4,
"token_cnt": get_token_num_gpt4,
},
"gpt-4-turbo-2024-04-09": {
"fn_with_ui": chatgpt_ui,
"fn_without_ui": chatgpt_noui,
"endpoint": openai_endpoint,
"max_token": 128000,
"tokenizer": tokenizer_gpt4,
"token_cnt": get_token_num_gpt4,
},
"gpt-3.5-random": {
"fn_with_ui": chatgpt_ui,
"fn_without_ui": chatgpt_noui,
@@ -247,6 +268,14 @@ model_info = {
"tokenizer": tokenizer_gpt35,
"token_cnt": get_token_num_gpt35,
},
"glm-4v": {
"fn_with_ui": zhipu_ui,
"fn_without_ui": zhipu_noui,
"endpoint": None,
"max_token": 1000,
"tokenizer": tokenizer_gpt35,
"token_cnt": get_token_num_gpt35,
},
"glm-3-turbo": {
"fn_with_ui": zhipu_ui,
"fn_without_ui": zhipu_noui,
@@ -778,13 +807,62 @@ for model in [m for m in AVAIL_LLM_MODELS if m.startswith("one-api-")]:
model: {
"fn_with_ui": chatgpt_ui,
"fn_without_ui": chatgpt_noui,
"can_multi_thread": True,
"endpoint": openai_endpoint,
"max_token": max_token_tmp,
"tokenizer": tokenizer_gpt35,
"token_cnt": get_token_num_gpt35,
},
})
# -=-=-=-=-=-=- vllm 对齐支持 -=-=-=-=-=-=-
for model in [m for m in AVAIL_LLM_MODELS if m.startswith("vllm-")]:
# 为了更灵活地接入vllm多模型管理界面,设计了此接口,例子AVAIL_LLM_MODELS = ["vllm-/home/hmp/llm/cache/Qwen1___5-32B-Chat(max_token=6666)"]
# 其中
# "vllm-" 是前缀(必要)
# "mixtral-8x7b" 是模型名(必要)
# "(max_token=6666)" 是配置(非必要)
try:
_, max_token_tmp = read_one_api_model_name(model)
except:
print(f"vllm模型 {model} 的 max_token 配置不是整数,请检查配置文件。")
continue
model_info.update({
model: {
"fn_with_ui": chatgpt_ui,
"fn_without_ui": chatgpt_noui,
"can_multi_thread": True,
"endpoint": openai_endpoint,
"max_token": max_token_tmp,
"tokenizer": tokenizer_gpt35,
"token_cnt": get_token_num_gpt35,
},
})
# -=-=-=-=-=-=- ollama 对齐支持 -=-=-=-=-=-=-
for model in [m for m in AVAIL_LLM_MODELS if m.startswith("ollama-")]:
from .bridge_ollama import predict_no_ui_long_connection as ollama_noui
from .bridge_ollama import predict as ollama_ui
break
for model in [m for m in AVAIL_LLM_MODELS if m.startswith("ollama-")]:
# 为了更灵活地接入ollama多模型管理界面,设计了此接口,例子AVAIL_LLM_MODELS = ["ollama-phi3(max_token=6666)"]
# 其中
# "ollama-" 是前缀(必要)
# "phi3" 是模型名(必要)
# "(max_token=6666)" 是配置(非必要)
try:
_, max_token_tmp = read_one_api_model_name(model)
except:
print(f"ollama模型 {model} 的 max_token 配置不是整数,请检查配置文件。")
continue
model_info.update({
model: {
"fn_with_ui": ollama_ui,
"fn_without_ui": ollama_noui,
"endpoint": ollama_endpoint,
"max_token": max_token_tmp,
"tokenizer": tokenizer_gpt35,
"token_cnt": get_token_num_gpt35,
},
})
# -=-=-=-=-=-=- azure模型对齐支持 -=-=-=-=-=-=-
AZURE_CFG_ARRAY = get_conf("AZURE_CFG_ARRAY") # <-- 用于定义和切换多个azure模型 -->

查看文件

@@ -6,7 +6,6 @@ from toolbox import get_conf, ProxyNetworkActivate
from .local_llm_class import LocalLLMHandle, get_local_llm_predict_fns
# ------------------------------------------------------------------------------------------------------------------------
# 🔌💻 Local Model
# ------------------------------------------------------------------------------------------------------------------------
@@ -23,20 +22,45 @@ class GetGLM3Handle(LocalLLMHandle):
import os, glob
import os
import platform
LOCAL_MODEL_QUANT, device = get_conf('LOCAL_MODEL_QUANT', 'LOCAL_MODEL_DEVICE')
if LOCAL_MODEL_QUANT == "INT4": # INT4
_model_name_ = "THUDM/chatglm3-6b-int4"
elif LOCAL_MODEL_QUANT == "INT8": # INT8
_model_name_ = "THUDM/chatglm3-6b-int8"
else:
_model_name_ = "THUDM/chatglm3-6b" # FP16
with ProxyNetworkActivate('Download_LLM'):
chatglm_tokenizer = AutoTokenizer.from_pretrained(_model_name_, trust_remote_code=True)
if device=='cpu':
chatglm_model = AutoModel.from_pretrained(_model_name_, trust_remote_code=True, device='cpu').float()
LOCAL_MODEL_QUANT, device = get_conf("LOCAL_MODEL_QUANT", "LOCAL_MODEL_DEVICE")
_model_name_ = "THUDM/chatglm3-6b"
# if LOCAL_MODEL_QUANT == "INT4": # INT4
# _model_name_ = "THUDM/chatglm3-6b-int4"
# elif LOCAL_MODEL_QUANT == "INT8": # INT8
# _model_name_ = "THUDM/chatglm3-6b-int8"
# else:
# _model_name_ = "THUDM/chatglm3-6b" # FP16
with ProxyNetworkActivate("Download_LLM"):
chatglm_tokenizer = AutoTokenizer.from_pretrained(
_model_name_, trust_remote_code=True
)
if device == "cpu":
chatglm_model = AutoModel.from_pretrained(
_model_name_,
trust_remote_code=True,
device="cpu",
).float()
elif LOCAL_MODEL_QUANT == "INT4": # INT4
chatglm_model = AutoModel.from_pretrained(
pretrained_model_name_or_path=_model_name_,
trust_remote_code=True,
device="cuda",
load_in_4bit=True,
)
elif LOCAL_MODEL_QUANT == "INT8": # INT8
chatglm_model = AutoModel.from_pretrained(
pretrained_model_name_or_path=_model_name_,
trust_remote_code=True,
device="cuda",
load_in_8bit=True,
)
else:
chatglm_model = AutoModel.from_pretrained(_model_name_, trust_remote_code=True, device='cuda')
chatglm_model = AutoModel.from_pretrained(
pretrained_model_name_or_path=_model_name_,
trust_remote_code=True,
device="cuda",
)
chatglm_model = chatglm_model.eval()
self._model = chatglm_model
@@ -46,32 +70,36 @@ class GetGLM3Handle(LocalLLMHandle):
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']
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)
for response, history in self._model.stream_chat(self._tokenizer,
query,
history,
max_length=max_length,
top_p=top_p,
temperature=temperature,
):
for response, history in self._model.stream_chat(
self._tokenizer,
query,
history,
max_length=max_length,
top_p=top_p,
temperature=temperature,
):
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(GetGLM3Handle, model_name, history_format='chatglm3')
predict_no_ui_long_connection, predict = get_local_llm_predict_fns(
GetGLM3Handle, model_name, history_format="chatglm3"
)

查看文件

@@ -323,7 +323,10 @@ def generate_payload(inputs, llm_kwargs, history, system_prompt, stream):
if not is_any_api_key(llm_kwargs['api_key']):
raise AssertionError("你提供了错误的API_KEY。\n\n1. 临时解决方案直接在输入区键入api_key,然后回车提交。\n\n2. 长效解决方案在config.py中配置。")
api_key = select_api_key(llm_kwargs['api_key'], llm_kwargs['llm_model'])
if llm_kwargs['llm_model'].startswith('vllm-'):
api_key = 'no-api-key'
else:
api_key = select_api_key(llm_kwargs['api_key'], llm_kwargs['llm_model'])
headers = {
"Content-Type": "application/json",
@@ -365,7 +368,9 @@ def generate_payload(inputs, llm_kwargs, history, system_prompt, stream):
if llm_kwargs['llm_model'].startswith('one-api-'):
model = llm_kwargs['llm_model'][len('one-api-'):]
model, _ = read_one_api_model_name(model)
if llm_kwargs['llm_model'].startswith('vllm-'):
model = llm_kwargs['llm_model'][len('vllm-'):]
model, _ = read_one_api_model_name(model)
if model == "gpt-3.5-random": # 随机选择, 绕过openai访问频率限制
model = random.choice([
"gpt-3.5-turbo",

查看文件

@@ -8,7 +8,7 @@ import os
import time
from request_llms.com_google import GoogleChatInit
from toolbox import ChatBotWithCookies
from toolbox import get_conf, update_ui, update_ui_lastest_msg, have_any_recent_upload_image_files, trimmed_format_exc
from toolbox import get_conf, update_ui, update_ui_lastest_msg, have_any_recent_upload_image_files, trimmed_format_exc, log_chat
proxies, TIMEOUT_SECONDS, MAX_RETRY = get_conf('proxies', 'TIMEOUT_SECONDS', 'MAX_RETRY')
timeout_bot_msg = '[Local Message] Request timeout. Network error. Please check proxy settings in config.py.' + \
@@ -99,6 +99,7 @@ def predict(inputs:str, llm_kwargs:dict, plugin_kwargs:dict, chatbot:ChatBotWith
gpt_replying_buffer += paraphrase['text'] # 使用 json 解析库进行处理
chatbot[-1] = (inputs, gpt_replying_buffer)
history[-1] = gpt_replying_buffer
log_chat(llm_model=llm_kwargs["llm_model"], input_str=inputs, output_str=gpt_replying_buffer)
yield from update_ui(chatbot=chatbot, history=history)
if error_match:
history = history[-2] # 错误的不纳入对话

查看文件

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

查看文件

@@ -75,6 +75,10 @@ def predict(inputs:str, llm_kwargs:dict, plugin_kwargs:dict, chatbot:ChatBotWith
llm_kwargs["llm_model"] = zhipuai_default_model
if llm_kwargs["llm_model"] in ["glm-4v"]:
if (len(inputs) + sum(len(temp) for temp in history) + 1047) > 2000:
chatbot.append((inputs, "上下文长度超过glm-4v上限2000tokens,注意图片大约占用1,047个tokens"))
yield from update_ui(chatbot=chatbot, history=history)
return
have_recent_file, image_paths = have_any_recent_upload_image_files(chatbot)
if not have_recent_file:
chatbot.append((inputs, "没有检测到任何近期上传的图像文件,请上传jpg格式的图片,此外,请注意拓展名需要小写"))

查看文件

@@ -36,8 +36,14 @@ class ZhipuChatInit:
what_i_have_asked = {"role": "user", "content": []}
what_i_have_asked['content'].append({"type": 'text', "text": user_input})
if encode_img:
if len(encode_img) > 1:
logging.warning("glm-4v只支持一张图片,将只取第一张图片进行处理")
print("glm-4v只支持一张图片,将只取第一张图片进行处理")
img_d = {"type": "image_url",
"image_url": {'url': encode_img}}
"image_url": {
"url": encode_img[0]['data']
}
}
what_i_have_asked['content'].append(img_d)
return what_i_have_asked

查看文件

@@ -1,7 +1,8 @@
https://public.agent-matrix.com/publish/gradio-3.32.9-py3-none-any.whl
fastapi==0.110
gradio-client==0.8
pypdf2==2.12.1
zhipuai>=2
zhipuai==2.0.1
tiktoken>=0.3.3
requests[socks]
pydantic==2.5.2
@@ -22,8 +23,10 @@ pyautogen
colorama
Markdown
pygments
edge-tts
pymupdf
openai
rjsmin
arxiv
numpy
rich
rich

查看文件

@@ -207,6 +207,53 @@ def fix_code_segment_indent(txt):
return txt
def markdown_convertion_for_file(txt):
"""
将Markdown格式的文本转换为HTML格式。如果包含数学公式,则先将公式转换为HTML格式。
"""
from themes.theme import advanced_css
pre = f"""
<!DOCTYPE html><head><meta charset="utf-8"><title>对话历史</title><style>{advanced_css}</style></head>
<body>
<div class="test_temp1" style="width:10%; height: 500px; float:left;"></div>
<div class="test_temp2" style="width:80%;padding: 40px;float:left;padding-left: 20px;padding-right: 20px;box-shadow: rgba(0, 0, 0, 0.2) 0px 0px 8px 8px;border-radius: 10px;">
<div class="markdown-body">
"""
suf = """
</div>
</div>
<div class="test_temp3" style="width:10%; height: 500px; float:left;"></div>
</body>
"""
if txt.startswith(pre) and txt.endswith(suf):
# print('警告,输入了已经经过转化的字符串,二次转化可能出问题')
return txt # 已经被转化过,不需要再次转化
find_equation_pattern = r'<script type="math/tex(?:.*?)>(.*?)</script>'
txt = fix_markdown_indent(txt)
# convert everything to html format
split = markdown.markdown(text="---")
convert_stage_1 = markdown.markdown(
text=txt,
extensions=[
"sane_lists",
"tables",
"mdx_math",
"pymdownx.superfences",
"pymdownx.highlight",
],
extension_configs={**markdown_extension_configs, **code_highlight_configs},
)
convert_stage_1 = markdown_bug_hunt(convert_stage_1)
# 2. convert to rendered equation
convert_stage_2_2, n = re.subn(
find_equation_pattern, replace_math_render, convert_stage_1, flags=re.DOTALL
)
# cat them together
return pre + convert_stage_2_2 + suf
@lru_cache(maxsize=128) # 使用 lru缓存 加快转换速度
def markdown_convertion(txt):
"""

查看文件

@@ -1,4 +1,6 @@
import json
from typing import Callable
def load_web_cookie_cache__fn_builder(customize_btns, cookies, predefined_btns)->Callable:
def load_web_cookie_cache(persistent_cookie_, cookies_):
import gradio as gr
@@ -22,7 +24,6 @@ def load_web_cookie_cache__fn_builder(customize_btns, cookies, predefined_btns)-
return ret
return load_web_cookie_cache
def assign_btn__fn_builder(customize_btns, predefined_btns, cookies, web_cookie_cache)->Callable:
def assign_btn(persistent_cookie_, cookies_, basic_btn_dropdown_, basic_fn_title, basic_fn_prefix, basic_fn_suffix, clean_up=False):
import gradio as gr
@@ -59,3 +60,29 @@ def assign_btn__fn_builder(customize_btns, predefined_btns, cookies, web_cookie_
return ret
return assign_btn
# cookies, web_cookie_cache = make_cookie_cache()
def make_cookie_cache():
# 定义 后端statecookies、前端web_cookie_cache两兄弟
import gradio as gr
from toolbox import load_chat_cookies
# 定义cookies的后端state
cookies = gr.State(load_chat_cookies())
# 定义cookies的一个孪生的前端存储区隐藏
web_cookie_cache = gr.Textbox(visible=False, elem_id="web_cookie_cache")
return cookies, web_cookie_cache
# history, history_cache, history_cache_update = make_history_cache()
def make_history_cache():
# 定义 后端statehistory、前端history_cache、后端setterhistory_cache_update三兄弟
import gradio as gr
# 定义history的后端state
history = gr.State([])
# 定义history的一个孪生的前端存储区隐藏
history_cache = gr.Textbox(visible=False, elem_id="history_cache")
# 定义history_cache->history的更新方法隐藏。在触发这个按钮时,会先执行js代码更新history_cache,然后再执行python代码更新history
def process_history_cache(history_cache):
return json.loads(history_cache)
# 另一种更简单的setter方法
history_cache_update = gr.Button("", elem_id="elem_update_history", visible=False).click(
process_history_cache, inputs=[history_cache], outputs=[history])
return history, history_cache, history_cache_update

查看文件

@@ -137,6 +137,47 @@ def start_app(app_block, CONCURRENT_COUNT, AUTHENTICATION, PORT, SSL_KEYFILE, SS
return "越权访问!"
return await endpoint(path_or_url, request)
TTS_TYPE = get_conf("TTS_TYPE")
if TTS_TYPE != "DISABLE":
# audio generation functionality
import httpx
from fastapi import FastAPI, Request, HTTPException
from starlette.responses import Response
async def forward_request(request: Request, method: str) -> Response:
async with httpx.AsyncClient() as client:
try:
# Forward the request to the target service
if TTS_TYPE == "EDGE_TTS":
import tempfile
import edge_tts
import wave
import uuid
from pydub import AudioSegment
json = await request.json()
voice = get_conf("EDGE_TTS_VOICE")
tts = edge_tts.Communicate(text=json['text'], voice=voice)
temp_folder = tempfile.gettempdir()
temp_file_name = str(uuid.uuid4().hex)
temp_file = os.path.join(temp_folder, f'{temp_file_name}.mp3')
await tts.save(temp_file)
mp3_audio = AudioSegment.from_file(temp_file, format="mp3")
mp3_audio.export(temp_file, format="wav")
with open(temp_file, 'rb') as wav_file: t = wav_file.read()
os.remove(temp_file)
return Response(content=t)
if TTS_TYPE == "LOCAL_SOVITS_API":
# Forward the request to the target service
TARGET_URL = get_conf("GPT_SOVITS_URL")
body = await request.body()
resp = await client.post(TARGET_URL, content=body, timeout=60)
# Return the response from the target service
return Response(content=resp.content, status_code=resp.status_code, headers=dict(resp.headers))
except httpx.RequestError as e:
raise HTTPException(status_code=400, detail=f"Request to the target service failed: {str(e)}")
@gradio_app.post("/vits")
async def forward_post_request(request: Request):
return await forward_request(request, "POST")
# --- --- app_lifespan --- ---
from contextlib import asynccontextmanager
@asynccontextmanager

查看文件

@@ -104,6 +104,14 @@ def extract_archive(file_path, dest_dir):
elif file_extension in [".tar", ".gz", ".bz2"]:
with tarfile.open(file_path, "r:*") as tarobj:
# 清理提取路径,移除任何不安全的元素
for member in tarobj.getmembers():
member_path = os.path.normpath(member.name)
full_path = os.path.join(dest_dir, member_path)
full_path = os.path.abspath(full_path)
if not full_path.startswith(os.path.abspath(dest_dir) + os.sep):
raise Exception(f"Attempted Path Traversal in {member.name}")
tarobj.extractall(path=dest_dir)
print("Successfully extracted tar archive to {}".format(dest_dir))

查看文件

@@ -14,7 +14,7 @@ def is_openai_api_key(key):
if len(CUSTOM_API_KEY_PATTERN) != 0:
API_MATCH_ORIGINAL = re.match(CUSTOM_API_KEY_PATTERN, key)
else:
API_MATCH_ORIGINAL = re.match(r"sk-[a-zA-Z0-9]{48}$|sess-[a-zA-Z0-9]{40}$", key)
API_MATCH_ORIGINAL = re.match(r"sk-[a-zA-Z0-9]{48}$|sk-proj-[a-zA-Z0-9]{48}$|sess-[a-zA-Z0-9]{40}$", key)
return bool(API_MATCH_ORIGINAL)

查看文件

@@ -26,6 +26,8 @@ def apply_gpt_academic_string_mask(string, mode="show_all"):
当字符串中有掩码tag时<gpt_academic_string_mask><show_...>,根据字符串要给谁看大模型,还是web渲染,对字符串进行处理,返回处理后的字符串
示意图https://mermaid.live/edit#pako:eNqlkUtLw0AUhf9KuOta0iaTplkIPlpduFJwoZEwJGNbzItpita2O6tF8QGKogXFtwu7cSHiq3-mk_oznFR8IYLgrGbuOd9hDrcCpmcR0GDW9ubNPKaBMDauuwI_A9M6YN-3y0bODwxsYos4BdMoBrTg5gwHF-d0mBH6-vqFQe58ed5m9XPW2uteX3Tubrj0ljLYcwxxR3h1zB43WeMs3G19yEM9uapDMe_NG9i2dagKw1Fee4c1D9nGEbtc-5n6HbNtJ8IyHOs8tbs7V2HrlDX2w2Y7XD_5haHEtQiNsOwfMVa_7TzsvrWIuJGo02qTrdwLk9gukQylHv3Afv1ML270s-HZUndrmW1tdA-WfvbM_jMFYuAQ6uCCxVdciTJ1CPLEITpo_GphypeouzXuw6XAmyi7JmgBLZEYlHwLB2S4gHMUO-9DH7tTnvf1CVoFFkBLSOk4QmlRTqpIlaWUHINyNFXjaQWpCYRURUKiWovBYo8X4ymEJFlECQUpqaQkJmuvWygPpg
"""
if not string:
return string
if "<gpt_academic_string_mask>" not in string: # No need to process
return string

查看文件

@@ -43,8 +43,10 @@ def validate_path():
validate_path() # validate path so you can run from base directory
from toolbox import markdown_convertion
html = markdown_convertion(md)
from shared_utils.advanced_markdown_format import markdown_convertion_for_file
with open("gpt_log/default_user/shared/2024-04-22-01-27-43.zip.extract/translated_markdown.md", "r", encoding="utf-8") as f:
md = f.read()
html = markdown_convertion_for_file(md)
# print(html)
with open("test.html", "w", encoding="utf-8") as f:
f.write(html)

查看文件

@@ -22,10 +22,12 @@ if __name__ == "__main__":
# plugin_test(plugin='crazy_functions.Latex输出PDF->Latex翻译中文并重新编译PDF', main_input="2307.07522")
plugin_test(
plugin="crazy_functions.Latex输出PDF->Latex翻译中文并重新编译PDF",
main_input="G:/SEAFILE_LOCAL/50503047/我的资料库/学位/paperlatex/aaai/Fu_8368_with_appendix",
)
plugin_test(plugin='crazy_functions.PDF批量翻译->批量翻译PDF文档', main_input='build/pdf/t1.pdf')
# plugin_test(
# plugin="crazy_functions.Latex输出PDF->Latex翻译中文并重新编译PDF",
# main_input="G:/SEAFILE_LOCAL/50503047/我的资料库/学位/paperlatex/aaai/Fu_8368_with_appendix",
# )
# plugin_test(plugin='crazy_functions.虚空终端->虚空终端', main_input='修改api-key为sk-jhoejriotherjep')
@@ -43,7 +45,7 @@ if __name__ == "__main__":
# plugin_test(plugin='crazy_functions.批量Markdown翻译->Markdown中译英', main_input="README.md")
# plugin_test(plugin='crazy_functions.批量翻译PDF文档_多线程->批量翻译PDF文档', main_input='crazy_functions/test_project/pdf_and_word/aaai.pdf')
# plugin_test(plugin='crazy_functions.PDF批量翻译->批量翻译PDF文档', main_input='crazy_functions/test_project/pdf_and_word/aaai.pdf')
# plugin_test(plugin='crazy_functions.谷歌检索小助手->谷歌检索小助手', main_input="https://scholar.google.com/scholar?hl=en&as_sdt=0%2C5&q=auto+reinforcement+learning&btnG=")

查看文件

@@ -38,6 +38,7 @@
left: calc(100% + 3px);
top: 0;
display: flex;
flex-direction: column;
justify-content: space-between;
}
/* .message-btn-row-leading, .message-btn-row-trailing {

查看文件

@@ -7,6 +7,9 @@ function push_data_to_gradio_component(DAT, ELEM_ID, TYPE) {
if (TYPE == "str") {
// convert dat to string: do nothing
}
else if (TYPE == "obj") {
// convert dat to string: do nothing
}
else if (TYPE == "no_conversion") {
// no nothing
}
@@ -254,11 +257,22 @@ function cancel_loading_status() {
// 第 2 部分: 复制按钮
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
function addCopyButton(botElement) {
var allow_auto_read_continously = true;
var allow_auto_read_tts_flag = false;
function addCopyButton(botElement, index, is_last_in_arr) {
// https://github.com/GaiZhenbiao/ChuanhuChatGPT/tree/main/web_assets/javascript
// Copy bot button
const copiedIcon = '<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 copyIcon = '<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"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg></span>';
// const audioIcon = '<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"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg></span>';
const audioIcon = '<span><svg t="1713628577799" fill="currentColor" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4587" width=".9em" height=".9em"><path d="M113.7664 540.4672c0-219.9552 178.2784-398.2336 398.2336-398.2336S910.2336 320.512 910.2336 540.4672v284.4672c0 31.4368-25.4976 56.9344-56.9344 56.9344h-56.9344c-31.4368 0-56.9344-25.4976-56.9344-56.9344V597.2992c0-31.4368 25.4976-56.9344 56.9344-56.9344h56.9344c0-188.5184-152.7808-341.2992-341.2992-341.2992S170.7008 351.9488 170.7008 540.4672h56.9344c31.4368 0 56.9344 25.4976 56.9344 56.9344v227.5328c0 31.4368-25.4976 56.9344-56.9344 56.9344h-56.9344c-31.4368 0-56.9344-25.4976-56.9344-56.9344V540.4672z" p-id="4588"></path></svg></span>';
// const cancelAudioIcon = '<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"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg></span>';
// 此功能没准备好
if (allow_auto_read_continously && is_last_in_arr && allow_auto_read_tts_flag) {
process_latest_text_output(botElement.innerText, index);
}
const messageBtnColumnElement = botElement.querySelector('.message-btn-row');
if (messageBtnColumnElement) {
@@ -273,6 +287,7 @@ function addCopyButton(botElement) {
copyButton.addEventListener('click', async () => {
const textToCopy = botElement.innerText;
try {
// push_text_to_audio(textToCopy).catch(console.error);
if ("clipboard" in navigator) {
await navigator.clipboard.writeText(textToCopy);
copyButton.innerHTML = copiedIcon;
@@ -299,9 +314,35 @@ function addCopyButton(botElement) {
console.error("Copy failed: ", error);
}
});
if (enable_tts){
var audioButton = document.createElement('button');
audioButton.classList.add('audio-toggle-btn');
audioButton.innerHTML = audioIcon;
audioButton.addEventListener('click', async () => {
if (audioPlayer.isPlaying) {
allow_auto_read_tts_flag = false;
toast_push('自动朗读已禁用。', 3000);
audioPlayer.stop();
setCookie("js_auto_read_cookie", "False", 365);
} else {
allow_auto_read_tts_flag = true;
toast_push('正在合成语音 & 自动朗读已开启 (再次点击此按钮可禁用自动朗读)。', 3000);
// toast_push('正在合成语音', 3000);
const readText = botElement.innerText;
push_text_to_audio(readText);
setCookie("js_auto_read_cookie", "True", 365);
}
});
}
var messageBtnColumn = document.createElement('div');
messageBtnColumn.classList.add('message-btn-row');
messageBtnColumn.appendChild(copyButton);
if (enable_tts){
messageBtnColumn.appendChild(audioButton);
}
botElement.appendChild(messageBtnColumn);
}
@@ -337,7 +378,15 @@ function chatbotContentChanged(attempt = 1, force = false) {
// https://github.com/GaiZhenbiao/ChuanhuChatGPT/tree/main/web_assets/javascript
for (var i = 0; i < attempt; i++) {
setTimeout(() => {
gradioApp().querySelectorAll('#gpt-chatbot .message-wrap .message.bot').forEach(addCopyButton);
const messages = gradioApp().querySelectorAll('#gpt-chatbot .message-wrap .message.bot');
messages.forEach((message, index, arr) => {
// Check if the current message is the last in the array
const is_last_in_arr = index === arr.length - 1;
// Now pass both the message element and the is_last_in_arr boolean to addCopyButton
addCopyButton(message, index, is_last_in_arr);
});
// gradioApp().querySelectorAll('#gpt-chatbot .message-wrap .message.bot').forEach(addCopyButton);
}, i === 0 ? 0 : 200);
}
// we have moved mermaid-related code to gradio-fix repository: binary-husky/gradio-fix@32150d0
@@ -621,16 +670,16 @@ function monitoring_input_box() {
if (elem_input_main) {
if (elem_input_main.querySelector("textarea")) {
register_func_paste(elem_input_main.querySelector("textarea"))
register_func_paste(elem_input_main.querySelector("textarea"));
}
}
if (elem_input_float) {
if (elem_input_float.querySelector("textarea")) {
register_func_paste(elem_input_float.querySelector("textarea"))
register_func_paste(elem_input_float.querySelector("textarea"));
}
}
if (elem_chatbot) {
register_func_drag(elem_chatbot)
register_func_drag(elem_chatbot);
}
}
@@ -737,7 +786,7 @@ function minor_ui_adjustment() {
}
setInterval(function () {
auto_hide_toolbar()
auto_hide_toolbar();
}, 200); // 每50毫秒执行一次
}
@@ -857,8 +906,8 @@ function gpt_academic_gradio_saveload(
}
}
async function GptAcademicJavaScriptInit(dark, prompt, live2d, layout) {
enable_tts = false;
async function GptAcademicJavaScriptInit(dark, prompt, live2d, layout, tts) {
// 第一部分,布局初始化
audio_fn_init();
minor_ui_adjustment();
@@ -873,7 +922,6 @@ async function GptAcademicJavaScriptInit(dark, prompt, live2d, layout) {
// 第二部分,读取Cookie,初始话界面
let searchString = "";
let bool_value = "";
// darkmode 深色模式
if (getCookie("js_darkmode_cookie")) {
dark = getCookie("js_darkmode_cookie")
@@ -889,11 +937,39 @@ async function GptAcademicJavaScriptInit(dark, prompt, live2d, layout) {
}
}
// 自动朗读
if (tts != "DISABLE"){
enable_tts = true;
if (getCookie("js_auto_read_cookie")) {
auto_read_tts = getCookie("js_auto_read_cookie")
auto_read_tts = auto_read_tts == "True";
if (auto_read_tts) {
allow_auto_read_tts_flag = true;
}
}
}
// SysPrompt 系统静默提示词
gpt_academic_gradio_saveload("load", "elem_prompt", "js_system_prompt_cookie", null, "str");
// Temperature 大模型温度参数
gpt_academic_gradio_saveload("load", "elem_temperature", "js_temperature_cookie", null, "float");
// md_dropdown 大模型类型选择
if (getCookie("js_md_dropdown_cookie")) {
const cached_model = getCookie("js_md_dropdown_cookie");
var model_sel = await get_gradio_component("elem_model_sel");
// deterine whether the cached model is in the choices
if (model_sel.props.choices.includes(cached_model)){
// change dropdown
gpt_academic_gradio_saveload("load", "elem_model_sel", "js_md_dropdown_cookie", null, "str");
// 连锁修改chatbot的label
push_data_to_gradio_component({
label: '当前模型:' + getCookie("js_md_dropdown_cookie"),
__type__: 'update'
}, "gpt-chatbot", "obj")
}
}
// clearButton 自动清除按钮
if (getCookie("js_clearbtn_show_cookie")) {
@@ -953,4 +1029,510 @@ async function GptAcademicJavaScriptInit(dark, prompt, live2d, layout) {
}
}
}
}
function reset_conversation(a, b) {
console.log("js_code_reset");
a = btoa(unescape(encodeURIComponent(JSON.stringify(a))));
setCookie("js_previous_chat_cookie", a, 1);
gen_restore_btn();
return [[], [], "已重置"];
}
// clear -> 将 history 缓存至 history_cache -> 点击复原 -> restore_previous_chat() -> 触发elem_update_history -> 读取 history_cache
function restore_previous_chat() {
console.log("restore_previous_chat");
let chat = getCookie("js_previous_chat_cookie");
chat = JSON.parse(decodeURIComponent(escape(atob(chat))));
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
}
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) {
console.log(fn_name);
if (fn_name === "保存当前的对话") {
// get chat profile path
let chatbot = await get_data_from_gradio_component('gpt-chatbot');
let may_have_chat_profile_info = chatbot[chatbot.length - 1][1];
function get_href(htmlString) {
const parser = new DOMParser();
const doc = parser.parseFromString(htmlString, 'text/html');
const anchor = doc.querySelector('a');
if (anchor) {
return anchor.getAttribute('href');
} else {
return null;
}
}
let href = get_href(may_have_chat_profile_info);
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
console.log(cleanedHref);
}
}
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// 第 8 部分: TTS语音生成函数
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
class AudioPlayer {
constructor() {
this.audioCtx = new (window.AudioContext || window.webkitAudioContext)();
this.queue = [];
this.isPlaying = false;
this.currentSource = null; // 添加属性来保存当前播放的源
}
// Base64 编码的字符串转换为 ArrayBuffer
base64ToArrayBuffer(base64) {
const binaryString = window.atob(base64);
const len = binaryString.length;
const bytes = new Uint8Array(len);
for (let i = 0; i < len; i++) {
bytes[i] = binaryString.charCodeAt(i);
}
return bytes.buffer;
}
// 检查音频播放队列并播放音频
checkQueue() {
if (!this.isPlaying && this.queue.length > 0) {
this.isPlaying = true;
const nextAudio = this.queue.shift();
this.play_wave(nextAudio);
}
}
// 将音频添加到播放队列
enqueueAudio(audio_buf_wave) {
if (allow_auto_read_tts_flag) {
this.queue.push(audio_buf_wave);
this.checkQueue();
}
}
// 播放音频
async play_wave(encodedAudio) {
//const audioData = this.base64ToArrayBuffer(encodedAudio);
const audioData = encodedAudio;
try {
const buffer = await this.audioCtx.decodeAudioData(audioData);
const source = this.audioCtx.createBufferSource();
source.buffer = buffer;
source.connect(this.audioCtx.destination);
source.onended = () => {
if (allow_auto_read_tts_flag) {
this.isPlaying = false;
this.currentSource = null; // 播放结束后清空当前源
this.checkQueue();
}
};
this.currentSource = source; // 保存当前播放的源
source.start();
} catch (e) {
console.log("Audio error!", e);
this.isPlaying = false;
this.currentSource = null; // 出错时也应清空当前源
this.checkQueue();
}
}
// 新增:立即停止播放音频的方法
stop() {
if (this.currentSource) {
this.queue = []; // 清空队列
this.currentSource.stop(); // 停止当前源
this.currentSource = null; // 清空当前源
this.isPlaying = false; // 更新播放状态
// 关闭音频上下文可能会导致无法再次播放音频,因此仅停止当前源
// this.audioCtx.close(); // 可选:如果需要可以关闭音频上下文
}
}
}
const audioPlayer = new AudioPlayer();
class FIFOLock {
constructor() {
this.queue = [];
this.currentTaskExecuting = false;
}
lock() {
let resolveLock;
const lock = new Promise(resolve => {
resolveLock = resolve;
});
this.queue.push(resolveLock);
if (!this.currentTaskExecuting) {
this._dequeueNext();
}
return lock;
}
_dequeueNext() {
if (this.queue.length === 0) {
this.currentTaskExecuting = false;
return;
}
this.currentTaskExecuting = true;
const resolveLock = this.queue.shift();
resolveLock();
}
unlock() {
this.currentTaskExecuting = false;
this._dequeueNext();
}
}
function delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
// Define the trigger function with delay parameter T in milliseconds
function trigger(T, fire) {
// Variable to keep track of the timer ID
let timeoutID = null;
// Variable to store the latest arguments
let lastArgs = null;
return function (...args) {
// Update lastArgs with the latest arguments
lastArgs = args;
// Clear the existing timer if the function is called again
if (timeoutID !== null) {
clearTimeout(timeoutID);
}
// Set a new timer that calls the `fire` function with the latest arguments after T milliseconds
timeoutID = setTimeout(() => {
fire(...lastArgs);
}, T);
};
}
prev_text = "";
prev_text_already_pushed = "";
prev_chatbot_index = -1;
const delay_live_text_update = trigger(3000, on_live_stream_terminate);
function on_live_stream_terminate(latest_text) {
// remove `prev_text_already_pushed` from `latest_text`
console.log("on_live_stream_terminate", latest_text)
remaining_text = latest_text.slice(prev_text_already_pushed.length);
if ((!isEmptyOrWhitespaceOnly(remaining_text)) && remaining_text.length != 0) {
prev_text_already_pushed = latest_text;
push_text_to_audio(remaining_text);
}
}
function is_continue_from_prev(text, prev_text) {
abl = 5
if (text.length < prev_text.length - abl) {
return false;
}
if (prev_text.length > 10) {
return text.startsWith(prev_text.slice(0, Math.min(prev_text.length - abl, 100)));
} else {
return text.startsWith(prev_text);
}
}
function isEmptyOrWhitespaceOnly(remaining_text) {
// Replace \n and 。 with empty strings
let textWithoutSpecifiedCharacters = remaining_text.replace(/[\n。]/g, '');
// Check if the remaining string is empty
return textWithoutSpecifiedCharacters.trim().length === 0;
}
function process_increased_text(remaining_text) {
// console.log('[is continue], remaining_text: ', remaining_text)
// remaining_text starts with \n or 。, then move these chars into prev_text_already_pushed
while (remaining_text.startsWith('\n') || remaining_text.startsWith('。')) {
prev_text_already_pushed = prev_text_already_pushed + remaining_text[0];
remaining_text = remaining_text.slice(1);
}
if (remaining_text.includes('\n') || remaining_text.includes('。')) { // determine remaining_text contain \n or 。
// new message begin!
index_of_last_sep = Math.max(remaining_text.lastIndexOf('\n'), remaining_text.lastIndexOf('。'));
// break the text into two parts
tobe_pushed = remaining_text.slice(0, index_of_last_sep + 1);
prev_text_already_pushed = prev_text_already_pushed + tobe_pushed;
// console.log('[is continue], push: ', tobe_pushed)
// console.log('[is continue], update prev_text_already_pushed: ', prev_text_already_pushed)
if (!isEmptyOrWhitespaceOnly(tobe_pushed)) {
// console.log('[is continue], remaining_text is empty')
push_text_to_audio(tobe_pushed);
}
}
}
function process_latest_text_output(text, chatbot_index) {
if (text.length == 0) {
prev_text = text;
prev_text_mask = text;
// console.log('empty text')
return;
}
if (text == prev_text) {
// console.log('[nothing changed]')
return;
}
var is_continue = is_continue_from_prev(text, prev_text_already_pushed);
if (chatbot_index == prev_chatbot_index && is_continue) {
// on_text_continue_grow
remaining_text = text.slice(prev_text_already_pushed.length);
process_increased_text(remaining_text);
delay_live_text_update(text); // in case of no \n or 。 in the text, this timer will finally commit
}
else if (chatbot_index == prev_chatbot_index && !is_continue) {
console.log('---------------------')
console.log('text twisting!')
console.log('[new message begin]', 'text', text, 'prev_text_already_pushed', prev_text_already_pushed)
console.log('---------------------')
prev_text_already_pushed = "";
delay_live_text_update(text); // in case of no \n or 。 in the text, this timer will finally commit
}
else {
// on_new_message_begin, we have to clear `prev_text_already_pushed`
console.log('---------------------')
console.log('new message begin!')
console.log('[new message begin]', 'text', text, 'prev_text_already_pushed', prev_text_already_pushed)
console.log('---------------------')
prev_text_already_pushed = "";
process_increased_text(text);
delay_live_text_update(text); // in case of no \n or 。 in the text, this timer will finally commit
}
prev_text = text;
prev_chatbot_index = chatbot_index;
}
const audio_push_lock = new FIFOLock();
async function push_text_to_audio(text) {
if (!allow_auto_read_tts_flag) {
return;
}
await audio_push_lock.lock();
var lines = text.split(/[\n。]/);
for (const audio_buf_text of lines) {
if (audio_buf_text) {
// Append '/vits' to the current URL to form the target endpoint
const url = `${window.location.href}vits`;
// Define the payload to be sent in the POST request
const payload = {
text: audio_buf_text, // Ensure 'audio_buf_text' is defined with valid data
text_language: "zh"
};
// Call the async postData function and log the response
post_text(url, payload, send_index);
send_index = send_index + 1;
console.log(send_index, audio_buf_text)
// sleep 2 seconds
if (allow_auto_read_tts_flag) {
await delay(3000);
}
}
}
audio_push_lock.unlock();
}
send_index = 0;
recv_index = 0;
to_be_processed = [];
async function UpdatePlayQueue(cnt, audio_buf_wave) {
if (cnt != recv_index) {
to_be_processed.push([cnt, audio_buf_wave]);
console.log('cache', cnt);
}
else {
console.log('processing', cnt);
recv_index = recv_index + 1;
if (audio_buf_wave) {
audioPlayer.enqueueAudio(audio_buf_wave);
}
// deal with other cached audio
while (true) {
find_any = false;
for (i = to_be_processed.length - 1; i >= 0; i--) {
if (to_be_processed[i][0] == recv_index) {
console.log('processing cached', recv_index);
if (to_be_processed[i][1]) {
audioPlayer.enqueueAudio(to_be_processed[i][1]);
}
to_be_processed.pop(i);
find_any = true;
recv_index = recv_index + 1;
}
}
if (!find_any) { break; }
}
}
}
function post_text(url, payload, cnt) {
if (allow_auto_read_tts_flag) {
postData(url, payload, cnt)
.then(data => {
UpdatePlayQueue(cnt, data);
return;
});
} else {
UpdatePlayQueue(cnt, null);
return;
}
}
notify_user_error = false
// Create an async function to perform the POST request
async function postData(url = '', data = {}) {
try {
// Use the Fetch API with await
const response = await fetch(url, {
method: 'POST', // Specify the request method
body: JSON.stringify(data), // Convert the JavaScript object to a JSON string
});
// Check if the response is ok (status in the range 200-299)
if (!response.ok) {
// If not OK, throw an error
console.info('There was a problem during audio generation requests:', response.status);
// if (!notify_user_error){
// notify_user_error = true;
// alert('There was a problem during audio generation requests:', response.status);
// }
return null;
}
// If OK, parse and return the JSON response
return await response.arrayBuffer();
} catch (error) {
// Log any errors that occur during the fetch operation
console.info('There was a problem during audio generation requests:', error);
// if (!notify_user_error){
// notify_user_error = true;
// alert('There was a problem during audio generation requests:', error);
// }
return null;
}
}

查看文件

@@ -1,10 +1,34 @@
from toolbox import get_conf
CODE_HIGHLIGHT, ADD_WAIFU, LAYOUT = get_conf("CODE_HIGHLIGHT", "ADD_WAIFU", "LAYOUT")
def minimize_js(common_js_path):
try:
import rjsmin, hashlib, glob, os
# clean up old minimized js files, matching `common_js_path + '.min.*'`
for old_min_js in glob.glob(common_js_path + '.min.*.js'):
os.remove(old_min_js)
# use rjsmin to minimize `common_js_path`
c_jsmin = rjsmin.jsmin
with open(common_js_path, "r") as f:
js_content = f.read()
minimized_js_content = c_jsmin(js_content)
# compute sha256 hash of minimized js content
sha_hash = hashlib.sha256(minimized_js_content.encode()).hexdigest()[:8]
minimized_js_path = common_js_path + '.min.' + sha_hash + '.js'
# save to minimized js file
with open(minimized_js_path, "w") as f:
f.write(minimized_js_content)
# return minimized js file path
return minimized_js_path
except:
return common_js_path
def get_common_html_javascript_code():
js = "\n"
common_js_path = "themes/common.js"
minimized_js_path = minimize_js(common_js_path)
for jsf in [
"file=themes/common.js",
f"file={minimized_js_path}",
]:
js += f"""<script src="{jsf}"></script>\n"""
@@ -15,4 +39,6 @@ def get_common_html_javascript_code():
"file=themes/waifu_plugin/jquery-ui.min.js",
]:
js += f"""<script src="{jsf}"></script>\n"""
return js
else:
js += """<script>window.loadLive2D = function(){};</script>\n"""
return js

查看文件

@@ -1,4 +1,3 @@
import logging
import os
import gradio as gr
from toolbox import get_conf, ProxyNetworkActivate
@@ -10,12 +9,15 @@ theme_dir = os.path.dirname(__file__)
def dynamic_set_theme(THEME):
set_theme = gr.themes.ThemeClass()
with ProxyNetworkActivate("Download_Gradio_Theme"):
logging.info("正在下载Gradio主题,请稍等。")
if THEME.startswith("Huggingface-"):
THEME = THEME.lstrip("Huggingface-")
if THEME.startswith("huggingface-"):
THEME = THEME.lstrip("huggingface-")
set_theme = set_theme.from_hub(THEME.lower())
print("正在下载Gradio主题,请稍等。")
try:
if THEME.startswith("Huggingface-"):
THEME = THEME.lstrip("Huggingface-")
if THEME.startswith("huggingface-"):
THEME = THEME.lstrip("huggingface-")
set_theme = set_theme.from_hub(THEME.lower())
except:
print("下载Gradio主题时出现异常。")
return set_theme
@@ -23,13 +25,16 @@ def adjust_theme():
try:
set_theme = gr.themes.ThemeClass()
with ProxyNetworkActivate("Download_Gradio_Theme"):
logging.info("正在下载Gradio主题,请稍等。")
THEME = get_conf("THEME")
if THEME.startswith("Huggingface-"):
THEME = THEME.lstrip("Huggingface-")
if THEME.startswith("huggingface-"):
THEME = THEME.lstrip("huggingface-")
set_theme = set_theme.from_hub(THEME.lower())
print("正在下载Gradio主题,请稍等。")
try:
THEME = get_conf("THEME")
if THEME.startswith("Huggingface-"):
THEME = THEME.lstrip("Huggingface-")
if THEME.startswith("huggingface-"):
THEME = THEME.lstrip("huggingface-")
set_theme = set_theme.from_hub(THEME.lower())
except:
print("下载Gradio主题时出现异常。")
from themes.common import get_common_html_javascript_code
js = get_common_html_javascript_code()
@@ -49,9 +54,7 @@ def adjust_theme():
)
except Exception:
set_theme = None
from toolbox import trimmed_format_exc
logging.error("gradio版本较旧, 不能自定义字体和颜色:", trimmed_format_exc())
print("gradio版本较旧, 不能自定义字体和颜色。")
return set_theme

0
themes/sovits_audio.js 普通文件
查看文件

查看文件

@@ -111,10 +111,10 @@ js_code_for_persistent_cookie_init = """(web_cookie_cache, cookie) => {
}
"""
# 详见 themes/common.js
js_code_reset = """
(a,b,c)=>{
return [[], [], "已重置"];
return reset_conversation(a,b);
}
"""

查看文件

@@ -79,6 +79,8 @@ class ChatBotWithCookies(list):
def get_cookies(self):
return self._cookies
def get_user(self):
return self._cookies.get("user_name", default_user_name)
def ArgsGeneralWrapper(f):
"""
@@ -190,6 +192,8 @@ def trimmed_format_exc():
replace_path = "."
return str.replace(current_path, replace_path)
def trimmed_format_exc_markdown():
return '\n\n```\n' + trimmed_format_exc() + '```'
def CatchException(f):
"""
@@ -534,6 +538,17 @@ def on_file_uploaded(
return chatbot, txt, txt2, cookies
def generate_file_link(report_files:List[str]):
file_links = ""
for f in report_files:
file_links += (
f'<br/><a href="file={os.path.abspath(f)}" target="_blank">{f}</a>'
)
return file_links
def on_report_generated(cookies:dict, files:List[str], chatbot:ChatBotWithCookies):
if "files_to_promote" in cookies:
report_files = cookies["files_to_promote"]
@@ -866,23 +881,6 @@ class ProxyNetworkActivate:
return
def objdump(obj, file="objdump.tmp"):
import pickle
with open(file, "wb+") as f:
pickle.dump(obj, f)
return
def objload(file="objdump.tmp"):
import pickle, os
if not os.path.exists(file):
return
with open(file, "rb") as f:
return pickle.load(f)
def Singleton(cls):
"""
一个单实例装饰器

查看文件

@@ -1,5 +1,5 @@
{
"version": 3.74,
"version": 3.75,
"show_feature": true,
"new_feature": "增加多用户文件鉴权验证提高安全性 <-> 优化oneapi接入方法 <-> 接入Cohere和月之暗面模型 <-> 简化挂载二级目录的步骤 <-> 支持Mermaid绘图库让大模型绘制脑图"
"new_feature": "添加TTS语音输出EdgeTTS和SoVits语音克隆 <-> Doc2x PDF翻译 <-> 添加回溯对话按钮"
}