Compare commits
3 Commits
master
...
threejs-ap
| Author | SHA1 | Date | |
|---|---|---|---|
| 3071057e6d | |||
| 271379cdee | |||
| 0d655f2d18 |
44
.github/workflows/build-with-audio-assistant.yml
vendored
44
.github/workflows/build-with-audio-assistant.yml
vendored
@ -1,44 +0,0 @@
|
|||||||
# https://docs.github.com/en/actions/publishing-packages/publishing-docker-images#publishing-images-to-github-packages
|
|
||||||
name: build-with-audio-assistant
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- 'master'
|
|
||||||
|
|
||||||
env:
|
|
||||||
REGISTRY: ghcr.io
|
|
||||||
IMAGE_NAME: ${{ github.repository }}_audio_assistant
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build-and-push-image:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
packages: write
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout repository
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
|
|
||||||
- name: Log in to the Container registry
|
|
||||||
uses: docker/login-action@v2
|
|
||||||
with:
|
|
||||||
registry: ${{ env.REGISTRY }}
|
|
||||||
username: ${{ github.actor }}
|
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
|
|
||||||
- name: Extract metadata (tags, labels) for Docker
|
|
||||||
id: meta
|
|
||||||
uses: docker/metadata-action@v4
|
|
||||||
with:
|
|
||||||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
|
||||||
|
|
||||||
- name: Build and push Docker image
|
|
||||||
uses: docker/build-push-action@v4
|
|
||||||
with:
|
|
||||||
context: .
|
|
||||||
push: true
|
|
||||||
file: docs/GithubAction+NoLocal+AudioAssistant
|
|
||||||
tags: ${{ steps.meta.outputs.tags }}
|
|
||||||
labels: ${{ steps.meta.outputs.labels }}
|
|
||||||
28
README.md
28
README.md
@ -44,7 +44,7 @@ chat分析报告生成 | [函数插件] 运行后自动生成总结汇报
|
|||||||
Latex论文一键校对 | [函数插件] 仿Grammarly对Latex文章进行语法、拼写纠错+输出对照PDF
|
Latex论文一键校对 | [函数插件] 仿Grammarly对Latex文章进行语法、拼写纠错+输出对照PDF
|
||||||
[谷歌学术统合小助手](https://www.bilibili.com/video/BV19L411U7ia) | [函数插件] 给定任意谷歌学术搜索页面URL,让gpt帮你[写relatedworks](https://www.bilibili.com/video/BV1GP411U7Az/)
|
[谷歌学术统合小助手](https://www.bilibili.com/video/BV19L411U7ia) | [函数插件] 给定任意谷歌学术搜索页面URL,让gpt帮你[写relatedworks](https://www.bilibili.com/video/BV1GP411U7Az/)
|
||||||
互联网信息聚合+GPT | [函数插件] 一键[让GPT从互联网获取信息](https://www.bilibili.com/video/BV1om4y127ck)回答问题,让信息永不过时
|
互联网信息聚合+GPT | [函数插件] 一键[让GPT从互联网获取信息](https://www.bilibili.com/video/BV1om4y127ck)回答问题,让信息永不过时
|
||||||
⭐Arxiv论文精细翻译 ([Docker](https://github.com/binary-husky/gpt_academic/pkgs/container/gpt_academic_with_latex)) | [函数插件] 一键[以超高质量翻译arxiv论文](https://www.bilibili.com/video/BV1dz4y1v77A/),目前最好的论文翻译工具
|
⭐Arxiv论文精细翻译 | [函数插件] 一键[以超高质量翻译arxiv论文](https://www.bilibili.com/video/BV1dz4y1v77A/),目前最好的论文翻译工具
|
||||||
⭐[实时语音对话输入](https://github.com/binary-husky/gpt_academic/blob/master/docs/use_audio.md) | [函数插件] 异步[监听音频](https://www.bilibili.com/video/BV1AV4y187Uy/),自动断句,自动寻找回答时机
|
⭐[实时语音对话输入](https://github.com/binary-husky/gpt_academic/blob/master/docs/use_audio.md) | [函数插件] 异步[监听音频](https://www.bilibili.com/video/BV1AV4y187Uy/),自动断句,自动寻找回答时机
|
||||||
公式/图片/表格显示 | 可以同时显示公式的[tex形式和渲染形式](https://user-images.githubusercontent.com/96192199/230598842-1d7fcddd-815d-40ee-af60-baf488a199df.png),支持公式、代码高亮
|
公式/图片/表格显示 | 可以同时显示公式的[tex形式和渲染形式](https://user-images.githubusercontent.com/96192199/230598842-1d7fcddd-815d-40ee-af60-baf488a199df.png),支持公式、代码高亮
|
||||||
多线程函数插件支持 | 支持多线调用chatgpt,一键处理[海量文本](https://www.bilibili.com/video/BV1FT411H7c5/)或程序
|
多线程函数插件支持 | 支持多线调用chatgpt,一键处理[海量文本](https://www.bilibili.com/video/BV1FT411H7c5/)或程序
|
||||||
@ -52,8 +52,8 @@ Latex论文一键校对 | [函数插件] 仿Grammarly对Latex文章进行语法
|
|||||||
[多LLM模型](https://www.bilibili.com/video/BV1wT411p7yf)支持 | 同时被GPT3.5、GPT4、[清华ChatGLM2](https://github.com/THUDM/ChatGLM2-6B)、[复旦MOSS](https://github.com/OpenLMLab/MOSS)同时伺候的感觉一定会很不错吧?
|
[多LLM模型](https://www.bilibili.com/video/BV1wT411p7yf)支持 | 同时被GPT3.5、GPT4、[清华ChatGLM2](https://github.com/THUDM/ChatGLM2-6B)、[复旦MOSS](https://github.com/OpenLMLab/MOSS)同时伺候的感觉一定会很不错吧?
|
||||||
⭐ChatGLM2微调模型 | 支持加载ChatGLM2微调模型,提供ChatGLM2微调辅助插件
|
⭐ChatGLM2微调模型 | 支持加载ChatGLM2微调模型,提供ChatGLM2微调辅助插件
|
||||||
更多LLM模型接入,支持[huggingface部署](https://huggingface.co/spaces/qingxu98/gpt-academic) | 加入Newbing接口(新必应),引入清华[Jittorllms](https://github.com/Jittor/JittorLLMs)支持[LLaMA](https://github.com/facebookresearch/llama)和[盘古α](https://openi.org.cn/pangu/)
|
更多LLM模型接入,支持[huggingface部署](https://huggingface.co/spaces/qingxu98/gpt-academic) | 加入Newbing接口(新必应),引入清华[Jittorllms](https://github.com/Jittor/JittorLLMs)支持[LLaMA](https://github.com/facebookresearch/llama)和[盘古α](https://openi.org.cn/pangu/)
|
||||||
⭐[虚空终端](https://github.com/binary-husky/void-terminal)pip包 | 脱离GUI,在Python中直接调用本项目的函数插件(开发中)
|
|
||||||
更多新功能展示 (图像生成等) …… | 见本文档结尾处 ……
|
更多新功能展示 (图像生成等) …… | 见本文档结尾处 ……
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
@ -93,7 +93,7 @@ Latex论文一键校对 | [函数插件] 仿Grammarly对Latex文章进行语法
|
|||||||
|
|
||||||
1. 下载项目
|
1. 下载项目
|
||||||
```sh
|
```sh
|
||||||
git clone --depth=1 https://github.com/binary-husky/gpt_academic.git
|
git clone https://github.com/binary-husky/gpt_academic.git
|
||||||
cd gpt_academic
|
cd gpt_academic
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -116,7 +116,7 @@ python -m pip install -r requirements.txt # 这个步骤和pip安装一样的步
|
|||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
<details><summary>如果需要支持清华ChatGLM2/复旦MOSS/RWKV作为后端,请点击展开此处</summary>
|
<details><summary>如果需要支持清华ChatGLM2/复旦MOSS作为后端,请点击展开此处</summary>
|
||||||
<p>
|
<p>
|
||||||
|
|
||||||
【可选步骤】如果需要支持清华ChatGLM2/复旦MOSS作为后端,需要额外安装更多依赖(前提条件:熟悉Python + 用过Pytorch + 电脑配置够强):
|
【可选步骤】如果需要支持清华ChatGLM2/复旦MOSS作为后端,需要额外安装更多依赖(前提条件:熟悉Python + 用过Pytorch + 电脑配置够强):
|
||||||
@ -126,12 +126,9 @@ python -m pip install -r request_llm/requirements_chatglm.txt
|
|||||||
|
|
||||||
# 【可选步骤II】支持复旦MOSS
|
# 【可选步骤II】支持复旦MOSS
|
||||||
python -m pip install -r request_llm/requirements_moss.txt
|
python -m pip install -r request_llm/requirements_moss.txt
|
||||||
git clone --depth=1 https://github.com/OpenLMLab/MOSS.git request_llm/moss # 注意执行此行代码时,必须处于项目根路径
|
git clone https://github.com/OpenLMLab/MOSS.git request_llm/moss # 注意执行此行代码时,必须处于项目根路径
|
||||||
|
|
||||||
# 【可选步骤III】支持RWKV Runner
|
# 【可选步骤III】确保config.py配置文件的AVAIL_LLM_MODELS包含了期望的模型,目前支持的全部模型如下(jittorllms系列目前仅支持docker方案):
|
||||||
参考wiki:https://github.com/binary-husky/gpt_academic/wiki/%E9%80%82%E9%85%8DRWKV-Runner
|
|
||||||
|
|
||||||
# 【可选步骤IV】确保config.py配置文件的AVAIL_LLM_MODELS包含了期望的模型,目前支持的全部模型如下(jittorllms系列目前仅支持docker方案):
|
|
||||||
AVAIL_LLM_MODELS = ["gpt-3.5-turbo", "api2d-gpt-3.5-turbo", "gpt-4", "api2d-gpt-4", "chatglm", "newbing", "moss"] # + ["jittorllms_rwkv", "jittorllms_pangualpha", "jittorllms_llama"]
|
AVAIL_LLM_MODELS = ["gpt-3.5-turbo", "api2d-gpt-3.5-turbo", "gpt-4", "api2d-gpt-4", "chatglm", "newbing", "moss"] # + ["jittorllms_rwkv", "jittorllms_pangualpha", "jittorllms_llama"]
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -150,10 +147,9 @@ python main.py
|
|||||||
1. 仅ChatGPT(推荐大多数人选择,等价于docker-compose方案1)
|
1. 仅ChatGPT(推荐大多数人选择,等价于docker-compose方案1)
|
||||||
[](https://github.com/binary-husky/gpt_academic/actions/workflows/build-without-local-llms.yml)
|
[](https://github.com/binary-husky/gpt_academic/actions/workflows/build-without-local-llms.yml)
|
||||||
[](https://github.com/binary-husky/gpt_academic/actions/workflows/build-with-latex.yml)
|
[](https://github.com/binary-husky/gpt_academic/actions/workflows/build-with-latex.yml)
|
||||||
[](https://github.com/binary-husky/gpt_academic/actions/workflows/build-with-audio-assistant.yml)
|
|
||||||
|
|
||||||
``` sh
|
``` sh
|
||||||
git clone --depth=1 https://github.com/binary-husky/gpt_academic.git # 下载项目
|
git clone https://github.com/binary-husky/gpt_academic.git # 下载项目
|
||||||
cd gpt_academic # 进入路径
|
cd gpt_academic # 进入路径
|
||||||
nano config.py # 用任意文本编辑器编辑config.py, 配置 “Proxy”, “API_KEY” 以及 “WEB_PORT” (例如50923) 等
|
nano config.py # 用任意文本编辑器编辑config.py, 配置 “Proxy”, “API_KEY” 以及 “WEB_PORT” (例如50923) 等
|
||||||
docker build -t gpt-academic . # 安装
|
docker build -t gpt-academic . # 安装
|
||||||
@ -199,12 +195,10 @@ docker-compose up
|
|||||||
5. 远程云服务器部署(需要云服务器知识与经验)。
|
5. 远程云服务器部署(需要云服务器知识与经验)。
|
||||||
请访问[部署wiki-1](https://github.com/binary-husky/gpt_academic/wiki/%E4%BA%91%E6%9C%8D%E5%8A%A1%E5%99%A8%E8%BF%9C%E7%A8%8B%E9%83%A8%E7%BD%B2%E6%8C%87%E5%8D%97)
|
请访问[部署wiki-1](https://github.com/binary-husky/gpt_academic/wiki/%E4%BA%91%E6%9C%8D%E5%8A%A1%E5%99%A8%E8%BF%9C%E7%A8%8B%E9%83%A8%E7%BD%B2%E6%8C%87%E5%8D%97)
|
||||||
|
|
||||||
6. 使用Sealos[一键部署](https://github.com/binary-husky/gpt_academic/issues/993)。
|
6. 使用WSL2(Windows Subsystem for Linux 子系统)。
|
||||||
|
|
||||||
7. 使用WSL2(Windows Subsystem for Linux 子系统)。
|
|
||||||
请访问[部署wiki-2](https://github.com/binary-husky/gpt_academic/wiki/%E4%BD%BF%E7%94%A8WSL2%EF%BC%88Windows-Subsystem-for-Linux-%E5%AD%90%E7%B3%BB%E7%BB%9F%EF%BC%89%E9%83%A8%E7%BD%B2)
|
请访问[部署wiki-2](https://github.com/binary-husky/gpt_academic/wiki/%E4%BD%BF%E7%94%A8WSL2%EF%BC%88Windows-Subsystem-for-Linux-%E5%AD%90%E7%B3%BB%E7%BB%9F%EF%BC%89%E9%83%A8%E7%BD%B2)
|
||||||
|
|
||||||
8. 如何在二级网址(如`http://localhost/subpath`)下运行。
|
7. 如何在二级网址(如`http://localhost/subpath`)下运行。
|
||||||
请访问[FastAPI运行说明](docs/WithFastapi.md)
|
请访问[FastAPI运行说明](docs/WithFastapi.md)
|
||||||
|
|
||||||
|
|
||||||
@ -292,10 +286,6 @@ Tip:不指定文件直接点击 `载入对话历史存档` 可以查看历史h
|
|||||||
<img src="https://github.com/binary-husky/gpt_academic/assets/96192199/476f66d9-7716-4537-b5c1-735372c25adb" height="200">
|
<img src="https://github.com/binary-husky/gpt_academic/assets/96192199/476f66d9-7716-4537-b5c1-735372c25adb" height="200">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
11. 语言、主题切换
|
|
||||||
<div align="center">
|
|
||||||
<img src="https://github.com/binary-husky/gpt_academic/assets/96192199/b6799499-b6fb-4f0c-9c8e-1b441872f4e8" width="500" >
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
### II:版本:
|
### II:版本:
|
||||||
|
|||||||
39
cc.json
Normal file
39
cc.json
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"name": "Box-1",
|
||||||
|
"width": 1,
|
||||||
|
"height": 1,
|
||||||
|
"depth": 1,
|
||||||
|
"location_x": 1,
|
||||||
|
"location_y": 0,
|
||||||
|
"location_z": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Box-2",
|
||||||
|
"width": 1,
|
||||||
|
"height": 1,
|
||||||
|
"depth": 1,
|
||||||
|
"location_x": -1,
|
||||||
|
"location_y": 0,
|
||||||
|
"location_z": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Box-3",
|
||||||
|
"width": 1,
|
||||||
|
"height": 1,
|
||||||
|
"depth": 1,
|
||||||
|
"location_x": 0,
|
||||||
|
"location_y": 1,
|
||||||
|
"location_z": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Box-4",
|
||||||
|
"width": 1,
|
||||||
|
"height": 1,
|
||||||
|
"depth": 1,
|
||||||
|
"location_x": 0,
|
||||||
|
"location_y": -1,
|
||||||
|
"location_z": 0
|
||||||
|
}
|
||||||
|
|
||||||
|
]
|
||||||
@ -3,18 +3,15 @@ def check_proxy(proxies):
|
|||||||
import requests
|
import requests
|
||||||
proxies_https = proxies['https'] if proxies is not None else '无'
|
proxies_https = proxies['https'] if proxies is not None else '无'
|
||||||
try:
|
try:
|
||||||
response = requests.get("https://ipapi.co/json/", proxies=proxies, timeout=4)
|
response = requests.get("https://ipapi.co/json/",
|
||||||
|
proxies=proxies, timeout=4)
|
||||||
data = response.json()
|
data = response.json()
|
||||||
print(f'查询代理的地理位置,返回的结果是{data}')
|
print(f'查询代理的地理位置,返回的结果是{data}')
|
||||||
if 'country_name' in data:
|
if 'country_name' in data:
|
||||||
country = data['country_name']
|
country = data['country_name']
|
||||||
result = f"代理配置 {proxies_https}, 代理所在地:{country}"
|
result = f"代理配置 {proxies_https}, 代理所在地:{country}"
|
||||||
elif 'error' in data:
|
elif 'error' in data:
|
||||||
alternative = _check_with_backup_source(proxies)
|
result = f"代理配置 {proxies_https}, 代理所在地:未知,IP查询频率受限"
|
||||||
if alternative is None:
|
|
||||||
result = f"代理配置 {proxies_https}, 代理所在地:未知,IP查询频率受限"
|
|
||||||
else:
|
|
||||||
result = f"代理配置 {proxies_https}, 代理所在地:{alternative}"
|
|
||||||
else:
|
else:
|
||||||
result = f"代理配置 {proxies_https}, 代理数据解析失败:{data}"
|
result = f"代理配置 {proxies_https}, 代理数据解析失败:{data}"
|
||||||
print(result)
|
print(result)
|
||||||
@ -24,11 +21,6 @@ def check_proxy(proxies):
|
|||||||
print(result)
|
print(result)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def _check_with_backup_source(proxies):
|
|
||||||
import random, string, requests
|
|
||||||
random_string = ''.join(random.choices(string.ascii_letters + string.digits, k=32))
|
|
||||||
try: return requests.get(f"http://{random_string}.edns.ip-api.com/json", proxies=proxies, timeout=4).json()['dns']['geo']
|
|
||||||
except: return None
|
|
||||||
|
|
||||||
def backup_and_download(current_version, remote_version):
|
def backup_and_download(current_version, remote_version):
|
||||||
"""
|
"""
|
||||||
|
|||||||
22
config.py
22
config.py
@ -32,9 +32,9 @@ else:
|
|||||||
|
|
||||||
# ------------------------------------ 以下配置可以优化体验, 但大部分场合下并不需要修改 ------------------------------------
|
# ------------------------------------ 以下配置可以优化体验, 但大部分场合下并不需要修改 ------------------------------------
|
||||||
|
|
||||||
# 重新URL重新定向,实现更换API_URL的作用(高危设置! 常规情况下不要修改! 通过修改此设置,您将把您的API-KEY和对话隐私完全暴露给您设定的中间人!)
|
# 重新URL重新定向,实现更换API_URL的作用(常规情况下,不要修改!! 高危设置!通过修改此设置,您将把您的API-KEY和对话隐私完全暴露给您设定的中间人!)
|
||||||
# 格式: API_URL_REDIRECT = {"https://api.openai.com/v1/chat/completions": "在这里填写重定向的api.openai.com的URL"}
|
# 格式 API_URL_REDIRECT = {"https://api.openai.com/v1/chat/completions": "在这里填写重定向的api.openai.com的URL"}
|
||||||
# 举例: API_URL_REDIRECT = {"https://api.openai.com/v1/chat/completions": "https://reverse-proxy-url/v1/chat/completions"}
|
# 例如 API_URL_REDIRECT = {"https://api.openai.com/v1/chat/completions":"https://reverse-proxy-url/v1/chat/completions"}
|
||||||
API_URL_REDIRECT = {}
|
API_URL_REDIRECT = {}
|
||||||
|
|
||||||
|
|
||||||
@ -71,7 +71,7 @@ MAX_RETRY = 2
|
|||||||
# 模型选择是 (注意: LLM_MODEL是默认选中的模型, 它*必须*被包含在AVAIL_LLM_MODELS列表中 )
|
# 模型选择是 (注意: LLM_MODEL是默认选中的模型, 它*必须*被包含在AVAIL_LLM_MODELS列表中 )
|
||||||
LLM_MODEL = "gpt-3.5-turbo" # 可选 ↓↓↓
|
LLM_MODEL = "gpt-3.5-turbo" # 可选 ↓↓↓
|
||||||
AVAIL_LLM_MODELS = ["gpt-3.5-turbo-16k", "gpt-3.5-turbo", "azure-gpt-3.5", "api2d-gpt-3.5-turbo", "gpt-4", "api2d-gpt-4", "chatglm", "moss", "newbing", "stack-claude"]
|
AVAIL_LLM_MODELS = ["gpt-3.5-turbo-16k", "gpt-3.5-turbo", "azure-gpt-3.5", "api2d-gpt-3.5-turbo", "gpt-4", "api2d-gpt-4", "chatglm", "moss", "newbing", "stack-claude"]
|
||||||
# P.S. 其他可用的模型还包括 ["gpt-3.5-turbo-0613", "gpt-3.5-turbo-16k-0613", "claude-1-100k", "claude-2", "internlm", "jittorllms_rwkv", "jittorllms_pangualpha", "jittorllms_llama"]
|
# P.S. 其他可用的模型还包括 ["gpt-3.5-turbo-0613", "gpt-3.5-turbo-16k-0613", "claude-1-100k", "claude-2", "jittorllms_rwkv", "jittorllms_pangualpha", "jittorllms_llama"]
|
||||||
|
|
||||||
|
|
||||||
# ChatGLM(2) Finetune Model Path (如果使用ChatGLM2微调模型,需要把"chatglmft"加入AVAIL_LLM_MODELS中)
|
# ChatGLM(2) Finetune Model Path (如果使用ChatGLM2微调模型,需要把"chatglmft"加入AVAIL_LLM_MODELS中)
|
||||||
@ -80,7 +80,6 @@ ChatGLM_PTUNING_CHECKPOINT = "" # 例如"/home/hmp/ChatGLM2-6B/ptuning/output/6b
|
|||||||
|
|
||||||
# 本地LLM模型如ChatGLM的执行方式 CPU/GPU
|
# 本地LLM模型如ChatGLM的执行方式 CPU/GPU
|
||||||
LOCAL_MODEL_DEVICE = "cpu" # 可选 "cuda"
|
LOCAL_MODEL_DEVICE = "cpu" # 可选 "cuda"
|
||||||
LOCAL_MODEL_QUANT = "FP16" # 默认 "FP16" "INT4" 启用量化INT4版本 "INT8" 启用量化INT8版本
|
|
||||||
|
|
||||||
|
|
||||||
# 设置gradio的并行线程数(不需要修改)
|
# 设置gradio的并行线程数(不需要修改)
|
||||||
@ -132,14 +131,9 @@ put your new bing cookies here
|
|||||||
|
|
||||||
# 阿里云实时语音识别 配置难度较高 仅建议高手用户使用 参考 https://github.com/binary-husky/gpt_academic/blob/master/docs/use_audio.md
|
# 阿里云实时语音识别 配置难度较高 仅建议高手用户使用 参考 https://github.com/binary-husky/gpt_academic/blob/master/docs/use_audio.md
|
||||||
ENABLE_AUDIO = False
|
ENABLE_AUDIO = False
|
||||||
ALIYUN_TOKEN="" # 例如 f37f30e0f9934c34a992f6f64f7eba4f
|
ALIYUN_TOKEN="" # 例如 f37f30e0f9934c34a992f6f64f7eba4f
|
||||||
ALIYUN_APPKEY="" # 例如 RoPlZrM88DnAFkZK
|
ALIYUN_APPKEY="" # 例如 RoPlZrM88DnAFkZK
|
||||||
ALIYUN_ACCESSKEY="" # (无需填写)
|
|
||||||
ALIYUN_SECRET="" # (无需填写)
|
|
||||||
|
|
||||||
# Claude API KEY
|
# Claude API KEY
|
||||||
ANTHROPIC_API_KEY = ""
|
ANTHROPIC_API_KEY = ""
|
||||||
|
|
||||||
|
|
||||||
# 自定义API KEY格式
|
|
||||||
CUSTOM_API_KEY_PATTERN = ""
|
|
||||||
@ -1,25 +1,20 @@
|
|||||||
# 'primary' 颜色对应 theme.py 中的 primary_hue
|
# 'primary' 颜色对应 theme.py 中的 primary_hue
|
||||||
# 'secondary' 颜色对应 theme.py 中的 neutral_hue
|
# 'secondary' 颜色对应 theme.py 中的 neutral_hue
|
||||||
# 'stop' 颜色对应 theme.py 中的 color_er
|
# 'stop' 颜色对应 theme.py 中的 color_er
|
||||||
import importlib
|
# 默认按钮颜色是 secondary
|
||||||
from toolbox import clear_line_break
|
from toolbox import clear_line_break
|
||||||
|
|
||||||
|
|
||||||
def get_core_functions():
|
def get_core_functions():
|
||||||
return {
|
return {
|
||||||
"英语学术润色": {
|
"英语学术润色": {
|
||||||
# 前缀,会被加在你的输入之前。例如,用来描述你的要求,例如翻译、解释代码、润色等等
|
# 前言
|
||||||
"Prefix": r"Below is a paragraph from an academic paper. Polish the writing to meet the academic style, " +
|
"Prefix": r"Below is a paragraph from an academic paper. Polish the writing to meet the academic style, " +
|
||||||
r"improve the spelling, grammar, clarity, concision and overall readability. When necessary, rewrite the whole sentence. " +
|
r"improve the spelling, grammar, clarity, concision and overall readability. When necessary, rewrite the whole sentence. " +
|
||||||
r"Furthermore, list all modification and explain the reasons to do so in markdown table." + "\n\n",
|
r"Furthermore, list all modification and explain the reasons to do so in markdown table." + "\n\n",
|
||||||
# 后缀,会被加在你的输入之后。例如,配合前缀可以把你的输入内容用引号圈起来
|
# 后语
|
||||||
"Suffix": r"",
|
"Suffix": r"",
|
||||||
# 按钮颜色 (默认 secondary)
|
"Color": r"secondary", # 按钮颜色
|
||||||
"Color": r"secondary",
|
|
||||||
# 按钮是否可见 (默认 True,即可见)
|
|
||||||
"Visible": True,
|
|
||||||
# 是否在触发时清除历史 (默认 False,即不处理之前的对话历史)
|
|
||||||
"AutoClearHistory": False
|
|
||||||
},
|
},
|
||||||
"中文学术润色": {
|
"中文学术润色": {
|
||||||
"Prefix": r"作为一名中文学术论文写作改进助理,你的任务是改进所提供文本的拼写、语法、清晰、简洁和整体可读性," +
|
"Prefix": r"作为一名中文学术论文写作改进助理,你的任务是改进所提供文本的拼写、语法、清晰、简洁和整体可读性," +
|
||||||
@ -81,14 +76,3 @@ def get_core_functions():
|
|||||||
"Suffix": r"",
|
"Suffix": r"",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def handle_core_functionality(additional_fn, inputs, history, chatbot):
|
|
||||||
import core_functional
|
|
||||||
importlib.reload(core_functional) # 热更新prompt
|
|
||||||
core_functional = core_functional.get_core_functions()
|
|
||||||
if "PreProcess" in core_functional[additional_fn]: inputs = core_functional[additional_fn]["PreProcess"](inputs) # 获取预处理函数(如果有的话)
|
|
||||||
inputs = core_functional[additional_fn]["Prefix"] + inputs + core_functional[additional_fn]["Suffix"]
|
|
||||||
if core_functional[additional_fn].get("AutoClearHistory", False):
|
|
||||||
history = []
|
|
||||||
return inputs, history
|
|
||||||
|
|||||||
@ -416,6 +416,17 @@ def get_crazy_functions():
|
|||||||
except:
|
except:
|
||||||
print('Load function plugin failed')
|
print('Load function plugin failed')
|
||||||
|
|
||||||
|
try:
|
||||||
|
from crazy_functions.Three场景交互3D import 三维生成
|
||||||
|
function_plugins.update({
|
||||||
|
"ThreeJS 三维交互": {
|
||||||
|
"Color": "stop",
|
||||||
|
"AsButton": False,
|
||||||
|
"Function": HotReload(三维生成)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
except:
|
||||||
|
print('Load function plugin failed')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from toolbox import get_conf
|
from toolbox import get_conf
|
||||||
|
|||||||
@ -157,7 +157,7 @@ def Latex英文纠错加PDF对比(txt, llm_kwargs, plugin_kwargs, chatbot, histo
|
|||||||
try:
|
try:
|
||||||
import glob, os, time, subprocess
|
import glob, os, time, subprocess
|
||||||
subprocess.Popen(['pdflatex', '-version'])
|
subprocess.Popen(['pdflatex', '-version'])
|
||||||
from .latex_fns.latex_actions import Latex精细分解与转化, 编译Latex
|
from .latex_utils import Latex精细分解与转化, 编译Latex
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
chatbot.append([ f"解析项目: {txt}",
|
chatbot.append([ f"解析项目: {txt}",
|
||||||
f"尝试执行Latex指令失败。Latex没有安装, 或者不在环境变量PATH中。安装方法https://tug.org/texlive/。报错信息\n\n```\n\n{trimmed_format_exc()}\n\n```\n\n"])
|
f"尝试执行Latex指令失败。Latex没有安装, 或者不在环境变量PATH中。安装方法https://tug.org/texlive/。报错信息\n\n```\n\n{trimmed_format_exc()}\n\n```\n\n"])
|
||||||
@ -234,7 +234,7 @@ def Latex翻译中文并重新编译PDF(txt, llm_kwargs, plugin_kwargs, chatbot,
|
|||||||
try:
|
try:
|
||||||
import glob, os, time, subprocess
|
import glob, os, time, subprocess
|
||||||
subprocess.Popen(['pdflatex', '-version'])
|
subprocess.Popen(['pdflatex', '-version'])
|
||||||
from .latex_fns.latex_actions import Latex精细分解与转化, 编译Latex
|
from .latex_utils import Latex精细分解与转化, 编译Latex
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
chatbot.append([ f"解析项目: {txt}",
|
chatbot.append([ f"解析项目: {txt}",
|
||||||
f"尝试执行Latex指令失败。Latex没有安装, 或者不在环境变量PATH中。安装方法https://tug.org/texlive/。报错信息\n\n```\n\n{trimmed_format_exc()}\n\n```\n\n"])
|
f"尝试执行Latex指令失败。Latex没有安装, 或者不在环境变量PATH中。安装方法https://tug.org/texlive/。报错信息\n\n```\n\n{trimmed_format_exc()}\n\n```\n\n"])
|
||||||
|
|||||||
249
crazy_functions/Three场景交互3D.py
Normal file
249
crazy_functions/Three场景交互3D.py
Normal file
@ -0,0 +1,249 @@
|
|||||||
|
from toolbox import CatchException, update_ui, gen_time_str
|
||||||
|
from .crazy_utils import request_gpt_model_in_new_thread_with_ui_alive
|
||||||
|
from .crazy_utils import input_clipping
|
||||||
|
|
||||||
|
def inspect_dependency(chatbot, history):
|
||||||
|
# 尝试导入依赖,如果缺少依赖,则给出安装建议
|
||||||
|
try:
|
||||||
|
from VISUALIZE.mcom import mcom
|
||||||
|
return True
|
||||||
|
except:
|
||||||
|
chatbot.append(["导入依赖失败", "使用该模块需要额外依赖,安装方法:```pip install vhmap```"])
|
||||||
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
||||||
|
return False
|
||||||
|
|
||||||
|
def get_code_block(reply):
|
||||||
|
try:
|
||||||
|
import json
|
||||||
|
json.loads(reply)
|
||||||
|
return reply
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
import re
|
||||||
|
pattern = r"```([\s\S]*?)```" # regex pattern to match code blocks
|
||||||
|
matches = re.findall(pattern, reply) # find all code blocks in text
|
||||||
|
res = ""
|
||||||
|
for match in matches:
|
||||||
|
if 'import ' not in match:
|
||||||
|
res = match.strip('python').strip('json')
|
||||||
|
break
|
||||||
|
if len(res) == 0:
|
||||||
|
print(reply)
|
||||||
|
raise RuntimeError("GPT is not generating proper Json.")
|
||||||
|
return res # code block
|
||||||
|
|
||||||
|
def get_json_blocks(reply):
|
||||||
|
import re, json
|
||||||
|
pattern = r"{([\s\S]*?)}" # regex pattern to match code blocks
|
||||||
|
matches = re.findall(pattern, reply) # find all code blocks in text
|
||||||
|
res = []
|
||||||
|
for match in matches:
|
||||||
|
if '"name"' in match:
|
||||||
|
try:
|
||||||
|
res.append(json.loads("{" + f'{match}' + "}"))
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
return res # code block
|
||||||
|
|
||||||
|
def read_json(code):
|
||||||
|
import json
|
||||||
|
return json.loads(code)
|
||||||
|
|
||||||
|
def parse_partial(vi, gpt_say):
|
||||||
|
# 解析Json
|
||||||
|
js = get_json_blocks(gpt_say)
|
||||||
|
vi.update(js)
|
||||||
|
|
||||||
|
|
||||||
|
@CatchException
|
||||||
|
def 三维生成(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port):
|
||||||
|
"""
|
||||||
|
txt 输入栏用户输入的文本,例如需要翻译的一段话,再例如一个包含了待处理文件的路径
|
||||||
|
llm_kwargs gpt模型参数,如温度和top_p等,一般原样传递下去就行
|
||||||
|
plugin_kwargs 插件模型的参数,暂时没有用武之地
|
||||||
|
chatbot 聊天显示框的句柄,用于显示给用户
|
||||||
|
history 聊天历史,前情提要
|
||||||
|
system_prompt 给gpt的静默提醒
|
||||||
|
web_port 当前软件运行的端口号
|
||||||
|
"""
|
||||||
|
from .vhmap_interact.vhmap import vhmp_interface
|
||||||
|
vi = vhmp_interface()
|
||||||
|
# 基本信息:功能、贡献者
|
||||||
|
chatbot.append([
|
||||||
|
"函数插件功能?",
|
||||||
|
"生成3D, 此插件处于开发阶段, 建议暂时不要使用, 作者: binary-husky, 插件初始化中 ..."
|
||||||
|
])
|
||||||
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
||||||
|
|
||||||
|
# 尝试导入依赖, 如果缺少依赖, 则给出安装建议
|
||||||
|
dep_ok = yield from inspect_dependency(chatbot=chatbot, history=history) # 刷新界面
|
||||||
|
if not dep_ok: return
|
||||||
|
|
||||||
|
# 输入
|
||||||
|
i_say = prompt(txt)
|
||||||
|
# 开始
|
||||||
|
gpt_say = yield from request_gpt_model_in_new_thread_with_ui_alive(
|
||||||
|
inputs=i_say, inputs_show_user=i_say,
|
||||||
|
llm_kwargs=llm_kwargs, chatbot=chatbot, history=[],
|
||||||
|
sys_prompt=r"You are a Json generator",
|
||||||
|
on_reply_update=lambda t:parse_partial(vi, t)
|
||||||
|
)
|
||||||
|
chatbot.append(["开始生成执行", "..."])
|
||||||
|
history.extend([i_say, gpt_say])
|
||||||
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 # 界面更新
|
||||||
|
|
||||||
|
# 解析Json
|
||||||
|
code = get_code_block(gpt_say)
|
||||||
|
js = read_json(code)
|
||||||
|
vi.update(js)
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
def prompt(text):
|
||||||
|
return r"""
|
||||||
|
> Requirements:
|
||||||
|
1. You can only use square Boxes to build cubes and walls.
|
||||||
|
2. The space you can work in is a sphere with origin (0,0,0) and radius 100.
|
||||||
|
3. The ground is z=0.
|
||||||
|
4. You can only use 100 boxes.
|
||||||
|
5. Format of each box is json, e.g.
|
||||||
|
{
|
||||||
|
"name": "Box-1",
|
||||||
|
"geometry": "box", // choose from "box", "octahedron", "sphere", "cylinder"
|
||||||
|
"size": 1.0,
|
||||||
|
"color": "rgb(255,165,0)",
|
||||||
|
"location_x": 1.0,
|
||||||
|
"location_y": 0.0,
|
||||||
|
"location_z": 0.0
|
||||||
|
},
|
||||||
|
6. Only produce json as output. Use markdown code block to wrap the json output.
|
||||||
|
|
||||||
|
> Example:
|
||||||
|
User: Generate 4 different objects around the origin.
|
||||||
|
You:
|
||||||
|
```
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"name": "Box-1",
|
||||||
|
"size": 1.0,
|
||||||
|
"geometry": "box",
|
||||||
|
"color": "rgb(255,11,10)",
|
||||||
|
"location_x": 1.0,
|
||||||
|
"location_y": 0.0,
|
||||||
|
"location_z": 0.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Box-2",
|
||||||
|
"size": 1.0,
|
||||||
|
"geometry": "octahedron",
|
||||||
|
"color": "rgb(255,11,10)",
|
||||||
|
"location_x": -1.0,
|
||||||
|
"location_y": 0.0,
|
||||||
|
"location_z": 0.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Box-3",
|
||||||
|
"size": 1.0,
|
||||||
|
"geometry": "sphere",
|
||||||
|
"color": "rgb(255,11,10)",
|
||||||
|
"location_x": 0.0,
|
||||||
|
"location_y": 1.0,
|
||||||
|
"location_z": 0.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Box-4",
|
||||||
|
"size": 1.0,
|
||||||
|
"geometry": "cylinder",
|
||||||
|
"color": "rgb(255,11,10)",
|
||||||
|
"location_x": 0.0,
|
||||||
|
"location_y": -1.0,
|
||||||
|
"location_z": 0.0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
> User: """ + text
|
||||||
|
|
||||||
|
"""
|
||||||
|
Please construct a 3D environment where a girl is sitting under a tree in a garden.
|
||||||
|
|
||||||
|
Requirements:
|
||||||
|
1. List objects in this scene and make a markdown list.
|
||||||
|
2. The list must contain creative details, give at least 20 objects
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
"""
|
||||||
|
Convert the result to json,
|
||||||
|
Requirements:
|
||||||
|
1. Format: [
|
||||||
|
{
|
||||||
|
"name": "object-1",
|
||||||
|
"location": [position_x, position_y, position_z]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
2. Generate relative position of objects
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
"""
|
||||||
|
> Requirements:
|
||||||
|
1. You can use box, octahedron, sphere, cylinder to build objects.
|
||||||
|
2. The ground is z=0.
|
||||||
|
3. You can only use 100 boxes.
|
||||||
|
4. Format of each box is json, e.g.
|
||||||
|
{
|
||||||
|
"name": "Box-1",
|
||||||
|
"geometry": "box", // choose from "box", "octahedron", "sphere", "cylinder"
|
||||||
|
"size": 1.0,
|
||||||
|
"color": "rgb(255,165,0)",
|
||||||
|
"location_x": 1.0,
|
||||||
|
"location_y": 0.0,
|
||||||
|
"location_z": 0.0
|
||||||
|
},
|
||||||
|
5. Only produce json as output. Use markdown code block to wrap the json output.
|
||||||
|
|
||||||
|
> Example:
|
||||||
|
```
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"name": "Box-1",
|
||||||
|
"size": 1.0,
|
||||||
|
"geometry": "box",
|
||||||
|
"color": "rgb(255,11,10)",
|
||||||
|
"location_x": 1.0,
|
||||||
|
"location_y": 0.0,
|
||||||
|
"location_z": 0.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Box-2",
|
||||||
|
"size": 1.0,
|
||||||
|
"geometry": "octahedron",
|
||||||
|
"color": "rgb(255,11,10)",
|
||||||
|
"location_x": -1.0,
|
||||||
|
"location_y": 0.0,
|
||||||
|
"location_z": 0.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Box-3",
|
||||||
|
"size": 1.0,
|
||||||
|
"geometry": "sphere",
|
||||||
|
"color": "rgb(255,11,10)",
|
||||||
|
"location_x": 0.0,
|
||||||
|
"location_y": 1.0,
|
||||||
|
"location_z": 0.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Box-4",
|
||||||
|
"size": 1.0,
|
||||||
|
"geometry": "cylinder",
|
||||||
|
"color": "rgb(255,11,10)",
|
||||||
|
"location_x": 0.0,
|
||||||
|
"location_y": -1.0,
|
||||||
|
"location_z": 0.0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
"""
|
||||||
@ -17,7 +17,7 @@ validate_path() # validate path so you can run from base directory
|
|||||||
# ==============================================================================================================================
|
# ==============================================================================================================================
|
||||||
|
|
||||||
from colorful import *
|
from colorful import *
|
||||||
from toolbox import get_conf, ChatBotWithCookies
|
from toolbox import get_conf, ChatBotWithCookies, load_chat_cookies
|
||||||
import contextlib
|
import contextlib
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
@ -32,6 +32,7 @@ llm_kwargs = {
|
|||||||
'max_length': None,
|
'max_length': None,
|
||||||
'temperature':1.0,
|
'temperature':1.0,
|
||||||
}
|
}
|
||||||
|
llm_kwargs.update(load_chat_cookies())
|
||||||
plugin_kwargs = { }
|
plugin_kwargs = { }
|
||||||
chatbot = ChatBotWithCookies(llm_kwargs)
|
chatbot = ChatBotWithCookies(llm_kwargs)
|
||||||
history = []
|
history = []
|
||||||
@ -195,12 +196,9 @@ def test_Latex():
|
|||||||
# txt = r"https://arxiv.org/abs/2303.08774"
|
# txt = r"https://arxiv.org/abs/2303.08774"
|
||||||
# txt = r"https://arxiv.org/abs/2303.12712"
|
# txt = r"https://arxiv.org/abs/2303.12712"
|
||||||
# txt = r"C:\Users\fuqingxu\arxiv_cache\2303.12712\workfolder"
|
# txt = r"C:\Users\fuqingxu\arxiv_cache\2303.12712\workfolder"
|
||||||
# txt = r"2306.17157" # 这个paper有个input命令文件名大小写错误!
|
txt = r"2306.17157" # 这个paper有个input命令文件名大小写错误!
|
||||||
# txt = "https://arxiv.org/abs/2205.14135"
|
|
||||||
# txt = r"C:\Users\fuqingxu\arxiv_cache\2205.14135\workfolder"
|
|
||||||
# txt = r"C:\Users\fuqingxu\arxiv_cache\2205.14135\workfolder"
|
|
||||||
txt = r"2210.03629"
|
|
||||||
txt = r"2307.04964"
|
|
||||||
for cookies, cb, hist, msg in (Latex翻译中文并重新编译PDF)(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port):
|
for cookies, cb, hist, msg in (Latex翻译中文并重新编译PDF)(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port):
|
||||||
cli_printer.print(cb) # print(cb)
|
cli_printer.print(cb) # print(cb)
|
||||||
|
|
||||||
@ -229,6 +227,15 @@ def test_chatglm_finetune():
|
|||||||
cli_printer.print(cb)
|
cli_printer.print(cb)
|
||||||
|
|
||||||
|
|
||||||
|
def 三维生成():
|
||||||
|
from crazy_functions.Three场景交互3D import 三维生成
|
||||||
|
txt = "Generate 10 boxes to form a triangle formation with random color."
|
||||||
|
plugin_kwargs = {"advanced_arg":""}
|
||||||
|
|
||||||
|
for cookies, cb, hist, msg in (三维生成)(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port):
|
||||||
|
cli_printer.print(cb)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
# test_解析一个Python项目()
|
# test_解析一个Python项目()
|
||||||
# test_Latex英文润色()
|
# test_Latex英文润色()
|
||||||
@ -243,7 +250,7 @@ if __name__ == "__main__":
|
|||||||
# test_数学动画生成manim()
|
# test_数学动画生成manim()
|
||||||
# test_Langchain知识库()
|
# test_Langchain知识库()
|
||||||
# test_Langchain知识库读取()
|
# test_Langchain知识库读取()
|
||||||
test_Latex()
|
# test_Latex()
|
||||||
# test_chatglm_finetune()
|
三维生成()
|
||||||
input("程序完成,回车退出。")
|
input("程序完成,回车退出。")
|
||||||
print("退出。")
|
print("退出。")
|
||||||
@ -40,6 +40,7 @@ def request_gpt_model_in_new_thread_with_ui_alive(
|
|||||||
chatbot, history, sys_prompt, refresh_interval=0.2,
|
chatbot, history, sys_prompt, refresh_interval=0.2,
|
||||||
handle_token_exceed=True,
|
handle_token_exceed=True,
|
||||||
retry_times_at_unknown_error=2,
|
retry_times_at_unknown_error=2,
|
||||||
|
on_reply_update=None
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
Request GPT model,请求GPT模型同时维持用户界面活跃。
|
Request GPT model,请求GPT模型同时维持用户界面活跃。
|
||||||
@ -123,6 +124,7 @@ def request_gpt_model_in_new_thread_with_ui_alive(
|
|||||||
if future.done():
|
if future.done():
|
||||||
break
|
break
|
||||||
chatbot[-1] = [chatbot[-1][0], mutable[0]]
|
chatbot[-1] = [chatbot[-1][0], mutable[0]]
|
||||||
|
if on_reply_update: on_reply_update(mutable[0])
|
||||||
yield from update_ui(chatbot=chatbot, history=[]) # 刷新界面
|
yield from update_ui(chatbot=chatbot, history=[]) # 刷新界面
|
||||||
|
|
||||||
final_result = future.result()
|
final_result = future.result()
|
||||||
|
|||||||
@ -1,456 +0,0 @@
|
|||||||
import os, shutil
|
|
||||||
import re
|
|
||||||
import numpy as np
|
|
||||||
PRESERVE = 0
|
|
||||||
TRANSFORM = 1
|
|
||||||
|
|
||||||
pj = os.path.join
|
|
||||||
|
|
||||||
class LinkedListNode():
|
|
||||||
"""
|
|
||||||
Linked List Node
|
|
||||||
"""
|
|
||||||
def __init__(self, string, preserve=True) -> None:
|
|
||||||
self.string = string
|
|
||||||
self.preserve = preserve
|
|
||||||
self.next = None
|
|
||||||
self.range = None
|
|
||||||
# self.begin_line = 0
|
|
||||||
# self.begin_char = 0
|
|
||||||
|
|
||||||
def convert_to_linklist(text, mask):
|
|
||||||
root = LinkedListNode("", preserve=True)
|
|
||||||
current_node = root
|
|
||||||
for c, m, i in zip(text, mask, range(len(text))):
|
|
||||||
if (m==PRESERVE and current_node.preserve) \
|
|
||||||
or (m==TRANSFORM and not current_node.preserve):
|
|
||||||
# add
|
|
||||||
current_node.string += c
|
|
||||||
else:
|
|
||||||
current_node.next = LinkedListNode(c, preserve=(m==PRESERVE))
|
|
||||||
current_node = current_node.next
|
|
||||||
return root
|
|
||||||
|
|
||||||
def post_process(root):
|
|
||||||
# 修复括号
|
|
||||||
node = root
|
|
||||||
while True:
|
|
||||||
string = node.string
|
|
||||||
if node.preserve:
|
|
||||||
node = node.next
|
|
||||||
if node is None: break
|
|
||||||
continue
|
|
||||||
def break_check(string):
|
|
||||||
str_stack = [""] # (lv, index)
|
|
||||||
for i, c in enumerate(string):
|
|
||||||
if c == '{':
|
|
||||||
str_stack.append('{')
|
|
||||||
elif c == '}':
|
|
||||||
if len(str_stack) == 1:
|
|
||||||
print('stack fix')
|
|
||||||
return i
|
|
||||||
str_stack.pop(-1)
|
|
||||||
else:
|
|
||||||
str_stack[-1] += c
|
|
||||||
return -1
|
|
||||||
bp = break_check(string)
|
|
||||||
|
|
||||||
if bp == -1:
|
|
||||||
pass
|
|
||||||
elif bp == 0:
|
|
||||||
node.string = string[:1]
|
|
||||||
q = LinkedListNode(string[1:], False)
|
|
||||||
q.next = node.next
|
|
||||||
node.next = q
|
|
||||||
else:
|
|
||||||
node.string = string[:bp]
|
|
||||||
q = LinkedListNode(string[bp:], False)
|
|
||||||
q.next = node.next
|
|
||||||
node.next = q
|
|
||||||
|
|
||||||
node = node.next
|
|
||||||
if node is None: break
|
|
||||||
|
|
||||||
# 屏蔽空行和太短的句子
|
|
||||||
node = root
|
|
||||||
while True:
|
|
||||||
if len(node.string.strip('\n').strip(''))==0: node.preserve = True
|
|
||||||
if len(node.string.strip('\n').strip(''))<42: node.preserve = True
|
|
||||||
node = node.next
|
|
||||||
if node is None: break
|
|
||||||
node = root
|
|
||||||
while True:
|
|
||||||
if node.next and node.preserve and node.next.preserve:
|
|
||||||
node.string += node.next.string
|
|
||||||
node.next = node.next.next
|
|
||||||
node = node.next
|
|
||||||
if node is None: break
|
|
||||||
|
|
||||||
# 将前后断行符脱离
|
|
||||||
node = root
|
|
||||||
prev_node = None
|
|
||||||
while True:
|
|
||||||
if not node.preserve:
|
|
||||||
lstriped_ = node.string.lstrip().lstrip('\n')
|
|
||||||
if (prev_node is not None) and (prev_node.preserve) and (len(lstriped_)!=len(node.string)):
|
|
||||||
prev_node.string += node.string[:-len(lstriped_)]
|
|
||||||
node.string = lstriped_
|
|
||||||
rstriped_ = node.string.rstrip().rstrip('\n')
|
|
||||||
if (node.next is not None) and (node.next.preserve) and (len(rstriped_)!=len(node.string)):
|
|
||||||
node.next.string = node.string[len(rstriped_):] + node.next.string
|
|
||||||
node.string = rstriped_
|
|
||||||
# =====
|
|
||||||
prev_node = node
|
|
||||||
node = node.next
|
|
||||||
if node is None: break
|
|
||||||
|
|
||||||
# 标注节点的行数范围
|
|
||||||
node = root
|
|
||||||
n_line = 0
|
|
||||||
expansion = 2
|
|
||||||
while True:
|
|
||||||
n_l = node.string.count('\n')
|
|
||||||
node.range = [n_line-expansion, n_line+n_l+expansion] # 失败时,扭转的范围
|
|
||||||
n_line = n_line+n_l
|
|
||||||
node = node.next
|
|
||||||
if node is None: break
|
|
||||||
return root
|
|
||||||
|
|
||||||
|
|
||||||
"""
|
|
||||||
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
|
||||||
Latex segmentation with a binary mask (PRESERVE=0, TRANSFORM=1)
|
|
||||||
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
def set_forbidden_text(text, mask, pattern, flags=0):
|
|
||||||
"""
|
|
||||||
Add a preserve text area in this paper
|
|
||||||
e.g. with pattern = r"\\begin\{algorithm\}(.*?)\\end\{algorithm\}"
|
|
||||||
you can mask out (mask = PRESERVE so that text become untouchable for GPT)
|
|
||||||
everything between "\begin{equation}" and "\end{equation}"
|
|
||||||
"""
|
|
||||||
if isinstance(pattern, list): pattern = '|'.join(pattern)
|
|
||||||
pattern_compile = re.compile(pattern, flags)
|
|
||||||
for res in pattern_compile.finditer(text):
|
|
||||||
mask[res.span()[0]:res.span()[1]] = PRESERVE
|
|
||||||
return text, mask
|
|
||||||
|
|
||||||
def reverse_forbidden_text(text, mask, pattern, flags=0, forbid_wrapper=True):
|
|
||||||
"""
|
|
||||||
Move area out of preserve area (make text editable for GPT)
|
|
||||||
count the number of the braces so as to catch compelete text area.
|
|
||||||
e.g.
|
|
||||||
\begin{abstract} blablablablablabla. \end{abstract}
|
|
||||||
"""
|
|
||||||
if isinstance(pattern, list): pattern = '|'.join(pattern)
|
|
||||||
pattern_compile = re.compile(pattern, flags)
|
|
||||||
for res in pattern_compile.finditer(text):
|
|
||||||
if not forbid_wrapper:
|
|
||||||
mask[res.span()[0]:res.span()[1]] = TRANSFORM
|
|
||||||
else:
|
|
||||||
mask[res.regs[0][0]: res.regs[1][0]] = PRESERVE # '\\begin{abstract}'
|
|
||||||
mask[res.regs[1][0]: res.regs[1][1]] = TRANSFORM # abstract
|
|
||||||
mask[res.regs[1][1]: res.regs[0][1]] = PRESERVE # abstract
|
|
||||||
return text, mask
|
|
||||||
|
|
||||||
def set_forbidden_text_careful_brace(text, mask, pattern, flags=0):
|
|
||||||
"""
|
|
||||||
Add a preserve text area in this paper (text become untouchable for GPT).
|
|
||||||
count the number of the braces so as to catch compelete text area.
|
|
||||||
e.g.
|
|
||||||
\caption{blablablablabla\texbf{blablabla}blablabla.}
|
|
||||||
"""
|
|
||||||
pattern_compile = re.compile(pattern, flags)
|
|
||||||
for res in pattern_compile.finditer(text):
|
|
||||||
brace_level = -1
|
|
||||||
p = begin = end = res.regs[0][0]
|
|
||||||
for _ in range(1024*16):
|
|
||||||
if text[p] == '}' and brace_level == 0: break
|
|
||||||
elif text[p] == '}': brace_level -= 1
|
|
||||||
elif text[p] == '{': brace_level += 1
|
|
||||||
p += 1
|
|
||||||
end = p+1
|
|
||||||
mask[begin:end] = PRESERVE
|
|
||||||
return text, mask
|
|
||||||
|
|
||||||
def reverse_forbidden_text_careful_brace(text, mask, pattern, flags=0, forbid_wrapper=True):
|
|
||||||
"""
|
|
||||||
Move area out of preserve area (make text editable for GPT)
|
|
||||||
count the number of the braces so as to catch compelete text area.
|
|
||||||
e.g.
|
|
||||||
\caption{blablablablabla\texbf{blablabla}blablabla.}
|
|
||||||
"""
|
|
||||||
pattern_compile = re.compile(pattern, flags)
|
|
||||||
for res in pattern_compile.finditer(text):
|
|
||||||
brace_level = 0
|
|
||||||
p = begin = end = res.regs[1][0]
|
|
||||||
for _ in range(1024*16):
|
|
||||||
if text[p] == '}' and brace_level == 0: break
|
|
||||||
elif text[p] == '}': brace_level -= 1
|
|
||||||
elif text[p] == '{': brace_level += 1
|
|
||||||
p += 1
|
|
||||||
end = p
|
|
||||||
mask[begin:end] = TRANSFORM
|
|
||||||
if forbid_wrapper:
|
|
||||||
mask[res.regs[0][0]:begin] = PRESERVE
|
|
||||||
mask[end:res.regs[0][1]] = PRESERVE
|
|
||||||
return text, mask
|
|
||||||
|
|
||||||
def set_forbidden_text_begin_end(text, mask, pattern, flags=0, limit_n_lines=42):
|
|
||||||
"""
|
|
||||||
Find all \begin{} ... \end{} text block that with less than limit_n_lines lines.
|
|
||||||
Add it to preserve area
|
|
||||||
"""
|
|
||||||
pattern_compile = re.compile(pattern, flags)
|
|
||||||
def search_with_line_limit(text, mask):
|
|
||||||
for res in pattern_compile.finditer(text):
|
|
||||||
cmd = res.group(1) # begin{what}
|
|
||||||
this = res.group(2) # content between begin and end
|
|
||||||
this_mask = mask[res.regs[2][0]:res.regs[2][1]]
|
|
||||||
white_list = ['document', 'abstract', 'lemma', 'definition', 'sproof',
|
|
||||||
'em', 'emph', 'textit', 'textbf', 'itemize', 'enumerate']
|
|
||||||
if (cmd in white_list) or this.count('\n') >= limit_n_lines: # use a magical number 42
|
|
||||||
this, this_mask = search_with_line_limit(this, this_mask)
|
|
||||||
mask[res.regs[2][0]:res.regs[2][1]] = this_mask
|
|
||||||
else:
|
|
||||||
mask[res.regs[0][0]:res.regs[0][1]] = PRESERVE
|
|
||||||
return text, mask
|
|
||||||
return search_with_line_limit(text, mask)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
"""
|
|
||||||
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
|
||||||
Latex Merge File
|
|
||||||
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
|
||||||
"""
|
|
||||||
|
|
||||||
def find_main_tex_file(file_manifest, mode):
|
|
||||||
"""
|
|
||||||
在多Tex文档中,寻找主文件,必须包含documentclass,返回找到的第一个。
|
|
||||||
P.S. 但愿没人把latex模板放在里面传进来 (6.25 加入判定latex模板的代码)
|
|
||||||
"""
|
|
||||||
canidates = []
|
|
||||||
for texf in file_manifest:
|
|
||||||
if os.path.basename(texf).startswith('merge'):
|
|
||||||
continue
|
|
||||||
with open(texf, 'r', encoding='utf8', errors='ignore') as f:
|
|
||||||
file_content = f.read()
|
|
||||||
if r'\documentclass' in file_content:
|
|
||||||
canidates.append(texf)
|
|
||||||
else:
|
|
||||||
continue
|
|
||||||
|
|
||||||
if len(canidates) == 0:
|
|
||||||
raise RuntimeError('无法找到一个主Tex文件(包含documentclass关键字)')
|
|
||||||
elif len(canidates) == 1:
|
|
||||||
return canidates[0]
|
|
||||||
else: # if len(canidates) >= 2 通过一些Latex模板中常见(但通常不会出现在正文)的单词,对不同latex源文件扣分,取评分最高者返回
|
|
||||||
canidates_score = []
|
|
||||||
# 给出一些判定模板文档的词作为扣分项
|
|
||||||
unexpected_words = ['\LaTeX', 'manuscript', 'Guidelines', 'font', 'citations', 'rejected', 'blind review', 'reviewers']
|
|
||||||
expected_words = ['\input', '\ref', '\cite']
|
|
||||||
for texf in canidates:
|
|
||||||
canidates_score.append(0)
|
|
||||||
with open(texf, 'r', encoding='utf8', errors='ignore') as f:
|
|
||||||
file_content = f.read()
|
|
||||||
for uw in unexpected_words:
|
|
||||||
if uw in file_content:
|
|
||||||
canidates_score[-1] -= 1
|
|
||||||
for uw in expected_words:
|
|
||||||
if uw in file_content:
|
|
||||||
canidates_score[-1] += 1
|
|
||||||
select = np.argmax(canidates_score) # 取评分最高者返回
|
|
||||||
return canidates[select]
|
|
||||||
|
|
||||||
def rm_comments(main_file):
|
|
||||||
new_file_remove_comment_lines = []
|
|
||||||
for l in main_file.splitlines():
|
|
||||||
# 删除整行的空注释
|
|
||||||
if l.lstrip().startswith("%"):
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
new_file_remove_comment_lines.append(l)
|
|
||||||
main_file = '\n'.join(new_file_remove_comment_lines)
|
|
||||||
# main_file = re.sub(r"\\include{(.*?)}", r"\\input{\1}", main_file) # 将 \include 命令转换为 \input 命令
|
|
||||||
main_file = re.sub(r'(?<!\\)%.*', '', main_file) # 使用正则表达式查找半行注释, 并替换为空字符串
|
|
||||||
return main_file
|
|
||||||
|
|
||||||
def find_tex_file_ignore_case(fp):
|
|
||||||
dir_name = os.path.dirname(fp)
|
|
||||||
base_name = os.path.basename(fp)
|
|
||||||
if not base_name.endswith('.tex'): base_name+='.tex'
|
|
||||||
if os.path.exists(pj(dir_name, base_name)): return pj(dir_name, base_name)
|
|
||||||
# go case in-sensitive
|
|
||||||
import glob
|
|
||||||
for f in glob.glob(dir_name+'/*.tex'):
|
|
||||||
base_name_s = os.path.basename(fp)
|
|
||||||
if base_name_s.lower() == base_name.lower(): return f
|
|
||||||
return None
|
|
||||||
|
|
||||||
def merge_tex_files_(project_foler, main_file, mode):
|
|
||||||
"""
|
|
||||||
Merge Tex project recrusively
|
|
||||||
"""
|
|
||||||
main_file = rm_comments(main_file)
|
|
||||||
for s in reversed([q for q in re.finditer(r"\\input\{(.*?)\}", main_file, re.M)]):
|
|
||||||
f = s.group(1)
|
|
||||||
fp = os.path.join(project_foler, f)
|
|
||||||
fp = find_tex_file_ignore_case(fp)
|
|
||||||
if fp:
|
|
||||||
with open(fp, 'r', encoding='utf-8', errors='replace') as fx: c = fx.read()
|
|
||||||
else:
|
|
||||||
raise RuntimeError(f'找不到{fp},Tex源文件缺失!')
|
|
||||||
c = merge_tex_files_(project_foler, c, mode)
|
|
||||||
main_file = main_file[:s.span()[0]] + c + main_file[s.span()[1]:]
|
|
||||||
return main_file
|
|
||||||
|
|
||||||
def merge_tex_files(project_foler, main_file, mode):
|
|
||||||
"""
|
|
||||||
Merge Tex project recrusively
|
|
||||||
P.S. 顺便把CTEX塞进去以支持中文
|
|
||||||
P.S. 顺便把Latex的注释去除
|
|
||||||
"""
|
|
||||||
main_file = merge_tex_files_(project_foler, main_file, mode)
|
|
||||||
main_file = rm_comments(main_file)
|
|
||||||
|
|
||||||
if mode == 'translate_zh':
|
|
||||||
# find paper documentclass
|
|
||||||
pattern = re.compile(r'\\documentclass.*\n')
|
|
||||||
match = pattern.search(main_file)
|
|
||||||
assert match is not None, "Cannot find documentclass statement!"
|
|
||||||
position = match.end()
|
|
||||||
add_ctex = '\\usepackage{ctex}\n'
|
|
||||||
add_url = '\\usepackage{url}\n' if '{url}' not in main_file else ''
|
|
||||||
main_file = main_file[:position] + add_ctex + add_url + main_file[position:]
|
|
||||||
# fontset=windows
|
|
||||||
import platform
|
|
||||||
main_file = re.sub(r"\\documentclass\[(.*?)\]{(.*?)}", r"\\documentclass[\1,fontset=windows,UTF8]{\2}",main_file)
|
|
||||||
main_file = re.sub(r"\\documentclass{(.*?)}", r"\\documentclass[fontset=windows,UTF8]{\1}",main_file)
|
|
||||||
# find paper abstract
|
|
||||||
pattern_opt1 = re.compile(r'\\begin\{abstract\}.*\n')
|
|
||||||
pattern_opt2 = re.compile(r"\\abstract\{(.*?)\}", flags=re.DOTALL)
|
|
||||||
match_opt1 = pattern_opt1.search(main_file)
|
|
||||||
match_opt2 = pattern_opt2.search(main_file)
|
|
||||||
assert (match_opt1 is not None) or (match_opt2 is not None), "Cannot find paper abstract section!"
|
|
||||||
return main_file
|
|
||||||
|
|
||||||
|
|
||||||
"""
|
|
||||||
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
|
||||||
Post process
|
|
||||||
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
|
||||||
"""
|
|
||||||
def mod_inbraket(match):
|
|
||||||
"""
|
|
||||||
为啥chatgpt会把cite里面的逗号换成中文逗号呀
|
|
||||||
"""
|
|
||||||
# get the matched string
|
|
||||||
cmd = match.group(1)
|
|
||||||
str_to_modify = match.group(2)
|
|
||||||
# modify the matched string
|
|
||||||
str_to_modify = str_to_modify.replace(':', ':') # 前面是中文冒号,后面是英文冒号
|
|
||||||
str_to_modify = str_to_modify.replace(',', ',') # 前面是中文逗号,后面是英文逗号
|
|
||||||
# str_to_modify = 'BOOM'
|
|
||||||
return "\\" + cmd + "{" + str_to_modify + "}"
|
|
||||||
|
|
||||||
def fix_content(final_tex, node_string):
|
|
||||||
"""
|
|
||||||
Fix common GPT errors to increase success rate
|
|
||||||
"""
|
|
||||||
final_tex = re.sub(r"(?<!\\)%", "\\%", final_tex)
|
|
||||||
final_tex = re.sub(r"\\([a-z]{2,10})\ \{", r"\\\1{", string=final_tex)
|
|
||||||
final_tex = re.sub(r"\\\ ([a-z]{2,10})\{", r"\\\1{", string=final_tex)
|
|
||||||
final_tex = re.sub(r"\\([a-z]{2,10})\{([^\}]*?)\}", mod_inbraket, string=final_tex)
|
|
||||||
|
|
||||||
if "Traceback" in final_tex and "[Local Message]" in final_tex:
|
|
||||||
final_tex = node_string # 出问题了,还原原文
|
|
||||||
if node_string.count('\\begin') != final_tex.count('\\begin'):
|
|
||||||
final_tex = node_string # 出问题了,还原原文
|
|
||||||
if node_string.count('\_') > 0 and node_string.count('\_') > final_tex.count('\_'):
|
|
||||||
# walk and replace any _ without \
|
|
||||||
final_tex = re.sub(r"(?<!\\)_", "\\_", final_tex)
|
|
||||||
|
|
||||||
def compute_brace_level(string):
|
|
||||||
# this function count the number of { and }
|
|
||||||
brace_level = 0
|
|
||||||
for c in string:
|
|
||||||
if c == "{": brace_level += 1
|
|
||||||
elif c == "}": brace_level -= 1
|
|
||||||
return brace_level
|
|
||||||
def join_most(tex_t, tex_o):
|
|
||||||
# this function join translated string and original string when something goes wrong
|
|
||||||
p_t = 0
|
|
||||||
p_o = 0
|
|
||||||
def find_next(string, chars, begin):
|
|
||||||
p = begin
|
|
||||||
while p < len(string):
|
|
||||||
if string[p] in chars: return p, string[p]
|
|
||||||
p += 1
|
|
||||||
return None, None
|
|
||||||
while True:
|
|
||||||
res1, char = find_next(tex_o, ['{','}'], p_o)
|
|
||||||
if res1 is None: break
|
|
||||||
res2, char = find_next(tex_t, [char], p_t)
|
|
||||||
if res2 is None: break
|
|
||||||
p_o = res1 + 1
|
|
||||||
p_t = res2 + 1
|
|
||||||
return tex_t[:p_t] + tex_o[p_o:]
|
|
||||||
|
|
||||||
if compute_brace_level(final_tex) != compute_brace_level(node_string):
|
|
||||||
# 出问题了,还原部分原文,保证括号正确
|
|
||||||
final_tex = join_most(final_tex, node_string)
|
|
||||||
return final_tex
|
|
||||||
|
|
||||||
def compile_latex_with_timeout(command, cwd, timeout=60):
|
|
||||||
import subprocess
|
|
||||||
process = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=cwd)
|
|
||||||
try:
|
|
||||||
stdout, stderr = process.communicate(timeout=timeout)
|
|
||||||
except subprocess.TimeoutExpired:
|
|
||||||
process.kill()
|
|
||||||
stdout, stderr = process.communicate()
|
|
||||||
print("Process timed out!")
|
|
||||||
return False
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def merge_pdfs(pdf1_path, pdf2_path, output_path):
|
|
||||||
import PyPDF2
|
|
||||||
Percent = 0.8
|
|
||||||
# Open the first PDF file
|
|
||||||
with open(pdf1_path, 'rb') as pdf1_file:
|
|
||||||
pdf1_reader = PyPDF2.PdfFileReader(pdf1_file)
|
|
||||||
# Open the second PDF file
|
|
||||||
with open(pdf2_path, 'rb') as pdf2_file:
|
|
||||||
pdf2_reader = PyPDF2.PdfFileReader(pdf2_file)
|
|
||||||
# Create a new PDF file to store the merged pages
|
|
||||||
output_writer = PyPDF2.PdfFileWriter()
|
|
||||||
# Determine the number of pages in each PDF file
|
|
||||||
num_pages = max(pdf1_reader.numPages, pdf2_reader.numPages)
|
|
||||||
# Merge the pages from the two PDF files
|
|
||||||
for page_num in range(num_pages):
|
|
||||||
# Add the page from the first PDF file
|
|
||||||
if page_num < pdf1_reader.numPages:
|
|
||||||
page1 = pdf1_reader.getPage(page_num)
|
|
||||||
else:
|
|
||||||
page1 = PyPDF2.PageObject.createBlankPage(pdf1_reader)
|
|
||||||
# Add the page from the second PDF file
|
|
||||||
if page_num < pdf2_reader.numPages:
|
|
||||||
page2 = pdf2_reader.getPage(page_num)
|
|
||||||
else:
|
|
||||||
page2 = PyPDF2.PageObject.createBlankPage(pdf1_reader)
|
|
||||||
# Create a new empty page with double width
|
|
||||||
new_page = PyPDF2.PageObject.createBlankPage(
|
|
||||||
width = int(int(page1.mediaBox.getWidth()) + int(page2.mediaBox.getWidth()) * Percent),
|
|
||||||
height = max(page1.mediaBox.getHeight(), page2.mediaBox.getHeight())
|
|
||||||
)
|
|
||||||
new_page.mergeTranslatedPage(page1, 0, 0)
|
|
||||||
new_page.mergeTranslatedPage(page2, int(int(page1.mediaBox.getWidth())-int(page2.mediaBox.getWidth())* (1-Percent)), 0)
|
|
||||||
output_writer.addPage(new_page)
|
|
||||||
# Save the merged PDF file
|
|
||||||
with open(output_path, 'wb') as output_file:
|
|
||||||
output_writer.write(output_file)
|
|
||||||
@ -1,16 +1,320 @@
|
|||||||
from toolbox import update_ui, update_ui_lastest_msg # 刷新Gradio前端界面
|
from toolbox import update_ui, update_ui_lastest_msg # 刷新Gradio前端界面
|
||||||
from toolbox import zip_folder, objdump, objload, promote_file_to_downloadzone
|
from toolbox import zip_folder, objdump, objload, 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
|
|
||||||
|
|
||||||
import os, shutil
|
import os, shutil
|
||||||
import re
|
import re
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
pj = os.path.join
|
pj = os.path.join
|
||||||
|
|
||||||
|
"""
|
||||||
|
========================================================================
|
||||||
|
Part One
|
||||||
|
Latex segmentation with a binary mask (PRESERVE=0, TRANSFORM=1)
|
||||||
|
========================================================================
|
||||||
|
"""
|
||||||
|
PRESERVE = 0
|
||||||
|
TRANSFORM = 1
|
||||||
|
|
||||||
|
def set_forbidden_text(text, mask, pattern, flags=0):
|
||||||
|
"""
|
||||||
|
Add a preserve text area in this paper
|
||||||
|
e.g. with pattern = r"\\begin\{algorithm\}(.*?)\\end\{algorithm\}"
|
||||||
|
you can mask out (mask = PRESERVE so that text become untouchable for GPT)
|
||||||
|
everything between "\begin{equation}" and "\end{equation}"
|
||||||
|
"""
|
||||||
|
if isinstance(pattern, list): pattern = '|'.join(pattern)
|
||||||
|
pattern_compile = re.compile(pattern, flags)
|
||||||
|
for res in pattern_compile.finditer(text):
|
||||||
|
mask[res.span()[0]:res.span()[1]] = PRESERVE
|
||||||
|
return text, mask
|
||||||
|
|
||||||
|
def reverse_forbidden_text(text, mask, pattern, flags=0, forbid_wrapper=True):
|
||||||
|
"""
|
||||||
|
Move area out of preserve area (make text editable for GPT)
|
||||||
|
count the number of the braces so as to catch compelete text area.
|
||||||
|
e.g.
|
||||||
|
\begin{abstract} blablablablablabla. \end{abstract}
|
||||||
|
"""
|
||||||
|
if isinstance(pattern, list): pattern = '|'.join(pattern)
|
||||||
|
pattern_compile = re.compile(pattern, flags)
|
||||||
|
for res in pattern_compile.finditer(text):
|
||||||
|
if not forbid_wrapper:
|
||||||
|
mask[res.span()[0]:res.span()[1]] = TRANSFORM
|
||||||
|
else:
|
||||||
|
mask[res.regs[0][0]: res.regs[1][0]] = PRESERVE # '\\begin{abstract}'
|
||||||
|
mask[res.regs[1][0]: res.regs[1][1]] = TRANSFORM # abstract
|
||||||
|
mask[res.regs[1][1]: res.regs[0][1]] = PRESERVE # abstract
|
||||||
|
return text, mask
|
||||||
|
|
||||||
|
def set_forbidden_text_careful_brace(text, mask, pattern, flags=0):
|
||||||
|
"""
|
||||||
|
Add a preserve text area in this paper (text become untouchable for GPT).
|
||||||
|
count the number of the braces so as to catch compelete text area.
|
||||||
|
e.g.
|
||||||
|
\caption{blablablablabla\texbf{blablabla}blablabla.}
|
||||||
|
"""
|
||||||
|
pattern_compile = re.compile(pattern, flags)
|
||||||
|
for res in pattern_compile.finditer(text):
|
||||||
|
brace_level = -1
|
||||||
|
p = begin = end = res.regs[0][0]
|
||||||
|
for _ in range(1024*16):
|
||||||
|
if text[p] == '}' and brace_level == 0: break
|
||||||
|
elif text[p] == '}': brace_level -= 1
|
||||||
|
elif text[p] == '{': brace_level += 1
|
||||||
|
p += 1
|
||||||
|
end = p+1
|
||||||
|
mask[begin:end] = PRESERVE
|
||||||
|
return text, mask
|
||||||
|
|
||||||
|
def reverse_forbidden_text_careful_brace(text, mask, pattern, flags=0, forbid_wrapper=True):
|
||||||
|
"""
|
||||||
|
Move area out of preserve area (make text editable for GPT)
|
||||||
|
count the number of the braces so as to catch compelete text area.
|
||||||
|
e.g.
|
||||||
|
\caption{blablablablabla\texbf{blablabla}blablabla.}
|
||||||
|
"""
|
||||||
|
pattern_compile = re.compile(pattern, flags)
|
||||||
|
for res in pattern_compile.finditer(text):
|
||||||
|
brace_level = 0
|
||||||
|
p = begin = end = res.regs[1][0]
|
||||||
|
for _ in range(1024*16):
|
||||||
|
if text[p] == '}' and brace_level == 0: break
|
||||||
|
elif text[p] == '}': brace_level -= 1
|
||||||
|
elif text[p] == '{': brace_level += 1
|
||||||
|
p += 1
|
||||||
|
end = p
|
||||||
|
mask[begin:end] = TRANSFORM
|
||||||
|
if forbid_wrapper:
|
||||||
|
mask[res.regs[0][0]:begin] = PRESERVE
|
||||||
|
mask[end:res.regs[0][1]] = PRESERVE
|
||||||
|
return text, mask
|
||||||
|
|
||||||
|
def set_forbidden_text_begin_end(text, mask, pattern, flags=0, limit_n_lines=42):
|
||||||
|
"""
|
||||||
|
Find all \begin{} ... \end{} text block that with less than limit_n_lines lines.
|
||||||
|
Add it to preserve area
|
||||||
|
"""
|
||||||
|
pattern_compile = re.compile(pattern, flags)
|
||||||
|
def search_with_line_limit(text, mask):
|
||||||
|
for res in pattern_compile.finditer(text):
|
||||||
|
cmd = res.group(1) # begin{what}
|
||||||
|
this = res.group(2) # content between begin and end
|
||||||
|
this_mask = mask[res.regs[2][0]:res.regs[2][1]]
|
||||||
|
white_list = ['document', 'abstract', 'lemma', 'definition', 'sproof',
|
||||||
|
'em', 'emph', 'textit', 'textbf', 'itemize', 'enumerate']
|
||||||
|
if (cmd in white_list) or this.count('\n') >= limit_n_lines: # use a magical number 42
|
||||||
|
this, this_mask = search_with_line_limit(this, this_mask)
|
||||||
|
mask[res.regs[2][0]:res.regs[2][1]] = this_mask
|
||||||
|
else:
|
||||||
|
mask[res.regs[0][0]:res.regs[0][1]] = PRESERVE
|
||||||
|
return text, mask
|
||||||
|
return search_with_line_limit(text, mask)
|
||||||
|
|
||||||
|
class LinkedListNode():
|
||||||
|
"""
|
||||||
|
Linked List Node
|
||||||
|
"""
|
||||||
|
def __init__(self, string, preserve=True) -> None:
|
||||||
|
self.string = string
|
||||||
|
self.preserve = preserve
|
||||||
|
self.next = None
|
||||||
|
# self.begin_line = 0
|
||||||
|
# self.begin_char = 0
|
||||||
|
|
||||||
|
def convert_to_linklist(text, mask):
|
||||||
|
root = LinkedListNode("", preserve=True)
|
||||||
|
current_node = root
|
||||||
|
for c, m, i in zip(text, mask, range(len(text))):
|
||||||
|
if (m==PRESERVE and current_node.preserve) \
|
||||||
|
or (m==TRANSFORM and not current_node.preserve):
|
||||||
|
# add
|
||||||
|
current_node.string += c
|
||||||
|
else:
|
||||||
|
current_node.next = LinkedListNode(c, preserve=(m==PRESERVE))
|
||||||
|
current_node = current_node.next
|
||||||
|
return root
|
||||||
|
"""
|
||||||
|
========================================================================
|
||||||
|
Latex Merge File
|
||||||
|
========================================================================
|
||||||
|
"""
|
||||||
|
|
||||||
|
def 寻找Latex主文件(file_manifest, mode):
|
||||||
|
"""
|
||||||
|
在多Tex文档中,寻找主文件,必须包含documentclass,返回找到的第一个。
|
||||||
|
P.S. 但愿没人把latex模板放在里面传进来 (6.25 加入判定latex模板的代码)
|
||||||
|
"""
|
||||||
|
canidates = []
|
||||||
|
for texf in file_manifest:
|
||||||
|
if os.path.basename(texf).startswith('merge'):
|
||||||
|
continue
|
||||||
|
with open(texf, 'r', encoding='utf8', errors='ignore') as f:
|
||||||
|
file_content = f.read()
|
||||||
|
if r'\documentclass' in file_content:
|
||||||
|
canidates.append(texf)
|
||||||
|
else:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if len(canidates) == 0:
|
||||||
|
raise RuntimeError('无法找到一个主Tex文件(包含documentclass关键字)')
|
||||||
|
elif len(canidates) == 1:
|
||||||
|
return canidates[0]
|
||||||
|
else: # if len(canidates) >= 2 通过一些Latex模板中常见(但通常不会出现在正文)的单词,对不同latex源文件扣分,取评分最高者返回
|
||||||
|
canidates_score = []
|
||||||
|
# 给出一些判定模板文档的词作为扣分项
|
||||||
|
unexpected_words = ['\LaTeX', 'manuscript', 'Guidelines', 'font', 'citations', 'rejected', 'blind review', 'reviewers']
|
||||||
|
expected_words = ['\input', '\ref', '\cite']
|
||||||
|
for texf in canidates:
|
||||||
|
canidates_score.append(0)
|
||||||
|
with open(texf, 'r', encoding='utf8', errors='ignore') as f:
|
||||||
|
file_content = f.read()
|
||||||
|
for uw in unexpected_words:
|
||||||
|
if uw in file_content:
|
||||||
|
canidates_score[-1] -= 1
|
||||||
|
for uw in expected_words:
|
||||||
|
if uw in file_content:
|
||||||
|
canidates_score[-1] += 1
|
||||||
|
select = np.argmax(canidates_score) # 取评分最高者返回
|
||||||
|
return canidates[select]
|
||||||
|
|
||||||
|
def rm_comments(main_file):
|
||||||
|
new_file_remove_comment_lines = []
|
||||||
|
for l in main_file.splitlines():
|
||||||
|
# 删除整行的空注释
|
||||||
|
if l.lstrip().startswith("%"):
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
new_file_remove_comment_lines.append(l)
|
||||||
|
main_file = '\n'.join(new_file_remove_comment_lines)
|
||||||
|
# main_file = re.sub(r"\\include{(.*?)}", r"\\input{\1}", main_file) # 将 \include 命令转换为 \input 命令
|
||||||
|
main_file = re.sub(r'(?<!\\)%.*', '', main_file) # 使用正则表达式查找半行注释, 并替换为空字符串
|
||||||
|
return main_file
|
||||||
|
|
||||||
|
def find_tex_file_ignore_case(fp):
|
||||||
|
dir_name = os.path.dirname(fp)
|
||||||
|
base_name = os.path.basename(fp)
|
||||||
|
if not base_name.endswith('.tex'): base_name+='.tex'
|
||||||
|
if os.path.exists(pj(dir_name, base_name)): return pj(dir_name, base_name)
|
||||||
|
# go case in-sensitive
|
||||||
|
import glob
|
||||||
|
for f in glob.glob(dir_name+'/*.tex'):
|
||||||
|
base_name_s = os.path.basename(fp)
|
||||||
|
if base_name_s.lower() == base_name.lower(): return f
|
||||||
|
return None
|
||||||
|
|
||||||
|
def merge_tex_files_(project_foler, main_file, mode):
|
||||||
|
"""
|
||||||
|
Merge Tex project recrusively
|
||||||
|
"""
|
||||||
|
main_file = rm_comments(main_file)
|
||||||
|
for s in reversed([q for q in re.finditer(r"\\input\{(.*?)\}", main_file, re.M)]):
|
||||||
|
f = s.group(1)
|
||||||
|
fp = os.path.join(project_foler, f)
|
||||||
|
fp = find_tex_file_ignore_case(fp)
|
||||||
|
if fp:
|
||||||
|
with open(fp, 'r', encoding='utf-8', errors='replace') as fx: c = fx.read()
|
||||||
|
else:
|
||||||
|
raise RuntimeError(f'找不到{fp},Tex源文件缺失!')
|
||||||
|
c = merge_tex_files_(project_foler, c, mode)
|
||||||
|
main_file = main_file[:s.span()[0]] + c + main_file[s.span()[1]:]
|
||||||
|
return main_file
|
||||||
|
|
||||||
|
def merge_tex_files(project_foler, main_file, mode):
|
||||||
|
"""
|
||||||
|
Merge Tex project recrusively
|
||||||
|
P.S. 顺便把CTEX塞进去以支持中文
|
||||||
|
P.S. 顺便把Latex的注释去除
|
||||||
|
"""
|
||||||
|
main_file = merge_tex_files_(project_foler, main_file, mode)
|
||||||
|
main_file = rm_comments(main_file)
|
||||||
|
|
||||||
|
if mode == 'translate_zh':
|
||||||
|
# find paper documentclass
|
||||||
|
pattern = re.compile(r'\\documentclass.*\n')
|
||||||
|
match = pattern.search(main_file)
|
||||||
|
assert match is not None, "Cannot find documentclass statement!"
|
||||||
|
position = match.end()
|
||||||
|
add_ctex = '\\usepackage{ctex}\n'
|
||||||
|
add_url = '\\usepackage{url}\n' if '{url}' not in main_file else ''
|
||||||
|
main_file = main_file[:position] + add_ctex + add_url + main_file[position:]
|
||||||
|
# fontset=windows
|
||||||
|
import platform
|
||||||
|
main_file = re.sub(r"\\documentclass\[(.*?)\]{(.*?)}", r"\\documentclass[\1,fontset=windows,UTF8]{\2}",main_file)
|
||||||
|
main_file = re.sub(r"\\documentclass{(.*?)}", r"\\documentclass[fontset=windows,UTF8]{\1}",main_file)
|
||||||
|
# find paper abstract
|
||||||
|
pattern_opt1 = re.compile(r'\\begin\{abstract\}.*\n')
|
||||||
|
pattern_opt2 = re.compile(r"\\abstract\{(.*?)\}", flags=re.DOTALL)
|
||||||
|
match_opt1 = pattern_opt1.search(main_file)
|
||||||
|
match_opt2 = pattern_opt2.search(main_file)
|
||||||
|
assert (match_opt1 is not None) or (match_opt2 is not None), "Cannot find paper abstract section!"
|
||||||
|
return main_file
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
"""
|
||||||
|
========================================================================
|
||||||
|
Post process
|
||||||
|
========================================================================
|
||||||
|
"""
|
||||||
|
def mod_inbraket(match):
|
||||||
|
"""
|
||||||
|
为啥chatgpt会把cite里面的逗号换成中文逗号呀
|
||||||
|
"""
|
||||||
|
# get the matched string
|
||||||
|
cmd = match.group(1)
|
||||||
|
str_to_modify = match.group(2)
|
||||||
|
# modify the matched string
|
||||||
|
str_to_modify = str_to_modify.replace(':', ':') # 前面是中文冒号,后面是英文冒号
|
||||||
|
str_to_modify = str_to_modify.replace(',', ',') # 前面是中文逗号,后面是英文逗号
|
||||||
|
# str_to_modify = 'BOOM'
|
||||||
|
return "\\" + cmd + "{" + str_to_modify + "}"
|
||||||
|
|
||||||
|
def fix_content(final_tex, node_string):
|
||||||
|
"""
|
||||||
|
Fix common GPT errors to increase success rate
|
||||||
|
"""
|
||||||
|
final_tex = re.sub(r"(?<!\\)%", "\\%", final_tex)
|
||||||
|
final_tex = re.sub(r"\\([a-z]{2,10})\ \{", r"\\\1{", string=final_tex)
|
||||||
|
final_tex = re.sub(r"\\\ ([a-z]{2,10})\{", r"\\\1{", string=final_tex)
|
||||||
|
final_tex = re.sub(r"\\([a-z]{2,10})\{([^\}]*?)\}", mod_inbraket, string=final_tex)
|
||||||
|
|
||||||
|
if "Traceback" in final_tex and "[Local Message]" in final_tex:
|
||||||
|
final_tex = node_string # 出问题了,还原原文
|
||||||
|
if node_string.count('\\begin') != final_tex.count('\\begin'):
|
||||||
|
final_tex = node_string # 出问题了,还原原文
|
||||||
|
if node_string.count('\_') > 0 and node_string.count('\_') > final_tex.count('\_'):
|
||||||
|
# walk and replace any _ without \
|
||||||
|
final_tex = re.sub(r"(?<!\\)_", "\\_", final_tex)
|
||||||
|
|
||||||
|
def compute_brace_level(string):
|
||||||
|
# this function count the number of { and }
|
||||||
|
brace_level = 0
|
||||||
|
for c in string:
|
||||||
|
if c == "{": brace_level += 1
|
||||||
|
elif c == "}": brace_level -= 1
|
||||||
|
return brace_level
|
||||||
|
def join_most(tex_t, tex_o):
|
||||||
|
# this function join translated string and original string when something goes wrong
|
||||||
|
p_t = 0
|
||||||
|
p_o = 0
|
||||||
|
def find_next(string, chars, begin):
|
||||||
|
p = begin
|
||||||
|
while p < len(string):
|
||||||
|
if string[p] in chars: return p, string[p]
|
||||||
|
p += 1
|
||||||
|
return None, None
|
||||||
|
while True:
|
||||||
|
res1, char = find_next(tex_o, ['{','}'], p_o)
|
||||||
|
if res1 is None: break
|
||||||
|
res2, char = find_next(tex_t, [char], p_t)
|
||||||
|
if res2 is None: break
|
||||||
|
p_o = res1 + 1
|
||||||
|
p_t = res2 + 1
|
||||||
|
return tex_t[:p_t] + tex_o[p_o:]
|
||||||
|
|
||||||
|
if compute_brace_level(final_tex) != compute_brace_level(node_string):
|
||||||
|
# 出问题了,还原部分原文,保证括号正确
|
||||||
|
final_tex = join_most(final_tex, node_string)
|
||||||
|
return final_tex
|
||||||
|
|
||||||
def split_subprocess(txt, project_folder, return_dict, opts):
|
def split_subprocess(txt, project_folder, return_dict, opts):
|
||||||
"""
|
"""
|
||||||
@ -22,8 +326,7 @@ def split_subprocess(txt, project_folder, return_dict, opts):
|
|||||||
mask = np.zeros(len(txt), dtype=np.uint8) + TRANSFORM
|
mask = np.zeros(len(txt), dtype=np.uint8) + TRANSFORM
|
||||||
|
|
||||||
# 吸收title与作者以上的部分
|
# 吸收title与作者以上的部分
|
||||||
text, mask = set_forbidden_text(text, mask, r"^(.*?)\\maketitle", re.DOTALL)
|
text, mask = set_forbidden_text(text, mask, r"(.*?)\\maketitle", re.DOTALL)
|
||||||
text, mask = set_forbidden_text(text, mask, r"^(.*?)\\begin{document}", re.DOTALL)
|
|
||||||
# 吸收iffalse注释
|
# 吸收iffalse注释
|
||||||
text, mask = set_forbidden_text(text, mask, r"\\iffalse(.*?)\\fi", re.DOTALL)
|
text, mask = set_forbidden_text(text, mask, r"\\iffalse(.*?)\\fi", re.DOTALL)
|
||||||
# 吸收在42行以内的begin-end组合
|
# 吸收在42行以内的begin-end组合
|
||||||
@ -53,9 +356,77 @@ def split_subprocess(txt, project_folder, return_dict, opts):
|
|||||||
text, mask = reverse_forbidden_text(text, mask, r"\\begin\{abstract\}(.*?)\\end\{abstract\}", re.DOTALL, forbid_wrapper=True)
|
text, mask = reverse_forbidden_text(text, mask, r"\\begin\{abstract\}(.*?)\\end\{abstract\}", re.DOTALL, forbid_wrapper=True)
|
||||||
root = convert_to_linklist(text, mask)
|
root = convert_to_linklist(text, mask)
|
||||||
|
|
||||||
# 最后一步处理,增强稳健性
|
# 修复括号
|
||||||
root = post_process(root)
|
node = root
|
||||||
|
while True:
|
||||||
|
string = node.string
|
||||||
|
if node.preserve:
|
||||||
|
node = node.next
|
||||||
|
if node is None: break
|
||||||
|
continue
|
||||||
|
def break_check(string):
|
||||||
|
str_stack = [""] # (lv, index)
|
||||||
|
for i, c in enumerate(string):
|
||||||
|
if c == '{':
|
||||||
|
str_stack.append('{')
|
||||||
|
elif c == '}':
|
||||||
|
if len(str_stack) == 1:
|
||||||
|
print('stack fix')
|
||||||
|
return i
|
||||||
|
str_stack.pop(-1)
|
||||||
|
else:
|
||||||
|
str_stack[-1] += c
|
||||||
|
return -1
|
||||||
|
bp = break_check(string)
|
||||||
|
|
||||||
|
if bp == -1:
|
||||||
|
pass
|
||||||
|
elif bp == 0:
|
||||||
|
node.string = string[:1]
|
||||||
|
q = LinkedListNode(string[1:], False)
|
||||||
|
q.next = node.next
|
||||||
|
node.next = q
|
||||||
|
else:
|
||||||
|
node.string = string[:bp]
|
||||||
|
q = LinkedListNode(string[bp:], False)
|
||||||
|
q.next = node.next
|
||||||
|
node.next = q
|
||||||
|
|
||||||
|
node = node.next
|
||||||
|
if node is None: break
|
||||||
|
|
||||||
|
# 屏蔽空行和太短的句子
|
||||||
|
node = root
|
||||||
|
while True:
|
||||||
|
if len(node.string.strip('\n').strip(''))==0: node.preserve = True
|
||||||
|
if len(node.string.strip('\n').strip(''))<42: node.preserve = True
|
||||||
|
node = node.next
|
||||||
|
if node is None: break
|
||||||
|
node = root
|
||||||
|
while True:
|
||||||
|
if node.next and node.preserve and node.next.preserve:
|
||||||
|
node.string += node.next.string
|
||||||
|
node.next = node.next.next
|
||||||
|
node = node.next
|
||||||
|
if node is None: break
|
||||||
|
|
||||||
|
# 将前后断行符脱离
|
||||||
|
node = root
|
||||||
|
prev_node = None
|
||||||
|
while True:
|
||||||
|
if not node.preserve:
|
||||||
|
lstriped_ = node.string.lstrip().lstrip('\n')
|
||||||
|
if (prev_node is not None) and (prev_node.preserve) and (len(lstriped_)!=len(node.string)):
|
||||||
|
prev_node.string += node.string[:-len(lstriped_)]
|
||||||
|
node.string = lstriped_
|
||||||
|
rstriped_ = node.string.rstrip().rstrip('\n')
|
||||||
|
if (node.next is not None) and (node.next.preserve) and (len(rstriped_)!=len(node.string)):
|
||||||
|
node.next.string = node.string[len(rstriped_):] + node.next.string
|
||||||
|
node.string = rstriped_
|
||||||
|
# =====
|
||||||
|
prev_node = node
|
||||||
|
node = node.next
|
||||||
|
if node is None: break
|
||||||
# 输出html调试文件,用红色标注处保留区(PRESERVE),用黑色标注转换区(TRANSFORM)
|
# 输出html调试文件,用红色标注处保留区(PRESERVE),用黑色标注转换区(TRANSFORM)
|
||||||
with open(pj(project_folder, 'debug_log.html'), 'w', encoding='utf8') as f:
|
with open(pj(project_folder, 'debug_log.html'), 'w', encoding='utf8') as f:
|
||||||
segment_parts_for_gpt = []
|
segment_parts_for_gpt = []
|
||||||
@ -66,7 +437,7 @@ def split_subprocess(txt, project_folder, return_dict, opts):
|
|||||||
show_html = node.string.replace('\n','<br/>')
|
show_html = node.string.replace('\n','<br/>')
|
||||||
if not node.preserve:
|
if not node.preserve:
|
||||||
segment_parts_for_gpt.append(node.string)
|
segment_parts_for_gpt.append(node.string)
|
||||||
f.write(f'<p style="color:black;">#{node.range}{show_html}#</p>')
|
f.write(f'<p style="color:black;">#{show_html}#</p>')
|
||||||
else:
|
else:
|
||||||
f.write(f'<p style="color:red;">{show_html}</p>')
|
f.write(f'<p style="color:red;">{show_html}</p>')
|
||||||
node = node.next
|
node = node.next
|
||||||
@ -77,6 +448,8 @@ def split_subprocess(txt, project_folder, return_dict, opts):
|
|||||||
return_dict['segment_parts_for_gpt'] = segment_parts_for_gpt
|
return_dict['segment_parts_for_gpt'] = segment_parts_for_gpt
|
||||||
return return_dict
|
return return_dict
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class LatexPaperSplit():
|
class LatexPaperSplit():
|
||||||
"""
|
"""
|
||||||
break down latex file to a linked list,
|
break down latex file to a linked list,
|
||||||
@ -91,32 +464,18 @@ class LatexPaperSplit():
|
|||||||
# 请您不要删除或修改这行警告,除非您是论文的原作者(如果您是论文原作者,欢迎加REAME中的QQ联系开发者)
|
# 请您不要删除或修改这行警告,除非您是论文的原作者(如果您是论文原作者,欢迎加REAME中的QQ联系开发者)
|
||||||
self.msg_declare = "为了防止大语言模型的意外谬误产生扩散影响,禁止移除或修改此警告。}}\\\\"
|
self.msg_declare = "为了防止大语言模型的意外谬误产生扩散影响,禁止移除或修改此警告。}}\\\\"
|
||||||
|
|
||||||
|
def merge_result(self, arr, mode, msg):
|
||||||
def merge_result(self, arr, mode, msg, buggy_lines=[], buggy_line_surgery_n_lines=10):
|
|
||||||
"""
|
"""
|
||||||
Merge the result after the GPT process completed
|
Merge the result after the GPT process completed
|
||||||
"""
|
"""
|
||||||
result_string = ""
|
result_string = ""
|
||||||
node_cnt = 0
|
p = 0
|
||||||
line_cnt = 0
|
|
||||||
|
|
||||||
for node in self.nodes:
|
for node in self.nodes:
|
||||||
if node.preserve:
|
if node.preserve:
|
||||||
line_cnt += node.string.count('\n')
|
|
||||||
result_string += node.string
|
result_string += node.string
|
||||||
else:
|
else:
|
||||||
translated_txt = fix_content(arr[node_cnt], node.string)
|
result_string += fix_content(arr[p], node.string)
|
||||||
begin_line = line_cnt
|
p += 1
|
||||||
end_line = line_cnt + translated_txt.count('\n')
|
|
||||||
|
|
||||||
# reverse translation if any error
|
|
||||||
if any([begin_line-buggy_line_surgery_n_lines <= b_line <= end_line+buggy_line_surgery_n_lines for b_line in buggy_lines]):
|
|
||||||
translated_txt = node.string
|
|
||||||
|
|
||||||
result_string += translated_txt
|
|
||||||
node_cnt += 1
|
|
||||||
line_cnt += translated_txt.count('\n')
|
|
||||||
|
|
||||||
if mode == 'translate_zh':
|
if mode == 'translate_zh':
|
||||||
pattern = re.compile(r'\\begin\{abstract\}.*\n')
|
pattern = re.compile(r'\\begin\{abstract\}.*\n')
|
||||||
match = pattern.search(result_string)
|
match = pattern.search(result_string)
|
||||||
@ -131,7 +490,6 @@ class LatexPaperSplit():
|
|||||||
result_string = result_string[:position] + self.msg + msg + self.msg_declare + result_string[position:]
|
result_string = result_string[:position] + self.msg + msg + self.msg_declare + result_string[position:]
|
||||||
return result_string
|
return result_string
|
||||||
|
|
||||||
|
|
||||||
def split(self, txt, project_folder, opts):
|
def split(self, txt, project_folder, opts):
|
||||||
"""
|
"""
|
||||||
break down latex file to a linked list,
|
break down latex file to a linked list,
|
||||||
@ -153,6 +511,7 @@ class LatexPaperSplit():
|
|||||||
return self.sp
|
return self.sp
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class LatexPaperFileGroup():
|
class LatexPaperFileGroup():
|
||||||
"""
|
"""
|
||||||
use tokenizer to break down text according to max_token_limit
|
use tokenizer to break down text according to max_token_limit
|
||||||
@ -180,7 +539,7 @@ class LatexPaperFileGroup():
|
|||||||
self.sp_file_index.append(index)
|
self.sp_file_index.append(index)
|
||||||
self.sp_file_tag.append(self.file_paths[index])
|
self.sp_file_tag.append(self.file_paths[index])
|
||||||
else:
|
else:
|
||||||
from ..crazy_utils import breakdown_txt_to_satisfy_token_limit_for_pdf
|
from .crazy_utils import breakdown_txt_to_satisfy_token_limit_for_pdf
|
||||||
segments = breakdown_txt_to_satisfy_token_limit_for_pdf(file_content, self.get_token_num, max_token_limit)
|
segments = breakdown_txt_to_satisfy_token_limit_for_pdf(file_content, self.get_token_num, max_token_limit)
|
||||||
for j, segment in enumerate(segments):
|
for j, segment in enumerate(segments):
|
||||||
self.sp_file_contents.append(segment)
|
self.sp_file_contents.append(segment)
|
||||||
@ -201,14 +560,41 @@ class LatexPaperFileGroup():
|
|||||||
f.write(res)
|
f.write(res)
|
||||||
return manifest
|
return manifest
|
||||||
|
|
||||||
|
def write_html(sp_file_contents, sp_file_result, chatbot, project_folder):
|
||||||
|
|
||||||
|
# write html
|
||||||
|
try:
|
||||||
|
import shutil
|
||||||
|
from .crazy_utils import construct_html
|
||||||
|
from toolbox import gen_time_str
|
||||||
|
ch = construct_html()
|
||||||
|
orig = ""
|
||||||
|
trans = ""
|
||||||
|
final = []
|
||||||
|
for c,r in zip(sp_file_contents, sp_file_result):
|
||||||
|
final.append(c)
|
||||||
|
final.append(r)
|
||||||
|
for i, k in enumerate(final):
|
||||||
|
if i%2==0:
|
||||||
|
orig = k
|
||||||
|
if i%2==1:
|
||||||
|
trans = k
|
||||||
|
ch.add_row(a=orig, b=trans)
|
||||||
|
create_report_file_name = f"{gen_time_str()}.trans.html"
|
||||||
|
ch.save_file(create_report_file_name)
|
||||||
|
shutil.copyfile(pj('./gpt_log/', create_report_file_name), pj(project_folder, create_report_file_name))
|
||||||
|
promote_file_to_downloadzone(file=f'./gpt_log/{create_report_file_name}', chatbot=chatbot)
|
||||||
|
except:
|
||||||
|
from toolbox import trimmed_format_exc
|
||||||
|
print('writing html result failed:', trimmed_format_exc())
|
||||||
|
|
||||||
def Latex精细分解与转化(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, mode='proofread', switch_prompt=None, opts=[]):
|
def Latex精细分解与转化(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, mode='proofread', switch_prompt=None, opts=[]):
|
||||||
import time, os, re
|
import time, os, re
|
||||||
from ..crazy_utils import request_gpt_model_multi_threads_with_very_awesome_ui_and_high_efficiency
|
from .crazy_utils import request_gpt_model_multi_threads_with_very_awesome_ui_and_high_efficiency
|
||||||
from .latex_actions import LatexPaperFileGroup, LatexPaperSplit
|
from .latex_utils import LatexPaperFileGroup, merge_tex_files, LatexPaperSplit, 寻找Latex主文件
|
||||||
|
|
||||||
# <-------- 寻找主tex文件 ---------->
|
# <-------- 寻找主tex文件 ---------->
|
||||||
maintex = find_main_tex_file(file_manifest, mode)
|
maintex = 寻找Latex主文件(file_manifest, mode)
|
||||||
chatbot.append((f"定位主Latex文件", f'[Local Message] 分析结果:该项目的Latex主文件是{maintex}, 如果分析错误, 请立即终止程序, 删除或修改歧义文件, 然后重试。主程序即将开始, 请稍候。'))
|
chatbot.append((f"定位主Latex文件", f'[Local Message] 分析结果:该项目的Latex主文件是{maintex}, 如果分析错误, 请立即终止程序, 删除或修改歧义文件, 然后重试。主程序即将开始, 请稍候。'))
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
||||||
time.sleep(3)
|
time.sleep(3)
|
||||||
@ -282,51 +668,54 @@ def Latex精细分解与转化(file_manifest, project_folder, llm_kwargs, plugin
|
|||||||
# <-------- 写出文件 ---------->
|
# <-------- 写出文件 ---------->
|
||||||
msg = f"当前大语言模型: {llm_kwargs['llm_model']},当前语言模型温度设定: {llm_kwargs['temperature']}。"
|
msg = f"当前大语言模型: {llm_kwargs['llm_model']},当前语言模型温度设定: {llm_kwargs['temperature']}。"
|
||||||
final_tex = lps.merge_result(pfg.file_result, mode, msg)
|
final_tex = lps.merge_result(pfg.file_result, mode, msg)
|
||||||
objdump((lps, pfg.file_result, mode, msg), file=pj(project_folder,'merge_result.pkl'))
|
|
||||||
|
|
||||||
with open(project_folder + f'/merge_{mode}.tex', 'w', encoding='utf-8', errors='replace') as f:
|
with open(project_folder + f'/merge_{mode}.tex', 'w', encoding='utf-8', errors='replace') as f:
|
||||||
if mode != 'translate_zh' or "binary" in final_tex: f.write(final_tex)
|
if mode != 'translate_zh' or "binary" in final_tex: f.write(final_tex)
|
||||||
|
|
||||||
|
|
||||||
# <-------- 整理结果, 退出 ---------->
|
# <-------- 整理结果, 退出 ---------->
|
||||||
chatbot.append((f"完成了吗?", 'GPT结果已输出, 即将编译PDF'))
|
chatbot.append((f"完成了吗?", 'GPT结果已输出, 正在编译PDF'))
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
||||||
|
|
||||||
# <-------- 返回 ---------->
|
# <-------- 返回 ---------->
|
||||||
return project_folder + f'/merge_{mode}.tex'
|
return project_folder + f'/merge_{mode}.tex'
|
||||||
|
|
||||||
|
|
||||||
def remove_buggy_lines(file_path, log_path, tex_name, tex_name_pure, n_fix, work_folder_modified, fixed_line=[]):
|
|
||||||
|
def remove_buggy_lines(file_path, log_path, tex_name, tex_name_pure, n_fix, work_folder_modified):
|
||||||
try:
|
try:
|
||||||
with open(log_path, 'r', encoding='utf-8', errors='replace') as f:
|
with open(log_path, 'r', encoding='utf-8', errors='replace') as f:
|
||||||
log = f.read()
|
log = f.read()
|
||||||
|
with open(file_path, 'r', encoding='utf-8', errors='replace') as f:
|
||||||
|
file_lines = f.readlines()
|
||||||
import re
|
import re
|
||||||
buggy_lines = re.findall(tex_name+':([0-9]{1,5}):', log)
|
buggy_lines = re.findall(tex_name+':([0-9]{1,5}):', log)
|
||||||
buggy_lines = [int(l) for l in buggy_lines]
|
buggy_lines = [int(l) for l in buggy_lines]
|
||||||
buggy_lines = sorted(buggy_lines)
|
buggy_lines = sorted(buggy_lines)
|
||||||
buggy_line = buggy_lines[0]-1
|
print("removing lines that has errors", buggy_lines)
|
||||||
print("reversing tex line that has errors", buggy_line)
|
file_lines.pop(buggy_lines[0]-1)
|
||||||
|
|
||||||
# 重组,逆转出错的段落
|
|
||||||
if buggy_line not in fixed_line:
|
|
||||||
fixed_line.append(buggy_line)
|
|
||||||
|
|
||||||
lps, file_result, mode, msg = objload(file=pj(work_folder_modified,'merge_result.pkl'))
|
|
||||||
final_tex = lps.merge_result(file_result, mode, msg, buggy_lines=fixed_line, buggy_line_surgery_n_lines=5*n_fix)
|
|
||||||
|
|
||||||
with open(pj(work_folder_modified, f"{tex_name_pure}_fix_{n_fix}.tex"), 'w', encoding='utf-8', errors='replace') as f:
|
with open(pj(work_folder_modified, f"{tex_name_pure}_fix_{n_fix}.tex"), 'w', encoding='utf-8', errors='replace') as f:
|
||||||
f.write(final_tex)
|
f.writelines(file_lines)
|
||||||
|
|
||||||
return True, f"{tex_name_pure}_fix_{n_fix}", buggy_lines
|
return True, f"{tex_name_pure}_fix_{n_fix}", buggy_lines
|
||||||
except:
|
except:
|
||||||
print("Fatal error occurred, but we cannot identify error, please download zip, read latex log, and compile manually.")
|
print("Fatal error occurred, but we cannot identify error, please download zip, read latex log, and compile manually.")
|
||||||
return False, -1, [-1]
|
return False, -1, [-1]
|
||||||
|
|
||||||
|
def compile_latex_with_timeout(command, cwd, timeout=60):
|
||||||
|
import subprocess
|
||||||
|
process = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=cwd)
|
||||||
|
try:
|
||||||
|
stdout, stderr = process.communicate(timeout=timeout)
|
||||||
|
except subprocess.TimeoutExpired:
|
||||||
|
process.kill()
|
||||||
|
stdout, stderr = process.communicate()
|
||||||
|
print("Process timed out!")
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
def 编译Latex(chatbot, history, main_file_original, main_file_modified, work_folder_original, work_folder_modified, work_folder, mode='default'):
|
def 编译Latex(chatbot, history, main_file_original, main_file_modified, work_folder_original, work_folder_modified, work_folder, mode='default'):
|
||||||
import os, time
|
import os, time
|
||||||
|
current_dir = os.getcwd()
|
||||||
n_fix = 1
|
n_fix = 1
|
||||||
fixed_line = []
|
|
||||||
max_try = 32
|
max_try = 32
|
||||||
chatbot.append([f"正在编译PDF文档", f'编译已经开始。当前工作路径为{work_folder},如果程序停顿5分钟以上,请直接去该路径下取回翻译结果,或者重启之后再度尝试 ...']); yield from update_ui(chatbot=chatbot, history=history)
|
chatbot.append([f"正在编译PDF文档", f'编译已经开始。当前工作路径为{work_folder},如果程序停顿5分钟以上,请直接去该路径下取回翻译结果,或者重启之后再度尝试 ...']); yield from update_ui(chatbot=chatbot, history=history)
|
||||||
chatbot.append([f"正在编译PDF文档", '...']); yield from update_ui(chatbot=chatbot, history=history); time.sleep(1); chatbot[-1] = list(chatbot[-1]) # 刷新界面
|
chatbot.append([f"正在编译PDF文档", '...']); yield from update_ui(chatbot=chatbot, history=history); time.sleep(1); chatbot[-1] = list(chatbot[-1]) # 刷新界面
|
||||||
@ -334,10 +723,6 @@ def 编译Latex(chatbot, history, main_file_original, main_file_modified, work_f
|
|||||||
|
|
||||||
while True:
|
while True:
|
||||||
import os
|
import os
|
||||||
may_exist_bbl = pj(work_folder_modified, f'merge.bbl')
|
|
||||||
target_bbl = pj(work_folder_modified, f'{main_file_modified}.bbl')
|
|
||||||
if os.path.exists(may_exist_bbl) and not os.path.exists(target_bbl):
|
|
||||||
shutil.copyfile(may_exist_bbl, target_bbl)
|
|
||||||
|
|
||||||
# https://stackoverflow.com/questions/738755/dont-make-me-manually-abort-a-latex-compile-when-theres-an-error
|
# https://stackoverflow.com/questions/738755/dont-make-me-manually-abort-a-latex-compile-when-theres-an-error
|
||||||
yield from update_ui_lastest_msg(f'尝试第 {n_fix}/{max_try} 次编译, 编译原始PDF ...', chatbot, history) # 刷新Gradio前端界面
|
yield from update_ui_lastest_msg(f'尝试第 {n_fix}/{max_try} 次编译, 编译原始PDF ...', chatbot, history) # 刷新Gradio前端界面
|
||||||
@ -371,6 +756,7 @@ def 编译Latex(chatbot, history, main_file_original, main_file_modified, work_f
|
|||||||
ok = compile_latex_with_timeout(f'pdflatex -interaction=batchmode -file-line-error merge_diff.tex', work_folder)
|
ok = compile_latex_with_timeout(f'pdflatex -interaction=batchmode -file-line-error merge_diff.tex', work_folder)
|
||||||
ok = compile_latex_with_timeout(f'pdflatex -interaction=batchmode -file-line-error merge_diff.tex', work_folder)
|
ok = compile_latex_with_timeout(f'pdflatex -interaction=batchmode -file-line-error merge_diff.tex', work_folder)
|
||||||
|
|
||||||
|
|
||||||
# <---------- 检查结果 ----------->
|
# <---------- 检查结果 ----------->
|
||||||
results_ = ""
|
results_ = ""
|
||||||
original_pdf_success = os.path.exists(pj(work_folder_original, f'{main_file_original}.pdf'))
|
original_pdf_success = os.path.exists(pj(work_folder_original, f'{main_file_original}.pdf'))
|
||||||
@ -387,19 +773,9 @@ def 编译Latex(chatbot, history, main_file_original, main_file_modified, work_f
|
|||||||
if modified_pdf_success:
|
if modified_pdf_success:
|
||||||
yield from update_ui_lastest_msg(f'转化PDF编译已经成功, 即将退出 ...', chatbot, history) # 刷新Gradio前端界面
|
yield from update_ui_lastest_msg(f'转化PDF编译已经成功, 即将退出 ...', chatbot, history) # 刷新Gradio前端界面
|
||||||
result_pdf = pj(work_folder_modified, f'{main_file_modified}.pdf') # get pdf path
|
result_pdf = pj(work_folder_modified, f'{main_file_modified}.pdf') # get pdf path
|
||||||
origin_pdf = pj(work_folder_original, f'{main_file_original}.pdf') # get pdf path
|
|
||||||
if os.path.exists(pj(work_folder, '..', 'translation')):
|
if os.path.exists(pj(work_folder, '..', 'translation')):
|
||||||
shutil.copyfile(result_pdf, pj(work_folder, '..', 'translation', 'translate_zh.pdf'))
|
shutil.copyfile(result_pdf, pj(work_folder, '..', 'translation', 'translate_zh.pdf'))
|
||||||
promote_file_to_downloadzone(result_pdf, rename_file=None, chatbot=chatbot) # promote file to web UI
|
promote_file_to_downloadzone(result_pdf, rename_file=None, chatbot=chatbot) # promote file to web UI
|
||||||
# 将两个PDF拼接
|
|
||||||
if original_pdf_success:
|
|
||||||
try:
|
|
||||||
from .latex_toolbox import merge_pdfs
|
|
||||||
concat_pdf = pj(work_folder_modified, f'comparison.pdf')
|
|
||||||
merge_pdfs(origin_pdf, result_pdf, concat_pdf)
|
|
||||||
promote_file_to_downloadzone(concat_pdf, rename_file=None, chatbot=chatbot) # promote file to web UI
|
|
||||||
except Exception as e:
|
|
||||||
pass
|
|
||||||
return True # 成功啦
|
return True # 成功啦
|
||||||
else:
|
else:
|
||||||
if n_fix>=max_try: break
|
if n_fix>=max_try: break
|
||||||
@ -411,7 +787,6 @@ def 编译Latex(chatbot, history, main_file_original, main_file_modified, work_f
|
|||||||
tex_name_pure=f'{main_file_modified}',
|
tex_name_pure=f'{main_file_modified}',
|
||||||
n_fix=n_fix,
|
n_fix=n_fix,
|
||||||
work_folder_modified=work_folder_modified,
|
work_folder_modified=work_folder_modified,
|
||||||
fixed_line=fixed_line
|
|
||||||
)
|
)
|
||||||
yield from update_ui_lastest_msg(f'由于最为关键的转化PDF编译失败, 将根据报错信息修正tex源文件并重试, 当前报错的latex代码处于第{buggy_lines}行 ...', chatbot, history) # 刷新Gradio前端界面
|
yield from update_ui_lastest_msg(f'由于最为关键的转化PDF编译失败, 将根据报错信息修正tex源文件并重试, 当前报错的latex代码处于第{buggy_lines}行 ...', chatbot, history) # 刷新Gradio前端界面
|
||||||
if not can_retry: break
|
if not can_retry: break
|
||||||
@ -419,29 +794,4 @@ def 编译Latex(chatbot, history, main_file_original, main_file_modified, work_f
|
|||||||
return False # 失败啦
|
return False # 失败啦
|
||||||
|
|
||||||
|
|
||||||
def write_html(sp_file_contents, sp_file_result, chatbot, project_folder):
|
|
||||||
# write html
|
|
||||||
try:
|
|
||||||
import shutil
|
|
||||||
from ..crazy_utils import construct_html
|
|
||||||
from toolbox import gen_time_str
|
|
||||||
ch = construct_html()
|
|
||||||
orig = ""
|
|
||||||
trans = ""
|
|
||||||
final = []
|
|
||||||
for c,r in zip(sp_file_contents, sp_file_result):
|
|
||||||
final.append(c)
|
|
||||||
final.append(r)
|
|
||||||
for i, k in enumerate(final):
|
|
||||||
if i%2==0:
|
|
||||||
orig = k
|
|
||||||
if i%2==1:
|
|
||||||
trans = k
|
|
||||||
ch.add_row(a=orig, b=trans)
|
|
||||||
create_report_file_name = f"{gen_time_str()}.trans.html"
|
|
||||||
ch.save_file(create_report_file_name)
|
|
||||||
shutil.copyfile(pj('./gpt_log/', create_report_file_name), pj(project_folder, create_report_file_name))
|
|
||||||
promote_file_to_downloadzone(file=f'./gpt_log/{create_report_file_name}', chatbot=chatbot)
|
|
||||||
except:
|
|
||||||
from toolbox import trimmed_format_exc
|
|
||||||
print('writing html result failed:', trimmed_format_exc())
|
|
||||||
@ -19,7 +19,7 @@ class AliyunASR():
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
def test_on_error(self, message, *args):
|
def test_on_error(self, message, *args):
|
||||||
print("on_error args=>{}".format(args))
|
# print("on_error args=>{}".format(args))
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def test_on_close(self, *args):
|
def test_on_close(self, *args):
|
||||||
@ -50,8 +50,6 @@ class AliyunASR():
|
|||||||
rad.clean_up()
|
rad.clean_up()
|
||||||
temp_folder = tempfile.gettempdir()
|
temp_folder = tempfile.gettempdir()
|
||||||
TOKEN, APPKEY = get_conf('ALIYUN_TOKEN', 'ALIYUN_APPKEY')
|
TOKEN, APPKEY = get_conf('ALIYUN_TOKEN', 'ALIYUN_APPKEY')
|
||||||
if len(TOKEN) == 0:
|
|
||||||
TOKEN = self.get_token()
|
|
||||||
self.aliyun_service_ok = True
|
self.aliyun_service_ok = True
|
||||||
URL="wss://nls-gateway.aliyuncs.com/ws/v1"
|
URL="wss://nls-gateway.aliyuncs.com/ws/v1"
|
||||||
sr = nls.NlsSpeechTranscriber(
|
sr = nls.NlsSpeechTranscriber(
|
||||||
@ -93,38 +91,3 @@ class AliyunASR():
|
|||||||
self.stop = True
|
self.stop = True
|
||||||
self.stop_msg = 'Aliyun音频服务异常,请检查ALIYUN_TOKEN和ALIYUN_APPKEY是否过期。'
|
self.stop_msg = 'Aliyun音频服务异常,请检查ALIYUN_TOKEN和ALIYUN_APPKEY是否过期。'
|
||||||
r = sr.stop()
|
r = sr.stop()
|
||||||
|
|
||||||
def get_token(self):
|
|
||||||
from toolbox import get_conf
|
|
||||||
import json
|
|
||||||
from aliyunsdkcore.request import CommonRequest
|
|
||||||
from aliyunsdkcore.client import AcsClient
|
|
||||||
AccessKey_ID, AccessKey_secret = get_conf('ALIYUN_ACCESSKEY', 'ALIYUN_SECRET')
|
|
||||||
|
|
||||||
# 创建AcsClient实例
|
|
||||||
client = AcsClient(
|
|
||||||
AccessKey_ID,
|
|
||||||
AccessKey_secret,
|
|
||||||
"cn-shanghai"
|
|
||||||
)
|
|
||||||
|
|
||||||
# 创建request,并设置参数。
|
|
||||||
request = CommonRequest()
|
|
||||||
request.set_method('POST')
|
|
||||||
request.set_domain('nls-meta.cn-shanghai.aliyuncs.com')
|
|
||||||
request.set_version('2019-02-28')
|
|
||||||
request.set_action_name('CreateToken')
|
|
||||||
|
|
||||||
try:
|
|
||||||
response = client.do_action_with_exception(request)
|
|
||||||
print(response)
|
|
||||||
jss = json.loads(response)
|
|
||||||
if 'Token' in jss and 'Id' in jss['Token']:
|
|
||||||
token = jss['Token']['Id']
|
|
||||||
expireTime = jss['Token']['ExpireTime']
|
|
||||||
print("token = " + token)
|
|
||||||
print("expireTime = " + str(expireTime))
|
|
||||||
except Exception as e:
|
|
||||||
print(e)
|
|
||||||
|
|
||||||
return token
|
|
||||||
|
|||||||
38
crazy_functions/vhmap_interact/vhmap.py
Normal file
38
crazy_functions/vhmap_interact/vhmap.py
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
from toolbox import update_ui, get_conf, trimmed_format_exc
|
||||||
|
import threading
|
||||||
|
|
||||||
|
def Singleton(cls):
|
||||||
|
_instance = {}
|
||||||
|
|
||||||
|
def _singleton(*args, **kargs):
|
||||||
|
if cls not in _instance:
|
||||||
|
_instance[cls] = cls(*args, **kargs)
|
||||||
|
return _instance[cls]
|
||||||
|
|
||||||
|
return _singleton
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
class vhmp_interface():
|
||||||
|
def __init__(self) -> None:
|
||||||
|
from VISUALIZE.mcom_rt import mcom
|
||||||
|
self.vis3d = mcom(path='TEMP/v2d_logger/', draw_mode='Threejs')
|
||||||
|
self.vis3d.v2d_init()
|
||||||
|
self.vis3d.设置样式('star')
|
||||||
|
# vis3d.设置样式('star') # 布置星空
|
||||||
|
self.vis3d.其他几何体之旋转缩放和平移('box', 'BoxGeometry(1,1,1)', 0,0,0, 1,1,1, 0,0,0)
|
||||||
|
# declare geo 'oct1', init with OctahedronGeometry, then (1)rotate & (2)scale & (3)translate
|
||||||
|
self.vis3d.其他几何体之旋转缩放和平移('octahedron', 'OctahedronGeometry(1,0)', 0,0,0, 1,1,1, 0,0,0) # 八面体
|
||||||
|
# 需要换成其他几何体,请把'OctahedronGeometry(1,0)'替换,参考网址 https://threejs.org/docs/index.html?q=Geometry
|
||||||
|
self.vis3d.其他几何体之旋转缩放和平移('sphere', 'SphereGeometry(1)', 0,0,0, 1,1,1, 0,0,0) # 球体
|
||||||
|
self.vis3d.其他几何体之旋转缩放和平移('cylinder', 'CylinderGeometry(1,1,5,32)', 0,0,0, 1,1,1, 0,0,0) # 球体
|
||||||
|
|
||||||
|
def update(self, json):
|
||||||
|
for obj in json:
|
||||||
|
self.vis3d.发送几何体(
|
||||||
|
f'{obj["geometry"]}|{obj["name"]}|{obj["color"]}|{obj["size"]}', # 填入 ‘形状|几何体之ID标识|颜色|大小’即可
|
||||||
|
obj["location_x"],
|
||||||
|
obj["location_y"],
|
||||||
|
obj["location_z"],
|
||||||
|
ro_x=0, ro_y=0, ro_z=0, # 三维位置+欧拉旋转变换,六自由度
|
||||||
|
track_n_frame=0) # 显示历史20帧留下的轨迹
|
||||||
|
self.vis3d.结束关键帧()
|
||||||
@ -55,7 +55,7 @@ def 图片生成(prompt, llm_kwargs, plugin_kwargs, chatbot, history, system_pro
|
|||||||
web_port 当前软件运行的端口号
|
web_port 当前软件运行的端口号
|
||||||
"""
|
"""
|
||||||
history = [] # 清空历史,以免输入溢出
|
history = [] # 清空历史,以免输入溢出
|
||||||
chatbot.append(("这是什么功能?", "[Local Message] 生成图像, 请先把模型切换至gpt-*或者api2d-*。如果中文效果不理想, 请尝试英文Prompt。正在处理中 ....."))
|
chatbot.append(("这是什么功能?", "[Local Message] 生成图像, 请先把模型切换至gpt-xxxx或者api2d-xxxx。如果中文效果不理想, 尝试Prompt。正在处理中 ....."))
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 # 由于请求gpt需要一段时间,我们先及时地做一次界面更新
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 # 由于请求gpt需要一段时间,我们先及时地做一次界面更新
|
||||||
if ("advanced_arg" in plugin_kwargs) and (plugin_kwargs["advanced_arg"] == ""): plugin_kwargs.pop("advanced_arg")
|
if ("advanced_arg" in plugin_kwargs) and (plugin_kwargs["advanced_arg"] == ""): plugin_kwargs.pop("advanced_arg")
|
||||||
resolution = plugin_kwargs.get("advanced_arg", '256x256')
|
resolution = plugin_kwargs.get("advanced_arg", '256x256')
|
||||||
|
|||||||
@ -1,7 +1,5 @@
|
|||||||
import glob, time, os, re
|
from toolbox import update_ui, trimmed_format_exc, gen_time_str
|
||||||
from toolbox import update_ui, trimmed_format_exc, gen_time_str, disable_auto_promotion
|
from toolbox import CatchException, report_execption, write_results_to_file
|
||||||
from toolbox import CatchException, report_execption, write_history_to_file
|
|
||||||
from toolbox import promote_file_to_downloadzone, get_log_folder
|
|
||||||
fast_debug = False
|
fast_debug = False
|
||||||
|
|
||||||
class PaperFileGroup():
|
class PaperFileGroup():
|
||||||
@ -44,13 +42,13 @@ class PaperFileGroup():
|
|||||||
def write_result(self, language):
|
def write_result(self, language):
|
||||||
manifest = []
|
manifest = []
|
||||||
for path, res in zip(self.file_paths, self.file_result):
|
for path, res in zip(self.file_paths, self.file_result):
|
||||||
dst_file = os.path.join(get_log_folder(), f'{gen_time_str()}.md')
|
with open(path + f'.{gen_time_str()}.{language}.md', 'w', encoding='utf8') as f:
|
||||||
with open(dst_file, 'w', encoding='utf8') as f:
|
manifest.append(path + f'.{gen_time_str()}.{language}.md')
|
||||||
manifest.append(dst_file)
|
|
||||||
f.write(res)
|
f.write(res)
|
||||||
return manifest
|
return manifest
|
||||||
|
|
||||||
def 多文件翻译(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, language='en'):
|
def 多文件翻译(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, language='en'):
|
||||||
|
import time, os, re
|
||||||
from .crazy_utils import request_gpt_model_multi_threads_with_very_awesome_ui_and_high_efficiency
|
from .crazy_utils import request_gpt_model_multi_threads_with_very_awesome_ui_and_high_efficiency
|
||||||
|
|
||||||
# <-------- 读取Markdown文件,删除其中的所有注释 ---------->
|
# <-------- 读取Markdown文件,删除其中的所有注释 ---------->
|
||||||
@ -104,38 +102,28 @@ def 多文件翻译(file_manifest, project_folder, llm_kwargs, plugin_kwargs, ch
|
|||||||
print(trimmed_format_exc())
|
print(trimmed_format_exc())
|
||||||
|
|
||||||
# <-------- 整理结果,退出 ---------->
|
# <-------- 整理结果,退出 ---------->
|
||||||
create_report_file_name = gen_time_str() + f"-chatgpt.md"
|
create_report_file_name = time.strftime("%Y-%m-%d-%H-%M-%S", time.localtime()) + f"-chatgpt.polish.md"
|
||||||
res = write_history_to_file(gpt_response_collection, file_basename=create_report_file_name)
|
res = write_results_to_file(gpt_response_collection, file_name=create_report_file_name)
|
||||||
promote_file_to_downloadzone(res, chatbot=chatbot)
|
|
||||||
history = gpt_response_collection
|
history = gpt_response_collection
|
||||||
chatbot.append((f"{fp}完成了吗?", res))
|
chatbot.append((f"{fp}完成了吗?", res))
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
||||||
|
|
||||||
|
|
||||||
def get_files_from_everything(txt, preference=''):
|
def get_files_from_everything(txt):
|
||||||
if txt == "": return False, None, None
|
import glob, os
|
||||||
|
|
||||||
success = True
|
success = True
|
||||||
if txt.startswith('http'):
|
if txt.startswith('http'):
|
||||||
|
# 网络的远程文件
|
||||||
|
txt = txt.replace("https://github.com/", "https://raw.githubusercontent.com/")
|
||||||
|
txt = txt.replace("/blob/", "/")
|
||||||
import requests
|
import requests
|
||||||
from toolbox import get_conf
|
from toolbox import get_conf
|
||||||
proxies, = get_conf('proxies')
|
proxies, = get_conf('proxies')
|
||||||
# 网络的远程文件
|
|
||||||
if preference == 'Github':
|
|
||||||
print('正在从github下载资源 ...')
|
|
||||||
if not txt.endswith('.md'):
|
|
||||||
# Make a request to the GitHub API to retrieve the repository information
|
|
||||||
url = txt.replace("https://github.com/", "https://api.github.com/repos/") + '/readme'
|
|
||||||
response = requests.get(url, proxies=proxies)
|
|
||||||
txt = response.json()['download_url']
|
|
||||||
else:
|
|
||||||
txt = txt.replace("https://github.com/", "https://raw.githubusercontent.com/")
|
|
||||||
txt = txt.replace("/blob/", "/")
|
|
||||||
|
|
||||||
r = requests.get(txt, proxies=proxies)
|
r = requests.get(txt, proxies=proxies)
|
||||||
download_local = f'{get_log_folder(plugin_name="批量Markdown翻译")}/raw-readme-{gen_time_str()}.md'
|
with open('./gpt_log/temp.md', 'wb+') as f: f.write(r.content)
|
||||||
project_folder = f'{get_log_folder(plugin_name="批量Markdown翻译")}'
|
project_folder = './gpt_log/'
|
||||||
with open(download_local, 'wb+') as f: f.write(r.content)
|
file_manifest = ['./gpt_log/temp.md']
|
||||||
file_manifest = [download_local]
|
|
||||||
elif txt.endswith('.md'):
|
elif txt.endswith('.md'):
|
||||||
# 直接给定文件
|
# 直接给定文件
|
||||||
file_manifest = [txt]
|
file_manifest = [txt]
|
||||||
@ -157,11 +145,11 @@ def Markdown英译中(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_p
|
|||||||
"函数插件功能?",
|
"函数插件功能?",
|
||||||
"对整个Markdown项目进行翻译。函数插件贡献者: Binary-Husky"])
|
"对整个Markdown项目进行翻译。函数插件贡献者: Binary-Husky"])
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
||||||
disable_auto_promotion(chatbot)
|
|
||||||
|
|
||||||
# 尝试导入依赖,如果缺少依赖,则给出安装建议
|
# 尝试导入依赖,如果缺少依赖,则给出安装建议
|
||||||
try:
|
try:
|
||||||
import tiktoken
|
import tiktoken
|
||||||
|
import glob, os
|
||||||
except:
|
except:
|
||||||
report_execption(chatbot, history,
|
report_execption(chatbot, history,
|
||||||
a=f"解析项目: {txt}",
|
a=f"解析项目: {txt}",
|
||||||
@ -170,7 +158,7 @@ def Markdown英译中(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_p
|
|||||||
return
|
return
|
||||||
history = [] # 清空历史,以免输入溢出
|
history = [] # 清空历史,以免输入溢出
|
||||||
|
|
||||||
success, file_manifest, project_folder = get_files_from_everything(txt, preference="Github")
|
success, file_manifest, project_folder = get_files_from_everything(txt)
|
||||||
|
|
||||||
if not success:
|
if not success:
|
||||||
# 什么都没有
|
# 什么都没有
|
||||||
@ -197,11 +185,11 @@ def Markdown中译英(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_p
|
|||||||
"函数插件功能?",
|
"函数插件功能?",
|
||||||
"对整个Markdown项目进行翻译。函数插件贡献者: Binary-Husky"])
|
"对整个Markdown项目进行翻译。函数插件贡献者: Binary-Husky"])
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
||||||
disable_auto_promotion(chatbot)
|
|
||||||
|
|
||||||
# 尝试导入依赖,如果缺少依赖,则给出安装建议
|
# 尝试导入依赖,如果缺少依赖,则给出安装建议
|
||||||
try:
|
try:
|
||||||
import tiktoken
|
import tiktoken
|
||||||
|
import glob, os
|
||||||
except:
|
except:
|
||||||
report_execption(chatbot, history,
|
report_execption(chatbot, history,
|
||||||
a=f"解析项目: {txt}",
|
a=f"解析项目: {txt}",
|
||||||
@ -230,11 +218,11 @@ def Markdown翻译指定语言(txt, llm_kwargs, plugin_kwargs, chatbot, history,
|
|||||||
"函数插件功能?",
|
"函数插件功能?",
|
||||||
"对整个Markdown项目进行翻译。函数插件贡献者: Binary-Husky"])
|
"对整个Markdown项目进行翻译。函数插件贡献者: Binary-Husky"])
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
||||||
disable_auto_promotion(chatbot)
|
|
||||||
|
|
||||||
# 尝试导入依赖,如果缺少依赖,则给出安装建议
|
# 尝试导入依赖,如果缺少依赖,则给出安装建议
|
||||||
try:
|
try:
|
||||||
import tiktoken
|
import tiktoken
|
||||||
|
import glob, os
|
||||||
except:
|
except:
|
||||||
report_execption(chatbot, history,
|
report_execption(chatbot, history,
|
||||||
a=f"解析项目: {txt}",
|
a=f"解析项目: {txt}",
|
||||||
|
|||||||
@ -97,7 +97,7 @@ class InterviewAssistant(AliyunASR):
|
|||||||
# 初始化音频采集线程
|
# 初始化音频采集线程
|
||||||
self.captured_audio = np.array([])
|
self.captured_audio = np.array([])
|
||||||
self.keep_latest_n_second = 10
|
self.keep_latest_n_second = 10
|
||||||
self.commit_after_pause_n_second = 2.0
|
self.commit_after_pause_n_second = 1.5
|
||||||
self.ready_audio_flagment = None
|
self.ready_audio_flagment = None
|
||||||
self.stop = False
|
self.stop = False
|
||||||
self.plugin_wd = WatchDog(timeout=5, bark_fn=self.__del__, msg="程序终止")
|
self.plugin_wd = WatchDog(timeout=5, bark_fn=self.__del__, msg="程序终止")
|
||||||
@ -179,12 +179,12 @@ def 语音助手(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt
|
|||||||
import nls
|
import nls
|
||||||
from scipy import io
|
from scipy import io
|
||||||
except:
|
except:
|
||||||
chatbot.append(["导入依赖失败", "使用该模块需要额外依赖, 安装方法:```pip install --upgrade aliyun-python-sdk-core==2.13.3 pyOpenSSL scipy git+https://github.com/aliyun/alibabacloud-nls-python-sdk.git```"])
|
chatbot.append(["导入依赖失败", "使用该模块需要额外依赖, 安装方法:```pip install --upgrade pyOpenSSL scipy git+https://github.com/aliyun/alibabacloud-nls-python-sdk.git```"])
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
||||||
return
|
return
|
||||||
|
|
||||||
APPKEY = get_conf('ALIYUN_APPKEY')
|
TOKEN, APPKEY = get_conf('ALIYUN_TOKEN', 'ALIYUN_APPKEY')
|
||||||
if APPKEY == "":
|
if TOKEN == "" or APPKEY == "":
|
||||||
chatbot.append(["导入依赖失败", "没有阿里云语音识别APPKEY和TOKEN, 详情见https://help.aliyun.com/document_detail/450255.html"])
|
chatbot.append(["导入依赖失败", "没有阿里云语音识别APPKEY和TOKEN, 详情见https://help.aliyun.com/document_detail/450255.html"])
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
||||||
return
|
return
|
||||||
|
|||||||
@ -115,36 +115,3 @@ services:
|
|||||||
command: >
|
command: >
|
||||||
bash -c "python3 -u main.py"
|
bash -c "python3 -u main.py"
|
||||||
|
|
||||||
|
|
||||||
## ===================================================
|
|
||||||
## 【方案五】 ChatGPT + 语音助手 (请先阅读 docs/use_audio.md)
|
|
||||||
## ===================================================
|
|
||||||
version: '3'
|
|
||||||
services:
|
|
||||||
gpt_academic_with_audio:
|
|
||||||
image: ghcr.io/binary-husky/gpt_academic_audio_assistant:master
|
|
||||||
environment:
|
|
||||||
# 请查阅 `config.py` 以查看所有的配置信息
|
|
||||||
API_KEY: ' fk195831-IdP0Pb3W6DCMUIbQwVX6MsSiyxwqybyS '
|
|
||||||
USE_PROXY: ' False '
|
|
||||||
proxies: ' None '
|
|
||||||
LLM_MODEL: ' gpt-3.5-turbo '
|
|
||||||
AVAIL_LLM_MODELS: ' ["gpt-3.5-turbo", "gpt-4"] '
|
|
||||||
ENABLE_AUDIO: ' True '
|
|
||||||
LOCAL_MODEL_DEVICE: ' cuda '
|
|
||||||
DEFAULT_WORKER_NUM: ' 20 '
|
|
||||||
WEB_PORT: ' 12343 '
|
|
||||||
ADD_WAIFU: ' True '
|
|
||||||
THEME: ' Chuanhu-Small-and-Beautiful '
|
|
||||||
ALIYUN_APPKEY: ' RoP1ZrM84DnAFkZK '
|
|
||||||
ALIYUN_TOKEN: ' f37f30e0f9934c34a992f6f64f7eba4f '
|
|
||||||
# (无需填写) ALIYUN_ACCESSKEY: ' LTAI5q6BrFUzoRXVGUWnekh1 '
|
|
||||||
# (无需填写) ALIYUN_SECRET: ' eHmI20AVWIaQZ0CiTD2bGQVsaP9i68 '
|
|
||||||
|
|
||||||
# 与宿主的网络融合
|
|
||||||
network_mode: "host"
|
|
||||||
|
|
||||||
# 不使用代理网络拉取最新代码
|
|
||||||
command: >
|
|
||||||
bash -c "python3 -u main.py"
|
|
||||||
|
|
||||||
|
|||||||
@ -1,22 +0,0 @@
|
|||||||
# 此Dockerfile适用于“无本地模型”的环境构建,如果需要使用chatglm等本地模型,请参考 docs/Dockerfile+ChatGLM
|
|
||||||
# 如何构建: 先修改 `config.py`, 然后 docker build -t gpt-academic-nolocal -f docs/Dockerfile+NoLocal .
|
|
||||||
# 如何运行: docker run --rm -it --net=host gpt-academic-nolocal
|
|
||||||
FROM python:3.11
|
|
||||||
|
|
||||||
# 指定路径
|
|
||||||
WORKDIR /gpt
|
|
||||||
|
|
||||||
# 装载项目文件
|
|
||||||
COPY . .
|
|
||||||
|
|
||||||
# 安装依赖
|
|
||||||
RUN pip3 install -r requirements.txt
|
|
||||||
|
|
||||||
# 安装语音插件的额外依赖
|
|
||||||
RUN pip3 install pyOpenSSL scipy git+https://github.com/aliyun/alibabacloud-nls-python-sdk.git
|
|
||||||
|
|
||||||
# 可选步骤,用于预热模块
|
|
||||||
RUN python3 -c 'from check_proxy import warm_up_modules; warm_up_modules()'
|
|
||||||
|
|
||||||
# 启动
|
|
||||||
CMD ["python3", "-u", "main.py"]
|
|
||||||
@ -2085,66 +2085,5 @@
|
|||||||
"欢迎使用 MOSS 人工智能助手!输入内容即可进行对话": "Welcome to use MOSS AI assistant! Enter the content to start the conversation.",
|
"欢迎使用 MOSS 人工智能助手!输入内容即可进行对话": "Welcome to use MOSS AI assistant! Enter the content to start the conversation.",
|
||||||
"记住当前的label": "Remember the current label.",
|
"记住当前的label": "Remember the current label.",
|
||||||
"不能正常加载ChatGLMFT的参数!": "Cannot load ChatGLMFT parameters normally!",
|
"不能正常加载ChatGLMFT的参数!": "Cannot load ChatGLMFT parameters normally!",
|
||||||
"建议直接在API_KEY处填写": "It is recommended to fill in directly at API_KEY.",
|
"建议直接在API_KEY处填写": "It is recommended to fill in directly at API_KEY."
|
||||||
"创建request": "Create request",
|
|
||||||
"默认 secondary": "Default secondary",
|
|
||||||
"会被加在你的输入之前": "Will be added before your input",
|
|
||||||
"缺少": "Missing",
|
|
||||||
"前者是API2D的结束条件": "The former is the termination condition of API2D",
|
|
||||||
"无需填写": "No need to fill in",
|
|
||||||
"后缀": "Suffix",
|
|
||||||
"扭转的范围": "Range of twisting",
|
|
||||||
"是否在触发时清除历史": "Whether to clear history when triggered",
|
|
||||||
"⭐多线程方法": "⭐Multi-threaded method",
|
|
||||||
"消耗大量的内存": "Consumes a large amount of memory",
|
|
||||||
"重组": "Reorganize",
|
|
||||||
"高危设置! 常规情况下不要修改! 通过修改此设置": "High-risk setting! Do not modify under normal circumstances! Modify this setting",
|
|
||||||
"检查USE_PROXY": "Check USE_PROXY",
|
|
||||||
"标注节点的行数范围": "Range of line numbers for annotated nodes",
|
|
||||||
"即不处理之前的对话历史": "That is, do not process previous conversation history",
|
|
||||||
"即将编译PDF": "Compiling PDF",
|
|
||||||
"没有设置ANTHROPIC_API_KEY选项": "ANTHROPIC_API_KEY option is not set",
|
|
||||||
"非Openai官方接口返回了错误": "Non-Openai official interface returned an error",
|
|
||||||
"您的 API_KEY 不满足任何一种已知的密钥格式": "Your API_KEY does not meet any known key format",
|
|
||||||
"格式": "Format",
|
|
||||||
"不能正常加载": "Cannot load properly",
|
|
||||||
"🏃♂️🏃♂️🏃♂️ 子进程执行": "🏃♂️🏃♂️🏃♂️ Subprocess execution",
|
|
||||||
"前缀": "Prefix",
|
|
||||||
"创建AcsClient实例": "Create AcsClient instance",
|
|
||||||
"⭐主进程执行": "⭐Main process execution",
|
|
||||||
"增强稳健性": "Enhance robustness",
|
|
||||||
"用来描述你的要求": "Used to describe your requirements",
|
|
||||||
"举例": "For example",
|
|
||||||
"⭐单线程方法": "⭐Single-threaded method",
|
|
||||||
"后者是OPENAI的结束条件": "The latter is the termination condition of OPENAI",
|
|
||||||
"防止proxies单独起作用": "Prevent proxies from working alone",
|
|
||||||
"将两个PDF拼接": "Concatenate two PDFs",
|
|
||||||
"最后一步处理": "The last step processing",
|
|
||||||
"正在从github下载资源": "Downloading resources from github",
|
|
||||||
"失败时": "When failed",
|
|
||||||
"尚未加载": "Not loaded yet",
|
|
||||||
"配合前缀可以把你的输入内容用引号圈起来": "With the prefix, you can enclose your input content in quotation marks",
|
|
||||||
"我好!": "I'm good!",
|
|
||||||
"默认 False": "Default False",
|
|
||||||
"的依赖": "Dependencies of",
|
|
||||||
"并设置参数": "and set parameters",
|
|
||||||
"会被加在你的输入之后": "Will be added after your input",
|
|
||||||
"安装": "Installation",
|
|
||||||
"一个单实例装饰器": "Single instance decorator",
|
|
||||||
"自定义API KEY格式": "Customize API KEY format",
|
|
||||||
"的参数": "Parameters of",
|
|
||||||
"api2d等请求源": "api2d and other request sources",
|
|
||||||
"逆转出错的段落": "Reverse the wrong paragraph",
|
|
||||||
"没有设置ANTHROPIC_API_KEY": "ANTHROPIC_API_KEY is not set",
|
|
||||||
"默认 True": "Default True",
|
|
||||||
"本项目现已支持OpenAI和Azure的api-key": "This project now supports OpenAI and Azure's api-key",
|
|
||||||
"即可见": "Visible immediately",
|
|
||||||
"请问什么是质子": "What is a proton?",
|
|
||||||
"按钮是否可见": "Is the button visible?",
|
|
||||||
"调用": "Call",
|
|
||||||
"如果要使用": "If you want to use",
|
|
||||||
"的参数!": "parameters!",
|
|
||||||
"例如翻译、解释代码、润色等等": "such as translation, code interpretation, polishing, etc.",
|
|
||||||
"响应异常": "Response exception",
|
|
||||||
"响应中": "Responding"
|
|
||||||
}
|
}
|
||||||
@ -939,6 +939,7 @@
|
|||||||
"以下は学術論文の基本情報です": "以下は学術論文の基本情報です",
|
"以下は学術論文の基本情報です": "以下は学術論文の基本情報です",
|
||||||
"出力が不完全になる原因となる": "出力が不完全になる原因となる",
|
"出力が不完全になる原因となる": "出力が不完全になる原因となる",
|
||||||
"ハイフンを使って": "ハイフンを使って",
|
"ハイフンを使って": "ハイフンを使って",
|
||||||
|
"シングルスレッド": "シングルスレッド",
|
||||||
"请先把模型切换至gpt-xxxx或者api2d-xxxx": "Please switch the model to gpt-xxxx or api2d-xxxx first.",
|
"请先把模型切换至gpt-xxxx或者api2d-xxxx": "Please switch the model to gpt-xxxx or api2d-xxxx first.",
|
||||||
"路径或网址": "Path or URL",
|
"路径或网址": "Path or URL",
|
||||||
"*代表通配符": "* represents a wildcard",
|
"*代表通配符": "* represents a wildcard",
|
||||||
@ -1483,632 +1484,5 @@
|
|||||||
"请提交新问题": "新しい問題を提出してください",
|
"请提交新问题": "新しい問題を提出してください",
|
||||||
"您正在调用一个": "あなたは呼び出しています",
|
"您正在调用一个": "あなたは呼び出しています",
|
||||||
"请编辑以下文本": "以下のテキストを編集してください",
|
"请编辑以下文本": "以下のテキストを編集してください",
|
||||||
"常见协议无非socks5h/http": "一般的なプロトコルはsocks5h/http以外ありません",
|
"常见协议无非socks5h/http": "一般的なプロトコルはsocks5h/http以外ありません"
|
||||||
"Latex英文纠错": "LatexEnglishErrorCorrection",
|
|
||||||
"连接bing搜索回答问题": "ConnectBingSearchAnswerQuestion",
|
|
||||||
"联网的ChatGPT_bing版": "OnlineChatGPT_BingVersion",
|
|
||||||
"总结音视频": "SummarizeAudioVideo",
|
|
||||||
"动画生成": "GenerateAnimation",
|
|
||||||
"数学动画生成manim": "GenerateMathematicalAnimationManim",
|
|
||||||
"Markdown翻译指定语言": "TranslateMarkdownSpecifiedLanguage",
|
|
||||||
"知识库问答": "KnowledgeBaseQuestionAnswer",
|
|
||||||
"Langchain知识库": "LangchainKnowledgeBase",
|
|
||||||
"读取知识库作答": "ReadKnowledgeBaseAnswer",
|
|
||||||
"交互功能模板函数": "InteractiveFunctionTemplateFunction",
|
|
||||||
"交互功能函数模板": "InteractiveFunctionFunctionTemplate",
|
|
||||||
"Latex英文纠错加PDF对比": "LatexEnglishErrorCorrectionWithPDFComparison",
|
|
||||||
"Latex输出PDF结果": "LatexOutputPDFResult",
|
|
||||||
"Latex翻译中文并重新编译PDF": "TranslateChineseAndRecompilePDF",
|
|
||||||
"语音助手": "VoiceAssistant",
|
|
||||||
"微调数据集生成": "FineTuneDatasetGeneration",
|
|
||||||
"chatglm微调工具": "ChatGLMFineTuningTool",
|
|
||||||
"启动微调": "StartFineTuning",
|
|
||||||
"sprint亮靛": "SprintAzureIndigo",
|
|
||||||
"专业词汇声明": "ProfessionalVocabularyDeclaration",
|
|
||||||
"Latex精细分解与转化": "LatexDetailedDecompositionAndConversion",
|
|
||||||
"编译Latex": "CompileLatex",
|
|
||||||
"将代码转为动画": "コードをアニメーションに変換する",
|
|
||||||
"解析arxiv网址失败": "arxivのURLの解析に失敗しました",
|
|
||||||
"其他模型转化效果未知": "他のモデルの変換効果は不明です",
|
|
||||||
"把文件复制过去": "ファイルをコピーする",
|
|
||||||
"!!!如果需要运行量化版本": "!!!量子化バージョンを実行する必要がある場合",
|
|
||||||
"报错信息如下. 如果是与网络相关的问题": "エラーメッセージは次のとおりです。ネットワークに関連する問題の場合",
|
|
||||||
"请检查ALIYUN_TOKEN和ALIYUN_APPKEY是否过期": "ALIYUN_TOKENとALIYUN_APPKEYの有効期限を確認してください",
|
|
||||||
"编译结束": "コンパイル終了",
|
|
||||||
"只读": "読み取り専用",
|
|
||||||
"模型选择是": "モデルの選択は",
|
|
||||||
"正在从github下载资源": "GitHubからリソースをダウンロードしています",
|
|
||||||
"同时分解长句": "同時に長い文を分解する",
|
|
||||||
"寻找主tex文件": "メインのtexファイルを検索する",
|
|
||||||
"例如您可以将以下命令复制到下方": "たとえば、以下のコマンドを下にコピーできます",
|
|
||||||
"使用中文总结音频“": "中国語で音声を要約する",
|
|
||||||
"此处填API密钥": "ここにAPIキーを入力してください",
|
|
||||||
"裁剪输入": "入力をトリミングする",
|
|
||||||
"当前语言模型温度设定": "現在の言語モデルの温度設定",
|
|
||||||
"history 是之前的对话列表": "historyは以前の対話リストです",
|
|
||||||
"对输入的word文档进行摘要生成": "入力されたWord文書の要約を生成する",
|
|
||||||
"输入问题后点击该插件": "質問を入力した後、このプラグインをクリックします",
|
|
||||||
"仅在Windows系统进行了测试": "Windowsシステムでのみテストされています",
|
|
||||||
"reverse 操作必须放在最后": "reverse操作は最後に配置する必要があります",
|
|
||||||
"即将编译PDF": "PDFをコンパイルする予定です",
|
|
||||||
"执行错误": "エラーが発生しました",
|
|
||||||
"段音频完成了吗": "セグメントのオーディオは完了しましたか",
|
|
||||||
"然后重启程序": "それからプログラムを再起動してください",
|
|
||||||
"是所有LLM的通用接口": "これはすべてのLLMの共通インターフェースです",
|
|
||||||
"当前报错的latex代码处于第": "現在のエラーのあるLaTeXコードは第",
|
|
||||||
"🏃♂️🏃♂️🏃♂️ 子进程执行": "🏃♂️🏃♂️🏃♂️ サブプロセスの実行",
|
|
||||||
"用来描述你的要求": "要求を説明するために使用されます",
|
|
||||||
"原始PDF编译是否成功": "元のPDFのコンパイルは成功しましたか",
|
|
||||||
"本地Latex论文精细翻译": "ローカルのLaTeX論文の詳細な翻訳",
|
|
||||||
"设置OpenAI密钥和模型": "OpenAIキーとモデルの設定",
|
|
||||||
"如果使用ChatGLM2微调模型": "ChatGLM2ファインチューニングモデルを使用する場合",
|
|
||||||
"项目Github地址 \\url{https": "プロジェクトのGithubアドレス \\url{https",
|
|
||||||
"将前后断行符脱离": "前後の改行文字を削除します",
|
|
||||||
"该项目的Latex主文件是": "このプロジェクトのLaTeXメインファイルは",
|
|
||||||
"编译已经开始": "コンパイルが開始されました",
|
|
||||||
"*{\\scriptsize\\textbf{警告": "*{\\scriptsize\\textbf{警告",
|
|
||||||
"从一批文件": "一連のファイルから",
|
|
||||||
"等待用户的再次调用": "ユーザーの再呼び出しを待っています",
|
|
||||||
"目前仅支持GPT3.5/GPT4": "現在、GPT3.5/GPT4のみをサポートしています",
|
|
||||||
"如果一句话小于7个字": "1つの文が7文字未満の場合",
|
|
||||||
"目前对机器学习类文献转化效果最好": "現在、機械学習の文献変換効果が最も良いです",
|
|
||||||
"寻找主文件": "メインファイルを検索中",
|
|
||||||
"解除插件状态": "プラグインの状態を解除します",
|
|
||||||
"默认为Chinese": "デフォルトはChineseです",
|
|
||||||
"依赖不足": "不足の依存関係",
|
|
||||||
"编译文献交叉引用": "文献の相互参照をコンパイルする",
|
|
||||||
"对不同latex源文件扣分": "異なるLaTeXソースファイルに罰則を課す",
|
|
||||||
"再列出用户可能提出的三个问题": "ユーザーが提出する可能性のある3つの問題を再リスト化する",
|
|
||||||
"建议排查": "トラブルシューティングの提案",
|
|
||||||
"生成时间戳": "タイムスタンプの生成",
|
|
||||||
"检查config中的AVAIL_LLM_MODELS选项": "configのAVAIL_LLM_MODELSオプションを確認する",
|
|
||||||
"chatglmft 没有 sys_prompt 接口": "chatglmftにはsys_promptインターフェースがありません",
|
|
||||||
"在一个异步线程中采集音频": "非同期スレッドでオーディオを収集する",
|
|
||||||
"初始化插件状态": "プラグインの状態を初期化する",
|
|
||||||
"内含已经翻译的Tex文档": "翻訳済みのTexドキュメントが含まれています",
|
|
||||||
"请注意自我隐私保护哦!": "プライバシー保護に注意してください!",
|
|
||||||
"使用正则表达式查找半行注释": "正規表現を使用して半行コメントを検索する",
|
|
||||||
"不能正常加载ChatGLMFT的参数!": "ChatGLMFTのパラメータを正常にロードできません!",
|
|
||||||
"首先你在中文语境下通读整篇论文": "まず、中国語の文脈で論文全体を読んでください",
|
|
||||||
"如 绿帽子*深蓝色衬衫*黑色运动裤": "例えば、緑の帽子*濃い青のシャツ*黒のスポーツパンツ",
|
|
||||||
"默认为default": "デフォルトはdefaultです",
|
|
||||||
"将": "置き換える",
|
|
||||||
"使用 Unsplash API": "Unsplash APIを使用する",
|
|
||||||
"会被加在你的输入之前": "あなたの入力の前に追加されます",
|
|
||||||
"还需要填写组织": "組織を入力する必要があります",
|
|
||||||
"test_LangchainKnowledgeBase读取": "test_LangchainKnowledgeBaseの読み込み",
|
|
||||||
"目前不支持历史消息查询": "現在、過去のメッセージのクエリはサポートされていません",
|
|
||||||
"临时存储用于调试": "デバッグ用の一時的なストレージ",
|
|
||||||
"提取总结": "テキストの翻訳",
|
|
||||||
"每秒采样数量": "テキストの翻訳",
|
|
||||||
"但通常不会出现在正文": "テキストの翻訳",
|
|
||||||
"通过调用conversations_open方法打开一个频道": "テキストの翻訳",
|
|
||||||
"导致输出不完整": "テキストの翻訳",
|
|
||||||
"获取已打开频道的最新消息并返回消息列表": "テキストの翻訳",
|
|
||||||
"Tex源文件缺失!": "テキストの翻訳",
|
|
||||||
"如果需要使用Slack Claude": "テキストの翻訳",
|
|
||||||
"扭转的范围": "テキストの翻訳",
|
|
||||||
"使用latexdiff生成论文转化前后对比": "テキストの翻訳",
|
|
||||||
"--读取文件": "テキストの翻訳",
|
|
||||||
"调用openai api 使用whisper-1模型": "テキストの翻訳",
|
|
||||||
"避免遗忘导致死锁": "テキストの翻訳",
|
|
||||||
"在多Tex文档中": "テキストの翻訳",
|
|
||||||
"失败时": "テキストの翻訳",
|
|
||||||
"然后转移到指定的另一个路径中": "テキストの翻訳",
|
|
||||||
"使用Newbing": "テキストの翻訳",
|
|
||||||
"的参数": "テキストの翻訳",
|
|
||||||
"后者是OPENAI的结束条件": "テキストの翻訳",
|
|
||||||
"构建知识库": "テキストの翻訳",
|
|
||||||
"吸收匿名公式": "テキストの翻訳",
|
|
||||||
"前缀": "テキストの翻訳",
|
|
||||||
"会直接转到该函数": "テキストの翻訳",
|
|
||||||
"Claude失败": "テキストの翻訳",
|
|
||||||
"P.S. 但愿没人把latex模板放在里面传进来": "P.S. 但愿没人把latex模板放在里面传进来",
|
|
||||||
"临时地启动代理网络": "临时地启动代理网络",
|
|
||||||
"读取文件内容到内存": "読み込んだファイルの内容をメモリに保存する",
|
|
||||||
"总结音频": "音声をまとめる",
|
|
||||||
"没有找到任何可读取文件": "読み込み可能なファイルが見つかりません",
|
|
||||||
"获取Slack消息失败": "Slackメッセージの取得に失敗しました",
|
|
||||||
"用黑色标注转换区": "黒い注釈で変換エリアをマークする",
|
|
||||||
"此插件处于开发阶段": "このプラグインは開発中です",
|
|
||||||
"其他操作系统表现未知": "他のオペレーティングシステムの動作は不明です",
|
|
||||||
"返回找到的第一个": "最初に見つかったものを返す",
|
|
||||||
"发现已经存在翻译好的PDF文档": "翻訳済みのPDFドキュメントが既に存在することがわかりました",
|
|
||||||
"不包含任何可用于": "使用できるものは含まれていません",
|
|
||||||
"发送到openai音频解析终端": "openai音声解析端に送信する",
|
|
||||||
"========================================= 插件主程序2 =====================================================": "========================================= プラグインメインプログラム2 =====================================================",
|
|
||||||
"正在重试": "再試行中",
|
|
||||||
"从而更全面地理解项目的整体功能": "プロジェクトの全体的な機能をより理解するために",
|
|
||||||
"正在等您说完问题": "質問が完了するのをお待ちしています",
|
|
||||||
"使用教程详情见 request_llm/README.md": "使用方法の詳細については、request_llm/README.mdを参照してください",
|
|
||||||
"6.25 加入判定latex模板的代码": "6.25 テンプレートの判定コードを追加",
|
|
||||||
"找不到任何音频或视频文件": "音声またはビデオファイルが見つかりません",
|
|
||||||
"请求GPT模型的": "GPTモデルのリクエスト",
|
|
||||||
"行": "行",
|
|
||||||
"分析上述回答": "上記の回答を分析する",
|
|
||||||
"如果要使用ChatGLMFT": "ChatGLMFTを使用する場合",
|
|
||||||
"上传Latex项目": "Latexプロジェクトをアップロードする",
|
|
||||||
"如参考文献、脚注、图注等": "参考文献、脚注、図のキャプションなど",
|
|
||||||
"未配置": "設定されていません",
|
|
||||||
"请在此处给出自定义翻译命令": "カスタム翻訳コマンドをここに入力してください",
|
|
||||||
"第二部分": "第2部分",
|
|
||||||
"解压失败! 需要安装pip install py7zr来解压7z文件": "解凍に失敗しました!7zファイルを解凍するにはpip install py7zrをインストールする必要があります",
|
|
||||||
"吸收在42行以内的begin-end组合": "42行以内のbegin-endの組み合わせを取り込む",
|
|
||||||
"Latex文件融合完成": "Latexファイルの統合が完了しました",
|
|
||||||
"输出html调试文件": "HTMLデバッグファイルの出力",
|
|
||||||
"论文概况": "論文の概要",
|
|
||||||
"修复括号": "括弧の修復",
|
|
||||||
"赋予插件状态": "プラグインの状態を付与する",
|
|
||||||
"标注节点的行数范围": "ノードの行数範囲を注釈する",
|
|
||||||
"MOSS can understand and communicate fluently in the language chosen by the user such as English and 中文. MOSS can perform any language-based tasks.": "MOSSは、ユーザーが選択した言語(英語や中文など)でスムーズに理解し、コミュニケーションすることができます。MOSSは、言語に基づくさまざまなタスクを実行できます。",
|
|
||||||
"LLM_MODEL是默认选中的模型": "LLM_MODELはデフォルトで選択されたモデルです",
|
|
||||||
"配合前缀可以把你的输入内容用引号圈起来": "接頭辞と組み合わせて、入力内容を引用符で囲むことができます",
|
|
||||||
"获取关键词": "キーワードの取得",
|
|
||||||
"本项目现已支持OpenAI和Azure的api-key": "このプロジェクトは、OpenAIおよびAzureのAPIキーをサポートしています",
|
|
||||||
"欢迎使用 MOSS 人工智能助手!": "MOSS AIアシスタントをご利用いただきありがとうございます!",
|
|
||||||
"在执行完成之后": "実行が完了した後",
|
|
||||||
"正在听您讲话": "お話をお聞きしています",
|
|
||||||
"Claude回复的片段": "Claudeの返信の一部",
|
|
||||||
"返回": "戻る",
|
|
||||||
"期望格式例如": "期待される形式の例",
|
|
||||||
"gpt 多线程请求": "GPTマルチスレッドリクエスト",
|
|
||||||
"当前工作路径为": "現在の作業パスは",
|
|
||||||
"该PDF由GPT-Academic开源项目调用大语言模型+Latex翻译插件一键生成": "このPDFはGPT-Academicオープンソースプロジェクトによって大規模言語モデル+Latex翻訳プラグインを使用して一括生成されました",
|
|
||||||
"解决插件锁定时的界面显示问题": "プラグインのロック時のインターフェース表示の問題を解決する",
|
|
||||||
"默认 secondary": "デフォルトのセカンダリ",
|
|
||||||
"会把列表拆解": "リストを分解します",
|
|
||||||
"暂时不支持历史消息": "一時的に歴史メッセージはサポートされていません",
|
|
||||||
"或者重启之后再度尝试": "または再起動後に再試行してください",
|
|
||||||
"吸收其他杂项": "他の雑項を吸収する",
|
|
||||||
"双手离开鼠标键盘吧": "両手をマウスとキーボードから離してください",
|
|
||||||
"建议更换代理协议": "プロキシプロトコルの変更をお勧めします",
|
|
||||||
"音频助手": "オーディオアシスタント",
|
|
||||||
"请耐心等待": "お待ちください",
|
|
||||||
"翻译结果": "翻訳結果",
|
|
||||||
"请在此处追加更细致的矫错指令": "ここにより詳細なエラー修正命令を追加してください",
|
|
||||||
"编译原始PDF": "元のPDFをコンパイルする",
|
|
||||||
"-构建知识库": "-ナレッジベースの構築",
|
|
||||||
"删除中间文件夹": "中間フォルダを削除する",
|
|
||||||
"这段代码定义了一个名为TempProxy的空上下文管理器": "このコードはTempProxyという名前の空のコンテキストマネージャを定義しています",
|
|
||||||
"参数说明": "パラメータの説明",
|
|
||||||
"正在预热文本向量化模组": "テキストベクトル化モジュールのプリヒート中",
|
|
||||||
"函数插件": "関数プラグイン",
|
|
||||||
"右下角更换模型菜单中可切换openai": "右下のモデルメニューでopenaiを切り替えることができます",
|
|
||||||
"先上传数据集": "まずデータセットをアップロードしてください",
|
|
||||||
"LatexEnglishErrorCorrection+高亮修正位置": "テキストの翻訳",
|
|
||||||
"正在构建知识库": "テキストの翻訳",
|
|
||||||
"用红色标注处保留区": "テキストの翻訳",
|
|
||||||
"安装Claude的依赖": "テキストの翻訳",
|
|
||||||
"已禁用": "テキストの翻訳",
|
|
||||||
"是否在提交时自动清空输入框": "テキストの翻訳",
|
|
||||||
"GPT 学术优化": "テキストの翻訳",
|
|
||||||
"需要特殊依赖": "テキストの翻訳",
|
|
||||||
"test_联网回答问题": "テキストの翻訳",
|
|
||||||
"除非您是论文的原作者": "テキストの翻訳",
|
|
||||||
"即可见": "テキストの翻訳",
|
|
||||||
"解析为简体中文": "テキストの翻訳",
|
|
||||||
"解析整个Python项目": "テキストの翻訳",
|
|
||||||
"========================================= 插件主程序1 =====================================================": "テキストの翻訳",
|
|
||||||
"当前参数": "テキストの翻訳",
|
|
||||||
"处理个别特殊插件的锁定状态": "テキストの翻訳",
|
|
||||||
"已知某些代码的局部作用是": "テキストの翻訳",
|
|
||||||
"请务必用 pip install -r requirements.txt 指令安装依赖": "テキストの翻訳",
|
|
||||||
"安装": "テキストの翻訳",
|
|
||||||
"请登录OpenAI查看详情 https": "テキストの翻訳",
|
|
||||||
"必须包含documentclass": "テキストの翻訳",
|
|
||||||
"极少数情况下": "テキストの翻訳",
|
|
||||||
"并将返回的频道ID保存在属性CHANNEL_ID中": "テキストの翻訳",
|
|
||||||
"您的 API_KEY 不满足任何一种已知的密钥格式": "テキストの翻訳",
|
|
||||||
"-预热文本向量化模组": "テキストの翻訳",
|
|
||||||
"什么都没有": "テキストの翻訳",
|
|
||||||
"等待GPT响应": "テキストの翻訳",
|
|
||||||
"请尝试把以下指令复制到高级参数区": "テキストの翻訳",
|
|
||||||
"模型参数": "テキストの翻訳",
|
|
||||||
"先删除": "テキストの翻訳",
|
|
||||||
"响应中": "テキストの翻訳",
|
|
||||||
"开始接收chatglmft的回复": "テキストの翻訳",
|
|
||||||
"手动指定语言": "テキストの翻訳",
|
|
||||||
"获取线程锁": "テキストの翻訳",
|
|
||||||
"当前大语言模型": "テキストの翻訳",
|
|
||||||
"段音频的第": "テキストの翻訳",
|
|
||||||
"正在编译对比PDF": "テキストの翻訳",
|
|
||||||
"根据需要切换prompt": "テキストの翻訳",
|
|
||||||
"取评分最高者返回": "テキストの翻訳",
|
|
||||||
"如果您是论文原作者": "テキストの翻訳",
|
|
||||||
"段音频的主要内容": "テキストの翻訳",
|
|
||||||
"为啥chatgpt会把cite里面的逗号换成中文逗号呀": "テキストの翻訳",
|
|
||||||
"为每一位访问的用户赋予一个独一无二的uuid编码": "テキストの翻訳",
|
|
||||||
"将每次对话记录写入Markdown格式的文件中": "テキストの翻訳",
|
|
||||||
"ChatGLMFT尚未加载": "テキストの翻訳",
|
|
||||||
"切割音频文件": "テキストの翻訳",
|
|
||||||
"例如 f37f30e0f9934c34a992f6f64f7eba4f": "テキストの翻訳",
|
|
||||||
"work_folder = Latex预处理": "テキストの翻訳",
|
|
||||||
"出问题了": "問題が発生しました",
|
|
||||||
"等待Claude响应中": "Claudeの応答を待っています",
|
|
||||||
"增强稳健性": "信頼性を向上させる",
|
|
||||||
"赋予插件锁定 锁定插件回调路径": "プラグインにコールバックパスをロックする",
|
|
||||||
"将多文件tex工程融合为一个巨型tex": "複数のファイルのtexプロジェクトを1つの巨大なtexに統合する",
|
|
||||||
"参考文献转Bib": "参考文献をBibに変換する",
|
|
||||||
"由于提问含不合规内容被Azure过滤": "質問が規則に違反しているため、Azureによってフィルタリングされました",
|
|
||||||
"读取优先级": "優先度を読み取る",
|
|
||||||
"格式如org-xxxxxxxxxxxxxxxxxxxxxxxx": "形式はorg-xxxxxxxxxxxxxxxxxxxxxxxxのようです",
|
|
||||||
"辅助gpt生成代码": "GPTのコード生成を補助する",
|
|
||||||
"读取音频文件": "音声ファイルを読み取る",
|
|
||||||
"输入arxivID": "arxivIDを入力する",
|
|
||||||
"转化PDF编译是否成功": "PDFのコンパイルが成功したかどうかを変換する",
|
|
||||||
"Call ChatGLMFT fail 不能正常加载ChatGLMFT的参数": "ChatGLMFTのパラメータを正常にロードできませんでした",
|
|
||||||
"创建AcsClient实例": "AcsClientのインスタンスを作成する",
|
|
||||||
"将 chatglm 直接对齐到 chatglm2": "chatglmをchatglm2に直接整列させる",
|
|
||||||
"要求": "要求",
|
|
||||||
"子任务失败时的重试次数": "サブタスクが失敗した場合のリトライ回数",
|
|
||||||
"请求子进程": "サブプロセスを要求する",
|
|
||||||
"按钮是否可见": "ボタンが表示可能かどうか",
|
|
||||||
"将 \\include 命令转换为 \\input 命令": "\\includeコマンドを\\inputコマンドに変換する",
|
|
||||||
"用户填3": "ユーザーが3を入力する",
|
|
||||||
"后面是英文逗号": "後ろに英語のカンマがあります",
|
|
||||||
"吸收iffalse注释": "iffalseコメントを吸収する",
|
|
||||||
"请稍候": "お待ちください",
|
|
||||||
"摘要生成后的文档路径": "要約生成後のドキュメントのパス",
|
|
||||||
"主程序即将开始": "メインプログラムがすぐに開始されます",
|
|
||||||
"处理历史信息": "履歴情報の処理",
|
|
||||||
"根据给定的切割时长将音频文件切割成多个片段": "指定された分割時間に基づいてオーディオファイルを複数のセグメントに分割する",
|
|
||||||
"解决部分词汇翻译不准确的问题": "一部の用語の翻訳の不正確さを解決する",
|
|
||||||
"即将退出": "すぐに終了します",
|
|
||||||
"用于给一小段代码上代理": "一部のコードにプロキシを適用するために使用されます",
|
|
||||||
"提取文件扩展名": "ファイルの拡張子を抽出する",
|
|
||||||
"目前支持的格式": "現在サポートされている形式",
|
|
||||||
"第一次调用": "最初の呼び出し",
|
|
||||||
"异步方法": "非同期メソッド",
|
|
||||||
"P.S. 顺便把Latex的注释去除": "P.S. LaTeXのコメントを削除する",
|
|
||||||
"构建完成": "ビルドが完了しました",
|
|
||||||
"缺少": "不足しています",
|
|
||||||
"建议暂时不要使用": "一時的に使用しないことをお勧めします",
|
|
||||||
"对比PDF编译是否成功": "PDFのコンパイルが成功したかどうかを比較する",
|
|
||||||
"填入azure openai api的密钥": "Azure OpenAI APIのキーを入力してください",
|
|
||||||
"功能尚不稳定": "機能はまだ安定していません",
|
|
||||||
"则跳过GPT请求环节": "GPTリクエストのスキップ",
|
|
||||||
"即不处理之前的对话历史": "以前の対話履歴を処理しない",
|
|
||||||
"非Openai官方接口返回了错误": "非公式のOpenAI APIがエラーを返しました",
|
|
||||||
"其他类型文献转化效果未知": "他のタイプの文献の変換効果は不明です",
|
|
||||||
"给出一些判定模板文档的词作为扣分项": "テンプレートドキュメントの単語を減点項目として提供する",
|
|
||||||
"找 API_ORG 设置项": "API_ORGの設定項目を検索します",
|
|
||||||
"调用函数": "関数を呼び出します",
|
|
||||||
"需要手动安装新增的依赖库": "新しい依存ライブラリを手動でインストールする必要があります",
|
|
||||||
"或者使用此插件继续上传更多文件": "または、このプラグインを使用してさらにファイルをアップロードします",
|
|
||||||
"640个字节为一组": "640バイトごとにグループ化します",
|
|
||||||
"逆转出错的段落": "エラーのあるパラグラフを逆転させます",
|
|
||||||
"对话助手函数插件": "対話アシスタント関数プラグイン",
|
|
||||||
"前者是API2D的结束条件": "前者はAPI2Dの終了条件です",
|
|
||||||
"终端": "ターミナル",
|
|
||||||
"仅调试": "デバッグのみ",
|
|
||||||
"论文": "論文",
|
|
||||||
"想象一个穿着者": "着用者を想像してください",
|
|
||||||
"音频内容是": "音声の内容は",
|
|
||||||
"如果需要使用AZURE 详情请见额外文档 docs\\use_azure.md": "AZUREを使用する必要がある場合は、詳細については別のドキュメント docs\\use_azure.md を参照してください",
|
|
||||||
"请先将.doc文档转换为.docx文档": ".docドキュメントを.docxドキュメントに変換してください",
|
|
||||||
"请查看终端的输出或耐心等待": "ターミナルの出力を確認するか、お待ちください",
|
|
||||||
"初始化音频采集线程": "オーディオキャプチャスレッドを初期化します",
|
|
||||||
"用该压缩包+ConversationHistoryArchive进行反馈": "この圧縮ファイル+ConversationHistoryArchiveを使用してフィードバックします",
|
|
||||||
"阿里云实时语音识别 配置难度较高 仅建议高手用户使用 参考 https": "阿里云リアルタイム音声認識の設定は難しいため、上級ユーザーのみに推奨されます 参考 https",
|
|
||||||
"多线程翻译开始": "マルチスレッド翻訳が開始されました",
|
|
||||||
"只有GenerateImage和生成图像相关": "GenerateImageと関連する画像の生成のみ",
|
|
||||||
"代理数据解析失败": "プロキシデータの解析に失敗しました",
|
|
||||||
"建议使用英文单词": "英単語の使用をお勧めします",
|
|
||||||
"功能描述": "機能の説明",
|
|
||||||
"读 docs\\use_azure.md": "ドキュメントを読む",
|
|
||||||
"将消耗较长时间下载中文向量化模型": "中国語のベクトル化モデルをダウンロードするのに時間がかかります",
|
|
||||||
"表示频道ID": "チャネルIDを表示する",
|
|
||||||
"未知指令": "不明なコマンド",
|
|
||||||
"包含documentclass关键字": "documentclassキーワードを含む",
|
|
||||||
"中读取数据构建知识库": "データを読み取って知識ベースを構築する",
|
|
||||||
"远程云服务器部署": "リモートクラウドサーバーにデプロイする",
|
|
||||||
"输入部分太自由": "入力が自由すぎる",
|
|
||||||
"读取pdf文件": "PDFファイルを読み込む",
|
|
||||||
"将两个PDF拼接": "2つのPDFを結合する",
|
|
||||||
"默认值为1000": "デフォルト値は1000です",
|
|
||||||
"写出文件": "ファイルに書き出す",
|
|
||||||
"生成的视频文件路径": "生成されたビデオファイルのパス",
|
|
||||||
"Arixv论文精细翻译": "Arixv論文の詳細な翻訳",
|
|
||||||
"用latex编译为PDF对修正处做高亮": "LaTeXでコンパイルしてPDFに修正をハイライトする",
|
|
||||||
"点击“停止”键可终止程序": "「停止」ボタンをクリックしてプログラムを終了できます",
|
|
||||||
"否则将导致每个人的Claude问询历史互相渗透": "さもないと、各人のClaudeの問い合わせ履歴が相互に侵入します",
|
|
||||||
"音频文件名": "オーディオファイル名",
|
|
||||||
"的参数!": "のパラメータ!",
|
|
||||||
"对话历史": "対話履歴",
|
|
||||||
"当下一次用户提交时": "次のユーザーの提出時に",
|
|
||||||
"数学GenerateAnimation": "数学GenerateAnimation",
|
|
||||||
"如果要使用Claude": "Claudeを使用する場合は",
|
|
||||||
"请向下翻": "下にスクロールしてください",
|
|
||||||
"报告已经添加到右侧“文件上传区”": "報告は右側の「ファイルアップロードエリア」に追加されました",
|
|
||||||
"删除整行的空注释": "空のコメントを含む行を削除する",
|
|
||||||
"建议直接在API_KEY处填写": "API_KEYの場所に直接入力することをお勧めします",
|
|
||||||
"暗色模式 / 亮色模式": "ダークモード/ライトモード",
|
|
||||||
"做一些外观色彩上的调整": "外観の色調整を行う",
|
|
||||||
"请切换至“KnowledgeBaseQuestionAnswer”插件进行知识库访问": "ナレッジベースのアクセスには「KnowledgeBaseQuestionAnswer」プラグインに切り替えてください",
|
|
||||||
"它*必须*被包含在AVAIL_LLM_MODELS列表中": "それはAVAIL_LLM_MODELSリストに含まれている必要があります",
|
|
||||||
"并设置参数": "パラメータを設定する",
|
|
||||||
"待处理的word文档路径": "処理待ちのWord文書のパス",
|
|
||||||
"调用缓存": "キャッシュを呼び出す",
|
|
||||||
"片段": "フラグメント",
|
|
||||||
"否则结束循环": "それ以外の場合はループを終了する",
|
|
||||||
"请对下面的音频片段做概述": "以下のオーディオフラグメントについて概要を作成してください",
|
|
||||||
"高危设置! 常规情况下不要修改! 通过修改此设置": "高リスクの設定!通常は変更しないでください!この設定を変更することで",
|
|
||||||
"插件锁定中": "プラグインがロックされています",
|
|
||||||
"开始": "開始",
|
|
||||||
"但请查收结果": "結果を確認してください",
|
|
||||||
"刷新Gradio前端界面": "Gradioフロントエンドインターフェースをリフレッシュする",
|
|
||||||
"批量SummarizeAudioVideo": "オーディオビデオを一括要約する",
|
|
||||||
"一个单实例装饰器": "単一のインスタンスデコレータ",
|
|
||||||
"Claude响应异常": "Claudeの応答が異常です",
|
|
||||||
"但内部用stream的方法避免中途网线被掐": "ただし、途中でネットワーク接続が切断されることを避けるために、内部ではストリームを使用しています",
|
|
||||||
"检查USE_PROXY": "USE_PROXYを確認する",
|
|
||||||
"永远给定None": "常にNoneを指定する",
|
|
||||||
"报告如何远程获取": "報告のリモート取得方法",
|
|
||||||
"您可以到Github Issue区": "GithubのIssueエリアにアクセスできます",
|
|
||||||
"如果只询问1个大语言模型": "1つの大規模言語モデルにのみ質問する場合",
|
|
||||||
"为了防止大语言模型的意外谬误产生扩散影响": "大規模言語モデルの誤った結果が広がるのを防ぐために",
|
|
||||||
"编译BibTex": "BibTexのコンパイル",
|
|
||||||
"⭐多线程方法": "マルチスレッドの方法",
|
|
||||||
"推荐http": "httpをおすすめします",
|
|
||||||
"如果要使用": "使用する場合",
|
|
||||||
"的单词": "の単語",
|
|
||||||
"如果本地使用不建议加这个": "ローカルで使用する場合はお勧めしません",
|
|
||||||
"避免线程阻塞": "スレッドのブロックを回避する",
|
|
||||||
"吸收title与作者以上的部分": "タイトルと著者以上の部分を吸収する",
|
|
||||||
"作者": "著者",
|
|
||||||
"5刀": "5ドル",
|
|
||||||
"ChatGLMFT响应异常": "ChatGLMFTの応答異常",
|
|
||||||
"才能继续下面的步骤": "次の手順に進むために",
|
|
||||||
"对这个人外貌、身处的环境、内心世界、过去经历进行描写": "この人の外見、環境、内面世界、過去の経験について描写する",
|
|
||||||
"找不到微调模型检查点": "ファインチューニングモデルのチェックポイントが見つかりません",
|
|
||||||
"请仔细鉴别并以原文为准": "注意深く確認し、元のテキストを参照してください",
|
|
||||||
"计算文件总时长和切割点": "ファイルの総時間とカットポイントを計算する",
|
|
||||||
"我将为您查找相关壁纸": "関連する壁紙を検索します",
|
|
||||||
"此插件Windows支持最佳": "このプラグインはWindowsに最適です",
|
|
||||||
"请输入关键词": "キーワードを入力してください",
|
|
||||||
"以下所有配置也都支持利用环境变量覆写": "以下のすべての設定は環境変数を使用して上書きすることもサポートしています",
|
|
||||||
"尝试第": "第#",
|
|
||||||
"开始生成动画": "アニメーションの生成を開始します",
|
|
||||||
"免费": "無料",
|
|
||||||
"我好!": "私は元気です!",
|
|
||||||
"str类型": "strタイプ",
|
|
||||||
"生成数学动画": "数学アニメーションの生成",
|
|
||||||
"GPT结果已输出": "GPTの結果が出力されました",
|
|
||||||
"PDF文件所在的路径": "PDFファイルのパス",
|
|
||||||
"源码自译解": "ソースコードの自動翻訳解析",
|
|
||||||
"格式如org-123456789abcdefghijklmno的": "org-123456789abcdefghijklmnoの形式",
|
|
||||||
"请对这部分内容进行语法矫正": "この部分の内容に文法修正を行ってください",
|
|
||||||
"调用whisper模型音频转文字": "whisperモデルを使用して音声をテキストに変換する",
|
|
||||||
"编译转化后的PDF": "変換されたPDFをコンパイルする",
|
|
||||||
"将音频解析为简体中文": "音声を簡体字中国語に解析する",
|
|
||||||
"删除或修改歧义文件": "曖昧なファイルを削除または修正する",
|
|
||||||
"ChatGLMFT消耗大量的内存": "ChatGLMFTは大量のメモリを消費します",
|
|
||||||
"图像生成所用到的提示文本": "画像生成に使用されるヒントテキスト",
|
|
||||||
"如果已经存在": "既に存在する場合",
|
|
||||||
"以下是一篇学术论文的基础信息": "以下は学術論文の基本情報です",
|
|
||||||
"解压失败! 需要安装pip install rarfile来解压rar文件": "解凍に失敗しました!rarファイルを解凍するにはpip install rarfileをインストールする必要があります",
|
|
||||||
"一般是文本过长": "通常、テキストが長すぎます",
|
|
||||||
"单线程": "シングルスレッド",
|
|
||||||
"Linux下必须使用Docker安装": "LinuxではDockerを使用してインストールする必要があります",
|
|
||||||
"请先上传文件素材": "まずファイル素材をアップロードしてください",
|
|
||||||
"如果分析错误": "もし解析エラーがある場合",
|
|
||||||
"快捷的调试函数": "便利なデバッグ関数",
|
|
||||||
"欢迎使用 MOSS 人工智能助手!输入内容即可进行对话": "MOSS AIアシスタントをご利用いただきありがとうございます!入力内容を入力すると、対話ができます",
|
|
||||||
"json等": "jsonなど",
|
|
||||||
"--读取参数": "--パラメータの読み込み",
|
|
||||||
"⭐单线程方法": "⭐シングルスレッドメソッド",
|
|
||||||
"请用一句话概括这些文件的整体功能": "これらのファイルの全体的な機能を一文で要約してください",
|
|
||||||
"用于灵活调整复杂功能的各种参数": "複雑な機能を柔軟に調整するためのさまざまなパラメータ",
|
|
||||||
"默认 False": "デフォルトはFalseです",
|
|
||||||
"生成中文PDF": "中国語のPDFを生成する",
|
|
||||||
"正在处理": "処理中",
|
|
||||||
"需要被切割的音频文件名": "分割する必要のある音声ファイル名",
|
|
||||||
"根据文本使用GPT模型生成相应的图像": "テキストに基づいてGPTモデルを使用して対応する画像を生成する",
|
|
||||||
"可选": "オプション",
|
|
||||||
"Aliyun音频服务异常": "Aliyunオーディオサービスの異常",
|
|
||||||
"尝试下载": "ダウンロードを試みる",
|
|
||||||
"需Latex": "LaTeXが必要です",
|
|
||||||
"拆分过长的Markdown文件": "長すぎるMarkdownファイルを分割する",
|
|
||||||
"当前支持的格式包括": "現在サポートされている形式には",
|
|
||||||
"=================================== 工具函数 ===============================================": "=================================== ユーティリティ関数 ===============================================",
|
|
||||||
"所有音频都总结完成了吗": "すべてのオーディオが要約されましたか",
|
|
||||||
"没有设置ANTHROPIC_API_KEY": "ANTHROPIC_API_KEYが設定されていません",
|
|
||||||
"详见项目主README.md": "詳細はプロジェクトのメインREADME.mdを参照してください",
|
|
||||||
"使用": "使用する",
|
|
||||||
"P.S. 其他可用的模型还包括": "P.S. 其他可用的模型还包括",
|
|
||||||
"保证括号正确": "保证括号正确",
|
|
||||||
"或代理节点": "或代理节点",
|
|
||||||
"整理结果为压缩包": "整理结果为压缩包",
|
|
||||||
"实时音频采集": "实时音频采集",
|
|
||||||
"获取回复": "获取回复",
|
|
||||||
"插件可读取“输入区”文本/路径作为参数": "插件可读取“输入区”文本/路径作为参数",
|
|
||||||
"请讲话": "请讲话",
|
|
||||||
"将文件复制一份到下载区": "将文件复制一份到下载区",
|
|
||||||
"from crazy_functions.虚空终端 import 终端": "from crazy_functions.虚空终端 import 终端",
|
|
||||||
"这个paper有个input命令文件名大小写错误!": "这个paper有个input命令文件名大小写错误!",
|
|
||||||
"解除插件锁定": "解除插件锁定",
|
|
||||||
"不能加载Claude组件": "不能加载Claude组件",
|
|
||||||
"如果有必要": "如果有必要",
|
|
||||||
"禁止移除或修改此警告": "禁止移除或修改此警告",
|
|
||||||
"然后进行问答": "然后进行问答",
|
|
||||||
"响应异常": "响应异常",
|
|
||||||
"使用英文": "使用英文",
|
|
||||||
"add gpt task 创建子线程请求gpt": "add gpt task 创建子线程请求gpt",
|
|
||||||
"实际得到格式": "实际得到格式",
|
|
||||||
"请继续分析其他源代码": "请继续分析其他源代码",
|
|
||||||
"”的主要内容": "”的主要内容",
|
|
||||||
"防止proxies单独起作用": "防止proxies单独起作用",
|
|
||||||
"临时地激活代理网络": "临时地激活代理网络",
|
|
||||||
"屏蔽空行和太短的句子": "屏蔽空行和太短的句子",
|
|
||||||
"把某个路径下所有文件压缩": "把某个路径下所有文件压缩",
|
|
||||||
"您需要首先调用构建知识库": "您需要首先调用构建知识库",
|
|
||||||
"翻译-": "翻译-",
|
|
||||||
"Newbing 请求失败": "Newbing 请求失败",
|
|
||||||
"次编译": "次编译",
|
|
||||||
"后缀": "后缀",
|
|
||||||
"文本碎片重组为完整的tex片段": "文本碎片重组为完整的tex片段",
|
|
||||||
"待注入的知识库名称id": "待注入的知识库名称id",
|
|
||||||
"消耗时间的函数": "消耗时间的函数",
|
|
||||||
"You are associated with a deactivated account. OpenAI以账户失效为由": "You are associated with a deactivated account. OpenAI以账户失效为由",
|
|
||||||
"成功啦": "成功啦",
|
|
||||||
"音频文件的路径": "音频文件的路径",
|
|
||||||
"英文Latex项目全文纠错": "英文Latex项目全文纠错",
|
|
||||||
"将子线程的gpt结果写入chatbot": "将子线程的gpt结果写入chatbot",
|
|
||||||
"开始最终总结": "开始最终总结",
|
|
||||||
"调用": "调用",
|
|
||||||
"正在锁定插件": "正在锁定插件",
|
|
||||||
"记住当前的label": "记住当前的label",
|
|
||||||
"根据自然语言执行插件命令": "根据自然语言执行插件命令",
|
|
||||||
"response中会携带traceback报错信息": "response中会携带traceback报错信息",
|
|
||||||
"避免多用户干扰": "避免多用户干扰",
|
|
||||||
"顺利完成": "顺利完成",
|
|
||||||
"详情见https": "详情见https",
|
|
||||||
"清空label": "ラベルをクリアする",
|
|
||||||
"这需要一段时间计算": "これには時間がかかります",
|
|
||||||
"找不到": "見つかりません",
|
|
||||||
"消耗大量的内存": "大量のメモリを消費する",
|
|
||||||
"安装方法https": "インストール方法https",
|
|
||||||
"为发送请求做准备": "リクエストの準備をする",
|
|
||||||
"第1次尝试": "1回目の試み",
|
|
||||||
"检查结果": "結果をチェックする",
|
|
||||||
"精细切分latex文件": "LaTeXファイルを細かく分割する",
|
|
||||||
"api2d等请求源": "api2dなどのリクエストソース",
|
|
||||||
"填入你亲手写的部署名": "あなたが手書きしたデプロイ名を入力してください",
|
|
||||||
"给出指令": "指示を与える",
|
|
||||||
"请问什么是质子": "プロトンとは何ですか",
|
|
||||||
"请直接去该路径下取回翻译结果": "直接そのパスに移動して翻訳結果を取得してください",
|
|
||||||
"等待Claude回复的片段": "Claudeの返信を待っているフラグメント",
|
|
||||||
"Latex没有安装": "LaTeXがインストールされていません",
|
|
||||||
"文档越长耗时越长": "ドキュメントが長いほど時間がかかります",
|
|
||||||
"没有阿里云语音识别APPKEY和TOKEN": "阿里雲の音声認識のAPPKEYとTOKENがありません",
|
|
||||||
"分析结果": "結果を分析する",
|
|
||||||
"请立即终止程序": "プログラムを即座に終了してください",
|
|
||||||
"正在尝试自动安装": "自動インストールを試みています",
|
|
||||||
"请直接提交即可": "直接提出してください",
|
|
||||||
"将指定目录下的PDF文件从英文翻译成中文": "指定されたディレクトリ内のPDFファイルを英語から中国語に翻訳する",
|
|
||||||
"请查收结果": "結果を確認してください",
|
|
||||||
"上下布局": "上下布局",
|
|
||||||
"此处可以输入解析提示": "此处可以输入解析提示",
|
|
||||||
"前面是中文逗号": "前面是中文逗号",
|
|
||||||
"的依赖": "的依赖",
|
|
||||||
"材料如下": "材料如下",
|
|
||||||
"欢迎加REAME中的QQ联系开发者": "欢迎加REAME中的QQ联系开发者",
|
|
||||||
"开始下载": "開始ダウンロード",
|
|
||||||
"100字以内": "100文字以内",
|
|
||||||
"创建request": "リクエストの作成",
|
|
||||||
"创建存储切割音频的文件夹": "切り取られた音声を保存するフォルダの作成",
|
|
||||||
"⭐主进程执行": "⭐メインプロセスの実行",
|
|
||||||
"音频解析结果": "音声解析結果",
|
|
||||||
"Your account is not active. OpenAI以账户失效为由": "アカウントがアクティブではありません。OpenAIはアカウントの無効化を理由にしています",
|
|
||||||
"虽然PDF生成失败了": "PDFの生成に失敗しました",
|
|
||||||
"如果这里报错": "ここでエラーが発生した場合",
|
|
||||||
"前面是中文冒号": "前面は中国語のコロンです",
|
|
||||||
"SummarizeAudioVideo内容": "SummarizeAudioVideoの内容",
|
|
||||||
"openai的官方KEY需要伴随组织编码": "openaiの公式KEYは組織コードと一緒に必要です",
|
|
||||||
"是本次输入": "これは今回の入力です",
|
|
||||||
"色彩主体": "色彩の主体",
|
|
||||||
"Markdown翻译": "Markdownの翻訳",
|
|
||||||
"会被加在你的输入之后": "あなたの入力の後に追加されます",
|
|
||||||
"失败啦": "失敗しました",
|
|
||||||
"每个切割音频片段的时长": "各切り取り音声の長さ",
|
|
||||||
"拆分过长的latex片段": "原始文本",
|
|
||||||
"待提取的知识库名称id": "原始文本",
|
|
||||||
"在这里放一些网上搜集的demo": "原始文本",
|
|
||||||
"环境变量配置格式见docker-compose.yml": "原始文本",
|
|
||||||
"Claude组件初始化成功": "原始文本",
|
|
||||||
"尚未加载": "原始文本",
|
|
||||||
"等待Claude响应": "原始文本",
|
|
||||||
"重组": "原始文本",
|
|
||||||
"将文件添加到chatbot cookie中": "原始文本",
|
|
||||||
"回答完问题后": "原始文本",
|
|
||||||
"将根据报错信息修正tex源文件并重试": "原始文本",
|
|
||||||
"是否在触发时清除历史": "原始文本",
|
|
||||||
"尝试执行Latex指令失败": "原始文本",
|
|
||||||
"默认 True": "原始文本",
|
|
||||||
"文本碎片重组为完整的tex文件": "原始文本",
|
|
||||||
"注意事项": "原始文本",
|
|
||||||
"您接下来不能再使用其他插件了": "原始文本",
|
|
||||||
"属性": "原始文本",
|
|
||||||
"正在编译PDF文档": "原始文本",
|
|
||||||
"提取视频中的音频": "原始文本",
|
|
||||||
"正在同时咨询ChatGPT和ChatGLM……": "原始文本",
|
|
||||||
"Chuanhu-Small-and-Beautiful主题": "原始文本",
|
|
||||||
"版权归原文作者所有": "原始文本",
|
|
||||||
"如果程序停顿5分钟以上": "原始文本",
|
|
||||||
"请输入要翻译成哪种语言": "日本語",
|
|
||||||
"以秒为单位": "秒単位で",
|
|
||||||
"请以以下方式load模型!!!": "以下の方法でモデルをロードしてください!!!",
|
|
||||||
"使用时": "使用時",
|
|
||||||
"对这个人外貌、身处的环境、内心世界、人设进行描写": "この人の外見、環境、内面世界、キャラクターを描写する",
|
|
||||||
"例如翻译、解释代码、润色等等": "例えば翻訳、コードの説明、修正など",
|
|
||||||
"多线程Demo": "マルチスレッドデモ",
|
|
||||||
"不能正常加载": "正常にロードできません",
|
|
||||||
"还原部分原文": "一部の元のテキストを復元する",
|
|
||||||
"可以将自身的状态存储到cookie中": "自身の状態をcookieに保存することができます",
|
|
||||||
"释放线程锁": "スレッドロックを解放する",
|
|
||||||
"当前知识库内的有效文件": "現在のナレッジベース内の有効なファイル",
|
|
||||||
"也是可读的": "読み取り可能です",
|
|
||||||
"等待ChatGLMFT响应中": "ChatGLMFTの応答を待っています",
|
|
||||||
"输入 stop 以终止对话": "stopを入力して対話を終了します",
|
|
||||||
"对整个Latex项目进行纠错": "全体のLatexプロジェクトを修正する",
|
|
||||||
"报错信息": "エラーメッセージ",
|
|
||||||
"下载pdf文件未成功": "PDFファイルのダウンロードに失敗しました",
|
|
||||||
"正在加载Claude组件": "Claudeコンポーネントを読み込んでいます",
|
|
||||||
"格式": "フォーマット",
|
|
||||||
"Claude响应缓慢": "Claudeの応答が遅い",
|
|
||||||
"该选项即将被弃用": "このオプションはまもなく廃止されます",
|
|
||||||
"正常状态": "正常な状態",
|
|
||||||
"中文Bing版": "中国語Bing版",
|
|
||||||
"代理网络配置": "プロキシネットワークの設定",
|
|
||||||
"Openai 限制免费用户每分钟20次请求": "Openaiは無料ユーザーに対して1分間に20回のリクエスト制限を設けています",
|
|
||||||
"gpt写的": "gptで書かれた",
|
|
||||||
"向已打开的频道发送一条文本消息": "既に開いているチャンネルにテキストメッセージを送信する",
|
|
||||||
"缺少ChatGLMFT的依赖": "ChatGLMFTの依存関係が不足しています",
|
|
||||||
"注意目前不能多人同时调用Claude接口": "現在、複数の人が同時にClaudeインターフェースを呼び出すことはできません",
|
|
||||||
"或者不在环境变量PATH中": "または環境変数PATHに存在しません",
|
|
||||||
"提问吧! 但注意": "質問してください!ただし注意してください",
|
|
||||||
"因此选择GenerateImage函数": "したがって、GenerateImage関数を選択します",
|
|
||||||
"无法找到一个主Tex文件": "メインのTexファイルが見つかりません",
|
|
||||||
"转化PDF编译已经成功": "PDF変換コンパイルが成功しました",
|
|
||||||
"因为在同一个频道里存在多人使用时历史消息渗透问题": "同じチャンネルで複数の人が使用する場合、過去のメッセージが漏洩する問題があります",
|
|
||||||
"SlackClient类用于与Slack API进行交互": "SlackClientクラスはSlack APIとのインタラクションに使用されます",
|
|
||||||
"如果存在调试缓存文件": "デバッグキャッシュファイルが存在する場合",
|
|
||||||
"举例": "例を挙げる",
|
|
||||||
"无需填写": "記入する必要はありません",
|
|
||||||
"配置教程&视频教程": "設定チュートリアル&ビデオチュートリアル",
|
|
||||||
"最后一步处理": "最後のステップの処理",
|
|
||||||
"定位主Latex文件": "メインのLatexファイルを特定する",
|
|
||||||
"暂不提交": "一時的に提出しない",
|
|
||||||
"由于最为关键的转化PDF编译失败": "最も重要なPDF変換コンパイルが失敗したため",
|
|
||||||
"用第二人称": "第二人称を使用する",
|
|
||||||
"例如 RoPlZrM88DnAFkZK": "例えば RoPlZrM88DnAFkZK",
|
|
||||||
"没有设置ANTHROPIC_API_KEY选项": "ANTHROPIC_API_KEYオプションが設定されていません",
|
|
||||||
"找不到任何.tex文件": "テキストの翻訳",
|
|
||||||
"请您不要删除或修改这行警告": "テキストの翻訳",
|
|
||||||
"只有第二步成功": "テキストの翻訳",
|
|
||||||
"调用Claude时": "テキストの翻訳",
|
|
||||||
"输入 clear 以清空对话历史": "テキストの翻訳",
|
|
||||||
"= 2 通过一些Latex模板中常见": "テキストの翻訳",
|
|
||||||
"没给定指令": "テキストの翻訳",
|
|
||||||
"还原原文": "テキストの翻訳",
|
|
||||||
"自定义API KEY格式": "テキストの翻訳",
|
|
||||||
"防止丢失最后一条消息": "テキストの翻訳",
|
|
||||||
"方法": "テキストの翻訳",
|
|
||||||
"压缩包": "テキストの翻訳",
|
|
||||||
"对各个llm模型进行单元测试": "テキストの翻訳",
|
|
||||||
"导入依赖失败": "テキストの翻訳",
|
|
||||||
"详情信息见requirements.txt": "テキストの翻訳",
|
|
||||||
"翻译内容可靠性无保障": "テキストの翻訳",
|
|
||||||
"刷新页面即可以退出KnowledgeBaseQuestionAnswer模式": "テキストの翻訳",
|
|
||||||
"上传本地文件/压缩包供函数插件调用": "テキストの翻訳",
|
|
||||||
"循环监听已打开频道的消息": "テキストの翻訳",
|
|
||||||
"一个包含所有切割音频片段文件路径的列表": "テキストの翻訳",
|
|
||||||
"检测到arxiv文档连接": "テキストの翻訳",
|
|
||||||
"P.S. 顺便把CTEX塞进去以支持中文": "テキストの翻訳",
|
|
||||||
"后面是英文冒号": "テキストの翻訳",
|
|
||||||
"上传文件自动修正路径": "テキストの翻訳",
|
|
||||||
"实现消息发送、接收等功能": "メッセージの送受信などの機能を実現する",
|
|
||||||
"改变输入参数的顺序与结构": "入力パラメータの順序と構造を変更する",
|
|
||||||
"正在精细切分latex文件": "LaTeXファイルを細かく分割しています",
|
|
||||||
"读取文件": "ファイルを読み込んでいます"
|
|
||||||
}
|
}
|
||||||
@ -2213,66 +2213,5 @@
|
|||||||
"“喂狗”": "“喂狗”",
|
"“喂狗”": "“喂狗”",
|
||||||
"第4步": "第4步",
|
"第4步": "第4步",
|
||||||
"退出": "退出",
|
"退出": "退出",
|
||||||
"使用 Unsplash API": "使用 Unsplash API",
|
"使用 Unsplash API": "使用 Unsplash API"
|
||||||
"非Openai官方接口返回了错误": "非Openai官方接口返回了错误",
|
|
||||||
"用来描述你的要求": "用來描述你的要求",
|
|
||||||
"自定义API KEY格式": "自定義API KEY格式",
|
|
||||||
"前缀": "前綴",
|
|
||||||
"会被加在你的输入之前": "會被加在你的輸入之前",
|
|
||||||
"api2d等请求源": "api2d等請求源",
|
|
||||||
"高危设置! 常规情况下不要修改! 通过修改此设置": "高危設置!常規情況下不要修改!通過修改此設置",
|
|
||||||
"即将编译PDF": "即將編譯PDF",
|
|
||||||
"默认 secondary": "默認 secondary",
|
|
||||||
"正在从github下载资源": "正在從github下載資源",
|
|
||||||
"响应异常": "響應異常",
|
|
||||||
"我好!": "我好!",
|
|
||||||
"无需填写": "無需填寫",
|
|
||||||
"缺少": "缺少",
|
|
||||||
"请问什么是质子": "請問什麼是質子",
|
|
||||||
"如果要使用": "如果要使用",
|
|
||||||
"重组": "重組",
|
|
||||||
"一个单实例装饰器": "一個單實例裝飾器",
|
|
||||||
"的参数!": "的參數!",
|
|
||||||
"🏃♂️🏃♂️🏃♂️ 子进程执行": "🏃♂️🏃♂️🏃♂️ 子進程執行",
|
|
||||||
"失败时": "失敗時",
|
|
||||||
"没有设置ANTHROPIC_API_KEY选项": "沒有設置ANTHROPIC_API_KEY選項",
|
|
||||||
"并设置参数": "並設置參數",
|
|
||||||
"格式": "格式",
|
|
||||||
"按钮是否可见": "按鈕是否可見",
|
|
||||||
"即可见": "即可見",
|
|
||||||
"创建request": "創建request",
|
|
||||||
"的依赖": "的依賴",
|
|
||||||
"⭐主进程执行": "⭐主進程執行",
|
|
||||||
"最后一步处理": "最後一步處理",
|
|
||||||
"没有设置ANTHROPIC_API_KEY": "沒有設置ANTHROPIC_API_KEY",
|
|
||||||
"的参数": "的參數",
|
|
||||||
"逆转出错的段落": "逆轉出錯的段落",
|
|
||||||
"本项目现已支持OpenAI和Azure的api-key": "本項目現已支持OpenAI和Azure的api-key",
|
|
||||||
"前者是API2D的结束条件": "前者是API2D的結束條件",
|
|
||||||
"增强稳健性": "增強穩健性",
|
|
||||||
"消耗大量的内存": "消耗大量的內存",
|
|
||||||
"您的 API_KEY 不满足任何一种已知的密钥格式": "您的API_KEY不滿足任何一種已知的密鑰格式",
|
|
||||||
"⭐单线程方法": "⭐單線程方法",
|
|
||||||
"是否在触发时清除历史": "是否在觸發時清除歷史",
|
|
||||||
"⭐多线程方法": "多線程方法",
|
|
||||||
"不能正常加载": "無法正常加載",
|
|
||||||
"举例": "舉例",
|
|
||||||
"即不处理之前的对话历史": "即不處理之前的對話歷史",
|
|
||||||
"尚未加载": "尚未加載",
|
|
||||||
"防止proxies单独起作用": "防止proxies單獨起作用",
|
|
||||||
"默认 False": "默認 False",
|
|
||||||
"检查USE_PROXY": "檢查USE_PROXY",
|
|
||||||
"响应中": "響應中",
|
|
||||||
"扭转的范围": "扭轉的範圍",
|
|
||||||
"后缀": "後綴",
|
|
||||||
"调用": "調用",
|
|
||||||
"创建AcsClient实例": "創建AcsClient實例",
|
|
||||||
"安装": "安裝",
|
|
||||||
"会被加在你的输入之后": "會被加在你的輸入之後",
|
|
||||||
"配合前缀可以把你的输入内容用引号圈起来": "配合前綴可以把你的輸入內容用引號圈起來",
|
|
||||||
"例如翻译、解释代码、润色等等": "例如翻譯、解釋代碼、潤色等等",
|
|
||||||
"后者是OPENAI的结束条件": "後者是OPENAI的結束條件",
|
|
||||||
"标注节点的行数范围": "標註節點的行數範圍",
|
|
||||||
"默认 True": "默認 True",
|
|
||||||
"将两个PDF拼接": "將兩個PDF拼接"
|
|
||||||
}
|
}
|
||||||
@ -28,16 +28,6 @@ ALIYUN_APPKEY = "RoPlZrM88DnAFkZK" # 此appkey已经失效
|
|||||||
参考 https://help.aliyun.com/document_detail/450255.html
|
参考 https://help.aliyun.com/document_detail/450255.html
|
||||||
先有阿里云开发者账号,登录之后,需要开通 智能语音交互 的功能,可以免费获得一个token,然后在 全部项目 中,创建一个项目,可以获得一个appkey.
|
先有阿里云开发者账号,登录之后,需要开通 智能语音交互 的功能,可以免费获得一个token,然后在 全部项目 中,创建一个项目,可以获得一个appkey.
|
||||||
|
|
||||||
- 进阶功能
|
|
||||||
进一步填写ALIYUN_ACCESSKEY和ALIYUN_SECRET实现自动获取ALIYUN_TOKEN
|
|
||||||
```
|
|
||||||
ALIYUN_APPKEY = "RoP1ZrM84DnAFkZK"
|
|
||||||
ALIYUN_TOKEN = ""
|
|
||||||
ALIYUN_ACCESSKEY = "LTAI5q6BrFUzoRXVGUWnekh1"
|
|
||||||
ALIYUN_SECRET = "eHmI20AVWIaQZ0CiTD2bGQVsaP9i68"
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
## 3.启动
|
## 3.启动
|
||||||
|
|
||||||
启动gpt-academic `python main.py`
|
启动gpt-academic `python main.py`
|
||||||
@ -58,7 +48,7 @@ III `[把特殊软件(如腾讯会议)的外放声音用VoiceMeeter截留]`
|
|||||||
|
|
||||||
VI 两种音频监听模式切换时,需要刷新页面才有效。
|
VI 两种音频监听模式切换时,需要刷新页面才有效。
|
||||||
|
|
||||||
VII 非localhost运行+非https情况下无法打开录音功能的坑:https://blog.csdn.net/weixin_39461487/article/details/109594434
|
|
||||||
|
|
||||||
## 5.点击函数插件区“实时音频采集” 或者其他音频交互功能
|
## 5.点击函数插件区“实时音频采集” 或者其他音频交互功能
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
6
main.py
6
main.py
@ -22,10 +22,8 @@ def main():
|
|||||||
# 问询记录, python 版本建议3.9+(越新越好)
|
# 问询记录, python 版本建议3.9+(越新越好)
|
||||||
import logging, uuid
|
import logging, uuid
|
||||||
os.makedirs("gpt_log", exist_ok=True)
|
os.makedirs("gpt_log", exist_ok=True)
|
||||||
try:logging.basicConfig(filename="gpt_log/chat_secrets.log", level=logging.INFO, encoding="utf-8", format="%(asctime)s %(levelname)-8s %(message)s", datefmt="%Y-%m-%d %H:%M:%S")
|
try:logging.basicConfig(filename="gpt_log/chat_secrets.log", level=logging.INFO, encoding="utf-8")
|
||||||
except:logging.basicConfig(filename="gpt_log/chat_secrets.log", level=logging.INFO, format="%(asctime)s %(levelname)-8s %(message)s", datefmt="%Y-%m-%d %H:%M:%S")
|
except:logging.basicConfig(filename="gpt_log/chat_secrets.log", level=logging.INFO)
|
||||||
# Disable logging output from the 'httpx' logger
|
|
||||||
logging.getLogger("httpx").setLevel(logging.WARNING)
|
|
||||||
print("所有问询记录将自动保存在本地目录./gpt_log/chat_secrets.log, 请注意自我隐私保护哦!")
|
print("所有问询记录将自动保存在本地目录./gpt_log/chat_secrets.log, 请注意自我隐私保护哦!")
|
||||||
|
|
||||||
# 一些普通功能模块
|
# 一些普通功能模块
|
||||||
|
|||||||
@ -3,18 +3,16 @@
|
|||||||
|
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
1. modify config.py, set your LLM_MODEL and API_KEY(s) to provide access to OPENAI (or any other LLM model provider)
|
1. modify LANG
|
||||||
|
|
||||||
2. modify LANG (below ↓)
|
|
||||||
LANG = "English"
|
LANG = "English"
|
||||||
|
|
||||||
3. modify TransPrompt (below ↓)
|
2. modify TransPrompt
|
||||||
TransPrompt = f"Replace each json value `#` with translated results in English, e.g., \"原始文本\":\"TranslatedText\". Keep Json format. Do not answer #."
|
TransPrompt = f"Replace each json value `#` with translated results in English, e.g., \"原始文本\":\"TranslatedText\". Keep Json format. Do not answer #."
|
||||||
|
|
||||||
4. Run `python multi_language.py`.
|
3. Run `python multi_language.py`.
|
||||||
Note: You need to run it multiple times to increase translation coverage because GPT makes mistakes sometimes.
|
Note: You need to run it multiple times to increase translation coverage because GPT makes mistakes sometimes.
|
||||||
|
|
||||||
5. Find the translated program in `multi-language\English\*`
|
4. Find the translated program in `multi-language\English\*`
|
||||||
|
|
||||||
P.S.
|
P.S.
|
||||||
|
|
||||||
|
|||||||
@ -248,6 +248,7 @@ if "moss" in AVAIL_LLM_MODELS:
|
|||||||
if "stack-claude" in AVAIL_LLM_MODELS:
|
if "stack-claude" in AVAIL_LLM_MODELS:
|
||||||
from .bridge_stackclaude import predict_no_ui_long_connection as claude_noui
|
from .bridge_stackclaude import predict_no_ui_long_connection as claude_noui
|
||||||
from .bridge_stackclaude import predict as claude_ui
|
from .bridge_stackclaude import predict as claude_ui
|
||||||
|
# claude
|
||||||
model_info.update({
|
model_info.update({
|
||||||
"stack-claude": {
|
"stack-claude": {
|
||||||
"fn_with_ui": claude_ui,
|
"fn_with_ui": claude_ui,
|
||||||
@ -262,6 +263,7 @@ if "newbing-free" in AVAIL_LLM_MODELS:
|
|||||||
try:
|
try:
|
||||||
from .bridge_newbingfree import predict_no_ui_long_connection as newbingfree_noui
|
from .bridge_newbingfree import predict_no_ui_long_connection as newbingfree_noui
|
||||||
from .bridge_newbingfree import predict as newbingfree_ui
|
from .bridge_newbingfree import predict as newbingfree_ui
|
||||||
|
# claude
|
||||||
model_info.update({
|
model_info.update({
|
||||||
"newbing-free": {
|
"newbing-free": {
|
||||||
"fn_with_ui": newbingfree_ui,
|
"fn_with_ui": newbingfree_ui,
|
||||||
@ -278,6 +280,7 @@ if "newbing" in AVAIL_LLM_MODELS: # same with newbing-free
|
|||||||
try:
|
try:
|
||||||
from .bridge_newbingfree import predict_no_ui_long_connection as newbingfree_noui
|
from .bridge_newbingfree import predict_no_ui_long_connection as newbingfree_noui
|
||||||
from .bridge_newbingfree import predict as newbingfree_ui
|
from .bridge_newbingfree import predict as newbingfree_ui
|
||||||
|
# claude
|
||||||
model_info.update({
|
model_info.update({
|
||||||
"newbing": {
|
"newbing": {
|
||||||
"fn_with_ui": newbingfree_ui,
|
"fn_with_ui": newbingfree_ui,
|
||||||
@ -294,6 +297,7 @@ if "chatglmft" in AVAIL_LLM_MODELS: # same with newbing-free
|
|||||||
try:
|
try:
|
||||||
from .bridge_chatglmft import predict_no_ui_long_connection as chatglmft_noui
|
from .bridge_chatglmft import predict_no_ui_long_connection as chatglmft_noui
|
||||||
from .bridge_chatglmft import predict as chatglmft_ui
|
from .bridge_chatglmft import predict as chatglmft_ui
|
||||||
|
# claude
|
||||||
model_info.update({
|
model_info.update({
|
||||||
"chatglmft": {
|
"chatglmft": {
|
||||||
"fn_with_ui": chatglmft_ui,
|
"fn_with_ui": chatglmft_ui,
|
||||||
@ -306,22 +310,7 @@ if "chatglmft" in AVAIL_LLM_MODELS: # same with newbing-free
|
|||||||
})
|
})
|
||||||
except:
|
except:
|
||||||
print(trimmed_format_exc())
|
print(trimmed_format_exc())
|
||||||
if "internlm" in AVAIL_LLM_MODELS:
|
|
||||||
try:
|
|
||||||
from .bridge_internlm import predict_no_ui_long_connection as internlm_noui
|
|
||||||
from .bridge_internlm import predict as internlm_ui
|
|
||||||
model_info.update({
|
|
||||||
"internlm": {
|
|
||||||
"fn_with_ui": internlm_ui,
|
|
||||||
"fn_without_ui": internlm_noui,
|
|
||||||
"endpoint": None,
|
|
||||||
"max_token": 4096,
|
|
||||||
"tokenizer": tokenizer_gpt35,
|
|
||||||
"token_cnt": get_token_num_gpt35,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
except:
|
|
||||||
print(trimmed_format_exc())
|
|
||||||
|
|
||||||
def LLM_CATCH_EXCEPTION(f):
|
def LLM_CATCH_EXCEPTION(f):
|
||||||
"""
|
"""
|
||||||
|
|||||||
@ -37,23 +37,15 @@ class GetGLMHandle(Process):
|
|||||||
# 子进程执行
|
# 子进程执行
|
||||||
# 第一次运行,加载参数
|
# 第一次运行,加载参数
|
||||||
retry = 0
|
retry = 0
|
||||||
LOCAL_MODEL_QUANT, device = get_conf('LOCAL_MODEL_QUANT', 'LOCAL_MODEL_DEVICE')
|
|
||||||
|
|
||||||
if LOCAL_MODEL_QUANT == "INT4": # INT4
|
|
||||||
_model_name_ = "THUDM/chatglm2-6b-int4"
|
|
||||||
elif LOCAL_MODEL_QUANT == "INT8": # INT8
|
|
||||||
_model_name_ = "THUDM/chatglm2-6b-int8"
|
|
||||||
else:
|
|
||||||
_model_name_ = "THUDM/chatglm2-6b" # FP16
|
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
if self.chatglm_model is None:
|
if self.chatglm_model is None:
|
||||||
self.chatglm_tokenizer = AutoTokenizer.from_pretrained(_model_name_, trust_remote_code=True)
|
self.chatglm_tokenizer = AutoTokenizer.from_pretrained("THUDM/chatglm2-6b", trust_remote_code=True)
|
||||||
|
device, = get_conf('LOCAL_MODEL_DEVICE')
|
||||||
if device=='cpu':
|
if device=='cpu':
|
||||||
self.chatglm_model = AutoModel.from_pretrained(_model_name_, trust_remote_code=True).float()
|
self.chatglm_model = AutoModel.from_pretrained("THUDM/chatglm2-6b", trust_remote_code=True).float()
|
||||||
else:
|
else:
|
||||||
self.chatglm_model = AutoModel.from_pretrained(_model_name_, trust_remote_code=True).half().cuda()
|
self.chatglm_model = AutoModel.from_pretrained("THUDM/chatglm2-6b", trust_remote_code=True).half().cuda()
|
||||||
self.chatglm_model = self.chatglm_model.eval()
|
self.chatglm_model = self.chatglm_model.eval()
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
@ -144,8 +136,11 @@ def predict(inputs, llm_kwargs, plugin_kwargs, chatbot, history=[], system_promp
|
|||||||
return
|
return
|
||||||
|
|
||||||
if additional_fn is not None:
|
if additional_fn is not None:
|
||||||
from core_functional import handle_core_functionality
|
import core_functional
|
||||||
inputs, history = handle_core_functionality(additional_fn, inputs, history, chatbot)
|
importlib.reload(core_functional) # 热更新prompt
|
||||||
|
core_functional = core_functional.get_core_functions()
|
||||||
|
if "PreProcess" in core_functional[additional_fn]: inputs = core_functional[additional_fn]["PreProcess"](inputs) # 获取预处理函数(如果有的话)
|
||||||
|
inputs = core_functional[additional_fn]["Prefix"] + inputs + core_functional[additional_fn]["Suffix"]
|
||||||
|
|
||||||
# 处理历史信息
|
# 处理历史信息
|
||||||
history_feedin = []
|
history_feedin = []
|
||||||
|
|||||||
@ -185,8 +185,11 @@ def predict(inputs, llm_kwargs, plugin_kwargs, chatbot, history=[], system_promp
|
|||||||
return
|
return
|
||||||
|
|
||||||
if additional_fn is not None:
|
if additional_fn is not None:
|
||||||
from core_functional import handle_core_functionality
|
import core_functional
|
||||||
inputs, history = handle_core_functionality(additional_fn, inputs, history, chatbot)
|
importlib.reload(core_functional) # 热更新prompt
|
||||||
|
core_functional = core_functional.get_core_functions()
|
||||||
|
if "PreProcess" in core_functional[additional_fn]: inputs = core_functional[additional_fn]["PreProcess"](inputs) # 获取预处理函数(如果有的话)
|
||||||
|
inputs = core_functional[additional_fn]["Prefix"] + inputs + core_functional[additional_fn]["Suffix"]
|
||||||
|
|
||||||
# 处理历史信息
|
# 处理历史信息
|
||||||
history_feedin = []
|
history_feedin = []
|
||||||
|
|||||||
@ -129,8 +129,11 @@ def predict(inputs, llm_kwargs, plugin_kwargs, chatbot, history=[], system_promp
|
|||||||
return
|
return
|
||||||
|
|
||||||
if additional_fn is not None:
|
if additional_fn is not None:
|
||||||
from core_functional import handle_core_functionality
|
import core_functional
|
||||||
inputs, history = handle_core_functionality(additional_fn, inputs, history, chatbot)
|
importlib.reload(core_functional) # 热更新prompt
|
||||||
|
core_functional = core_functional.get_core_functions()
|
||||||
|
if "PreProcess" in core_functional[additional_fn]: inputs = core_functional[additional_fn]["PreProcess"](inputs) # 获取预处理函数(如果有的话)
|
||||||
|
inputs = core_functional[additional_fn]["Prefix"] + inputs + core_functional[additional_fn]["Suffix"]
|
||||||
|
|
||||||
raw_input = inputs
|
raw_input = inputs
|
||||||
logging.info(f'[raw_input] {raw_input}')
|
logging.info(f'[raw_input] {raw_input}')
|
||||||
@ -171,10 +174,9 @@ def predict(inputs, llm_kwargs, plugin_kwargs, chatbot, history=[], system_promp
|
|||||||
chunk = next(stream_response)
|
chunk = next(stream_response)
|
||||||
except StopIteration:
|
except StopIteration:
|
||||||
# 非OpenAI官方接口的出现这样的报错,OpenAI和API2D不会走这里
|
# 非OpenAI官方接口的出现这样的报错,OpenAI和API2D不会走这里
|
||||||
chunk_decoded = chunk.decode()
|
from toolbox import regular_txt_to_markdown; tb_str = '```\n' + trimmed_format_exc() + '```'
|
||||||
error_msg = chunk_decoded
|
chatbot[-1] = (chatbot[-1][0], f"[Local Message] 远程返回错误: \n\n{tb_str} \n\n{regular_txt_to_markdown(chunk.decode())}")
|
||||||
chatbot, history = handle_error(inputs, llm_kwargs, chatbot, history, chunk_decoded, error_msg)
|
yield from update_ui(chatbot=chatbot, history=history, msg="远程返回错误:" + chunk.decode()) # 刷新界面
|
||||||
yield from update_ui(chatbot=chatbot, history=history, msg="非Openai官方接口返回了错误:" + chunk.decode()) # 刷新界面
|
|
||||||
return
|
return
|
||||||
|
|
||||||
# print(chunk.decode()[6:])
|
# print(chunk.decode()[6:])
|
||||||
@ -185,7 +187,7 @@ def predict(inputs, llm_kwargs, plugin_kwargs, chatbot, history=[], system_promp
|
|||||||
if chunk:
|
if chunk:
|
||||||
try:
|
try:
|
||||||
chunk_decoded = chunk.decode()
|
chunk_decoded = chunk.decode()
|
||||||
# 前者是API2D的结束条件,后者是OPENAI的结束条件
|
# 前者API2D的
|
||||||
if ('data: [DONE]' in chunk_decoded) or (len(json.loads(chunk_decoded[6:])['choices'][0]["delta"]) == 0):
|
if ('data: [DONE]' in chunk_decoded) or (len(json.loads(chunk_decoded[6:])['choices'][0]["delta"]) == 0):
|
||||||
# 判定为数据流的结束,gpt_replying_buffer也写完了
|
# 判定为数据流的结束,gpt_replying_buffer也写完了
|
||||||
logging.info(f'[response] {gpt_replying_buffer}')
|
logging.info(f'[response] {gpt_replying_buffer}')
|
||||||
@ -198,44 +200,40 @@ def predict(inputs, llm_kwargs, plugin_kwargs, chatbot, history=[], system_promp
|
|||||||
history[-1] = gpt_replying_buffer
|
history[-1] = gpt_replying_buffer
|
||||||
chatbot[-1] = (history[-2], history[-1])
|
chatbot[-1] = (history[-2], history[-1])
|
||||||
yield from update_ui(chatbot=chatbot, history=history, msg=status_text) # 刷新界面
|
yield from update_ui(chatbot=chatbot, history=history, msg=status_text) # 刷新界面
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
traceback.print_exc()
|
||||||
yield from update_ui(chatbot=chatbot, history=history, msg="Json解析不合常规") # 刷新界面
|
yield from update_ui(chatbot=chatbot, history=history, msg="Json解析不合常规") # 刷新界面
|
||||||
chunk = get_full_error(chunk, stream_response)
|
chunk = get_full_error(chunk, stream_response)
|
||||||
chunk_decoded = chunk.decode()
|
chunk_decoded = chunk.decode()
|
||||||
error_msg = chunk_decoded
|
error_msg = chunk_decoded
|
||||||
chatbot, history = handle_error(inputs, llm_kwargs, chatbot, history, chunk_decoded, error_msg)
|
openai_website = ' 请登录OpenAI查看详情 https://platform.openai.com/signup'
|
||||||
yield from update_ui(chatbot=chatbot, history=history, msg="Json异常" + error_msg) # 刷新界面
|
if "reduce the length" in error_msg:
|
||||||
print(error_msg)
|
if len(history) >= 2: history[-1] = ""; history[-2] = "" # 清除当前溢出的输入:history[-2] 是本次输入, history[-1] 是本次输出
|
||||||
return
|
history = clip_history(inputs=inputs, history=history, tokenizer=model_info[llm_kwargs['llm_model']]['tokenizer'],
|
||||||
|
|
||||||
def handle_error(inputs, llm_kwargs, chatbot, history, chunk_decoded, error_msg):
|
|
||||||
from .bridge_all import model_info
|
|
||||||
openai_website = ' 请登录OpenAI查看详情 https://platform.openai.com/signup'
|
|
||||||
if "reduce the length" in error_msg:
|
|
||||||
if len(history) >= 2: history[-1] = ""; history[-2] = "" # 清除当前溢出的输入:history[-2] 是本次输入, history[-1] 是本次输出
|
|
||||||
history = clip_history(inputs=inputs, history=history, tokenizer=model_info[llm_kwargs['llm_model']]['tokenizer'],
|
|
||||||
max_token_limit=(model_info[llm_kwargs['llm_model']]['max_token'])) # history至少释放二分之一
|
max_token_limit=(model_info[llm_kwargs['llm_model']]['max_token'])) # history至少释放二分之一
|
||||||
chatbot[-1] = (chatbot[-1][0], "[Local Message] Reduce the length. 本次输入过长, 或历史数据过长. 历史缓存数据已部分释放, 您可以请再次尝试. (若再次失败则更可能是因为输入过长.)")
|
chatbot[-1] = (chatbot[-1][0], "[Local Message] Reduce the length. 本次输入过长, 或历史数据过长. 历史缓存数据已部分释放, 您可以请再次尝试. (若再次失败则更可能是因为输入过长.)")
|
||||||
# history = [] # 清除历史
|
# history = [] # 清除历史
|
||||||
elif "does not exist" in error_msg:
|
elif "does not exist" in error_msg:
|
||||||
chatbot[-1] = (chatbot[-1][0], f"[Local Message] Model {llm_kwargs['llm_model']} does not exist. 模型不存在, 或者您没有获得体验资格.")
|
chatbot[-1] = (chatbot[-1][0], f"[Local Message] Model {llm_kwargs['llm_model']} does not exist. 模型不存在, 或者您没有获得体验资格.")
|
||||||
elif "Incorrect API key" in error_msg:
|
elif "Incorrect API key" in error_msg:
|
||||||
chatbot[-1] = (chatbot[-1][0], "[Local Message] Incorrect API key. OpenAI以提供了不正确的API_KEY为由, 拒绝服务. " + openai_website)
|
chatbot[-1] = (chatbot[-1][0], "[Local Message] Incorrect API key. OpenAI以提供了不正确的API_KEY为由, 拒绝服务. " + openai_website)
|
||||||
elif "exceeded your current quota" in error_msg:
|
elif "exceeded your current quota" in error_msg:
|
||||||
chatbot[-1] = (chatbot[-1][0], "[Local Message] You exceeded your current quota. OpenAI以账户额度不足为由, 拒绝服务." + openai_website)
|
chatbot[-1] = (chatbot[-1][0], "[Local Message] You exceeded your current quota. OpenAI以账户额度不足为由, 拒绝服务." + openai_website)
|
||||||
elif "account is not active" in error_msg:
|
elif "account is not active" in error_msg:
|
||||||
chatbot[-1] = (chatbot[-1][0], "[Local Message] Your account is not active. OpenAI以账户失效为由, 拒绝服务." + openai_website)
|
chatbot[-1] = (chatbot[-1][0], "[Local Message] Your account is not active. OpenAI以账户失效为由, 拒绝服务." + openai_website)
|
||||||
elif "associated with a deactivated account" in error_msg:
|
elif "associated with a deactivated account" in error_msg:
|
||||||
chatbot[-1] = (chatbot[-1][0], "[Local Message] You are associated with a deactivated account. OpenAI以账户失效为由, 拒绝服务." + openai_website)
|
chatbot[-1] = (chatbot[-1][0], "[Local Message] You are associated with a deactivated account. OpenAI以账户失效为由, 拒绝服务." + openai_website)
|
||||||
elif "bad forward key" in error_msg:
|
elif "bad forward key" in error_msg:
|
||||||
chatbot[-1] = (chatbot[-1][0], "[Local Message] Bad forward key. API2D账户额度不足.")
|
chatbot[-1] = (chatbot[-1][0], "[Local Message] Bad forward key. API2D账户额度不足.")
|
||||||
elif "Not enough point" in error_msg:
|
elif "Not enough point" in error_msg:
|
||||||
chatbot[-1] = (chatbot[-1][0], "[Local Message] Not enough point. API2D账户点数不足.")
|
chatbot[-1] = (chatbot[-1][0], "[Local Message] Not enough point. API2D账户点数不足.")
|
||||||
else:
|
else:
|
||||||
from toolbox import regular_txt_to_markdown
|
from toolbox import regular_txt_to_markdown
|
||||||
tb_str = '```\n' + trimmed_format_exc() + '```'
|
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)}")
|
chatbot[-1] = (chatbot[-1][0], f"[Local Message] 异常 \n\n{tb_str} \n\n{regular_txt_to_markdown(chunk_decoded)}")
|
||||||
return chatbot, history
|
yield from update_ui(chatbot=chatbot, history=history, msg="Json异常" + error_msg) # 刷新界面
|
||||||
|
return
|
||||||
|
|
||||||
def generate_payload(inputs, llm_kwargs, history, system_prompt, stream):
|
def generate_payload(inputs, llm_kwargs, history, system_prompt, stream):
|
||||||
"""
|
"""
|
||||||
|
|||||||
@ -116,8 +116,11 @@ def predict(inputs, llm_kwargs, plugin_kwargs, chatbot, history=[], system_promp
|
|||||||
return
|
return
|
||||||
|
|
||||||
if additional_fn is not None:
|
if additional_fn is not None:
|
||||||
from core_functional import handle_core_functionality
|
import core_functional
|
||||||
inputs, history = handle_core_functionality(additional_fn, inputs, history, chatbot)
|
importlib.reload(core_functional) # 热更新prompt
|
||||||
|
core_functional = core_functional.get_core_functions()
|
||||||
|
if "PreProcess" in core_functional[additional_fn]: inputs = core_functional[additional_fn]["PreProcess"](inputs) # 获取预处理函数(如果有的话)
|
||||||
|
inputs = core_functional[additional_fn]["Prefix"] + inputs + core_functional[additional_fn]["Suffix"]
|
||||||
|
|
||||||
raw_input = inputs
|
raw_input = inputs
|
||||||
logging.info(f'[raw_input] {raw_input}')
|
logging.info(f'[raw_input] {raw_input}')
|
||||||
|
|||||||
@ -1,312 +0,0 @@
|
|||||||
|
|
||||||
from transformers import AutoModel, AutoTokenizer
|
|
||||||
import time
|
|
||||||
import threading
|
|
||||||
import importlib
|
|
||||||
from toolbox import update_ui, get_conf, Singleton
|
|
||||||
from multiprocessing import Process, Pipe
|
|
||||||
|
|
||||||
model_name = "InternLM"
|
|
||||||
cmd_to_install = "`pip install ???`"
|
|
||||||
load_message = f"{model_name}尚未加载,加载需要一段时间。注意,取决于`config.py`的配置,{model_name}消耗大量的内存(CPU)或显存(GPU),也许会导致低配计算机卡死 ……"
|
|
||||||
def try_to_import_special_deps():
|
|
||||||
import sentencepiece
|
|
||||||
|
|
||||||
user_prompt = "<|User|>:{user}<eoh>\n"
|
|
||||||
robot_prompt = "<|Bot|>:{robot}<eoa>\n"
|
|
||||||
cur_query_prompt = "<|User|>:{user}<eoh>\n<|Bot|>:"
|
|
||||||
|
|
||||||
|
|
||||||
def combine_history(prompt, hist):
|
|
||||||
messages = hist
|
|
||||||
total_prompt = ""
|
|
||||||
for message in messages:
|
|
||||||
cur_content = message
|
|
||||||
cur_prompt = user_prompt.replace("{user}", cur_content[0])
|
|
||||||
total_prompt += cur_prompt
|
|
||||||
cur_prompt = robot_prompt.replace("{robot}", cur_content[1])
|
|
||||||
total_prompt += cur_prompt
|
|
||||||
total_prompt = total_prompt + cur_query_prompt.replace("{user}", prompt)
|
|
||||||
return total_prompt
|
|
||||||
|
|
||||||
|
|
||||||
@Singleton
|
|
||||||
class GetInternlmHandle(Process):
|
|
||||||
def __init__(self):
|
|
||||||
# ⭐主进程执行
|
|
||||||
super().__init__(daemon=True)
|
|
||||||
self.parent, self.child = Pipe()
|
|
||||||
self._model = None
|
|
||||||
self._tokenizer = None
|
|
||||||
self.info = ""
|
|
||||||
self.success = True
|
|
||||||
self.check_dependency()
|
|
||||||
self.start()
|
|
||||||
self.threadLock = threading.Lock()
|
|
||||||
|
|
||||||
def ready(self):
|
|
||||||
# ⭐主进程执行
|
|
||||||
return self._model is not None
|
|
||||||
|
|
||||||
def load_model_and_tokenizer(self):
|
|
||||||
# 🏃♂️🏃♂️🏃♂️ 子进程执行
|
|
||||||
import torch
|
|
||||||
from transformers import AutoModelForCausalLM, AutoTokenizer
|
|
||||||
device, = get_conf('LOCAL_MODEL_DEVICE')
|
|
||||||
if self._model is None:
|
|
||||||
tokenizer = AutoTokenizer.from_pretrained("internlm/internlm-chat-7b", trust_remote_code=True)
|
|
||||||
if device=='cpu':
|
|
||||||
model = AutoModelForCausalLM.from_pretrained("internlm/internlm-chat-7b", trust_remote_code=True).to(torch.bfloat16)
|
|
||||||
else:
|
|
||||||
model = AutoModelForCausalLM.from_pretrained("internlm/internlm-chat-7b", trust_remote_code=True).to(torch.bfloat16).cuda()
|
|
||||||
|
|
||||||
model = model.eval()
|
|
||||||
return model, tokenizer
|
|
||||||
|
|
||||||
def llm_stream_generator(self, **kwargs):
|
|
||||||
import torch
|
|
||||||
import logging
|
|
||||||
import copy
|
|
||||||
import warnings
|
|
||||||
import torch.nn as nn
|
|
||||||
from transformers.generation.utils import LogitsProcessorList, StoppingCriteriaList, GenerationConfig
|
|
||||||
|
|
||||||
# 🏃♂️🏃♂️🏃♂️ 子进程执行
|
|
||||||
def adaptor():
|
|
||||||
model = self._model
|
|
||||||
tokenizer = self._tokenizer
|
|
||||||
prompt = kwargs['query']
|
|
||||||
max_length = kwargs['max_length']
|
|
||||||
top_p = kwargs['top_p']
|
|
||||||
temperature = kwargs['temperature']
|
|
||||||
history = kwargs['history']
|
|
||||||
real_prompt = combine_history(prompt, history)
|
|
||||||
return model, tokenizer, real_prompt, max_length, top_p, temperature
|
|
||||||
|
|
||||||
model, tokenizer, prompt, max_length, top_p, temperature = adaptor()
|
|
||||||
prefix_allowed_tokens_fn = None
|
|
||||||
logits_processor = None
|
|
||||||
stopping_criteria = None
|
|
||||||
additional_eos_token_id = 103028
|
|
||||||
generation_config = None
|
|
||||||
# 🏃♂️🏃♂️🏃♂️ 子进程执行
|
|
||||||
# 🏃♂️🏃♂️🏃♂️ https://github.com/InternLM/InternLM/blob/efbf5335709a8c8faeac6eaf07193973ff1d56a1/web_demo.py#L25
|
|
||||||
|
|
||||||
inputs = tokenizer([prompt], padding=True, return_tensors="pt")
|
|
||||||
input_length = len(inputs["input_ids"][0])
|
|
||||||
for k, v in inputs.items():
|
|
||||||
inputs[k] = v.cuda()
|
|
||||||
input_ids = inputs["input_ids"]
|
|
||||||
batch_size, input_ids_seq_length = input_ids.shape[0], input_ids.shape[-1]
|
|
||||||
if generation_config is None:
|
|
||||||
generation_config = model.generation_config
|
|
||||||
generation_config = copy.deepcopy(generation_config)
|
|
||||||
model_kwargs = generation_config.update(**kwargs)
|
|
||||||
bos_token_id, eos_token_id = generation_config.bos_token_id, generation_config.eos_token_id
|
|
||||||
if isinstance(eos_token_id, int):
|
|
||||||
eos_token_id = [eos_token_id]
|
|
||||||
if additional_eos_token_id is not None:
|
|
||||||
eos_token_id.append(additional_eos_token_id)
|
|
||||||
has_default_max_length = kwargs.get("max_length") is None and generation_config.max_length is not None
|
|
||||||
if has_default_max_length and generation_config.max_new_tokens is None:
|
|
||||||
warnings.warn(
|
|
||||||
f"Using `max_length`'s default ({generation_config.max_length}) to control the generation length. "
|
|
||||||
"This behaviour is deprecated and will be removed from the config in v5 of Transformers -- we"
|
|
||||||
" recommend using `max_new_tokens` to control the maximum length of the generation.",
|
|
||||||
UserWarning,
|
|
||||||
)
|
|
||||||
elif generation_config.max_new_tokens is not None:
|
|
||||||
generation_config.max_length = generation_config.max_new_tokens + input_ids_seq_length
|
|
||||||
if not has_default_max_length:
|
|
||||||
logging.warn(
|
|
||||||
f"Both `max_new_tokens` (={generation_config.max_new_tokens}) and `max_length`(="
|
|
||||||
f"{generation_config.max_length}) seem to have been set. `max_new_tokens` will take precedence. "
|
|
||||||
"Please refer to the documentation for more information. "
|
|
||||||
"(https://huggingface.co/docs/transformers/main/en/main_classes/text_generation)",
|
|
||||||
UserWarning,
|
|
||||||
)
|
|
||||||
|
|
||||||
if input_ids_seq_length >= generation_config.max_length:
|
|
||||||
input_ids_string = "input_ids"
|
|
||||||
logging.warning(
|
|
||||||
f"Input length of {input_ids_string} is {input_ids_seq_length}, but `max_length` is set to"
|
|
||||||
f" {generation_config.max_length}. This can lead to unexpected behavior. You should consider"
|
|
||||||
" increasing `max_new_tokens`."
|
|
||||||
)
|
|
||||||
|
|
||||||
# 2. Set generation parameters if not already defined
|
|
||||||
logits_processor = logits_processor if logits_processor is not None else LogitsProcessorList()
|
|
||||||
stopping_criteria = stopping_criteria if stopping_criteria is not None else StoppingCriteriaList()
|
|
||||||
|
|
||||||
logits_processor = model._get_logits_processor(
|
|
||||||
generation_config=generation_config,
|
|
||||||
input_ids_seq_length=input_ids_seq_length,
|
|
||||||
encoder_input_ids=input_ids,
|
|
||||||
prefix_allowed_tokens_fn=prefix_allowed_tokens_fn,
|
|
||||||
logits_processor=logits_processor,
|
|
||||||
)
|
|
||||||
|
|
||||||
stopping_criteria = model._get_stopping_criteria(
|
|
||||||
generation_config=generation_config, stopping_criteria=stopping_criteria
|
|
||||||
)
|
|
||||||
logits_warper = model._get_logits_warper(generation_config)
|
|
||||||
|
|
||||||
unfinished_sequences = input_ids.new(input_ids.shape[0]).fill_(1)
|
|
||||||
scores = None
|
|
||||||
while True:
|
|
||||||
model_inputs = model.prepare_inputs_for_generation(input_ids, **model_kwargs)
|
|
||||||
# forward pass to get next token
|
|
||||||
outputs = model(
|
|
||||||
**model_inputs,
|
|
||||||
return_dict=True,
|
|
||||||
output_attentions=False,
|
|
||||||
output_hidden_states=False,
|
|
||||||
)
|
|
||||||
|
|
||||||
next_token_logits = outputs.logits[:, -1, :]
|
|
||||||
|
|
||||||
# pre-process distribution
|
|
||||||
next_token_scores = logits_processor(input_ids, next_token_logits)
|
|
||||||
next_token_scores = logits_warper(input_ids, next_token_scores)
|
|
||||||
|
|
||||||
# sample
|
|
||||||
probs = nn.functional.softmax(next_token_scores, dim=-1)
|
|
||||||
if generation_config.do_sample:
|
|
||||||
next_tokens = torch.multinomial(probs, num_samples=1).squeeze(1)
|
|
||||||
else:
|
|
||||||
next_tokens = torch.argmax(probs, dim=-1)
|
|
||||||
|
|
||||||
# update generated ids, model inputs, and length for next step
|
|
||||||
input_ids = torch.cat([input_ids, next_tokens[:, None]], dim=-1)
|
|
||||||
model_kwargs = model._update_model_kwargs_for_generation(
|
|
||||||
outputs, model_kwargs, is_encoder_decoder=False
|
|
||||||
)
|
|
||||||
unfinished_sequences = unfinished_sequences.mul((min(next_tokens != i for i in eos_token_id)).long())
|
|
||||||
|
|
||||||
output_token_ids = input_ids[0].cpu().tolist()
|
|
||||||
output_token_ids = output_token_ids[input_length:]
|
|
||||||
for each_eos_token_id in eos_token_id:
|
|
||||||
if output_token_ids[-1] == each_eos_token_id:
|
|
||||||
output_token_ids = output_token_ids[:-1]
|
|
||||||
response = tokenizer.decode(output_token_ids)
|
|
||||||
|
|
||||||
yield response
|
|
||||||
# stop when each sentence is finished, or if we exceed the maximum length
|
|
||||||
if unfinished_sequences.max() == 0 or stopping_criteria(input_ids, scores):
|
|
||||||
return
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def check_dependency(self):
|
|
||||||
# 🏃♂️🏃♂️🏃♂️ 子进程执行
|
|
||||||
try:
|
|
||||||
try_to_import_special_deps()
|
|
||||||
self.info = "依赖检测通过"
|
|
||||||
self.success = True
|
|
||||||
except:
|
|
||||||
self.info = f"缺少{model_name}的依赖,如果要使用{model_name},除了基础的pip依赖以外,您还需要运行{cmd_to_install}安装{model_name}的依赖。"
|
|
||||||
self.success = False
|
|
||||||
|
|
||||||
def run(self):
|
|
||||||
# 🏃♂️🏃♂️🏃♂️ 子进程执行
|
|
||||||
# 第一次运行,加载参数
|
|
||||||
try:
|
|
||||||
self._model, self._tokenizer = self.load_model_and_tokenizer()
|
|
||||||
except:
|
|
||||||
from toolbox import trimmed_format_exc
|
|
||||||
self.child.send(f'[Local Message] 不能正常加载{model_name}的参数.' + '\n```\n' + trimmed_format_exc() + '\n```\n')
|
|
||||||
raise RuntimeError(f"不能正常加载{model_name}的参数!")
|
|
||||||
|
|
||||||
while True:
|
|
||||||
# 进入任务等待状态
|
|
||||||
kwargs = self.child.recv()
|
|
||||||
# 收到消息,开始请求
|
|
||||||
try:
|
|
||||||
for response_full in self.llm_stream_generator(**kwargs):
|
|
||||||
self.child.send(response_full)
|
|
||||||
except:
|
|
||||||
from toolbox import trimmed_format_exc
|
|
||||||
self.child.send(f'[Local Message] 调用{model_name}失败.' + '\n```\n' + trimmed_format_exc() + '\n```\n')
|
|
||||||
# 请求处理结束,开始下一个循环
|
|
||||||
self.child.send('[Finish]')
|
|
||||||
|
|
||||||
def stream_chat(self, **kwargs):
|
|
||||||
# ⭐主进程执行
|
|
||||||
self.threadLock.acquire()
|
|
||||||
self.parent.send(kwargs)
|
|
||||||
while True:
|
|
||||||
res = self.parent.recv()
|
|
||||||
if res != '[Finish]':
|
|
||||||
yield res
|
|
||||||
else:
|
|
||||||
break
|
|
||||||
self.threadLock.release()
|
|
||||||
|
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------------------------------------------------
|
|
||||||
# 🔌💻 GPT-Academic
|
|
||||||
# ------------------------------------------------------------------------------------------------------------------------
|
|
||||||
def predict_no_ui_long_connection(inputs, llm_kwargs, history=[], sys_prompt="", observe_window=[], console_slience=False):
|
|
||||||
"""
|
|
||||||
⭐多线程方法
|
|
||||||
函数的说明请见 request_llm/bridge_all.py
|
|
||||||
"""
|
|
||||||
_llm_handle = GetInternlmHandle()
|
|
||||||
if len(observe_window) >= 1: observe_window[0] = load_message + "\n\n" + _llm_handle.info
|
|
||||||
if not _llm_handle.success:
|
|
||||||
error = _llm_handle.info
|
|
||||||
_llm_handle = None
|
|
||||||
raise RuntimeError(error)
|
|
||||||
|
|
||||||
# chatglm 没有 sys_prompt 接口,因此把prompt加入 history
|
|
||||||
history_feedin = []
|
|
||||||
history_feedin.append(["What can I do?", sys_prompt])
|
|
||||||
for i in range(len(history)//2):
|
|
||||||
history_feedin.append([history[2*i], history[2*i+1]] )
|
|
||||||
|
|
||||||
watch_dog_patience = 5 # 看门狗 (watchdog) 的耐心, 设置5秒即可
|
|
||||||
response = ""
|
|
||||||
for response in _llm_handle.stream_chat(query=inputs, history=history_feedin, max_length=llm_kwargs['max_length'], top_p=llm_kwargs['top_p'], temperature=llm_kwargs['temperature']):
|
|
||||||
if len(observe_window) >= 1: observe_window[0] = response
|
|
||||||
if len(observe_window) >= 2:
|
|
||||||
if (time.time()-observe_window[1]) > watch_dog_patience:
|
|
||||||
raise RuntimeError("程序终止。")
|
|
||||||
return response
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def predict(inputs, llm_kwargs, plugin_kwargs, chatbot, history=[], system_prompt='', stream = True, additional_fn=None):
|
|
||||||
"""
|
|
||||||
⭐单线程方法
|
|
||||||
函数的说明请见 request_llm/bridge_all.py
|
|
||||||
"""
|
|
||||||
chatbot.append((inputs, ""))
|
|
||||||
|
|
||||||
_llm_handle = GetInternlmHandle()
|
|
||||||
chatbot[-1] = (inputs, load_message + "\n\n" + _llm_handle.info)
|
|
||||||
yield from update_ui(chatbot=chatbot, history=[])
|
|
||||||
if not _llm_handle.success:
|
|
||||||
_llm_handle = None
|
|
||||||
return
|
|
||||||
|
|
||||||
if additional_fn is not None:
|
|
||||||
from core_functional import handle_core_functionality
|
|
||||||
inputs, history = handle_core_functionality(additional_fn, inputs, history, chatbot)
|
|
||||||
|
|
||||||
# 处理历史信息
|
|
||||||
history_feedin = []
|
|
||||||
history_feedin.append(["What can I do?", system_prompt] )
|
|
||||||
for i in range(len(history)//2):
|
|
||||||
history_feedin.append([history[2*i], history[2*i+1]] )
|
|
||||||
|
|
||||||
# 开始接收chatglm的回复
|
|
||||||
response = f"[Local Message]: 等待{model_name}响应中 ..."
|
|
||||||
for response in _llm_handle.stream_chat(query=inputs, history=history_feedin, max_length=llm_kwargs['max_length'], top_p=llm_kwargs['top_p'], temperature=llm_kwargs['temperature']):
|
|
||||||
chatbot[-1] = (inputs, response)
|
|
||||||
yield from update_ui(chatbot=chatbot, history=history)
|
|
||||||
|
|
||||||
# 总结输出
|
|
||||||
if response == f"[Local Message]: 等待{model_name}响应中 ...":
|
|
||||||
response = f"[Local Message]: {model_name}响应异常 ..."
|
|
||||||
history.extend([inputs, response])
|
|
||||||
yield from update_ui(chatbot=chatbot, history=history)
|
|
||||||
@ -154,8 +154,11 @@ def predict(inputs, llm_kwargs, plugin_kwargs, chatbot, history=[], system_promp
|
|||||||
return
|
return
|
||||||
|
|
||||||
if additional_fn is not None:
|
if additional_fn is not None:
|
||||||
from core_functional import handle_core_functionality
|
import core_functional
|
||||||
inputs, history = handle_core_functionality(additional_fn, inputs, history, chatbot)
|
importlib.reload(core_functional) # 热更新prompt
|
||||||
|
core_functional = core_functional.get_core_functions()
|
||||||
|
if "PreProcess" in core_functional[additional_fn]: inputs = core_functional[additional_fn]["PreProcess"](inputs) # 获取预处理函数(如果有的话)
|
||||||
|
inputs = core_functional[additional_fn]["Prefix"] + inputs + core_functional[additional_fn]["Suffix"]
|
||||||
|
|
||||||
# 处理历史信息
|
# 处理历史信息
|
||||||
history_feedin = []
|
history_feedin = []
|
||||||
|
|||||||
@ -154,8 +154,11 @@ def predict(inputs, llm_kwargs, plugin_kwargs, chatbot, history=[], system_promp
|
|||||||
return
|
return
|
||||||
|
|
||||||
if additional_fn is not None:
|
if additional_fn is not None:
|
||||||
from core_functional import handle_core_functionality
|
import core_functional
|
||||||
inputs, history = handle_core_functionality(additional_fn, inputs, history, chatbot)
|
importlib.reload(core_functional) # 热更新prompt
|
||||||
|
core_functional = core_functional.get_core_functions()
|
||||||
|
if "PreProcess" in core_functional[additional_fn]: inputs = core_functional[additional_fn]["PreProcess"](inputs) # 获取预处理函数(如果有的话)
|
||||||
|
inputs = core_functional[additional_fn]["Prefix"] + inputs + core_functional[additional_fn]["Suffix"]
|
||||||
|
|
||||||
# 处理历史信息
|
# 处理历史信息
|
||||||
history_feedin = []
|
history_feedin = []
|
||||||
|
|||||||
@ -154,8 +154,11 @@ def predict(inputs, llm_kwargs, plugin_kwargs, chatbot, history=[], system_promp
|
|||||||
return
|
return
|
||||||
|
|
||||||
if additional_fn is not None:
|
if additional_fn is not None:
|
||||||
from core_functional import handle_core_functionality
|
import core_functional
|
||||||
inputs, history = handle_core_functionality(additional_fn, inputs, history, chatbot)
|
importlib.reload(core_functional) # 热更新prompt
|
||||||
|
core_functional = core_functional.get_core_functions()
|
||||||
|
if "PreProcess" in core_functional[additional_fn]: inputs = core_functional[additional_fn]["PreProcess"](inputs) # 获取预处理函数(如果有的话)
|
||||||
|
inputs = core_functional[additional_fn]["Prefix"] + inputs + core_functional[additional_fn]["Suffix"]
|
||||||
|
|
||||||
# 处理历史信息
|
# 处理历史信息
|
||||||
history_feedin = []
|
history_feedin = []
|
||||||
|
|||||||
@ -224,8 +224,11 @@ def predict(inputs, llm_kwargs, plugin_kwargs, chatbot, history=[], system_promp
|
|||||||
yield from update_ui(chatbot=chatbot, history=history)
|
yield from update_ui(chatbot=chatbot, history=history)
|
||||||
|
|
||||||
if additional_fn is not None:
|
if additional_fn is not None:
|
||||||
from core_functional import handle_core_functionality
|
import core_functional
|
||||||
inputs, history = handle_core_functionality(additional_fn, inputs, history, chatbot)
|
importlib.reload(core_functional) # 热更新prompt
|
||||||
|
core_functional = core_functional.get_core_functions()
|
||||||
|
if "PreProcess" in core_functional[additional_fn]: inputs = core_functional[additional_fn]["PreProcess"](inputs) # 获取预处理函数(如果有的话)
|
||||||
|
inputs = core_functional[additional_fn]["Prefix"] + inputs + core_functional[additional_fn]["Suffix"]
|
||||||
|
|
||||||
# 处理历史信息
|
# 处理历史信息
|
||||||
history_feedin = []
|
history_feedin = []
|
||||||
|
|||||||
@ -224,8 +224,11 @@ def predict(inputs, llm_kwargs, plugin_kwargs, chatbot, history=[], system_promp
|
|||||||
return
|
return
|
||||||
|
|
||||||
if additional_fn is not None:
|
if additional_fn is not None:
|
||||||
from core_functional import handle_core_functionality
|
import core_functional
|
||||||
inputs, history = handle_core_functionality(additional_fn, inputs, history, chatbot)
|
importlib.reload(core_functional) # 热更新prompt
|
||||||
|
core_functional = core_functional.get_core_functions()
|
||||||
|
if "PreProcess" in core_functional[additional_fn]: inputs = core_functional[additional_fn]["PreProcess"](inputs) # 获取预处理函数(如果有的话)
|
||||||
|
inputs = core_functional[additional_fn]["Prefix"] + inputs + core_functional[additional_fn]["Suffix"]
|
||||||
|
|
||||||
history_feedin = []
|
history_feedin = []
|
||||||
for i in range(len(history)//2):
|
for i in range(len(history)//2):
|
||||||
|
|||||||
@ -248,8 +248,14 @@ def predict(inputs, llm_kwargs, plugin_kwargs, chatbot, history=[], system_promp
|
|||||||
return
|
return
|
||||||
|
|
||||||
if additional_fn is not None:
|
if additional_fn is not None:
|
||||||
from core_functional import handle_core_functionality
|
import core_functional
|
||||||
inputs, history = handle_core_functionality(additional_fn, inputs, history, chatbot)
|
importlib.reload(core_functional) # 热更新prompt
|
||||||
|
core_functional = core_functional.get_core_functions()
|
||||||
|
if "PreProcess" in core_functional[additional_fn]:
|
||||||
|
inputs = core_functional[additional_fn]["PreProcess"](
|
||||||
|
inputs) # 获取预处理函数(如果有的话)
|
||||||
|
inputs = core_functional[additional_fn]["Prefix"] + \
|
||||||
|
inputs + core_functional[additional_fn]["Suffix"]
|
||||||
|
|
||||||
history_feedin = []
|
history_feedin = []
|
||||||
for i in range(len(history)//2):
|
for i in range(len(history)//2):
|
||||||
|
|||||||
@ -96,8 +96,11 @@ def predict(inputs, llm_kwargs, plugin_kwargs, chatbot, history=[], system_promp
|
|||||||
additional_fn代表点击的哪个按钮,按钮见functional.py
|
additional_fn代表点击的哪个按钮,按钮见functional.py
|
||||||
"""
|
"""
|
||||||
if additional_fn is not None:
|
if additional_fn is not None:
|
||||||
from core_functional import handle_core_functionality
|
import core_functional
|
||||||
inputs, history = handle_core_functionality(additional_fn, inputs, history, chatbot)
|
importlib.reload(core_functional) # 热更新prompt
|
||||||
|
core_functional = core_functional.get_core_functions()
|
||||||
|
if "PreProcess" in core_functional[additional_fn]: inputs = core_functional[additional_fn]["PreProcess"](inputs) # 获取预处理函数(如果有的话)
|
||||||
|
inputs = core_functional[additional_fn]["Prefix"] + inputs + core_functional[additional_fn]["Suffix"]
|
||||||
|
|
||||||
raw_input = "What I would like to say is the following: " + inputs
|
raw_input = "What I would like to say is the following: " + inputs
|
||||||
history.extend([inputs, ""])
|
history.extend([inputs, ""])
|
||||||
|
|||||||
@ -447,15 +447,6 @@ class _ChatHub:
|
|||||||
"""
|
"""
|
||||||
Ask a question to the bot
|
Ask a question to the bot
|
||||||
"""
|
"""
|
||||||
req_header = HEADERS
|
|
||||||
if self.cookies is not None:
|
|
||||||
ws_cookies = []
|
|
||||||
for cookie in self.cookies:
|
|
||||||
ws_cookies.append(f"{cookie['name']}={cookie['value']}")
|
|
||||||
req_header.update({
|
|
||||||
'Cookie': ';'.join(ws_cookies),
|
|
||||||
})
|
|
||||||
|
|
||||||
timeout = aiohttp.ClientTimeout(total=30)
|
timeout = aiohttp.ClientTimeout(total=30)
|
||||||
self.session = aiohttp.ClientSession(timeout=timeout)
|
self.session = aiohttp.ClientSession(timeout=timeout)
|
||||||
|
|
||||||
@ -464,7 +455,7 @@ class _ChatHub:
|
|||||||
# Check if websocket is closed
|
# Check if websocket is closed
|
||||||
self.wss = await self.session.ws_connect(
|
self.wss = await self.session.ws_connect(
|
||||||
wss_link,
|
wss_link,
|
||||||
headers=req_header,
|
headers=HEADERS,
|
||||||
ssl=ssl_context,
|
ssl=ssl_context,
|
||||||
proxy=self.proxy,
|
proxy=self.proxy,
|
||||||
autoping=False,
|
autoping=False,
|
||||||
@ -519,11 +510,7 @@ class _ChatHub:
|
|||||||
resp_txt_no_link = ""
|
resp_txt_no_link = ""
|
||||||
while not final:
|
while not final:
|
||||||
msg = await self.wss.receive()
|
msg = await self.wss.receive()
|
||||||
try:
|
objects = msg.data.split(DELIMITER)
|
||||||
objects = msg.data.split(DELIMITER)
|
|
||||||
except :
|
|
||||||
continue
|
|
||||||
|
|
||||||
for obj in objects:
|
for obj in objects:
|
||||||
if obj is None or not obj:
|
if obj is None or not obj:
|
||||||
continue
|
continue
|
||||||
@ -1122,4 +1109,4 @@ class ImageQuery(Query):
|
|||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
@ -14,8 +14,7 @@ if __name__ == "__main__":
|
|||||||
# from request_llm.bridge_moss import predict_no_ui_long_connection
|
# from request_llm.bridge_moss import predict_no_ui_long_connection
|
||||||
# from request_llm.bridge_jittorllms_pangualpha import predict_no_ui_long_connection
|
# from request_llm.bridge_jittorllms_pangualpha import predict_no_ui_long_connection
|
||||||
# from request_llm.bridge_jittorllms_llama import predict_no_ui_long_connection
|
# from request_llm.bridge_jittorllms_llama import predict_no_ui_long_connection
|
||||||
# from request_llm.bridge_claude import predict_no_ui_long_connection
|
from request_llm.bridge_claude import predict_no_ui_long_connection
|
||||||
from request_llm.bridge_internlm import predict_no_ui_long_connection
|
|
||||||
|
|
||||||
llm_kwargs = {
|
llm_kwargs = {
|
||||||
'max_length': 512,
|
'max_length': 512,
|
||||||
@ -23,8 +22,45 @@ if __name__ == "__main__":
|
|||||||
'temperature': 1,
|
'temperature': 1,
|
||||||
}
|
}
|
||||||
|
|
||||||
result = predict_no_ui_long_connection( inputs="请问什么是质子?",
|
result = predict_no_ui_long_connection(inputs="你好",
|
||||||
llm_kwargs=llm_kwargs,
|
llm_kwargs=llm_kwargs,
|
||||||
history=["你好", "我好!"],
|
history=[],
|
||||||
sys_prompt="")
|
sys_prompt="")
|
||||||
print('final result:', result)
|
print('final result:', result)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# # print(result)
|
||||||
|
# from multiprocessing import Process, Pipe
|
||||||
|
# class GetGLMHandle(Process):
|
||||||
|
# def __init__(self):
|
||||||
|
# super().__init__(daemon=True)
|
||||||
|
# pass
|
||||||
|
# def run(self):
|
||||||
|
# # 子进程执行
|
||||||
|
# # 第一次运行,加载参数
|
||||||
|
# def validate_path():
|
||||||
|
# import os, sys
|
||||||
|
# dir_name = os.path.dirname(__file__)
|
||||||
|
# root_dir_assume = os.path.abspath(os.path.dirname(__file__) + '/..')
|
||||||
|
# os.chdir(root_dir_assume + '/request_llm/jittorllms')
|
||||||
|
# sys.path.append(root_dir_assume + '/request_llm/jittorllms')
|
||||||
|
# validate_path() # validate path so you can run from base directory
|
||||||
|
# jittorllms_model = None
|
||||||
|
# import types
|
||||||
|
# try:
|
||||||
|
# if jittorllms_model is None:
|
||||||
|
# from models import get_model
|
||||||
|
# # availabel_models = ["chatglm", "pangualpha", "llama", "chatrwkv"]
|
||||||
|
# args_dict = {'model': 'chatrwkv'}
|
||||||
|
# print('self.jittorllms_model = get_model(types.SimpleNamespace(**args_dict))')
|
||||||
|
# jittorllms_model = get_model(types.SimpleNamespace(**args_dict))
|
||||||
|
# print('done get model')
|
||||||
|
# except:
|
||||||
|
# # self.child.send('[Local Message] Call jittorllms fail 不能正常加载jittorllms的参数。')
|
||||||
|
# raise RuntimeError("不能正常加载jittorllms的参数!")
|
||||||
|
# x = GetGLMHandle()
|
||||||
|
# x.start()
|
||||||
|
|
||||||
|
|
||||||
|
# input()
|
||||||
@ -18,4 +18,3 @@ openai
|
|||||||
numpy
|
numpy
|
||||||
arxiv
|
arxiv
|
||||||
rich
|
rich
|
||||||
pypdf2==2.12.1
|
|
||||||
|
|||||||
192
toolbox.py
192
toolbox.py
@ -117,20 +117,20 @@ def CatchException(f):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
@wraps(f)
|
@wraps(f)
|
||||||
def decorated(main_input, llm_kwargs, plugin_kwargs, chatbot_with_cookie, history, *args, **kwargs):
|
def decorated(txt, top_p, temperature, chatbot, history, systemPromptTxt, WEB_PORT=-1):
|
||||||
try:
|
try:
|
||||||
yield from f(main_input, llm_kwargs, plugin_kwargs, chatbot_with_cookie, history, *args, **kwargs)
|
yield from f(txt, top_p, temperature, chatbot, history, systemPromptTxt, WEB_PORT)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
from check_proxy import check_proxy
|
from check_proxy import check_proxy
|
||||||
from toolbox import get_conf
|
from toolbox import get_conf
|
||||||
proxies, = get_conf('proxies')
|
proxies, = get_conf('proxies')
|
||||||
tb_str = '```\n' + trimmed_format_exc() + '```'
|
tb_str = '```\n' + trimmed_format_exc() + '```'
|
||||||
if len(chatbot_with_cookie) == 0:
|
if len(chatbot) == 0:
|
||||||
chatbot_with_cookie.clear()
|
chatbot.clear()
|
||||||
chatbot_with_cookie.append(["插件调度异常", "异常原因"])
|
chatbot.append(["插件调度异常", "异常原因"])
|
||||||
chatbot_with_cookie[-1] = (chatbot_with_cookie[-1][0],
|
chatbot[-1] = (chatbot[-1][0],
|
||||||
f"[Local Message] 实验性函数调用出错: \n\n{tb_str} \n\n当前代理可用性: \n\n{check_proxy(proxies)}")
|
f"[Local Message] 实验性函数调用出错: \n\n{tb_str} \n\n当前代理可用性: \n\n{check_proxy(proxies)}")
|
||||||
yield from update_ui(chatbot=chatbot_with_cookie, history=history, msg=f'异常 {e}') # 刷新界面
|
yield from update_ui(chatbot=chatbot, history=history, msg=f'异常 {e}') # 刷新界面
|
||||||
return decorated
|
return decorated
|
||||||
|
|
||||||
|
|
||||||
@ -196,10 +196,11 @@ def write_results_to_file(history, file_name=None):
|
|||||||
import time
|
import time
|
||||||
if file_name is None:
|
if file_name is None:
|
||||||
# file_name = time.strftime("chatGPT分析报告%Y-%m-%d-%H-%M-%S", time.localtime()) + '.md'
|
# file_name = time.strftime("chatGPT分析报告%Y-%m-%d-%H-%M-%S", time.localtime()) + '.md'
|
||||||
file_name = 'GPT-Report-' + gen_time_str() + '.md'
|
file_name = 'chatGPT分析报告' + \
|
||||||
|
time.strftime("%Y-%m-%d-%H-%M-%S", time.localtime()) + '.md'
|
||||||
os.makedirs('./gpt_log/', exist_ok=True)
|
os.makedirs('./gpt_log/', exist_ok=True)
|
||||||
with open(f'./gpt_log/{file_name}', 'w', encoding='utf8') as f:
|
with open(f'./gpt_log/{file_name}', 'w', encoding='utf8') as f:
|
||||||
f.write('# GPT-Academic Report\n')
|
f.write('# chatGPT 分析报告\n')
|
||||||
for i, content in enumerate(history):
|
for i, content in enumerate(history):
|
||||||
try:
|
try:
|
||||||
if type(content) != str: content = str(content)
|
if type(content) != str: content = str(content)
|
||||||
@ -218,37 +219,6 @@ def write_results_to_file(history, file_name=None):
|
|||||||
return res
|
return res
|
||||||
|
|
||||||
|
|
||||||
def write_history_to_file(history, file_basename=None, file_fullname=None):
|
|
||||||
"""
|
|
||||||
将对话记录history以Markdown格式写入文件中。如果没有指定文件名,则使用当前时间生成文件名。
|
|
||||||
"""
|
|
||||||
import os
|
|
||||||
import time
|
|
||||||
if file_fullname is None:
|
|
||||||
if file_basename is not None:
|
|
||||||
file_fullname = os.path.join(get_log_folder(), file_basename)
|
|
||||||
else:
|
|
||||||
file_fullname = os.path.join(get_log_folder(), f'GPT-Academic-{gen_time_str()}.md')
|
|
||||||
os.makedirs(os.path.dirname(file_fullname), exist_ok=True)
|
|
||||||
with open(file_fullname, 'w', encoding='utf8') as f:
|
|
||||||
f.write('# GPT-Academic Report\n')
|
|
||||||
for i, content in enumerate(history):
|
|
||||||
try:
|
|
||||||
if type(content) != str: content = str(content)
|
|
||||||
except:
|
|
||||||
continue
|
|
||||||
if i % 2 == 0:
|
|
||||||
f.write('## ')
|
|
||||||
try:
|
|
||||||
f.write(content)
|
|
||||||
except:
|
|
||||||
# remove everything that cannot be handled by utf8
|
|
||||||
f.write(content.encode('utf-8', 'ignore').decode())
|
|
||||||
f.write('\n\n')
|
|
||||||
res = os.path.abspath(file_fullname)
|
|
||||||
return res
|
|
||||||
|
|
||||||
|
|
||||||
def regular_txt_to_markdown(text):
|
def regular_txt_to_markdown(text):
|
||||||
"""
|
"""
|
||||||
将普通文本转换为Markdown格式的文本。
|
将普通文本转换为Markdown格式的文本。
|
||||||
@ -496,7 +466,7 @@ def promote_file_to_downloadzone(file, rename_file=None, chatbot=None):
|
|||||||
# 将文件复制一份到下载区
|
# 将文件复制一份到下载区
|
||||||
import shutil
|
import shutil
|
||||||
if rename_file is None: rename_file = f'{gen_time_str()}-{os.path.basename(file)}'
|
if rename_file is None: rename_file = f'{gen_time_str()}-{os.path.basename(file)}'
|
||||||
new_path = os.path.join(get_log_folder(), rename_file)
|
new_path = os.path.join(f'./gpt_log/', rename_file)
|
||||||
# 如果已经存在,先删除
|
# 如果已经存在,先删除
|
||||||
if os.path.exists(new_path) and not os.path.samefile(new_path, file): os.remove(new_path)
|
if os.path.exists(new_path) and not os.path.samefile(new_path, file): os.remove(new_path)
|
||||||
# 把文件复制过去
|
# 把文件复制过去
|
||||||
@ -507,10 +477,6 @@ def promote_file_to_downloadzone(file, rename_file=None, chatbot=None):
|
|||||||
else: current = []
|
else: current = []
|
||||||
chatbot._cookies.update({'file_to_promote': [new_path] + current})
|
chatbot._cookies.update({'file_to_promote': [new_path] + current})
|
||||||
|
|
||||||
def disable_auto_promotion(chatbot):
|
|
||||||
chatbot._cookies.update({'file_to_promote': []})
|
|
||||||
return
|
|
||||||
|
|
||||||
def on_file_uploaded(files, chatbot, txt, txt2, checkboxes):
|
def on_file_uploaded(files, chatbot, txt, txt2, checkboxes):
|
||||||
"""
|
"""
|
||||||
当文件被上传时的回调函数
|
当文件被上传时的回调函数
|
||||||
@ -526,7 +492,7 @@ def on_file_uploaded(files, chatbot, txt, txt2, checkboxes):
|
|||||||
shutil.rmtree('./private_upload/')
|
shutil.rmtree('./private_upload/')
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
time_tag = gen_time_str()
|
time_tag = time.strftime("%Y-%m-%d-%H-%M-%S", time.localtime())
|
||||||
os.makedirs(f'private_upload/{time_tag}', exist_ok=True)
|
os.makedirs(f'private_upload/{time_tag}', exist_ok=True)
|
||||||
err_msg = ''
|
err_msg = ''
|
||||||
for file in files:
|
for file in files:
|
||||||
@ -572,11 +538,7 @@ def load_chat_cookies():
|
|||||||
return {'api_key': API_KEY, 'llm_model': LLM_MODEL}
|
return {'api_key': API_KEY, 'llm_model': LLM_MODEL}
|
||||||
|
|
||||||
def is_openai_api_key(key):
|
def is_openai_api_key(key):
|
||||||
CUSTOM_API_KEY_PATTERN, = get_conf('CUSTOM_API_KEY_PATTERN')
|
API_MATCH_ORIGINAL = re.match(r"sk-[a-zA-Z0-9]{48}$", 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}$", key)
|
|
||||||
return bool(API_MATCH_ORIGINAL)
|
return bool(API_MATCH_ORIGINAL)
|
||||||
|
|
||||||
def is_azure_api_key(key):
|
def is_azure_api_key(key):
|
||||||
@ -632,7 +594,7 @@ def select_api_key(keys, llm_model):
|
|||||||
if is_azure_api_key(k): avail_key_list.append(k)
|
if is_azure_api_key(k): avail_key_list.append(k)
|
||||||
|
|
||||||
if len(avail_key_list) == 0:
|
if len(avail_key_list) == 0:
|
||||||
raise RuntimeError(f"您提供的api-key不满足要求,不包含任何可用于{llm_model}的api-key。您可能选择了错误的模型或请求源(右下角更换模型菜单中可切换openai,azure,claude,api2d等请求源)。")
|
raise RuntimeError(f"您提供的api-key不满足要求,不包含任何可用于{llm_model}的api-key。您可能选择了错误的模型或请求源(右下角更换模型菜单中可切换openai,azure和api2d请求源)")
|
||||||
|
|
||||||
api_key = random.choice(avail_key_list) # 随机负载均衡
|
api_key = random.choice(avail_key_list) # 随机负载均衡
|
||||||
return api_key
|
return api_key
|
||||||
@ -708,14 +670,13 @@ def read_single_conf_with_lru_cache(arg):
|
|||||||
|
|
||||||
# 在读取API_KEY时,检查一下是不是忘了改config
|
# 在读取API_KEY时,检查一下是不是忘了改config
|
||||||
if arg == 'API_KEY':
|
if arg == 'API_KEY':
|
||||||
print亮蓝(f"[API_KEY] 本项目现已支持OpenAI和Azure的api-key。也支持同时填写多个api-key,如API_KEY=\"openai-key1,openai-key2,azure-key3\"")
|
print亮蓝(f"[API_KEY] 本项目现已支持OpenAI和API2D的api-key。也支持同时填写多个api-key,如API_KEY=\"openai-key1,openai-key2,api2d-key3\"")
|
||||||
print亮蓝(f"[API_KEY] 您既可以在config.py中修改api-key(s),也可以在问题输入区输入临时的api-key(s),然后回车键提交后即可生效。")
|
print亮蓝(f"[API_KEY] 您既可以在config.py中修改api-key(s),也可以在问题输入区输入临时的api-key(s),然后回车键提交后即可生效。")
|
||||||
if is_any_api_key(r):
|
if is_any_api_key(r):
|
||||||
print亮绿(f"[API_KEY] 您的 API_KEY 是: {r[:15]}*** API_KEY 导入成功")
|
print亮绿(f"[API_KEY] 您的 API_KEY 是: {r[:15]}*** API_KEY 导入成功")
|
||||||
else:
|
else:
|
||||||
print亮红( "[API_KEY] 您的 API_KEY 不满足任何一种已知的密钥格式,请在config文件中修改API密钥之后再运行。")
|
print亮红( "[API_KEY] 正确的 API_KEY 是'sk'开头的51位密钥(OpenAI),或者 'fk'开头的41位密钥,请在config文件中修改API密钥之后再运行。")
|
||||||
if arg == 'proxies':
|
if arg == 'proxies':
|
||||||
if not read_single_conf_with_lru_cache('USE_PROXY'): r = None # 检查USE_PROXY,防止proxies单独起作用
|
|
||||||
if r is None:
|
if r is None:
|
||||||
print亮红('[PROXY] 网络代理状态:未配置。无代理状态下很可能无法访问OpenAI家族的模型。建议:检查USE_PROXY选项是否修改。')
|
print亮红('[PROXY] 网络代理状态:未配置。无代理状态下很可能无法访问OpenAI家族的模型。建议:检查USE_PROXY选项是否修改。')
|
||||||
else:
|
else:
|
||||||
@ -724,7 +685,6 @@ def read_single_conf_with_lru_cache(arg):
|
|||||||
return r
|
return r
|
||||||
|
|
||||||
|
|
||||||
@lru_cache(maxsize=128)
|
|
||||||
def get_conf(*args):
|
def get_conf(*args):
|
||||||
# 建议您复制一个config_private.py放自己的秘密, 如API和代理网址, 避免不小心传github被别人看到
|
# 建议您复制一个config_private.py放自己的秘密, 如API和代理网址, 避免不小心传github被别人看到
|
||||||
res = []
|
res = []
|
||||||
@ -883,7 +843,8 @@ def zip_folder(source_folder, dest_folder, zip_name):
|
|||||||
print(f"Zip file created at {zip_file}")
|
print(f"Zip file created at {zip_file}")
|
||||||
|
|
||||||
def zip_result(folder):
|
def zip_result(folder):
|
||||||
t = gen_time_str()
|
import time
|
||||||
|
t = time.strftime("%Y-%m-%d-%H-%M-%S", time.localtime())
|
||||||
zip_folder(folder, './gpt_log/', f'{t}-result.zip')
|
zip_folder(folder, './gpt_log/', f'{t}-result.zip')
|
||||||
return pj('./gpt_log/', f'{t}-result.zip')
|
return pj('./gpt_log/', f'{t}-result.zip')
|
||||||
|
|
||||||
@ -891,11 +852,6 @@ def gen_time_str():
|
|||||||
import time
|
import time
|
||||||
return time.strftime("%Y-%m-%d-%H-%M-%S", time.localtime())
|
return time.strftime("%Y-%m-%d-%H-%M-%S", time.localtime())
|
||||||
|
|
||||||
def get_log_folder(user='default', plugin_name='shared'):
|
|
||||||
_dir = os.path.join(os.path.dirname(__file__), 'gpt_log', user, plugin_name)
|
|
||||||
if not os.path.exists(_dir): os.makedirs(_dir)
|
|
||||||
return _dir
|
|
||||||
|
|
||||||
class ProxyNetworkActivate():
|
class ProxyNetworkActivate():
|
||||||
"""
|
"""
|
||||||
这段代码定义了一个名为TempProxy的空上下文管理器, 用于给一小段代码上代理
|
这段代码定义了一个名为TempProxy的空上下文管理器, 用于给一小段代码上代理
|
||||||
@ -927,114 +883,4 @@ def objload(file='objdump.tmp'):
|
|||||||
return
|
return
|
||||||
with open(file, 'rb') as f:
|
with open(file, 'rb') as f:
|
||||||
return pickle.load(f)
|
return pickle.load(f)
|
||||||
|
|
||||||
def Singleton(cls):
|
|
||||||
"""
|
|
||||||
一个单实例装饰器
|
|
||||||
"""
|
|
||||||
_instance = {}
|
|
||||||
|
|
||||||
def _singleton(*args, **kargs):
|
|
||||||
if cls not in _instance:
|
|
||||||
_instance[cls] = cls(*args, **kargs)
|
|
||||||
return _instance[cls]
|
|
||||||
|
|
||||||
return _singleton
|
|
||||||
|
|
||||||
"""
|
|
||||||
========================================================================
|
|
||||||
第四部分
|
|
||||||
接驳虚空终端:
|
|
||||||
- set_conf: 在运行过程中动态地修改配置
|
|
||||||
- set_multi_conf: 在运行过程中动态地修改多个配置
|
|
||||||
- get_plugin_handle: 获取插件的句柄
|
|
||||||
- get_plugin_default_kwargs: 获取插件的默认参数
|
|
||||||
- get_chat_handle: 获取简单聊天的句柄
|
|
||||||
- get_chat_default_kwargs: 获取简单聊天的默认参数
|
|
||||||
========================================================================
|
|
||||||
"""
|
|
||||||
|
|
||||||
def set_conf(key, value):
|
|
||||||
from toolbox import read_single_conf_with_lru_cache, get_conf
|
|
||||||
read_single_conf_with_lru_cache.cache_clear()
|
|
||||||
get_conf.cache_clear()
|
|
||||||
os.environ[key] = str(value)
|
|
||||||
altered, = get_conf(key)
|
|
||||||
return altered
|
|
||||||
|
|
||||||
def set_multi_conf(dic):
|
|
||||||
for k, v in dic.items(): set_conf(k, v)
|
|
||||||
return
|
|
||||||
|
|
||||||
def get_plugin_handle(plugin_name):
|
|
||||||
"""
|
|
||||||
e.g. plugin_name = 'crazy_functions.批量Markdown翻译->Markdown翻译指定语言'
|
|
||||||
"""
|
|
||||||
import importlib
|
|
||||||
assert '->' in plugin_name, \
|
|
||||||
"Example of plugin_name: crazy_functions.批量Markdown翻译->Markdown翻译指定语言"
|
|
||||||
module, fn_name = plugin_name.split('->')
|
|
||||||
f_hot_reload = getattr(importlib.import_module(module, fn_name), fn_name)
|
|
||||||
return f_hot_reload
|
|
||||||
|
|
||||||
def get_chat_handle():
|
|
||||||
"""
|
|
||||||
"""
|
|
||||||
from request_llm.bridge_all import predict_no_ui_long_connection
|
|
||||||
return predict_no_ui_long_connection
|
|
||||||
|
|
||||||
def get_plugin_default_kwargs():
|
|
||||||
"""
|
|
||||||
"""
|
|
||||||
from toolbox import get_conf, ChatBotWithCookies
|
|
||||||
|
|
||||||
WEB_PORT, LLM_MODEL, API_KEY = \
|
|
||||||
get_conf('WEB_PORT', 'LLM_MODEL', 'API_KEY')
|
|
||||||
|
|
||||||
llm_kwargs = {
|
|
||||||
'api_key': API_KEY,
|
|
||||||
'llm_model': LLM_MODEL,
|
|
||||||
'top_p':1.0,
|
|
||||||
'max_length': None,
|
|
||||||
'temperature':1.0,
|
|
||||||
}
|
|
||||||
chatbot = ChatBotWithCookies(llm_kwargs)
|
|
||||||
|
|
||||||
# txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port
|
|
||||||
default_plugin_kwargs = {
|
|
||||||
"main_input": "./README.md",
|
|
||||||
"llm_kwargs": llm_kwargs,
|
|
||||||
"plugin_kwargs": {},
|
|
||||||
"chatbot_with_cookie": chatbot,
|
|
||||||
"history": [],
|
|
||||||
"system_prompt": "You are a good AI.",
|
|
||||||
"web_port": WEB_PORT
|
|
||||||
}
|
|
||||||
return default_plugin_kwargs
|
|
||||||
|
|
||||||
def get_chat_default_kwargs():
|
|
||||||
"""
|
|
||||||
"""
|
|
||||||
from toolbox import get_conf
|
|
||||||
|
|
||||||
LLM_MODEL, API_KEY = get_conf('LLM_MODEL', 'API_KEY')
|
|
||||||
|
|
||||||
llm_kwargs = {
|
|
||||||
'api_key': API_KEY,
|
|
||||||
'llm_model': LLM_MODEL,
|
|
||||||
'top_p':1.0,
|
|
||||||
'max_length': None,
|
|
||||||
'temperature':1.0,
|
|
||||||
}
|
|
||||||
|
|
||||||
default_chat_kwargs = {
|
|
||||||
"inputs": "Hello there, are you ready?",
|
|
||||||
"llm_kwargs": llm_kwargs,
|
|
||||||
"history": [],
|
|
||||||
"sys_prompt": "You are AI assistant",
|
|
||||||
"observe_window": None,
|
|
||||||
"console_slience": False,
|
|
||||||
}
|
|
||||||
|
|
||||||
return default_chat_kwargs
|
|
||||||
|
|
||||||
6
version
6
version
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"version": 3.47,
|
"version": 3.46,
|
||||||
"show_feature": true,
|
"show_feature": true,
|
||||||
"new_feature": "优化一键升级 <-> 提高arxiv翻译速度和成功率 <-> 支持自定义APIKEY格式 <-> 临时修复theme的文件丢失问题 <-> 新增实时语音对话插件(自动断句,脱手对话) <-> 支持加载自定义的ChatGLM2微调模型 <-> 动态ChatBot窗口高度 <-> 修复Azure接口的BUG <-> 完善多语言模块 <-> 完善本地Latex矫错和翻译功能 <-> 增加gpt-3.5-16k的支持"
|
"new_feature": "临时修复theme的文件丢失问题 <-> 新增实时语音对话插件(自动断句,脱手对话) <-> 支持加载自定义的ChatGLM2微调模型 <-> 动态ChatBot窗口高度 <-> 修复Azure接口的BUG <-> 完善多语言模块 <-> 完善本地Latex矫错和翻译功能 <-> 增加gpt-3.5-16k的支持 <-> 新增最强Arxiv论文翻译插件 <-> 修复gradio复制按钮BUG <-> 修复PDF翻译的BUG, 新增HTML中英双栏对照 <-> 添加了OpenAI图片生成插件"
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user