镜像自地址
https://github.com/binary-husky/gpt_academic.git
已同步 2025-12-06 22:46:48 +00:00
比较提交
360 次代码提交
hongyi-zha
...
boyin_summ
| 作者 | SHA1 | 提交日期 | |
|---|---|---|---|
|
|
61676d0536 | ||
|
|
df2ef7940c | ||
|
|
c10f2b45e5 | ||
|
|
7e2ede2d12 | ||
|
|
ec10e2a3ac | ||
|
|
7474d43433 | ||
|
|
83489f9acf | ||
|
|
36e50d490d | ||
|
|
9172337695 | ||
|
|
180550b8f0 | ||
|
|
7497dcb852 | ||
|
|
5dab7b2290 | ||
|
|
23ef2ffb22 | ||
|
|
848d0f65c7 | ||
|
|
f0b0364f74 | ||
|
|
89dc6c7265 | ||
|
|
69f3755682 | ||
|
|
4727113243 | ||
|
|
21111d3bd0 | ||
|
|
701018f48c | ||
|
|
8733c4e1e9 | ||
|
|
8498ddf6bf | ||
|
|
3c3293818d | ||
|
|
310122f5a7 | ||
|
|
c83bf214d0 | ||
|
|
e34c49dce5 | ||
|
|
3890467c84 | ||
|
|
074b3c9828 | ||
|
|
b8e8457a01 | ||
|
|
2c93a24d7e | ||
|
|
e9af6ef3a0 | ||
|
|
5ae8981dbb | ||
|
|
adbed044e4 | ||
|
|
2fe5febaf0 | ||
|
|
f54d8e559a | ||
|
|
e68fc2bc69 | ||
|
|
f695d7f1da | ||
|
|
679352d896 | ||
|
|
12c9ab1e33 | ||
|
|
da4a5efc49 | ||
|
|
9ac450cfb6 | ||
|
|
172f9e220b | ||
|
|
a28b7d8475 | ||
|
|
7d3ed36899 | ||
|
|
a7bc5fa357 | ||
|
|
4f5dd9ebcf | ||
|
|
427feb99d8 | ||
|
|
a01ca93362 | ||
|
|
597c320808 | ||
|
|
18290fd138 | ||
|
|
0d0575a639 | ||
|
|
4e041e1d4e | ||
|
|
7ef39770c7 | ||
|
|
8222f638cf | ||
|
|
ab32c314ab | ||
|
|
dcfed97054 | ||
|
|
dd66ca26f7 | ||
|
|
8b91d2ac0a | ||
|
|
e4e00b713f | ||
|
|
710a65522c | ||
|
|
34784c1d40 | ||
|
|
80b1a6f99b | ||
|
|
08c3c56f53 | ||
|
|
294716c832 | ||
|
|
16f4fd636e | ||
|
|
e07caf7a69 | ||
|
|
a95b3daab9 | ||
|
|
4873e9dfdc | ||
|
|
a119ab36fe | ||
|
|
f9384e4e5f | ||
|
|
6fe5f6ee6e | ||
|
|
068d753426 | ||
|
|
5010537f3c | ||
|
|
f35f6633e0 | ||
|
|
573dc4d184 | ||
|
|
da8b2d69ce | ||
|
|
58e732c26f | ||
|
|
ca238daa8c | ||
|
|
60b3491513 | ||
|
|
c1175bfb7d | ||
|
|
b705afd5ff | ||
|
|
dfcd28abce | ||
|
|
1edaa9e234 | ||
|
|
f0cd617ec2 | ||
|
|
0b08bb2cea | ||
|
|
d1f8607ac8 | ||
|
|
7eb68a2086 | ||
|
|
ee9e99036a | ||
|
|
55e255220b | ||
|
|
019cd26ae8 | ||
|
|
a5b21d5cc0 | ||
|
|
ce940ff70f | ||
|
|
fc6a83c29f | ||
|
|
1d3212e367 | ||
|
|
8a835352a3 | ||
|
|
5456c9fa43 | ||
|
|
ea67054c30 | ||
|
|
1084108df6 | ||
|
|
40c9700a8d | ||
|
|
6da5623813 | ||
|
|
778c9cd9ec | ||
|
|
e290317146 | ||
|
|
85b92b7f07 | ||
|
|
ff899777ce | ||
|
|
c1b8c773c3 | ||
|
|
8747c48175 | ||
|
|
c0010c88bc | ||
|
|
68838da8ad | ||
|
|
ca7de8fcdd | ||
|
|
7ebc2d00e7 | ||
|
|
47fb81cfde | ||
|
|
83961c1002 | ||
|
|
a8621333af | ||
|
|
f402ef8134 | ||
|
|
65d0f486f1 | ||
|
|
41f25a6a9b | ||
|
|
4a6a032334 | ||
|
|
f945a7bd19 | ||
|
|
379dcb2fa7 | ||
|
|
114192e025 | ||
|
|
30c905917a | ||
|
|
0c6c357e9c | ||
|
|
9d11b17f25 | ||
|
|
1d9e9fa6a1 | ||
|
|
6cd2d80dfd | ||
|
|
18d3245fc9 | ||
|
|
194e665a3b | ||
|
|
7e201c5028 | ||
|
|
6babcb4a9c | ||
|
|
00e5a31b50 | ||
|
|
d8b9686eeb | ||
|
|
b7b4e201cb | ||
|
|
26e7677dc3 | ||
|
|
25e06de1b6 | ||
|
|
5e64a50898 | ||
|
|
0ad571e6b5 | ||
|
|
60a42fb070 | ||
|
|
ddad5247fc | ||
|
|
c94d5054a2 | ||
|
|
ececfb9b6e | ||
|
|
9f13c5cedf | ||
|
|
68b36042ce | ||
|
|
cac6c50d2f | ||
|
|
f884eb43cf | ||
|
|
d37383dd4e | ||
|
|
dfae4e8081 | ||
|
|
15cc08505f | ||
|
|
c5a82f6ab7 | ||
|
|
768ed4514a | ||
|
|
9dfbff7fd0 | ||
|
|
47cedde954 | ||
|
|
1e16485087 | ||
|
|
f3660d669f | ||
|
|
e6d1cb09cb | ||
|
|
12aebf9707 | ||
|
|
0b5385e5e5 | ||
|
|
2ff1a1fb0b | ||
|
|
cdadd38cf7 | ||
|
|
48e10fb10a | ||
|
|
ba484c55a0 | ||
|
|
ca64a592f5 | ||
|
|
cb96ca132a | ||
|
|
737101b81d | ||
|
|
612caa2f5f | ||
|
|
85dbe4a4bf | ||
|
|
2262a4d80a | ||
|
|
b456ff02ab | ||
|
|
24a21ae320 | ||
|
|
3d5790cc2c | ||
|
|
7de6015800 | ||
|
|
46428b7c7a | ||
|
|
66a50c8019 | ||
|
|
814dc943ac | ||
|
|
96cd1f0b25 | ||
|
|
4fc17f4add | ||
|
|
b3665d8fec | ||
|
|
80c4281888 | ||
|
|
beda56abb0 | ||
|
|
cb16941d01 | ||
|
|
5cf9ac7849 | ||
|
|
51ddb88ceb | ||
|
|
69dfe5d514 | ||
|
|
6819f87512 | ||
|
|
3d51b9d5bb | ||
|
|
bff87ada92 | ||
|
|
a938412b6f | ||
|
|
a48acf6fec | ||
|
|
c6b9ab5214 | ||
|
|
aa3332de69 | ||
|
|
d43175d46d | ||
|
|
8ca9232db2 | ||
|
|
1339aa0e1a | ||
|
|
f41419e767 | ||
|
|
d88c585305 | ||
|
|
0a88d18c7a | ||
|
|
0d0edc2216 | ||
|
|
5e0875fcf4 | ||
|
|
c508b84db8 | ||
|
|
f2b67602bb | ||
|
|
29daba5d2f | ||
|
|
9477824ac1 | ||
|
|
459c5b2d24 | ||
|
|
abf9b5aee5 | ||
|
|
2ce4482146 | ||
|
|
4282b83035 | ||
|
|
537be57c9b | ||
|
|
3aa92d6c80 | ||
|
|
b7eb9aba49 | ||
|
|
881a596a30 | ||
|
|
1b3c331d01 | ||
|
|
70d5f2a7df | ||
|
|
fd2f8b9090 | ||
|
|
225a2de011 | ||
|
|
6aea6d8e2b | ||
|
|
8d85616c27 | ||
|
|
e4533dd24d | ||
|
|
43ed8cb8a8 | ||
|
|
3eff964424 | ||
|
|
ebde98b34b | ||
|
|
6f883031c0 | ||
|
|
fa15059f07 | ||
|
|
685c573619 | ||
|
|
5fcd02506c | ||
|
|
bd5280df1b | ||
|
|
744759704d | ||
|
|
81df0aa210 | ||
|
|
cadaa81030 | ||
|
|
3b6cbbdcb0 | ||
|
|
52e49c48b8 | ||
|
|
6ad15a6129 | ||
|
|
09990d44d3 | ||
|
|
eac5191815 | ||
|
|
ae4407135d | ||
|
|
f0e15bd710 | ||
|
|
5c5f442649 | ||
|
|
160552cc5f | ||
|
|
c131ec0b20 | ||
|
|
2f3aeb7976 | ||
|
|
eff5b89b98 | ||
|
|
f77ab27bc9 | ||
|
|
ba0a8b7072 | ||
|
|
2406022c2a | ||
|
|
02b6f26b05 | ||
|
|
2a003e8d49 | ||
|
|
21891b0f6d | ||
|
|
163f12c533 | ||
|
|
bdd46c5dd1 | ||
|
|
ae51a0e686 | ||
|
|
f2582ea137 | ||
|
|
ddd2fd84da | ||
|
|
6c90ff80ea | ||
|
|
cb7c0703be | ||
|
|
5181cd441d | ||
|
|
216d4374e7 | ||
|
|
8af6c0cab6 | ||
|
|
67ad041372 | ||
|
|
725c72229c | ||
|
|
e42ede512b | ||
|
|
84ccc9e64c | ||
|
|
c172847e19 | ||
|
|
d166d25eb4 | ||
|
|
516bbb1331 | ||
|
|
c3140ce344 | ||
|
|
cd18663800 | ||
|
|
dbf1322836 | ||
|
|
98dd3ae1c0 | ||
|
|
3036709496 | ||
|
|
8e9c07644f | ||
|
|
90d96b77e6 | ||
|
|
66c876a9ca | ||
|
|
0665eb75ed | ||
|
|
6b784035fa | ||
|
|
8bb3d84912 | ||
|
|
a0193cf227 | ||
|
|
b72289bfb0 | ||
|
|
bdfe3862eb | ||
|
|
dae180b9ea | ||
|
|
e359fff040 | ||
|
|
2e9b4a5770 | ||
|
|
e0c5859cf9 | ||
|
|
b9b1e12dc9 | ||
|
|
8814026ec3 | ||
|
|
3025d5be45 | ||
|
|
6c13bb7b46 | ||
|
|
c27e559f10 | ||
|
|
cdb5288f49 | ||
|
|
49c6fcfe97 | ||
|
|
45fa0404eb | ||
|
|
f889ef7625 | ||
|
|
a93bf4410d | ||
|
|
1c0764753a | ||
|
|
c847209ac9 | ||
|
|
4f9d40c14f | ||
|
|
91926d24b7 | ||
|
|
ef311c4859 | ||
|
|
82795d3817 | ||
|
|
49e28a5a00 | ||
|
|
01def2e329 | ||
|
|
2291be2b28 | ||
|
|
c89ec7969f | ||
|
|
1506c19834 | ||
|
|
a6fdc493b7 | ||
|
|
113067c6ab | ||
|
|
7b6828ab07 | ||
|
|
d818c38dfe | ||
|
|
08b4e9796e | ||
|
|
b55d573819 | ||
|
|
06b0e800a2 | ||
|
|
7bbaf05961 | ||
|
|
3b83279855 | ||
|
|
37164a826e | ||
|
|
dd2a97e7a9 | ||
|
|
e579006c4a | ||
|
|
031f19b6dd | ||
|
|
142b516749 | ||
|
|
f2e73aa580 | ||
|
|
8565a35cf7 | ||
|
|
72d78eb150 | ||
|
|
7aeda537ac | ||
|
|
6cea17d4b7 | ||
|
|
20bc51d747 | ||
|
|
b8ebefa427 | ||
|
|
dcc9326f0b | ||
|
|
94fc396eb9 | ||
|
|
e594e1b928 | ||
|
|
8fe545d97b | ||
|
|
6f978fa72e | ||
|
|
19be471aa8 | ||
|
|
38956934fd | ||
|
|
32439e14b5 | ||
|
|
317389bf4b | ||
|
|
2c740fc641 | ||
|
|
96832a8228 | ||
|
|
361557da3c | ||
|
|
5f18d4a1af | ||
|
|
0d10bc570f | ||
|
|
3ce7d9347d | ||
|
|
8a78d7b89f | ||
|
|
0e43b08837 | ||
|
|
74bced2d35 | ||
|
|
961a24846f | ||
|
|
b7e4744f28 | ||
|
|
71adc40901 | ||
|
|
a2099f1622 | ||
|
|
c0a697f6c8 | ||
|
|
bdde1d2fd7 | ||
|
|
63373ab3b6 | ||
|
|
fb6566adde | ||
|
|
9f2ef9ec49 | ||
|
|
35c1aa21e4 | ||
|
|
627d739720 | ||
|
|
37f15185b6 | ||
|
|
9643e1c25f | ||
|
|
28eae2f80e | ||
|
|
7ab379688e | ||
|
|
3d4c6f54f1 | ||
|
|
1714116a89 | ||
|
|
2bc65a99ca | ||
|
|
d698b96209 | ||
|
|
6b1c6f0bf7 |
44
.github/workflows/build-with-jittorllms.yml
vendored
44
.github/workflows/build-with-jittorllms.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-jittorllms
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- 'master'
|
|
||||||
|
|
||||||
env:
|
|
||||||
REGISTRY: ghcr.io
|
|
||||||
IMAGE_NAME: ${{ github.repository }}_jittorllms
|
|
||||||
|
|
||||||
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+JittorLLMs
|
|
||||||
tags: ${{ steps.meta.outputs.tags }}
|
|
||||||
labels: ${{ steps.meta.outputs.labels }}
|
|
||||||
@@ -1,14 +1,14 @@
|
|||||||
# https://docs.github.com/en/actions/publishing-packages/publishing-docker-images#publishing-images-to-github-packages
|
# https://docs.github.com/en/actions/publishing-packages/publishing-docker-images#publishing-images-to-github-packages
|
||||||
name: build-with-all-capacity-beta
|
name: build-with-latex-arm
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- 'master'
|
- "master"
|
||||||
|
|
||||||
env:
|
env:
|
||||||
REGISTRY: ghcr.io
|
REGISTRY: ghcr.io
|
||||||
IMAGE_NAME: ${{ github.repository }}_with_all_capacity_beta
|
IMAGE_NAME: ${{ github.repository }}_with_latex_arm
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build-and-push-image:
|
build-and-push-image:
|
||||||
@@ -18,11 +18,17 @@ jobs:
|
|||||||
packages: write
|
packages: write
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
|
- name: Set up QEMU
|
||||||
|
uses: docker/setup-qemu-action@v3
|
||||||
|
|
||||||
|
- name: Set up Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v3
|
||||||
|
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Log in to the Container registry
|
- name: Log in to the Container registry
|
||||||
uses: docker/login-action@v2
|
uses: docker/login-action@v3
|
||||||
with:
|
with:
|
||||||
registry: ${{ env.REGISTRY }}
|
registry: ${{ env.REGISTRY }}
|
||||||
username: ${{ github.actor }}
|
username: ${{ github.actor }}
|
||||||
@@ -35,10 +41,11 @@ jobs:
|
|||||||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
||||||
|
|
||||||
- name: Build and push Docker image
|
- name: Build and push Docker image
|
||||||
uses: docker/build-push-action@v4
|
uses: docker/build-push-action@v6
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
push: true
|
push: true
|
||||||
file: docs/GithubAction+AllCapacityBeta
|
platforms: linux/arm64
|
||||||
|
file: docs/GithubAction+NoLocal+Latex
|
||||||
tags: ${{ steps.meta.outputs.tags }}
|
tags: ${{ steps.meta.outputs.tags }}
|
||||||
labels: ${{ steps.meta.outputs.labels }}
|
labels: ${{ steps.meta.outputs.labels }}
|
||||||
8
.gitignore
vendored
8
.gitignore
vendored
@@ -131,6 +131,9 @@ dmypy.json
|
|||||||
# Pyre type checker
|
# Pyre type checker
|
||||||
.pyre/
|
.pyre/
|
||||||
|
|
||||||
|
# macOS files
|
||||||
|
.DS_Store
|
||||||
|
|
||||||
.vscode
|
.vscode
|
||||||
.idea
|
.idea
|
||||||
|
|
||||||
@@ -153,3 +156,8 @@ media
|
|||||||
flagged
|
flagged
|
||||||
request_llms/ChatGLM-6b-onnx-u8s8
|
request_llms/ChatGLM-6b-onnx-u8s8
|
||||||
.pre-commit-config.yaml
|
.pre-commit-config.yaml
|
||||||
|
test.*
|
||||||
|
temp.*
|
||||||
|
objdump*
|
||||||
|
*.min.*.js
|
||||||
|
TODO
|
||||||
@@ -12,13 +12,17 @@ RUN echo '[global]' > /etc/pip.conf && \
|
|||||||
echo 'trusted-host = mirrors.aliyun.com' >> /etc/pip.conf
|
echo 'trusted-host = mirrors.aliyun.com' >> /etc/pip.conf
|
||||||
|
|
||||||
|
|
||||||
|
# 语音输出功能(以下两行,第一行更换阿里源,第二行安装ffmpeg,都可以删除)
|
||||||
|
RUN UBUNTU_VERSION=$(awk -F= '/^VERSION_CODENAME=/{print $2}' /etc/os-release); echo "deb https://mirrors.aliyun.com/debian/ $UBUNTU_VERSION main non-free contrib" > /etc/apt/sources.list; apt-get update
|
||||||
|
RUN apt-get install ffmpeg -y
|
||||||
|
|
||||||
|
|
||||||
# 进入工作路径(必要)
|
# 进入工作路径(必要)
|
||||||
WORKDIR /gpt
|
WORKDIR /gpt
|
||||||
|
|
||||||
|
|
||||||
# 安装大部分依赖,利用Docker缓存加速以后的构建 (以下三行,可以删除)
|
# 安装大部分依赖,利用Docker缓存加速以后的构建 (以下两行,可以删除)
|
||||||
COPY requirements.txt ./
|
COPY requirements.txt ./
|
||||||
COPY ./docs/gradio-3.32.6-py3-none-any.whl ./docs/gradio-3.32.6-py3-none-any.whl
|
|
||||||
RUN pip3 install -r requirements.txt
|
RUN pip3 install -r requirements.txt
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
104
README.md
104
README.md
@@ -1,8 +1,9 @@
|
|||||||
> **Caution**
|
> [!IMPORTANT]
|
||||||
>
|
> 2024.10.10: 突发停电,紧急恢复了提供[whl包](https://drive.google.com/file/d/19U_hsLoMrjOlQSzYS3pzWX9fTzyusArP/view?usp=sharing)的文件服务器
|
||||||
> 2023.11.12: 某些依赖包尚不兼容python 3.12,推荐python 3.11。
|
> 2024.10.8: 版本3.90加入对llama-index的初步支持,版本3.80加入插件二级菜单功能(详见wiki)
|
||||||
>
|
> 2024.5.1: 加入Doc2x翻译PDF论文的功能,[查看详情](https://github.com/binary-husky/gpt_academic/wiki/Doc2x)
|
||||||
> 2023.12.26: 安装依赖时,请选择`requirements.txt`中**指定的版本**。 安装命令:`pip install -r requirements.txt`。本项目完全开源免费,您可通过订阅[在线服务](https://github.com/binary-husky/gpt_academic/wiki/online)的方式鼓励本项目的发展。
|
> 2024.3.11: 全力支持Qwen、GLM、DeepseekCoder等中文大语言模型! SoVits语音克隆模块,[查看详情](https://www.bilibili.com/video/BV1Rp421S7tF/)
|
||||||
|
> 2024.1.17: 安装依赖时,请选择`requirements.txt`中**指定的版本**。 安装命令:`pip install -r requirements.txt`。本项目完全开源免费,您可通过订阅[在线服务](https://github.com/binary-husky/gpt_academic/wiki/online)的方式鼓励本项目的发展。
|
||||||
|
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
@@ -42,13 +43,11 @@ If you like this project, please give it a Star.
|
|||||||
Read this in [English](docs/README.English.md) | [日本語](docs/README.Japanese.md) | [한국어](docs/README.Korean.md) | [Русский](docs/README.Russian.md) | [Français](docs/README.French.md). All translations have been provided by the project itself. To translate this project to arbitrary language with GPT, read and run [`multi_language.py`](multi_language.py) (experimental).
|
Read this in [English](docs/README.English.md) | [日本語](docs/README.Japanese.md) | [한국어](docs/README.Korean.md) | [Русский](docs/README.Russian.md) | [Français](docs/README.French.md). All translations have been provided by the project itself. To translate this project to arbitrary language with GPT, read and run [`multi_language.py`](multi_language.py) (experimental).
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
|
> [!NOTE]
|
||||||
> 1.请注意只有 **高亮** 标识的插件(按钮)才支持读取文件,部分插件位于插件区的**下拉菜单**中。另外我们以**最高优先级**欢迎和处理任何新插件的PR。
|
> 1.本项目中每个文件的功能都在[自译解报告](https://github.com/binary-husky/gpt_academic/wiki/GPT‐Academic项目自译解报告)`self_analysis.md`详细说明。随着版本的迭代,您也可以随时自行点击相关函数插件,调用GPT重新生成项目的自我解析报告。常见问题请查阅wiki。
|
||||||
>
|
|
||||||
> 2.本项目中每个文件的功能都在[自译解报告](https://github.com/binary-husky/gpt_academic/wiki/GPT‐Academic项目自译解报告)`self_analysis.md`详细说明。随着版本的迭代,您也可以随时自行点击相关函数插件,调用GPT重新生成项目的自我解析报告。常见问题请查阅wiki。
|
|
||||||
> [](#installation) [](https://github.com/binary-husky/gpt_academic/releases) [](https://github.com/binary-husky/gpt_academic/wiki/项目配置说明) []([https://github.com/binary-husky/gpt_academic/wiki/项目配置说明](https://github.com/binary-husky/gpt_academic/wiki))
|
> [](#installation) [](https://github.com/binary-husky/gpt_academic/releases) [](https://github.com/binary-husky/gpt_academic/wiki/项目配置说明) []([https://github.com/binary-husky/gpt_academic/wiki/项目配置说明](https://github.com/binary-husky/gpt_academic/wiki))
|
||||||
>
|
>
|
||||||
> 3.本项目兼容并鼓励尝试国产大语言模型ChatGLM等。支持多个api-key共存,可在配置文件中填写如`API_KEY="openai-key1,openai-key2,azure-key3,api2d-key4"`。需要临时更换`API_KEY`时,在输入区输入临时的`API_KEY`然后回车键提交即可生效。
|
> 2.本项目兼容并鼓励尝试国内中文大语言基座模型如通义千问,智谱GLM等。支持多个api-key共存,可在配置文件中填写如`API_KEY="openai-key1,openai-key2,azure-key3,api2d-key4"`。需要临时更换`API_KEY`时,在输入区输入临时的`API_KEY`然后回车键提交即可生效。
|
||||||
|
|
||||||
<br><br>
|
<br><br>
|
||||||
|
|
||||||
@@ -56,7 +55,12 @@ Read this in [English](docs/README.English.md) | [日本語](docs/README.Japanes
|
|||||||
|
|
||||||
功能(⭐= 近期新增功能) | 描述
|
功能(⭐= 近期新增功能) | 描述
|
||||||
--- | ---
|
--- | ---
|
||||||
⭐[接入新模型](https://github.com/binary-husky/gpt_academic/wiki/%E5%A6%82%E4%BD%95%E5%88%87%E6%8D%A2%E6%A8%A1%E5%9E%8B) | 百度[千帆](https://cloud.baidu.com/doc/WENXINWORKSHOP/s/Nlks5zkzu)与文心一言, 通义千问[Qwen](https://modelscope.cn/models/qwen/Qwen-7B-Chat/summary),上海AI-Lab[书生](https://github.com/InternLM/InternLM),讯飞[星火](https://xinghuo.xfyun.cn/),[LLaMa2](https://huggingface.co/meta-llama/Llama-2-7b-chat-hf),[智谱API](https://open.bigmodel.cn/),DALLE3, [DeepseekCoder](https://coder.deepseek.com/)
|
⭐[接入新模型](https://github.com/binary-husky/gpt_academic/wiki/%E5%A6%82%E4%BD%95%E5%88%87%E6%8D%A2%E6%A8%A1%E5%9E%8B) | 百度[千帆](https://cloud.baidu.com/doc/WENXINWORKSHOP/s/Nlks5zkzu)与文心一言, 通义千问[Qwen](https://modelscope.cn/models/qwen/Qwen-7B-Chat/summary),上海AI-Lab[书生](https://github.com/InternLM/InternLM),讯飞[星火](https://xinghuo.xfyun.cn/),[LLaMa2](https://huggingface.co/meta-llama/Llama-2-7b-chat-hf),[智谱GLM4](https://open.bigmodel.cn/),DALLE3, [DeepseekCoder](https://coder.deepseek.com/)
|
||||||
|
⭐支持mermaid图像渲染 | 支持让GPT生成[流程图](https://www.bilibili.com/video/BV18c41147H9/)、状态转移图、甘特图、饼状图、GitGraph等等(3.7版本)
|
||||||
|
⭐Arxiv论文精细翻译 ([Docker](https://github.com/binary-husky/gpt_academic/pkgs/container/gpt_academic_with_latex)) | [插件] 一键[以超高质量翻译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/),自动断句,自动寻找回答时机
|
||||||
|
⭐AutoGen多智能体插件 | [插件] 借助微软AutoGen,探索多Agent的智能涌现可能!
|
||||||
|
⭐虚空终端插件 | [插件] 能够使用自然语言直接调度本项目其他插件
|
||||||
润色、翻译、代码解释 | 一键润色、翻译、查找论文语法错误、解释代码
|
润色、翻译、代码解释 | 一键润色、翻译、查找论文语法错误、解释代码
|
||||||
[自定义快捷键](https://www.bilibili.com/video/BV14s4y1E7jN) | 支持自定义快捷键
|
[自定义快捷键](https://www.bilibili.com/video/BV14s4y1E7jN) | 支持自定义快捷键
|
||||||
模块化设计 | 支持自定义强大的[插件](https://github.com/binary-husky/gpt_academic/tree/master/crazy_functions),插件支持[热更新](https://github.com/binary-husky/gpt_academic/wiki/%E5%87%BD%E6%95%B0%E6%8F%92%E4%BB%B6%E6%8C%87%E5%8D%97)
|
模块化设计 | 支持自定义强大的[插件](https://github.com/binary-husky/gpt_academic/tree/master/crazy_functions),插件支持[热更新](https://github.com/binary-husky/gpt_academic/wiki/%E5%87%BD%E6%95%B0%E6%8F%92%E4%BB%B6%E6%8C%87%E5%8D%97)
|
||||||
@@ -64,23 +68,17 @@ Read this in [English](docs/README.English.md) | [日本語](docs/README.Japanes
|
|||||||
读论文、[翻译](https://www.bilibili.com/video/BV1KT411x7Wn)论文 | [插件] 一键解读latex/pdf论文全文并生成摘要
|
读论文、[翻译](https://www.bilibili.com/video/BV1KT411x7Wn)论文 | [插件] 一键解读latex/pdf论文全文并生成摘要
|
||||||
Latex全文[翻译](https://www.bilibili.com/video/BV1nk4y1Y7Js/)、[润色](https://www.bilibili.com/video/BV1FT411H7c5/) | [插件] 一键翻译或润色latex论文
|
Latex全文[翻译](https://www.bilibili.com/video/BV1nk4y1Y7Js/)、[润色](https://www.bilibili.com/video/BV1FT411H7c5/) | [插件] 一键翻译或润色latex论文
|
||||||
批量注释生成 | [插件] 一键批量生成函数注释
|
批量注释生成 | [插件] 一键批量生成函数注释
|
||||||
Markdown[中英互译](https://www.bilibili.com/video/BV1yo4y157jV/) | [插件] 看到上面5种语言的[README](https://github.com/binary-husky/gpt_academic/blob/master/docs/README_EN.md)了吗?就是出自他的手笔
|
Markdown[中英互译](https://www.bilibili.com/video/BV1yo4y157jV/) | [插件] 看到上面5种语言的[README](https://github.com/binary-husky/gpt_academic/blob/master/docs/README.English.md)了吗?就是出自他的手笔
|
||||||
chat分析报告生成 | [插件] 运行后自动生成总结汇报
|
|
||||||
[PDF论文全文翻译功能](https://www.bilibili.com/video/BV1KT411x7Wn) | [插件] PDF论文提取题目&摘要+翻译全文(多线程)
|
[PDF论文全文翻译功能](https://www.bilibili.com/video/BV1KT411x7Wn) | [插件] PDF论文提取题目&摘要+翻译全文(多线程)
|
||||||
[Arxiv小助手](https://www.bilibili.com/video/BV1LM4y1279X) | [插件] 输入arxiv文章url即可一键翻译摘要+下载PDF
|
[Arxiv小助手](https://www.bilibili.com/video/BV1LM4y1279X) | [插件] 输入arxiv文章url即可一键翻译摘要+下载PDF
|
||||||
Latex论文一键校对 | [插件] 仿Grammarly对Latex文章进行语法、拼写纠错+输出对照PDF
|
Latex论文一键校对 | [插件] 仿Grammarly对Latex文章进行语法、拼写纠错+输出对照PDF
|
||||||
[谷歌学术统合小助手](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/),目前最好的论文翻译工具
|
|
||||||
⭐[实时语音对话输入](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),支持公式、代码高亮
|
||||||
⭐AutoGen多智能体插件 | [插件] 借助微软AutoGen,探索多Agent的智能涌现可能!
|
|
||||||
启动暗色[主题](https://github.com/binary-husky/gpt_academic/issues/173) | 在浏览器url后面添加```/?__theme=dark```可以切换dark主题
|
启动暗色[主题](https://github.com/binary-husky/gpt_academic/issues/173) | 在浏览器url后面添加```/?__theme=dark```可以切换dark主题
|
||||||
[多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微调辅助插件
|
|
||||||
更多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/)
|
||||||
⭐[void-terminal](https://github.com/binary-husky/void-terminal) pip包 | 脱离GUI,在Python中直接调用本项目的所有函数插件(开发中)
|
⭐[void-terminal](https://github.com/binary-husky/void-terminal) pip包 | 脱离GUI,在Python中直接调用本项目的所有函数插件(开发中)
|
||||||
⭐虚空终端插件 | [插件] 能够使用自然语言直接调度本项目其他插件
|
|
||||||
更多新功能展示 (图像生成等) …… | 见本文档结尾处 ……
|
更多新功能展示 (图像生成等) …… | 见本文档结尾处 ……
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -90,6 +88,10 @@ Latex论文一键校对 | [插件] 仿Grammarly对Latex文章进行语法、拼
|
|||||||
<img src="https://user-images.githubusercontent.com/96192199/279702205-d81137c3-affd-4cd1-bb5e-b15610389762.gif" width="700" >
|
<img src="https://user-images.githubusercontent.com/96192199/279702205-d81137c3-affd-4cd1-bb5e-b15610389762.gif" width="700" >
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div align="center">
|
||||||
|
<img src="https://github.com/binary-husky/gpt_academic/assets/96192199/70ff1ec5-e589-4561-a29e-b831079b37fb.gif" width="700" >
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
- 所有按钮都通过读取functional.py动态生成,可随意加自定义功能,解放剪贴板
|
- 所有按钮都通过读取functional.py动态生成,可随意加自定义功能,解放剪贴板
|
||||||
<div align="center">
|
<div align="center">
|
||||||
@@ -119,6 +121,25 @@ Latex论文一键校对 | [插件] 仿Grammarly对Latex文章进行语法、拼
|
|||||||
<br><br>
|
<br><br>
|
||||||
|
|
||||||
# Installation
|
# Installation
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart TD
|
||||||
|
A{"安装方法"} --> W1("I. 🔑直接运行 (Windows, Linux or MacOS)")
|
||||||
|
W1 --> W11["1. Python pip包管理依赖"]
|
||||||
|
W1 --> W12["2. Anaconda包管理依赖(推荐⭐)"]
|
||||||
|
|
||||||
|
A --> W2["II. 🐳使用Docker (Windows, Linux or MacOS)"]
|
||||||
|
|
||||||
|
W2 --> k1["1. 部署项目全部能力的大镜像(推荐⭐)"]
|
||||||
|
W2 --> k2["2. 仅在线模型(GPT, GLM4等)镜像"]
|
||||||
|
W2 --> k3["3. 在线模型 + Latex的大镜像"]
|
||||||
|
|
||||||
|
A --> W4["IV. 🚀其他部署方法"]
|
||||||
|
W4 --> C1["1. Windows/MacOS 一键安装运行脚本(推荐⭐)"]
|
||||||
|
W4 --> C2["2. Huggingface, Sealos远程部署"]
|
||||||
|
W4 --> C4["3. ... 其他 ..."]
|
||||||
|
```
|
||||||
|
|
||||||
### 安装方法I:直接运行 (Windows, Linux or MacOS)
|
### 安装方法I:直接运行 (Windows, Linux or MacOS)
|
||||||
|
|
||||||
1. 下载项目
|
1. 下载项目
|
||||||
@@ -132,7 +153,7 @@ Latex论文一键校对 | [插件] 仿Grammarly对Latex文章进行语法、拼
|
|||||||
|
|
||||||
在`config.py`中,配置API KEY等变量。[特殊网络环境设置方法](https://github.com/binary-husky/gpt_academic/issues/1)、[Wiki-项目配置说明](https://github.com/binary-husky/gpt_academic/wiki/项目配置说明)。
|
在`config.py`中,配置API KEY等变量。[特殊网络环境设置方法](https://github.com/binary-husky/gpt_academic/issues/1)、[Wiki-项目配置说明](https://github.com/binary-husky/gpt_academic/wiki/项目配置说明)。
|
||||||
|
|
||||||
「 程序会优先检查是否存在名为`config_private.py`的私密配置文件,并用其中的配置覆盖`config.py`的同名配置。如您能理解以上读取逻辑,我们强烈建议您在`config.py`同路径下创建一个名为`config_private.py`的新配置文件,并使用`config_private.py`配置项目,以确保更新或其他用户无法轻易查看您的私有配置 」。
|
「 程序会优先检查是否存在名为`config_private.py`的私密配置文件,并用其中的配置覆盖`config.py`的同名配置。如您能理解以上读取逻辑,我们强烈建议您在`config.py`同路径下创建一个名为`config_private.py`的新配置文件,并使用`config_private.py`配置项目,从而确保自动更新时不会丢失配置 」。
|
||||||
|
|
||||||
「 支持通过`环境变量`配置项目,环境变量的书写格式参考`docker-compose.yml`文件或者我们的[Wiki页面](https://github.com/binary-husky/gpt_academic/wiki/项目配置说明)。配置读取优先级: `环境变量` > `config_private.py` > `config.py` 」。
|
「 支持通过`环境变量`配置项目,环境变量的书写格式参考`docker-compose.yml`文件或者我们的[Wiki页面](https://github.com/binary-husky/gpt_academic/wiki/项目配置说明)。配置读取优先级: `环境变量` > `config_private.py` > `config.py` 」。
|
||||||
|
|
||||||
@@ -152,10 +173,10 @@ Latex论文一键校对 | [插件] 仿Grammarly对Latex文章进行语法、拼
|
|||||||
<details><summary>如果需要支持清华ChatGLM2/复旦MOSS/RWKV作为后端,请点击展开此处</summary>
|
<details><summary>如果需要支持清华ChatGLM2/复旦MOSS/RWKV作为后端,请点击展开此处</summary>
|
||||||
<p>
|
<p>
|
||||||
|
|
||||||
【可选步骤】如果需要支持清华ChatGLM2/复旦MOSS作为后端,需要额外安装更多依赖(前提条件:熟悉Python + 用过Pytorch + 电脑配置够强):
|
【可选步骤】如果需要支持清华ChatGLM3/复旦MOSS作为后端,需要额外安装更多依赖(前提条件:熟悉Python + 用过Pytorch + 电脑配置够强):
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
# 【可选步骤I】支持清华ChatGLM2。清华ChatGLM备注:如果遇到"Call ChatGLM fail 不能正常加载ChatGLM的参数" 错误,参考如下: 1:以上默认安装的为torch+cpu版,使用cuda需要卸载torch重新安装torch+cuda; 2:如因本机配置不够无法加载模型,可以修改request_llm/bridge_chatglm.py中的模型精度, 将 AutoTokenizer.from_pretrained("THUDM/chatglm-6b", trust_remote_code=True) 都修改为 AutoTokenizer.from_pretrained("THUDM/chatglm-6b-int4", trust_remote_code=True)
|
# 【可选步骤I】支持清华ChatGLM3。清华ChatGLM备注:如果遇到"Call ChatGLM fail 不能正常加载ChatGLM的参数" 错误,参考如下: 1:以上默认安装的为torch+cpu版,使用cuda需要卸载torch重新安装torch+cuda; 2:如因本机配置不够无法加载模型,可以修改request_llm/bridge_chatglm.py中的模型精度, 将 AutoTokenizer.from_pretrained("THUDM/chatglm-6b", trust_remote_code=True) 都修改为 AutoTokenizer.from_pretrained("THUDM/chatglm-6b-int4", trust_remote_code=True)
|
||||||
python -m pip install -r request_llms/requirements_chatglm.txt
|
python -m pip install -r request_llms/requirements_chatglm.txt
|
||||||
|
|
||||||
# 【可选步骤II】支持复旦MOSS
|
# 【可选步骤II】支持复旦MOSS
|
||||||
@@ -197,7 +218,7 @@ pip install peft
|
|||||||
docker-compose up
|
docker-compose up
|
||||||
```
|
```
|
||||||
|
|
||||||
1. 仅ChatGPT+文心一言+spark等在线模型(推荐大多数人选择)
|
1. 仅ChatGPT + GLM4 + 文心一言+spark等在线模型(推荐大多数人选择)
|
||||||
[](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)
|
[](https://github.com/binary-husky/gpt_academic/actions/workflows/build-with-audio-assistant.yml)
|
||||||
@@ -209,7 +230,7 @@ pip install peft
|
|||||||
|
|
||||||
P.S. 如果需要依赖Latex的插件功能,请见Wiki。另外,您也可以直接使用方案4或者方案0获取Latex功能。
|
P.S. 如果需要依赖Latex的插件功能,请见Wiki。另外,您也可以直接使用方案4或者方案0获取Latex功能。
|
||||||
|
|
||||||
2. ChatGPT + ChatGLM2 + MOSS + LLAMA2 + 通义千问(需要熟悉[Nvidia Docker](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/install-guide.html#installing-on-ubuntu-and-debian)运行时)
|
2. ChatGPT + GLM3 + MOSS + LLAMA2 + 通义千问(需要熟悉[Nvidia Docker](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/install-guide.html#installing-on-ubuntu-and-debian)运行时)
|
||||||
[](https://github.com/binary-husky/gpt_academic/actions/workflows/build-with-chatglm.yml)
|
[](https://github.com/binary-husky/gpt_academic/actions/workflows/build-with-chatglm.yml)
|
||||||
|
|
||||||
``` sh
|
``` sh
|
||||||
@@ -237,8 +258,7 @@ P.S. 如果需要依赖Latex的插件功能,请见Wiki。另外,您也可以
|
|||||||
# Advanced Usage
|
# Advanced Usage
|
||||||
### I:自定义新的便捷按钮(学术快捷键)
|
### I:自定义新的便捷按钮(学术快捷键)
|
||||||
|
|
||||||
任意文本编辑器打开`core_functional.py`,添加如下条目,然后重启程序。(如果按钮已存在,那么可以直接修改(前缀、后缀都已支持热修改),无需重启程序即可生效。)
|
现在已可以通过UI中的`界面外观`菜单中的`自定义菜单`添加新的便捷按钮。如果需要在代码中定义,请使用任意文本编辑器打开`core_functional.py`,添加如下条目即可:
|
||||||
例如
|
|
||||||
|
|
||||||
```python
|
```python
|
||||||
"超级英译中": {
|
"超级英译中": {
|
||||||
@@ -308,9 +328,9 @@ Tip:不指定文件直接点击 `载入对话历史存档` 可以查看历史h
|
|||||||
<img src="https://github.com/binary-husky/gpt_academic/assets/96192199/bc7ab234-ad90-48a0-8d62-f703d9e74665" width="500" >
|
<img src="https://github.com/binary-husky/gpt_academic/assets/96192199/bc7ab234-ad90-48a0-8d62-f703d9e74665" width="500" >
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
8. OpenAI音频解析与总结
|
8. 基于mermaid的流图、脑图绘制
|
||||||
<div align="center">
|
<div align="center">
|
||||||
<img src="https://github.com/binary-husky/gpt_academic/assets/96192199/709ccf95-3aee-498a-934a-e1c22d3d5d5b" width="500" >
|
<img src="https://github.com/binary-husky/gpt_academic/assets/96192199/c518b82f-bd53-46e2-baf5-ad1b081c1da4" width="500" >
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
9. Latex全文校对纠错
|
9. Latex全文校对纠错
|
||||||
@@ -327,8 +347,8 @@ Tip:不指定文件直接点击 `载入对话历史存档` 可以查看历史h
|
|||||||
|
|
||||||
|
|
||||||
### II:版本:
|
### II:版本:
|
||||||
|
- version 3.80(TODO): 优化AutoGen插件主题并设计一系列衍生插件
|
||||||
- version 3.70(todo): 优化AutoGen插件主题并设计一系列衍生插件
|
- version 3.70: 引入Mermaid绘图,实现GPT画脑图等功能
|
||||||
- version 3.60: 引入AutoGen作为新一代插件的基石
|
- version 3.60: 引入AutoGen作为新一代插件的基石
|
||||||
- version 3.57: 支持GLM3,星火v3,文心一言v4,修复本地模型的并发BUG
|
- version 3.57: 支持GLM3,星火v3,文心一言v4,修复本地模型的并发BUG
|
||||||
- version 3.56: 支持动态追加基础功能按钮,新汇报PDF汇总页面
|
- version 3.56: 支持动态追加基础功能按钮,新汇报PDF汇总页面
|
||||||
@@ -361,6 +381,32 @@ GPT Academic开发者QQ群:`610599535`
|
|||||||
- 某些浏览器翻译插件干扰此软件前端的运行
|
- 某些浏览器翻译插件干扰此软件前端的运行
|
||||||
- 官方Gradio目前有很多兼容性问题,请**务必使用`requirement.txt`安装Gradio**
|
- 官方Gradio目前有很多兼容性问题,请**务必使用`requirement.txt`安装Gradio**
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
timeline LR
|
||||||
|
title GPT-Academic项目发展历程
|
||||||
|
section 2.x
|
||||||
|
1.0~2.2: 基础功能: 引入模块化函数插件: 可折叠式布局: 函数插件支持热重载
|
||||||
|
2.3~2.5: 增强多线程交互性: 新增PDF全文翻译功能: 新增输入区切换位置的功能: 自更新
|
||||||
|
2.6: 重构了插件结构: 提高了交互性: 加入更多插件
|
||||||
|
section 3.x
|
||||||
|
3.0~3.1: 对chatglm支持: 对其他小型llm支持: 支持同时问询多个gpt模型: 支持多个apikey负载均衡
|
||||||
|
3.2~3.3: 函数插件支持更多参数接口: 保存对话功能: 解读任意语言代码: 同时询问任意的LLM组合: 互联网信息综合功能
|
||||||
|
3.4: 加入arxiv论文翻译: 加入latex论文批改功能
|
||||||
|
3.44: 正式支持Azure: 优化界面易用性
|
||||||
|
3.46: 自定义ChatGLM2微调模型: 实时语音对话
|
||||||
|
3.49: 支持阿里达摩院通义千问: 上海AI-Lab书生: 讯飞星火: 支持百度千帆平台 & 文心一言
|
||||||
|
3.50: 虚空终端: 支持插件分类: 改进UI: 设计新主题
|
||||||
|
3.53: 动态选择不同界面主题: 提高稳定性: 解决多用户冲突问题
|
||||||
|
3.55: 动态代码解释器: 重构前端界面: 引入悬浮窗口与菜单栏
|
||||||
|
3.56: 动态追加基础功能按钮: 新汇报PDF汇总页面
|
||||||
|
3.57: GLM3, 星火v3: 支持文心一言v4: 修复本地模型的并发BUG
|
||||||
|
3.60: 引入AutoGen
|
||||||
|
3.70: 引入Mermaid绘图: 实现GPT画脑图等功能
|
||||||
|
3.80(TODO): 优化AutoGen插件主题: 设计衍生插件
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
### III:主题
|
### III:主题
|
||||||
可以通过修改`THEME`选项(config.py)变更主题
|
可以通过修改`THEME`选项(config.py)变更主题
|
||||||
1. `Chuanhu-Small-and-Beautiful` [网址](https://github.com/GaiZhenbiao/ChuanhuChatGPT/)
|
1. `Chuanhu-Small-and-Beautiful` [网址](https://github.com/GaiZhenbiao/ChuanhuChatGPT/)
|
||||||
|
|||||||
149
check_proxy.py
149
check_proxy.py
@@ -1,37 +1,77 @@
|
|||||||
|
from loguru import logger
|
||||||
|
|
||||||
def check_proxy(proxies):
|
def check_proxy(proxies, return_ip=False):
|
||||||
|
"""
|
||||||
|
检查代理配置并返回结果。
|
||||||
|
|
||||||
|
Args:
|
||||||
|
proxies (dict): 包含http和https代理配置的字典。
|
||||||
|
return_ip (bool, optional): 是否返回代理的IP地址。默认为False。
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str or None: 检查的结果信息或代理的IP地址(如果`return_ip`为True)。
|
||||||
|
"""
|
||||||
import requests
|
import requests
|
||||||
proxies_https = proxies['https'] if proxies is not None else '无'
|
proxies_https = proxies['https'] if proxies is not None else '无'
|
||||||
|
ip = None
|
||||||
try:
|
try:
|
||||||
response = requests.get("https://ipapi.co/json/", proxies=proxies, timeout=4)
|
response = requests.get("https://ipapi.co/json/", proxies=proxies, timeout=4) # ⭐ 执行GET请求以获取代理信息
|
||||||
data = response.json()
|
data = response.json()
|
||||||
if 'country_name' in data:
|
if 'country_name' in data:
|
||||||
country = data['country_name']
|
country = data['country_name']
|
||||||
result = f"代理配置 {proxies_https}, 代理所在地:{country}"
|
result = f"代理配置 {proxies_https}, 代理所在地:{country}"
|
||||||
|
if 'ip' in data:
|
||||||
|
ip = data['ip']
|
||||||
elif 'error' in data:
|
elif 'error' in data:
|
||||||
alternative = _check_with_backup_source(proxies)
|
alternative, ip = _check_with_backup_source(proxies) # ⭐ 调用备用方法检查代理配置
|
||||||
if alternative is None:
|
if alternative is None:
|
||||||
result = f"代理配置 {proxies_https}, 代理所在地:未知,IP查询频率受限"
|
result = f"代理配置 {proxies_https}, 代理所在地:未知,IP查询频率受限"
|
||||||
else:
|
else:
|
||||||
result = f"代理配置 {proxies_https}, 代理所在地:{alternative}"
|
result = f"代理配置 {proxies_https}, 代理所在地:{alternative}"
|
||||||
else:
|
else:
|
||||||
result = f"代理配置 {proxies_https}, 代理数据解析失败:{data}"
|
result = f"代理配置 {proxies_https}, 代理数据解析失败:{data}"
|
||||||
print(result)
|
|
||||||
|
if not return_ip:
|
||||||
|
logger.warning(result)
|
||||||
return result
|
return result
|
||||||
|
else:
|
||||||
|
return ip
|
||||||
except:
|
except:
|
||||||
result = f"代理配置 {proxies_https}, 代理所在地查询超时,代理可能无效"
|
result = f"代理配置 {proxies_https}, 代理所在地查询超时,代理可能无效"
|
||||||
print(result)
|
if not return_ip:
|
||||||
|
logger.warning(result)
|
||||||
return result
|
return result
|
||||||
|
else:
|
||||||
|
return ip
|
||||||
|
|
||||||
def _check_with_backup_source(proxies):
|
def _check_with_backup_source(proxies):
|
||||||
|
"""
|
||||||
|
通过备份源检查代理,并获取相应信息。
|
||||||
|
|
||||||
|
Args:
|
||||||
|
proxies (dict): 包含代理信息的字典。
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
tuple: 代理信息(geo)和IP地址(ip)的元组。
|
||||||
|
"""
|
||||||
import random, string, requests
|
import random, string, requests
|
||||||
random_string = ''.join(random.choices(string.ascii_letters + string.digits, k=32))
|
random_string = ''.join(random.choices(string.ascii_letters + string.digits, k=32))
|
||||||
try: return requests.get(f"http://{random_string}.edns.ip-api.com/json", proxies=proxies, timeout=4).json()['dns']['geo']
|
try:
|
||||||
except: return None
|
res_json = requests.get(f"http://{random_string}.edns.ip-api.com/json", proxies=proxies, timeout=4).json() # ⭐ 执行代理检查和备份源请求
|
||||||
|
return res_json['dns']['geo'], res_json['dns']['ip']
|
||||||
|
except:
|
||||||
|
return None, None
|
||||||
|
|
||||||
def backup_and_download(current_version, remote_version):
|
def backup_and_download(current_version, remote_version):
|
||||||
"""
|
"""
|
||||||
一键更新协议:备份和下载
|
一键更新协议:备份当前版本,下载远程版本并解压缩。
|
||||||
|
|
||||||
|
Args:
|
||||||
|
current_version (str): 当前版本号。
|
||||||
|
remote_version (str): 远程版本号。
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: 新版本目录的路径。
|
||||||
"""
|
"""
|
||||||
from toolbox import get_conf
|
from toolbox import get_conf
|
||||||
import shutil
|
import shutil
|
||||||
@@ -47,8 +87,8 @@ def backup_and_download(current_version, remote_version):
|
|||||||
shutil.copytree('./', backup_dir, ignore=lambda x, y: ['history'])
|
shutil.copytree('./', backup_dir, ignore=lambda x, y: ['history'])
|
||||||
proxies = get_conf('proxies')
|
proxies = get_conf('proxies')
|
||||||
try: r = requests.get('https://github.com/binary-husky/chatgpt_academic/archive/refs/heads/master.zip', proxies=proxies, stream=True)
|
try: r = requests.get('https://github.com/binary-husky/chatgpt_academic/archive/refs/heads/master.zip', proxies=proxies, stream=True)
|
||||||
except: r = requests.get('https://public.gpt-academic.top/publish/master.zip', proxies=proxies, stream=True)
|
except: r = requests.get('https://public.agent-matrix.com/publish/master.zip', proxies=proxies, stream=True)
|
||||||
zip_file_path = backup_dir+'/master.zip'
|
zip_file_path = backup_dir+'/master.zip' # ⭐ 保存备份文件的路径
|
||||||
with open(zip_file_path, 'wb+') as f:
|
with open(zip_file_path, 'wb+') as f:
|
||||||
f.write(r.content)
|
f.write(r.content)
|
||||||
dst_path = new_version_dir
|
dst_path = new_version_dir
|
||||||
@@ -64,6 +104,17 @@ def backup_and_download(current_version, remote_version):
|
|||||||
def patch_and_restart(path):
|
def patch_and_restart(path):
|
||||||
"""
|
"""
|
||||||
一键更新协议:覆盖和重启
|
一键更新协议:覆盖和重启
|
||||||
|
|
||||||
|
Args:
|
||||||
|
path (str): 新版本代码所在的路径
|
||||||
|
|
||||||
|
注意事项:
|
||||||
|
如果您的程序没有使用config_private.py私密配置文件,则会将config.py重命名为config_private.py以避免配置丢失。
|
||||||
|
|
||||||
|
更新流程:
|
||||||
|
- 复制最新版本代码到当前目录
|
||||||
|
- 更新pip包依赖
|
||||||
|
- 如果更新失败,则提示手动安装依赖库并重启
|
||||||
"""
|
"""
|
||||||
from distutils import dir_util
|
from distutils import dir_util
|
||||||
import shutil
|
import shutil
|
||||||
@@ -71,33 +122,44 @@ def patch_and_restart(path):
|
|||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
import glob
|
import glob
|
||||||
from colorful import print亮黄, print亮绿, print亮红
|
from shared_utils.colorful import log亮黄, log亮绿, log亮红
|
||||||
# if not using config_private, move origin config.py as config_private.py
|
|
||||||
if not os.path.exists('config_private.py'):
|
if not os.path.exists('config_private.py'):
|
||||||
print亮黄('由于您没有设置config_private.py私密配置,现将您的现有配置移动至config_private.py以防止配置丢失,',
|
log亮黄('由于您没有设置config_private.py私密配置,现将您的现有配置移动至config_private.py以防止配置丢失,',
|
||||||
'另外您可以随时在history子文件夹下找回旧版的程序。')
|
'另外您可以随时在history子文件夹下找回旧版的程序。')
|
||||||
shutil.copyfile('config.py', 'config_private.py')
|
shutil.copyfile('config.py', 'config_private.py')
|
||||||
|
|
||||||
path_new_version = glob.glob(path + '/*-master')[0]
|
path_new_version = glob.glob(path + '/*-master')[0]
|
||||||
dir_util.copy_tree(path_new_version, './')
|
dir_util.copy_tree(path_new_version, './') # ⭐ 将最新版本代码复制到当前目录
|
||||||
print亮绿('代码已经更新,即将更新pip包依赖……')
|
|
||||||
for i in reversed(range(5)): time.sleep(1); print(i)
|
log亮绿('代码已经更新,即将更新pip包依赖……')
|
||||||
|
for i in reversed(range(5)): time.sleep(1); log亮绿(i)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import subprocess
|
import subprocess
|
||||||
subprocess.check_call([sys.executable, '-m', 'pip', 'install', '-r', 'requirements.txt'])
|
subprocess.check_call([sys.executable, '-m', 'pip', 'install', '-r', 'requirements.txt'])
|
||||||
except:
|
except:
|
||||||
print亮红('pip包依赖安装出现问题,需要手动安装新增的依赖库 `python -m pip install -r requirements.txt`,然后在用常规的`python main.py`的方式启动。')
|
log亮红('pip包依赖安装出现问题,需要手动安装新增的依赖库 `python -m pip install -r requirements.txt`,然后在用常规的`python main.py`的方式启动。')
|
||||||
print亮绿('更新完成,您可以随时在history子文件夹下找回旧版的程序,5s之后重启')
|
|
||||||
print亮红('假如重启失败,您可能需要手动安装新增的依赖库 `python -m pip install -r requirements.txt`,然后在用常规的`python main.py`的方式启动。')
|
log亮绿('更新完成,您可以随时在history子文件夹下找回旧版的程序,5s之后重启')
|
||||||
print(' ------------------------------ -----------------------------------')
|
log亮红('假如重启失败,您可能需要手动安装新增的依赖库 `python -m pip install -r requirements.txt`,然后在用常规的`python main.py`的方式启动。')
|
||||||
for i in reversed(range(8)): time.sleep(1); print(i)
|
log亮绿(' ------------------------------ -----------------------------------')
|
||||||
os.execl(sys.executable, sys.executable, *sys.argv)
|
|
||||||
|
for i in reversed(range(8)): time.sleep(1); log亮绿(i)
|
||||||
|
os.execl(sys.executable, sys.executable, *sys.argv) # 重启程序
|
||||||
|
|
||||||
|
|
||||||
def get_current_version():
|
def get_current_version():
|
||||||
|
"""
|
||||||
|
获取当前的版本号。
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: 当前的版本号。如果无法获取版本号,则返回空字符串。
|
||||||
|
"""
|
||||||
import json
|
import json
|
||||||
try:
|
try:
|
||||||
with open('./version', 'r', encoding='utf8') as f:
|
with open('./version', 'r', encoding='utf8') as f:
|
||||||
current_version = json.loads(f.read())['version']
|
current_version = json.loads(f.read())['version'] # ⭐ 从读取的json数据中提取版本号
|
||||||
except:
|
except:
|
||||||
current_version = ""
|
current_version = ""
|
||||||
return current_version
|
return current_version
|
||||||
@@ -106,6 +168,12 @@ def get_current_version():
|
|||||||
def auto_update(raise_error=False):
|
def auto_update(raise_error=False):
|
||||||
"""
|
"""
|
||||||
一键更新协议:查询版本和用户意见
|
一键更新协议:查询版本和用户意见
|
||||||
|
|
||||||
|
Args:
|
||||||
|
raise_error (bool, optional): 是否在出错时抛出错误。默认为 False。
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
None
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
from toolbox import get_conf
|
from toolbox import get_conf
|
||||||
@@ -113,7 +181,7 @@ def auto_update(raise_error=False):
|
|||||||
import json
|
import json
|
||||||
proxies = get_conf('proxies')
|
proxies = get_conf('proxies')
|
||||||
try: response = requests.get("https://raw.githubusercontent.com/binary-husky/chatgpt_academic/master/version", proxies=proxies, timeout=5)
|
try: response = requests.get("https://raw.githubusercontent.com/binary-husky/chatgpt_academic/master/version", proxies=proxies, timeout=5)
|
||||||
except: response = requests.get("https://public.gpt-academic.top/publish/version", proxies=proxies, timeout=5)
|
except: response = requests.get("https://public.agent-matrix.com/publish/version", proxies=proxies, timeout=5)
|
||||||
remote_json_data = json.loads(response.text)
|
remote_json_data = json.loads(response.text)
|
||||||
remote_version = remote_json_data['version']
|
remote_version = remote_json_data['version']
|
||||||
if remote_json_data["show_feature"]:
|
if remote_json_data["show_feature"]:
|
||||||
@@ -124,22 +192,22 @@ def auto_update(raise_error=False):
|
|||||||
current_version = f.read()
|
current_version = f.read()
|
||||||
current_version = json.loads(current_version)['version']
|
current_version = json.loads(current_version)['version']
|
||||||
if (remote_version - current_version) >= 0.01-1e-5:
|
if (remote_version - current_version) >= 0.01-1e-5:
|
||||||
from colorful import print亮黄
|
from shared_utils.colorful import log亮黄
|
||||||
print亮黄(f'\n新版本可用。新版本:{remote_version},当前版本:{current_version}。{new_feature}')
|
log亮黄(f'\n新版本可用。新版本:{remote_version},当前版本:{current_version}。{new_feature}') # ⭐ 在控制台打印新版本信息
|
||||||
print('(1)Github更新地址:\nhttps://github.com/binary-husky/chatgpt_academic\n')
|
logger.info('(1)Github更新地址:\nhttps://github.com/binary-husky/chatgpt_academic\n')
|
||||||
user_instruction = input('(2)是否一键更新代码(Y+回车=确认,输入其他/无输入+回车=不更新)?')
|
user_instruction = input('(2)是否一键更新代码(Y+回车=确认,输入其他/无输入+回车=不更新)?')
|
||||||
if user_instruction in ['Y', 'y']:
|
if user_instruction in ['Y', 'y']:
|
||||||
path = backup_and_download(current_version, remote_version)
|
path = backup_and_download(current_version, remote_version) # ⭐ 备份并下载文件
|
||||||
try:
|
try:
|
||||||
patch_and_restart(path)
|
patch_and_restart(path) # ⭐ 执行覆盖并重启操作
|
||||||
except:
|
except:
|
||||||
msg = '更新失败。'
|
msg = '更新失败。'
|
||||||
if raise_error:
|
if raise_error:
|
||||||
from toolbox import trimmed_format_exc
|
from toolbox import trimmed_format_exc
|
||||||
msg += trimmed_format_exc()
|
msg += trimmed_format_exc()
|
||||||
print(msg)
|
logger.warning(msg)
|
||||||
else:
|
else:
|
||||||
print('自动更新程序:已禁用')
|
logger.info('自动更新程序:已禁用')
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
return
|
return
|
||||||
@@ -148,10 +216,13 @@ def auto_update(raise_error=False):
|
|||||||
if raise_error:
|
if raise_error:
|
||||||
from toolbox import trimmed_format_exc
|
from toolbox import trimmed_format_exc
|
||||||
msg += trimmed_format_exc()
|
msg += trimmed_format_exc()
|
||||||
print(msg)
|
logger.info(msg)
|
||||||
|
|
||||||
def warm_up_modules():
|
def warm_up_modules():
|
||||||
print('正在执行一些模块的预热 ...')
|
"""
|
||||||
|
预热模块,加载特定模块并执行预热操作。
|
||||||
|
"""
|
||||||
|
logger.info('正在执行一些模块的预热 ...')
|
||||||
from toolbox import ProxyNetworkActivate
|
from toolbox import ProxyNetworkActivate
|
||||||
from request_llms.bridge_all import model_info
|
from request_llms.bridge_all import model_info
|
||||||
with ProxyNetworkActivate("Warmup_Modules"):
|
with ProxyNetworkActivate("Warmup_Modules"):
|
||||||
@@ -161,7 +232,17 @@ def warm_up_modules():
|
|||||||
enc.encode("模块预热", disallowed_special=())
|
enc.encode("模块预热", disallowed_special=())
|
||||||
|
|
||||||
def warm_up_vectordb():
|
def warm_up_vectordb():
|
||||||
print('正在执行一些模块的预热 ...')
|
"""
|
||||||
|
执行一些模块的预热操作。
|
||||||
|
|
||||||
|
本函数主要用于执行一些模块的预热操作,确保在后续的流程中能够顺利运行。
|
||||||
|
|
||||||
|
⭐ 关键作用:预热模块
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
None
|
||||||
|
"""
|
||||||
|
logger.info('正在执行一些模块的预热 ...')
|
||||||
from toolbox import ProxyNetworkActivate
|
from toolbox import ProxyNetworkActivate
|
||||||
with ProxyNetworkActivate("Warmup_Modules"):
|
with ProxyNetworkActivate("Warmup_Modules"):
|
||||||
import nltk
|
import nltk
|
||||||
|
|||||||
153
config.py
153
config.py
@@ -30,11 +30,44 @@ if USE_PROXY:
|
|||||||
else:
|
else:
|
||||||
proxies = None
|
proxies = None
|
||||||
|
|
||||||
# ------------------------------------ 以下配置可以优化体验, 但大部分场合下并不需要修改 ------------------------------------
|
# [step 3]>> 模型选择是 (注意: LLM_MODEL是默认选中的模型, 它*必须*被包含在AVAIL_LLM_MODELS列表中 )
|
||||||
|
LLM_MODEL = "gpt-3.5-turbo-16k" # 可选 ↓↓↓
|
||||||
|
AVAIL_LLM_MODELS = ["gpt-4-1106-preview", "gpt-4-turbo-preview", "gpt-4-vision-preview",
|
||||||
|
"gpt-4o", "gpt-4o-mini", "gpt-4-turbo", "gpt-4-turbo-2024-04-09",
|
||||||
|
"gpt-3.5-turbo-1106", "gpt-3.5-turbo-16k", "gpt-3.5-turbo", "azure-gpt-3.5",
|
||||||
|
"gpt-4", "gpt-4-32k", "azure-gpt-4", "glm-4", "glm-4v", "glm-3-turbo",
|
||||||
|
"gemini-1.5-pro", "chatglm3"
|
||||||
|
]
|
||||||
|
|
||||||
|
EMBEDDING_MODEL = "text-embedding-3-small"
|
||||||
|
|
||||||
|
# --- --- --- ---
|
||||||
|
# P.S. 其他可用的模型还包括
|
||||||
|
# AVAIL_LLM_MODELS = [
|
||||||
|
# "glm-4-0520", "glm-4-air", "glm-4-airx", "glm-4-flash",
|
||||||
|
# "qianfan", "deepseekcoder",
|
||||||
|
# "spark", "sparkv2", "sparkv3", "sparkv3.5", "sparkv4",
|
||||||
|
# "qwen-turbo", "qwen-plus", "qwen-max", "qwen-local",
|
||||||
|
# "moonshot-v1-128k", "moonshot-v1-32k", "moonshot-v1-8k",
|
||||||
|
# "gpt-3.5-turbo-0613", "gpt-3.5-turbo-16k-0613", "gpt-3.5-turbo-0125", "gpt-4o-2024-05-13"
|
||||||
|
# "claude-3-haiku-20240307","claude-3-sonnet-20240229","claude-3-opus-20240229", "claude-2.1", "claude-instant-1.2",
|
||||||
|
# "moss", "llama2", "chatglm_onnx", "internlm", "jittorllms_pangualpha", "jittorllms_llama",
|
||||||
|
# "deepseek-chat" ,"deepseek-coder",
|
||||||
|
# "gemini-1.5-flash",
|
||||||
|
# "yi-34b-chat-0205","yi-34b-chat-200k","yi-large","yi-medium","yi-spark","yi-large-turbo","yi-large-preview",
|
||||||
|
# ]
|
||||||
|
# --- --- --- ---
|
||||||
|
# 此外,您还可以在接入one-api/vllm/ollama/Openroute时,
|
||||||
|
# 使用"one-api-*","vllm-*","ollama-*","openrouter-*"前缀直接使用非标准方式接入的模型,例如
|
||||||
|
# AVAIL_LLM_MODELS = ["one-api-claude-3-sonnet-20240229(max_token=100000)", "ollama-phi3(max_token=4096)","openrouter-openai/gpt-4o-mini","openrouter-openai/chatgpt-4o-latest"]
|
||||||
|
# --- --- --- ---
|
||||||
|
|
||||||
|
|
||||||
|
# --------------- 以下配置可以优化体验 ---------------
|
||||||
|
|
||||||
# 重新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", "http://localhost:11434/api/chat": "在这里填写您ollama的URL"}
|
||||||
API_URL_REDIRECT = {}
|
API_URL_REDIRECT = {}
|
||||||
|
|
||||||
|
|
||||||
@@ -77,6 +110,10 @@ TIMEOUT_SECONDS = 30
|
|||||||
WEB_PORT = -1
|
WEB_PORT = -1
|
||||||
|
|
||||||
|
|
||||||
|
# 是否自动打开浏览器页面
|
||||||
|
AUTO_OPEN_BROWSER = True
|
||||||
|
|
||||||
|
|
||||||
# 如果OpenAI不响应(网络卡顿、代理失败、KEY失效),重试的次数限制
|
# 如果OpenAI不响应(网络卡顿、代理失败、KEY失效),重试的次数限制
|
||||||
MAX_RETRY = 2
|
MAX_RETRY = 2
|
||||||
|
|
||||||
@@ -85,20 +122,6 @@ MAX_RETRY = 2
|
|||||||
DEFAULT_FN_GROUPS = ['对话', '编程', '学术', '智能体']
|
DEFAULT_FN_GROUPS = ['对话', '编程', '学术', '智能体']
|
||||||
|
|
||||||
|
|
||||||
# 模型选择是 (注意: LLM_MODEL是默认选中的模型, 它*必须*被包含在AVAIL_LLM_MODELS列表中 )
|
|
||||||
LLM_MODEL = "gpt-3.5-turbo" # 可选 ↓↓↓
|
|
||||||
AVAIL_LLM_MODELS = ["gpt-3.5-turbo-1106","gpt-4-1106-preview","gpt-4-vision-preview",
|
|
||||||
"gpt-3.5-turbo-16k", "gpt-3.5-turbo", "azure-gpt-3.5",
|
|
||||||
"gpt-4", "gpt-4-32k", "azure-gpt-4", "api2d-gpt-4",
|
|
||||||
"gemini-pro", "chatglm3", "moss", "claude-2"]
|
|
||||||
# P.S. 其他可用的模型还包括 [
|
|
||||||
# "qwen-turbo", "qwen-plus", "qwen-max"
|
|
||||||
# "zhipuai", "qianfan", "deepseekcoder", "llama2", "qwen-local", "gpt-3.5-turbo-0613",
|
|
||||||
# "gpt-3.5-turbo-16k-0613", "gpt-3.5-random", "api2d-gpt-3.5-turbo", 'api2d-gpt-3.5-turbo-16k',
|
|
||||||
# "spark", "sparkv2", "sparkv3", "chatglm_onnx", "claude-1-100k", "claude-2", "internlm", "jittorllms_pangualpha", "jittorllms_llama"
|
|
||||||
# ]
|
|
||||||
|
|
||||||
|
|
||||||
# 定义界面上“询问多个GPT模型”插件应该使用哪些模型,请从AVAIL_LLM_MODELS中选择,并在不同模型之间用`&`间隔,例如"gpt-3.5-turbo&chatglm3&azure-gpt-4"
|
# 定义界面上“询问多个GPT模型”插件应该使用哪些模型,请从AVAIL_LLM_MODELS中选择,并在不同模型之间用`&`间隔,例如"gpt-3.5-turbo&chatglm3&azure-gpt-4"
|
||||||
MULTI_QUERY_LLM_MODELS = "gpt-3.5-turbo&chatglm3"
|
MULTI_QUERY_LLM_MODELS = "gpt-3.5-turbo&chatglm3"
|
||||||
|
|
||||||
@@ -116,7 +139,7 @@ DASHSCOPE_API_KEY = "" # 阿里灵积云API_KEY
|
|||||||
# 百度千帆(LLM_MODEL="qianfan")
|
# 百度千帆(LLM_MODEL="qianfan")
|
||||||
BAIDU_CLOUD_API_KEY = ''
|
BAIDU_CLOUD_API_KEY = ''
|
||||||
BAIDU_CLOUD_SECRET_KEY = ''
|
BAIDU_CLOUD_SECRET_KEY = ''
|
||||||
BAIDU_CLOUD_QIANFAN_MODEL = 'ERNIE-Bot' # 可选 "ERNIE-Bot-4"(文心大模型4.0), "ERNIE-Bot"(文心一言), "ERNIE-Bot-turbo", "BLOOMZ-7B", "Llama-2-70B-Chat", "Llama-2-13B-Chat", "Llama-2-7B-Chat"
|
BAIDU_CLOUD_QIANFAN_MODEL = 'ERNIE-Bot' # 可选 "ERNIE-Bot-4"(文心大模型4.0), "ERNIE-Bot"(文心一言), "ERNIE-Bot-turbo", "BLOOMZ-7B", "Llama-2-70B-Chat", "Llama-2-13B-Chat", "Llama-2-7B-Chat", "ERNIE-Speed-128K", "ERNIE-Speed-8K", "ERNIE-Lite-8K"
|
||||||
|
|
||||||
|
|
||||||
# 如果使用ChatGLM2微调模型,请把 LLM_MODEL="chatglmft",并在此处指定模型路径
|
# 如果使用ChatGLM2微调模型,请把 LLM_MODEL="chatglmft",并在此处指定模型路径
|
||||||
@@ -127,6 +150,7 @@ CHATGLM_PTUNING_CHECKPOINT = "" # 例如"/home/hmp/ChatGLM2-6B/ptuning/output/6b
|
|||||||
LOCAL_MODEL_DEVICE = "cpu" # 可选 "cuda"
|
LOCAL_MODEL_DEVICE = "cpu" # 可选 "cuda"
|
||||||
LOCAL_MODEL_QUANT = "FP16" # 默认 "FP16" "INT4" 启用量化INT4版本 "INT8" 启用量化INT8版本
|
LOCAL_MODEL_QUANT = "FP16" # 默认 "FP16" "INT4" 启用量化INT4版本 "INT8" 启用量化INT8版本
|
||||||
|
|
||||||
|
|
||||||
# 设置gradio的并行线程数(不需要修改)
|
# 设置gradio的并行线程数(不需要修改)
|
||||||
CONCURRENT_COUNT = 100
|
CONCURRENT_COUNT = 100
|
||||||
|
|
||||||
@@ -144,7 +168,8 @@ ADD_WAIFU = False
|
|||||||
AUTHENTICATION = []
|
AUTHENTICATION = []
|
||||||
|
|
||||||
|
|
||||||
# 如果需要在二级路径下运行(常规情况下,不要修改!!)(需要配合修改main.py才能生效!)
|
# 如果需要在二级路径下运行(常规情况下,不要修改!!)
|
||||||
|
# (举例 CUSTOM_PATH = "/gpt_academic",可以让软件运行在 http://ip:port/gpt_academic/ 下。)
|
||||||
CUSTOM_PATH = "/"
|
CUSTOM_PATH = "/"
|
||||||
|
|
||||||
|
|
||||||
@@ -172,14 +197,8 @@ AZURE_ENGINE = "填入你亲手写的部署名" # 读 docs\use_azure.
|
|||||||
AZURE_CFG_ARRAY = {}
|
AZURE_CFG_ARRAY = {}
|
||||||
|
|
||||||
|
|
||||||
# 使用Newbing (不推荐使用,未来将删除)
|
# 阿里云实时语音识别 配置难度较高
|
||||||
NEWBING_STYLE = "creative" # ["creative", "balanced", "precise"]
|
# 参考 https://github.com/binary-husky/gpt_academic/blob/master/docs/use_audio.md
|
||||||
NEWBING_COOKIES = """
|
|
||||||
put your new bing cookies here
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
# 阿里云实时语音识别 配置难度较高 仅建议高手用户使用 参考 https://github.com/binary-husky/gpt_academic/blob/master/docs/use_audio.md
|
|
||||||
ENABLE_AUDIO = False
|
ENABLE_AUDIO = False
|
||||||
ALIYUN_TOKEN="" # 例如 f37f30e0f9934c34a992f6f64f7eba4f
|
ALIYUN_TOKEN="" # 例如 f37f30e0f9934c34a992f6f64f7eba4f
|
||||||
ALIYUN_APPKEY="" # 例如 RoPlZrM88DnAFkZK
|
ALIYUN_APPKEY="" # 例如 RoPlZrM88DnAFkZK
|
||||||
@@ -187,6 +206,12 @@ ALIYUN_ACCESSKEY="" # (无需填写)
|
|||||||
ALIYUN_SECRET="" # (无需填写)
|
ALIYUN_SECRET="" # (无需填写)
|
||||||
|
|
||||||
|
|
||||||
|
# GPT-SOVITS 文本转语音服务的运行地址(将语言模型的生成文本朗读出来)
|
||||||
|
TTS_TYPE = "EDGE_TTS" # EDGE_TTS / LOCAL_SOVITS_API / DISABLE
|
||||||
|
GPT_SOVITS_URL = ""
|
||||||
|
EDGE_TTS_VOICE = "zh-CN-XiaoxiaoNeural"
|
||||||
|
|
||||||
|
|
||||||
# 接入讯飞星火大模型 https://console.xfyun.cn/services/iat
|
# 接入讯飞星火大模型 https://console.xfyun.cn/services/iat
|
||||||
XFYUN_APPID = "00000000"
|
XFYUN_APPID = "00000000"
|
||||||
XFYUN_API_SECRET = "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
|
XFYUN_API_SECRET = "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
|
||||||
@@ -195,13 +220,38 @@ XFYUN_API_KEY = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
|||||||
|
|
||||||
# 接入智谱大模型
|
# 接入智谱大模型
|
||||||
ZHIPUAI_API_KEY = ""
|
ZHIPUAI_API_KEY = ""
|
||||||
ZHIPUAI_MODEL = "chatglm_turbo"
|
ZHIPUAI_MODEL = "" # 此选项已废弃,不再需要填写
|
||||||
|
|
||||||
|
|
||||||
# Claude API KEY
|
# Claude API KEY
|
||||||
ANTHROPIC_API_KEY = ""
|
ANTHROPIC_API_KEY = ""
|
||||||
|
|
||||||
|
|
||||||
|
# 月之暗面 API KEY
|
||||||
|
MOONSHOT_API_KEY = ""
|
||||||
|
|
||||||
|
|
||||||
|
# 零一万物(Yi Model) API KEY
|
||||||
|
YIMODEL_API_KEY = ""
|
||||||
|
|
||||||
|
|
||||||
|
# 深度求索(DeepSeek) API KEY,默认请求地址为"https://api.deepseek.com/v1/chat/completions"
|
||||||
|
DEEPSEEK_API_KEY = ""
|
||||||
|
|
||||||
|
|
||||||
|
# 紫东太初大模型 https://ai-maas.wair.ac.cn
|
||||||
|
TAICHU_API_KEY = ""
|
||||||
|
|
||||||
|
|
||||||
|
# Mathpix 拥有执行PDF的OCR功能,但是需要注册账号
|
||||||
|
MATHPIX_APPID = ""
|
||||||
|
MATHPIX_APPKEY = ""
|
||||||
|
|
||||||
|
|
||||||
|
# DOC2X的PDF解析服务,注册账号并获取API KEY: https://doc2x.noedgeai.com/login
|
||||||
|
DOC2X_API_KEY = ""
|
||||||
|
|
||||||
|
|
||||||
# 自定义API KEY格式
|
# 自定义API KEY格式
|
||||||
CUSTOM_API_KEY_PATTERN = ""
|
CUSTOM_API_KEY_PATTERN = ""
|
||||||
|
|
||||||
@@ -223,6 +273,10 @@ GROBID_URLS = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
# Searxng互联网检索服务
|
||||||
|
SEARXNG_URL = "https://cloud-1.agent-matrix.com/"
|
||||||
|
|
||||||
|
|
||||||
# 是否允许通过自然语言描述修改本页的配置,该功能具有一定的危险性,默认关闭
|
# 是否允许通过自然语言描述修改本页的配置,该功能具有一定的危险性,默认关闭
|
||||||
ALLOW_RESET_CONFIG = False
|
ALLOW_RESET_CONFIG = False
|
||||||
|
|
||||||
@@ -231,21 +285,21 @@ ALLOW_RESET_CONFIG = False
|
|||||||
AUTOGEN_USE_DOCKER = False
|
AUTOGEN_USE_DOCKER = False
|
||||||
|
|
||||||
|
|
||||||
# 临时的上传文件夹位置,请勿修改
|
# 临时的上传文件夹位置,请尽量不要修改
|
||||||
PATH_PRIVATE_UPLOAD = "private_upload"
|
PATH_PRIVATE_UPLOAD = "private_upload"
|
||||||
|
|
||||||
|
|
||||||
# 日志文件夹的位置,请勿修改
|
# 日志文件夹的位置,请尽量不要修改
|
||||||
PATH_LOGGING = "gpt_log"
|
PATH_LOGGING = "gpt_log"
|
||||||
|
|
||||||
|
|
||||||
# 除了连接OpenAI之外,还有哪些场合允许使用代理,请勿修改
|
# 存储翻译好的arxiv论文的路径,请尽量不要修改
|
||||||
|
ARXIV_CACHE_DIR = "gpt_log/arxiv_cache"
|
||||||
|
|
||||||
|
|
||||||
|
# 除了连接OpenAI之外,还有哪些场合允许使用代理,请尽量不要修改
|
||||||
WHEN_TO_USE_PROXY = ["Download_LLM", "Download_Gradio_Theme", "Connect_Grobid",
|
WHEN_TO_USE_PROXY = ["Download_LLM", "Download_Gradio_Theme", "Connect_Grobid",
|
||||||
"Warmup_Modules", "Nougat_Download", "AutoGen"]
|
"Warmup_Modules", "Nougat_Download", "AutoGen", "Connect_OpenAI_Embedding"]
|
||||||
|
|
||||||
|
|
||||||
# *实验性功能*: 自动检测并屏蔽失效的KEY,请勿使用
|
|
||||||
BLOCK_INVALID_APIKEY = False
|
|
||||||
|
|
||||||
|
|
||||||
# 启用插件热加载
|
# 启用插件热加载
|
||||||
@@ -255,7 +309,11 @@ PLUGIN_HOT_RELOAD = False
|
|||||||
# 自定义按钮的最大数量限制
|
# 自定义按钮的最大数量限制
|
||||||
NUM_CUSTOM_BASIC_BTN = 4
|
NUM_CUSTOM_BASIC_BTN = 4
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
--------------- 配置关联关系说明 ---------------
|
||||||
|
|
||||||
在线大模型配置关联关系示意图
|
在线大模型配置关联关系示意图
|
||||||
│
|
│
|
||||||
├── "gpt-3.5-turbo" 等openai模型
|
├── "gpt-3.5-turbo" 等openai模型
|
||||||
@@ -279,7 +337,7 @@ NUM_CUSTOM_BASIC_BTN = 4
|
|||||||
│ ├── XFYUN_API_SECRET
|
│ ├── XFYUN_API_SECRET
|
||||||
│ └── XFYUN_API_KEY
|
│ └── XFYUN_API_KEY
|
||||||
│
|
│
|
||||||
├── "claude-1-100k" 等claude模型
|
├── "claude-3-opus-20240229" 等claude模型
|
||||||
│ └── ANTHROPIC_API_KEY
|
│ └── ANTHROPIC_API_KEY
|
||||||
│
|
│
|
||||||
├── "stack-claude"
|
├── "stack-claude"
|
||||||
@@ -291,9 +349,11 @@ NUM_CUSTOM_BASIC_BTN = 4
|
|||||||
│ ├── BAIDU_CLOUD_API_KEY
|
│ ├── BAIDU_CLOUD_API_KEY
|
||||||
│ └── BAIDU_CLOUD_SECRET_KEY
|
│ └── BAIDU_CLOUD_SECRET_KEY
|
||||||
│
|
│
|
||||||
├── "zhipuai" 智谱AI大模型chatglm_turbo
|
├── "glm-4", "glm-3-turbo", "zhipuai" 智谱AI大模型
|
||||||
│ ├── ZHIPUAI_API_KEY
|
│ └── ZHIPUAI_API_KEY
|
||||||
│ └── ZHIPUAI_MODEL
|
│
|
||||||
|
├── "yi-34b-chat-0205", "yi-34b-chat-200k" 等零一万物(Yi Model)大模型
|
||||||
|
│ └── YIMODEL_API_KEY
|
||||||
│
|
│
|
||||||
├── "qwen-turbo" 等通义千问大模型
|
├── "qwen-turbo" 等通义千问大模型
|
||||||
│ └── DASHSCOPE_API_KEY
|
│ └── DASHSCOPE_API_KEY
|
||||||
@@ -301,9 +361,10 @@ NUM_CUSTOM_BASIC_BTN = 4
|
|||||||
├── "Gemini"
|
├── "Gemini"
|
||||||
│ └── GEMINI_API_KEY
|
│ └── GEMINI_API_KEY
|
||||||
│
|
│
|
||||||
└── "newbing" Newbing接口不再稳定,不推荐使用
|
└── "one-api-...(max_token=...)" 用一种更方便的方式接入one-api多模型管理界面
|
||||||
├── NEWBING_STYLE
|
├── AVAIL_LLM_MODELS
|
||||||
└── NEWBING_COOKIES
|
├── API_KEY
|
||||||
|
└── API_URL_REDIRECT
|
||||||
|
|
||||||
|
|
||||||
本地大模型示意图
|
本地大模型示意图
|
||||||
@@ -337,6 +398,9 @@ NUM_CUSTOM_BASIC_BTN = 4
|
|||||||
|
|
||||||
插件在线服务配置依赖关系示意图
|
插件在线服务配置依赖关系示意图
|
||||||
│
|
│
|
||||||
|
├── 互联网检索
|
||||||
|
│ └── SEARXNG_URL
|
||||||
|
│
|
||||||
├── 语音功能
|
├── 语音功能
|
||||||
│ ├── ENABLE_AUDIO
|
│ ├── ENABLE_AUDIO
|
||||||
│ ├── ALIYUN_TOKEN
|
│ ├── ALIYUN_TOKEN
|
||||||
@@ -345,6 +409,9 @@ NUM_CUSTOM_BASIC_BTN = 4
|
|||||||
│ └── ALIYUN_SECRET
|
│ └── ALIYUN_SECRET
|
||||||
│
|
│
|
||||||
└── PDF文档精准解析
|
└── PDF文档精准解析
|
||||||
└── GROBID_URLS
|
├── GROBID_URLS
|
||||||
|
├── MATHPIX_APPID
|
||||||
|
└── MATHPIX_APPKEY
|
||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -3,30 +3,71 @@
|
|||||||
# 'stop' 颜色对应 theme.py 中的 color_er
|
# 'stop' 颜色对应 theme.py 中的 color_er
|
||||||
import importlib
|
import importlib
|
||||||
from toolbox import clear_line_break
|
from toolbox import clear_line_break
|
||||||
|
from toolbox import apply_gpt_academic_string_mask_langbased
|
||||||
|
from toolbox import build_gpt_academic_masked_string_langbased
|
||||||
|
from textwrap import dedent
|
||||||
|
|
||||||
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, " +
|
# [1*] 前缀字符串,会被加在你的输入之前。例如,用来描述你的要求,例如翻译、解释代码、润色等等。
|
||||||
r"improve the spelling, grammar, clarity, concision and overall readability. When necessary, rewrite the whole sentence. " +
|
# 这里填一个提示词字符串就行了,这里为了区分中英文情景搞复杂了一点
|
||||||
r"Firstly, you should provide the polished paragraph. "
|
"Prefix": build_gpt_academic_masked_string_langbased(
|
||||||
r"Secondly, you should list all your modification and explain the reasons to do so in markdown table." + "\n\n",
|
text_show_english=
|
||||||
# 后缀,会被加在你的输入之后。例如,配合前缀可以把你的输入内容用引号圈起来
|
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"Firstly, you should provide the polished paragraph (in English). "
|
||||||
|
r"Secondly, you should list all your modification and explain the reasons to do so in markdown table.",
|
||||||
|
text_show_chinese=
|
||||||
|
r"作为一名中文学术论文写作改进助理,你的任务是改进所提供文本的拼写、语法、清晰、简洁和整体可读性,"
|
||||||
|
r"同时分解长句,减少重复,并提供改进建议。请先提供文本的更正版本,然后在markdown表格中列出修改的内容,并给出修改的理由:"
|
||||||
|
) + "\n\n",
|
||||||
|
# [2*] 后缀字符串,会被加在你的输入之后。例如,配合前缀可以把你的输入内容用引号圈起来
|
||||||
"Suffix": r"",
|
"Suffix": r"",
|
||||||
# 按钮颜色 (默认 secondary)
|
# [3] 按钮颜色 (可选参数,默认 secondary)
|
||||||
"Color": r"secondary",
|
"Color": r"secondary",
|
||||||
# 按钮是否可见 (默认 True,即可见)
|
# [4] 按钮是否可见 (可选参数,默认 True,即可见)
|
||||||
"Visible": True,
|
"Visible": True,
|
||||||
# 是否在触发时清除历史 (默认 False,即不处理之前的对话历史)
|
# [5] 是否在触发时清除历史 (可选参数,默认 False,即不处理之前的对话历史)
|
||||||
"AutoClearHistory": False
|
"AutoClearHistory": False,
|
||||||
|
# [6] 文本预处理 (可选参数,默认 None,举例:写个函数移除所有的换行符)
|
||||||
|
"PreProcess": None,
|
||||||
|
# [7] 模型选择 (可选参数。如不设置,则使用当前全局模型;如设置,则用指定模型覆盖全局模型。)
|
||||||
|
# "ModelOverride": "gpt-3.5-turbo", # 主要用途:强制点击此基础功能按钮时,使用指定的模型。
|
||||||
},
|
},
|
||||||
"中文学术润色": {
|
|
||||||
"Prefix": r"作为一名中文学术论文写作改进助理,你的任务是改进所提供文本的拼写、语法、清晰、简洁和整体可读性," +
|
|
||||||
r"同时分解长句,减少重复,并提供改进建议。请只提供文本的更正版本,避免包括解释。请编辑以下文本" + "\n\n",
|
"总结绘制脑图": {
|
||||||
"Suffix": r"",
|
# 前缀,会被加在你的输入之前。例如,用来描述你的要求,例如翻译、解释代码、润色等等
|
||||||
|
"Prefix": '''"""\n\n''',
|
||||||
|
# 后缀,会被加在你的输入之后。例如,配合前缀可以把你的输入内容用引号圈起来
|
||||||
|
"Suffix":
|
||||||
|
# dedent() 函数用于去除多行字符串的缩进
|
||||||
|
dedent("\n\n"+r'''
|
||||||
|
"""
|
||||||
|
|
||||||
|
使用mermaid flowchart对以上文本进行总结,概括上述段落的内容以及内在逻辑关系,例如:
|
||||||
|
|
||||||
|
以下是对以上文本的总结,以mermaid flowchart的形式展示:
|
||||||
|
```mermaid
|
||||||
|
flowchart LR
|
||||||
|
A["节点名1"] --> B("节点名2")
|
||||||
|
B --> C{"节点名3"}
|
||||||
|
C --> D["节点名4"]
|
||||||
|
C --> |"箭头名1"| E["节点名5"]
|
||||||
|
C --> |"箭头名2"| F["节点名6"]
|
||||||
|
```
|
||||||
|
|
||||||
|
注意:
|
||||||
|
(1)使用中文
|
||||||
|
(2)节点名字使用引号包裹,如["Laptop"]
|
||||||
|
(3)`|` 和 `"`之间不要存在空格
|
||||||
|
(4)根据情况选择flowchart LR(从左到右)或者flowchart TD(从上到下)
|
||||||
|
'''),
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
"查找语法错误": {
|
"查找语法错误": {
|
||||||
"Prefix": r"Help me ensure that the grammar and the spelling is correct. "
|
"Prefix": r"Help me ensure that the grammar and the spelling is correct. "
|
||||||
r"Do not try to polish the text, if no mistake is found, tell me that this paragraph is good. "
|
r"Do not try to polish the text, if no mistake is found, tell me that this paragraph is good. "
|
||||||
@@ -46,41 +87,60 @@ def get_core_functions():
|
|||||||
"Suffix": r"",
|
"Suffix": r"",
|
||||||
"PreProcess": clear_line_break, # 预处理:清除换行符
|
"PreProcess": clear_line_break, # 预处理:清除换行符
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
"中译英": {
|
"中译英": {
|
||||||
"Prefix": r"Please translate following sentence to English:" + "\n\n",
|
"Prefix": r"Please translate following sentence to English:" + "\n\n",
|
||||||
"Suffix": r"",
|
"Suffix": r"",
|
||||||
},
|
},
|
||||||
"学术中英互译": {
|
|
||||||
"Prefix": r"I want you to act as a scientific English-Chinese translator, " +
|
|
||||||
r"I will provide you with some paragraphs in one language " +
|
"学术英中互译": {
|
||||||
r"and your task is to accurately and academically translate the paragraphs only into the other language. " +
|
"Prefix": build_gpt_academic_masked_string_langbased(
|
||||||
r"Do not repeat the original provided paragraphs after translation. " +
|
text_show_chinese=
|
||||||
r"You should use artificial intelligence tools, " +
|
r"I want you to act as a scientific English-Chinese translator, "
|
||||||
r"such as natural language processing, and rhetorical knowledge " +
|
r"I will provide you with some paragraphs in one language "
|
||||||
r"and experience about effective writing techniques to reply. " +
|
r"and your task is to accurately and academically translate the paragraphs only into the other language. "
|
||||||
r"I'll give you my paragraphs as follows, tell me what language it is written in, and then translate:" + "\n\n",
|
r"Do not repeat the original provided paragraphs after translation. "
|
||||||
"Suffix": "",
|
r"You should use artificial intelligence tools, "
|
||||||
"Color": "secondary",
|
r"such as natural language processing, and rhetorical knowledge "
|
||||||
|
r"and experience about effective writing techniques to reply. "
|
||||||
|
r"I'll give you my paragraphs as follows, tell me what language it is written in, and then translate:",
|
||||||
|
text_show_english=
|
||||||
|
r"你是经验丰富的翻译,请把以下学术文章段落翻译成中文,"
|
||||||
|
r"并同时充分考虑中文的语法、清晰、简洁和整体可读性,"
|
||||||
|
r"必要时,你可以修改整个句子的顺序以确保翻译后的段落符合中文的语言习惯。"
|
||||||
|
r"你需要翻译的文本如下:"
|
||||||
|
) + "\n\n",
|
||||||
|
"Suffix": r"",
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
"英译中": {
|
"英译中": {
|
||||||
"Prefix": r"翻译成地道的中文:" + "\n\n",
|
"Prefix": r"翻译成地道的中文:" + "\n\n",
|
||||||
"Suffix": r"",
|
"Suffix": r"",
|
||||||
"Visible": False,
|
"Visible": False,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
"找图片": {
|
"找图片": {
|
||||||
"Prefix": r"我需要你找一张网络图片。使用Unsplash API(https://source.unsplash.com/960x640/?<英语关键词>)获取图片URL," +
|
"Prefix": r"我需要你找一张网络图片。使用Unsplash API(https://source.unsplash.com/960x640/?<英语关键词>)获取图片URL,"
|
||||||
r"然后请使用Markdown格式封装,并且不要有反斜线,不要用代码块。现在,请按以下描述给我发送图片:" + "\n\n",
|
r"然后请使用Markdown格式封装,并且不要有反斜线,不要用代码块。现在,请按以下描述给我发送图片:" + "\n\n",
|
||||||
"Suffix": r"",
|
"Suffix": r"",
|
||||||
"Visible": False,
|
"Visible": False,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
"解释代码": {
|
"解释代码": {
|
||||||
"Prefix": r"请解释以下代码:" + "\n```\n",
|
"Prefix": r"请解释以下代码:" + "\n```\n",
|
||||||
"Suffix": "\n```\n",
|
"Suffix": "\n```\n",
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
"参考文献转Bib": {
|
"参考文献转Bib": {
|
||||||
"Prefix": r"Here are some bibliography items, please transform them into bibtex style." +
|
"Prefix": r"Here are some bibliography items, please transform them into bibtex style."
|
||||||
r"Note that, reference styles maybe more than one kind, you should transform each item correctly." +
|
r"Note that, reference styles maybe more than one kind, you should transform each item correctly."
|
||||||
r"Items need to be transformed:",
|
r"Items need to be transformed:" + "\n\n",
|
||||||
"Visible": False,
|
"Visible": False,
|
||||||
"Suffix": r"",
|
"Suffix": r"",
|
||||||
}
|
}
|
||||||
@@ -98,8 +158,18 @@ def handle_core_functionality(additional_fn, inputs, history, chatbot):
|
|||||||
return inputs, history
|
return inputs, history
|
||||||
else:
|
else:
|
||||||
# 预制功能
|
# 预制功能
|
||||||
if "PreProcess" in core_functional[additional_fn]: inputs = core_functional[additional_fn]["PreProcess"](inputs) # 获取预处理函数(如果有的话)
|
if "PreProcess" in core_functional[additional_fn]:
|
||||||
inputs = core_functional[additional_fn]["Prefix"] + inputs + core_functional[additional_fn]["Suffix"]
|
if core_functional[additional_fn]["PreProcess"] is not None:
|
||||||
|
inputs = core_functional[additional_fn]["PreProcess"](inputs) # 获取预处理函数(如果有的话)
|
||||||
|
# 为字符串加上上面定义的前缀和后缀。
|
||||||
|
inputs = apply_gpt_academic_string_mask_langbased(
|
||||||
|
string = core_functional[additional_fn]["Prefix"] + inputs + core_functional[additional_fn]["Suffix"],
|
||||||
|
lang_reference = inputs,
|
||||||
|
)
|
||||||
if core_functional[additional_fn].get("AutoClearHistory", False):
|
if core_functional[additional_fn].get("AutoClearHistory", False):
|
||||||
history = []
|
history = []
|
||||||
return inputs, history
|
return inputs, history
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
t = get_core_functions()["总结绘制脑图"]
|
||||||
|
print(t["Prefix"] + t["Suffix"])
|
||||||
@@ -1,146 +1,185 @@
|
|||||||
from toolbox import HotReload # HotReload 的意思是热更新,修改函数插件后,不需要重启程序,代码直接生效
|
from toolbox import HotReload # HotReload 的意思是热更新,修改函数插件后,不需要重启程序,代码直接生效
|
||||||
from toolbox import trimmed_format_exc
|
from toolbox import trimmed_format_exc
|
||||||
|
from loguru import logger
|
||||||
|
|
||||||
|
|
||||||
def get_crazy_functions():
|
def get_crazy_functions():
|
||||||
from crazy_functions.读文章写摘要 import 读文章写摘要
|
from crazy_functions.读文章写摘要 import 读文章写摘要
|
||||||
from crazy_functions.生成函数注释 import 批量生成函数注释
|
from crazy_functions.生成函数注释 import 批量生成函数注释
|
||||||
from crazy_functions.解析项目源代码 import 解析项目本身
|
from crazy_functions.SourceCode_Analyse import 解析项目本身
|
||||||
from crazy_functions.解析项目源代码 import 解析一个Python项目
|
from crazy_functions.SourceCode_Analyse import 解析一个Python项目
|
||||||
from crazy_functions.解析项目源代码 import 解析一个Matlab项目
|
from crazy_functions.SourceCode_Analyse import 解析一个Matlab项目
|
||||||
from crazy_functions.解析项目源代码 import 解析一个C项目的头文件
|
from crazy_functions.SourceCode_Analyse import 解析一个C项目的头文件
|
||||||
from crazy_functions.解析项目源代码 import 解析一个C项目
|
from crazy_functions.SourceCode_Analyse import 解析一个C项目
|
||||||
from crazy_functions.解析项目源代码 import 解析一个Golang项目
|
from crazy_functions.SourceCode_Analyse import 解析一个Golang项目
|
||||||
from crazy_functions.解析项目源代码 import 解析一个Rust项目
|
from crazy_functions.SourceCode_Analyse import 解析一个Rust项目
|
||||||
from crazy_functions.解析项目源代码 import 解析一个Java项目
|
from crazy_functions.SourceCode_Analyse import 解析一个Java项目
|
||||||
from crazy_functions.解析项目源代码 import 解析一个前端项目
|
from crazy_functions.SourceCode_Analyse import 解析一个前端项目
|
||||||
from crazy_functions.高级功能函数模板 import 高阶功能模板函数
|
from crazy_functions.高级功能函数模板 import 高阶功能模板函数
|
||||||
|
from crazy_functions.高级功能函数模板 import Demo_Wrap
|
||||||
from crazy_functions.Latex全文润色 import Latex英文润色
|
from crazy_functions.Latex全文润色 import Latex英文润色
|
||||||
from crazy_functions.询问多个大语言模型 import 同时问询
|
from crazy_functions.询问多个大语言模型 import 同时问询
|
||||||
from crazy_functions.解析项目源代码 import 解析一个Lua项目
|
from crazy_functions.SourceCode_Analyse import 解析一个Lua项目
|
||||||
from crazy_functions.解析项目源代码 import 解析一个CSharp项目
|
from crazy_functions.SourceCode_Analyse import 解析一个CSharp项目
|
||||||
from crazy_functions.总结word文档 import 总结word文档
|
|
||||||
from crazy_functions.解析JupyterNotebook import 解析ipynb文件
|
from crazy_functions.解析JupyterNotebook import 解析ipynb文件
|
||||||
from crazy_functions.对话历史存档 import 对话历史存档
|
from crazy_functions.Conversation_To_File import 载入对话历史存档
|
||||||
from crazy_functions.对话历史存档 import 载入对话历史存档
|
from crazy_functions.Conversation_To_File import 对话历史存档
|
||||||
from crazy_functions.对话历史存档 import 删除所有本地对话历史记录
|
from crazy_functions.Conversation_To_File import Conversation_To_File_Wrap
|
||||||
|
from crazy_functions.Conversation_To_File import 删除所有本地对话历史记录
|
||||||
from crazy_functions.辅助功能 import 清除缓存
|
from crazy_functions.辅助功能 import 清除缓存
|
||||||
from crazy_functions.批量Markdown翻译 import Markdown英译中
|
from crazy_functions.批量文件询问 import 批量文件询问
|
||||||
|
from crazy_functions.Markdown_Translate import Markdown英译中
|
||||||
from crazy_functions.批量总结PDF文档 import 批量总结PDF文档
|
from crazy_functions.批量总结PDF文档 import 批量总结PDF文档
|
||||||
from crazy_functions.批量翻译PDF文档_多线程 import 批量翻译PDF文档
|
from crazy_functions.PDF_Translate import 批量翻译PDF文档
|
||||||
from crazy_functions.谷歌检索小助手 import 谷歌检索小助手
|
from crazy_functions.谷歌检索小助手 import 谷歌检索小助手
|
||||||
from crazy_functions.理解PDF文档内容 import 理解PDF文档内容标准文件输入
|
from crazy_functions.理解PDF文档内容 import 理解PDF文档内容标准文件输入
|
||||||
from crazy_functions.Latex全文润色 import Latex中文润色
|
from crazy_functions.Latex全文润色 import Latex中文润色
|
||||||
from crazy_functions.Latex全文润色 import Latex英文纠错
|
from crazy_functions.Latex全文润色 import Latex英文纠错
|
||||||
from crazy_functions.Latex全文翻译 import Latex中译英
|
from crazy_functions.Markdown_Translate import Markdown中译英
|
||||||
from crazy_functions.Latex全文翻译 import Latex英译中
|
|
||||||
from crazy_functions.批量Markdown翻译 import Markdown中译英
|
|
||||||
from crazy_functions.虚空终端 import 虚空终端
|
from crazy_functions.虚空终端 import 虚空终端
|
||||||
|
from crazy_functions.生成多种Mermaid图表 import Mermaid_Gen
|
||||||
|
from crazy_functions.PDF_Translate_Wrap import PDF_Tran
|
||||||
|
from crazy_functions.Latex_Function import Latex英文纠错加PDF对比
|
||||||
|
from crazy_functions.Latex_Function import Latex翻译中文并重新编译PDF
|
||||||
|
from crazy_functions.Latex_Function import PDF翻译中文并重新编译PDF
|
||||||
|
from crazy_functions.Latex_Function_Wrap import Arxiv_Localize
|
||||||
|
from crazy_functions.Latex_Function_Wrap import PDF_Localize
|
||||||
|
from crazy_functions.Internet_GPT import 连接网络回答问题
|
||||||
|
from crazy_functions.Internet_GPT_Wrap import NetworkGPT_Wrap
|
||||||
|
from crazy_functions.Image_Generate import 图片生成_DALLE2, 图片生成_DALLE3, 图片修改_DALLE2
|
||||||
|
from crazy_functions.Image_Generate_Wrap import ImageGen_Wrap
|
||||||
|
from crazy_functions.SourceCode_Comment import 注释Python项目
|
||||||
|
from crazy_functions.SourceCode_Comment_Wrap import SourceCodeComment_Wrap
|
||||||
|
|
||||||
function_plugins = {
|
function_plugins = {
|
||||||
"虚空终端": {
|
"虚空终端": {
|
||||||
"Group": "对话|编程|学术|智能体",
|
"Group": "对话|编程|学术|智能体",
|
||||||
"Color": "stop",
|
"Color": "stop",
|
||||||
"AsButton": True,
|
"AsButton": True,
|
||||||
"Function": HotReload(虚空终端)
|
"Info": "使用自然语言实现您的想法",
|
||||||
|
"Function": HotReload(虚空终端),
|
||||||
},
|
},
|
||||||
"解析整个Python项目": {
|
"解析整个Python项目": {
|
||||||
"Group": "编程",
|
"Group": "编程",
|
||||||
"Color": "stop",
|
"Color": "stop",
|
||||||
"AsButton": True,
|
"AsButton": True,
|
||||||
"Info": "解析一个Python项目的所有源文件(.py) | 输入参数为路径",
|
"Info": "解析一个Python项目的所有源文件(.py) | 输入参数为路径",
|
||||||
"Function": HotReload(解析一个Python项目)
|
"Function": HotReload(解析一个Python项目),
|
||||||
|
},
|
||||||
|
"注释Python项目": {
|
||||||
|
"Group": "编程",
|
||||||
|
"Color": "stop",
|
||||||
|
"AsButton": False,
|
||||||
|
"Info": "上传一系列python源文件(或者压缩包), 为这些代码添加docstring | 输入参数为路径",
|
||||||
|
"Function": HotReload(注释Python项目),
|
||||||
|
"Class": SourceCodeComment_Wrap,
|
||||||
},
|
},
|
||||||
"载入对话历史存档(先上传存档或输入路径)": {
|
"载入对话历史存档(先上传存档或输入路径)": {
|
||||||
"Group": "对话",
|
"Group": "对话",
|
||||||
"Color": "stop",
|
"Color": "stop",
|
||||||
"AsButton": False,
|
"AsButton": False,
|
||||||
"Info": "载入对话历史存档 | 输入参数为路径",
|
"Info": "载入对话历史存档 | 输入参数为路径",
|
||||||
"Function": HotReload(载入对话历史存档)
|
"Function": HotReload(载入对话历史存档),
|
||||||
},
|
},
|
||||||
"删除所有本地对话历史记录(谨慎操作)": {
|
"删除所有本地对话历史记录(谨慎操作)": {
|
||||||
"Group": "对话",
|
"Group": "对话",
|
||||||
"AsButton": False,
|
"AsButton": False,
|
||||||
"Info": "删除所有本地对话历史记录,谨慎操作 | 不需要输入参数",
|
"Info": "删除所有本地对话历史记录,谨慎操作 | 不需要输入参数",
|
||||||
"Function": HotReload(删除所有本地对话历史记录)
|
"Function": HotReload(删除所有本地对话历史记录),
|
||||||
},
|
},
|
||||||
"清除所有缓存文件(谨慎操作)": {
|
"清除所有缓存文件(谨慎操作)": {
|
||||||
"Group": "对话",
|
"Group": "对话",
|
||||||
"Color": "stop",
|
"Color": "stop",
|
||||||
"AsButton": False, # 加入下拉菜单中
|
"AsButton": False, # 加入下拉菜单中
|
||||||
"Info": "清除所有缓存文件,谨慎操作 | 不需要输入参数",
|
"Info": "清除所有缓存文件,谨慎操作 | 不需要输入参数",
|
||||||
"Function": HotReload(清除缓存)
|
"Function": HotReload(清除缓存),
|
||||||
},
|
},
|
||||||
"批量总结Word文档": {
|
"生成多种Mermaid图表(从当前对话或路径(.pdf/.md/.docx)中生产图表)": {
|
||||||
|
"Group": "对话",
|
||||||
|
"Color": "stop",
|
||||||
|
"AsButton": False,
|
||||||
|
"Info" : "基于当前对话或文件生成多种Mermaid图表,图表类型由模型判断",
|
||||||
|
"Function": None,
|
||||||
|
"Class": Mermaid_Gen
|
||||||
|
},
|
||||||
|
"Arxiv论文翻译": {
|
||||||
"Group": "学术",
|
"Group": "学术",
|
||||||
"Color": "stop",
|
"Color": "stop",
|
||||||
"AsButton": True,
|
"AsButton": True,
|
||||||
"Info": "批量总结word文档 | 输入参数为路径",
|
"Info": "Arixv论文精细翻译 | 输入参数arxiv论文的ID,比如1812.10695",
|
||||||
"Function": HotReload(总结word文档)
|
"Function": HotReload(Latex翻译中文并重新编译PDF), # 当注册Class后,Function旧接口仅会在“虚空终端”中起作用
|
||||||
|
"Class": Arxiv_Localize, # 新一代插件需要注册Class
|
||||||
|
},
|
||||||
|
"批量文件询问": {
|
||||||
|
"Group": "学术",
|
||||||
|
"Color": "stop",
|
||||||
|
"AsButton": False,
|
||||||
|
"AdvancedArgs": True,
|
||||||
|
"Info": "通过在高级参数区写入prompt,可自定义询问逻辑,默认情况下为总结逻辑 | 输入参数为路径",
|
||||||
|
"Function": HotReload(批量文件询问),
|
||||||
},
|
},
|
||||||
"解析整个Matlab项目": {
|
"解析整个Matlab项目": {
|
||||||
"Group": "编程",
|
"Group": "编程",
|
||||||
"Color": "stop",
|
"Color": "stop",
|
||||||
"AsButton": False,
|
"AsButton": False,
|
||||||
"Info": "解析一个Matlab项目的所有源文件(.m) | 输入参数为路径",
|
"Info": "解析一个Matlab项目的所有源文件(.m) | 输入参数为路径",
|
||||||
"Function": HotReload(解析一个Matlab项目)
|
"Function": HotReload(解析一个Matlab项目),
|
||||||
},
|
},
|
||||||
"解析整个C++项目头文件": {
|
"解析整个C++项目头文件": {
|
||||||
"Group": "编程",
|
"Group": "编程",
|
||||||
"Color": "stop",
|
"Color": "stop",
|
||||||
"AsButton": False, # 加入下拉菜单中
|
"AsButton": False, # 加入下拉菜单中
|
||||||
"Info": "解析一个C++项目的所有头文件(.h/.hpp) | 输入参数为路径",
|
"Info": "解析一个C++项目的所有头文件(.h/.hpp) | 输入参数为路径",
|
||||||
"Function": HotReload(解析一个C项目的头文件)
|
"Function": HotReload(解析一个C项目的头文件),
|
||||||
},
|
},
|
||||||
"解析整个C++项目(.cpp/.hpp/.c/.h)": {
|
"解析整个C++项目(.cpp/.hpp/.c/.h)": {
|
||||||
"Group": "编程",
|
"Group": "编程",
|
||||||
"Color": "stop",
|
"Color": "stop",
|
||||||
"AsButton": False, # 加入下拉菜单中
|
"AsButton": False, # 加入下拉菜单中
|
||||||
"Info": "解析一个C++项目的所有源文件(.cpp/.hpp/.c/.h)| 输入参数为路径",
|
"Info": "解析一个C++项目的所有源文件(.cpp/.hpp/.c/.h)| 输入参数为路径",
|
||||||
"Function": HotReload(解析一个C项目)
|
"Function": HotReload(解析一个C项目),
|
||||||
},
|
},
|
||||||
"解析整个Go项目": {
|
"解析整个Go项目": {
|
||||||
"Group": "编程",
|
"Group": "编程",
|
||||||
"Color": "stop",
|
"Color": "stop",
|
||||||
"AsButton": False, # 加入下拉菜单中
|
"AsButton": False, # 加入下拉菜单中
|
||||||
"Info": "解析一个Go项目的所有源文件 | 输入参数为路径",
|
"Info": "解析一个Go项目的所有源文件 | 输入参数为路径",
|
||||||
"Function": HotReload(解析一个Golang项目)
|
"Function": HotReload(解析一个Golang项目),
|
||||||
},
|
},
|
||||||
"解析整个Rust项目": {
|
"解析整个Rust项目": {
|
||||||
"Group": "编程",
|
"Group": "编程",
|
||||||
"Color": "stop",
|
"Color": "stop",
|
||||||
"AsButton": False, # 加入下拉菜单中
|
"AsButton": False, # 加入下拉菜单中
|
||||||
"Info": "解析一个Rust项目的所有源文件 | 输入参数为路径",
|
"Info": "解析一个Rust项目的所有源文件 | 输入参数为路径",
|
||||||
"Function": HotReload(解析一个Rust项目)
|
"Function": HotReload(解析一个Rust项目),
|
||||||
},
|
},
|
||||||
"解析整个Java项目": {
|
"解析整个Java项目": {
|
||||||
"Group": "编程",
|
"Group": "编程",
|
||||||
"Color": "stop",
|
"Color": "stop",
|
||||||
"AsButton": False, # 加入下拉菜单中
|
"AsButton": False, # 加入下拉菜单中
|
||||||
"Info": "解析一个Java项目的所有源文件 | 输入参数为路径",
|
"Info": "解析一个Java项目的所有源文件 | 输入参数为路径",
|
||||||
"Function": HotReload(解析一个Java项目)
|
"Function": HotReload(解析一个Java项目),
|
||||||
},
|
},
|
||||||
"解析整个前端项目(js,ts,css等)": {
|
"解析整个前端项目(js,ts,css等)": {
|
||||||
"Group": "编程",
|
"Group": "编程",
|
||||||
"Color": "stop",
|
"Color": "stop",
|
||||||
"AsButton": False, # 加入下拉菜单中
|
"AsButton": False, # 加入下拉菜单中
|
||||||
"Info": "解析一个前端项目的所有源文件(js,ts,css等) | 输入参数为路径",
|
"Info": "解析一个前端项目的所有源文件(js,ts,css等) | 输入参数为路径",
|
||||||
"Function": HotReload(解析一个前端项目)
|
"Function": HotReload(解析一个前端项目),
|
||||||
},
|
},
|
||||||
"解析整个Lua项目": {
|
"解析整个Lua项目": {
|
||||||
"Group": "编程",
|
"Group": "编程",
|
||||||
"Color": "stop",
|
"Color": "stop",
|
||||||
"AsButton": False, # 加入下拉菜单中
|
"AsButton": False, # 加入下拉菜单中
|
||||||
"Info": "解析一个Lua项目的所有源文件 | 输入参数为路径",
|
"Info": "解析一个Lua项目的所有源文件 | 输入参数为路径",
|
||||||
"Function": HotReload(解析一个Lua项目)
|
"Function": HotReload(解析一个Lua项目),
|
||||||
},
|
},
|
||||||
"解析整个CSharp项目": {
|
"解析整个CSharp项目": {
|
||||||
"Group": "编程",
|
"Group": "编程",
|
||||||
"Color": "stop",
|
"Color": "stop",
|
||||||
"AsButton": False, # 加入下拉菜单中
|
"AsButton": False, # 加入下拉菜单中
|
||||||
"Info": "解析一个CSharp项目的所有源文件 | 输入参数为路径",
|
"Info": "解析一个CSharp项目的所有源文件 | 输入参数为路径",
|
||||||
"Function": HotReload(解析一个CSharp项目)
|
"Function": HotReload(解析一个CSharp项目),
|
||||||
},
|
},
|
||||||
"解析Jupyter Notebook文件": {
|
"解析Jupyter Notebook文件": {
|
||||||
"Group": "编程",
|
"Group": "编程",
|
||||||
@@ -156,103 +195,118 @@ def get_crazy_functions():
|
|||||||
"Color": "stop",
|
"Color": "stop",
|
||||||
"AsButton": False,
|
"AsButton": False,
|
||||||
"Info": "读取Tex论文并写摘要 | 输入参数为路径",
|
"Info": "读取Tex论文并写摘要 | 输入参数为路径",
|
||||||
"Function": HotReload(读文章写摘要)
|
"Function": HotReload(读文章写摘要),
|
||||||
},
|
},
|
||||||
"翻译README或MD": {
|
"翻译README或MD": {
|
||||||
"Group": "编程",
|
"Group": "编程",
|
||||||
"Color": "stop",
|
"Color": "stop",
|
||||||
"AsButton": True,
|
"AsButton": True,
|
||||||
"Info": "将Markdown翻译为中文 | 输入参数为路径或URL",
|
"Info": "将Markdown翻译为中文 | 输入参数为路径或URL",
|
||||||
"Function": HotReload(Markdown英译中)
|
"Function": HotReload(Markdown英译中),
|
||||||
},
|
},
|
||||||
"翻译Markdown或README(支持Github链接)": {
|
"翻译Markdown或README(支持Github链接)": {
|
||||||
"Group": "编程",
|
"Group": "编程",
|
||||||
"Color": "stop",
|
"Color": "stop",
|
||||||
"AsButton": False,
|
"AsButton": False,
|
||||||
"Info": "将Markdown或README翻译为中文 | 输入参数为路径或URL",
|
"Info": "将Markdown或README翻译为中文 | 输入参数为路径或URL",
|
||||||
"Function": HotReload(Markdown英译中)
|
"Function": HotReload(Markdown英译中),
|
||||||
},
|
},
|
||||||
"批量生成函数注释": {
|
"批量生成函数注释": {
|
||||||
"Group": "编程",
|
"Group": "编程",
|
||||||
"Color": "stop",
|
"Color": "stop",
|
||||||
"AsButton": False, # 加入下拉菜单中
|
"AsButton": False, # 加入下拉菜单中
|
||||||
"Info": "批量生成函数的注释 | 输入参数为路径",
|
"Info": "批量生成函数的注释 | 输入参数为路径",
|
||||||
"Function": HotReload(批量生成函数注释)
|
"Function": HotReload(批量生成函数注释),
|
||||||
},
|
},
|
||||||
"保存当前的对话": {
|
"保存当前的对话": {
|
||||||
"Group": "对话",
|
"Group": "对话",
|
||||||
|
"Color": "stop",
|
||||||
"AsButton": True,
|
"AsButton": True,
|
||||||
"Info": "保存当前的对话 | 不需要输入参数",
|
"Info": "保存当前的对话 | 不需要输入参数",
|
||||||
"Function": HotReload(对话历史存档)
|
"Function": HotReload(对话历史存档), # 当注册Class后,Function旧接口仅会在“虚空终端”中起作用
|
||||||
|
"Class": Conversation_To_File_Wrap # 新一代插件需要注册Class
|
||||||
},
|
},
|
||||||
"[多线程Demo]解析此项目本身(源码自译解)": {
|
"[多线程Demo]解析此项目本身(源码自译解)": {
|
||||||
"Group": "对话|编程",
|
"Group": "对话|编程",
|
||||||
|
"Color": "stop",
|
||||||
"AsButton": False, # 加入下拉菜单中
|
"AsButton": False, # 加入下拉菜单中
|
||||||
"Info": "多线程解析并翻译此项目的源码 | 不需要输入参数",
|
"Info": "多线程解析并翻译此项目的源码 | 不需要输入参数",
|
||||||
"Function": HotReload(解析项目本身)
|
"Function": HotReload(解析项目本身),
|
||||||
|
},
|
||||||
|
"查互联网后回答": {
|
||||||
|
"Group": "对话",
|
||||||
|
"Color": "stop",
|
||||||
|
"AsButton": True, # 加入下拉菜单中
|
||||||
|
# "Info": "连接网络回答问题(需要访问谷歌)| 输入参数是一个问题",
|
||||||
|
"Function": HotReload(连接网络回答问题),
|
||||||
|
"Class": NetworkGPT_Wrap # 新一代插件需要注册Class
|
||||||
},
|
},
|
||||||
"历史上的今天": {
|
"历史上的今天": {
|
||||||
"Group": "对话",
|
"Group": "对话",
|
||||||
"AsButton": True,
|
"Color": "stop",
|
||||||
|
"AsButton": False,
|
||||||
"Info": "查看历史上的今天事件 (这是一个面向开发者的插件Demo) | 不需要输入参数",
|
"Info": "查看历史上的今天事件 (这是一个面向开发者的插件Demo) | 不需要输入参数",
|
||||||
"Function": HotReload(高阶功能模板函数)
|
"Function": None,
|
||||||
|
"Class": Demo_Wrap, # 新一代插件需要注册Class
|
||||||
},
|
},
|
||||||
"精准翻译PDF论文": {
|
"精准翻译PDF论文": {
|
||||||
"Group": "学术",
|
"Group": "学术",
|
||||||
"Color": "stop",
|
"Color": "stop",
|
||||||
"AsButton": True,
|
"AsButton": True,
|
||||||
"Info": "精准翻译PDF论文为中文 | 输入参数为路径",
|
"Info": "精准翻译PDF论文为中文 | 输入参数为路径",
|
||||||
"Function": HotReload(批量翻译PDF文档)
|
"Function": HotReload(批量翻译PDF文档), # 当注册Class后,Function旧接口仅会在“虚空终端”中起作用
|
||||||
|
"Class": PDF_Tran, # 新一代插件需要注册Class
|
||||||
},
|
},
|
||||||
"询问多个GPT模型": {
|
"询问多个GPT模型": {
|
||||||
"Group": "对话",
|
"Group": "对话",
|
||||||
"Color": "stop",
|
"Color": "stop",
|
||||||
"AsButton": True,
|
"AsButton": True,
|
||||||
"Function": HotReload(同时问询)
|
"Function": HotReload(同时问询),
|
||||||
},
|
},
|
||||||
"批量总结PDF文档": {
|
"批量总结PDF文档": {
|
||||||
"Group": "学术",
|
"Group": "学术",
|
||||||
"Color": "stop",
|
"Color": "stop",
|
||||||
"AsButton": False, # 加入下拉菜单中
|
"AsButton": False, # 加入下拉菜单中
|
||||||
"Info": "批量总结PDF文档的内容 | 输入参数为路径",
|
"Info": "批量总结PDF文档的内容 | 输入参数为路径",
|
||||||
"Function": HotReload(批量总结PDF文档)
|
"Function": HotReload(批量总结PDF文档),
|
||||||
},
|
},
|
||||||
"谷歌学术检索助手(输入谷歌学术搜索页url)": {
|
"谷歌学术检索助手(输入谷歌学术搜索页url)": {
|
||||||
"Group": "学术",
|
"Group": "学术",
|
||||||
"Color": "stop",
|
"Color": "stop",
|
||||||
"AsButton": False, # 加入下拉菜单中
|
"AsButton": False, # 加入下拉菜单中
|
||||||
"Info": "使用谷歌学术检索助手搜索指定URL的结果 | 输入参数为谷歌学术搜索页的URL",
|
"Info": "使用谷歌学术检索助手搜索指定URL的结果 | 输入参数为谷歌学术搜索页的URL",
|
||||||
"Function": HotReload(谷歌检索小助手)
|
"Function": HotReload(谷歌检索小助手),
|
||||||
},
|
},
|
||||||
"理解PDF文档内容 (模仿ChatPDF)": {
|
"理解PDF文档内容 (模仿ChatPDF)": {
|
||||||
"Group": "学术",
|
"Group": "学术",
|
||||||
"Color": "stop",
|
"Color": "stop",
|
||||||
"AsButton": False, # 加入下拉菜单中
|
"AsButton": False, # 加入下拉菜单中
|
||||||
"Info": "理解PDF文档的内容并进行回答 | 输入参数为路径",
|
"Info": "理解PDF文档的内容并进行回答 | 输入参数为路径",
|
||||||
"Function": HotReload(理解PDF文档内容标准文件输入)
|
"Function": HotReload(理解PDF文档内容标准文件输入),
|
||||||
},
|
},
|
||||||
"英文Latex项目全文润色(输入路径或上传压缩包)": {
|
"英文Latex项目全文润色(输入路径或上传压缩包)": {
|
||||||
"Group": "学术",
|
"Group": "学术",
|
||||||
"Color": "stop",
|
"Color": "stop",
|
||||||
"AsButton": False, # 加入下拉菜单中
|
"AsButton": False, # 加入下拉菜单中
|
||||||
"Info": "对英文Latex项目全文进行润色处理 | 输入参数为路径或上传压缩包",
|
"Info": "对英文Latex项目全文进行润色处理 | 输入参数为路径或上传压缩包",
|
||||||
"Function": HotReload(Latex英文润色)
|
"Function": HotReload(Latex英文润色),
|
||||||
},
|
|
||||||
"英文Latex项目全文纠错(输入路径或上传压缩包)": {
|
|
||||||
"Group": "学术",
|
|
||||||
"Color": "stop",
|
|
||||||
"AsButton": False, # 加入下拉菜单中
|
|
||||||
"Info": "对英文Latex项目全文进行纠错处理 | 输入参数为路径或上传压缩包",
|
|
||||||
"Function": HotReload(Latex英文纠错)
|
|
||||||
},
|
},
|
||||||
|
|
||||||
"中文Latex项目全文润色(输入路径或上传压缩包)": {
|
"中文Latex项目全文润色(输入路径或上传压缩包)": {
|
||||||
"Group": "学术",
|
"Group": "学术",
|
||||||
"Color": "stop",
|
"Color": "stop",
|
||||||
"AsButton": False, # 加入下拉菜单中
|
"AsButton": False, # 加入下拉菜单中
|
||||||
"Info": "对中文Latex项目全文进行润色处理 | 输入参数为路径或上传压缩包",
|
"Info": "对中文Latex项目全文进行润色处理 | 输入参数为路径或上传压缩包",
|
||||||
"Function": HotReload(Latex中文润色)
|
"Function": HotReload(Latex中文润色),
|
||||||
},
|
},
|
||||||
|
# 已经被新插件取代
|
||||||
|
# "英文Latex项目全文纠错(输入路径或上传压缩包)": {
|
||||||
|
# "Group": "学术",
|
||||||
|
# "Color": "stop",
|
||||||
|
# "AsButton": False, # 加入下拉菜单中
|
||||||
|
# "Info": "对英文Latex项目全文进行纠错处理 | 输入参数为路径或上传压缩包",
|
||||||
|
# "Function": HotReload(Latex英文纠错),
|
||||||
|
# },
|
||||||
# 已经被新插件取代
|
# 已经被新插件取代
|
||||||
# "Latex项目全文中译英(输入路径或上传压缩包)": {
|
# "Latex项目全文中译英(输入路径或上传压缩包)": {
|
||||||
# "Group": "学术",
|
# "Group": "学术",
|
||||||
@@ -261,7 +315,6 @@ def get_crazy_functions():
|
|||||||
# "Info": "对Latex项目全文进行中译英处理 | 输入参数为路径或上传压缩包",
|
# "Info": "对Latex项目全文进行中译英处理 | 输入参数为路径或上传压缩包",
|
||||||
# "Function": HotReload(Latex中译英)
|
# "Function": HotReload(Latex中译英)
|
||||||
# },
|
# },
|
||||||
|
|
||||||
# 已经被新插件取代
|
# 已经被新插件取代
|
||||||
# "Latex项目全文英译中(输入路径或上传压缩包)": {
|
# "Latex项目全文英译中(输入路径或上传压缩包)": {
|
||||||
# "Group": "学术",
|
# "Group": "学术",
|
||||||
@@ -270,130 +323,187 @@ def get_crazy_functions():
|
|||||||
# "Info": "对Latex项目全文进行英译中处理 | 输入参数为路径或上传压缩包",
|
# "Info": "对Latex项目全文进行英译中处理 | 输入参数为路径或上传压缩包",
|
||||||
# "Function": HotReload(Latex英译中)
|
# "Function": HotReload(Latex英译中)
|
||||||
# },
|
# },
|
||||||
|
|
||||||
"批量Markdown中译英(输入路径或上传压缩包)": {
|
"批量Markdown中译英(输入路径或上传压缩包)": {
|
||||||
"Group": "编程",
|
"Group": "编程",
|
||||||
"Color": "stop",
|
"Color": "stop",
|
||||||
"AsButton": False, # 加入下拉菜单中
|
"AsButton": False, # 加入下拉菜单中
|
||||||
"Info": "批量将Markdown文件中文翻译为英文 | 输入参数为路径或上传压缩包",
|
"Info": "批量将Markdown文件中文翻译为英文 | 输入参数为路径或上传压缩包",
|
||||||
"Function": HotReload(Markdown中译英)
|
"Function": HotReload(Markdown中译英),
|
||||||
|
},
|
||||||
|
"Latex英文纠错+高亮修正位置 [需Latex]": {
|
||||||
|
"Group": "学术",
|
||||||
|
"Color": "stop",
|
||||||
|
"AsButton": False,
|
||||||
|
"AdvancedArgs": True,
|
||||||
|
"ArgsReminder": "如果有必要, 请在此处追加更细致的矫错指令(使用英文)。",
|
||||||
|
"Function": HotReload(Latex英文纠错加PDF对比),
|
||||||
|
},
|
||||||
|
"📚Arxiv论文精细翻译(输入arxivID)[需Latex]": {
|
||||||
|
"Group": "学术",
|
||||||
|
"Color": "stop",
|
||||||
|
"AsButton": False,
|
||||||
|
"AdvancedArgs": True,
|
||||||
|
"ArgsReminder": r"如果有必要, 请在此处给出自定义翻译命令, 解决部分词汇翻译不准确的问题。 "
|
||||||
|
r"例如当单词'agent'翻译不准确时, 请尝试把以下指令复制到高级参数区: "
|
||||||
|
r'If the term "agent" is used in this section, it should be translated to "智能体". ',
|
||||||
|
"Info": "Arixv论文精细翻译 | 输入参数arxiv论文的ID,比如1812.10695",
|
||||||
|
"Function": HotReload(Latex翻译中文并重新编译PDF), # 当注册Class后,Function旧接口仅会在“虚空终端”中起作用
|
||||||
|
"Class": Arxiv_Localize, # 新一代插件需要注册Class
|
||||||
|
},
|
||||||
|
"📚本地Latex论文精细翻译(上传Latex项目)[需Latex]": {
|
||||||
|
"Group": "学术",
|
||||||
|
"Color": "stop",
|
||||||
|
"AsButton": False,
|
||||||
|
"AdvancedArgs": True,
|
||||||
|
"ArgsReminder": r"如果有必要, 请在此处给出自定义翻译命令, 解决部分词汇翻译不准确的问题。 "
|
||||||
|
r"例如当单词'agent'翻译不准确时, 请尝试把以下指令复制到高级参数区: "
|
||||||
|
r'If the term "agent" is used in this section, it should be translated to "智能体". ',
|
||||||
|
"Info": "本地Latex论文精细翻译 | 输入参数是路径",
|
||||||
|
"Function": HotReload(Latex翻译中文并重新编译PDF),
|
||||||
|
},
|
||||||
|
"PDF翻译中文并重新编译PDF(上传PDF)[需Latex]": {
|
||||||
|
"Group": "学术",
|
||||||
|
"Color": "stop",
|
||||||
|
"AsButton": False,
|
||||||
|
"AdvancedArgs": True,
|
||||||
|
"ArgsReminder": r"如果有必要, 请在此处给出自定义翻译命令, 解决部分词汇翻译不准确的问题。 "
|
||||||
|
r"例如当单词'agent'翻译不准确时, 请尝试把以下指令复制到高级参数区: "
|
||||||
|
r'If the term "agent" is used in this section, it should be translated to "智能体". ',
|
||||||
|
"Info": "PDF翻译中文,并重新编译PDF | 输入参数为路径",
|
||||||
|
"Function": HotReload(PDF翻译中文并重新编译PDF), # 当注册Class后,Function旧接口仅会在“虚空终端”中起作用
|
||||||
|
"Class": PDF_Localize # 新一代插件需要注册Class
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function_plugins.update(
|
||||||
|
{
|
||||||
|
"🎨图片生成(DALLE2/DALLE3, 使用前切换到GPT系列模型)": {
|
||||||
|
"Group": "对话",
|
||||||
|
"Color": "stop",
|
||||||
|
"AsButton": False,
|
||||||
|
"Info": "使用 DALLE2/DALLE3 生成图片 | 输入参数字符串,提供图像的内容",
|
||||||
|
"Function": HotReload(图片生成_DALLE2), # 当注册Class后,Function旧接口仅会在“虚空终端”中起作用
|
||||||
|
"Class": ImageGen_Wrap # 新一代插件需要注册Class
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
function_plugins.update(
|
||||||
|
{
|
||||||
|
"🎨图片修改_DALLE2 (使用前请切换模型到GPT系列)": {
|
||||||
|
"Group": "对话",
|
||||||
|
"Color": "stop",
|
||||||
|
"AsButton": False,
|
||||||
|
"AdvancedArgs": False, # 调用时,唤起高级参数输入区(默认False)
|
||||||
|
# "Info": "使用DALLE2修改图片 | 输入参数字符串,提供图像的内容",
|
||||||
|
"Function": HotReload(图片修改_DALLE2),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# -=--=- 尚未充分测试的实验性插件 & 需要额外依赖的插件 -=--=-
|
# -=--=- 尚未充分测试的实验性插件 & 需要额外依赖的插件 -=--=-
|
||||||
try:
|
try:
|
||||||
from crazy_functions.下载arxiv论文翻译摘要 import 下载arxiv论文并翻译摘要
|
from crazy_functions.下载arxiv论文翻译摘要 import 下载arxiv论文并翻译摘要
|
||||||
function_plugins.update({
|
|
||||||
|
function_plugins.update(
|
||||||
|
{
|
||||||
"一键下载arxiv论文并翻译摘要(先在input输入编号,如1812.10695)": {
|
"一键下载arxiv论文并翻译摘要(先在input输入编号,如1812.10695)": {
|
||||||
"Group": "学术",
|
"Group": "学术",
|
||||||
"Color": "stop",
|
"Color": "stop",
|
||||||
"AsButton": False, # 加入下拉菜单中
|
"AsButton": False, # 加入下拉菜单中
|
||||||
# "Info": "下载arxiv论文并翻译摘要 | 输入参数为arxiv编号如1812.10695",
|
# "Info": "下载arxiv论文并翻译摘要 | 输入参数为arxiv编号如1812.10695",
|
||||||
"Function": HotReload(下载arxiv论文并翻译摘要)
|
"Function": HotReload(下载arxiv论文并翻译摘要),
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
)
|
||||||
except:
|
except:
|
||||||
print(trimmed_format_exc())
|
logger.error(trimmed_format_exc())
|
||||||
print('Load function plugin failed')
|
logger.error("Load function plugin failed")
|
||||||
|
|
||||||
|
# try:
|
||||||
|
# from crazy_functions.联网的ChatGPT import 连接网络回答问题
|
||||||
|
|
||||||
|
# function_plugins.update(
|
||||||
|
# {
|
||||||
|
# "连接网络回答问题(输入问题后点击该插件,需要访问谷歌)": {
|
||||||
|
# "Group": "对话",
|
||||||
|
# "Color": "stop",
|
||||||
|
# "AsButton": False, # 加入下拉菜单中
|
||||||
|
# # "Info": "连接网络回答问题(需要访问谷歌)| 输入参数是一个问题",
|
||||||
|
# "Function": HotReload(连接网络回答问题),
|
||||||
|
# }
|
||||||
|
# }
|
||||||
|
# )
|
||||||
|
# from crazy_functions.联网的ChatGPT_bing版 import 连接bing搜索回答问题
|
||||||
|
|
||||||
|
# function_plugins.update(
|
||||||
|
# {
|
||||||
|
# "连接网络回答问题(中文Bing版,输入问题后点击该插件)": {
|
||||||
|
# "Group": "对话",
|
||||||
|
# "Color": "stop",
|
||||||
|
# "AsButton": False, # 加入下拉菜单中
|
||||||
|
# "Info": "连接网络回答问题(需要访问中文Bing)| 输入参数是一个问题",
|
||||||
|
# "Function": HotReload(连接bing搜索回答问题),
|
||||||
|
# }
|
||||||
|
# }
|
||||||
|
# )
|
||||||
|
# except:
|
||||||
|
# logger.error(trimmed_format_exc())
|
||||||
|
# logger.error("Load function plugin failed")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from crazy_functions.联网的ChatGPT import 连接网络回答问题
|
from crazy_functions.SourceCode_Analyse import 解析任意code项目
|
||||||
function_plugins.update({
|
|
||||||
"连接网络回答问题(输入问题后点击该插件,需要访问谷歌)": {
|
|
||||||
"Group": "对话",
|
|
||||||
"Color": "stop",
|
|
||||||
"AsButton": False, # 加入下拉菜单中
|
|
||||||
# "Info": "连接网络回答问题(需要访问谷歌)| 输入参数是一个问题",
|
|
||||||
"Function": HotReload(连接网络回答问题)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
from crazy_functions.联网的ChatGPT_bing版 import 连接bing搜索回答问题
|
|
||||||
function_plugins.update({
|
|
||||||
"连接网络回答问题(中文Bing版,输入问题后点击该插件)": {
|
|
||||||
"Group": "对话",
|
|
||||||
"Color": "stop",
|
|
||||||
"AsButton": False, # 加入下拉菜单中
|
|
||||||
"Info": "连接网络回答问题(需要访问中文Bing)| 输入参数是一个问题",
|
|
||||||
"Function": HotReload(连接bing搜索回答问题)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
except:
|
|
||||||
print(trimmed_format_exc())
|
|
||||||
print('Load function plugin failed')
|
|
||||||
|
|
||||||
try:
|
function_plugins.update(
|
||||||
from crazy_functions.解析项目源代码 import 解析任意code项目
|
{
|
||||||
function_plugins.update({
|
|
||||||
"解析项目源代码(手动指定和筛选源代码文件类型)": {
|
"解析项目源代码(手动指定和筛选源代码文件类型)": {
|
||||||
"Group": "编程",
|
"Group": "编程",
|
||||||
"Color": "stop",
|
"Color": "stop",
|
||||||
"AsButton": False,
|
"AsButton": False,
|
||||||
"AdvancedArgs": True, # 调用时,唤起高级参数输入区(默认False)
|
"AdvancedArgs": True, # 调用时,唤起高级参数输入区(默认False)
|
||||||
"ArgsReminder": "输入时用逗号隔开, *代表通配符, 加了^代表不匹配; 不输入代表全部匹配。例如: \"*.c, ^*.cpp, config.toml, ^*.toml\"", # 高级参数输入区的显示提示
|
"ArgsReminder": '输入时用逗号隔开, *代表通配符, 加了^代表不匹配; 不输入代表全部匹配。例如: "*.c, ^*.cpp, config.toml, ^*.toml"', # 高级参数输入区的显示提示
|
||||||
"Function": HotReload(解析任意code项目)
|
"Function": HotReload(解析任意code项目),
|
||||||
},
|
},
|
||||||
})
|
}
|
||||||
|
)
|
||||||
except:
|
except:
|
||||||
print(trimmed_format_exc())
|
logger.error(trimmed_format_exc())
|
||||||
print('Load function plugin failed')
|
logger.error("Load function plugin failed")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from crazy_functions.询问多个大语言模型 import 同时问询_指定模型
|
from crazy_functions.询问多个大语言模型 import 同时问询_指定模型
|
||||||
function_plugins.update({
|
|
||||||
|
function_plugins.update(
|
||||||
|
{
|
||||||
"询问多个GPT模型(手动指定询问哪些模型)": {
|
"询问多个GPT模型(手动指定询问哪些模型)": {
|
||||||
"Group": "对话",
|
"Group": "对话",
|
||||||
"Color": "stop",
|
"Color": "stop",
|
||||||
"AsButton": False,
|
"AsButton": False,
|
||||||
"AdvancedArgs": True, # 调用时,唤起高级参数输入区(默认False)
|
"AdvancedArgs": True, # 调用时,唤起高级参数输入区(默认False)
|
||||||
"ArgsReminder": "支持任意数量的llm接口,用&符号分隔。例如chatglm&gpt-3.5-turbo&gpt-4", # 高级参数输入区的显示提示
|
"ArgsReminder": "支持任意数量的llm接口,用&符号分隔。例如chatglm&gpt-3.5-turbo&gpt-4", # 高级参数输入区的显示提示
|
||||||
"Function": HotReload(同时问询_指定模型)
|
"Function": HotReload(同时问询_指定模型),
|
||||||
},
|
},
|
||||||
})
|
}
|
||||||
|
)
|
||||||
except:
|
except:
|
||||||
print(trimmed_format_exc())
|
logger.error(trimmed_format_exc())
|
||||||
print('Load function plugin failed')
|
logger.error("Load function plugin failed")
|
||||||
|
|
||||||
|
|
||||||
try:
|
|
||||||
from crazy_functions.图片生成 import 图片生成_DALLE2, 图片生成_DALLE3, 图片修改_DALLE2
|
|
||||||
function_plugins.update({
|
|
||||||
"图片生成_DALLE2 (先切换模型到gpt-*)": {
|
|
||||||
"Group": "对话",
|
|
||||||
"Color": "stop",
|
|
||||||
"AsButton": False,
|
|
||||||
"AdvancedArgs": True, # 调用时,唤起高级参数输入区(默认False)
|
|
||||||
"ArgsReminder": "在这里输入分辨率, 如1024x1024(默认),支持 256x256, 512x512, 1024x1024", # 高级参数输入区的显示提示
|
|
||||||
"Info": "使用DALLE2生成图片 | 输入参数字符串,提供图像的内容",
|
|
||||||
"Function": HotReload(图片生成_DALLE2)
|
|
||||||
},
|
|
||||||
})
|
|
||||||
function_plugins.update({
|
|
||||||
"图片生成_DALLE3 (先切换模型到gpt-*)": {
|
|
||||||
"Group": "对话",
|
|
||||||
"Color": "stop",
|
|
||||||
"AsButton": False,
|
|
||||||
"AdvancedArgs": True, # 调用时,唤起高级参数输入区(默认False)
|
|
||||||
"ArgsReminder": "在这里输入自定义参数「分辨率-质量(可选)-风格(可选)」, 参数示例「1024x1024-hd-vivid」 || 分辨率支持 「1024x1024」(默认) /「1792x1024」/「1024x1792」 || 质量支持 「-standard」(默认) /「-hd」 || 风格支持 「-vivid」(默认) /「-natural」", # 高级参数输入区的显示提示
|
|
||||||
"Info": "使用DALLE3生成图片 | 输入参数字符串,提供图像的内容",
|
|
||||||
"Function": HotReload(图片生成_DALLE3)
|
|
||||||
},
|
|
||||||
})
|
|
||||||
function_plugins.update({
|
|
||||||
"图片修改_DALLE2 (先切换模型到gpt-*)": {
|
|
||||||
"Group": "对话",
|
|
||||||
"Color": "stop",
|
|
||||||
"AsButton": False,
|
|
||||||
"AdvancedArgs": False, # 调用时,唤起高级参数输入区(默认False)
|
|
||||||
# "Info": "使用DALLE2修改图片 | 输入参数字符串,提供图像的内容",
|
|
||||||
"Function": HotReload(图片修改_DALLE2)
|
|
||||||
},
|
|
||||||
})
|
|
||||||
except:
|
|
||||||
print(trimmed_format_exc())
|
|
||||||
print('Load function plugin failed')
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from crazy_functions.总结音视频 import 总结音视频
|
from crazy_functions.总结音视频 import 总结音视频
|
||||||
function_plugins.update({
|
|
||||||
|
function_plugins.update(
|
||||||
|
{
|
||||||
"批量总结音视频(输入路径或上传压缩包)": {
|
"批量总结音视频(输入路径或上传压缩包)": {
|
||||||
"Group": "对话",
|
"Group": "对话",
|
||||||
"Color": "stop",
|
"Color": "stop",
|
||||||
@@ -401,208 +511,235 @@ def get_crazy_functions():
|
|||||||
"AdvancedArgs": True,
|
"AdvancedArgs": True,
|
||||||
"ArgsReminder": "调用openai api 使用whisper-1模型, 目前支持的格式:mp4, m4a, wav, mpga, mpeg, mp3。此处可以输入解析提示,例如:解析为简体中文(默认)。",
|
"ArgsReminder": "调用openai api 使用whisper-1模型, 目前支持的格式:mp4, m4a, wav, mpga, mpeg, mp3。此处可以输入解析提示,例如:解析为简体中文(默认)。",
|
||||||
"Info": "批量总结音频或视频 | 输入参数为路径",
|
"Info": "批量总结音频或视频 | 输入参数为路径",
|
||||||
"Function": HotReload(总结音视频)
|
"Function": HotReload(总结音视频),
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
)
|
||||||
except:
|
except:
|
||||||
print(trimmed_format_exc())
|
logger.error(trimmed_format_exc())
|
||||||
print('Load function plugin failed')
|
logger.error("Load function plugin failed")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from crazy_functions.数学动画生成manim import 动画生成
|
from crazy_functions.数学动画生成manim import 动画生成
|
||||||
function_plugins.update({
|
|
||||||
|
function_plugins.update(
|
||||||
|
{
|
||||||
"数学动画生成(Manim)": {
|
"数学动画生成(Manim)": {
|
||||||
"Group": "对话",
|
"Group": "对话",
|
||||||
"Color": "stop",
|
"Color": "stop",
|
||||||
"AsButton": False,
|
"AsButton": False,
|
||||||
"Info": "按照自然语言描述生成一个动画 | 输入参数是一段话",
|
"Info": "按照自然语言描述生成一个动画 | 输入参数是一段话",
|
||||||
"Function": HotReload(动画生成)
|
"Function": HotReload(动画生成),
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
)
|
||||||
except:
|
except:
|
||||||
print(trimmed_format_exc())
|
logger.error(trimmed_format_exc())
|
||||||
print('Load function plugin failed')
|
logger.error("Load function plugin failed")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from crazy_functions.批量Markdown翻译 import Markdown翻译指定语言
|
from crazy_functions.Markdown_Translate import Markdown翻译指定语言
|
||||||
function_plugins.update({
|
|
||||||
|
function_plugins.update(
|
||||||
|
{
|
||||||
"Markdown翻译(指定翻译成何种语言)": {
|
"Markdown翻译(指定翻译成何种语言)": {
|
||||||
"Group": "编程",
|
"Group": "编程",
|
||||||
"Color": "stop",
|
"Color": "stop",
|
||||||
"AsButton": False,
|
"AsButton": False,
|
||||||
"AdvancedArgs": True,
|
"AdvancedArgs": True,
|
||||||
"ArgsReminder": "请输入要翻译成哪种语言,默认为Chinese。",
|
"ArgsReminder": "请输入要翻译成哪种语言,默认为Chinese。",
|
||||||
"Function": HotReload(Markdown翻译指定语言)
|
"Function": HotReload(Markdown翻译指定语言),
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
)
|
||||||
except:
|
except:
|
||||||
print(trimmed_format_exc())
|
logger.error(trimmed_format_exc())
|
||||||
print('Load function plugin failed')
|
logger.error("Load function plugin failed")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from crazy_functions.知识库问答 import 知识库文件注入
|
from crazy_functions.知识库问答 import 知识库文件注入
|
||||||
function_plugins.update({
|
|
||||||
|
function_plugins.update(
|
||||||
|
{
|
||||||
"构建知识库(先上传文件素材,再运行此插件)": {
|
"构建知识库(先上传文件素材,再运行此插件)": {
|
||||||
"Group": "对话",
|
"Group": "对话",
|
||||||
"Color": "stop",
|
"Color": "stop",
|
||||||
"AsButton": False,
|
"AsButton": False,
|
||||||
"AdvancedArgs": True,
|
"AdvancedArgs": True,
|
||||||
"ArgsReminder": "此处待注入的知识库名称id, 默认为default。文件进入知识库后可长期保存。可以通过再次调用本插件的方式,向知识库追加更多文档。",
|
"ArgsReminder": "此处待注入的知识库名称id, 默认为default。文件进入知识库后可长期保存。可以通过再次调用本插件的方式,向知识库追加更多文档。",
|
||||||
"Function": HotReload(知识库文件注入)
|
"Function": HotReload(知识库文件注入),
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
)
|
||||||
except:
|
except:
|
||||||
print(trimmed_format_exc())
|
logger.error(trimmed_format_exc())
|
||||||
print('Load function plugin failed')
|
logger.error("Load function plugin failed")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from crazy_functions.知识库问答 import 读取知识库作答
|
from crazy_functions.知识库问答 import 读取知识库作答
|
||||||
function_plugins.update({
|
|
||||||
|
function_plugins.update(
|
||||||
|
{
|
||||||
"知识库文件注入(构建知识库后,再运行此插件)": {
|
"知识库文件注入(构建知识库后,再运行此插件)": {
|
||||||
"Group": "对话",
|
"Group": "对话",
|
||||||
"Color": "stop",
|
"Color": "stop",
|
||||||
"AsButton": False,
|
"AsButton": False,
|
||||||
"AdvancedArgs": True,
|
"AdvancedArgs": True,
|
||||||
"ArgsReminder": "待提取的知识库名称id, 默认为default, 您需要构建知识库后再运行此插件。",
|
"ArgsReminder": "待提取的知识库名称id, 默认为default, 您需要构建知识库后再运行此插件。",
|
||||||
"Function": HotReload(读取知识库作答)
|
"Function": HotReload(读取知识库作答),
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
)
|
||||||
except:
|
except:
|
||||||
print(trimmed_format_exc())
|
logger.error(trimmed_format_exc())
|
||||||
print('Load function plugin failed')
|
logger.error("Load function plugin failed")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from crazy_functions.交互功能函数模板 import 交互功能模板函数
|
from crazy_functions.交互功能函数模板 import 交互功能模板函数
|
||||||
function_plugins.update({
|
|
||||||
|
function_plugins.update(
|
||||||
|
{
|
||||||
"交互功能模板Demo函数(查找wallhaven.cc的壁纸)": {
|
"交互功能模板Demo函数(查找wallhaven.cc的壁纸)": {
|
||||||
"Group": "对话",
|
"Group": "对话",
|
||||||
"Color": "stop",
|
"Color": "stop",
|
||||||
"AsButton": False,
|
"AsButton": False,
|
||||||
"Function": HotReload(交互功能模板函数)
|
"Function": HotReload(交互功能模板函数),
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
)
|
||||||
except:
|
except:
|
||||||
print(trimmed_format_exc())
|
logger.error(trimmed_format_exc())
|
||||||
print('Load function plugin failed')
|
logger.error("Load function plugin failed")
|
||||||
|
|
||||||
try:
|
|
||||||
from crazy_functions.Latex输出PDF结果 import Latex英文纠错加PDF对比
|
|
||||||
function_plugins.update({
|
|
||||||
"Latex英文纠错+高亮修正位置 [需Latex]": {
|
|
||||||
"Group": "学术",
|
|
||||||
"Color": "stop",
|
|
||||||
"AsButton": False,
|
|
||||||
"AdvancedArgs": True,
|
|
||||||
"ArgsReminder": "如果有必要, 请在此处追加更细致的矫错指令(使用英文)。",
|
|
||||||
"Function": HotReload(Latex英文纠错加PDF对比)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
from crazy_functions.Latex输出PDF结果 import Latex翻译中文并重新编译PDF
|
|
||||||
function_plugins.update({
|
|
||||||
"Arxiv论文精细翻译(输入arxivID)[需Latex]": {
|
|
||||||
"Group": "学术",
|
|
||||||
"Color": "stop",
|
|
||||||
"AsButton": False,
|
|
||||||
"AdvancedArgs": True,
|
|
||||||
"ArgsReminder":
|
|
||||||
"如果有必要, 请在此处给出自定义翻译命令, 解决部分词汇翻译不准确的问题。 " +
|
|
||||||
"例如当单词'agent'翻译不准确时, 请尝试把以下指令复制到高级参数区: " +
|
|
||||||
'If the term "agent" is used in this section, it should be translated to "智能体". ',
|
|
||||||
"Info": "Arixv论文精细翻译 | 输入参数arxiv论文的ID,比如1812.10695",
|
|
||||||
"Function": HotReload(Latex翻译中文并重新编译PDF)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
function_plugins.update({
|
|
||||||
"本地Latex论文精细翻译(上传Latex项目)[需Latex]": {
|
|
||||||
"Group": "学术",
|
|
||||||
"Color": "stop",
|
|
||||||
"AsButton": False,
|
|
||||||
"AdvancedArgs": True,
|
|
||||||
"ArgsReminder":
|
|
||||||
"如果有必要, 请在此处给出自定义翻译命令, 解决部分词汇翻译不准确的问题。 " +
|
|
||||||
"例如当单词'agent'翻译不准确时, 请尝试把以下指令复制到高级参数区: " +
|
|
||||||
'If the term "agent" is used in this section, it should be translated to "智能体". ',
|
|
||||||
"Info": "本地Latex论文精细翻译 | 输入参数是路径",
|
|
||||||
"Function": HotReload(Latex翻译中文并重新编译PDF)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
except:
|
|
||||||
print(trimmed_format_exc())
|
|
||||||
print('Load function plugin failed')
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from toolbox import get_conf
|
from toolbox import get_conf
|
||||||
ENABLE_AUDIO = get_conf('ENABLE_AUDIO')
|
|
||||||
|
ENABLE_AUDIO = get_conf("ENABLE_AUDIO")
|
||||||
if ENABLE_AUDIO:
|
if ENABLE_AUDIO:
|
||||||
from crazy_functions.语音助手 import 语音助手
|
from crazy_functions.语音助手 import 语音助手
|
||||||
function_plugins.update({
|
|
||||||
|
function_plugins.update(
|
||||||
|
{
|
||||||
"实时语音对话": {
|
"实时语音对话": {
|
||||||
"Group": "对话",
|
"Group": "对话",
|
||||||
"Color": "stop",
|
"Color": "stop",
|
||||||
"AsButton": True,
|
"AsButton": True,
|
||||||
"Info": "这是一个时刻聆听着的语音对话助手 | 没有输入参数",
|
"Info": "这是一个时刻聆听着的语音对话助手 | 没有输入参数",
|
||||||
"Function": HotReload(语音助手)
|
"Function": HotReload(语音助手),
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
)
|
||||||
except:
|
except:
|
||||||
print(trimmed_format_exc())
|
logger.error(trimmed_format_exc())
|
||||||
print('Load function plugin failed')
|
logger.error("Load function plugin failed")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from crazy_functions.批量翻译PDF文档_NOUGAT import 批量翻译PDF文档
|
from crazy_functions.批量翻译PDF文档_NOUGAT import 批量翻译PDF文档
|
||||||
function_plugins.update({
|
|
||||||
|
function_plugins.update(
|
||||||
|
{
|
||||||
"精准翻译PDF文档(NOUGAT)": {
|
"精准翻译PDF文档(NOUGAT)": {
|
||||||
"Group": "学术",
|
"Group": "学术",
|
||||||
"Color": "stop",
|
"Color": "stop",
|
||||||
"AsButton": False,
|
"AsButton": False,
|
||||||
"Function": HotReload(批量翻译PDF文档)
|
"Function": HotReload(批量翻译PDF文档),
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
)
|
||||||
except:
|
except:
|
||||||
print(trimmed_format_exc())
|
logger.error(trimmed_format_exc())
|
||||||
print('Load function plugin failed')
|
logger.error("Load function plugin failed")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from crazy_functions.函数动态生成 import 函数动态生成
|
from crazy_functions.函数动态生成 import 函数动态生成
|
||||||
function_plugins.update({
|
|
||||||
|
function_plugins.update(
|
||||||
|
{
|
||||||
"动态代码解释器(CodeInterpreter)": {
|
"动态代码解释器(CodeInterpreter)": {
|
||||||
"Group": "智能体",
|
"Group": "智能体",
|
||||||
"Color": "stop",
|
"Color": "stop",
|
||||||
"AsButton": False,
|
"AsButton": False,
|
||||||
"Function": HotReload(函数动态生成)
|
"Function": HotReload(函数动态生成),
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
)
|
||||||
except:
|
except:
|
||||||
print(trimmed_format_exc())
|
logger.error(trimmed_format_exc())
|
||||||
print('Load function plugin failed')
|
logger.error("Load function plugin failed")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from crazy_functions.多智能体 import 多智能体终端
|
from crazy_functions.多智能体 import 多智能体终端
|
||||||
function_plugins.update({
|
|
||||||
|
function_plugins.update(
|
||||||
|
{
|
||||||
"AutoGen多智能体终端(仅供测试)": {
|
"AutoGen多智能体终端(仅供测试)": {
|
||||||
"Group": "智能体",
|
"Group": "智能体",
|
||||||
"Color": "stop",
|
"Color": "stop",
|
||||||
"AsButton": False,
|
"AsButton": False,
|
||||||
"Function": HotReload(多智能体终端)
|
"Function": HotReload(多智能体终端),
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
)
|
||||||
except:
|
except:
|
||||||
print(trimmed_format_exc())
|
logger.error(trimmed_format_exc())
|
||||||
print('Load function plugin failed')
|
logger.error("Load function plugin failed")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from crazy_functions.互动小游戏 import 随机小游戏
|
from crazy_functions.互动小游戏 import 随机小游戏
|
||||||
function_plugins.update({
|
|
||||||
|
function_plugins.update(
|
||||||
|
{
|
||||||
"随机互动小游戏(仅供测试)": {
|
"随机互动小游戏(仅供测试)": {
|
||||||
"Group": "智能体",
|
"Group": "智能体",
|
||||||
"Color": "stop",
|
"Color": "stop",
|
||||||
"AsButton": False,
|
"AsButton": False,
|
||||||
"Function": HotReload(随机小游戏)
|
"Function": HotReload(随机小游戏),
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
)
|
||||||
except:
|
except:
|
||||||
print(trimmed_format_exc())
|
logger.error(trimmed_format_exc())
|
||||||
print('Load function plugin failed')
|
logger.error("Load function plugin failed")
|
||||||
|
|
||||||
|
try:
|
||||||
|
from crazy_functions.Rag_Interface import Rag问答
|
||||||
|
|
||||||
|
function_plugins.update(
|
||||||
|
{
|
||||||
|
"Rag智能召回": {
|
||||||
|
"Group": "对话",
|
||||||
|
"Color": "stop",
|
||||||
|
"AsButton": False,
|
||||||
|
"Info": "将问答数据记录到向量库中,作为长期参考。",
|
||||||
|
"Function": HotReload(Rag问答),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
except:
|
||||||
|
logger.error(trimmed_format_exc())
|
||||||
|
logger.error("Load function plugin failed")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# try:
|
||||||
|
# from crazy_functions.高级功能函数模板 import 测试图表渲染
|
||||||
|
# function_plugins.update({
|
||||||
|
# "绘制逻辑关系(测试图表渲染)": {
|
||||||
|
# "Group": "智能体",
|
||||||
|
# "Color": "stop",
|
||||||
|
# "AsButton": True,
|
||||||
|
# "Function": HotReload(测试图表渲染)
|
||||||
|
# }
|
||||||
|
# })
|
||||||
|
# except:
|
||||||
|
# logger.error(trimmed_format_exc())
|
||||||
|
# print('Load function plugin failed')
|
||||||
|
|
||||||
# try:
|
# try:
|
||||||
# from crazy_functions.chatglm微调工具 import 微调数据集生成
|
# from crazy_functions.chatglm微调工具 import 微调数据集生成
|
||||||
@@ -618,8 +755,6 @@ def get_crazy_functions():
|
|||||||
# except:
|
# except:
|
||||||
# print('Load function plugin failed')
|
# print('Load function plugin failed')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
设置默认值:
|
设置默认值:
|
||||||
- 默认 Group = 对话
|
- 默认 Group = 对话
|
||||||
@@ -629,12 +764,12 @@ def get_crazy_functions():
|
|||||||
"""
|
"""
|
||||||
for name, function_meta in function_plugins.items():
|
for name, function_meta in function_plugins.items():
|
||||||
if "Group" not in function_meta:
|
if "Group" not in function_meta:
|
||||||
function_plugins[name]["Group"] = '对话'
|
function_plugins[name]["Group"] = "对话"
|
||||||
if "AsButton" not in function_meta:
|
if "AsButton" not in function_meta:
|
||||||
function_plugins[name]["AsButton"] = True
|
function_plugins[name]["AsButton"] = True
|
||||||
if "AdvancedArgs" not in function_meta:
|
if "AdvancedArgs" not in function_meta:
|
||||||
function_plugins[name]["AdvancedArgs"] = False
|
function_plugins[name]["AdvancedArgs"] = False
|
||||||
if "Color" not in function_meta:
|
if "Color" not in function_meta:
|
||||||
function_plugins[name]["Color"] = 'secondary'
|
function_plugins[name]["Color"] = "secondary"
|
||||||
|
|
||||||
return function_plugins
|
return function_plugins
|
||||||
|
|||||||
@@ -1,232 +0,0 @@
|
|||||||
from collections.abc import Callable, Iterable, Mapping
|
|
||||||
from typing import Any
|
|
||||||
from toolbox import CatchException, update_ui, gen_time_str, trimmed_format_exc
|
|
||||||
from toolbox import promote_file_to_downloadzone, get_log_folder
|
|
||||||
from .crazy_utils import request_gpt_model_in_new_thread_with_ui_alive
|
|
||||||
from .crazy_utils import input_clipping, try_install_deps
|
|
||||||
from multiprocessing import Process, Pipe
|
|
||||||
import os
|
|
||||||
import time
|
|
||||||
|
|
||||||
templete = """
|
|
||||||
```python
|
|
||||||
import ... # Put dependencies here, e.g. import numpy as np
|
|
||||||
|
|
||||||
class TerminalFunction(object): # Do not change the name of the class, The name of the class must be `TerminalFunction`
|
|
||||||
|
|
||||||
def run(self, path): # The name of the function must be `run`, it takes only a positional argument.
|
|
||||||
# rewrite the function you have just written here
|
|
||||||
...
|
|
||||||
return generated_file_path
|
|
||||||
```
|
|
||||||
"""
|
|
||||||
|
|
||||||
def inspect_dependency(chatbot, history):
|
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
|
||||||
return True
|
|
||||||
|
|
||||||
def get_code_block(reply):
|
|
||||||
import re
|
|
||||||
pattern = r"```([\s\S]*?)```" # regex pattern to match code blocks
|
|
||||||
matches = re.findall(pattern, reply) # find all code blocks in text
|
|
||||||
if len(matches) == 1:
|
|
||||||
return matches[0].strip('python') # code block
|
|
||||||
for match in matches:
|
|
||||||
if 'class TerminalFunction' in match:
|
|
||||||
return match.strip('python') # code block
|
|
||||||
raise RuntimeError("GPT is not generating proper code.")
|
|
||||||
|
|
||||||
def gpt_interact_multi_step(txt, file_type, llm_kwargs, chatbot, history):
|
|
||||||
# 输入
|
|
||||||
prompt_compose = [
|
|
||||||
f'Your job:\n'
|
|
||||||
f'1. write a single Python function, which takes a path of a `{file_type}` file as the only argument and returns a `string` containing the result of analysis or the path of generated files. \n',
|
|
||||||
f"2. You should write this function to perform following task: " + txt + "\n",
|
|
||||||
f"3. Wrap the output python function with markdown codeblock."
|
|
||||||
]
|
|
||||||
i_say = "".join(prompt_compose)
|
|
||||||
demo = []
|
|
||||||
|
|
||||||
# 第一步
|
|
||||||
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=demo,
|
|
||||||
sys_prompt= r"You are a programmer."
|
|
||||||
)
|
|
||||||
history.extend([i_say, gpt_say])
|
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 # 界面更新
|
|
||||||
|
|
||||||
# 第二步
|
|
||||||
prompt_compose = [
|
|
||||||
"If previous stage is successful, rewrite the function you have just written to satisfy following templete: \n",
|
|
||||||
templete
|
|
||||||
]
|
|
||||||
i_say = "".join(prompt_compose); inputs_show_user = "If previous stage is successful, rewrite the function you have just written to satisfy executable templete. "
|
|
||||||
gpt_say = yield from request_gpt_model_in_new_thread_with_ui_alive(
|
|
||||||
inputs=i_say, inputs_show_user=inputs_show_user,
|
|
||||||
llm_kwargs=llm_kwargs, chatbot=chatbot, history=history,
|
|
||||||
sys_prompt= r"You are a programmer."
|
|
||||||
)
|
|
||||||
code_to_return = gpt_say
|
|
||||||
history.extend([i_say, gpt_say])
|
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 # 界面更新
|
|
||||||
|
|
||||||
# # 第三步
|
|
||||||
# i_say = "Please list to packages to install to run the code above. Then show me how to use `try_install_deps` function to install them."
|
|
||||||
# i_say += 'For instance. `try_install_deps(["opencv-python", "scipy", "numpy"])`'
|
|
||||||
# installation_advance = yield from request_gpt_model_in_new_thread_with_ui_alive(
|
|
||||||
# inputs=i_say, inputs_show_user=inputs_show_user,
|
|
||||||
# llm_kwargs=llm_kwargs, chatbot=chatbot, history=history,
|
|
||||||
# sys_prompt= r"You are a programmer."
|
|
||||||
# )
|
|
||||||
# # # 第三步
|
|
||||||
# i_say = "Show me how to use `pip` to install packages to run the code above. "
|
|
||||||
# i_say += 'For instance. `pip install -r opencv-python scipy numpy`'
|
|
||||||
# installation_advance = yield from request_gpt_model_in_new_thread_with_ui_alive(
|
|
||||||
# inputs=i_say, inputs_show_user=i_say,
|
|
||||||
# llm_kwargs=llm_kwargs, chatbot=chatbot, history=history,
|
|
||||||
# sys_prompt= r"You are a programmer."
|
|
||||||
# )
|
|
||||||
installation_advance = ""
|
|
||||||
|
|
||||||
return code_to_return, installation_advance, txt, file_type, llm_kwargs, chatbot, history
|
|
||||||
|
|
||||||
def make_module(code):
|
|
||||||
module_file = 'gpt_fn_' + gen_time_str().replace('-','_')
|
|
||||||
with open(f'{get_log_folder()}/{module_file}.py', 'w', encoding='utf8') as f:
|
|
||||||
f.write(code)
|
|
||||||
|
|
||||||
def get_class_name(class_string):
|
|
||||||
import re
|
|
||||||
# Use regex to extract the class name
|
|
||||||
class_name = re.search(r'class (\w+)\(', class_string).group(1)
|
|
||||||
return class_name
|
|
||||||
|
|
||||||
class_name = get_class_name(code)
|
|
||||||
return f"{get_log_folder().replace('/', '.')}.{module_file}->{class_name}"
|
|
||||||
|
|
||||||
def init_module_instance(module):
|
|
||||||
import importlib
|
|
||||||
module_, class_ = module.split('->')
|
|
||||||
init_f = getattr(importlib.import_module(module_), class_)
|
|
||||||
return init_f()
|
|
||||||
|
|
||||||
def for_immediate_show_off_when_possible(file_type, fp, chatbot):
|
|
||||||
if file_type in ['png', 'jpg']:
|
|
||||||
image_path = os.path.abspath(fp)
|
|
||||||
chatbot.append(['这是一张图片, 展示如下:',
|
|
||||||
f'本地文件地址: <br/>`{image_path}`<br/>'+
|
|
||||||
f'本地文件预览: <br/><div align="center"><img src="file={image_path}"></div>'
|
|
||||||
])
|
|
||||||
return chatbot
|
|
||||||
|
|
||||||
def subprocess_worker(instance, file_path, return_dict):
|
|
||||||
return_dict['result'] = instance.run(file_path)
|
|
||||||
|
|
||||||
def have_any_recent_upload_files(chatbot):
|
|
||||||
_5min = 5 * 60
|
|
||||||
if not chatbot: return False # chatbot is None
|
|
||||||
most_recent_uploaded = chatbot._cookies.get("most_recent_uploaded", None)
|
|
||||||
if not most_recent_uploaded: return False # most_recent_uploaded is None
|
|
||||||
if time.time() - most_recent_uploaded["time"] < _5min: return True # most_recent_uploaded is new
|
|
||||||
else: return False # most_recent_uploaded is too old
|
|
||||||
|
|
||||||
def get_recent_file_prompt_support(chatbot):
|
|
||||||
most_recent_uploaded = chatbot._cookies.get("most_recent_uploaded", None)
|
|
||||||
path = most_recent_uploaded['path']
|
|
||||||
return path
|
|
||||||
|
|
||||||
@CatchException
|
|
||||||
def 虚空终端CodeInterpreter(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 当前软件运行的端口号
|
|
||||||
"""
|
|
||||||
raise NotImplementedError
|
|
||||||
|
|
||||||
# 清空历史,以免输入溢出
|
|
||||||
history = []; clear_file_downloadzone(chatbot)
|
|
||||||
|
|
||||||
# 基本信息:功能、贡献者
|
|
||||||
chatbot.append([
|
|
||||||
"函数插件功能?",
|
|
||||||
"CodeInterpreter开源版, 此插件处于开发阶段, 建议暂时不要使用, 插件初始化中 ..."
|
|
||||||
])
|
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
|
||||||
|
|
||||||
if have_any_recent_upload_files(chatbot):
|
|
||||||
file_path = get_recent_file_prompt_support(chatbot)
|
|
||||||
else:
|
|
||||||
chatbot.append(["文件检索", "没有发现任何近期上传的文件。"])
|
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
|
||||||
|
|
||||||
# 读取文件
|
|
||||||
if ("recently_uploaded_files" in plugin_kwargs) and (plugin_kwargs["recently_uploaded_files"] == ""): plugin_kwargs.pop("recently_uploaded_files")
|
|
||||||
recently_uploaded_files = plugin_kwargs.get("recently_uploaded_files", None)
|
|
||||||
file_path = recently_uploaded_files[-1]
|
|
||||||
file_type = file_path.split('.')[-1]
|
|
||||||
|
|
||||||
# 粗心检查
|
|
||||||
if is_the_upload_folder(txt):
|
|
||||||
chatbot.append([
|
|
||||||
"...",
|
|
||||||
f"请在输入框内填写需求,然后再次点击该插件(文件路径 {file_path} 已经被记忆)"
|
|
||||||
])
|
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
|
||||||
return
|
|
||||||
|
|
||||||
# 开始干正事
|
|
||||||
for j in range(5): # 最多重试5次
|
|
||||||
try:
|
|
||||||
code, installation_advance, txt, file_type, llm_kwargs, chatbot, history = \
|
|
||||||
yield from gpt_interact_multi_step(txt, file_type, llm_kwargs, chatbot, history)
|
|
||||||
code = get_code_block(code)
|
|
||||||
res = make_module(code)
|
|
||||||
instance = init_module_instance(res)
|
|
||||||
break
|
|
||||||
except Exception as e:
|
|
||||||
chatbot.append([f"第{j}次代码生成尝试,失败了", f"错误追踪\n```\n{trimmed_format_exc()}\n```\n"])
|
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
|
||||||
|
|
||||||
# 代码生成结束, 开始执行
|
|
||||||
try:
|
|
||||||
import multiprocessing
|
|
||||||
manager = multiprocessing.Manager()
|
|
||||||
return_dict = manager.dict()
|
|
||||||
|
|
||||||
p = multiprocessing.Process(target=subprocess_worker, args=(instance, file_path, return_dict))
|
|
||||||
# only has 10 seconds to run
|
|
||||||
p.start(); p.join(timeout=10)
|
|
||||||
if p.is_alive(): p.terminate(); p.join()
|
|
||||||
p.close()
|
|
||||||
res = return_dict['result']
|
|
||||||
# res = instance.run(file_path)
|
|
||||||
except Exception as e:
|
|
||||||
chatbot.append(["执行失败了", f"错误追踪\n```\n{trimmed_format_exc()}\n```\n"])
|
|
||||||
# chatbot.append(["如果是缺乏依赖,请参考以下建议", installation_advance])
|
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
|
||||||
return
|
|
||||||
|
|
||||||
# 顺利完成,收尾
|
|
||||||
res = str(res)
|
|
||||||
if os.path.exists(res):
|
|
||||||
chatbot.append(["执行成功了,结果是一个有效文件", "结果:" + res])
|
|
||||||
new_file_path = promote_file_to_downloadzone(res, chatbot=chatbot)
|
|
||||||
chatbot = for_immediate_show_off_when_possible(file_type, new_file_path, chatbot)
|
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 # 界面更新
|
|
||||||
else:
|
|
||||||
chatbot.append(["执行成功了,结果是一个字符串", "结果:" + res])
|
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 # 界面更新
|
|
||||||
|
|
||||||
"""
|
|
||||||
测试:
|
|
||||||
裁剪图像,保留下半部分
|
|
||||||
交换图像的蓝色通道和红色通道
|
|
||||||
将图像转为灰度图像
|
|
||||||
将csv文件转excel表格
|
|
||||||
"""
|
|
||||||
@@ -0,0 +1,220 @@
|
|||||||
|
from toolbox import CatchException, update_ui, promote_file_to_downloadzone, get_log_folder, get_user
|
||||||
|
from crazy_functions.plugin_template.plugin_class_template import GptAcademicPluginTemplate, ArgProperty
|
||||||
|
import re
|
||||||
|
|
||||||
|
f_prefix = 'GPT-Academic对话存档'
|
||||||
|
|
||||||
|
def write_chat_to_file(chatbot, history=None, file_name=None):
|
||||||
|
"""
|
||||||
|
将对话记录history以Markdown格式写入文件中。如果没有指定文件名,则使用当前时间生成文件名。
|
||||||
|
"""
|
||||||
|
import os
|
||||||
|
import time
|
||||||
|
from themes.theme import advanced_css
|
||||||
|
|
||||||
|
if file_name is None:
|
||||||
|
file_name = f_prefix + time.strftime("%Y-%m-%d-%H-%M-%S", time.localtime()) + '.html'
|
||||||
|
fp = os.path.join(get_log_folder(get_user(chatbot), plugin_name='chat_history'), file_name)
|
||||||
|
|
||||||
|
with open(fp, 'w', encoding='utf8') as f:
|
||||||
|
from textwrap import dedent
|
||||||
|
form = dedent("""
|
||||||
|
<!DOCTYPE html><head><meta charset="utf-8"><title>对话存档</title><style>{CSS}</style></head>
|
||||||
|
<body>
|
||||||
|
<div class="test_temp1" style="width:10%; height: 500px; float:left;"></div>
|
||||||
|
<div class="test_temp2" style="width:80%;padding: 40px;float:left;padding-left: 20px;padding-right: 20px;box-shadow: rgba(0, 0, 0, 0.2) 0px 0px 8px 8px;border-radius: 10px;">
|
||||||
|
<div class="chat-body" style="display: flex;justify-content: center;flex-direction: column;align-items: center;flex-wrap: nowrap;">
|
||||||
|
{CHAT_PREVIEW}
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
<div style="text-align: center;width:80%;padding: 0px;float:left;padding-left:20px;padding-right:20px;box-shadow: rgba(0, 0, 0, 0.05) 0px 0px 1px 2px;border-radius: 1px;">对话(原始数据)</div>
|
||||||
|
{HISTORY_PREVIEW}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="test_temp3" style="width:10%; height: 500px; float:left;"></div>
|
||||||
|
</body>
|
||||||
|
""")
|
||||||
|
|
||||||
|
qa_from = dedent("""
|
||||||
|
<div class="QaBox" style="width:80%;padding: 20px;margin-bottom: 20px;box-shadow: rgb(0 255 159 / 50%) 0px 0px 1px 2px;border-radius: 4px;">
|
||||||
|
<div class="Question" style="border-radius: 2px;">{QUESTION}</div>
|
||||||
|
<hr color="blue" style="border-top: dotted 2px #ccc;">
|
||||||
|
<div class="Answer" style="border-radius: 2px;">{ANSWER}</div>
|
||||||
|
</div>
|
||||||
|
""")
|
||||||
|
|
||||||
|
history_from = dedent("""
|
||||||
|
<div class="historyBox" style="width:80%;padding: 0px;float:left;padding-left:20px;padding-right:20px;box-shadow: rgba(0, 0, 0, 0.05) 0px 0px 1px 2px;border-radius: 1px;">
|
||||||
|
<div class="entry" style="border-radius: 2px;">{ENTRY}</div>
|
||||||
|
</div>
|
||||||
|
""")
|
||||||
|
CHAT_PREVIEW_BUF = ""
|
||||||
|
for i, contents in enumerate(chatbot):
|
||||||
|
question, answer = contents[0], contents[1]
|
||||||
|
if question is None: question = ""
|
||||||
|
try: question = str(question)
|
||||||
|
except: question = ""
|
||||||
|
if answer is None: answer = ""
|
||||||
|
try: answer = str(answer)
|
||||||
|
except: answer = ""
|
||||||
|
CHAT_PREVIEW_BUF += qa_from.format(QUESTION=question, ANSWER=answer)
|
||||||
|
|
||||||
|
HISTORY_PREVIEW_BUF = ""
|
||||||
|
for h in history:
|
||||||
|
HISTORY_PREVIEW_BUF += history_from.format(ENTRY=h)
|
||||||
|
html_content = form.format(CHAT_PREVIEW=CHAT_PREVIEW_BUF, HISTORY_PREVIEW=HISTORY_PREVIEW_BUF, CSS=advanced_css)
|
||||||
|
f.write(html_content)
|
||||||
|
|
||||||
|
promote_file_to_downloadzone(fp, rename_file=file_name, chatbot=chatbot)
|
||||||
|
return '对话历史写入:' + fp
|
||||||
|
|
||||||
|
def gen_file_preview(file_name):
|
||||||
|
try:
|
||||||
|
with open(file_name, 'r', encoding='utf8') as f:
|
||||||
|
file_content = f.read()
|
||||||
|
# pattern to match the text between <head> and </head>
|
||||||
|
pattern = re.compile(r'<head>.*?</head>', flags=re.DOTALL)
|
||||||
|
file_content = re.sub(pattern, '', file_content)
|
||||||
|
html, history = file_content.split('<hr color="blue"> \n\n 对话数据 (无渲染):\n')
|
||||||
|
history = history.strip('<code>')
|
||||||
|
history = history.strip('</code>')
|
||||||
|
history = history.split("\n>>>")
|
||||||
|
return list(filter(lambda x:x!="", history))[0][:100]
|
||||||
|
except:
|
||||||
|
return ""
|
||||||
|
|
||||||
|
def read_file_to_chat(chatbot, history, file_name):
|
||||||
|
with open(file_name, 'r', encoding='utf8') as f:
|
||||||
|
file_content = f.read()
|
||||||
|
from bs4 import BeautifulSoup
|
||||||
|
soup = BeautifulSoup(file_content, 'lxml')
|
||||||
|
# 提取QaBox信息
|
||||||
|
chatbot.clear()
|
||||||
|
qa_box_list = []
|
||||||
|
qa_boxes = soup.find_all("div", class_="QaBox")
|
||||||
|
for box in qa_boxes:
|
||||||
|
question = box.find("div", class_="Question").get_text(strip=False)
|
||||||
|
answer = box.find("div", class_="Answer").get_text(strip=False)
|
||||||
|
qa_box_list.append({"Question": question, "Answer": answer})
|
||||||
|
chatbot.append([question, answer])
|
||||||
|
# 提取historyBox信息
|
||||||
|
history_box_list = []
|
||||||
|
history_boxes = soup.find_all("div", class_="historyBox")
|
||||||
|
for box in history_boxes:
|
||||||
|
entry = box.find("div", class_="entry").get_text(strip=False)
|
||||||
|
history_box_list.append(entry)
|
||||||
|
history = history_box_list
|
||||||
|
chatbot.append([None, f"[Local Message] 载入对话{len(qa_box_list)}条,上下文{len(history)}条。"])
|
||||||
|
return chatbot, history
|
||||||
|
|
||||||
|
@CatchException
|
||||||
|
def 对话历史存档(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request):
|
||||||
|
"""
|
||||||
|
txt 输入栏用户输入的文本,例如需要翻译的一段话,再例如一个包含了待处理文件的路径
|
||||||
|
llm_kwargs gpt模型参数,如温度和top_p等,一般原样传递下去就行
|
||||||
|
plugin_kwargs 插件模型的参数,暂时没有用武之地
|
||||||
|
chatbot 聊天显示框的句柄,用于显示给用户
|
||||||
|
history 聊天历史,前情提要
|
||||||
|
system_prompt 给gpt的静默提醒
|
||||||
|
user_request 当前用户的请求信息(IP地址等)
|
||||||
|
"""
|
||||||
|
file_name = plugin_kwargs.get("file_name", None)
|
||||||
|
if (file_name is not None) and (file_name != "") and (not file_name.endswith('.html')): file_name += '.html'
|
||||||
|
else: file_name = None
|
||||||
|
|
||||||
|
chatbot.append((None, f"[Local Message] {write_chat_to_file(chatbot, history, file_name)},您可以调用下拉菜单中的“载入对话历史存档”还原当下的对话。"))
|
||||||
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 # 由于请求gpt需要一段时间,我们先及时地做一次界面更新
|
||||||
|
|
||||||
|
|
||||||
|
class Conversation_To_File_Wrap(GptAcademicPluginTemplate):
|
||||||
|
def __init__(self):
|
||||||
|
"""
|
||||||
|
请注意`execute`会执行在不同的线程中,因此您在定义和使用类变量时,应当慎之又慎!
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
def define_arg_selection_menu(self):
|
||||||
|
"""
|
||||||
|
定义插件的二级选项菜单
|
||||||
|
|
||||||
|
第一个参数,名称`file_name`,参数`type`声明这是一个文本框,文本框上方显示`title`,文本框内部显示`description`,`default_value`为默认值;
|
||||||
|
"""
|
||||||
|
gui_definition = {
|
||||||
|
"file_name": ArgProperty(title="保存文件名", description="输入对话存档文件名,留空则使用时间作为文件名", default_value="", type="string").model_dump_json(), # 主输入,自动从输入框同步
|
||||||
|
}
|
||||||
|
return gui_definition
|
||||||
|
|
||||||
|
def execute(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request):
|
||||||
|
"""
|
||||||
|
执行插件
|
||||||
|
"""
|
||||||
|
yield from 对话历史存档(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def hide_cwd(str):
|
||||||
|
import os
|
||||||
|
current_path = os.getcwd()
|
||||||
|
replace_path = "."
|
||||||
|
return str.replace(current_path, replace_path)
|
||||||
|
|
||||||
|
@CatchException
|
||||||
|
def 载入对话历史存档(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request):
|
||||||
|
"""
|
||||||
|
txt 输入栏用户输入的文本,例如需要翻译的一段话,再例如一个包含了待处理文件的路径
|
||||||
|
llm_kwargs gpt模型参数,如温度和top_p等,一般原样传递下去就行
|
||||||
|
plugin_kwargs 插件模型的参数,暂时没有用武之地
|
||||||
|
chatbot 聊天显示框的句柄,用于显示给用户
|
||||||
|
history 聊天历史,前情提要
|
||||||
|
system_prompt 给gpt的静默提醒
|
||||||
|
user_request 当前用户的请求信息(IP地址等)
|
||||||
|
"""
|
||||||
|
from crazy_functions.crazy_utils import get_files_from_everything
|
||||||
|
success, file_manifest, _ = get_files_from_everything(txt, type='.html')
|
||||||
|
|
||||||
|
if not success:
|
||||||
|
if txt == "": txt = '空空如也的输入栏'
|
||||||
|
import glob
|
||||||
|
local_history = "<br/>".join([
|
||||||
|
"`"+hide_cwd(f)+f" ({gen_file_preview(f)})"+"`"
|
||||||
|
for f in glob.glob(
|
||||||
|
f'{get_log_folder(get_user(chatbot), plugin_name="chat_history")}/**/{f_prefix}*.html',
|
||||||
|
recursive=True
|
||||||
|
)])
|
||||||
|
chatbot.append([f"正在查找对话历史文件(html格式): {txt}", f"找不到任何html文件: {txt}。但本地存储了以下历史文件,您可以将任意一个文件路径粘贴到输入区,然后重试:<br/>{local_history}"])
|
||||||
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
chatbot, history = read_file_to_chat(chatbot, history, file_manifest[0])
|
||||||
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
||||||
|
except:
|
||||||
|
chatbot.append([f"载入对话历史文件", f"对话历史文件损坏!"])
|
||||||
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
||||||
|
return
|
||||||
|
|
||||||
|
@CatchException
|
||||||
|
def 删除所有本地对话历史记录(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request):
|
||||||
|
"""
|
||||||
|
txt 输入栏用户输入的文本,例如需要翻译的一段话,再例如一个包含了待处理文件的路径
|
||||||
|
llm_kwargs gpt模型参数,如温度和top_p等,一般原样传递下去就行
|
||||||
|
plugin_kwargs 插件模型的参数,暂时没有用武之地
|
||||||
|
chatbot 聊天显示框的句柄,用于显示给用户
|
||||||
|
history 聊天历史,前情提要
|
||||||
|
system_prompt 给gpt的静默提醒
|
||||||
|
user_request 当前用户的请求信息(IP地址等)
|
||||||
|
"""
|
||||||
|
|
||||||
|
import glob, os
|
||||||
|
local_history = "<br/>".join([
|
||||||
|
"`"+hide_cwd(f)+"`"
|
||||||
|
for f in glob.glob(
|
||||||
|
f'{get_log_folder(get_user(chatbot), plugin_name="chat_history")}/**/{f_prefix}*.html', recursive=True
|
||||||
|
)])
|
||||||
|
for f in glob.glob(f'{get_log_folder(get_user(chatbot), plugin_name="chat_history")}/**/{f_prefix}*.html', recursive=True):
|
||||||
|
os.remove(f)
|
||||||
|
chatbot.append([f"删除所有历史对话文件", f"已删除<br/>{local_history}"])
|
||||||
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
||||||
|
return
|
||||||
@@ -30,7 +30,7 @@ def gen_image(llm_kwargs, prompt, resolution="1024x1024", model="dall-e-2", qual
|
|||||||
if style is not None:
|
if style is not None:
|
||||||
data['style'] = style
|
data['style'] = style
|
||||||
response = requests.post(url, headers=headers, json=data, proxies=proxies)
|
response = requests.post(url, headers=headers, json=data, proxies=proxies)
|
||||||
print(response.content)
|
# logger.info(response.content)
|
||||||
try:
|
try:
|
||||||
image_url = json.loads(response.content.decode('utf8'))['data'][0]['url']
|
image_url = json.loads(response.content.decode('utf8'))['data'][0]['url']
|
||||||
except:
|
except:
|
||||||
@@ -76,7 +76,7 @@ def edit_image(llm_kwargs, prompt, image_path, resolution="1024x1024", model="da
|
|||||||
}
|
}
|
||||||
|
|
||||||
response = requests.post(url, headers=headers, files=files, proxies=proxies)
|
response = requests.post(url, headers=headers, files=files, proxies=proxies)
|
||||||
print(response.content)
|
# logger.info(response.content)
|
||||||
try:
|
try:
|
||||||
image_url = json.loads(response.content.decode('utf8'))['data'][0]['url']
|
image_url = json.loads(response.content.decode('utf8'))['data'][0]['url']
|
||||||
except:
|
except:
|
||||||
@@ -93,7 +93,7 @@ def edit_image(llm_kwargs, prompt, image_path, resolution="1024x1024", model="da
|
|||||||
|
|
||||||
|
|
||||||
@CatchException
|
@CatchException
|
||||||
def 图片生成_DALLE2(prompt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port):
|
def 图片生成_DALLE2(prompt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request):
|
||||||
"""
|
"""
|
||||||
txt 输入栏用户输入的文本,例如需要翻译的一段话,再例如一个包含了待处理文件的路径
|
txt 输入栏用户输入的文本,例如需要翻译的一段话,再例如一个包含了待处理文件的路径
|
||||||
llm_kwargs gpt模型参数,如温度和top_p等,一般原样传递下去就行
|
llm_kwargs gpt模型参数,如温度和top_p等,一般原样传递下去就行
|
||||||
@@ -101,14 +101,14 @@ def 图片生成_DALLE2(prompt, llm_kwargs, plugin_kwargs, chatbot, history, sys
|
|||||||
chatbot 聊天显示框的句柄,用于显示给用户
|
chatbot 聊天显示框的句柄,用于显示给用户
|
||||||
history 聊天历史,前情提要
|
history 聊天历史,前情提要
|
||||||
system_prompt 给gpt的静默提醒
|
system_prompt 给gpt的静默提醒
|
||||||
web_port 当前软件运行的端口号
|
user_request 当前用户的请求信息(IP地址等)
|
||||||
"""
|
"""
|
||||||
history = [] # 清空历史,以免输入溢出
|
history = [] # 清空历史,以免输入溢出
|
||||||
if prompt.strip() == "":
|
if prompt.strip() == "":
|
||||||
chatbot.append((prompt, "[Local Message] 图像生成提示为空白,请在“输入区”输入图像生成提示。"))
|
chatbot.append((prompt, "[Local Message] 图像生成提示为空白,请在“输入区”输入图像生成提示。"))
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 界面更新
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 界面更新
|
||||||
return
|
return
|
||||||
chatbot.append(("您正在调用“图像生成”插件。", "[Local Message] 生成图像, 请先把模型切换至gpt-*。如果中文Prompt效果不理想, 请尝试英文Prompt。正在处理中 ....."))
|
chatbot.append(("您正在调用“图像生成”插件。", "[Local Message] 生成图像, 使用前请切换模型到GPT系列。如果中文Prompt效果不理想, 请尝试英文Prompt。正在处理中 ....."))
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 由于请求gpt需要一段时间,我们先及时地做一次界面更新
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 由于请求gpt需要一段时间,我们先及时地做一次界面更新
|
||||||
if ("advanced_arg" in plugin_kwargs) and (plugin_kwargs["advanced_arg"] == ""): plugin_kwargs.pop("advanced_arg")
|
if ("advanced_arg" in plugin_kwargs) and (plugin_kwargs["advanced_arg"] == ""): plugin_kwargs.pop("advanced_arg")
|
||||||
resolution = plugin_kwargs.get("advanced_arg", '1024x1024')
|
resolution = plugin_kwargs.get("advanced_arg", '1024x1024')
|
||||||
@@ -123,13 +123,13 @@ def 图片生成_DALLE2(prompt, llm_kwargs, plugin_kwargs, chatbot, history, sys
|
|||||||
|
|
||||||
|
|
||||||
@CatchException
|
@CatchException
|
||||||
def 图片生成_DALLE3(prompt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port):
|
def 图片生成_DALLE3(prompt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request):
|
||||||
history = [] # 清空历史,以免输入溢出
|
history = [] # 清空历史,以免输入溢出
|
||||||
if prompt.strip() == "":
|
if prompt.strip() == "":
|
||||||
chatbot.append((prompt, "[Local Message] 图像生成提示为空白,请在“输入区”输入图像生成提示。"))
|
chatbot.append((prompt, "[Local Message] 图像生成提示为空白,请在“输入区”输入图像生成提示。"))
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 界面更新
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 界面更新
|
||||||
return
|
return
|
||||||
chatbot.append(("您正在调用“图像生成”插件。", "[Local Message] 生成图像, 请先把模型切换至gpt-*。如果中文Prompt效果不理想, 请尝试英文Prompt。正在处理中 ....."))
|
chatbot.append(("您正在调用“图像生成”插件。", "[Local Message] 生成图像, 使用前请切换模型到GPT系列。如果中文Prompt效果不理想, 请尝试英文Prompt。正在处理中 ....."))
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 由于请求gpt需要一段时间,我们先及时地做一次界面更新
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 由于请求gpt需要一段时间,我们先及时地做一次界面更新
|
||||||
if ("advanced_arg" in plugin_kwargs) and (plugin_kwargs["advanced_arg"] == ""): plugin_kwargs.pop("advanced_arg")
|
if ("advanced_arg" in plugin_kwargs) and (plugin_kwargs["advanced_arg"] == ""): plugin_kwargs.pop("advanced_arg")
|
||||||
resolution_arg = plugin_kwargs.get("advanced_arg", '1024x1024-standard-vivid').lower()
|
resolution_arg = plugin_kwargs.get("advanced_arg", '1024x1024-standard-vivid').lower()
|
||||||
@@ -166,7 +166,7 @@ class ImageEditState(GptAcademicState):
|
|||||||
return confirm, file
|
return confirm, file
|
||||||
|
|
||||||
def lock_plugin(self, chatbot):
|
def lock_plugin(self, chatbot):
|
||||||
chatbot._cookies['lock_plugin'] = 'crazy_functions.图片生成->图片修改_DALLE2'
|
chatbot._cookies['lock_plugin'] = 'crazy_functions.Image_Generate->图片修改_DALLE2'
|
||||||
self.dump_state(chatbot)
|
self.dump_state(chatbot)
|
||||||
|
|
||||||
def unlock_plugin(self, chatbot):
|
def unlock_plugin(self, chatbot):
|
||||||
@@ -209,7 +209,7 @@ class ImageEditState(GptAcademicState):
|
|||||||
return all([x['value'] is not None for x in self.req])
|
return all([x['value'] is not None for x in self.req])
|
||||||
|
|
||||||
@CatchException
|
@CatchException
|
||||||
def 图片修改_DALLE2(prompt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port):
|
def 图片修改_DALLE2(prompt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request):
|
||||||
# 尚未完成
|
# 尚未完成
|
||||||
history = [] # 清空历史
|
history = [] # 清空历史
|
||||||
state = ImageEditState.get_state(chatbot, ImageEditState)
|
state = ImageEditState.get_state(chatbot, ImageEditState)
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
|
||||||
|
from toolbox import get_conf, update_ui
|
||||||
|
from crazy_functions.Image_Generate import 图片生成_DALLE2, 图片生成_DALLE3, 图片修改_DALLE2
|
||||||
|
from crazy_functions.plugin_template.plugin_class_template import GptAcademicPluginTemplate, ArgProperty
|
||||||
|
|
||||||
|
|
||||||
|
class ImageGen_Wrap(GptAcademicPluginTemplate):
|
||||||
|
def __init__(self):
|
||||||
|
"""
|
||||||
|
请注意`execute`会执行在不同的线程中,因此您在定义和使用类变量时,应当慎之又慎!
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
def define_arg_selection_menu(self):
|
||||||
|
"""
|
||||||
|
定义插件的二级选项菜单
|
||||||
|
|
||||||
|
第一个参数,名称`main_input`,参数`type`声明这是一个文本框,文本框上方显示`title`,文本框内部显示`description`,`default_value`为默认值;
|
||||||
|
第二个参数,名称`advanced_arg`,参数`type`声明这是一个文本框,文本框上方显示`title`,文本框内部显示`description`,`default_value`为默认值;
|
||||||
|
|
||||||
|
"""
|
||||||
|
gui_definition = {
|
||||||
|
"main_input":
|
||||||
|
ArgProperty(title="输入图片描述", description="需要生成图像的文本描述,尽量使用英文", default_value="", type="string").model_dump_json(), # 主输入,自动从输入框同步
|
||||||
|
"model_name":
|
||||||
|
ArgProperty(title="模型", options=["DALLE2", "DALLE3"], default_value="DALLE3", description="无", type="dropdown").model_dump_json(),
|
||||||
|
"resolution":
|
||||||
|
ArgProperty(title="分辨率", options=["256x256(限DALLE2)", "512x512(限DALLE2)", "1024x1024", "1792x1024(限DALLE3)", "1024x1792(限DALLE3)"], default_value="1024x1024", description="无", type="dropdown").model_dump_json(),
|
||||||
|
"quality (仅DALLE3生效)":
|
||||||
|
ArgProperty(title="质量", options=["standard", "hd"], default_value="standard", description="无", type="dropdown").model_dump_json(),
|
||||||
|
"style (仅DALLE3生效)":
|
||||||
|
ArgProperty(title="风格", options=["vivid", "natural"], default_value="vivid", description="无", type="dropdown").model_dump_json(),
|
||||||
|
|
||||||
|
}
|
||||||
|
return gui_definition
|
||||||
|
|
||||||
|
def execute(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request):
|
||||||
|
"""
|
||||||
|
执行插件
|
||||||
|
"""
|
||||||
|
# 分辨率
|
||||||
|
resolution = plugin_kwargs["resolution"].replace("(限DALLE2)", "").replace("(限DALLE3)", "")
|
||||||
|
|
||||||
|
if plugin_kwargs["model_name"] == "DALLE2":
|
||||||
|
plugin_kwargs["advanced_arg"] = resolution
|
||||||
|
yield from 图片生成_DALLE2(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request)
|
||||||
|
|
||||||
|
elif plugin_kwargs["model_name"] == "DALLE3":
|
||||||
|
quality = plugin_kwargs["quality (仅DALLE3生效)"]
|
||||||
|
style = plugin_kwargs["style (仅DALLE3生效)"]
|
||||||
|
plugin_kwargs["advanced_arg"] = f"{resolution}-{quality}-{style}"
|
||||||
|
yield from 图片生成_DALLE3(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request)
|
||||||
|
|
||||||
|
else:
|
||||||
|
chatbot.append([None, "抱歉,找不到该模型"])
|
||||||
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
||||||
278
crazy_functions/Internet_GPT.py
普通文件
278
crazy_functions/Internet_GPT.py
普通文件
@@ -0,0 +1,278 @@
|
|||||||
|
import requests
|
||||||
|
import random
|
||||||
|
import time
|
||||||
|
import re
|
||||||
|
import json
|
||||||
|
from bs4 import BeautifulSoup
|
||||||
|
from functools import lru_cache
|
||||||
|
from itertools import zip_longest
|
||||||
|
from check_proxy import check_proxy
|
||||||
|
from toolbox import CatchException, update_ui, get_conf
|
||||||
|
from crazy_functions.crazy_utils import request_gpt_model_in_new_thread_with_ui_alive, input_clipping
|
||||||
|
from request_llms.bridge_all import model_info
|
||||||
|
from request_llms.bridge_all import predict_no_ui_long_connection
|
||||||
|
from crazy_functions.prompts.internet import SearchOptimizerPrompt, SearchAcademicOptimizerPrompt
|
||||||
|
|
||||||
|
def search_optimizer(
|
||||||
|
query,
|
||||||
|
proxies,
|
||||||
|
history,
|
||||||
|
llm_kwargs,
|
||||||
|
optimizer=1,
|
||||||
|
categories="general",
|
||||||
|
searxng_url=None,
|
||||||
|
engines=None,
|
||||||
|
):
|
||||||
|
# ------------- < 第1步:尝试进行搜索优化 > -------------
|
||||||
|
# * 增强优化,会尝试结合历史记录进行搜索优化
|
||||||
|
if optimizer == 2:
|
||||||
|
his = " "
|
||||||
|
if len(history) == 0:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
for i, h in enumerate(history):
|
||||||
|
if i % 2 == 0:
|
||||||
|
his += f"Q: {h}\n"
|
||||||
|
else:
|
||||||
|
his += f"A: {h}\n"
|
||||||
|
if categories == "general":
|
||||||
|
sys_prompt = SearchOptimizerPrompt.format(query=query, history=his, num=4)
|
||||||
|
elif categories == "science":
|
||||||
|
sys_prompt = SearchAcademicOptimizerPrompt.format(query=query, history=his, num=4)
|
||||||
|
else:
|
||||||
|
his = " "
|
||||||
|
if categories == "general":
|
||||||
|
sys_prompt = SearchOptimizerPrompt.format(query=query, history=his, num=3)
|
||||||
|
elif categories == "science":
|
||||||
|
sys_prompt = SearchAcademicOptimizerPrompt.format(query=query, history=his, num=3)
|
||||||
|
|
||||||
|
mutable = ["", time.time(), ""]
|
||||||
|
llm_kwargs["temperature"] = 0.8
|
||||||
|
try:
|
||||||
|
querys_json = predict_no_ui_long_connection(
|
||||||
|
inputs=query,
|
||||||
|
llm_kwargs=llm_kwargs,
|
||||||
|
history=[],
|
||||||
|
sys_prompt=sys_prompt,
|
||||||
|
observe_window=mutable,
|
||||||
|
)
|
||||||
|
except Exception:
|
||||||
|
querys_json = "1234"
|
||||||
|
#* 尝试解码优化后的搜索结果
|
||||||
|
querys_json = re.sub(r"```json|```", "", querys_json)
|
||||||
|
try:
|
||||||
|
querys = json.loads(querys_json)
|
||||||
|
except Exception:
|
||||||
|
#* 如果解码失败,降低温度再试一次
|
||||||
|
try:
|
||||||
|
llm_kwargs["temperature"] = 0.4
|
||||||
|
querys_json = predict_no_ui_long_connection(
|
||||||
|
inputs=query,
|
||||||
|
llm_kwargs=llm_kwargs,
|
||||||
|
history=[],
|
||||||
|
sys_prompt=sys_prompt,
|
||||||
|
observe_window=mutable,
|
||||||
|
)
|
||||||
|
querys_json = re.sub(r"```json|```", "", querys_json)
|
||||||
|
querys = json.loads(querys_json)
|
||||||
|
except Exception:
|
||||||
|
#* 如果再次失败,直接返回原始问题
|
||||||
|
querys = [query]
|
||||||
|
links = []
|
||||||
|
success = 0
|
||||||
|
Exceptions = ""
|
||||||
|
for q in querys:
|
||||||
|
try:
|
||||||
|
link = searxng_request(q, proxies, categories, searxng_url, engines=engines)
|
||||||
|
if len(link) > 0:
|
||||||
|
links.append(link[:-5])
|
||||||
|
success += 1
|
||||||
|
except Exception:
|
||||||
|
Exceptions = Exception
|
||||||
|
pass
|
||||||
|
if success == 0:
|
||||||
|
raise ValueError(f"在线搜索失败!\n{Exceptions}")
|
||||||
|
# * 清洗搜索结果,依次放入每组第一,第二个搜索结果,并清洗重复的搜索结果
|
||||||
|
seen_links = set()
|
||||||
|
result = []
|
||||||
|
for tuple in zip_longest(*links, fillvalue=None):
|
||||||
|
for item in tuple:
|
||||||
|
if item is not None:
|
||||||
|
link = item["link"]
|
||||||
|
if link not in seen_links:
|
||||||
|
seen_links.add(link)
|
||||||
|
result.append(item)
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
@lru_cache
|
||||||
|
def get_auth_ip():
|
||||||
|
ip = check_proxy(None, return_ip=True)
|
||||||
|
if ip is None:
|
||||||
|
return '114.114.114.' + str(random.randint(1, 10))
|
||||||
|
return ip
|
||||||
|
|
||||||
|
|
||||||
|
def searxng_request(query, proxies, categories='general', searxng_url=None, engines=None):
|
||||||
|
if searxng_url is None:
|
||||||
|
url = get_conf("SEARXNG_URL")
|
||||||
|
else:
|
||||||
|
url = searxng_url
|
||||||
|
|
||||||
|
if engines == "Mixed":
|
||||||
|
engines = None
|
||||||
|
|
||||||
|
if categories == 'general':
|
||||||
|
params = {
|
||||||
|
'q': query, # 搜索查询
|
||||||
|
'format': 'json', # 输出格式为JSON
|
||||||
|
'language': 'zh', # 搜索语言
|
||||||
|
'engines': engines,
|
||||||
|
}
|
||||||
|
elif categories == 'science':
|
||||||
|
params = {
|
||||||
|
'q': query, # 搜索查询
|
||||||
|
'format': 'json', # 输出格式为JSON
|
||||||
|
'language': 'zh', # 搜索语言
|
||||||
|
'categories': 'science'
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
raise ValueError('不支持的检索类型')
|
||||||
|
|
||||||
|
headers = {
|
||||||
|
'Accept-Language': 'zh-CN,zh;q=0.9',
|
||||||
|
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36',
|
||||||
|
'X-Forwarded-For': get_auth_ip(),
|
||||||
|
'X-Real-IP': get_auth_ip()
|
||||||
|
}
|
||||||
|
results = []
|
||||||
|
response = requests.post(url, params=params, headers=headers, proxies=proxies, timeout=30)
|
||||||
|
if response.status_code == 200:
|
||||||
|
json_result = response.json()
|
||||||
|
for result in json_result['results']:
|
||||||
|
item = {
|
||||||
|
"title": result.get("title", ""),
|
||||||
|
"source": result.get("engines", "unknown"),
|
||||||
|
"content": result.get("content", ""),
|
||||||
|
"link": result["url"],
|
||||||
|
}
|
||||||
|
results.append(item)
|
||||||
|
return results
|
||||||
|
else:
|
||||||
|
if response.status_code == 429:
|
||||||
|
raise ValueError("Searxng(在线搜索服务)当前使用人数太多,请稍后。")
|
||||||
|
else:
|
||||||
|
raise ValueError("在线搜索失败,状态码: " + str(response.status_code) + '\t' + response.content.decode('utf-8'))
|
||||||
|
|
||||||
|
|
||||||
|
def scrape_text(url, proxies) -> str:
|
||||||
|
"""Scrape text from a webpage
|
||||||
|
|
||||||
|
Args:
|
||||||
|
url (str): The URL to scrape text from
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: The scraped text
|
||||||
|
"""
|
||||||
|
headers = {
|
||||||
|
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.61 Safari/537.36',
|
||||||
|
'Content-Type': 'text/plain',
|
||||||
|
}
|
||||||
|
try:
|
||||||
|
response = requests.get(url, headers=headers, proxies=proxies, timeout=8)
|
||||||
|
if response.encoding == "ISO-8859-1": response.encoding = response.apparent_encoding
|
||||||
|
except:
|
||||||
|
return "无法连接到该网页"
|
||||||
|
soup = BeautifulSoup(response.text, "html.parser")
|
||||||
|
for script in soup(["script", "style"]):
|
||||||
|
script.extract()
|
||||||
|
text = soup.get_text()
|
||||||
|
lines = (line.strip() for line in text.splitlines())
|
||||||
|
chunks = (phrase.strip() for line in lines for phrase in line.split(" "))
|
||||||
|
text = "\n".join(chunk for chunk in chunks if chunk)
|
||||||
|
return text
|
||||||
|
|
||||||
|
|
||||||
|
@CatchException
|
||||||
|
def 连接网络回答问题(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request):
|
||||||
|
optimizer_history = history[:-8]
|
||||||
|
history = [] # 清空历史,以免输入溢出
|
||||||
|
chatbot.append((f"请结合互联网信息回答以下问题:{txt}", "检索中..."))
|
||||||
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
||||||
|
|
||||||
|
# ------------- < 第1步:爬取搜索引擎的结果 > -------------
|
||||||
|
from toolbox import get_conf
|
||||||
|
proxies = get_conf('proxies')
|
||||||
|
categories = plugin_kwargs.get('categories', 'general')
|
||||||
|
searxng_url = plugin_kwargs.get('searxng_url', None)
|
||||||
|
engines = plugin_kwargs.get('engine', None)
|
||||||
|
optimizer = plugin_kwargs.get('optimizer', "关闭")
|
||||||
|
if optimizer == "关闭":
|
||||||
|
urls = searxng_request(txt, proxies, categories, searxng_url, engines=engines)
|
||||||
|
else:
|
||||||
|
urls = search_optimizer(txt, proxies, optimizer_history, llm_kwargs, optimizer, categories, searxng_url, engines)
|
||||||
|
history = []
|
||||||
|
if len(urls) == 0:
|
||||||
|
chatbot.append((f"结论:{txt}",
|
||||||
|
"[Local Message] 受到限制,无法从searxng获取信息!请尝试更换搜索引擎。"))
|
||||||
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
||||||
|
return
|
||||||
|
|
||||||
|
# ------------- < 第2步:依次访问网页 > -------------
|
||||||
|
max_search_result = 5 # 最多收纳多少个网页的结果
|
||||||
|
if optimizer == "开启(增强)":
|
||||||
|
max_search_result = 8
|
||||||
|
chatbot.append(["联网检索中 ...", None])
|
||||||
|
for index, url in enumerate(urls[:max_search_result]):
|
||||||
|
res = scrape_text(url['link'], proxies)
|
||||||
|
prefix = f"第{index}份搜索结果 [源自{url['source'][0]}搜索] ({url['title'][:25]}):"
|
||||||
|
history.extend([prefix, res])
|
||||||
|
res_squeeze = res.replace('\n', '...')
|
||||||
|
chatbot[-1] = [prefix + "\n\n" + res_squeeze[:500] + "......", None]
|
||||||
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
||||||
|
|
||||||
|
# ------------- < 第3步:ChatGPT综合 > -------------
|
||||||
|
if (optimizer != "开启(增强)"):
|
||||||
|
i_say = f"从以上搜索结果中抽取信息,然后回答问题:{txt}"
|
||||||
|
i_say, history = input_clipping( # 裁剪输入,从最长的条目开始裁剪,防止爆token
|
||||||
|
inputs=i_say,
|
||||||
|
history=history,
|
||||||
|
max_token_limit=min(model_info[llm_kwargs['llm_model']]['max_token']*3//4, 8192)
|
||||||
|
)
|
||||||
|
gpt_say = yield from request_gpt_model_in_new_thread_with_ui_alive(
|
||||||
|
inputs=i_say, inputs_show_user=i_say,
|
||||||
|
llm_kwargs=llm_kwargs, chatbot=chatbot, history=history,
|
||||||
|
sys_prompt="请从给定的若干条搜索结果中抽取信息,对最相关的两个搜索结果进行总结,然后回答问题。"
|
||||||
|
)
|
||||||
|
chatbot[-1] = (i_say, gpt_say)
|
||||||
|
history.append(i_say);history.append(gpt_say)
|
||||||
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 # 界面更新
|
||||||
|
|
||||||
|
#* 或者使用搜索优化器,这样可以保证后续问答能读取到有效的历史记录
|
||||||
|
else:
|
||||||
|
i_say = f"从以上搜索结果中抽取与问题:{txt} 相关的信息:"
|
||||||
|
i_say, history = input_clipping( # 裁剪输入,从最长的条目开始裁剪,防止爆token
|
||||||
|
inputs=i_say,
|
||||||
|
history=history,
|
||||||
|
max_token_limit=min(model_info[llm_kwargs['llm_model']]['max_token']*3//4, 8192)
|
||||||
|
)
|
||||||
|
gpt_say = yield from request_gpt_model_in_new_thread_with_ui_alive(
|
||||||
|
inputs=i_say, inputs_show_user=i_say,
|
||||||
|
llm_kwargs=llm_kwargs, chatbot=chatbot, history=history,
|
||||||
|
sys_prompt="请从给定的若干条搜索结果中抽取信息,对最相关的三个搜索结果进行总结"
|
||||||
|
)
|
||||||
|
chatbot[-1] = (i_say, gpt_say)
|
||||||
|
history = []
|
||||||
|
history.append(i_say);history.append(gpt_say)
|
||||||
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 # 界面更新
|
||||||
|
|
||||||
|
# ------------- < 第4步:根据综合回答问题 > -------------
|
||||||
|
i_say = f"请根据以上搜索结果回答问题:{txt}"
|
||||||
|
gpt_say = yield from request_gpt_model_in_new_thread_with_ui_alive(
|
||||||
|
inputs=i_say, inputs_show_user=i_say,
|
||||||
|
llm_kwargs=llm_kwargs, chatbot=chatbot, history=history,
|
||||||
|
sys_prompt="请根据给定的若干条搜索结果回答问题"
|
||||||
|
)
|
||||||
|
chatbot[-1] = (i_say, gpt_say)
|
||||||
|
history.append(i_say);history.append(gpt_say)
|
||||||
|
yield from update_ui(chatbot=chatbot, history=history)
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
|
||||||
|
from toolbox import get_conf
|
||||||
|
from crazy_functions.Internet_GPT import 连接网络回答问题
|
||||||
|
from crazy_functions.plugin_template.plugin_class_template import GptAcademicPluginTemplate, ArgProperty
|
||||||
|
|
||||||
|
|
||||||
|
class NetworkGPT_Wrap(GptAcademicPluginTemplate):
|
||||||
|
def __init__(self):
|
||||||
|
"""
|
||||||
|
请注意`execute`会执行在不同的线程中,因此您在定义和使用类变量时,应当慎之又慎!
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
def define_arg_selection_menu(self):
|
||||||
|
"""
|
||||||
|
定义插件的二级选项菜单
|
||||||
|
|
||||||
|
第一个参数,名称`main_input`,参数`type`声明这是一个文本框,文本框上方显示`title`,文本框内部显示`description`,`default_value`为默认值;
|
||||||
|
第二个参数,名称`advanced_arg`,参数`type`声明这是一个文本框,文本框上方显示`title`,文本框内部显示`description`,`default_value`为默认值;
|
||||||
|
第三个参数,名称`allow_cache`,参数`type`声明这是一个下拉菜单,下拉菜单上方显示`title`+`description`,下拉菜单的选项为`options`,`default_value`为下拉菜单默认值;
|
||||||
|
|
||||||
|
"""
|
||||||
|
gui_definition = {
|
||||||
|
"main_input":
|
||||||
|
ArgProperty(title="输入问题", description="待通过互联网检索的问题,会自动读取输入框内容", default_value="", type="string").model_dump_json(), # 主输入,自动从输入框同步
|
||||||
|
"categories":
|
||||||
|
ArgProperty(title="搜索分类", options=["网页", "学术论文"], default_value="网页", description="无", type="dropdown").model_dump_json(),
|
||||||
|
"engine":
|
||||||
|
ArgProperty(title="选择搜索引擎", options=["Mixed", "bing", "google", "duckduckgo"], default_value="google", description="无", type="dropdown").model_dump_json(),
|
||||||
|
"optimizer":
|
||||||
|
ArgProperty(title="搜索优化", options=["关闭", "开启", "开启(增强)"], default_value="关闭", description="是否使用搜索增强。注意这可能会消耗较多token", type="dropdown").model_dump_json(),
|
||||||
|
"searxng_url":
|
||||||
|
ArgProperty(title="Searxng服务地址", description="输入Searxng的地址", default_value=get_conf("SEARXNG_URL"), type="string").model_dump_json(), # 主输入,自动从输入框同步
|
||||||
|
|
||||||
|
}
|
||||||
|
return gui_definition
|
||||||
|
|
||||||
|
def execute(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request):
|
||||||
|
"""
|
||||||
|
执行插件
|
||||||
|
"""
|
||||||
|
if plugin_kwargs["categories"] == "网页": plugin_kwargs["categories"] = "general"
|
||||||
|
if plugin_kwargs["categories"] == "学术论文": plugin_kwargs["categories"] = "science"
|
||||||
|
yield from 连接网络回答问题(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request)
|
||||||
|
|
||||||
595
crazy_functions/Latex_Function.py
普通文件
595
crazy_functions/Latex_Function.py
普通文件
@@ -0,0 +1,595 @@
|
|||||||
|
from toolbox import update_ui, trimmed_format_exc, get_conf, get_log_folder, promote_file_to_downloadzone, check_repeat_upload, map_file_to_sha256
|
||||||
|
from toolbox import CatchException, report_exception, update_ui_lastest_msg, zip_result, gen_time_str
|
||||||
|
from functools import partial
|
||||||
|
from loguru import logger
|
||||||
|
|
||||||
|
import glob, os, requests, time, json, tarfile, threading
|
||||||
|
|
||||||
|
pj = os.path.join
|
||||||
|
ARXIV_CACHE_DIR = get_conf("ARXIV_CACHE_DIR")
|
||||||
|
|
||||||
|
|
||||||
|
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 工具函数 =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
||||||
|
# 专业词汇声明 = 'If the term "agent" is used in this section, it should be translated to "智能体". '
|
||||||
|
def switch_prompt(pfg, mode, more_requirement):
|
||||||
|
"""
|
||||||
|
Generate prompts and system prompts based on the mode for proofreading or translating.
|
||||||
|
Args:
|
||||||
|
- pfg: Proofreader or Translator instance.
|
||||||
|
- mode: A string specifying the mode, either 'proofread' or 'translate_zh'.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
- inputs_array: A list of strings containing prompts for users to respond to.
|
||||||
|
- sys_prompt_array: A list of strings containing prompts for system prompts.
|
||||||
|
"""
|
||||||
|
n_split = len(pfg.sp_file_contents)
|
||||||
|
if mode == 'proofread_en':
|
||||||
|
inputs_array = [r"Below is a section from an academic paper, proofread this section." +
|
||||||
|
r"Do not modify any latex command such as \section, \cite, \begin, \item and equations. " + more_requirement +
|
||||||
|
r"Answer me only with the revised text:" +
|
||||||
|
f"\n\n{frag}" for frag in pfg.sp_file_contents]
|
||||||
|
sys_prompt_array = ["You are a professional academic paper writer." for _ in range(n_split)]
|
||||||
|
elif mode == 'translate_zh':
|
||||||
|
inputs_array = [
|
||||||
|
r"Below is a section from an English academic paper, translate it into Chinese. " + more_requirement +
|
||||||
|
r"Do not modify any latex command such as \section, \cite, \begin, \item and equations. " +
|
||||||
|
r"Answer me only with the translated text:" +
|
||||||
|
f"\n\n{frag}" for frag in pfg.sp_file_contents]
|
||||||
|
sys_prompt_array = ["You are a professional translator." for _ in range(n_split)]
|
||||||
|
else:
|
||||||
|
assert False, "未知指令"
|
||||||
|
return inputs_array, sys_prompt_array
|
||||||
|
|
||||||
|
|
||||||
|
def desend_to_extracted_folder_if_exist(project_folder):
|
||||||
|
"""
|
||||||
|
Descend into the extracted folder if it exists, otherwise return the original folder.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
- project_folder: A string specifying the folder path.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
- A string specifying the path to the extracted folder, or the original folder if there is no extracted folder.
|
||||||
|
"""
|
||||||
|
maybe_dir = [f for f in glob.glob(f'{project_folder}/*') if os.path.isdir(f)]
|
||||||
|
if len(maybe_dir) == 0: return project_folder
|
||||||
|
if maybe_dir[0].endswith('.extract'): return maybe_dir[0]
|
||||||
|
return project_folder
|
||||||
|
|
||||||
|
|
||||||
|
def move_project(project_folder, arxiv_id=None):
|
||||||
|
"""
|
||||||
|
Create a new work folder and copy the project folder to it.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
- project_folder: A string specifying the folder path of the project.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
- A string specifying the path to the new work folder.
|
||||||
|
"""
|
||||||
|
import shutil, time
|
||||||
|
time.sleep(2) # avoid time string conflict
|
||||||
|
if arxiv_id is not None:
|
||||||
|
new_workfolder = pj(ARXIV_CACHE_DIR, arxiv_id, 'workfolder')
|
||||||
|
else:
|
||||||
|
new_workfolder = f'{get_log_folder()}/{gen_time_str()}'
|
||||||
|
try:
|
||||||
|
shutil.rmtree(new_workfolder)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# align subfolder if there is a folder wrapper
|
||||||
|
items = glob.glob(pj(project_folder, '*'))
|
||||||
|
items = [item for item in items if os.path.basename(item) != '__MACOSX']
|
||||||
|
if len(glob.glob(pj(project_folder, '*.tex'))) == 0 and len(items) == 1:
|
||||||
|
if os.path.isdir(items[0]): project_folder = items[0]
|
||||||
|
|
||||||
|
shutil.copytree(src=project_folder, dst=new_workfolder)
|
||||||
|
return new_workfolder
|
||||||
|
|
||||||
|
|
||||||
|
def arxiv_download(chatbot, history, txt, allow_cache=True):
|
||||||
|
def check_cached_translation_pdf(arxiv_id):
|
||||||
|
translation_dir = pj(ARXIV_CACHE_DIR, arxiv_id, 'translation')
|
||||||
|
if not os.path.exists(translation_dir):
|
||||||
|
os.makedirs(translation_dir)
|
||||||
|
target_file = pj(translation_dir, 'translate_zh.pdf')
|
||||||
|
if os.path.exists(target_file):
|
||||||
|
promote_file_to_downloadzone(target_file, rename_file=None, chatbot=chatbot)
|
||||||
|
target_file_compare = pj(translation_dir, 'comparison.pdf')
|
||||||
|
if os.path.exists(target_file_compare):
|
||||||
|
promote_file_to_downloadzone(target_file_compare, rename_file=None, chatbot=chatbot)
|
||||||
|
return target_file
|
||||||
|
return False
|
||||||
|
|
||||||
|
def is_float(s):
|
||||||
|
try:
|
||||||
|
float(s)
|
||||||
|
return True
|
||||||
|
except ValueError:
|
||||||
|
return False
|
||||||
|
|
||||||
|
if txt.startswith('https://arxiv.org/pdf/'):
|
||||||
|
arxiv_id = txt.split('/')[-1] # 2402.14207v2.pdf
|
||||||
|
txt = arxiv_id.split('v')[0] # 2402.14207
|
||||||
|
|
||||||
|
if ('.' in txt) and ('/' not in txt) and is_float(txt): # is arxiv ID
|
||||||
|
txt = 'https://arxiv.org/abs/' + txt.strip()
|
||||||
|
if ('.' in txt) and ('/' not in txt) and is_float(txt[:10]): # is arxiv ID
|
||||||
|
txt = 'https://arxiv.org/abs/' + txt[:10]
|
||||||
|
|
||||||
|
if not txt.startswith('https://arxiv.org'):
|
||||||
|
return txt, None # 是本地文件,跳过下载
|
||||||
|
|
||||||
|
# <-------------- inspect format ------------->
|
||||||
|
chatbot.append([f"检测到arxiv文档连接", '尝试下载 ...'])
|
||||||
|
yield from update_ui(chatbot=chatbot, history=history)
|
||||||
|
time.sleep(1) # 刷新界面
|
||||||
|
|
||||||
|
url_ = txt # https://arxiv.org/abs/1707.06690
|
||||||
|
|
||||||
|
if not txt.startswith('https://arxiv.org/abs/'):
|
||||||
|
msg = f"解析arxiv网址失败, 期望格式例如: https://arxiv.org/abs/1707.06690。实际得到格式: {url_}。"
|
||||||
|
yield from update_ui_lastest_msg(msg, chatbot=chatbot, history=history) # 刷新界面
|
||||||
|
return msg, None
|
||||||
|
# <-------------- set format ------------->
|
||||||
|
arxiv_id = url_.split('/abs/')[-1]
|
||||||
|
if 'v' in arxiv_id: arxiv_id = arxiv_id[:10]
|
||||||
|
cached_translation_pdf = check_cached_translation_pdf(arxiv_id)
|
||||||
|
if cached_translation_pdf and allow_cache: return cached_translation_pdf, arxiv_id
|
||||||
|
|
||||||
|
extract_dst = pj(ARXIV_CACHE_DIR, arxiv_id, 'extract')
|
||||||
|
translation_dir = pj(ARXIV_CACHE_DIR, arxiv_id, 'e-print')
|
||||||
|
dst = pj(translation_dir, arxiv_id + '.tar')
|
||||||
|
os.makedirs(translation_dir, exist_ok=True)
|
||||||
|
# <-------------- download arxiv source file ------------->
|
||||||
|
|
||||||
|
def fix_url_and_download():
|
||||||
|
# for url_tar in [url_.replace('/abs/', '/e-print/'), url_.replace('/abs/', '/src/')]:
|
||||||
|
for url_tar in [url_.replace('/abs/', '/src/'), url_.replace('/abs/', '/e-print/')]:
|
||||||
|
proxies = get_conf('proxies')
|
||||||
|
r = requests.get(url_tar, proxies=proxies)
|
||||||
|
if r.status_code == 200:
|
||||||
|
with open(dst, 'wb+') as f:
|
||||||
|
f.write(r.content)
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
if os.path.exists(dst) and allow_cache:
|
||||||
|
yield from update_ui_lastest_msg(f"调用缓存 {arxiv_id}", chatbot=chatbot, history=history) # 刷新界面
|
||||||
|
success = True
|
||||||
|
else:
|
||||||
|
yield from update_ui_lastest_msg(f"开始下载 {arxiv_id}", chatbot=chatbot, history=history) # 刷新界面
|
||||||
|
success = fix_url_and_download()
|
||||||
|
yield from update_ui_lastest_msg(f"下载完成 {arxiv_id}", chatbot=chatbot, history=history) # 刷新界面
|
||||||
|
|
||||||
|
|
||||||
|
if not success:
|
||||||
|
yield from update_ui_lastest_msg(f"下载失败 {arxiv_id}", chatbot=chatbot, history=history)
|
||||||
|
raise tarfile.ReadError(f"论文下载失败 {arxiv_id}")
|
||||||
|
|
||||||
|
# <-------------- extract file ------------->
|
||||||
|
from toolbox import extract_archive
|
||||||
|
try:
|
||||||
|
extract_archive(file_path=dst, dest_dir=extract_dst)
|
||||||
|
except tarfile.ReadError:
|
||||||
|
os.remove(dst)
|
||||||
|
raise tarfile.ReadError(f"论文下载失败")
|
||||||
|
return extract_dst, arxiv_id
|
||||||
|
|
||||||
|
|
||||||
|
def pdf2tex_project(pdf_file_path, plugin_kwargs):
|
||||||
|
if plugin_kwargs["method"] == "MATHPIX":
|
||||||
|
# Mathpix API credentials
|
||||||
|
app_id, app_key = get_conf('MATHPIX_APPID', 'MATHPIX_APPKEY')
|
||||||
|
headers = {"app_id": app_id, "app_key": app_key}
|
||||||
|
|
||||||
|
# Step 1: Send PDF file for processing
|
||||||
|
options = {
|
||||||
|
"conversion_formats": {"tex.zip": True},
|
||||||
|
"math_inline_delimiters": ["$", "$"],
|
||||||
|
"rm_spaces": True
|
||||||
|
}
|
||||||
|
|
||||||
|
response = requests.post(url="https://api.mathpix.com/v3/pdf",
|
||||||
|
headers=headers,
|
||||||
|
data={"options_json": json.dumps(options)},
|
||||||
|
files={"file": open(pdf_file_path, "rb")})
|
||||||
|
|
||||||
|
if response.ok:
|
||||||
|
pdf_id = response.json()["pdf_id"]
|
||||||
|
logger.info(f"PDF processing initiated. PDF ID: {pdf_id}")
|
||||||
|
|
||||||
|
# Step 2: Check processing status
|
||||||
|
while True:
|
||||||
|
conversion_response = requests.get(f"https://api.mathpix.com/v3/pdf/{pdf_id}", headers=headers)
|
||||||
|
conversion_data = conversion_response.json()
|
||||||
|
|
||||||
|
if conversion_data["status"] == "completed":
|
||||||
|
logger.info("PDF processing completed.")
|
||||||
|
break
|
||||||
|
elif conversion_data["status"] == "error":
|
||||||
|
logger.info("Error occurred during processing.")
|
||||||
|
else:
|
||||||
|
logger.info(f"Processing status: {conversion_data['status']}")
|
||||||
|
time.sleep(5) # wait for a few seconds before checking again
|
||||||
|
|
||||||
|
# Step 3: Save results to local files
|
||||||
|
output_dir = os.path.join(os.path.dirname(pdf_file_path), 'mathpix_output')
|
||||||
|
if not os.path.exists(output_dir):
|
||||||
|
os.makedirs(output_dir)
|
||||||
|
|
||||||
|
url = f"https://api.mathpix.com/v3/pdf/{pdf_id}.tex"
|
||||||
|
response = requests.get(url, headers=headers)
|
||||||
|
file_name_wo_dot = '_'.join(os.path.basename(pdf_file_path).split('.')[:-1])
|
||||||
|
output_name = f"{file_name_wo_dot}.tex.zip"
|
||||||
|
output_path = os.path.join(output_dir, output_name)
|
||||||
|
with open(output_path, "wb") as output_file:
|
||||||
|
output_file.write(response.content)
|
||||||
|
logger.info(f"tex.zip file saved at: {output_path}")
|
||||||
|
|
||||||
|
import zipfile
|
||||||
|
unzip_dir = os.path.join(output_dir, file_name_wo_dot)
|
||||||
|
with zipfile.ZipFile(output_path, 'r') as zip_ref:
|
||||||
|
zip_ref.extractall(unzip_dir)
|
||||||
|
|
||||||
|
return unzip_dir
|
||||||
|
|
||||||
|
else:
|
||||||
|
logger.error(f"Error sending PDF for processing. Status code: {response.status_code}")
|
||||||
|
return None
|
||||||
|
else:
|
||||||
|
from crazy_functions.pdf_fns.parse_pdf_via_doc2x import 解析PDF_DOC2X_转Latex
|
||||||
|
unzip_dir = 解析PDF_DOC2X_转Latex(pdf_file_path)
|
||||||
|
return unzip_dir
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 插件主程序1 =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||||
|
|
||||||
|
|
||||||
|
@CatchException
|
||||||
|
def Latex英文纠错加PDF对比(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request):
|
||||||
|
# <-------------- information about this plugin ------------->
|
||||||
|
chatbot.append(["函数插件功能?",
|
||||||
|
"对整个Latex项目进行纠错, 用latex编译为PDF对修正处做高亮。函数插件贡献者: Binary-Husky。注意事项: 目前对机器学习类文献转化效果最好,其他类型文献转化效果未知。仅在Windows系统进行了测试,其他操作系统表现未知。"])
|
||||||
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
||||||
|
|
||||||
|
# <-------------- more requirements ------------->
|
||||||
|
if ("advanced_arg" in plugin_kwargs) and (plugin_kwargs["advanced_arg"] == ""): plugin_kwargs.pop("advanced_arg")
|
||||||
|
more_req = plugin_kwargs.get("advanced_arg", "")
|
||||||
|
_switch_prompt_ = partial(switch_prompt, more_requirement=more_req)
|
||||||
|
|
||||||
|
# <-------------- check deps ------------->
|
||||||
|
try:
|
||||||
|
import glob, os, time, subprocess
|
||||||
|
subprocess.Popen(['pdflatex', '-version'])
|
||||||
|
from .latex_fns.latex_actions import Latex精细分解与转化, 编译Latex
|
||||||
|
except Exception as e:
|
||||||
|
chatbot.append([f"解析项目: {txt}",
|
||||||
|
f"尝试执行Latex指令失败。Latex没有安装, 或者不在环境变量PATH中。安装方法https://tug.org/texlive/。报错信息\n\n```\n\n{trimmed_format_exc()}\n\n```\n\n"])
|
||||||
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
||||||
|
return
|
||||||
|
|
||||||
|
# <-------------- clear history and read input ------------->
|
||||||
|
history = []
|
||||||
|
if os.path.exists(txt):
|
||||||
|
project_folder = txt
|
||||||
|
else:
|
||||||
|
if txt == "": txt = '空空如也的输入栏'
|
||||||
|
report_exception(chatbot, history, a=f"解析项目: {txt}", b=f"找不到本地项目或无权访问: {txt}")
|
||||||
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
||||||
|
return
|
||||||
|
file_manifest = [f for f in glob.glob(f'{project_folder}/**/*.tex', recursive=True)]
|
||||||
|
if len(file_manifest) == 0:
|
||||||
|
report_exception(chatbot, history, a=f"解析项目: {txt}", b=f"找不到任何.tex文件: {txt}")
|
||||||
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
||||||
|
return
|
||||||
|
|
||||||
|
# <-------------- if is a zip/tar file ------------->
|
||||||
|
project_folder = desend_to_extracted_folder_if_exist(project_folder)
|
||||||
|
|
||||||
|
# <-------------- move latex project away from temp folder ------------->
|
||||||
|
from shared_utils.fastapi_server import validate_path_safety
|
||||||
|
validate_path_safety(project_folder, chatbot.get_user())
|
||||||
|
project_folder = move_project(project_folder, arxiv_id=None)
|
||||||
|
|
||||||
|
# <-------------- if merge_translate_zh is already generated, skip gpt req ------------->
|
||||||
|
if not os.path.exists(project_folder + '/merge_proofread_en.tex'):
|
||||||
|
yield from Latex精细分解与转化(file_manifest, project_folder, llm_kwargs, plugin_kwargs,
|
||||||
|
chatbot, history, system_prompt, mode='proofread_en',
|
||||||
|
switch_prompt=_switch_prompt_)
|
||||||
|
|
||||||
|
# <-------------- compile PDF ------------->
|
||||||
|
success = yield from 编译Latex(chatbot, history, main_file_original='merge',
|
||||||
|
main_file_modified='merge_proofread_en',
|
||||||
|
work_folder_original=project_folder, work_folder_modified=project_folder,
|
||||||
|
work_folder=project_folder)
|
||||||
|
|
||||||
|
# <-------------- zip PDF ------------->
|
||||||
|
zip_res = zip_result(project_folder)
|
||||||
|
if success:
|
||||||
|
chatbot.append((f"成功啦", '请查收结果(压缩包)...'))
|
||||||
|
yield from update_ui(chatbot=chatbot, history=history);
|
||||||
|
time.sleep(1) # 刷新界面
|
||||||
|
promote_file_to_downloadzone(file=zip_res, chatbot=chatbot)
|
||||||
|
else:
|
||||||
|
chatbot.append((f"失败了",
|
||||||
|
'虽然PDF生成失败了, 但请查收结果(压缩包), 内含已经翻译的Tex文档, 也是可读的, 您可以到Github Issue区, 用该压缩包+Conversation_To_File进行反馈 ...'))
|
||||||
|
yield from update_ui(chatbot=chatbot, history=history);
|
||||||
|
time.sleep(1) # 刷新界面
|
||||||
|
promote_file_to_downloadzone(file=zip_res, chatbot=chatbot)
|
||||||
|
|
||||||
|
# <-------------- we are done ------------->
|
||||||
|
return success
|
||||||
|
|
||||||
|
|
||||||
|
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 插件主程序2 =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||||
|
|
||||||
|
@CatchException
|
||||||
|
def Latex翻译中文并重新编译PDF(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request):
|
||||||
|
# <-------------- information about this plugin ------------->
|
||||||
|
chatbot.append([
|
||||||
|
"函数插件功能?",
|
||||||
|
"对整个Latex项目进行翻译, 生成中文PDF。函数插件贡献者: Binary-Husky。注意事项: 此插件Windows支持最佳,Linux下必须使用Docker安装,详见项目主README.md。目前对机器学习类文献转化效果最好,其他类型文献转化效果未知。"])
|
||||||
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
||||||
|
|
||||||
|
# <-------------- more requirements ------------->
|
||||||
|
if ("advanced_arg" in plugin_kwargs) and (plugin_kwargs["advanced_arg"] == ""): plugin_kwargs.pop("advanced_arg")
|
||||||
|
more_req = plugin_kwargs.get("advanced_arg", "")
|
||||||
|
|
||||||
|
no_cache = ("--no-cache" in more_req)
|
||||||
|
if no_cache: more_req = more_req.replace("--no-cache", "").strip()
|
||||||
|
|
||||||
|
allow_gptac_cloud_io = ("--allow-cloudio" in more_req) # 从云端下载翻译结果,以及上传翻译结果到云端
|
||||||
|
if allow_gptac_cloud_io: more_req = more_req.replace("--allow-cloudio", "").strip()
|
||||||
|
|
||||||
|
allow_cache = not no_cache
|
||||||
|
_switch_prompt_ = partial(switch_prompt, more_requirement=more_req)
|
||||||
|
|
||||||
|
|
||||||
|
# <-------------- check deps ------------->
|
||||||
|
try:
|
||||||
|
import glob, os, time, subprocess
|
||||||
|
subprocess.Popen(['pdflatex', '-version'])
|
||||||
|
from .latex_fns.latex_actions import Latex精细分解与转化, 编译Latex
|
||||||
|
except Exception as e:
|
||||||
|
chatbot.append([f"解析项目: {txt}",
|
||||||
|
f"尝试执行Latex指令失败。Latex没有安装, 或者不在环境变量PATH中。安装方法https://tug.org/texlive/。报错信息\n\n```\n\n{trimmed_format_exc()}\n\n```\n\n"])
|
||||||
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
||||||
|
return
|
||||||
|
|
||||||
|
# <-------------- clear history and read input ------------->
|
||||||
|
history = []
|
||||||
|
try:
|
||||||
|
txt, arxiv_id = yield from arxiv_download(chatbot, history, txt, allow_cache)
|
||||||
|
except tarfile.ReadError as e:
|
||||||
|
yield from update_ui_lastest_msg(
|
||||||
|
"无法自动下载该论文的Latex源码,请前往arxiv打开此论文下载页面,点other Formats,然后download source手动下载latex源码包。接下来调用本地Latex翻译插件即可。",
|
||||||
|
chatbot=chatbot, history=history)
|
||||||
|
return
|
||||||
|
|
||||||
|
if txt.endswith('.pdf'):
|
||||||
|
report_exception(chatbot, history, a=f"解析项目: {txt}", b=f"发现已经存在翻译好的PDF文档")
|
||||||
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
||||||
|
return
|
||||||
|
|
||||||
|
# #################################################################
|
||||||
|
if allow_gptac_cloud_io and arxiv_id:
|
||||||
|
# 访问 GPTAC学术云,查询云端是否存在该论文的翻译版本
|
||||||
|
from crazy_functions.latex_fns.latex_actions import check_gptac_cloud
|
||||||
|
success, downloaded = check_gptac_cloud(arxiv_id, chatbot)
|
||||||
|
if success:
|
||||||
|
chatbot.append([
|
||||||
|
f"检测到GPTAC云端存在翻译版本, 如果不满意翻译结果, 请禁用云端分享, 然后重新执行。",
|
||||||
|
None
|
||||||
|
])
|
||||||
|
yield from update_ui(chatbot=chatbot, history=history)
|
||||||
|
return
|
||||||
|
#################################################################
|
||||||
|
|
||||||
|
if os.path.exists(txt):
|
||||||
|
project_folder = txt
|
||||||
|
else:
|
||||||
|
if txt == "": txt = '空空如也的输入栏'
|
||||||
|
report_exception(chatbot, history, a=f"解析项目: {txt}", b=f"找不到本地项目或无法处理: {txt}")
|
||||||
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
||||||
|
return
|
||||||
|
|
||||||
|
file_manifest = [f for f in glob.glob(f'{project_folder}/**/*.tex', recursive=True)]
|
||||||
|
if len(file_manifest) == 0:
|
||||||
|
report_exception(chatbot, history, a=f"解析项目: {txt}", b=f"找不到任何.tex文件: {txt}")
|
||||||
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
||||||
|
return
|
||||||
|
|
||||||
|
# <-------------- if is a zip/tar file ------------->
|
||||||
|
project_folder = desend_to_extracted_folder_if_exist(project_folder)
|
||||||
|
|
||||||
|
# <-------------- move latex project away from temp folder ------------->
|
||||||
|
from shared_utils.fastapi_server import validate_path_safety
|
||||||
|
validate_path_safety(project_folder, chatbot.get_user())
|
||||||
|
project_folder = move_project(project_folder, arxiv_id)
|
||||||
|
|
||||||
|
# <-------------- if merge_translate_zh is already generated, skip gpt req ------------->
|
||||||
|
if not os.path.exists(project_folder + '/merge_translate_zh.tex'):
|
||||||
|
yield from Latex精细分解与转化(file_manifest, project_folder, llm_kwargs, plugin_kwargs,
|
||||||
|
chatbot, history, system_prompt, mode='translate_zh',
|
||||||
|
switch_prompt=_switch_prompt_)
|
||||||
|
|
||||||
|
# <-------------- compile PDF ------------->
|
||||||
|
success = yield from 编译Latex(chatbot, history, main_file_original='merge',
|
||||||
|
main_file_modified='merge_translate_zh', mode='translate_zh',
|
||||||
|
work_folder_original=project_folder, work_folder_modified=project_folder,
|
||||||
|
work_folder=project_folder)
|
||||||
|
|
||||||
|
# <-------------- zip PDF ------------->
|
||||||
|
zip_res = zip_result(project_folder)
|
||||||
|
if success:
|
||||||
|
if allow_gptac_cloud_io and arxiv_id:
|
||||||
|
# 如果用户允许,我们将翻译好的arxiv论文PDF上传到GPTAC学术云
|
||||||
|
from crazy_functions.latex_fns.latex_actions import upload_to_gptac_cloud_if_user_allow
|
||||||
|
threading.Thread(target=upload_to_gptac_cloud_if_user_allow,
|
||||||
|
args=(chatbot, arxiv_id), daemon=True).start()
|
||||||
|
|
||||||
|
chatbot.append((f"成功啦", '请查收结果(压缩包)...'))
|
||||||
|
yield from update_ui(chatbot=chatbot, history=history)
|
||||||
|
time.sleep(1) # 刷新界面
|
||||||
|
promote_file_to_downloadzone(file=zip_res, chatbot=chatbot)
|
||||||
|
|
||||||
|
else:
|
||||||
|
chatbot.append((f"失败了",
|
||||||
|
'虽然PDF生成失败了, 但请查收结果(压缩包), 内含已经翻译的Tex文档, 您可以到Github Issue区, 用该压缩包进行反馈。如系统是Linux,请检查系统字体(见Github wiki) ...'))
|
||||||
|
yield from update_ui(chatbot=chatbot, history=history)
|
||||||
|
time.sleep(1) # 刷新界面
|
||||||
|
promote_file_to_downloadzone(file=zip_res, chatbot=chatbot)
|
||||||
|
|
||||||
|
# <-------------- we are done ------------->
|
||||||
|
return success
|
||||||
|
|
||||||
|
|
||||||
|
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 插件主程序3 =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||||
|
|
||||||
|
@CatchException
|
||||||
|
def PDF翻译中文并重新编译PDF(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port):
|
||||||
|
# <-------------- information about this plugin ------------->
|
||||||
|
chatbot.append([
|
||||||
|
"函数插件功能?",
|
||||||
|
"将PDF转换为Latex项目,翻译为中文后重新编译为PDF。函数插件贡献者: Marroh。注意事项: 此插件Windows支持最佳,Linux下必须使用Docker安装,详见项目主README.md。目前对机器学习类文献转化效果最好,其他类型文献转化效果未知。"])
|
||||||
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
||||||
|
|
||||||
|
# <-------------- more requirements ------------->
|
||||||
|
if ("advanced_arg" in plugin_kwargs) and (plugin_kwargs["advanced_arg"] == ""): plugin_kwargs.pop("advanced_arg")
|
||||||
|
more_req = plugin_kwargs.get("advanced_arg", "")
|
||||||
|
no_cache = more_req.startswith("--no-cache")
|
||||||
|
if no_cache: more_req.lstrip("--no-cache")
|
||||||
|
allow_cache = not no_cache
|
||||||
|
_switch_prompt_ = partial(switch_prompt, more_requirement=more_req)
|
||||||
|
|
||||||
|
# <-------------- check deps ------------->
|
||||||
|
try:
|
||||||
|
import glob, os, time, subprocess
|
||||||
|
subprocess.Popen(['pdflatex', '-version'])
|
||||||
|
from .latex_fns.latex_actions import Latex精细分解与转化, 编译Latex
|
||||||
|
except Exception as e:
|
||||||
|
chatbot.append([f"解析项目: {txt}",
|
||||||
|
f"尝试执行Latex指令失败。Latex没有安装, 或者不在环境变量PATH中。安装方法https://tug.org/texlive/。报错信息\n\n```\n\n{trimmed_format_exc()}\n\n```\n\n"])
|
||||||
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
||||||
|
return
|
||||||
|
|
||||||
|
# <-------------- clear history and read input ------------->
|
||||||
|
if os.path.exists(txt):
|
||||||
|
project_folder = txt
|
||||||
|
else:
|
||||||
|
if txt == "": txt = '空空如也的输入栏'
|
||||||
|
report_exception(chatbot, history, a=f"解析项目: {txt}", b=f"找不到本地项目或无法处理: {txt}")
|
||||||
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
||||||
|
return
|
||||||
|
|
||||||
|
file_manifest = [f for f in glob.glob(f'{project_folder}/**/*.pdf', recursive=True)]
|
||||||
|
if len(file_manifest) == 0:
|
||||||
|
report_exception(chatbot, history, a=f"解析项目: {txt}", b=f"找不到任何.pdf文件: {txt}")
|
||||||
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
||||||
|
return
|
||||||
|
if len(file_manifest) != 1:
|
||||||
|
report_exception(chatbot, history, a=f"解析项目: {txt}", b=f"不支持同时处理多个pdf文件: {txt}")
|
||||||
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
||||||
|
return
|
||||||
|
|
||||||
|
if plugin_kwargs.get("method", "") == 'MATHPIX':
|
||||||
|
app_id, app_key = get_conf('MATHPIX_APPID', 'MATHPIX_APPKEY')
|
||||||
|
if len(app_id) == 0 or len(app_key) == 0:
|
||||||
|
report_exception(chatbot, history, a="缺失 MATHPIX_APPID 和 MATHPIX_APPKEY。", b=f"请配置 MATHPIX_APPID 和 MATHPIX_APPKEY")
|
||||||
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
||||||
|
return
|
||||||
|
if plugin_kwargs.get("method", "") == 'DOC2X':
|
||||||
|
app_id, app_key = "", ""
|
||||||
|
DOC2X_API_KEY = get_conf('DOC2X_API_KEY')
|
||||||
|
if len(DOC2X_API_KEY) == 0:
|
||||||
|
report_exception(chatbot, history, a="缺失 DOC2X_API_KEY。", b=f"请配置 DOC2X_API_KEY")
|
||||||
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
||||||
|
return
|
||||||
|
|
||||||
|
hash_tag = map_file_to_sha256(file_manifest[0])
|
||||||
|
|
||||||
|
# # <-------------- check repeated pdf ------------->
|
||||||
|
# chatbot.append([f"检查PDF是否被重复上传", "正在检查..."])
|
||||||
|
# yield from update_ui(chatbot=chatbot, history=history)
|
||||||
|
# repeat, project_folder = check_repeat_upload(file_manifest[0], hash_tag)
|
||||||
|
|
||||||
|
# if repeat:
|
||||||
|
# yield from update_ui_lastest_msg(f"发现重复上传,请查收结果(压缩包)...", chatbot=chatbot, history=history)
|
||||||
|
# try:
|
||||||
|
# translate_pdf = [f for f in glob.glob(f'{project_folder}/**/merge_translate_zh.pdf', recursive=True)][0]
|
||||||
|
# promote_file_to_downloadzone(translate_pdf, rename_file=None, chatbot=chatbot)
|
||||||
|
# comparison_pdf = [f for f in glob.glob(f'{project_folder}/**/comparison.pdf', recursive=True)][0]
|
||||||
|
# promote_file_to_downloadzone(comparison_pdf, rename_file=None, chatbot=chatbot)
|
||||||
|
# zip_res = zip_result(project_folder)
|
||||||
|
# promote_file_to_downloadzone(file=zip_res, chatbot=chatbot)
|
||||||
|
# return
|
||||||
|
# except:
|
||||||
|
# report_exception(chatbot, history, a=f"解析项目: {txt}", b=f"发现重复上传,但是无法找到相关文件")
|
||||||
|
# yield from update_ui(chatbot=chatbot, history=history)
|
||||||
|
# else:
|
||||||
|
# yield from update_ui_lastest_msg(f"未发现重复上传", chatbot=chatbot, history=history)
|
||||||
|
|
||||||
|
# <-------------- convert pdf into tex ------------->
|
||||||
|
chatbot.append([f"解析项目: {txt}", "正在将PDF转换为tex项目,请耐心等待..."])
|
||||||
|
yield from update_ui(chatbot=chatbot, history=history)
|
||||||
|
project_folder = pdf2tex_project(file_manifest[0], plugin_kwargs)
|
||||||
|
if project_folder is None:
|
||||||
|
report_exception(chatbot, history, a=f"解析项目: {txt}", b=f"PDF转换为tex项目失败")
|
||||||
|
yield from update_ui(chatbot=chatbot, history=history)
|
||||||
|
return False
|
||||||
|
|
||||||
|
# <-------------- translate latex file into Chinese ------------->
|
||||||
|
yield from update_ui_lastest_msg("正在tex项目将翻译为中文...", chatbot=chatbot, history=history)
|
||||||
|
file_manifest = [f for f in glob.glob(f'{project_folder}/**/*.tex', recursive=True)]
|
||||||
|
if len(file_manifest) == 0:
|
||||||
|
report_exception(chatbot, history, a=f"解析项目: {txt}", b=f"找不到任何.tex文件: {txt}")
|
||||||
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
||||||
|
return
|
||||||
|
|
||||||
|
# <-------------- if is a zip/tar file ------------->
|
||||||
|
project_folder = desend_to_extracted_folder_if_exist(project_folder)
|
||||||
|
|
||||||
|
# <-------------- move latex project away from temp folder ------------->
|
||||||
|
from shared_utils.fastapi_server import validate_path_safety
|
||||||
|
validate_path_safety(project_folder, chatbot.get_user())
|
||||||
|
project_folder = move_project(project_folder)
|
||||||
|
|
||||||
|
# <-------------- set a hash tag for repeat-checking ------------->
|
||||||
|
with open(pj(project_folder, hash_tag + '.tag'), 'w') as f:
|
||||||
|
f.write(hash_tag)
|
||||||
|
f.close()
|
||||||
|
|
||||||
|
|
||||||
|
# <-------------- if merge_translate_zh is already generated, skip gpt req ------------->
|
||||||
|
if not os.path.exists(project_folder + '/merge_translate_zh.tex'):
|
||||||
|
yield from Latex精细分解与转化(file_manifest, project_folder, llm_kwargs, plugin_kwargs,
|
||||||
|
chatbot, history, system_prompt, mode='translate_zh',
|
||||||
|
switch_prompt=_switch_prompt_)
|
||||||
|
|
||||||
|
# <-------------- compile PDF ------------->
|
||||||
|
yield from update_ui_lastest_msg("正在将翻译好的项目tex项目编译为PDF...", chatbot=chatbot, history=history)
|
||||||
|
success = yield from 编译Latex(chatbot, history, main_file_original='merge',
|
||||||
|
main_file_modified='merge_translate_zh', mode='translate_zh',
|
||||||
|
work_folder_original=project_folder, work_folder_modified=project_folder,
|
||||||
|
work_folder=project_folder)
|
||||||
|
|
||||||
|
# <-------------- zip PDF ------------->
|
||||||
|
zip_res = zip_result(project_folder)
|
||||||
|
if success:
|
||||||
|
chatbot.append((f"成功啦", '请查收结果(压缩包)...'))
|
||||||
|
yield from update_ui(chatbot=chatbot, history=history);
|
||||||
|
time.sleep(1) # 刷新界面
|
||||||
|
promote_file_to_downloadzone(file=zip_res, chatbot=chatbot)
|
||||||
|
else:
|
||||||
|
chatbot.append((f"失败了",
|
||||||
|
'虽然PDF生成失败了, 但请查收结果(压缩包), 内含已经翻译的Tex文档, 您可以到Github Issue区, 用该压缩包进行反馈。如系统是Linux,请检查系统字体(见Github wiki) ...'))
|
||||||
|
yield from update_ui(chatbot=chatbot, history=history);
|
||||||
|
time.sleep(1) # 刷新界面
|
||||||
|
promote_file_to_downloadzone(file=zip_res, chatbot=chatbot)
|
||||||
|
|
||||||
|
# <-------------- we are done ------------->
|
||||||
|
return success
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
|
||||||
|
from crazy_functions.Latex_Function import Latex翻译中文并重新编译PDF, PDF翻译中文并重新编译PDF
|
||||||
|
from crazy_functions.plugin_template.plugin_class_template import GptAcademicPluginTemplate, ArgProperty
|
||||||
|
|
||||||
|
|
||||||
|
class Arxiv_Localize(GptAcademicPluginTemplate):
|
||||||
|
def __init__(self):
|
||||||
|
"""
|
||||||
|
请注意`execute`会执行在不同的线程中,因此您在定义和使用类变量时,应当慎之又慎!
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
def define_arg_selection_menu(self):
|
||||||
|
"""
|
||||||
|
定义插件的二级选项菜单
|
||||||
|
|
||||||
|
第一个参数,名称`main_input`,参数`type`声明这是一个文本框,文本框上方显示`title`,文本框内部显示`description`,`default_value`为默认值;
|
||||||
|
第二个参数,名称`advanced_arg`,参数`type`声明这是一个文本框,文本框上方显示`title`,文本框内部显示`description`,`default_value`为默认值;
|
||||||
|
第三个参数,名称`allow_cache`,参数`type`声明这是一个下拉菜单,下拉菜单上方显示`title`+`description`,下拉菜单的选项为`options`,`default_value`为下拉菜单默认值;
|
||||||
|
|
||||||
|
"""
|
||||||
|
gui_definition = {
|
||||||
|
"main_input":
|
||||||
|
ArgProperty(title="ArxivID", description="输入Arxiv的ID或者网址", default_value="", type="string").model_dump_json(), # 主输入,自动从输入框同步
|
||||||
|
"advanced_arg":
|
||||||
|
ArgProperty(title="额外的翻译提示词",
|
||||||
|
description=r"如果有必要, 请在此处给出自定义翻译命令, 解决部分词汇翻译不准确的问题。 "
|
||||||
|
r"例如当单词'agent'翻译不准确时, 请尝试把以下指令复制到高级参数区: "
|
||||||
|
r'If the term "agent" is used in this section, it should be translated to "智能体". ',
|
||||||
|
default_value="", type="string").model_dump_json(), # 高级参数输入区,自动同步
|
||||||
|
"allow_cache":
|
||||||
|
ArgProperty(title="是否允许从缓存中调取结果", options=["允许缓存", "从头执行"], default_value="允许缓存", description="无", type="dropdown").model_dump_json(),
|
||||||
|
"allow_cloudio":
|
||||||
|
ArgProperty(title="是否允许从GPTAC学术云下载(或者上传)翻译结果(仅针对Arxiv论文)", options=["允许", "禁止"], default_value="禁止", description="共享文献,互助互利", type="dropdown").model_dump_json(),
|
||||||
|
}
|
||||||
|
return gui_definition
|
||||||
|
|
||||||
|
def execute(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request):
|
||||||
|
"""
|
||||||
|
执行插件
|
||||||
|
"""
|
||||||
|
allow_cache = plugin_kwargs["allow_cache"]
|
||||||
|
allow_cloudio = plugin_kwargs["allow_cloudio"]
|
||||||
|
advanced_arg = plugin_kwargs["advanced_arg"]
|
||||||
|
|
||||||
|
if allow_cache == "从头执行": plugin_kwargs["advanced_arg"] = "--no-cache " + plugin_kwargs["advanced_arg"]
|
||||||
|
|
||||||
|
# 从云端下载翻译结果,以及上传翻译结果到云端;人人为我,我为人人。
|
||||||
|
if allow_cloudio == "允许": plugin_kwargs["advanced_arg"] = "--allow-cloudio " + plugin_kwargs["advanced_arg"]
|
||||||
|
|
||||||
|
yield from Latex翻译中文并重新编译PDF(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class PDF_Localize(GptAcademicPluginTemplate):
|
||||||
|
def __init__(self):
|
||||||
|
"""
|
||||||
|
请注意`execute`会执行在不同的线程中,因此您在定义和使用类变量时,应当慎之又慎!
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
def define_arg_selection_menu(self):
|
||||||
|
"""
|
||||||
|
定义插件的二级选项菜单
|
||||||
|
"""
|
||||||
|
gui_definition = {
|
||||||
|
"main_input":
|
||||||
|
ArgProperty(title="PDF文件路径", description="未指定路径,请上传文件后,再点击该插件", default_value="", type="string").model_dump_json(), # 主输入,自动从输入框同步
|
||||||
|
"advanced_arg":
|
||||||
|
ArgProperty(title="额外的翻译提示词",
|
||||||
|
description=r"如果有必要, 请在此处给出自定义翻译命令, 解决部分词汇翻译不准确的问题。 "
|
||||||
|
r"例如当单词'agent'翻译不准确时, 请尝试把以下指令复制到高级参数区: "
|
||||||
|
r'If the term "agent" is used in this section, it should be translated to "智能体". ',
|
||||||
|
default_value="", type="string").model_dump_json(), # 高级参数输入区,自动同步
|
||||||
|
"method":
|
||||||
|
ArgProperty(title="采用哪种方法执行转换", options=["MATHPIX", "DOC2X"], default_value="DOC2X", description="无", type="dropdown").model_dump_json(),
|
||||||
|
|
||||||
|
}
|
||||||
|
return gui_definition
|
||||||
|
|
||||||
|
def execute(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request):
|
||||||
|
"""
|
||||||
|
执行插件
|
||||||
|
"""
|
||||||
|
yield from PDF翻译中文并重新编译PDF(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request)
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
from toolbox import update_ui, trimmed_format_exc, promote_file_to_downloadzone, get_log_folder
|
from toolbox import update_ui, trimmed_format_exc, promote_file_to_downloadzone, get_log_folder
|
||||||
from toolbox import CatchException, report_exception, write_history_to_file, zip_folder
|
from toolbox import CatchException, report_exception, write_history_to_file, zip_folder
|
||||||
|
from loguru import logger
|
||||||
|
|
||||||
class PaperFileGroup():
|
class PaperFileGroup():
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
@@ -33,7 +33,7 @@ class PaperFileGroup():
|
|||||||
self.sp_file_index.append(index)
|
self.sp_file_index.append(index)
|
||||||
self.sp_file_tag.append(self.file_paths[index] + f".part-{j}.tex")
|
self.sp_file_tag.append(self.file_paths[index] + f".part-{j}.tex")
|
||||||
|
|
||||||
print('Segmentation: done')
|
logger.info('Segmentation: done')
|
||||||
def merge_result(self):
|
def merge_result(self):
|
||||||
self.file_result = ["" for _ in range(len(self.file_paths))]
|
self.file_result = ["" for _ in range(len(self.file_paths))]
|
||||||
for r, k in zip(self.sp_file_result, self.sp_file_index):
|
for r, k in zip(self.sp_file_result, self.sp_file_index):
|
||||||
@@ -56,7 +56,7 @@ class PaperFileGroup():
|
|||||||
|
|
||||||
def 多文件润色(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, language='en', mode='polish'):
|
def 多文件润色(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, language='en', mode='polish'):
|
||||||
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_functions.crazy_utils import request_gpt_model_multi_threads_with_very_awesome_ui_and_high_efficiency
|
||||||
|
|
||||||
|
|
||||||
# <-------- 读取Latex文件,删除其中的所有注释 ---------->
|
# <-------- 读取Latex文件,删除其中的所有注释 ---------->
|
||||||
@@ -81,8 +81,8 @@ def 多文件润色(file_manifest, project_folder, llm_kwargs, plugin_kwargs, ch
|
|||||||
# <-------- 多线程润色开始 ---------->
|
# <-------- 多线程润色开始 ---------->
|
||||||
if language == 'en':
|
if language == 'en':
|
||||||
if mode == 'polish':
|
if mode == 'polish':
|
||||||
inputs_array = ["Below is a section from an academic paper, polish this section to meet the academic standard, " +
|
inputs_array = [r"Below is a section from an academic paper, polish this section to meet the academic standard, " +
|
||||||
"improve the grammar, clarity and overall readability, do not modify any latex command such as \section, \cite and equations:" +
|
r"improve the grammar, clarity and overall readability, do not modify any latex command such as \section, \cite and equations:" +
|
||||||
f"\n\n{frag}" for frag in pfg.sp_file_contents]
|
f"\n\n{frag}" for frag in pfg.sp_file_contents]
|
||||||
else:
|
else:
|
||||||
inputs_array = [r"Below is a section from an academic paper, proofread this section." +
|
inputs_array = [r"Below is a section from an academic paper, proofread this section." +
|
||||||
@@ -93,10 +93,10 @@ def 多文件润色(file_manifest, project_folder, llm_kwargs, plugin_kwargs, ch
|
|||||||
sys_prompt_array = ["You are a professional academic paper writer." for _ in range(n_split)]
|
sys_prompt_array = ["You are a professional academic paper writer." for _ in range(n_split)]
|
||||||
elif language == 'zh':
|
elif language == 'zh':
|
||||||
if mode == 'polish':
|
if mode == 'polish':
|
||||||
inputs_array = [f"以下是一篇学术论文中的一段内容,请将此部分润色以满足学术标准,提高语法、清晰度和整体可读性,不要修改任何LaTeX命令,例如\section,\cite和方程式:" +
|
inputs_array = [r"以下是一篇学术论文中的一段内容,请将此部分润色以满足学术标准,提高语法、清晰度和整体可读性,不要修改任何LaTeX命令,例如\section,\cite和方程式:" +
|
||||||
f"\n\n{frag}" for frag in pfg.sp_file_contents]
|
f"\n\n{frag}" for frag in pfg.sp_file_contents]
|
||||||
else:
|
else:
|
||||||
inputs_array = [f"以下是一篇学术论文中的一段内容,请对这部分内容进行语法矫正。不要修改任何LaTeX命令,例如\section,\cite和方程式:" +
|
inputs_array = [r"以下是一篇学术论文中的一段内容,请对这部分内容进行语法矫正。不要修改任何LaTeX命令,例如\section,\cite和方程式:" +
|
||||||
f"\n\n{frag}" for frag in pfg.sp_file_contents]
|
f"\n\n{frag}" for frag in pfg.sp_file_contents]
|
||||||
inputs_show_user_array = [f"润色 {f}" for f in pfg.sp_file_tag]
|
inputs_show_user_array = [f"润色 {f}" for f in pfg.sp_file_tag]
|
||||||
sys_prompt_array=["你是一位专业的中文学术论文作家。" for _ in range(n_split)]
|
sys_prompt_array=["你是一位专业的中文学术论文作家。" for _ in range(n_split)]
|
||||||
@@ -122,7 +122,7 @@ def 多文件润色(file_manifest, project_folder, llm_kwargs, plugin_kwargs, ch
|
|||||||
pfg.write_result()
|
pfg.write_result()
|
||||||
pfg.zip_result()
|
pfg.zip_result()
|
||||||
except:
|
except:
|
||||||
print(trimmed_format_exc())
|
logger.error(trimmed_format_exc())
|
||||||
|
|
||||||
# <-------- 整理结果,退出 ---------->
|
# <-------- 整理结果,退出 ---------->
|
||||||
create_report_file_name = time.strftime("%Y-%m-%d-%H-%M-%S", time.localtime()) + f"-chatgpt.polish.md"
|
create_report_file_name = time.strftime("%Y-%m-%d-%H-%M-%S", time.localtime()) + f"-chatgpt.polish.md"
|
||||||
@@ -135,11 +135,11 @@ def 多文件润色(file_manifest, project_folder, llm_kwargs, plugin_kwargs, ch
|
|||||||
|
|
||||||
|
|
||||||
@CatchException
|
@CatchException
|
||||||
def Latex英文润色(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port):
|
def Latex英文润色(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request):
|
||||||
# 基本信息:功能、贡献者
|
# 基本信息:功能、贡献者
|
||||||
chatbot.append([
|
chatbot.append([
|
||||||
"函数插件功能?",
|
"函数插件功能?",
|
||||||
"对整个Latex项目进行润色。函数插件贡献者: Binary-Husky。(注意,此插件不调用Latex,如果有Latex环境,请使用“Latex英文纠错+高亮”插件)"])
|
"对整个Latex项目进行润色。函数插件贡献者: Binary-Husky。(注意,此插件不调用Latex,如果有Latex环境,请使用「Latex英文纠错+高亮修正位置(需Latex)插件」"])
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
||||||
|
|
||||||
# 尝试导入依赖,如果缺少依赖,则给出安装建议
|
# 尝试导入依赖,如果缺少依赖,则给出安装建议
|
||||||
@@ -173,7 +173,7 @@ def Latex英文润色(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_p
|
|||||||
|
|
||||||
|
|
||||||
@CatchException
|
@CatchException
|
||||||
def Latex中文润色(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port):
|
def Latex中文润色(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request):
|
||||||
# 基本信息:功能、贡献者
|
# 基本信息:功能、贡献者
|
||||||
chatbot.append([
|
chatbot.append([
|
||||||
"函数插件功能?",
|
"函数插件功能?",
|
||||||
@@ -209,7 +209,7 @@ def Latex中文润色(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_p
|
|||||||
|
|
||||||
|
|
||||||
@CatchException
|
@CatchException
|
||||||
def Latex英文纠错(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port):
|
def Latex英文纠错(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request):
|
||||||
# 基本信息:功能、贡献者
|
# 基本信息:功能、贡献者
|
||||||
chatbot.append([
|
chatbot.append([
|
||||||
"函数插件功能?",
|
"函数插件功能?",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
from toolbox import update_ui, promote_file_to_downloadzone
|
from toolbox import update_ui, promote_file_to_downloadzone
|
||||||
from toolbox import CatchException, report_exception, write_history_to_file
|
from toolbox import CatchException, report_exception, write_history_to_file
|
||||||
fast_debug = False
|
from loguru import logger
|
||||||
|
|
||||||
class PaperFileGroup():
|
class PaperFileGroup():
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
@@ -33,11 +33,11 @@ class PaperFileGroup():
|
|||||||
self.sp_file_index.append(index)
|
self.sp_file_index.append(index)
|
||||||
self.sp_file_tag.append(self.file_paths[index] + f".part-{j}.tex")
|
self.sp_file_tag.append(self.file_paths[index] + f".part-{j}.tex")
|
||||||
|
|
||||||
print('Segmentation: done')
|
logger.info('Segmentation: done')
|
||||||
|
|
||||||
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
|
import time, os, re
|
||||||
from .crazy_utils import request_gpt_model_multi_threads_with_very_awesome_ui_and_high_efficiency
|
from crazy_functions.crazy_utils import request_gpt_model_multi_threads_with_very_awesome_ui_and_high_efficiency
|
||||||
|
|
||||||
# <-------- 读取Latex文件,删除其中的所有注释 ---------->
|
# <-------- 读取Latex文件,删除其中的所有注释 ---------->
|
||||||
pfg = PaperFileGroup()
|
pfg = PaperFileGroup()
|
||||||
@@ -106,7 +106,7 @@ def 多文件翻译(file_manifest, project_folder, llm_kwargs, plugin_kwargs, ch
|
|||||||
|
|
||||||
|
|
||||||
@CatchException
|
@CatchException
|
||||||
def Latex英译中(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port):
|
def Latex英译中(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request):
|
||||||
# 基本信息:功能、贡献者
|
# 基本信息:功能、贡献者
|
||||||
chatbot.append([
|
chatbot.append([
|
||||||
"函数插件功能?",
|
"函数插件功能?",
|
||||||
@@ -143,7 +143,7 @@ def Latex英译中(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prom
|
|||||||
|
|
||||||
|
|
||||||
@CatchException
|
@CatchException
|
||||||
def Latex中译英(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port):
|
def Latex中译英(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request):
|
||||||
# 基本信息:功能、贡献者
|
# 基本信息:功能、贡献者
|
||||||
chatbot.append([
|
chatbot.append([
|
||||||
"函数插件功能?",
|
"函数插件功能?",
|
||||||
|
|||||||
@@ -1,306 +0,0 @@
|
|||||||
from toolbox import update_ui, trimmed_format_exc, get_conf, get_log_folder, promote_file_to_downloadzone
|
|
||||||
from toolbox import CatchException, report_exception, update_ui_lastest_msg, zip_result, gen_time_str
|
|
||||||
from functools import partial
|
|
||||||
import glob, os, requests, time
|
|
||||||
pj = os.path.join
|
|
||||||
ARXIV_CACHE_DIR = os.path.expanduser(f"~/arxiv_cache/")
|
|
||||||
|
|
||||||
# =================================== 工具函数 ===============================================
|
|
||||||
# 专业词汇声明 = 'If the term "agent" is used in this section, it should be translated to "智能体". '
|
|
||||||
def switch_prompt(pfg, mode, more_requirement):
|
|
||||||
"""
|
|
||||||
Generate prompts and system prompts based on the mode for proofreading or translating.
|
|
||||||
Args:
|
|
||||||
- pfg: Proofreader or Translator instance.
|
|
||||||
- mode: A string specifying the mode, either 'proofread' or 'translate_zh'.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
- inputs_array: A list of strings containing prompts for users to respond to.
|
|
||||||
- sys_prompt_array: A list of strings containing prompts for system prompts.
|
|
||||||
"""
|
|
||||||
n_split = len(pfg.sp_file_contents)
|
|
||||||
if mode == 'proofread_en':
|
|
||||||
inputs_array = [r"Below is a section from an academic paper, proofread this section." +
|
|
||||||
r"Do not modify any latex command such as \section, \cite, \begin, \item and equations. " + more_requirement +
|
|
||||||
r"Answer me only with the revised text:" +
|
|
||||||
f"\n\n{frag}" for frag in pfg.sp_file_contents]
|
|
||||||
sys_prompt_array = ["You are a professional academic paper writer." for _ in range(n_split)]
|
|
||||||
elif mode == 'translate_zh':
|
|
||||||
inputs_array = [r"Below is a section from an English academic paper, translate it into Chinese. " + more_requirement +
|
|
||||||
r"Do not modify any latex command such as \section, \cite, \begin, \item and equations. " +
|
|
||||||
r"Answer me only with the translated text:" +
|
|
||||||
f"\n\n{frag}" for frag in pfg.sp_file_contents]
|
|
||||||
sys_prompt_array = ["You are a professional translator." for _ in range(n_split)]
|
|
||||||
else:
|
|
||||||
assert False, "未知指令"
|
|
||||||
return inputs_array, sys_prompt_array
|
|
||||||
|
|
||||||
def desend_to_extracted_folder_if_exist(project_folder):
|
|
||||||
"""
|
|
||||||
Descend into the extracted folder if it exists, otherwise return the original folder.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
- project_folder: A string specifying the folder path.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
- A string specifying the path to the extracted folder, or the original folder if there is no extracted folder.
|
|
||||||
"""
|
|
||||||
maybe_dir = [f for f in glob.glob(f'{project_folder}/*') if os.path.isdir(f)]
|
|
||||||
if len(maybe_dir) == 0: return project_folder
|
|
||||||
if maybe_dir[0].endswith('.extract'): return maybe_dir[0]
|
|
||||||
return project_folder
|
|
||||||
|
|
||||||
def move_project(project_folder, arxiv_id=None):
|
|
||||||
"""
|
|
||||||
Create a new work folder and copy the project folder to it.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
- project_folder: A string specifying the folder path of the project.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
- A string specifying the path to the new work folder.
|
|
||||||
"""
|
|
||||||
import shutil, time
|
|
||||||
time.sleep(2) # avoid time string conflict
|
|
||||||
if arxiv_id is not None:
|
|
||||||
new_workfolder = pj(ARXIV_CACHE_DIR, arxiv_id, 'workfolder')
|
|
||||||
else:
|
|
||||||
new_workfolder = f'{get_log_folder()}/{gen_time_str()}'
|
|
||||||
try:
|
|
||||||
shutil.rmtree(new_workfolder)
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
|
|
||||||
# align subfolder if there is a folder wrapper
|
|
||||||
items = glob.glob(pj(project_folder,'*'))
|
|
||||||
items = [item for item in items if os.path.basename(item)!='__MACOSX']
|
|
||||||
if len(glob.glob(pj(project_folder,'*.tex'))) == 0 and len(items) == 1:
|
|
||||||
if os.path.isdir(items[0]): project_folder = items[0]
|
|
||||||
|
|
||||||
shutil.copytree(src=project_folder, dst=new_workfolder)
|
|
||||||
return new_workfolder
|
|
||||||
|
|
||||||
def arxiv_download(chatbot, history, txt, allow_cache=True):
|
|
||||||
def check_cached_translation_pdf(arxiv_id):
|
|
||||||
translation_dir = pj(ARXIV_CACHE_DIR, arxiv_id, 'translation')
|
|
||||||
if not os.path.exists(translation_dir):
|
|
||||||
os.makedirs(translation_dir)
|
|
||||||
target_file = pj(translation_dir, 'translate_zh.pdf')
|
|
||||||
if os.path.exists(target_file):
|
|
||||||
promote_file_to_downloadzone(target_file, rename_file=None, chatbot=chatbot)
|
|
||||||
target_file_compare = pj(translation_dir, 'comparison.pdf')
|
|
||||||
if os.path.exists(target_file_compare):
|
|
||||||
promote_file_to_downloadzone(target_file_compare, rename_file=None, chatbot=chatbot)
|
|
||||||
return target_file
|
|
||||||
return False
|
|
||||||
def is_float(s):
|
|
||||||
try:
|
|
||||||
float(s)
|
|
||||||
return True
|
|
||||||
except ValueError:
|
|
||||||
return False
|
|
||||||
if ('.' in txt) and ('/' not in txt) and is_float(txt): # is arxiv ID
|
|
||||||
txt = 'https://arxiv.org/abs/' + txt.strip()
|
|
||||||
if ('.' in txt) and ('/' not in txt) and is_float(txt[:10]): # is arxiv ID
|
|
||||||
txt = 'https://arxiv.org/abs/' + txt[:10]
|
|
||||||
if not txt.startswith('https://arxiv.org'):
|
|
||||||
return txt, None
|
|
||||||
|
|
||||||
# <-------------- inspect format ------------->
|
|
||||||
chatbot.append([f"检测到arxiv文档连接", '尝试下载 ...'])
|
|
||||||
yield from update_ui(chatbot=chatbot, history=history)
|
|
||||||
time.sleep(1) # 刷新界面
|
|
||||||
|
|
||||||
url_ = txt # https://arxiv.org/abs/1707.06690
|
|
||||||
if not txt.startswith('https://arxiv.org/abs/'):
|
|
||||||
msg = f"解析arxiv网址失败, 期望格式例如: https://arxiv.org/abs/1707.06690。实际得到格式: {url_}。"
|
|
||||||
yield from update_ui_lastest_msg(msg, chatbot=chatbot, history=history) # 刷新界面
|
|
||||||
return msg, None
|
|
||||||
# <-------------- set format ------------->
|
|
||||||
arxiv_id = url_.split('/abs/')[-1]
|
|
||||||
if 'v' in arxiv_id: arxiv_id = arxiv_id[:10]
|
|
||||||
cached_translation_pdf = check_cached_translation_pdf(arxiv_id)
|
|
||||||
if cached_translation_pdf and allow_cache: return cached_translation_pdf, arxiv_id
|
|
||||||
|
|
||||||
url_tar = url_.replace('/abs/', '/e-print/')
|
|
||||||
translation_dir = pj(ARXIV_CACHE_DIR, arxiv_id, 'e-print')
|
|
||||||
extract_dst = pj(ARXIV_CACHE_DIR, arxiv_id, 'extract')
|
|
||||||
os.makedirs(translation_dir, exist_ok=True)
|
|
||||||
|
|
||||||
# <-------------- download arxiv source file ------------->
|
|
||||||
dst = pj(translation_dir, arxiv_id+'.tar')
|
|
||||||
if os.path.exists(dst):
|
|
||||||
yield from update_ui_lastest_msg("调用缓存", chatbot=chatbot, history=history) # 刷新界面
|
|
||||||
else:
|
|
||||||
yield from update_ui_lastest_msg("开始下载", chatbot=chatbot, history=history) # 刷新界面
|
|
||||||
proxies = get_conf('proxies')
|
|
||||||
r = requests.get(url_tar, proxies=proxies)
|
|
||||||
with open(dst, 'wb+') as f:
|
|
||||||
f.write(r.content)
|
|
||||||
# <-------------- extract file ------------->
|
|
||||||
yield from update_ui_lastest_msg("下载完成", chatbot=chatbot, history=history) # 刷新界面
|
|
||||||
from toolbox import extract_archive
|
|
||||||
extract_archive(file_path=dst, dest_dir=extract_dst)
|
|
||||||
return extract_dst, arxiv_id
|
|
||||||
# ========================================= 插件主程序1 =====================================================
|
|
||||||
|
|
||||||
|
|
||||||
@CatchException
|
|
||||||
def Latex英文纠错加PDF对比(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port):
|
|
||||||
# <-------------- information about this plugin ------------->
|
|
||||||
chatbot.append([ "函数插件功能?",
|
|
||||||
"对整个Latex项目进行纠错, 用latex编译为PDF对修正处做高亮。函数插件贡献者: Binary-Husky。注意事项: 目前仅支持GPT3.5/GPT4,其他模型转化效果未知。目前对机器学习类文献转化效果最好,其他类型文献转化效果未知。仅在Windows系统进行了测试,其他操作系统表现未知。"])
|
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
|
||||||
|
|
||||||
# <-------------- more requirements ------------->
|
|
||||||
if ("advanced_arg" in plugin_kwargs) and (plugin_kwargs["advanced_arg"] == ""): plugin_kwargs.pop("advanced_arg")
|
|
||||||
more_req = plugin_kwargs.get("advanced_arg", "")
|
|
||||||
_switch_prompt_ = partial(switch_prompt, more_requirement=more_req)
|
|
||||||
|
|
||||||
# <-------------- check deps ------------->
|
|
||||||
try:
|
|
||||||
import glob, os, time, subprocess
|
|
||||||
subprocess.Popen(['pdflatex', '-version'])
|
|
||||||
from .latex_fns.latex_actions import Latex精细分解与转化, 编译Latex
|
|
||||||
except Exception as e:
|
|
||||||
chatbot.append([ f"解析项目: {txt}",
|
|
||||||
f"尝试执行Latex指令失败。Latex没有安装, 或者不在环境变量PATH中。安装方法https://tug.org/texlive/。报错信息\n\n```\n\n{trimmed_format_exc()}\n\n```\n\n"])
|
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
|
||||||
return
|
|
||||||
|
|
||||||
|
|
||||||
# <-------------- clear history and read input ------------->
|
|
||||||
history = []
|
|
||||||
if os.path.exists(txt):
|
|
||||||
project_folder = txt
|
|
||||||
else:
|
|
||||||
if txt == "": txt = '空空如也的输入栏'
|
|
||||||
report_exception(chatbot, history, a = f"解析项目: {txt}", b = f"找不到本地项目或无权访问: {txt}")
|
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
|
||||||
return
|
|
||||||
file_manifest = [f for f in glob.glob(f'{project_folder}/**/*.tex', recursive=True)]
|
|
||||||
if len(file_manifest) == 0:
|
|
||||||
report_exception(chatbot, history, a = f"解析项目: {txt}", b = f"找不到任何.tex文件: {txt}")
|
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
|
||||||
return
|
|
||||||
|
|
||||||
|
|
||||||
# <-------------- if is a zip/tar file ------------->
|
|
||||||
project_folder = desend_to_extracted_folder_if_exist(project_folder)
|
|
||||||
|
|
||||||
|
|
||||||
# <-------------- move latex project away from temp folder ------------->
|
|
||||||
project_folder = move_project(project_folder, arxiv_id=None)
|
|
||||||
|
|
||||||
|
|
||||||
# <-------------- if merge_translate_zh is already generated, skip gpt req ------------->
|
|
||||||
if not os.path.exists(project_folder + '/merge_proofread_en.tex'):
|
|
||||||
yield from Latex精细分解与转化(file_manifest, project_folder, llm_kwargs, plugin_kwargs,
|
|
||||||
chatbot, history, system_prompt, mode='proofread_en', switch_prompt=_switch_prompt_)
|
|
||||||
|
|
||||||
|
|
||||||
# <-------------- compile PDF ------------->
|
|
||||||
success = yield from 编译Latex(chatbot, history, main_file_original='merge', main_file_modified='merge_proofread_en',
|
|
||||||
work_folder_original=project_folder, work_folder_modified=project_folder, work_folder=project_folder)
|
|
||||||
|
|
||||||
|
|
||||||
# <-------------- zip PDF ------------->
|
|
||||||
zip_res = zip_result(project_folder)
|
|
||||||
if success:
|
|
||||||
chatbot.append((f"成功啦", '请查收结果(压缩包)...'))
|
|
||||||
yield from update_ui(chatbot=chatbot, history=history); time.sleep(1) # 刷新界面
|
|
||||||
promote_file_to_downloadzone(file=zip_res, chatbot=chatbot)
|
|
||||||
else:
|
|
||||||
chatbot.append((f"失败了", '虽然PDF生成失败了, 但请查收结果(压缩包), 内含已经翻译的Tex文档, 也是可读的, 您可以到Github Issue区, 用该压缩包+对话历史存档进行反馈 ...'))
|
|
||||||
yield from update_ui(chatbot=chatbot, history=history); time.sleep(1) # 刷新界面
|
|
||||||
promote_file_to_downloadzone(file=zip_res, chatbot=chatbot)
|
|
||||||
|
|
||||||
# <-------------- we are done ------------->
|
|
||||||
return success
|
|
||||||
|
|
||||||
# ========================================= 插件主程序2 =====================================================
|
|
||||||
|
|
||||||
@CatchException
|
|
||||||
def Latex翻译中文并重新编译PDF(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port):
|
|
||||||
# <-------------- information about this plugin ------------->
|
|
||||||
chatbot.append([
|
|
||||||
"函数插件功能?",
|
|
||||||
"对整个Latex项目进行翻译, 生成中文PDF。函数插件贡献者: Binary-Husky。注意事项: 此插件Windows支持最佳,Linux下必须使用Docker安装,详见项目主README.md。目前仅支持GPT3.5/GPT4,其他模型转化效果未知。目前对机器学习类文献转化效果最好,其他类型文献转化效果未知。"])
|
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
|
||||||
|
|
||||||
# <-------------- more requirements ------------->
|
|
||||||
if ("advanced_arg" in plugin_kwargs) and (plugin_kwargs["advanced_arg"] == ""): plugin_kwargs.pop("advanced_arg")
|
|
||||||
more_req = plugin_kwargs.get("advanced_arg", "")
|
|
||||||
no_cache = more_req.startswith("--no-cache")
|
|
||||||
if no_cache: more_req.lstrip("--no-cache")
|
|
||||||
allow_cache = not no_cache
|
|
||||||
_switch_prompt_ = partial(switch_prompt, more_requirement=more_req)
|
|
||||||
|
|
||||||
# <-------------- check deps ------------->
|
|
||||||
try:
|
|
||||||
import glob, os, time, subprocess
|
|
||||||
subprocess.Popen(['pdflatex', '-version'])
|
|
||||||
from .latex_fns.latex_actions import Latex精细分解与转化, 编译Latex
|
|
||||||
except Exception as e:
|
|
||||||
chatbot.append([ f"解析项目: {txt}",
|
|
||||||
f"尝试执行Latex指令失败。Latex没有安装, 或者不在环境变量PATH中。安装方法https://tug.org/texlive/。报错信息\n\n```\n\n{trimmed_format_exc()}\n\n```\n\n"])
|
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
|
||||||
return
|
|
||||||
|
|
||||||
|
|
||||||
# <-------------- clear history and read input ------------->
|
|
||||||
history = []
|
|
||||||
txt, arxiv_id = yield from arxiv_download(chatbot, history, txt, allow_cache)
|
|
||||||
if txt.endswith('.pdf'):
|
|
||||||
report_exception(chatbot, history, a = f"解析项目: {txt}", b = f"发现已经存在翻译好的PDF文档")
|
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
|
||||||
return
|
|
||||||
|
|
||||||
|
|
||||||
if os.path.exists(txt):
|
|
||||||
project_folder = txt
|
|
||||||
else:
|
|
||||||
if txt == "": txt = '空空如也的输入栏'
|
|
||||||
report_exception(chatbot, history, a = f"解析项目: {txt}", b = f"找不到本地项目或无法处理: {txt}")
|
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
|
||||||
return
|
|
||||||
|
|
||||||
file_manifest = [f for f in glob.glob(f'{project_folder}/**/*.tex', recursive=True)]
|
|
||||||
if len(file_manifest) == 0:
|
|
||||||
report_exception(chatbot, history, a = f"解析项目: {txt}", b = f"找不到任何.tex文件: {txt}")
|
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
|
||||||
return
|
|
||||||
|
|
||||||
|
|
||||||
# <-------------- if is a zip/tar file ------------->
|
|
||||||
project_folder = desend_to_extracted_folder_if_exist(project_folder)
|
|
||||||
|
|
||||||
|
|
||||||
# <-------------- move latex project away from temp folder ------------->
|
|
||||||
project_folder = move_project(project_folder, arxiv_id)
|
|
||||||
|
|
||||||
|
|
||||||
# <-------------- if merge_translate_zh is already generated, skip gpt req ------------->
|
|
||||||
if not os.path.exists(project_folder + '/merge_translate_zh.tex'):
|
|
||||||
yield from Latex精细分解与转化(file_manifest, project_folder, llm_kwargs, plugin_kwargs,
|
|
||||||
chatbot, history, system_prompt, mode='translate_zh', switch_prompt=_switch_prompt_)
|
|
||||||
|
|
||||||
|
|
||||||
# <-------------- compile PDF ------------->
|
|
||||||
success = yield from 编译Latex(chatbot, history, main_file_original='merge', main_file_modified='merge_translate_zh', mode='translate_zh',
|
|
||||||
work_folder_original=project_folder, work_folder_modified=project_folder, work_folder=project_folder)
|
|
||||||
|
|
||||||
# <-------------- zip PDF ------------->
|
|
||||||
zip_res = zip_result(project_folder)
|
|
||||||
if success:
|
|
||||||
chatbot.append((f"成功啦", '请查收结果(压缩包)...'))
|
|
||||||
yield from update_ui(chatbot=chatbot, history=history); time.sleep(1) # 刷新界面
|
|
||||||
promote_file_to_downloadzone(file=zip_res, chatbot=chatbot)
|
|
||||||
else:
|
|
||||||
chatbot.append((f"失败了", '虽然PDF生成失败了, 但请查收结果(压缩包), 内含已经翻译的Tex文档, 您可以到Github Issue区, 用该压缩包进行反馈。如系统是Linux,请检查系统字体(见Github wiki) ...'))
|
|
||||||
yield from update_ui(chatbot=chatbot, history=history); time.sleep(1) # 刷新界面
|
|
||||||
promote_file_to_downloadzone(file=zip_res, chatbot=chatbot)
|
|
||||||
|
|
||||||
|
|
||||||
# <-------------- we are done ------------->
|
|
||||||
return success
|
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
import glob, time, os, re, logging
|
import glob, shutil, os, re
|
||||||
from toolbox import update_ui, trimmed_format_exc, gen_time_str, disable_auto_promotion
|
from loguru import logger
|
||||||
|
from toolbox import update_ui, trimmed_format_exc, gen_time_str
|
||||||
from toolbox import CatchException, report_exception, get_log_folder
|
from toolbox import CatchException, report_exception, get_log_folder
|
||||||
from toolbox import write_history_to_file, promote_file_to_downloadzone
|
from toolbox import write_history_to_file, promote_file_to_downloadzone
|
||||||
fast_debug = False
|
fast_debug = False
|
||||||
@@ -18,7 +19,7 @@ class PaperFileGroup():
|
|||||||
def get_token_num(txt): return len(enc.encode(txt, disallowed_special=()))
|
def get_token_num(txt): return len(enc.encode(txt, disallowed_special=()))
|
||||||
self.get_token_num = get_token_num
|
self.get_token_num = get_token_num
|
||||||
|
|
||||||
def run_file_split(self, max_token_limit=1900):
|
def run_file_split(self, max_token_limit=2048):
|
||||||
"""
|
"""
|
||||||
将长文本分离开来
|
将长文本分离开来
|
||||||
"""
|
"""
|
||||||
@@ -34,7 +35,7 @@ class PaperFileGroup():
|
|||||||
self.sp_file_contents.append(segment)
|
self.sp_file_contents.append(segment)
|
||||||
self.sp_file_index.append(index)
|
self.sp_file_index.append(index)
|
||||||
self.sp_file_tag.append(self.file_paths[index] + f".part-{j}.md")
|
self.sp_file_tag.append(self.file_paths[index] + f".part-{j}.md")
|
||||||
logging.info('Segmentation: done')
|
logger.info('Segmentation: done')
|
||||||
|
|
||||||
def merge_result(self):
|
def merge_result(self):
|
||||||
self.file_result = ["" for _ in range(len(self.file_paths))]
|
self.file_result = ["" for _ in range(len(self.file_paths))]
|
||||||
@@ -51,7 +52,7 @@ class PaperFileGroup():
|
|||||||
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'):
|
||||||
from .crazy_utils import request_gpt_model_multi_threads_with_very_awesome_ui_and_high_efficiency
|
from crazy_functions.crazy_utils import request_gpt_model_multi_threads_with_very_awesome_ui_and_high_efficiency
|
||||||
|
|
||||||
# <-------- 读取Markdown文件,删除其中的所有注释 ---------->
|
# <-------- 读取Markdown文件,删除其中的所有注释 ---------->
|
||||||
pfg = PaperFileGroup()
|
pfg = PaperFileGroup()
|
||||||
@@ -64,25 +65,25 @@ def 多文件翻译(file_manifest, project_folder, llm_kwargs, plugin_kwargs, ch
|
|||||||
pfg.file_contents.append(file_content)
|
pfg.file_contents.append(file_content)
|
||||||
|
|
||||||
# <-------- 拆分过长的Markdown文件 ---------->
|
# <-------- 拆分过长的Markdown文件 ---------->
|
||||||
pfg.run_file_split(max_token_limit=1500)
|
pfg.run_file_split(max_token_limit=1024)
|
||||||
n_split = len(pfg.sp_file_contents)
|
n_split = len(pfg.sp_file_contents)
|
||||||
|
|
||||||
# <-------- 多线程翻译开始 ---------->
|
# <-------- 多线程翻译开始 ---------->
|
||||||
if language == 'en->zh':
|
if language == 'en->zh':
|
||||||
inputs_array = ["This is a Markdown file, translate it into Chinese, do not modify any existing Markdown commands:" +
|
inputs_array = ["This is a Markdown file, translate it into Chinese, do NOT modify any existing Markdown commands, do NOT use code wrapper (```), ONLY answer me with translated results:" +
|
||||||
f"\n\n{frag}" for frag in pfg.sp_file_contents]
|
f"\n\n{frag}" for frag in pfg.sp_file_contents]
|
||||||
inputs_show_user_array = [f"翻译 {f}" for f in pfg.sp_file_tag]
|
inputs_show_user_array = [f"翻译 {f}" for f in pfg.sp_file_tag]
|
||||||
sys_prompt_array = ["You are a professional academic paper translator." for _ in range(n_split)]
|
sys_prompt_array = ["You are a professional academic paper translator." + plugin_kwargs.get("additional_prompt", "") for _ in range(n_split)]
|
||||||
elif language == 'zh->en':
|
elif language == 'zh->en':
|
||||||
inputs_array = [f"This is a Markdown file, translate it into English, do not modify any existing Markdown commands:" +
|
inputs_array = [f"This is a Markdown file, translate it into English, do NOT modify any existing Markdown commands, do NOT use code wrapper (```), ONLY answer me with translated results:" +
|
||||||
f"\n\n{frag}" for frag in pfg.sp_file_contents]
|
f"\n\n{frag}" for frag in pfg.sp_file_contents]
|
||||||
inputs_show_user_array = [f"翻译 {f}" for f in pfg.sp_file_tag]
|
inputs_show_user_array = [f"翻译 {f}" for f in pfg.sp_file_tag]
|
||||||
sys_prompt_array = ["You are a professional academic paper translator." for _ in range(n_split)]
|
sys_prompt_array = ["You are a professional academic paper translator." + plugin_kwargs.get("additional_prompt", "") for _ in range(n_split)]
|
||||||
else:
|
else:
|
||||||
inputs_array = [f"This is a Markdown file, translate it into {language}, do not modify any existing Markdown commands, only answer me with translated results:" +
|
inputs_array = [f"This is a Markdown file, translate it into {language}, do NOT modify any existing Markdown commands, do NOT use code wrapper (```), ONLY answer me with translated results:" +
|
||||||
f"\n\n{frag}" for frag in pfg.sp_file_contents]
|
f"\n\n{frag}" for frag in pfg.sp_file_contents]
|
||||||
inputs_show_user_array = [f"翻译 {f}" for f in pfg.sp_file_tag]
|
inputs_show_user_array = [f"翻译 {f}" for f in pfg.sp_file_tag]
|
||||||
sys_prompt_array = ["You are a professional academic paper translator." for _ in range(n_split)]
|
sys_prompt_array = ["You are a professional academic paper translator." + plugin_kwargs.get("additional_prompt", "") for _ in range(n_split)]
|
||||||
|
|
||||||
gpt_response_collection = yield from request_gpt_model_multi_threads_with_very_awesome_ui_and_high_efficiency(
|
gpt_response_collection = yield from request_gpt_model_multi_threads_with_very_awesome_ui_and_high_efficiency(
|
||||||
inputs_array=inputs_array,
|
inputs_array=inputs_array,
|
||||||
@@ -99,9 +100,14 @@ def 多文件翻译(file_manifest, project_folder, llm_kwargs, plugin_kwargs, ch
|
|||||||
for i_say, gpt_say in zip(gpt_response_collection[0::2], gpt_response_collection[1::2]):
|
for i_say, gpt_say in zip(gpt_response_collection[0::2], gpt_response_collection[1::2]):
|
||||||
pfg.sp_file_result.append(gpt_say)
|
pfg.sp_file_result.append(gpt_say)
|
||||||
pfg.merge_result()
|
pfg.merge_result()
|
||||||
pfg.write_result(language)
|
output_file_arr = pfg.write_result(language)
|
||||||
|
for output_file in output_file_arr:
|
||||||
|
promote_file_to_downloadzone(output_file, chatbot=chatbot)
|
||||||
|
if 'markdown_expected_output_path' in plugin_kwargs:
|
||||||
|
expected_f_name = plugin_kwargs['markdown_expected_output_path']
|
||||||
|
shutil.copyfile(output_file, expected_f_name)
|
||||||
except:
|
except:
|
||||||
logging.error(trimmed_format_exc())
|
logger.error(trimmed_format_exc())
|
||||||
|
|
||||||
# <-------- 整理结果,退出 ---------->
|
# <-------- 整理结果,退出 ---------->
|
||||||
create_report_file_name = gen_time_str() + f"-chatgpt.md"
|
create_report_file_name = gen_time_str() + f"-chatgpt.md"
|
||||||
@@ -121,7 +127,7 @@ def get_files_from_everything(txt, preference=''):
|
|||||||
proxies = get_conf('proxies')
|
proxies = get_conf('proxies')
|
||||||
# 网络的远程文件
|
# 网络的远程文件
|
||||||
if preference == 'Github':
|
if preference == 'Github':
|
||||||
logging.info('正在从github下载资源 ...')
|
logger.info('正在从github下载资源 ...')
|
||||||
if not txt.endswith('.md'):
|
if not txt.endswith('.md'):
|
||||||
# Make a request to the GitHub API to retrieve the repository information
|
# Make a request to the GitHub API to retrieve the repository information
|
||||||
url = txt.replace("https://github.com/", "https://api.github.com/repos/") + '/readme'
|
url = txt.replace("https://github.com/", "https://api.github.com/repos/") + '/readme'
|
||||||
@@ -153,13 +159,12 @@ def get_files_from_everything(txt, preference=''):
|
|||||||
|
|
||||||
|
|
||||||
@CatchException
|
@CatchException
|
||||||
def Markdown英译中(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port):
|
def Markdown英译中(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request):
|
||||||
# 基本信息:功能、贡献者
|
# 基本信息:功能、贡献者
|
||||||
chatbot.append([
|
chatbot.append([
|
||||||
"函数插件功能?",
|
"函数插件功能?",
|
||||||
"对整个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:
|
||||||
@@ -193,13 +198,12 @@ def Markdown英译中(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_p
|
|||||||
|
|
||||||
|
|
||||||
@CatchException
|
@CatchException
|
||||||
def Markdown中译英(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port):
|
def Markdown中译英(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request):
|
||||||
# 基本信息:功能、贡献者
|
# 基本信息:功能、贡献者
|
||||||
chatbot.append([
|
chatbot.append([
|
||||||
"函数插件功能?",
|
"函数插件功能?",
|
||||||
"对整个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:
|
||||||
@@ -226,13 +230,12 @@ def Markdown中译英(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_p
|
|||||||
|
|
||||||
|
|
||||||
@CatchException
|
@CatchException
|
||||||
def Markdown翻译指定语言(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port):
|
def Markdown翻译指定语言(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request):
|
||||||
# 基本信息:功能、贡献者
|
# 基本信息:功能、贡献者
|
||||||
chatbot.append([
|
chatbot.append([
|
||||||
"函数插件功能?",
|
"函数插件功能?",
|
||||||
"对整个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:
|
||||||
83
crazy_functions/PDF_Translate.py
普通文件
83
crazy_functions/PDF_Translate.py
普通文件
@@ -0,0 +1,83 @@
|
|||||||
|
from toolbox import CatchException, check_packages, get_conf
|
||||||
|
from toolbox import update_ui, update_ui_lastest_msg, disable_auto_promotion
|
||||||
|
from toolbox import trimmed_format_exc_markdown
|
||||||
|
from crazy_functions.crazy_utils import get_files_from_everything
|
||||||
|
from crazy_functions.pdf_fns.parse_pdf import get_avail_grobid_url
|
||||||
|
from crazy_functions.pdf_fns.parse_pdf_via_doc2x import 解析PDF_基于DOC2X
|
||||||
|
from crazy_functions.pdf_fns.parse_pdf_legacy import 解析PDF_简单拆解
|
||||||
|
from crazy_functions.pdf_fns.parse_pdf_grobid import 解析PDF_基于GROBID
|
||||||
|
from shared_utils.colorful import *
|
||||||
|
|
||||||
|
@CatchException
|
||||||
|
def 批量翻译PDF文档(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request):
|
||||||
|
|
||||||
|
disable_auto_promotion(chatbot)
|
||||||
|
# 基本信息:功能、贡献者
|
||||||
|
chatbot.append([None, "插件功能:批量翻译PDF文档。函数插件贡献者: Binary-Husky"])
|
||||||
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
||||||
|
|
||||||
|
# 尝试导入依赖,如果缺少依赖,则给出安装建议
|
||||||
|
try:
|
||||||
|
check_packages(["fitz", "tiktoken", "scipdf"])
|
||||||
|
except:
|
||||||
|
chatbot.append([None, f"导入软件依赖失败。使用该模块需要额外依赖,安装方法```pip install --upgrade pymupdf tiktoken scipdf_parser```。"])
|
||||||
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
||||||
|
return
|
||||||
|
|
||||||
|
# 清空历史,以免输入溢出
|
||||||
|
history = []
|
||||||
|
success, file_manifest, project_folder = get_files_from_everything(txt, type='.pdf')
|
||||||
|
|
||||||
|
# 检测输入参数,如没有给定输入参数,直接退出
|
||||||
|
if (not success) and txt == "": txt = '空空如也的输入栏。提示:请先上传文件(把PDF文件拖入对话)。'
|
||||||
|
|
||||||
|
# 如果没找到任何文件
|
||||||
|
if len(file_manifest) == 0:
|
||||||
|
chatbot.append([None, f"找不到任何.pdf拓展名的文件: {txt}"])
|
||||||
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
||||||
|
return
|
||||||
|
|
||||||
|
# 开始正式执行任务
|
||||||
|
method = plugin_kwargs.get("pdf_parse_method", None)
|
||||||
|
if method == "DOC2X":
|
||||||
|
# ------- 第一种方法,效果最好,但是需要DOC2X服务 -------
|
||||||
|
DOC2X_API_KEY = get_conf("DOC2X_API_KEY")
|
||||||
|
if len(DOC2X_API_KEY) != 0:
|
||||||
|
try:
|
||||||
|
yield from 解析PDF_基于DOC2X(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, DOC2X_API_KEY, user_request)
|
||||||
|
return
|
||||||
|
except:
|
||||||
|
chatbot.append([None, f"DOC2X服务不可用,现在将执行效果稍差的旧版代码。{trimmed_format_exc_markdown()}"])
|
||||||
|
yield from update_ui(chatbot=chatbot, history=history)
|
||||||
|
|
||||||
|
if method == "GROBID":
|
||||||
|
# ------- 第二种方法,效果次优 -------
|
||||||
|
grobid_url = get_avail_grobid_url()
|
||||||
|
if grobid_url is not None:
|
||||||
|
yield from 解析PDF_基于GROBID(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, grobid_url)
|
||||||
|
return
|
||||||
|
|
||||||
|
if method == "ClASSIC":
|
||||||
|
# ------- 第三种方法,早期代码,效果不理想 -------
|
||||||
|
yield from update_ui_lastest_msg("GROBID服务不可用,请检查config中的GROBID_URL。作为替代,现在将执行效果稍差的旧版代码。", chatbot, history, delay=3)
|
||||||
|
yield from 解析PDF_简单拆解(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt)
|
||||||
|
return
|
||||||
|
|
||||||
|
if method is None:
|
||||||
|
# ------- 以上三种方法都试一遍 -------
|
||||||
|
DOC2X_API_KEY = get_conf("DOC2X_API_KEY")
|
||||||
|
if len(DOC2X_API_KEY) != 0:
|
||||||
|
try:
|
||||||
|
yield from 解析PDF_基于DOC2X(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, DOC2X_API_KEY, user_request)
|
||||||
|
return
|
||||||
|
except:
|
||||||
|
chatbot.append([None, f"DOC2X服务不可用,正在尝试GROBID。{trimmed_format_exc_markdown()}"])
|
||||||
|
yield from update_ui(chatbot=chatbot, history=history)
|
||||||
|
grobid_url = get_avail_grobid_url()
|
||||||
|
if grobid_url is not None:
|
||||||
|
yield from 解析PDF_基于GROBID(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, grobid_url)
|
||||||
|
return
|
||||||
|
yield from update_ui_lastest_msg("GROBID服务不可用,请检查config中的GROBID_URL。作为替代,现在将执行效果稍差的旧版代码。", chatbot, history, delay=3)
|
||||||
|
yield from 解析PDF_简单拆解(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt)
|
||||||
|
return
|
||||||
|
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
from crazy_functions.plugin_template.plugin_class_template import GptAcademicPluginTemplate, ArgProperty
|
||||||
|
from .PDF_Translate import 批量翻译PDF文档
|
||||||
|
|
||||||
|
|
||||||
|
class PDF_Tran(GptAcademicPluginTemplate):
|
||||||
|
def __init__(self):
|
||||||
|
"""
|
||||||
|
请注意`execute`会执行在不同的线程中,因此您在定义和使用类变量时,应当慎之又慎!
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
def define_arg_selection_menu(self):
|
||||||
|
"""
|
||||||
|
定义插件的二级选项菜单
|
||||||
|
"""
|
||||||
|
gui_definition = {
|
||||||
|
"main_input":
|
||||||
|
ArgProperty(title="PDF文件路径", description="未指定路径,请上传文件后,再点击该插件", default_value="", type="string").model_dump_json(), # 主输入,自动从输入框同步
|
||||||
|
"additional_prompt":
|
||||||
|
ArgProperty(title="额外提示词", description="例如:对专有名词、翻译语气等方面的要求", default_value="", type="string").model_dump_json(), # 高级参数输入区,自动同步
|
||||||
|
"pdf_parse_method":
|
||||||
|
ArgProperty(title="PDF解析方法", options=["DOC2X", "GROBID", "ClASSIC"], description="无", default_value="GROBID", type="dropdown").model_dump_json(),
|
||||||
|
}
|
||||||
|
return gui_definition
|
||||||
|
|
||||||
|
def execute(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request):
|
||||||
|
"""
|
||||||
|
执行插件
|
||||||
|
"""
|
||||||
|
main_input = plugin_kwargs["main_input"]
|
||||||
|
additional_prompt = plugin_kwargs["additional_prompt"]
|
||||||
|
pdf_parse_method = plugin_kwargs["pdf_parse_method"]
|
||||||
|
yield from 批量翻译PDF文档(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request)
|
||||||
92
crazy_functions/Rag_Interface.py
普通文件
92
crazy_functions/Rag_Interface.py
普通文件
@@ -0,0 +1,92 @@
|
|||||||
|
from toolbox import CatchException, update_ui, get_conf, get_log_folder, update_ui_lastest_msg
|
||||||
|
from crazy_functions.crazy_utils import input_clipping
|
||||||
|
from crazy_functions.crazy_utils import request_gpt_model_in_new_thread_with_ui_alive
|
||||||
|
|
||||||
|
RAG_WORKER_REGISTER = {}
|
||||||
|
MAX_HISTORY_ROUND = 5
|
||||||
|
MAX_CONTEXT_TOKEN_LIMIT = 4096
|
||||||
|
REMEMBER_PREVIEW = 1000
|
||||||
|
|
||||||
|
@CatchException
|
||||||
|
def Rag问答(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request):
|
||||||
|
|
||||||
|
# import vector store lib
|
||||||
|
VECTOR_STORE_TYPE = "Milvus"
|
||||||
|
if VECTOR_STORE_TYPE == "Milvus":
|
||||||
|
try:
|
||||||
|
from crazy_functions.rag_fns.milvus_worker import MilvusRagWorker as LlamaIndexRagWorker
|
||||||
|
except:
|
||||||
|
VECTOR_STORE_TYPE = "Simple"
|
||||||
|
if VECTOR_STORE_TYPE == "Simple":
|
||||||
|
from crazy_functions.rag_fns.llama_index_worker import LlamaIndexRagWorker
|
||||||
|
|
||||||
|
# 1. we retrieve rag worker from global context
|
||||||
|
user_name = chatbot.get_user()
|
||||||
|
checkpoint_dir = get_log_folder(user_name, plugin_name='experimental_rag')
|
||||||
|
if user_name in RAG_WORKER_REGISTER:
|
||||||
|
rag_worker = RAG_WORKER_REGISTER[user_name]
|
||||||
|
else:
|
||||||
|
rag_worker = RAG_WORKER_REGISTER[user_name] = LlamaIndexRagWorker(
|
||||||
|
user_name,
|
||||||
|
llm_kwargs,
|
||||||
|
checkpoint_dir=checkpoint_dir,
|
||||||
|
auto_load_checkpoint=True)
|
||||||
|
current_context = f"{VECTOR_STORE_TYPE} @ {checkpoint_dir}"
|
||||||
|
tip = "提示:输入“清空向量数据库”可以清空RAG向量数据库"
|
||||||
|
if txt == "清空向量数据库":
|
||||||
|
chatbot.append([txt, f'正在清空 ({current_context}) ...'])
|
||||||
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
||||||
|
rag_worker.purge()
|
||||||
|
yield from update_ui_lastest_msg('已清空', chatbot, history, delay=0) # 刷新界面
|
||||||
|
return
|
||||||
|
|
||||||
|
chatbot.append([txt, f'正在召回知识 ({current_context}) ...'])
|
||||||
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
||||||
|
|
||||||
|
# 2. clip history to reduce token consumption
|
||||||
|
# 2-1. reduce chat round
|
||||||
|
txt_origin = txt
|
||||||
|
|
||||||
|
if len(history) > MAX_HISTORY_ROUND * 2:
|
||||||
|
history = history[-(MAX_HISTORY_ROUND * 2):]
|
||||||
|
txt_clip, history, flags = input_clipping(txt, history, max_token_limit=MAX_CONTEXT_TOKEN_LIMIT, return_clip_flags=True)
|
||||||
|
input_is_clipped_flag = (flags["original_input_len"] != flags["clipped_input_len"])
|
||||||
|
|
||||||
|
# 2-2. if input is clipped, add input to vector store before retrieve
|
||||||
|
if input_is_clipped_flag:
|
||||||
|
yield from update_ui_lastest_msg('检测到长输入, 正在向量化 ...', chatbot, history, delay=0) # 刷新界面
|
||||||
|
# save input to vector store
|
||||||
|
rag_worker.add_text_to_vector_store(txt_origin)
|
||||||
|
yield from update_ui_lastest_msg('向量化完成 ...', chatbot, history, delay=0) # 刷新界面
|
||||||
|
if len(txt_origin) > REMEMBER_PREVIEW:
|
||||||
|
HALF = REMEMBER_PREVIEW//2
|
||||||
|
i_say_to_remember = txt[:HALF] + f" ...\n...(省略{len(txt_origin)-REMEMBER_PREVIEW}字)...\n... " + txt[-HALF:]
|
||||||
|
if (flags["original_input_len"] - flags["clipped_input_len"]) > HALF:
|
||||||
|
txt_clip = txt_clip + f" ...\n...(省略{len(txt_origin)-len(txt_clip)-HALF}字)...\n... " + txt[-HALF:]
|
||||||
|
else:
|
||||||
|
pass
|
||||||
|
i_say = txt_clip
|
||||||
|
else:
|
||||||
|
i_say_to_remember = i_say = txt_clip
|
||||||
|
else:
|
||||||
|
i_say_to_remember = i_say = txt_clip
|
||||||
|
|
||||||
|
# 3. we search vector store and build prompts
|
||||||
|
nodes = rag_worker.retrieve_from_store_with_query(i_say)
|
||||||
|
prompt = rag_worker.build_prompt(query=i_say, nodes=nodes)
|
||||||
|
|
||||||
|
# 4. it is time to query llms
|
||||||
|
if len(chatbot) != 0: chatbot.pop(-1) # pop temp chat, because we are going to add them again inside `request_gpt_model_in_new_thread_with_ui_alive`
|
||||||
|
model_say = yield from request_gpt_model_in_new_thread_with_ui_alive(
|
||||||
|
inputs=prompt, inputs_show_user=i_say,
|
||||||
|
llm_kwargs=llm_kwargs, chatbot=chatbot, history=history,
|
||||||
|
sys_prompt=system_prompt,
|
||||||
|
retry_times_at_unknown_error=0
|
||||||
|
)
|
||||||
|
|
||||||
|
# 5. remember what has been asked / answered
|
||||||
|
yield from update_ui_lastest_msg(model_say + '</br></br>' + f'对话记忆中, 请稍等 ({current_context}) ...', chatbot, history, delay=0.5) # 刷新界面
|
||||||
|
rag_worker.remember_qa(i_say_to_remember, model_say)
|
||||||
|
history.extend([i_say, model_say])
|
||||||
|
|
||||||
|
yield from update_ui_lastest_msg(model_say, chatbot, history, delay=0, msg=tip) # 刷新界面
|
||||||
167
crazy_functions/Social_Helper.py
普通文件
167
crazy_functions/Social_Helper.py
普通文件
@@ -0,0 +1,167 @@
|
|||||||
|
import pickle, os, random
|
||||||
|
from toolbox import CatchException, update_ui, get_conf, get_log_folder, update_ui_lastest_msg
|
||||||
|
from crazy_functions.crazy_utils import input_clipping
|
||||||
|
from crazy_functions.crazy_utils import request_gpt_model_in_new_thread_with_ui_alive
|
||||||
|
from request_llms.bridge_all import predict_no_ui_long_connection
|
||||||
|
from crazy_functions.json_fns.select_tool import structure_output, select_tool
|
||||||
|
from pydantic import BaseModel, Field
|
||||||
|
from loguru import logger
|
||||||
|
from typing import List
|
||||||
|
|
||||||
|
|
||||||
|
SOCIAL_NETWOK_WORKER_REGISTER = {}
|
||||||
|
|
||||||
|
class SocialNetwork():
|
||||||
|
def __init__(self):
|
||||||
|
self.people = []
|
||||||
|
|
||||||
|
class SaveAndLoad():
|
||||||
|
def __init__(self, user_name, llm_kwargs, auto_load_checkpoint=True, checkpoint_dir=None) -> None:
|
||||||
|
self.user_name = user_name
|
||||||
|
self.checkpoint_dir = checkpoint_dir
|
||||||
|
if auto_load_checkpoint:
|
||||||
|
self.social_network = self.load_from_checkpoint(checkpoint_dir)
|
||||||
|
else:
|
||||||
|
self.social_network = SocialNetwork()
|
||||||
|
|
||||||
|
def does_checkpoint_exist(self, checkpoint_dir=None):
|
||||||
|
import os, glob
|
||||||
|
if checkpoint_dir is None: checkpoint_dir = self.checkpoint_dir
|
||||||
|
if not os.path.exists(checkpoint_dir): return False
|
||||||
|
if len(glob.glob(os.path.join(checkpoint_dir, "social_network.pkl"))) == 0: return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
def save_to_checkpoint(self, checkpoint_dir=None):
|
||||||
|
if checkpoint_dir is None: checkpoint_dir = self.checkpoint_dir
|
||||||
|
with open(os.path.join(checkpoint_dir, 'social_network.pkl'), "wb+") as f:
|
||||||
|
pickle.dump(self.social_network, f)
|
||||||
|
return
|
||||||
|
|
||||||
|
def load_from_checkpoint(self, checkpoint_dir=None):
|
||||||
|
if checkpoint_dir is None: checkpoint_dir = self.checkpoint_dir
|
||||||
|
if self.does_checkpoint_exist(checkpoint_dir=checkpoint_dir):
|
||||||
|
with open(os.path.join(checkpoint_dir, 'social_network.pkl'), "rb") as f:
|
||||||
|
social_network = pickle.load(f)
|
||||||
|
return social_network
|
||||||
|
else:
|
||||||
|
return SocialNetwork()
|
||||||
|
|
||||||
|
|
||||||
|
class Friend(BaseModel):
|
||||||
|
friend_name: str = Field(description="name of a friend")
|
||||||
|
friend_description: str = Field(description="description of a friend (everything about this friend)")
|
||||||
|
friend_relationship: str = Field(description="The relationship with a friend (e.g. friend, family, colleague)")
|
||||||
|
|
||||||
|
class FriendList(BaseModel):
|
||||||
|
friends_list: List[Friend] = Field(description="The list of friends")
|
||||||
|
|
||||||
|
|
||||||
|
class SocialNetworkWorker(SaveAndLoad):
|
||||||
|
def ai_socail_advice(self, prompt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, run_gpt_fn, intention_type):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def ai_remove_friend(self, prompt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, run_gpt_fn, intention_type):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def ai_list_friends(self, prompt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, run_gpt_fn, intention_type):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def ai_add_multi_friends(self, prompt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, run_gpt_fn, intention_type):
|
||||||
|
friend, err_msg = structure_output(
|
||||||
|
txt=prompt,
|
||||||
|
prompt="根据提示, 解析多个联系人的身份信息\n\n",
|
||||||
|
err_msg=f"不能理解该联系人",
|
||||||
|
run_gpt_fn=run_gpt_fn,
|
||||||
|
pydantic_cls=FriendList
|
||||||
|
)
|
||||||
|
if friend.friends_list:
|
||||||
|
for f in friend.friends_list:
|
||||||
|
self.add_friend(f)
|
||||||
|
msg = f"成功添加{len(friend.friends_list)}个联系人: {str(friend.friends_list)}"
|
||||||
|
yield from update_ui_lastest_msg(lastmsg=msg, chatbot=chatbot, history=history, delay=0)
|
||||||
|
|
||||||
|
|
||||||
|
def run(self, txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request):
|
||||||
|
prompt = txt
|
||||||
|
run_gpt_fn = lambda inputs, sys_prompt: predict_no_ui_long_connection(inputs=inputs, llm_kwargs=llm_kwargs, history=[], sys_prompt=sys_prompt, observe_window=[])
|
||||||
|
self.tools_to_select = {
|
||||||
|
"SocialAdvice":{
|
||||||
|
"explain_to_llm": "如果用户希望获取社交指导,调用SocialAdvice生成一些社交建议",
|
||||||
|
"callback": self.ai_socail_advice,
|
||||||
|
},
|
||||||
|
"AddFriends":{
|
||||||
|
"explain_to_llm": "如果用户给出了联系人,调用AddMultiFriends把联系人添加到数据库",
|
||||||
|
"callback": self.ai_add_multi_friends,
|
||||||
|
},
|
||||||
|
"RemoveFriend":{
|
||||||
|
"explain_to_llm": "如果用户希望移除某个联系人,调用RemoveFriend",
|
||||||
|
"callback": self.ai_remove_friend,
|
||||||
|
},
|
||||||
|
"ListFriends":{
|
||||||
|
"explain_to_llm": "如果用户列举联系人,调用ListFriends",
|
||||||
|
"callback": self.ai_list_friends,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try:
|
||||||
|
Explaination = '\n'.join([f'{k}: {v["explain_to_llm"]}' for k, v in self.tools_to_select.items()])
|
||||||
|
class UserSociaIntention(BaseModel):
|
||||||
|
intention_type: str = Field(
|
||||||
|
description=
|
||||||
|
f"The type of user intention. You must choose from {self.tools_to_select.keys()}.\n\n"
|
||||||
|
f"Explaination:\n{Explaination}",
|
||||||
|
default="SocialAdvice"
|
||||||
|
)
|
||||||
|
pydantic_cls_instance, err_msg = select_tool(
|
||||||
|
prompt=txt,
|
||||||
|
run_gpt_fn=run_gpt_fn,
|
||||||
|
pydantic_cls=UserSociaIntention
|
||||||
|
)
|
||||||
|
except Exception as e:
|
||||||
|
yield from update_ui_lastest_msg(
|
||||||
|
lastmsg=f"无法理解用户意图 {err_msg}",
|
||||||
|
chatbot=chatbot,
|
||||||
|
history=history,
|
||||||
|
delay=0
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
intention_type = pydantic_cls_instance.intention_type
|
||||||
|
intention_callback = self.tools_to_select[pydantic_cls_instance.intention_type]['callback']
|
||||||
|
yield from intention_callback(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, run_gpt_fn, intention_type)
|
||||||
|
|
||||||
|
|
||||||
|
def add_friend(self, friend):
|
||||||
|
# check whether the friend is already in the social network
|
||||||
|
for f in self.social_network.people:
|
||||||
|
if f.friend_name == friend.friend_name:
|
||||||
|
f.friend_description = friend.friend_description
|
||||||
|
f.friend_relationship = friend.friend_relationship
|
||||||
|
logger.info(f"Repeated friend, update info: {friend}")
|
||||||
|
return
|
||||||
|
logger.info(f"Add a new friend: {friend}")
|
||||||
|
self.social_network.people.append(friend)
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
@CatchException
|
||||||
|
def I人助手(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request):
|
||||||
|
|
||||||
|
# 1. we retrieve worker from global context
|
||||||
|
user_name = chatbot.get_user()
|
||||||
|
checkpoint_dir=get_log_folder(user_name, plugin_name='experimental_rag')
|
||||||
|
if user_name in SOCIAL_NETWOK_WORKER_REGISTER:
|
||||||
|
social_network_worker = SOCIAL_NETWOK_WORKER_REGISTER[user_name]
|
||||||
|
else:
|
||||||
|
social_network_worker = SOCIAL_NETWOK_WORKER_REGISTER[user_name] = SocialNetworkWorker(
|
||||||
|
user_name,
|
||||||
|
llm_kwargs,
|
||||||
|
checkpoint_dir=checkpoint_dir,
|
||||||
|
auto_load_checkpoint=True
|
||||||
|
)
|
||||||
|
|
||||||
|
# 2. save
|
||||||
|
yield from social_network_worker.run(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request)
|
||||||
|
social_network_worker.save_to_checkpoint(checkpoint_dir)
|
||||||
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
||||||
|
|
||||||
@@ -1,12 +1,12 @@
|
|||||||
from toolbox import update_ui, promote_file_to_downloadzone, disable_auto_promotion
|
from toolbox import update_ui, promote_file_to_downloadzone
|
||||||
from toolbox import CatchException, report_exception, write_history_to_file
|
from toolbox import CatchException, report_exception, write_history_to_file
|
||||||
from .crazy_utils import input_clipping
|
from shared_utils.fastapi_server import validate_path_safety
|
||||||
|
from crazy_functions.crazy_utils import input_clipping
|
||||||
|
|
||||||
def 解析源代码新(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt):
|
def 解析源代码新(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt):
|
||||||
import os, copy
|
import os, copy
|
||||||
from .crazy_utils import request_gpt_model_multi_threads_with_very_awesome_ui_and_high_efficiency
|
from crazy_functions.crazy_utils import request_gpt_model_multi_threads_with_very_awesome_ui_and_high_efficiency
|
||||||
from .crazy_utils import request_gpt_model_in_new_thread_with_ui_alive
|
from crazy_functions.crazy_utils import request_gpt_model_in_new_thread_with_ui_alive
|
||||||
disable_auto_promotion(chatbot=chatbot)
|
|
||||||
|
|
||||||
summary_batch_isolation = True
|
summary_batch_isolation = True
|
||||||
inputs_array = []
|
inputs_array = []
|
||||||
@@ -23,7 +23,7 @@ def 解析源代码新(file_manifest, project_folder, llm_kwargs, plugin_kwargs,
|
|||||||
file_content = f.read()
|
file_content = f.read()
|
||||||
prefix = "接下来请你逐文件分析下面的工程" if index==0 else ""
|
prefix = "接下来请你逐文件分析下面的工程" if index==0 else ""
|
||||||
i_say = prefix + f'请对下面的程序文件做一个概述文件名是{os.path.relpath(fp, project_folder)},文件代码是 ```{file_content}```'
|
i_say = prefix + f'请对下面的程序文件做一个概述文件名是{os.path.relpath(fp, project_folder)},文件代码是 ```{file_content}```'
|
||||||
i_say_show_user = prefix + f'[{index}/{len(file_manifest)}] 请对下面的程序文件做一个概述: {fp}'
|
i_say_show_user = prefix + f'[{index+1}/{len(file_manifest)}] 请对下面的程序文件做一个概述: {fp}'
|
||||||
# 装载请求内容
|
# 装载请求内容
|
||||||
inputs_array.append(i_say)
|
inputs_array.append(i_say)
|
||||||
inputs_show_user_array.append(i_say_show_user)
|
inputs_show_user_array.append(i_say_show_user)
|
||||||
@@ -83,7 +83,8 @@ def 解析源代码新(file_manifest, project_folder, llm_kwargs, plugin_kwargs,
|
|||||||
history=this_iteration_history_feed, # 迭代之前的分析
|
history=this_iteration_history_feed, # 迭代之前的分析
|
||||||
sys_prompt="你是一个程序架构分析师,正在分析一个项目的源代码。" + sys_prompt_additional)
|
sys_prompt="你是一个程序架构分析师,正在分析一个项目的源代码。" + sys_prompt_additional)
|
||||||
|
|
||||||
summary = "请用一句话概括这些文件的整体功能"
|
diagram_code = make_diagram(this_iteration_files, result, this_iteration_history_feed)
|
||||||
|
summary = "请用一句话概括这些文件的整体功能。\n\n" + diagram_code
|
||||||
summary_result = yield from request_gpt_model_in_new_thread_with_ui_alive(
|
summary_result = yield from request_gpt_model_in_new_thread_with_ui_alive(
|
||||||
inputs=summary,
|
inputs=summary,
|
||||||
inputs_show_user=summary,
|
inputs_show_user=summary,
|
||||||
@@ -104,9 +105,12 @@ def 解析源代码新(file_manifest, project_folder, llm_kwargs, plugin_kwargs,
|
|||||||
chatbot.append(("完成了吗?", res))
|
chatbot.append(("完成了吗?", res))
|
||||||
yield from update_ui(chatbot=chatbot, history=history_to_return) # 刷新界面
|
yield from update_ui(chatbot=chatbot, history=history_to_return) # 刷新界面
|
||||||
|
|
||||||
|
def make_diagram(this_iteration_files, result, this_iteration_history_feed):
|
||||||
|
from crazy_functions.diagram_fns.file_tree import build_file_tree_mermaid_diagram
|
||||||
|
return build_file_tree_mermaid_diagram(this_iteration_history_feed[0::2], this_iteration_history_feed[1::2], "项目示意图")
|
||||||
|
|
||||||
@CatchException
|
@CatchException
|
||||||
def 解析项目本身(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port):
|
def 解析项目本身(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request):
|
||||||
history = [] # 清空历史,以免输入溢出
|
history = [] # 清空历史,以免输入溢出
|
||||||
import glob
|
import glob
|
||||||
file_manifest = [f for f in glob.glob('./*.py')] + \
|
file_manifest = [f for f in glob.glob('./*.py')] + \
|
||||||
@@ -119,11 +123,12 @@ def 解析项目本身(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_
|
|||||||
yield from 解析源代码新(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt)
|
yield from 解析源代码新(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt)
|
||||||
|
|
||||||
@CatchException
|
@CatchException
|
||||||
def 解析一个Python项目(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port):
|
def 解析一个Python项目(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request):
|
||||||
history = [] # 清空历史,以免输入溢出
|
history = [] # 清空历史,以免输入溢出
|
||||||
import glob, os
|
import glob, os
|
||||||
if os.path.exists(txt):
|
if os.path.exists(txt):
|
||||||
project_folder = txt
|
project_folder = txt
|
||||||
|
validate_path_safety(project_folder, chatbot.get_user())
|
||||||
else:
|
else:
|
||||||
if txt == "": txt = '空空如也的输入栏'
|
if txt == "": txt = '空空如也的输入栏'
|
||||||
report_exception(chatbot, history, a = f"解析项目: {txt}", b = f"找不到本地项目或无权访问: {txt}")
|
report_exception(chatbot, history, a = f"解析项目: {txt}", b = f"找不到本地项目或无权访问: {txt}")
|
||||||
@@ -137,11 +142,12 @@ def 解析一个Python项目(txt, llm_kwargs, plugin_kwargs, chatbot, history, s
|
|||||||
yield from 解析源代码新(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt)
|
yield from 解析源代码新(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt)
|
||||||
|
|
||||||
@CatchException
|
@CatchException
|
||||||
def 解析一个Matlab项目(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port):
|
def 解析一个Matlab项目(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request):
|
||||||
history = [] # 清空历史,以免输入溢出
|
history = [] # 清空历史,以免输入溢出
|
||||||
import glob, os
|
import glob, os
|
||||||
if os.path.exists(txt):
|
if os.path.exists(txt):
|
||||||
project_folder = txt
|
project_folder = txt
|
||||||
|
validate_path_safety(project_folder, chatbot.get_user())
|
||||||
else:
|
else:
|
||||||
if txt == "": txt = '空空如也的输入栏'
|
if txt == "": txt = '空空如也的输入栏'
|
||||||
report_exception(chatbot, history, a = f"解析Matlab项目: {txt}", b = f"找不到本地项目或无权访问: {txt}")
|
report_exception(chatbot, history, a = f"解析Matlab项目: {txt}", b = f"找不到本地项目或无权访问: {txt}")
|
||||||
@@ -155,11 +161,12 @@ def 解析一个Matlab项目(txt, llm_kwargs, plugin_kwargs, chatbot, history, s
|
|||||||
yield from 解析源代码新(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt)
|
yield from 解析源代码新(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt)
|
||||||
|
|
||||||
@CatchException
|
@CatchException
|
||||||
def 解析一个C项目的头文件(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port):
|
def 解析一个C项目的头文件(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request):
|
||||||
history = [] # 清空历史,以免输入溢出
|
history = [] # 清空历史,以免输入溢出
|
||||||
import glob, os
|
import glob, os
|
||||||
if os.path.exists(txt):
|
if os.path.exists(txt):
|
||||||
project_folder = txt
|
project_folder = txt
|
||||||
|
validate_path_safety(project_folder, chatbot.get_user())
|
||||||
else:
|
else:
|
||||||
if txt == "": txt = '空空如也的输入栏'
|
if txt == "": txt = '空空如也的输入栏'
|
||||||
report_exception(chatbot, history, a = f"解析项目: {txt}", b = f"找不到本地项目或无权访问: {txt}")
|
report_exception(chatbot, history, a = f"解析项目: {txt}", b = f"找不到本地项目或无权访问: {txt}")
|
||||||
@@ -175,11 +182,12 @@ def 解析一个C项目的头文件(txt, llm_kwargs, plugin_kwargs, chatbot, his
|
|||||||
yield from 解析源代码新(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt)
|
yield from 解析源代码新(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt)
|
||||||
|
|
||||||
@CatchException
|
@CatchException
|
||||||
def 解析一个C项目(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port):
|
def 解析一个C项目(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request):
|
||||||
history = [] # 清空历史,以免输入溢出
|
history = [] # 清空历史,以免输入溢出
|
||||||
import glob, os
|
import glob, os
|
||||||
if os.path.exists(txt):
|
if os.path.exists(txt):
|
||||||
project_folder = txt
|
project_folder = txt
|
||||||
|
validate_path_safety(project_folder, chatbot.get_user())
|
||||||
else:
|
else:
|
||||||
if txt == "": txt = '空空如也的输入栏'
|
if txt == "": txt = '空空如也的输入栏'
|
||||||
report_exception(chatbot, history, a = f"解析项目: {txt}", b = f"找不到本地项目或无权访问: {txt}")
|
report_exception(chatbot, history, a = f"解析项目: {txt}", b = f"找不到本地项目或无权访问: {txt}")
|
||||||
@@ -197,11 +205,12 @@ def 解析一个C项目(txt, llm_kwargs, plugin_kwargs, chatbot, history, system
|
|||||||
|
|
||||||
|
|
||||||
@CatchException
|
@CatchException
|
||||||
def 解析一个Java项目(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port):
|
def 解析一个Java项目(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request):
|
||||||
history = [] # 清空历史,以免输入溢出
|
history = [] # 清空历史,以免输入溢出
|
||||||
import glob, os
|
import glob, os
|
||||||
if os.path.exists(txt):
|
if os.path.exists(txt):
|
||||||
project_folder = txt
|
project_folder = txt
|
||||||
|
validate_path_safety(project_folder, chatbot.get_user())
|
||||||
else:
|
else:
|
||||||
if txt == "": txt = '空空如也的输入栏'
|
if txt == "": txt = '空空如也的输入栏'
|
||||||
report_exception(chatbot, history, a=f"解析项目: {txt}", b=f"找不到本地项目或无权访问: {txt}")
|
report_exception(chatbot, history, a=f"解析项目: {txt}", b=f"找不到本地项目或无权访问: {txt}")
|
||||||
@@ -219,11 +228,12 @@ def 解析一个Java项目(txt, llm_kwargs, plugin_kwargs, chatbot, history, sys
|
|||||||
|
|
||||||
|
|
||||||
@CatchException
|
@CatchException
|
||||||
def 解析一个前端项目(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port):
|
def 解析一个前端项目(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request):
|
||||||
history = [] # 清空历史,以免输入溢出
|
history = [] # 清空历史,以免输入溢出
|
||||||
import glob, os
|
import glob, os
|
||||||
if os.path.exists(txt):
|
if os.path.exists(txt):
|
||||||
project_folder = txt
|
project_folder = txt
|
||||||
|
validate_path_safety(project_folder, chatbot.get_user())
|
||||||
else:
|
else:
|
||||||
if txt == "": txt = '空空如也的输入栏'
|
if txt == "": txt = '空空如也的输入栏'
|
||||||
report_exception(chatbot, history, a=f"解析项目: {txt}", b=f"找不到本地项目或无权访问: {txt}")
|
report_exception(chatbot, history, a=f"解析项目: {txt}", b=f"找不到本地项目或无权访问: {txt}")
|
||||||
@@ -248,11 +258,12 @@ def 解析一个前端项目(txt, llm_kwargs, plugin_kwargs, chatbot, history, s
|
|||||||
|
|
||||||
|
|
||||||
@CatchException
|
@CatchException
|
||||||
def 解析一个Golang项目(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port):
|
def 解析一个Golang项目(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request):
|
||||||
history = [] # 清空历史,以免输入溢出
|
history = [] # 清空历史,以免输入溢出
|
||||||
import glob, os
|
import glob, os
|
||||||
if os.path.exists(txt):
|
if os.path.exists(txt):
|
||||||
project_folder = txt
|
project_folder = txt
|
||||||
|
validate_path_safety(project_folder, chatbot.get_user())
|
||||||
else:
|
else:
|
||||||
if txt == "": txt = '空空如也的输入栏'
|
if txt == "": txt = '空空如也的输入栏'
|
||||||
report_exception(chatbot, history, a=f"解析项目: {txt}", b=f"找不到本地项目或无权访问: {txt}")
|
report_exception(chatbot, history, a=f"解析项目: {txt}", b=f"找不到本地项目或无权访问: {txt}")
|
||||||
@@ -269,11 +280,12 @@ def 解析一个Golang项目(txt, llm_kwargs, plugin_kwargs, chatbot, history, s
|
|||||||
yield from 解析源代码新(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt)
|
yield from 解析源代码新(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt)
|
||||||
|
|
||||||
@CatchException
|
@CatchException
|
||||||
def 解析一个Rust项目(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port):
|
def 解析一个Rust项目(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request):
|
||||||
history = [] # 清空历史,以免输入溢出
|
history = [] # 清空历史,以免输入溢出
|
||||||
import glob, os
|
import glob, os
|
||||||
if os.path.exists(txt):
|
if os.path.exists(txt):
|
||||||
project_folder = txt
|
project_folder = txt
|
||||||
|
validate_path_safety(project_folder, chatbot.get_user())
|
||||||
else:
|
else:
|
||||||
if txt == "": txt = '空空如也的输入栏'
|
if txt == "": txt = '空空如也的输入栏'
|
||||||
report_exception(chatbot, history, a=f"解析项目: {txt}", b=f"找不到本地项目或无权访问: {txt}")
|
report_exception(chatbot, history, a=f"解析项目: {txt}", b=f"找不到本地项目或无权访问: {txt}")
|
||||||
@@ -289,11 +301,12 @@ def 解析一个Rust项目(txt, llm_kwargs, plugin_kwargs, chatbot, history, sys
|
|||||||
yield from 解析源代码新(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt)
|
yield from 解析源代码新(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt)
|
||||||
|
|
||||||
@CatchException
|
@CatchException
|
||||||
def 解析一个Lua项目(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port):
|
def 解析一个Lua项目(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request):
|
||||||
history = [] # 清空历史,以免输入溢出
|
history = [] # 清空历史,以免输入溢出
|
||||||
import glob, os
|
import glob, os
|
||||||
if os.path.exists(txt):
|
if os.path.exists(txt):
|
||||||
project_folder = txt
|
project_folder = txt
|
||||||
|
validate_path_safety(project_folder, chatbot.get_user())
|
||||||
else:
|
else:
|
||||||
if txt == "": txt = '空空如也的输入栏'
|
if txt == "": txt = '空空如也的输入栏'
|
||||||
report_exception(chatbot, history, a = f"解析项目: {txt}", b = f"找不到本地项目或无权访问: {txt}")
|
report_exception(chatbot, history, a = f"解析项目: {txt}", b = f"找不到本地项目或无权访问: {txt}")
|
||||||
@@ -311,11 +324,12 @@ def 解析一个Lua项目(txt, llm_kwargs, plugin_kwargs, chatbot, history, syst
|
|||||||
|
|
||||||
|
|
||||||
@CatchException
|
@CatchException
|
||||||
def 解析一个CSharp项目(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port):
|
def 解析一个CSharp项目(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request):
|
||||||
history = [] # 清空历史,以免输入溢出
|
history = [] # 清空历史,以免输入溢出
|
||||||
import glob, os
|
import glob, os
|
||||||
if os.path.exists(txt):
|
if os.path.exists(txt):
|
||||||
project_folder = txt
|
project_folder = txt
|
||||||
|
validate_path_safety(project_folder, chatbot.get_user())
|
||||||
else:
|
else:
|
||||||
if txt == "": txt = '空空如也的输入栏'
|
if txt == "": txt = '空空如也的输入栏'
|
||||||
report_exception(chatbot, history, a = f"解析项目: {txt}", b = f"找不到本地项目或无权访问: {txt}")
|
report_exception(chatbot, history, a = f"解析项目: {txt}", b = f"找不到本地项目或无权访问: {txt}")
|
||||||
@@ -331,7 +345,7 @@ def 解析一个CSharp项目(txt, llm_kwargs, plugin_kwargs, chatbot, history, s
|
|||||||
|
|
||||||
|
|
||||||
@CatchException
|
@CatchException
|
||||||
def 解析任意code项目(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port):
|
def 解析任意code项目(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request):
|
||||||
txt_pattern = plugin_kwargs.get("advanced_arg")
|
txt_pattern = plugin_kwargs.get("advanced_arg")
|
||||||
txt_pattern = txt_pattern.replace(",", ",")
|
txt_pattern = txt_pattern.replace(",", ",")
|
||||||
# 将要匹配的模式(例如: *.c, *.cpp, *.py, config.toml)
|
# 将要匹配的模式(例如: *.c, *.cpp, *.py, config.toml)
|
||||||
@@ -341,15 +355,19 @@ def 解析任意code项目(txt, llm_kwargs, plugin_kwargs, chatbot, history, sys
|
|||||||
pattern_except_suffix = [_.lstrip(" ^*.,").rstrip(" ,") for _ in txt_pattern.split(" ") if _ != "" and _.strip().startswith("^*.")]
|
pattern_except_suffix = [_.lstrip(" ^*.,").rstrip(" ,") for _ in txt_pattern.split(" ") if _ != "" and _.strip().startswith("^*.")]
|
||||||
pattern_except_suffix += ['zip', 'rar', '7z', 'tar', 'gz'] # 避免解析压缩文件
|
pattern_except_suffix += ['zip', 'rar', '7z', 'tar', 'gz'] # 避免解析压缩文件
|
||||||
# 将要忽略匹配的文件名(例如: ^README.md)
|
# 将要忽略匹配的文件名(例如: ^README.md)
|
||||||
pattern_except_name = [_.lstrip(" ^*,").rstrip(" ,").replace(".", "\.") for _ in txt_pattern.split(" ") if _ != "" and _.strip().startswith("^") and not _.strip().startswith("^*.")]
|
pattern_except_name = [_.lstrip(" ^*,").rstrip(" ,").replace(".", r"\.") # 移除左边通配符,移除右侧逗号,转义点号
|
||||||
|
for _ in txt_pattern.split(" ") # 以空格分割
|
||||||
|
if (_ != "" and _.strip().startswith("^") and not _.strip().startswith("^*.")) # ^开始,但不是^*.开始
|
||||||
|
]
|
||||||
# 生成正则表达式
|
# 生成正则表达式
|
||||||
pattern_except = '/[^/]+\.(' + "|".join(pattern_except_suffix) + ')$'
|
pattern_except = r'/[^/]+\.(' + "|".join(pattern_except_suffix) + ')$'
|
||||||
pattern_except += '|/(' + "|".join(pattern_except_name) + ')$' if pattern_except_name != [] else ''
|
pattern_except += '|/(' + "|".join(pattern_except_name) + ')$' if pattern_except_name != [] else ''
|
||||||
|
|
||||||
history.clear()
|
history.clear()
|
||||||
import glob, os, re
|
import glob, os, re
|
||||||
if os.path.exists(txt):
|
if os.path.exists(txt):
|
||||||
project_folder = txt
|
project_folder = txt
|
||||||
|
validate_path_safety(project_folder, chatbot.get_user())
|
||||||
else:
|
else:
|
||||||
if txt == "": txt = '空空如也的输入栏'
|
if txt == "": txt = '空空如也的输入栏'
|
||||||
report_exception(chatbot, history, a = f"解析项目: {txt}", b = f"找不到本地项目或无权访问: {txt}")
|
report_exception(chatbot, history, a = f"解析项目: {txt}", b = f"找不到本地项目或无权访问: {txt}")
|
||||||
@@ -0,0 +1,162 @@
|
|||||||
|
import os, copy, time
|
||||||
|
from toolbox import CatchException, report_exception, update_ui, zip_result, promote_file_to_downloadzone, update_ui_lastest_msg, get_conf, generate_file_link
|
||||||
|
from shared_utils.fastapi_server import validate_path_safety
|
||||||
|
from crazy_functions.crazy_utils import input_clipping
|
||||||
|
from crazy_functions.crazy_utils import request_gpt_model_multi_threads_with_very_awesome_ui_and_high_efficiency
|
||||||
|
from crazy_functions.crazy_utils import request_gpt_model_in_new_thread_with_ui_alive
|
||||||
|
from crazy_functions.agent_fns.python_comment_agent import PythonCodeComment
|
||||||
|
from crazy_functions.diagram_fns.file_tree import FileNode
|
||||||
|
from crazy_functions.agent_fns.watchdog import WatchDog
|
||||||
|
from shared_utils.advanced_markdown_format import markdown_convertion_for_file
|
||||||
|
from loguru import logger
|
||||||
|
|
||||||
|
|
||||||
|
def 注释源代码(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt):
|
||||||
|
|
||||||
|
summary_batch_isolation = True
|
||||||
|
inputs_array = []
|
||||||
|
inputs_show_user_array = []
|
||||||
|
history_array = []
|
||||||
|
sys_prompt_array = []
|
||||||
|
|
||||||
|
assert len(file_manifest) <= 512, "源文件太多(超过512个), 请缩减输入文件的数量。或者,您也可以选择删除此行警告,并修改代码拆分file_manifest列表,从而实现分批次处理。"
|
||||||
|
|
||||||
|
# 建立文件树
|
||||||
|
file_tree_struct = FileNode("root", build_manifest=True)
|
||||||
|
for file_path in file_manifest:
|
||||||
|
file_tree_struct.add_file(file_path, file_path)
|
||||||
|
|
||||||
|
# <第一步,逐个文件分析,多线程>
|
||||||
|
lang = "" if not plugin_kwargs["use_chinese"] else " (you must use Chinese)"
|
||||||
|
for index, fp in enumerate(file_manifest):
|
||||||
|
# 读取文件
|
||||||
|
with open(fp, 'r', encoding='utf-8', errors='replace') as f:
|
||||||
|
file_content = f.read()
|
||||||
|
prefix = ""
|
||||||
|
i_say = prefix + f'Please conclude the following source code at {os.path.relpath(fp, project_folder)} with only one sentence{lang}, the code is:\n```{file_content}```'
|
||||||
|
i_say_show_user = prefix + f'[{index+1}/{len(file_manifest)}] 请用一句话对下面的程序文件做一个整体概述: {fp}'
|
||||||
|
# 装载请求内容
|
||||||
|
MAX_TOKEN_SINGLE_FILE = 2560
|
||||||
|
i_say, _ = input_clipping(inputs=i_say, history=[], max_token_limit=MAX_TOKEN_SINGLE_FILE)
|
||||||
|
inputs_array.append(i_say)
|
||||||
|
inputs_show_user_array.append(i_say_show_user)
|
||||||
|
history_array.append([])
|
||||||
|
sys_prompt_array.append(f"You are a software architecture analyst analyzing a source code project. Do not dig into details, tell me what the code is doing in general. Your answer must be short, simple and clear{lang}.")
|
||||||
|
# 文件读取完成,对每一个源代码文件,生成一个请求线程,发送到大模型进行分析
|
||||||
|
gpt_response_collection = yield from request_gpt_model_multi_threads_with_very_awesome_ui_and_high_efficiency(
|
||||||
|
inputs_array = inputs_array,
|
||||||
|
inputs_show_user_array = inputs_show_user_array,
|
||||||
|
history_array = history_array,
|
||||||
|
sys_prompt_array = sys_prompt_array,
|
||||||
|
llm_kwargs = llm_kwargs,
|
||||||
|
chatbot = chatbot,
|
||||||
|
show_user_at_complete = True
|
||||||
|
)
|
||||||
|
|
||||||
|
# <第二步,逐个文件分析,生成带注释文件>
|
||||||
|
tasks = ["" for _ in range(len(file_manifest))]
|
||||||
|
def bark_fn(tasks):
|
||||||
|
for i in range(len(tasks)): tasks[i] = "watchdog is dead"
|
||||||
|
wd = WatchDog(timeout=10, bark_fn=lambda: bark_fn(tasks), interval=3, msg="ThreadWatcher timeout")
|
||||||
|
wd.begin_watch()
|
||||||
|
from concurrent.futures import ThreadPoolExecutor
|
||||||
|
executor = ThreadPoolExecutor(max_workers=get_conf('DEFAULT_WORKER_NUM'))
|
||||||
|
def _task_multi_threading(i_say, gpt_say, fp, file_tree_struct, index):
|
||||||
|
language = 'Chinese' if plugin_kwargs["use_chinese"] else 'English'
|
||||||
|
def observe_window_update(x):
|
||||||
|
if tasks[index] == "watchdog is dead":
|
||||||
|
raise TimeoutError("ThreadWatcher: watchdog is dead")
|
||||||
|
tasks[index] = x
|
||||||
|
pcc = PythonCodeComment(llm_kwargs, plugin_kwargs, language=language, observe_window_update=observe_window_update)
|
||||||
|
pcc.read_file(path=fp, brief=gpt_say)
|
||||||
|
revised_path, revised_content = pcc.begin_comment_source_code(None, None)
|
||||||
|
file_tree_struct.manifest[fp].revised_path = revised_path
|
||||||
|
file_tree_struct.manifest[fp].revised_content = revised_content
|
||||||
|
# <将结果写回源文件>
|
||||||
|
with open(fp, 'w', encoding='utf-8') as f:
|
||||||
|
f.write(file_tree_struct.manifest[fp].revised_content)
|
||||||
|
# <生成对比html>
|
||||||
|
with open("crazy_functions/agent_fns/python_comment_compare.html", 'r', encoding='utf-8') as f:
|
||||||
|
html_template = f.read()
|
||||||
|
warp = lambda x: "```python\n\n" + x + "\n\n```"
|
||||||
|
from themes.theme import load_dynamic_theme
|
||||||
|
_, advanced_css, _, _ = load_dynamic_theme("Default")
|
||||||
|
html_template = html_template.replace("ADVANCED_CSS", advanced_css)
|
||||||
|
html_template = html_template.replace("REPLACE_CODE_FILE_LEFT", pcc.get_markdown_block_in_html(markdown_convertion_for_file(warp(pcc.original_content))))
|
||||||
|
html_template = html_template.replace("REPLACE_CODE_FILE_RIGHT", pcc.get_markdown_block_in_html(markdown_convertion_for_file(warp(revised_content))))
|
||||||
|
compare_html_path = fp + '.compare.html'
|
||||||
|
file_tree_struct.manifest[fp].compare_html = compare_html_path
|
||||||
|
with open(compare_html_path, 'w', encoding='utf-8') as f:
|
||||||
|
f.write(html_template)
|
||||||
|
tasks[index] = ""
|
||||||
|
|
||||||
|
chatbot.append([None, f"正在处理:"])
|
||||||
|
futures = []
|
||||||
|
index = 0
|
||||||
|
for i_say, gpt_say, fp in zip(gpt_response_collection[0::2], gpt_response_collection[1::2], file_manifest):
|
||||||
|
future = executor.submit(_task_multi_threading, i_say, gpt_say, fp, file_tree_struct, index)
|
||||||
|
index += 1
|
||||||
|
futures.append(future)
|
||||||
|
|
||||||
|
# <第三步,等待任务完成>
|
||||||
|
cnt = 0
|
||||||
|
while True:
|
||||||
|
cnt += 1
|
||||||
|
wd.feed()
|
||||||
|
time.sleep(3)
|
||||||
|
worker_done = [h.done() for h in futures]
|
||||||
|
remain = len(worker_done) - sum(worker_done)
|
||||||
|
|
||||||
|
# <展示已经完成的部分>
|
||||||
|
preview_html_list = []
|
||||||
|
for done, fp in zip(worker_done, file_manifest):
|
||||||
|
if not done: continue
|
||||||
|
if hasattr(file_tree_struct.manifest[fp], 'compare_html'):
|
||||||
|
preview_html_list.append(file_tree_struct.manifest[fp].compare_html)
|
||||||
|
else:
|
||||||
|
logger.error(f"文件: {fp} 的注释结果未能成功")
|
||||||
|
file_links = generate_file_link(preview_html_list)
|
||||||
|
|
||||||
|
yield from update_ui_lastest_msg(
|
||||||
|
f"当前任务: <br/>{'<br/>'.join(tasks)}.<br/>" +
|
||||||
|
f"剩余源文件数量: {remain}.<br/>" +
|
||||||
|
f"已完成的文件: {sum(worker_done)}.<br/>" +
|
||||||
|
file_links +
|
||||||
|
"<br/>" +
|
||||||
|
''.join(['.']*(cnt % 10 + 1)
|
||||||
|
), chatbot=chatbot, history=history, delay=0)
|
||||||
|
yield from update_ui(chatbot=chatbot, history=[]) # 刷新界面
|
||||||
|
if all(worker_done):
|
||||||
|
executor.shutdown()
|
||||||
|
break
|
||||||
|
|
||||||
|
# <第四步,压缩结果>
|
||||||
|
zip_res = zip_result(project_folder)
|
||||||
|
promote_file_to_downloadzone(file=zip_res, chatbot=chatbot)
|
||||||
|
|
||||||
|
# <END>
|
||||||
|
chatbot.append((None, "所有源文件均已处理完毕。"))
|
||||||
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@CatchException
|
||||||
|
def 注释Python项目(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request):
|
||||||
|
history = [] # 清空历史,以免输入溢出
|
||||||
|
plugin_kwargs["use_chinese"] = plugin_kwargs.get("use_chinese", False)
|
||||||
|
import glob, os
|
||||||
|
if os.path.exists(txt):
|
||||||
|
project_folder = txt
|
||||||
|
validate_path_safety(project_folder, chatbot.get_user())
|
||||||
|
else:
|
||||||
|
if txt == "": txt = '空空如也的输入栏'
|
||||||
|
report_exception(chatbot, history, a = f"解析项目: {txt}", b = f"找不到本地项目或无权访问: {txt}")
|
||||||
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
||||||
|
return
|
||||||
|
file_manifest = [f for f in glob.glob(f'{project_folder}/**/*.py', recursive=True)]
|
||||||
|
if len(file_manifest) == 0:
|
||||||
|
report_exception(chatbot, history, a = f"解析项目: {txt}", b = f"找不到任何python文件: {txt}")
|
||||||
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
||||||
|
return
|
||||||
|
|
||||||
|
yield from 注释源代码(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt)
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
|
||||||
|
from toolbox import get_conf, update_ui
|
||||||
|
from crazy_functions.plugin_template.plugin_class_template import GptAcademicPluginTemplate, ArgProperty
|
||||||
|
from crazy_functions.SourceCode_Comment import 注释Python项目
|
||||||
|
|
||||||
|
class SourceCodeComment_Wrap(GptAcademicPluginTemplate):
|
||||||
|
def __init__(self):
|
||||||
|
"""
|
||||||
|
请注意`execute`会执行在不同的线程中,因此您在定义和使用类变量时,应当慎之又慎!
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
def define_arg_selection_menu(self):
|
||||||
|
"""
|
||||||
|
定义插件的二级选项菜单
|
||||||
|
"""
|
||||||
|
gui_definition = {
|
||||||
|
"main_input":
|
||||||
|
ArgProperty(title="路径", description="程序路径(上传文件后自动填写)", default_value="", type="string").model_dump_json(), # 主输入,自动从输入框同步
|
||||||
|
"use_chinese":
|
||||||
|
ArgProperty(title="注释语言", options=["英文", "中文"], default_value="英文", description="无", type="dropdown").model_dump_json(),
|
||||||
|
# "use_emoji":
|
||||||
|
# ArgProperty(title="在注释中使用emoji", options=["禁止", "允许"], default_value="禁止", description="无", type="dropdown").model_dump_json(),
|
||||||
|
}
|
||||||
|
return gui_definition
|
||||||
|
|
||||||
|
def execute(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request):
|
||||||
|
"""
|
||||||
|
执行插件
|
||||||
|
"""
|
||||||
|
if plugin_kwargs["use_chinese"] == "中文":
|
||||||
|
plugin_kwargs["use_chinese"] = True
|
||||||
|
else:
|
||||||
|
plugin_kwargs["use_chinese"] = False
|
||||||
|
|
||||||
|
yield from 注释Python项目(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request)
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
from crazy_functions.agent_fns.pipe import PluginMultiprocessManager, PipeCom
|
from crazy_functions.agent_fns.pipe import PluginMultiprocessManager, PipeCom
|
||||||
|
from loguru import logger
|
||||||
|
|
||||||
class EchoDemo(PluginMultiprocessManager):
|
class EchoDemo(PluginMultiprocessManager):
|
||||||
def subprocess_worker(self, child_conn):
|
def subprocess_worker(self, child_conn):
|
||||||
@@ -16,4 +17,4 @@ class EchoDemo(PluginMultiprocessManager):
|
|||||||
elif msg.cmd == "terminate":
|
elif msg.cmd == "terminate":
|
||||||
self.child_conn.send(PipeCom("done", ""))
|
self.child_conn.send(PipeCom("done", ""))
|
||||||
break
|
break
|
||||||
print('[debug] subprocess_worker terminated')
|
logger.info('[debug] subprocess_worker terminated')
|
||||||
@@ -35,7 +35,11 @@ def gpt_academic_generate_oai_reply(
|
|||||||
class AutoGenGeneral(PluginMultiprocessManager):
|
class AutoGenGeneral(PluginMultiprocessManager):
|
||||||
def gpt_academic_print_override(self, user_proxy, message, sender):
|
def gpt_academic_print_override(self, user_proxy, message, sender):
|
||||||
# ⭐⭐ run in subprocess
|
# ⭐⭐ run in subprocess
|
||||||
self.child_conn.send(PipeCom("show", sender.name + "\n\n---\n\n" + message["content"]))
|
try:
|
||||||
|
print_msg = sender.name + "\n\n---\n\n" + message["content"]
|
||||||
|
except:
|
||||||
|
print_msg = sender.name + "\n\n---\n\n" + message
|
||||||
|
self.child_conn.send(PipeCom("show", print_msg))
|
||||||
|
|
||||||
def gpt_academic_get_human_input(self, user_proxy, message):
|
def gpt_academic_get_human_input(self, user_proxy, message):
|
||||||
# ⭐⭐ run in subprocess
|
# ⭐⭐ run in subprocess
|
||||||
@@ -62,7 +66,6 @@ class AutoGenGeneral(PluginMultiprocessManager):
|
|||||||
def exe_autogen(self, input):
|
def exe_autogen(self, input):
|
||||||
# ⭐⭐ run in subprocess
|
# ⭐⭐ run in subprocess
|
||||||
input = input.content
|
input = input.content
|
||||||
with ProxyNetworkActivate("AutoGen"):
|
|
||||||
code_execution_config = {"work_dir": self.autogen_work_dir, "use_docker": self.use_docker}
|
code_execution_config = {"work_dir": self.autogen_work_dir, "use_docker": self.use_docker}
|
||||||
agents = self.define_agents()
|
agents = self.define_agents()
|
||||||
user_proxy = None
|
user_proxy = None
|
||||||
@@ -85,6 +88,7 @@ class AutoGenGeneral(PluginMultiprocessManager):
|
|||||||
if agent_kwargs['name'] == 'assistant': assistant = agent_handle
|
if agent_kwargs['name'] == 'assistant': assistant = agent_handle
|
||||||
try:
|
try:
|
||||||
if user_proxy is None or assistant is None: raise Exception("用户代理或助理代理未定义")
|
if user_proxy is None or assistant is None: raise Exception("用户代理或助理代理未定义")
|
||||||
|
with ProxyNetworkActivate("AutoGen"):
|
||||||
user_proxy.initiate_chat(assistant, message=input)
|
user_proxy.initiate_chat(assistant, message=input)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
tb_str = '```\n' + trimmed_format_exc() + '```'
|
tb_str = '```\n' + trimmed_format_exc() + '```'
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
from toolbox import get_log_folder, update_ui, gen_time_str, get_conf, promote_file_to_downloadzone
|
from toolbox import get_log_folder, update_ui, gen_time_str, get_conf, promote_file_to_downloadzone
|
||||||
from crazy_functions.agent_fns.watchdog import WatchDog
|
from crazy_functions.agent_fns.watchdog import WatchDog
|
||||||
|
from loguru import logger
|
||||||
import time, os
|
import time, os
|
||||||
|
|
||||||
class PipeCom:
|
class PipeCom:
|
||||||
@@ -9,7 +10,7 @@ class PipeCom:
|
|||||||
|
|
||||||
|
|
||||||
class PluginMultiprocessManager:
|
class PluginMultiprocessManager:
|
||||||
def __init__(self, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port):
|
def __init__(self, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request):
|
||||||
# ⭐ run in main process
|
# ⭐ run in main process
|
||||||
self.autogen_work_dir = os.path.join(get_log_folder("autogen"), gen_time_str())
|
self.autogen_work_dir = os.path.join(get_log_folder("autogen"), gen_time_str())
|
||||||
self.previous_work_dir_files = {}
|
self.previous_work_dir_files = {}
|
||||||
@@ -18,7 +19,7 @@ class PluginMultiprocessManager:
|
|||||||
self.chatbot = chatbot
|
self.chatbot = chatbot
|
||||||
self.history = history
|
self.history = history
|
||||||
self.system_prompt = system_prompt
|
self.system_prompt = system_prompt
|
||||||
# self.web_port = web_port
|
# self.user_request = user_request
|
||||||
self.alive = True
|
self.alive = True
|
||||||
self.use_docker = get_conf("AUTOGEN_USE_DOCKER")
|
self.use_docker = get_conf("AUTOGEN_USE_DOCKER")
|
||||||
self.last_user_input = ""
|
self.last_user_input = ""
|
||||||
@@ -47,7 +48,7 @@ class PluginMultiprocessManager:
|
|||||||
def terminate(self):
|
def terminate(self):
|
||||||
self.p.terminate()
|
self.p.terminate()
|
||||||
self.alive = False
|
self.alive = False
|
||||||
print("[debug] instance terminated")
|
logger.info("[debug] instance terminated")
|
||||||
|
|
||||||
def subprocess_worker(self, child_conn):
|
def subprocess_worker(self, child_conn):
|
||||||
# ⭐⭐ run in subprocess
|
# ⭐⭐ run in subprocess
|
||||||
|
|||||||
@@ -0,0 +1,457 @@
|
|||||||
|
import datetime
|
||||||
|
import re
|
||||||
|
import os
|
||||||
|
from loguru import logger
|
||||||
|
from textwrap import dedent
|
||||||
|
from toolbox import CatchException, update_ui
|
||||||
|
from request_llms.bridge_all import predict_no_ui_long_connection
|
||||||
|
from crazy_functions.crazy_utils import request_gpt_model_in_new_thread_with_ui_alive
|
||||||
|
|
||||||
|
# TODO: 解决缩进问题
|
||||||
|
|
||||||
|
find_function_end_prompt = '''
|
||||||
|
Below is a page of code that you need to read. This page may not yet complete, you job is to split this page to sperate functions, class functions etc.
|
||||||
|
- Provide the line number where the first visible function ends.
|
||||||
|
- Provide the line number where the next visible function begins.
|
||||||
|
- If there are no other functions in this page, you should simply return the line number of the last line.
|
||||||
|
- Only focus on functions declared by `def` keyword. Ignore inline functions. Ignore function calls.
|
||||||
|
|
||||||
|
------------------ Example ------------------
|
||||||
|
INPUT:
|
||||||
|
|
||||||
|
```
|
||||||
|
L0000 |import sys
|
||||||
|
L0001 |import re
|
||||||
|
L0002 |
|
||||||
|
L0003 |def trimmed_format_exc():
|
||||||
|
L0004 | import os
|
||||||
|
L0005 | import traceback
|
||||||
|
L0006 | str = traceback.format_exc()
|
||||||
|
L0007 | current_path = os.getcwd()
|
||||||
|
L0008 | replace_path = "."
|
||||||
|
L0009 | return str.replace(current_path, replace_path)
|
||||||
|
L0010 |
|
||||||
|
L0011 |
|
||||||
|
L0012 |def trimmed_format_exc_markdown():
|
||||||
|
L0013 | ...
|
||||||
|
L0014 | ...
|
||||||
|
```
|
||||||
|
|
||||||
|
OUTPUT:
|
||||||
|
|
||||||
|
```
|
||||||
|
<first_function_end_at>L0009</first_function_end_at>
|
||||||
|
<next_function_begin_from>L0012</next_function_begin_from>
|
||||||
|
```
|
||||||
|
|
||||||
|
------------------ End of Example ------------------
|
||||||
|
|
||||||
|
|
||||||
|
------------------ the real INPUT you need to process NOW ------------------
|
||||||
|
```
|
||||||
|
{THE_TAGGED_CODE}
|
||||||
|
```
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
revise_funtion_prompt = '''
|
||||||
|
You need to read the following code, and revise the source code ({FILE_BASENAME}) according to following instructions:
|
||||||
|
1. You should analyze the purpose of the functions (if there are any).
|
||||||
|
2. You need to add docstring for the provided functions (if there are any).
|
||||||
|
|
||||||
|
Be aware:
|
||||||
|
1. You must NOT modify the indent of code.
|
||||||
|
2. You are NOT authorized to change or translate non-comment code, and you are NOT authorized to add empty lines either, toggle qu.
|
||||||
|
3. Use {LANG} to add comments and docstrings. Do NOT translate Chinese that is already in the code.
|
||||||
|
4. Besides adding a docstring, use the ⭐ symbol to annotate the most core and important line of code within the function, explaining its role.
|
||||||
|
|
||||||
|
------------------ Example ------------------
|
||||||
|
INPUT:
|
||||||
|
```
|
||||||
|
L0000 |
|
||||||
|
L0001 |def zip_result(folder):
|
||||||
|
L0002 | t = gen_time_str()
|
||||||
|
L0003 | zip_folder(folder, get_log_folder(), f"result.zip")
|
||||||
|
L0004 | return os.path.join(get_log_folder(), f"result.zip")
|
||||||
|
L0005 |
|
||||||
|
L0006 |
|
||||||
|
```
|
||||||
|
|
||||||
|
OUTPUT:
|
||||||
|
|
||||||
|
<instruction_1_purpose>
|
||||||
|
This function compresses a given folder, and return the path of the resulting `zip` file.
|
||||||
|
</instruction_1_purpose>
|
||||||
|
<instruction_2_revised_code>
|
||||||
|
```
|
||||||
|
def zip_result(folder):
|
||||||
|
"""
|
||||||
|
Compresses the specified folder into a zip file and stores it in the log folder.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
folder (str): The path to the folder that needs to be compressed.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: The path to the created zip file in the log folder.
|
||||||
|
"""
|
||||||
|
t = gen_time_str()
|
||||||
|
zip_folder(folder, get_log_folder(), f"result.zip") # ⭐ Execute the zipping of folder
|
||||||
|
return os.path.join(get_log_folder(), f"result.zip")
|
||||||
|
```
|
||||||
|
</instruction_2_revised_code>
|
||||||
|
------------------ End of Example ------------------
|
||||||
|
|
||||||
|
|
||||||
|
------------------ the real INPUT you need to process NOW ({FILE_BASENAME}) ------------------
|
||||||
|
```
|
||||||
|
{THE_CODE}
|
||||||
|
```
|
||||||
|
{INDENT_REMINDER}
|
||||||
|
{BRIEF_REMINDER}
|
||||||
|
{HINT_REMINDER}
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
revise_funtion_prompt_chinese = '''
|
||||||
|
您需要阅读以下代码,并根据以下说明修订源代码({FILE_BASENAME}):
|
||||||
|
1. 如果源代码中包含函数的话, 你应该分析给定函数实现了什么功能
|
||||||
|
2. 如果源代码中包含函数的话, 你需要为函数添加docstring, docstring必须使用中文
|
||||||
|
|
||||||
|
请注意:
|
||||||
|
1. 你不得修改代码的缩进
|
||||||
|
2. 你无权更改或翻译代码中的非注释部分,也不允许添加空行
|
||||||
|
3. 使用 {LANG} 添加注释和文档字符串。不要翻译代码中已有的中文
|
||||||
|
4. 除了添加docstring之外, 使用⭐符号给该函数中最核心、最重要的一行代码添加注释,并说明其作用
|
||||||
|
|
||||||
|
------------------ 示例 ------------------
|
||||||
|
INPUT:
|
||||||
|
```
|
||||||
|
L0000 |
|
||||||
|
L0001 |def zip_result(folder):
|
||||||
|
L0002 | t = gen_time_str()
|
||||||
|
L0003 | zip_folder(folder, get_log_folder(), f"result.zip")
|
||||||
|
L0004 | return os.path.join(get_log_folder(), f"result.zip")
|
||||||
|
L0005 |
|
||||||
|
L0006 |
|
||||||
|
```
|
||||||
|
|
||||||
|
OUTPUT:
|
||||||
|
|
||||||
|
<instruction_1_purpose>
|
||||||
|
该函数用于压缩指定文件夹,并返回生成的`zip`文件的路径。
|
||||||
|
</instruction_1_purpose>
|
||||||
|
<instruction_2_revised_code>
|
||||||
|
```
|
||||||
|
def zip_result(folder):
|
||||||
|
"""
|
||||||
|
该函数将指定的文件夹压缩成ZIP文件, 并将其存储在日志文件夹中。
|
||||||
|
|
||||||
|
输入参数:
|
||||||
|
folder (str): 需要压缩的文件夹的路径。
|
||||||
|
返回值:
|
||||||
|
str: 日志文件夹中创建的ZIP文件的路径。
|
||||||
|
"""
|
||||||
|
t = gen_time_str()
|
||||||
|
zip_folder(folder, get_log_folder(), f"result.zip") # ⭐ 执行文件夹的压缩
|
||||||
|
return os.path.join(get_log_folder(), f"result.zip")
|
||||||
|
```
|
||||||
|
</instruction_2_revised_code>
|
||||||
|
------------------ End of Example ------------------
|
||||||
|
|
||||||
|
|
||||||
|
------------------ the real INPUT you need to process NOW ({FILE_BASENAME}) ------------------
|
||||||
|
```
|
||||||
|
{THE_CODE}
|
||||||
|
```
|
||||||
|
{INDENT_REMINDER}
|
||||||
|
{BRIEF_REMINDER}
|
||||||
|
{HINT_REMINDER}
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
class PythonCodeComment():
|
||||||
|
|
||||||
|
def __init__(self, llm_kwargs, plugin_kwargs, language, observe_window_update) -> None:
|
||||||
|
self.original_content = ""
|
||||||
|
self.full_context = []
|
||||||
|
self.full_context_with_line_no = []
|
||||||
|
self.current_page_start = 0
|
||||||
|
self.page_limit = 100 # 100 lines of code each page
|
||||||
|
self.ignore_limit = 20
|
||||||
|
self.llm_kwargs = llm_kwargs
|
||||||
|
self.plugin_kwargs = plugin_kwargs
|
||||||
|
self.language = language
|
||||||
|
self.observe_window_update = observe_window_update
|
||||||
|
if self.language == "chinese":
|
||||||
|
self.core_prompt = revise_funtion_prompt_chinese
|
||||||
|
else:
|
||||||
|
self.core_prompt = revise_funtion_prompt
|
||||||
|
self.path = None
|
||||||
|
self.file_basename = None
|
||||||
|
self.file_brief = ""
|
||||||
|
|
||||||
|
def generate_tagged_code_from_full_context(self):
|
||||||
|
for i, code in enumerate(self.full_context):
|
||||||
|
number = i
|
||||||
|
padded_number = f"{number:04}"
|
||||||
|
result = f"L{padded_number}"
|
||||||
|
self.full_context_with_line_no.append(f"{result} | {code}")
|
||||||
|
return self.full_context_with_line_no
|
||||||
|
|
||||||
|
def read_file(self, path, brief):
|
||||||
|
with open(path, 'r', encoding='utf8') as f:
|
||||||
|
self.full_context = f.readlines()
|
||||||
|
self.original_content = ''.join(self.full_context)
|
||||||
|
self.file_basename = os.path.basename(path)
|
||||||
|
self.file_brief = brief
|
||||||
|
self.full_context_with_line_no = self.generate_tagged_code_from_full_context()
|
||||||
|
self.path = path
|
||||||
|
|
||||||
|
def find_next_function_begin(self, tagged_code:list, begin_and_end):
|
||||||
|
begin, end = begin_and_end
|
||||||
|
THE_TAGGED_CODE = ''.join(tagged_code)
|
||||||
|
self.llm_kwargs['temperature'] = 0
|
||||||
|
result = predict_no_ui_long_connection(
|
||||||
|
inputs=find_function_end_prompt.format(THE_TAGGED_CODE=THE_TAGGED_CODE),
|
||||||
|
llm_kwargs=self.llm_kwargs,
|
||||||
|
history=[],
|
||||||
|
sys_prompt="",
|
||||||
|
observe_window=[],
|
||||||
|
console_slience=True
|
||||||
|
)
|
||||||
|
|
||||||
|
def extract_number(text):
|
||||||
|
# 使用正则表达式匹配模式
|
||||||
|
match = re.search(r'<next_function_begin_from>L(\d+)</next_function_begin_from>', text)
|
||||||
|
if match:
|
||||||
|
# 提取匹配的数字部分并转换为整数
|
||||||
|
return int(match.group(1))
|
||||||
|
return None
|
||||||
|
|
||||||
|
line_no = extract_number(result)
|
||||||
|
if line_no is not None:
|
||||||
|
return line_no
|
||||||
|
else:
|
||||||
|
return end
|
||||||
|
|
||||||
|
def _get_next_window(self):
|
||||||
|
#
|
||||||
|
current_page_start = self.current_page_start
|
||||||
|
|
||||||
|
if self.current_page_start == len(self.full_context) + 1:
|
||||||
|
raise StopIteration
|
||||||
|
|
||||||
|
# 如果剩余的行数非常少,一鼓作气处理掉
|
||||||
|
if len(self.full_context) - self.current_page_start < self.ignore_limit:
|
||||||
|
future_page_start = len(self.full_context) + 1
|
||||||
|
self.current_page_start = future_page_start
|
||||||
|
return current_page_start, future_page_start
|
||||||
|
|
||||||
|
|
||||||
|
tagged_code = self.full_context_with_line_no[ self.current_page_start: self.current_page_start + self.page_limit]
|
||||||
|
line_no = self.find_next_function_begin(tagged_code, [self.current_page_start, self.current_page_start + self.page_limit])
|
||||||
|
|
||||||
|
if line_no > len(self.full_context) - 5:
|
||||||
|
line_no = len(self.full_context) + 1
|
||||||
|
|
||||||
|
future_page_start = line_no
|
||||||
|
self.current_page_start = future_page_start
|
||||||
|
|
||||||
|
# ! consider eof
|
||||||
|
return current_page_start, future_page_start
|
||||||
|
|
||||||
|
def dedent(self, text):
|
||||||
|
"""Remove any common leading whitespace from every line in `text`.
|
||||||
|
"""
|
||||||
|
# Look for the longest leading string of spaces and tabs common to
|
||||||
|
# all lines.
|
||||||
|
margin = None
|
||||||
|
_whitespace_only_re = re.compile('^[ \t]+$', re.MULTILINE)
|
||||||
|
_leading_whitespace_re = re.compile('(^[ \t]*)(?:[^ \t\n])', re.MULTILINE)
|
||||||
|
text = _whitespace_only_re.sub('', text)
|
||||||
|
indents = _leading_whitespace_re.findall(text)
|
||||||
|
for indent in indents:
|
||||||
|
if margin is None:
|
||||||
|
margin = indent
|
||||||
|
|
||||||
|
# Current line more deeply indented than previous winner:
|
||||||
|
# no change (previous winner is still on top).
|
||||||
|
elif indent.startswith(margin):
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Current line consistent with and no deeper than previous winner:
|
||||||
|
# it's the new winner.
|
||||||
|
elif margin.startswith(indent):
|
||||||
|
margin = indent
|
||||||
|
|
||||||
|
# Find the largest common whitespace between current line and previous
|
||||||
|
# winner.
|
||||||
|
else:
|
||||||
|
for i, (x, y) in enumerate(zip(margin, indent)):
|
||||||
|
if x != y:
|
||||||
|
margin = margin[:i]
|
||||||
|
break
|
||||||
|
|
||||||
|
# sanity check (testing/debugging only)
|
||||||
|
if 0 and margin:
|
||||||
|
for line in text.split("\n"):
|
||||||
|
assert not line or line.startswith(margin), \
|
||||||
|
"line = %r, margin = %r" % (line, margin)
|
||||||
|
|
||||||
|
if margin:
|
||||||
|
text = re.sub(r'(?m)^' + margin, '', text)
|
||||||
|
return text, len(margin)
|
||||||
|
else:
|
||||||
|
return text, 0
|
||||||
|
|
||||||
|
def get_next_batch(self):
|
||||||
|
current_page_start, future_page_start = self._get_next_window()
|
||||||
|
return ''.join(self.full_context[current_page_start: future_page_start]), current_page_start, future_page_start
|
||||||
|
|
||||||
|
def tag_code(self, fn, hint):
|
||||||
|
code = fn
|
||||||
|
_, n_indent = self.dedent(code)
|
||||||
|
indent_reminder = "" if n_indent == 0 else "(Reminder: as you can see, this piece of code has indent made up with {n_indent} whitespace, please preseve them in the OUTPUT.)"
|
||||||
|
brief_reminder = "" if self.file_brief == "" else f"({self.file_basename} abstract: {self.file_brief})"
|
||||||
|
hint_reminder = "" if hint is None else f"(Reminder: do not ignore or modify code such as `{hint}`, provide complete code in the OUTPUT.)"
|
||||||
|
self.llm_kwargs['temperature'] = 0
|
||||||
|
result = predict_no_ui_long_connection(
|
||||||
|
inputs=self.core_prompt.format(
|
||||||
|
LANG=self.language,
|
||||||
|
FILE_BASENAME=self.file_basename,
|
||||||
|
THE_CODE=code,
|
||||||
|
INDENT_REMINDER=indent_reminder,
|
||||||
|
BRIEF_REMINDER=brief_reminder,
|
||||||
|
HINT_REMINDER=hint_reminder
|
||||||
|
),
|
||||||
|
llm_kwargs=self.llm_kwargs,
|
||||||
|
history=[],
|
||||||
|
sys_prompt="",
|
||||||
|
observe_window=[],
|
||||||
|
console_slience=True
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_code_block(reply):
|
||||||
|
import re
|
||||||
|
pattern = r"```([\s\S]*?)```" # regex pattern to match code blocks
|
||||||
|
matches = re.findall(pattern, reply) # find all code blocks in text
|
||||||
|
if len(matches) == 1:
|
||||||
|
return matches[0].strip('python') # code block
|
||||||
|
return None
|
||||||
|
|
||||||
|
code_block = get_code_block(result)
|
||||||
|
if code_block is not None:
|
||||||
|
code_block = self.sync_and_patch(original=code, revised=code_block)
|
||||||
|
return code_block
|
||||||
|
else:
|
||||||
|
return code
|
||||||
|
|
||||||
|
def get_markdown_block_in_html(self, html):
|
||||||
|
from bs4 import BeautifulSoup
|
||||||
|
soup = BeautifulSoup(html, 'lxml')
|
||||||
|
found_list = soup.find_all("div", class_="markdown-body")
|
||||||
|
if found_list:
|
||||||
|
res = found_list[0]
|
||||||
|
return res.prettify()
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def sync_and_patch(self, original, revised):
|
||||||
|
"""Ensure the number of pre-string empty lines in revised matches those in original."""
|
||||||
|
|
||||||
|
def count_leading_empty_lines(s, reverse=False):
|
||||||
|
"""Count the number of leading empty lines in a string."""
|
||||||
|
lines = s.split('\n')
|
||||||
|
if reverse: lines = list(reversed(lines))
|
||||||
|
count = 0
|
||||||
|
for line in lines:
|
||||||
|
if line.strip() == '':
|
||||||
|
count += 1
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
return count
|
||||||
|
|
||||||
|
original_empty_lines = count_leading_empty_lines(original)
|
||||||
|
revised_empty_lines = count_leading_empty_lines(revised)
|
||||||
|
|
||||||
|
if original_empty_lines > revised_empty_lines:
|
||||||
|
additional_lines = '\n' * (original_empty_lines - revised_empty_lines)
|
||||||
|
revised = additional_lines + revised
|
||||||
|
elif original_empty_lines < revised_empty_lines:
|
||||||
|
lines = revised.split('\n')
|
||||||
|
revised = '\n'.join(lines[revised_empty_lines - original_empty_lines:])
|
||||||
|
|
||||||
|
original_empty_lines = count_leading_empty_lines(original, reverse=True)
|
||||||
|
revised_empty_lines = count_leading_empty_lines(revised, reverse=True)
|
||||||
|
|
||||||
|
if original_empty_lines > revised_empty_lines:
|
||||||
|
additional_lines = '\n' * (original_empty_lines - revised_empty_lines)
|
||||||
|
revised = revised + additional_lines
|
||||||
|
elif original_empty_lines < revised_empty_lines:
|
||||||
|
lines = revised.split('\n')
|
||||||
|
revised = '\n'.join(lines[:-(revised_empty_lines - original_empty_lines)])
|
||||||
|
|
||||||
|
return revised
|
||||||
|
|
||||||
|
def begin_comment_source_code(self, chatbot=None, history=None):
|
||||||
|
# from toolbox import update_ui_lastest_msg
|
||||||
|
assert self.path is not None
|
||||||
|
assert '.py' in self.path # must be python source code
|
||||||
|
# write_target = self.path + '.revised.py'
|
||||||
|
|
||||||
|
write_content = ""
|
||||||
|
# with open(self.path + '.revised.py', 'w+', encoding='utf8') as f:
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
# yield from update_ui_lastest_msg(f"({self.file_basename}) 正在读取下一段代码片段:\n", chatbot=chatbot, history=history, delay=0)
|
||||||
|
next_batch, line_no_start, line_no_end = self.get_next_batch()
|
||||||
|
self.observe_window_update(f"正在处理{self.file_basename} - {line_no_start}/{len(self.full_context)}\n")
|
||||||
|
# yield from update_ui_lastest_msg(f"({self.file_basename}) 处理代码片段:\n\n{next_batch}", chatbot=chatbot, history=history, delay=0)
|
||||||
|
|
||||||
|
hint = None
|
||||||
|
MAX_ATTEMPT = 2
|
||||||
|
for attempt in range(MAX_ATTEMPT):
|
||||||
|
result = self.tag_code(next_batch, hint)
|
||||||
|
try:
|
||||||
|
successful, hint = self.verify_successful(next_batch, result)
|
||||||
|
except Exception as e:
|
||||||
|
logger.error('ignored exception:\n' + str(e))
|
||||||
|
break
|
||||||
|
if successful:
|
||||||
|
break
|
||||||
|
if attempt == MAX_ATTEMPT - 1:
|
||||||
|
# cannot deal with this, give up
|
||||||
|
result = next_batch
|
||||||
|
break
|
||||||
|
|
||||||
|
# f.write(result)
|
||||||
|
write_content += result
|
||||||
|
except StopIteration:
|
||||||
|
next_batch, line_no_start, line_no_end = [], -1, -1
|
||||||
|
return None, write_content
|
||||||
|
|
||||||
|
def verify_successful(self, original, revised):
|
||||||
|
""" Determine whether the revised code contains every line that already exists
|
||||||
|
"""
|
||||||
|
from crazy_functions.ast_fns.comment_remove import remove_python_comments
|
||||||
|
original = remove_python_comments(original)
|
||||||
|
original_lines = original.split('\n')
|
||||||
|
revised_lines = revised.split('\n')
|
||||||
|
|
||||||
|
for l in original_lines:
|
||||||
|
l = l.strip()
|
||||||
|
if '\'' in l or '\"' in l: continue # ast sometimes toggle " to '
|
||||||
|
found = False
|
||||||
|
for lt in revised_lines:
|
||||||
|
if l in lt:
|
||||||
|
found = True
|
||||||
|
break
|
||||||
|
if not found:
|
||||||
|
return False, l
|
||||||
|
return True, None
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<style>ADVANCED_CSS</style>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>源文件对比</title>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-family: Arial, sans-serif;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
height: 100vh;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
.container {
|
||||||
|
display: flex;
|
||||||
|
width: 95%;
|
||||||
|
height: -webkit-fill-available;
|
||||||
|
}
|
||||||
|
.code-container {
|
||||||
|
flex: 1;
|
||||||
|
margin: 0px;
|
||||||
|
padding: 0px;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
background-color: #f9f9f9;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
pre {
|
||||||
|
white-space: pre-wrap;
|
||||||
|
word-wrap: break-word;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<div class="code-container">
|
||||||
|
REPLACE_CODE_FILE_LEFT
|
||||||
|
</div>
|
||||||
|
<div class="code-container">
|
||||||
|
REPLACE_CODE_FILE_RIGHT
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
import threading, time
|
import threading, time
|
||||||
|
from loguru import logger
|
||||||
|
|
||||||
class WatchDog():
|
class WatchDog():
|
||||||
def __init__(self, timeout, bark_fn, interval=3, msg="") -> None:
|
def __init__(self, timeout, bark_fn, interval=3, msg="") -> None:
|
||||||
@@ -13,7 +14,7 @@ class WatchDog():
|
|||||||
while True:
|
while True:
|
||||||
if self.kill_dog: break
|
if self.kill_dog: break
|
||||||
if time.time() - self.last_feed > self.timeout:
|
if time.time() - self.last_feed > self.timeout:
|
||||||
if len(self.msg) > 0: print(self.msg)
|
if len(self.msg) > 0: logger.info(self.msg)
|
||||||
self.bark_fn()
|
self.bark_fn()
|
||||||
break
|
break
|
||||||
time.sleep(self.interval)
|
time.sleep(self.interval)
|
||||||
|
|||||||
@@ -0,0 +1,54 @@
|
|||||||
|
import token
|
||||||
|
import tokenize
|
||||||
|
import copy
|
||||||
|
import io
|
||||||
|
|
||||||
|
|
||||||
|
def remove_python_comments(input_source: str) -> str:
|
||||||
|
source_flag = copy.copy(input_source)
|
||||||
|
source = io.StringIO(input_source)
|
||||||
|
ls = input_source.split('\n')
|
||||||
|
prev_toktype = token.INDENT
|
||||||
|
readline = source.readline
|
||||||
|
|
||||||
|
def get_char_index(lineno, col):
|
||||||
|
# find the index of the char in the source code
|
||||||
|
if lineno == 1:
|
||||||
|
return len('\n'.join(ls[:(lineno-1)])) + col
|
||||||
|
else:
|
||||||
|
return len('\n'.join(ls[:(lineno-1)])) + col + 1
|
||||||
|
|
||||||
|
def replace_char_between(start_lineno, start_col, end_lineno, end_col, source, replace_char, ls):
|
||||||
|
# replace char between start_lineno, start_col and end_lineno, end_col with replace_char, but keep '\n' and ' '
|
||||||
|
b = get_char_index(start_lineno, start_col)
|
||||||
|
e = get_char_index(end_lineno, end_col)
|
||||||
|
for i in range(b, e):
|
||||||
|
if source[i] == '\n':
|
||||||
|
source = source[:i] + '\n' + source[i+1:]
|
||||||
|
elif source[i] == ' ':
|
||||||
|
source = source[:i] + ' ' + source[i+1:]
|
||||||
|
else:
|
||||||
|
source = source[:i] + replace_char + source[i+1:]
|
||||||
|
return source
|
||||||
|
|
||||||
|
tokgen = tokenize.generate_tokens(readline)
|
||||||
|
for toktype, ttext, (slineno, scol), (elineno, ecol), ltext in tokgen:
|
||||||
|
if toktype == token.STRING and (prev_toktype == token.INDENT):
|
||||||
|
source_flag = replace_char_between(slineno, scol, elineno, ecol, source_flag, ' ', ls)
|
||||||
|
elif toktype == token.STRING and (prev_toktype == token.NEWLINE):
|
||||||
|
source_flag = replace_char_between(slineno, scol, elineno, ecol, source_flag, ' ', ls)
|
||||||
|
elif toktype == tokenize.COMMENT:
|
||||||
|
source_flag = replace_char_between(slineno, scol, elineno, ecol, source_flag, ' ', ls)
|
||||||
|
prev_toktype = toktype
|
||||||
|
return source_flag
|
||||||
|
|
||||||
|
|
||||||
|
# 示例使用
|
||||||
|
if __name__ == "__main__":
|
||||||
|
with open("source.py", "r", encoding="utf-8") as f:
|
||||||
|
source_code = f.read()
|
||||||
|
|
||||||
|
cleaned_code = remove_python_comments(source_code)
|
||||||
|
|
||||||
|
with open("cleaned_source.py", "w", encoding="utf-8") as f:
|
||||||
|
f.write(cleaned_code)
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
from toolbox import CatchException, update_ui, promote_file_to_downloadzone
|
from toolbox import CatchException, update_ui, promote_file_to_downloadzone
|
||||||
from .crazy_utils import request_gpt_model_multi_threads_with_very_awesome_ui_and_high_efficiency
|
from crazy_functions.crazy_utils import request_gpt_model_multi_threads_with_very_awesome_ui_and_high_efficiency
|
||||||
import datetime, json
|
import datetime, json
|
||||||
|
|
||||||
def fetch_items(list_of_items, batch_size):
|
def fetch_items(list_of_items, batch_size):
|
||||||
@@ -32,7 +32,7 @@ def string_to_options(arguments):
|
|||||||
return args
|
return args
|
||||||
|
|
||||||
@CatchException
|
@CatchException
|
||||||
def 微调数据集生成(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port):
|
def 微调数据集生成(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request):
|
||||||
"""
|
"""
|
||||||
txt 输入栏用户输入的文本,例如需要翻译的一段话,再例如一个包含了待处理文件的路径
|
txt 输入栏用户输入的文本,例如需要翻译的一段话,再例如一个包含了待处理文件的路径
|
||||||
llm_kwargs gpt模型参数,如温度和top_p等,一般原样传递下去就行
|
llm_kwargs gpt模型参数,如温度和top_p等,一般原样传递下去就行
|
||||||
@@ -40,7 +40,7 @@ def 微调数据集生成(txt, llm_kwargs, plugin_kwargs, chatbot, history, syst
|
|||||||
chatbot 聊天显示框的句柄,用于显示给用户
|
chatbot 聊天显示框的句柄,用于显示给用户
|
||||||
history 聊天历史,前情提要
|
history 聊天历史,前情提要
|
||||||
system_prompt 给gpt的静默提醒
|
system_prompt 给gpt的静默提醒
|
||||||
web_port 当前软件运行的端口号
|
user_request 当前用户的请求信息(IP地址等)
|
||||||
"""
|
"""
|
||||||
history = [] # 清空历史,以免输入溢出
|
history = [] # 清空历史,以免输入溢出
|
||||||
chatbot.append(("这是什么功能?", "[Local Message] 微调数据集生成"))
|
chatbot.append(("这是什么功能?", "[Local Message] 微调数据集生成"))
|
||||||
@@ -80,7 +80,7 @@ def 微调数据集生成(txt, llm_kwargs, plugin_kwargs, chatbot, history, syst
|
|||||||
|
|
||||||
|
|
||||||
@CatchException
|
@CatchException
|
||||||
def 启动微调(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port):
|
def 启动微调(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request):
|
||||||
"""
|
"""
|
||||||
txt 输入栏用户输入的文本,例如需要翻译的一段话,再例如一个包含了待处理文件的路径
|
txt 输入栏用户输入的文本,例如需要翻译的一段话,再例如一个包含了待处理文件的路径
|
||||||
llm_kwargs gpt模型参数,如温度和top_p等,一般原样传递下去就行
|
llm_kwargs gpt模型参数,如温度和top_p等,一般原样传递下去就行
|
||||||
@@ -88,7 +88,7 @@ def 启动微调(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt
|
|||||||
chatbot 聊天显示框的句柄,用于显示给用户
|
chatbot 聊天显示框的句柄,用于显示给用户
|
||||||
history 聊天历史,前情提要
|
history 聊天历史,前情提要
|
||||||
system_prompt 给gpt的静默提醒
|
system_prompt 给gpt的静默提醒
|
||||||
web_port 当前软件运行的端口号
|
user_request 当前用户的请求信息(IP地址等)
|
||||||
"""
|
"""
|
||||||
import subprocess
|
import subprocess
|
||||||
history = [] # 清空历史,以免输入溢出
|
history = [] # 清空历史,以免输入溢出
|
||||||
|
|||||||
@@ -1,25 +1,39 @@
|
|||||||
from toolbox import update_ui, get_conf, trimmed_format_exc, get_max_token, Singleton
|
|
||||||
import threading
|
|
||||||
import os
|
import os
|
||||||
import logging
|
import threading
|
||||||
|
from loguru import logger
|
||||||
|
from shared_utils.char_visual_effect import scolling_visual_effect
|
||||||
|
from toolbox import update_ui, get_conf, trimmed_format_exc, get_max_token, Singleton
|
||||||
|
|
||||||
def input_clipping(inputs, history, max_token_limit):
|
def input_clipping(inputs, history, max_token_limit, return_clip_flags=False):
|
||||||
|
"""
|
||||||
|
当输入文本 + 历史文本超出最大限制时,采取措施丢弃一部分文本。
|
||||||
|
输入:
|
||||||
|
- inputs 本次请求
|
||||||
|
- history 历史上下文
|
||||||
|
- max_token_limit 最大token限制
|
||||||
|
输出:
|
||||||
|
- inputs 本次请求(经过clip)
|
||||||
|
- history 历史上下文(经过clip)
|
||||||
|
"""
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from request_llms.bridge_all import model_info
|
from request_llms.bridge_all import model_info
|
||||||
enc = model_info["gpt-3.5-turbo"]['tokenizer']
|
enc = model_info["gpt-3.5-turbo"]['tokenizer']
|
||||||
def get_token_num(txt): return len(enc.encode(txt, disallowed_special=()))
|
def get_token_num(txt): return len(enc.encode(txt, disallowed_special=()))
|
||||||
|
|
||||||
|
|
||||||
mode = 'input-and-history'
|
mode = 'input-and-history'
|
||||||
# 当 输入部分的token占比 小于 全文的一半时,只裁剪历史
|
# 当 输入部分的token占比 小于 全文的一半时,只裁剪历史
|
||||||
input_token_num = get_token_num(inputs)
|
input_token_num = get_token_num(inputs)
|
||||||
|
original_input_len = len(inputs)
|
||||||
if input_token_num < max_token_limit//2:
|
if input_token_num < max_token_limit//2:
|
||||||
mode = 'only-history'
|
mode = 'only-history'
|
||||||
max_token_limit = max_token_limit - input_token_num
|
max_token_limit = max_token_limit - input_token_num
|
||||||
|
|
||||||
everything = [inputs] if mode == 'input-and-history' else ['']
|
everything = [inputs] if mode == 'input-and-history' else ['']
|
||||||
everything.extend(history)
|
everything.extend(history)
|
||||||
n_token = get_token_num('\n'.join(everything))
|
full_token_num = n_token = get_token_num('\n'.join(everything))
|
||||||
everything_token = [get_token_num(e) for e in everything]
|
everything_token = [get_token_num(e) for e in everything]
|
||||||
|
everything_token_num = sum(everything_token)
|
||||||
delta = max(everything_token) // 16 # 截断时的颗粒度
|
delta = max(everything_token) // 16 # 截断时的颗粒度
|
||||||
|
|
||||||
while n_token > max_token_limit:
|
while n_token > max_token_limit:
|
||||||
@@ -32,10 +46,24 @@ def input_clipping(inputs, history, max_token_limit):
|
|||||||
|
|
||||||
if mode == 'input-and-history':
|
if mode == 'input-and-history':
|
||||||
inputs = everything[0]
|
inputs = everything[0]
|
||||||
|
full_token_num = everything_token_num
|
||||||
else:
|
else:
|
||||||
pass
|
full_token_num = everything_token_num + input_token_num
|
||||||
|
|
||||||
history = everything[1:]
|
history = everything[1:]
|
||||||
|
|
||||||
|
flags = {
|
||||||
|
"mode": mode,
|
||||||
|
"original_input_token_num": input_token_num,
|
||||||
|
"original_full_token_num": full_token_num,
|
||||||
|
"original_input_len": original_input_len,
|
||||||
|
"clipped_input_len": len(inputs),
|
||||||
|
}
|
||||||
|
|
||||||
|
if not return_clip_flags:
|
||||||
return inputs, history
|
return inputs, history
|
||||||
|
else:
|
||||||
|
return inputs, history, flags
|
||||||
|
|
||||||
def request_gpt_model_in_new_thread_with_ui_alive(
|
def request_gpt_model_in_new_thread_with_ui_alive(
|
||||||
inputs, inputs_show_user, llm_kwargs,
|
inputs, inputs_show_user, llm_kwargs,
|
||||||
@@ -105,7 +133,7 @@ def request_gpt_model_in_new_thread_with_ui_alive(
|
|||||||
except:
|
except:
|
||||||
# 【第三种情况】:其他错误:重试几次
|
# 【第三种情况】:其他错误:重试几次
|
||||||
tb_str = '```\n' + trimmed_format_exc() + '```'
|
tb_str = '```\n' + trimmed_format_exc() + '```'
|
||||||
print(tb_str)
|
logger.error(tb_str)
|
||||||
mutable[0] += f"[Local Message] 警告,在执行过程中遭遇问题, Traceback:\n\n{tb_str}\n\n"
|
mutable[0] += f"[Local Message] 警告,在执行过程中遭遇问题, Traceback:\n\n{tb_str}\n\n"
|
||||||
if retry_op > 0:
|
if retry_op > 0:
|
||||||
retry_op -= 1
|
retry_op -= 1
|
||||||
@@ -135,18 +163,30 @@ def request_gpt_model_in_new_thread_with_ui_alive(
|
|||||||
yield from update_ui(chatbot=chatbot, history=[]) # 如果最后成功了,则删除报错信息
|
yield from update_ui(chatbot=chatbot, history=[]) # 如果最后成功了,则删除报错信息
|
||||||
return final_result
|
return final_result
|
||||||
|
|
||||||
def can_multi_process(llm):
|
def can_multi_process(llm) -> bool:
|
||||||
|
from request_llms.bridge_all import model_info
|
||||||
|
|
||||||
|
def default_condition(llm) -> bool:
|
||||||
|
# legacy condition
|
||||||
if llm.startswith('gpt-'): return True
|
if llm.startswith('gpt-'): return True
|
||||||
if llm.startswith('api2d-'): return True
|
if llm.startswith('api2d-'): return True
|
||||||
if llm.startswith('azure-'): return True
|
if llm.startswith('azure-'): return True
|
||||||
if llm.startswith('spark'): return True
|
if llm.startswith('spark'): return True
|
||||||
if llm.startswith('zhipuai'): return True
|
if llm.startswith('zhipuai') or llm.startswith('glm-'): return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
if llm in model_info:
|
||||||
|
if 'can_multi_thread' in model_info[llm]:
|
||||||
|
return model_info[llm]['can_multi_thread']
|
||||||
|
else:
|
||||||
|
return default_condition(llm)
|
||||||
|
else:
|
||||||
|
return default_condition(llm)
|
||||||
|
|
||||||
def request_gpt_model_multi_threads_with_very_awesome_ui_and_high_efficiency(
|
def request_gpt_model_multi_threads_with_very_awesome_ui_and_high_efficiency(
|
||||||
inputs_array, inputs_show_user_array, llm_kwargs,
|
inputs_array, inputs_show_user_array, llm_kwargs,
|
||||||
chatbot, history_array, sys_prompt_array,
|
chatbot, history_array, sys_prompt_array,
|
||||||
refresh_interval=0.2, max_workers=-1, scroller_max_len=30,
|
refresh_interval=0.2, max_workers=-1, scroller_max_len=75,
|
||||||
handle_token_exceed=True, show_user_at_complete=False,
|
handle_token_exceed=True, show_user_at_complete=False,
|
||||||
retry_times_at_unknown_error=2,
|
retry_times_at_unknown_error=2,
|
||||||
):
|
):
|
||||||
@@ -243,7 +283,7 @@ def request_gpt_model_multi_threads_with_very_awesome_ui_and_high_efficiency(
|
|||||||
# 【第三种情况】:其他错误
|
# 【第三种情况】:其他错误
|
||||||
if detect_timeout(): raise RuntimeError("检测到程序终止。")
|
if detect_timeout(): raise RuntimeError("检测到程序终止。")
|
||||||
tb_str = '```\n' + trimmed_format_exc() + '```'
|
tb_str = '```\n' + trimmed_format_exc() + '```'
|
||||||
print(tb_str)
|
logger.error(tb_str)
|
||||||
gpt_say += f"[Local Message] 警告,线程{index}在执行过程中遭遇问题, Traceback:\n\n{tb_str}\n\n"
|
gpt_say += f"[Local Message] 警告,线程{index}在执行过程中遭遇问题, Traceback:\n\n{tb_str}\n\n"
|
||||||
if len(mutable[index][0]) > 0: gpt_say += "此线程失败前收到的回答:\n\n" + mutable[index][0]
|
if len(mutable[index][0]) > 0: gpt_say += "此线程失败前收到的回答:\n\n" + mutable[index][0]
|
||||||
if retry_op > 0:
|
if retry_op > 0:
|
||||||
@@ -271,6 +311,8 @@ def request_gpt_model_multi_threads_with_very_awesome_ui_and_high_efficiency(
|
|||||||
futures = [executor.submit(_req_gpt, index, inputs, history, sys_prompt) for index, inputs, history, sys_prompt in zip(
|
futures = [executor.submit(_req_gpt, index, inputs, history, sys_prompt) for index, inputs, history, sys_prompt in zip(
|
||||||
range(len(inputs_array)), inputs_array, history_array, sys_prompt_array)]
|
range(len(inputs_array)), inputs_array, history_array, sys_prompt_array)]
|
||||||
cnt = 0
|
cnt = 0
|
||||||
|
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
# yield一次以刷新前端页面
|
# yield一次以刷新前端页面
|
||||||
time.sleep(refresh_interval)
|
time.sleep(refresh_interval)
|
||||||
@@ -283,9 +325,7 @@ def request_gpt_model_multi_threads_with_very_awesome_ui_and_high_efficiency(
|
|||||||
mutable[thread_index][1] = time.time()
|
mutable[thread_index][1] = time.time()
|
||||||
# 在前端打印些好玩的东西
|
# 在前端打印些好玩的东西
|
||||||
for thread_index, _ in enumerate(worker_done):
|
for thread_index, _ in enumerate(worker_done):
|
||||||
print_something_really_funny = "[ ...`"+mutable[thread_index][0][-scroller_max_len:].\
|
print_something_really_funny = f"[ ...`{scolling_visual_effect(mutable[thread_index][0], scroller_max_len)}`... ]"
|
||||||
replace('\n', '').replace('`', '.').replace(
|
|
||||||
' ', '.').replace('<br/>', '.....').replace('$', '.')+"`... ]"
|
|
||||||
observe_win.append(print_something_really_funny)
|
observe_win.append(print_something_really_funny)
|
||||||
# 在前端打印些好玩的东西
|
# 在前端打印些好玩的东西
|
||||||
stat_str = ''.join([f'`{mutable[thread_index][2]}`: {obs}\n\n'
|
stat_str = ''.join([f'`{mutable[thread_index][2]}`: {obs}\n\n'
|
||||||
@@ -338,7 +378,7 @@ def read_and_clean_pdf_text(fp):
|
|||||||
import fitz, copy
|
import fitz, copy
|
||||||
import re
|
import re
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from colorful import print亮黄, print亮绿
|
# from shared_utils.colorful import print亮黄, print亮绿
|
||||||
fc = 0 # Index 0 文本
|
fc = 0 # Index 0 文本
|
||||||
fs = 1 # Index 1 字体
|
fs = 1 # Index 1 字体
|
||||||
fb = 2 # Index 2 框框
|
fb = 2 # Index 2 框框
|
||||||
@@ -555,15 +595,15 @@ class nougat_interface():
|
|||||||
def nougat_with_timeout(self, command, cwd, timeout=3600):
|
def nougat_with_timeout(self, command, cwd, timeout=3600):
|
||||||
import subprocess
|
import subprocess
|
||||||
from toolbox import ProxyNetworkActivate
|
from toolbox import ProxyNetworkActivate
|
||||||
logging.info(f'正在执行命令 {command}')
|
logger.info(f'正在执行命令 {command}')
|
||||||
with ProxyNetworkActivate("Nougat_Download"):
|
with ProxyNetworkActivate("Nougat_Download"):
|
||||||
process = subprocess.Popen(command, shell=True, cwd=cwd, env=os.environ)
|
process = subprocess.Popen(command, shell=False, cwd=cwd, env=os.environ)
|
||||||
try:
|
try:
|
||||||
stdout, stderr = process.communicate(timeout=timeout)
|
stdout, stderr = process.communicate(timeout=timeout)
|
||||||
except subprocess.TimeoutExpired:
|
except subprocess.TimeoutExpired:
|
||||||
process.kill()
|
process.kill()
|
||||||
stdout, stderr = process.communicate()
|
stdout, stderr = process.communicate()
|
||||||
print("Process timed out!")
|
logger.error("Process timed out!")
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@@ -581,7 +621,8 @@ class nougat_interface():
|
|||||||
|
|
||||||
yield from update_ui_lastest_msg("正在解析论文, 请稍候。进度:正在加载NOUGAT... (提示:首次运行需要花费较长时间下载NOUGAT参数)",
|
yield from update_ui_lastest_msg("正在解析论文, 请稍候。进度:正在加载NOUGAT... (提示:首次运行需要花费较长时间下载NOUGAT参数)",
|
||||||
chatbot=chatbot, history=history, delay=0)
|
chatbot=chatbot, history=history, delay=0)
|
||||||
self.nougat_with_timeout(f'nougat --out "{os.path.abspath(dst)}" "{os.path.abspath(fp)}"', os.getcwd(), timeout=3600)
|
command = ['nougat', '--out', os.path.abspath(dst), os.path.abspath(fp)]
|
||||||
|
self.nougat_with_timeout(command, cwd=os.getcwd(), timeout=3600)
|
||||||
res = glob.glob(os.path.join(dst,'*.mmd'))
|
res = glob.glob(os.path.join(dst,'*.mmd'))
|
||||||
if len(res) == 0:
|
if len(res) == 0:
|
||||||
self.threadLock.release()
|
self.threadLock.release()
|
||||||
|
|||||||
@@ -0,0 +1,127 @@
|
|||||||
|
import os
|
||||||
|
from textwrap import indent
|
||||||
|
from loguru import logger
|
||||||
|
|
||||||
|
class FileNode:
|
||||||
|
def __init__(self, name, build_manifest=False):
|
||||||
|
self.name = name
|
||||||
|
self.children = []
|
||||||
|
self.is_leaf = False
|
||||||
|
self.level = 0
|
||||||
|
self.parenting_ship = []
|
||||||
|
self.comment = ""
|
||||||
|
self.comment_maxlen_show = 50
|
||||||
|
self.build_manifest = build_manifest
|
||||||
|
self.manifest = {}
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def add_linebreaks_at_spaces(string, interval=10):
|
||||||
|
return '\n'.join(string[i:i+interval] for i in range(0, len(string), interval))
|
||||||
|
|
||||||
|
def sanitize_comment(self, comment):
|
||||||
|
if len(comment) > self.comment_maxlen_show: suf = '...'
|
||||||
|
else: suf = ''
|
||||||
|
comment = comment[:self.comment_maxlen_show]
|
||||||
|
comment = comment.replace('\"', '').replace('`', '').replace('\n', '').replace('`', '').replace('$', '')
|
||||||
|
comment = self.add_linebreaks_at_spaces(comment, 10)
|
||||||
|
return '`' + comment + suf + '`'
|
||||||
|
|
||||||
|
def add_file(self, file_path, file_comment):
|
||||||
|
directory_names, file_name = os.path.split(file_path)
|
||||||
|
current_node = self
|
||||||
|
level = 1
|
||||||
|
if directory_names == "":
|
||||||
|
new_node = FileNode(file_name)
|
||||||
|
self.manifest[file_path] = new_node
|
||||||
|
current_node.children.append(new_node)
|
||||||
|
new_node.is_leaf = True
|
||||||
|
new_node.comment = self.sanitize_comment(file_comment)
|
||||||
|
new_node.level = level
|
||||||
|
current_node = new_node
|
||||||
|
else:
|
||||||
|
dnamesplit = directory_names.split(os.sep)
|
||||||
|
for i, directory_name in enumerate(dnamesplit):
|
||||||
|
found_child = False
|
||||||
|
level += 1
|
||||||
|
for child in current_node.children:
|
||||||
|
if child.name == directory_name:
|
||||||
|
current_node = child
|
||||||
|
found_child = True
|
||||||
|
break
|
||||||
|
if not found_child:
|
||||||
|
new_node = FileNode(directory_name)
|
||||||
|
current_node.children.append(new_node)
|
||||||
|
new_node.level = level - 1
|
||||||
|
current_node = new_node
|
||||||
|
term = FileNode(file_name)
|
||||||
|
self.manifest[file_path] = term
|
||||||
|
term.level = level
|
||||||
|
term.comment = self.sanitize_comment(file_comment)
|
||||||
|
term.is_leaf = True
|
||||||
|
current_node.children.append(term)
|
||||||
|
|
||||||
|
def print_files_recursively(self, level=0, code="R0"):
|
||||||
|
logger.info(' '*level + self.name + ' ' + str(self.is_leaf) + ' ' + str(self.level))
|
||||||
|
for j, child in enumerate(self.children):
|
||||||
|
child.print_files_recursively(level=level+1, code=code+str(j))
|
||||||
|
self.parenting_ship.extend(child.parenting_ship)
|
||||||
|
p1 = f"""{code}[\"🗎{self.name}\"]""" if self.is_leaf else f"""{code}[[\"📁{self.name}\"]]"""
|
||||||
|
p2 = """ --> """
|
||||||
|
p3 = f"""{code+str(j)}[\"🗎{child.name}\"]""" if child.is_leaf else f"""{code+str(j)}[[\"📁{child.name}\"]]"""
|
||||||
|
edge_code = p1 + p2 + p3
|
||||||
|
if edge_code in self.parenting_ship:
|
||||||
|
continue
|
||||||
|
self.parenting_ship.append(edge_code)
|
||||||
|
if self.comment != "":
|
||||||
|
pc1 = f"""{code}[\"🗎{self.name}\"]""" if self.is_leaf else f"""{code}[[\"📁{self.name}\"]]"""
|
||||||
|
pc2 = f""" -.-x """
|
||||||
|
pc3 = f"""C{code}[\"{self.comment}\"]:::Comment"""
|
||||||
|
edge_code = pc1 + pc2 + pc3
|
||||||
|
self.parenting_ship.append(edge_code)
|
||||||
|
|
||||||
|
|
||||||
|
MERMAID_TEMPLATE = r"""
|
||||||
|
```mermaid
|
||||||
|
flowchart LR
|
||||||
|
%% <gpt_academic_hide_mermaid_code> 一个特殊标记,用于在生成mermaid图表时隐藏代码块
|
||||||
|
classDef Comment stroke-dasharray: 5 5
|
||||||
|
subgraph {graph_name}
|
||||||
|
{relationship}
|
||||||
|
end
|
||||||
|
```
|
||||||
|
"""
|
||||||
|
|
||||||
|
def build_file_tree_mermaid_diagram(file_manifest, file_comments, graph_name):
|
||||||
|
# Create the root node
|
||||||
|
file_tree_struct = FileNode("root")
|
||||||
|
# Build the tree structure
|
||||||
|
for file_path, file_comment in zip(file_manifest, file_comments):
|
||||||
|
file_tree_struct.add_file(file_path, file_comment)
|
||||||
|
file_tree_struct.print_files_recursively()
|
||||||
|
cc = "\n".join(file_tree_struct.parenting_ship)
|
||||||
|
ccc = indent(cc, prefix=" "*8)
|
||||||
|
return MERMAID_TEMPLATE.format(graph_name=graph_name, relationship=ccc)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
# File manifest
|
||||||
|
file_manifest = [
|
||||||
|
"cradle_void_terminal.ipynb",
|
||||||
|
"tests/test_utils.py",
|
||||||
|
"tests/test_plugins.py",
|
||||||
|
"tests/test_llms.py",
|
||||||
|
"config.py",
|
||||||
|
"build/ChatGLM-6b-onnx-u8s8/chatglm-6b-int8-onnx-merged/model_weights_0.bin",
|
||||||
|
"crazy_functions/latex_fns/latex_actions.py",
|
||||||
|
"crazy_functions/latex_fns/latex_toolbox.py"
|
||||||
|
]
|
||||||
|
file_comments = [
|
||||||
|
"根据位置和名称,可能是一个模块的初始化文件根据位置和名称,可能是一个模块的初始化文件根据位置和名称,可能是一个模块的初始化文件",
|
||||||
|
"包含一些用于文本处理和模型微调的函数和装饰器包含一些用于文本处理和模型微调的函数和装饰器包含一些用于文本处理和模型微调的函数和装饰器",
|
||||||
|
"用于构建HTML报告的类和方法用于构建HTML报告的类和方法用于构建HTML报告的类和方法",
|
||||||
|
"包含了用于文本切分的函数,以及处理PDF文件的示例代码包含了用于文本切分的函数,以及处理PDF文件的示例代码包含了用于文本切分的函数,以及处理PDF文件的示例代码",
|
||||||
|
"用于解析和翻译PDF文件的功能和相关辅助函数用于解析和翻译PDF文件的功能和相关辅助函数用于解析和翻译PDF文件的功能和相关辅助函数",
|
||||||
|
"是一个包的初始化文件,用于初始化包的属性和导入模块是一个包的初始化文件,用于初始化包的属性和导入模块是一个包的初始化文件,用于初始化包的属性和导入模块",
|
||||||
|
"用于加载和分割文件中的文本的通用文件加载器用于加载和分割文件中的文本的通用文件加载器用于加载和分割文件中的文本的通用文件加载器",
|
||||||
|
"包含了用于构建和管理向量数据库的函数和类包含了用于构建和管理向量数据库的函数和类包含了用于构建和管理向量数据库的函数和类",
|
||||||
|
]
|
||||||
|
logger.info(build_file_tree_mermaid_diagram(file_manifest, file_comments, "项目文件树"))
|
||||||
@@ -0,0 +1,450 @@
|
|||||||
|
import os
|
||||||
|
import time
|
||||||
|
from abc import ABC, abstractmethod
|
||||||
|
from datetime import datetime
|
||||||
|
from docx import Document
|
||||||
|
from docx.enum.style import WD_STYLE_TYPE
|
||||||
|
from docx.enum.text import WD_PARAGRAPH_ALIGNMENT, WD_LINE_SPACING
|
||||||
|
from docx.oxml.ns import qn
|
||||||
|
from docx.shared import Inches, Cm
|
||||||
|
from docx.shared import Pt, RGBColor, Inches
|
||||||
|
from typing import Dict, List, Tuple
|
||||||
|
|
||||||
|
|
||||||
|
class DocumentFormatter(ABC):
|
||||||
|
"""文档格式化基类,定义文档格式化的基本接口"""
|
||||||
|
|
||||||
|
def __init__(self, final_summary: str, file_summaries_map: Dict, failed_files: List[Tuple]):
|
||||||
|
self.final_summary = final_summary
|
||||||
|
self.file_summaries_map = file_summaries_map
|
||||||
|
self.failed_files = failed_files
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def format_failed_files(self) -> str:
|
||||||
|
"""格式化失败文件列表"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def format_file_summaries(self) -> str:
|
||||||
|
"""格式化文件总结内容"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def create_document(self) -> str:
|
||||||
|
"""创建完整文档"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class WordFormatter(DocumentFormatter):
|
||||||
|
"""Word格式文档生成器 - 符合中国政府公文格式规范(GB/T 9704-2012),并进行了优化"""
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
self.doc = Document()
|
||||||
|
self._setup_document()
|
||||||
|
self._create_styles()
|
||||||
|
# 初始化三级标题编号系统
|
||||||
|
self.numbers = {
|
||||||
|
1: 0, # 一级标题编号
|
||||||
|
2: 0, # 二级标题编号
|
||||||
|
3: 0 # 三级标题编号
|
||||||
|
}
|
||||||
|
|
||||||
|
def _setup_document(self):
|
||||||
|
"""设置文档基本格式,包括页面设置和页眉"""
|
||||||
|
sections = self.doc.sections
|
||||||
|
for section in sections:
|
||||||
|
# 设置页面大小为A4
|
||||||
|
section.page_width = Cm(21)
|
||||||
|
section.page_height = Cm(29.7)
|
||||||
|
# 设置页边距
|
||||||
|
section.top_margin = Cm(3.7) # 上边距37mm
|
||||||
|
section.bottom_margin = Cm(3.5) # 下边距35mm
|
||||||
|
section.left_margin = Cm(2.8) # 左边距28mm
|
||||||
|
section.right_margin = Cm(2.6) # 右边距26mm
|
||||||
|
# 设置页眉页脚距离
|
||||||
|
section.header_distance = Cm(2.0)
|
||||||
|
section.footer_distance = Cm(2.0)
|
||||||
|
|
||||||
|
# 添加页眉
|
||||||
|
header = section.header
|
||||||
|
header_para = header.paragraphs[0]
|
||||||
|
header_para.alignment = WD_PARAGRAPH_ALIGNMENT.RIGHT
|
||||||
|
header_run = header_para.add_run("该文档由GPT-academic生成")
|
||||||
|
header_run.font.name = '仿宋'
|
||||||
|
header_run._element.rPr.rFonts.set(qn('w:eastAsia'), '仿宋')
|
||||||
|
header_run.font.size = Pt(9)
|
||||||
|
|
||||||
|
def _create_styles(self):
|
||||||
|
"""创建文档样式"""
|
||||||
|
# 创建正文样式
|
||||||
|
style = self.doc.styles.add_style('Normal_Custom', WD_STYLE_TYPE.PARAGRAPH)
|
||||||
|
style.font.name = '仿宋'
|
||||||
|
style._element.rPr.rFonts.set(qn('w:eastAsia'), '仿宋')
|
||||||
|
style.font.size = Pt(14)
|
||||||
|
style.paragraph_format.line_spacing_rule = WD_LINE_SPACING.ONE_POINT_FIVE
|
||||||
|
style.paragraph_format.space_after = Pt(0)
|
||||||
|
style.paragraph_format.first_line_indent = Pt(28)
|
||||||
|
|
||||||
|
# 创建各级标题样式
|
||||||
|
self._create_heading_style('Title_Custom', '方正小标宋简体', 32, WD_PARAGRAPH_ALIGNMENT.CENTER)
|
||||||
|
self._create_heading_style('Heading1_Custom', '黑体', 22, WD_PARAGRAPH_ALIGNMENT.LEFT)
|
||||||
|
self._create_heading_style('Heading2_Custom', '黑体', 18, WD_PARAGRAPH_ALIGNMENT.LEFT)
|
||||||
|
self._create_heading_style('Heading3_Custom', '黑体', 16, WD_PARAGRAPH_ALIGNMENT.LEFT)
|
||||||
|
|
||||||
|
def _create_heading_style(self, style_name: str, font_name: str, font_size: int, alignment):
|
||||||
|
"""创建标题样式"""
|
||||||
|
style = self.doc.styles.add_style(style_name, WD_STYLE_TYPE.PARAGRAPH)
|
||||||
|
style.font.name = font_name
|
||||||
|
style._element.rPr.rFonts.set(qn('w:eastAsia'), font_name)
|
||||||
|
style.font.size = Pt(font_size)
|
||||||
|
style.font.bold = True
|
||||||
|
style.paragraph_format.alignment = alignment
|
||||||
|
style.paragraph_format.space_before = Pt(12)
|
||||||
|
style.paragraph_format.space_after = Pt(12)
|
||||||
|
style.paragraph_format.line_spacing_rule = WD_LINE_SPACING.ONE_POINT_FIVE
|
||||||
|
return style
|
||||||
|
|
||||||
|
def _get_heading_number(self, level: int) -> str:
|
||||||
|
"""
|
||||||
|
生成标题编号
|
||||||
|
|
||||||
|
Args:
|
||||||
|
level: 标题级别 (0-3)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: 格式化的标题编号
|
||||||
|
"""
|
||||||
|
if level == 0: # 主标题不需要编号
|
||||||
|
return ""
|
||||||
|
|
||||||
|
self.numbers[level] += 1 # 增加当前级别的编号
|
||||||
|
|
||||||
|
# 重置下级标题编号
|
||||||
|
for i in range(level + 1, 4):
|
||||||
|
self.numbers[i] = 0
|
||||||
|
|
||||||
|
# 根据级别返回不同格式的编号
|
||||||
|
if level == 1:
|
||||||
|
return f"{self.numbers[1]}. "
|
||||||
|
elif level == 2:
|
||||||
|
return f"{self.numbers[1]}.{self.numbers[2]} "
|
||||||
|
elif level == 3:
|
||||||
|
return f"{self.numbers[1]}.{self.numbers[2]}.{self.numbers[3]} "
|
||||||
|
return ""
|
||||||
|
|
||||||
|
def _add_heading(self, text: str, level: int):
|
||||||
|
"""
|
||||||
|
添加带编号的标题
|
||||||
|
|
||||||
|
Args:
|
||||||
|
text: 标题文本
|
||||||
|
level: 标题级别 (0-3)
|
||||||
|
"""
|
||||||
|
style_map = {
|
||||||
|
0: 'Title_Custom',
|
||||||
|
1: 'Heading1_Custom',
|
||||||
|
2: 'Heading2_Custom',
|
||||||
|
3: 'Heading3_Custom'
|
||||||
|
}
|
||||||
|
|
||||||
|
number = self._get_heading_number(level)
|
||||||
|
paragraph = self.doc.add_paragraph(style=style_map[level])
|
||||||
|
|
||||||
|
if number:
|
||||||
|
number_run = paragraph.add_run(number)
|
||||||
|
font_size = 22 if level == 1 else (18 if level == 2 else 16)
|
||||||
|
self._get_run_style(number_run, '黑体', font_size, True)
|
||||||
|
|
||||||
|
text_run = paragraph.add_run(text)
|
||||||
|
font_size = 32 if level == 0 else (22 if level == 1 else (18 if level == 2 else 16))
|
||||||
|
self._get_run_style(text_run, '黑体', font_size, True)
|
||||||
|
|
||||||
|
# 主标题添加日期
|
||||||
|
if level == 0:
|
||||||
|
date_paragraph = self.doc.add_paragraph()
|
||||||
|
date_paragraph.alignment = WD_PARAGRAPH_ALIGNMENT.CENTER
|
||||||
|
date_run = date_paragraph.add_run(datetime.now().strftime('%Y年%m月%d日'))
|
||||||
|
self._get_run_style(date_run, '仿宋', 16, False)
|
||||||
|
|
||||||
|
return paragraph
|
||||||
|
|
||||||
|
def _get_run_style(self, run, font_name: str, font_size: int, bold: bool = False):
|
||||||
|
"""设置文本运行对象的样式"""
|
||||||
|
run.font.name = font_name
|
||||||
|
run._element.rPr.rFonts.set(qn('w:eastAsia'), font_name)
|
||||||
|
run.font.size = Pt(font_size)
|
||||||
|
run.font.bold = bold
|
||||||
|
|
||||||
|
def format_failed_files(self) -> str:
|
||||||
|
"""格式化失败文件列表"""
|
||||||
|
result = []
|
||||||
|
if not self.failed_files:
|
||||||
|
return "\n".join(result)
|
||||||
|
|
||||||
|
result.append("处理失败文件:")
|
||||||
|
for fp, reason in self.failed_files:
|
||||||
|
result.append(f"• {os.path.basename(fp)}: {reason}")
|
||||||
|
|
||||||
|
self._add_heading("处理失败文件", 1)
|
||||||
|
for fp, reason in self.failed_files:
|
||||||
|
self._add_content(f"• {os.path.basename(fp)}: {reason}", indent=False)
|
||||||
|
self.doc.add_paragraph()
|
||||||
|
|
||||||
|
return "\n".join(result)
|
||||||
|
|
||||||
|
def _add_content(self, text: str, indent: bool = True):
|
||||||
|
"""添加正文内容"""
|
||||||
|
paragraph = self.doc.add_paragraph(text, style='Normal_Custom')
|
||||||
|
if not indent:
|
||||||
|
paragraph.paragraph_format.first_line_indent = Pt(0)
|
||||||
|
return paragraph
|
||||||
|
|
||||||
|
def format_file_summaries(self) -> str:
|
||||||
|
"""
|
||||||
|
格式化文件总结内容,确保正确的标题层级
|
||||||
|
|
||||||
|
返回:
|
||||||
|
str: 格式化后的文件总结字符串
|
||||||
|
|
||||||
|
标题层级规则:
|
||||||
|
1. 一级标题为"各文件详细总结"
|
||||||
|
2. 如果文件有目录路径:
|
||||||
|
- 目录路径作为二级标题 (2.1, 2.2 等)
|
||||||
|
- 该目录下所有文件作为三级标题 (2.1.1, 2.1.2 等)
|
||||||
|
3. 如果文件没有目录路径:
|
||||||
|
- 文件直接作为二级标题 (2.1, 2.2 等)
|
||||||
|
"""
|
||||||
|
result = []
|
||||||
|
# 首先对文件路径进行分组整理
|
||||||
|
file_groups = {}
|
||||||
|
for path in sorted(self.file_summaries_map.keys()):
|
||||||
|
dir_path = os.path.dirname(path)
|
||||||
|
if dir_path not in file_groups:
|
||||||
|
file_groups[dir_path] = []
|
||||||
|
file_groups[dir_path].append(path)
|
||||||
|
|
||||||
|
# 处理没有目录的文件
|
||||||
|
root_files = file_groups.get("", [])
|
||||||
|
if root_files:
|
||||||
|
for path in sorted(root_files):
|
||||||
|
file_name = os.path.basename(path)
|
||||||
|
result.append(f"\n📄 {file_name}")
|
||||||
|
result.append(self.file_summaries_map[path])
|
||||||
|
# 无目录的文件作为二级标题
|
||||||
|
self._add_heading(f"📄 {file_name}", 2)
|
||||||
|
self._add_content(self.file_summaries_map[path])
|
||||||
|
self.doc.add_paragraph()
|
||||||
|
|
||||||
|
# 处理有目录的文件
|
||||||
|
for dir_path in sorted(file_groups.keys()):
|
||||||
|
if dir_path == "": # 跳过已处理的根目录文件
|
||||||
|
continue
|
||||||
|
|
||||||
|
# 添加目录作为二级标题
|
||||||
|
result.append(f"\n📁 {dir_path}")
|
||||||
|
self._add_heading(f"📁 {dir_path}", 2)
|
||||||
|
|
||||||
|
# 该目录下的所有文件作为三级标题
|
||||||
|
for path in sorted(file_groups[dir_path]):
|
||||||
|
file_name = os.path.basename(path)
|
||||||
|
result.append(f"\n📄 {file_name}")
|
||||||
|
result.append(self.file_summaries_map[path])
|
||||||
|
|
||||||
|
# 添加文件名作为三级标题
|
||||||
|
self._add_heading(f"📄 {file_name}", 3)
|
||||||
|
self._add_content(self.file_summaries_map[path])
|
||||||
|
self.doc.add_paragraph()
|
||||||
|
|
||||||
|
return "\n".join(result)
|
||||||
|
|
||||||
|
|
||||||
|
def create_document(self):
|
||||||
|
"""创建完整Word文档并返回文档对象"""
|
||||||
|
# 重置所有编号
|
||||||
|
for level in self.numbers:
|
||||||
|
self.numbers[level] = 0
|
||||||
|
|
||||||
|
# 添加主标题
|
||||||
|
self._add_heading("文档总结报告", 0)
|
||||||
|
self.doc.add_paragraph()
|
||||||
|
|
||||||
|
# 添加总体摘要
|
||||||
|
self._add_heading("总体摘要", 1)
|
||||||
|
self._add_content(self.final_summary)
|
||||||
|
self.doc.add_paragraph()
|
||||||
|
|
||||||
|
# 添加失败文件列表(如果有)
|
||||||
|
if self.failed_files:
|
||||||
|
self.format_failed_files()
|
||||||
|
|
||||||
|
# 添加文件详细总结
|
||||||
|
self._add_heading("各文件详细总结", 1)
|
||||||
|
self.format_file_summaries()
|
||||||
|
|
||||||
|
return self.doc
|
||||||
|
|
||||||
|
|
||||||
|
class MarkdownFormatter(DocumentFormatter):
|
||||||
|
"""Markdown格式文档生成器"""
|
||||||
|
|
||||||
|
def format_failed_files(self) -> str:
|
||||||
|
if not self.failed_files:
|
||||||
|
return ""
|
||||||
|
|
||||||
|
formatted_text = ["\n## ⚠️ 处理失败的文件"]
|
||||||
|
for fp, reason in self.failed_files:
|
||||||
|
formatted_text.append(f"- {os.path.basename(fp)}: {reason}")
|
||||||
|
formatted_text.append("\n---")
|
||||||
|
return "\n".join(formatted_text)
|
||||||
|
|
||||||
|
def format_file_summaries(self) -> str:
|
||||||
|
formatted_text = []
|
||||||
|
sorted_paths = sorted(self.file_summaries_map.keys())
|
||||||
|
current_dir = ""
|
||||||
|
|
||||||
|
for path in sorted_paths:
|
||||||
|
dir_path = os.path.dirname(path)
|
||||||
|
if dir_path != current_dir:
|
||||||
|
if dir_path:
|
||||||
|
formatted_text.append(f"\n## 📁 {dir_path}")
|
||||||
|
current_dir = dir_path
|
||||||
|
|
||||||
|
file_name = os.path.basename(path)
|
||||||
|
formatted_text.append(f"\n### 📄 {file_name}")
|
||||||
|
formatted_text.append(self.file_summaries_map[path])
|
||||||
|
formatted_text.append("\n---")
|
||||||
|
|
||||||
|
return "\n".join(formatted_text)
|
||||||
|
|
||||||
|
def create_document(self) -> str:
|
||||||
|
document = [
|
||||||
|
"# 📑 文档总结报告",
|
||||||
|
"\n## 总体摘要",
|
||||||
|
self.final_summary
|
||||||
|
]
|
||||||
|
|
||||||
|
if self.failed_files:
|
||||||
|
document.append(self.format_failed_files())
|
||||||
|
|
||||||
|
document.extend([
|
||||||
|
"\n# 📚 各文件详细总结",
|
||||||
|
self.format_file_summaries()
|
||||||
|
])
|
||||||
|
|
||||||
|
return "\n".join(document)
|
||||||
|
|
||||||
|
|
||||||
|
class HtmlFormatter(DocumentFormatter):
|
||||||
|
"""HTML格式文档生成器"""
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
self.css_styles = """
|
||||||
|
body {
|
||||||
|
font-family: "Microsoft YaHei", Arial, sans-serif;
|
||||||
|
line-height: 1.6;
|
||||||
|
max-width: 1000px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 20px;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
h1 {
|
||||||
|
color: #2c3e50;
|
||||||
|
border-bottom: 2px solid #eee;
|
||||||
|
padding-bottom: 10px;
|
||||||
|
font-size: 24px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
h2 {
|
||||||
|
color: #34495e;
|
||||||
|
margin-top: 30px;
|
||||||
|
font-size: 20px;
|
||||||
|
border-left: 4px solid #3498db;
|
||||||
|
padding-left: 10px;
|
||||||
|
}
|
||||||
|
h3 {
|
||||||
|
color: #2c3e50;
|
||||||
|
font-size: 18px;
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
.summary {
|
||||||
|
background-color: #f8f9fa;
|
||||||
|
padding: 20px;
|
||||||
|
border-radius: 5px;
|
||||||
|
margin: 20px 0;
|
||||||
|
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
||||||
|
}
|
||||||
|
.details {
|
||||||
|
margin-top: 40px;
|
||||||
|
}
|
||||||
|
.failed-files {
|
||||||
|
background-color: #fff3f3;
|
||||||
|
padding: 15px;
|
||||||
|
border-left: 4px solid #e74c3c;
|
||||||
|
margin: 20px 0;
|
||||||
|
}
|
||||||
|
.file-summary {
|
||||||
|
background-color: #fff;
|
||||||
|
padding: 15px;
|
||||||
|
margin: 15px 0;
|
||||||
|
border-radius: 4px;
|
||||||
|
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
|
||||||
|
def format_failed_files(self) -> str:
|
||||||
|
if not self.failed_files:
|
||||||
|
return ""
|
||||||
|
|
||||||
|
failed_files_html = ['<div class="failed-files">']
|
||||||
|
failed_files_html.append("<h2>⚠️ 处理失败的文件</h2>")
|
||||||
|
failed_files_html.append("<ul>")
|
||||||
|
for fp, reason in self.failed_files:
|
||||||
|
failed_files_html.append(f"<li><strong>{os.path.basename(fp)}:</strong> {reason}</li>")
|
||||||
|
failed_files_html.append("</ul></div>")
|
||||||
|
return "\n".join(failed_files_html)
|
||||||
|
|
||||||
|
def format_file_summaries(self) -> str:
|
||||||
|
formatted_html = []
|
||||||
|
sorted_paths = sorted(self.file_summaries_map.keys())
|
||||||
|
current_dir = ""
|
||||||
|
|
||||||
|
for path in sorted_paths:
|
||||||
|
dir_path = os.path.dirname(path)
|
||||||
|
if dir_path != current_dir:
|
||||||
|
if dir_path:
|
||||||
|
formatted_html.append(f'<h2>📁 {dir_path}</h2>')
|
||||||
|
current_dir = dir_path
|
||||||
|
|
||||||
|
file_name = os.path.basename(path)
|
||||||
|
formatted_html.append('<div class="file-summary">')
|
||||||
|
formatted_html.append(f'<h3>📄 {file_name}</h3>')
|
||||||
|
formatted_html.append(f'<p>{self.file_summaries_map[path]}</p>')
|
||||||
|
formatted_html.append('</div>')
|
||||||
|
|
||||||
|
return "\n".join(formatted_html)
|
||||||
|
|
||||||
|
def create_document(self) -> str:
|
||||||
|
return f"""
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset='utf-8'>
|
||||||
|
<title>文档总结报告</title>
|
||||||
|
<style>{self.css_styles}</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>📑 文档总结报告</h1>
|
||||||
|
<h2>总体摘要</h2>
|
||||||
|
<div class="summary">{self.final_summary}</div>
|
||||||
|
{self.format_failed_files()}
|
||||||
|
<div class="details">
|
||||||
|
<h2>📚 各文件详细总结</h2>
|
||||||
|
{self.format_file_summaries()}
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
@@ -92,7 +92,7 @@ class MiniGame_ResumeStory(GptAcademicGameBaseState):
|
|||||||
|
|
||||||
def generate_story_image(self, story_paragraph):
|
def generate_story_image(self, story_paragraph):
|
||||||
try:
|
try:
|
||||||
from crazy_functions.图片生成 import gen_image
|
from crazy_functions.Image_Generate import gen_image
|
||||||
prompt_ = predict_no_ui_long_connection(inputs=story_paragraph, llm_kwargs=self.llm_kwargs, history=[], sys_prompt='你需要根据用户给出的小说段落,进行简短的环境描写。要求:80字以内。')
|
prompt_ = predict_no_ui_long_connection(inputs=story_paragraph, llm_kwargs=self.llm_kwargs, history=[], sys_prompt='你需要根据用户给出的小说段落,进行简短的环境描写。要求:80字以内。')
|
||||||
image_url, image_path = gen_image(self.llm_kwargs, prompt_, '512x512', model="dall-e-2", quality='standard', style='natural')
|
image_url, image_path = gen_image(self.llm_kwargs, prompt_, '512x512', model="dall-e-2", quality='standard', style='natural')
|
||||||
return f'<br/><div align="center"><img src="file={image_path}"></div>'
|
return f'<br/><div align="center"><img src="file={image_path}"></div>'
|
||||||
|
|||||||
@@ -24,8 +24,8 @@ class Actor(BaseModel):
|
|||||||
film_names: List[str] = Field(description="list of names of films they starred in")
|
film_names: List[str] = Field(description="list of names of films they starred in")
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import json, re, logging
|
import json, re
|
||||||
|
from loguru import logger as logging
|
||||||
|
|
||||||
PYDANTIC_FORMAT_INSTRUCTIONS = """The output should be formatted as a JSON instance that conforms to the JSON schema below.
|
PYDANTIC_FORMAT_INSTRUCTIONS = """The output should be formatted as a JSON instance that conforms to the JSON schema below.
|
||||||
|
|
||||||
@@ -62,8 +62,8 @@ class GptJsonIO():
|
|||||||
if "type" in reduced_schema:
|
if "type" in reduced_schema:
|
||||||
del reduced_schema["type"]
|
del reduced_schema["type"]
|
||||||
# Ensure json in context is well-formed with double quotes.
|
# Ensure json in context is well-formed with double quotes.
|
||||||
if self.example_instruction:
|
|
||||||
schema_str = json.dumps(reduced_schema)
|
schema_str = json.dumps(reduced_schema)
|
||||||
|
if self.example_instruction:
|
||||||
return PYDANTIC_FORMAT_INSTRUCTIONS.format(schema=schema_str)
|
return PYDANTIC_FORMAT_INSTRUCTIONS.format(schema=schema_str)
|
||||||
else:
|
else:
|
||||||
return PYDANTIC_FORMAT_INSTRUCTIONS_SIMPLE.format(schema=schema_str)
|
return PYDANTIC_FORMAT_INSTRUCTIONS_SIMPLE.format(schema=schema_str)
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
from crazy_functions.json_fns.pydantic_io import GptJsonIO, JsonStringError
|
||||||
|
|
||||||
|
def structure_output(txt, prompt, err_msg, run_gpt_fn, pydantic_cls):
|
||||||
|
gpt_json_io = GptJsonIO(pydantic_cls)
|
||||||
|
analyze_res = run_gpt_fn(
|
||||||
|
txt,
|
||||||
|
sys_prompt=prompt + gpt_json_io.format_instructions
|
||||||
|
)
|
||||||
|
try:
|
||||||
|
friend = gpt_json_io.generate_output_auto_repair(analyze_res, run_gpt_fn)
|
||||||
|
except JsonStringError as e:
|
||||||
|
return None, err_msg
|
||||||
|
|
||||||
|
err_msg = ""
|
||||||
|
return friend, err_msg
|
||||||
|
|
||||||
|
|
||||||
|
def select_tool(prompt, run_gpt_fn, pydantic_cls):
|
||||||
|
pydantic_cls_instance, err_msg = structure_output(
|
||||||
|
txt=prompt,
|
||||||
|
prompt="根据提示, 分析应该调用哪个工具函数\n\n",
|
||||||
|
err_msg=f"不能理解该联系人",
|
||||||
|
run_gpt_fn=run_gpt_fn,
|
||||||
|
pydantic_cls=pydantic_cls
|
||||||
|
)
|
||||||
|
return pydantic_cls_instance, err_msg
|
||||||
@@ -1,14 +1,17 @@
|
|||||||
from toolbox import update_ui, update_ui_lastest_msg, get_log_folder
|
import os
|
||||||
from toolbox import get_conf, 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
|
|
||||||
from .latex_toolbox import find_title_and_abs
|
|
||||||
|
|
||||||
import os, shutil
|
|
||||||
import re
|
import re
|
||||||
|
import shutil
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
from loguru import logger
|
||||||
|
from toolbox import update_ui, update_ui_lastest_msg, get_log_folder, gen_time_str
|
||||||
|
from toolbox import get_conf, promote_file_to_downloadzone
|
||||||
|
from crazy_functions.latex_fns.latex_toolbox import PRESERVE, TRANSFORM
|
||||||
|
from crazy_functions.latex_fns.latex_toolbox import set_forbidden_text, set_forbidden_text_begin_end, set_forbidden_text_careful_brace
|
||||||
|
from crazy_functions.latex_fns.latex_toolbox import reverse_forbidden_text_careful_brace, reverse_forbidden_text, convert_to_linklist, post_process
|
||||||
|
from crazy_functions.latex_fns.latex_toolbox import fix_content, find_main_tex_file, merge_tex_files, compile_latex_with_timeout
|
||||||
|
from crazy_functions.latex_fns.latex_toolbox import find_title_and_abs
|
||||||
|
from crazy_functions.latex_fns.latex_pickle_io import objdump, objload
|
||||||
|
|
||||||
|
|
||||||
pj = os.path.join
|
pj = os.path.join
|
||||||
|
|
||||||
@@ -322,7 +325,7 @@ def remove_buggy_lines(file_path, log_path, tex_name, tex_name_pure, n_fix, work
|
|||||||
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
|
buggy_line = buggy_lines[0]-1
|
||||||
print("reversing tex line that has errors", buggy_line)
|
logger.warning("reversing tex line that has errors", buggy_line)
|
||||||
|
|
||||||
# 重组,逆转出错的段落
|
# 重组,逆转出错的段落
|
||||||
if buggy_line not in fixed_line:
|
if buggy_line not in fixed_line:
|
||||||
@@ -336,7 +339,7 @@ def remove_buggy_lines(file_path, log_path, tex_name, tex_name_pure, n_fix, work
|
|||||||
|
|
||||||
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.")
|
logger.error("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]
|
||||||
|
|
||||||
|
|
||||||
@@ -379,7 +382,7 @@ def 编译Latex(chatbot, history, main_file_original, main_file_modified, work_f
|
|||||||
|
|
||||||
if mode!='translate_zh':
|
if mode!='translate_zh':
|
||||||
yield from update_ui_lastest_msg(f'尝试第 {n_fix}/{max_try} 次编译, 使用latexdiff生成论文转化前后对比 ...', chatbot, history) # 刷新Gradio前端界面
|
yield from update_ui_lastest_msg(f'尝试第 {n_fix}/{max_try} 次编译, 使用latexdiff生成论文转化前后对比 ...', chatbot, history) # 刷新Gradio前端界面
|
||||||
print( f'latexdiff --encoding=utf8 --append-safecmd=subfile {work_folder_original}/{main_file_original}.tex {work_folder_modified}/{main_file_modified}.tex --flatten > {work_folder}/merge_diff.tex')
|
logger.info( f'latexdiff --encoding=utf8 --append-safecmd=subfile {work_folder_original}/{main_file_original}.tex {work_folder_modified}/{main_file_modified}.tex --flatten > {work_folder}/merge_diff.tex')
|
||||||
ok = compile_latex_with_timeout(f'latexdiff --encoding=utf8 --append-safecmd=subfile {work_folder_original}/{main_file_original}.tex {work_folder_modified}/{main_file_modified}.tex --flatten > {work_folder}/merge_diff.tex', os.getcwd())
|
ok = compile_latex_with_timeout(f'latexdiff --encoding=utf8 --append-safecmd=subfile {work_folder_original}/{main_file_original}.tex {work_folder_modified}/{main_file_modified}.tex --flatten > {work_folder}/merge_diff.tex', os.getcwd())
|
||||||
|
|
||||||
yield from update_ui_lastest_msg(f'尝试第 {n_fix}/{max_try} 次编译, 正在编译对比PDF ...', chatbot, history) # 刷新Gradio前端界面
|
yield from update_ui_lastest_msg(f'尝试第 {n_fix}/{max_try} 次编译, 正在编译对比PDF ...', chatbot, history) # 刷新Gradio前端界面
|
||||||
@@ -418,7 +421,7 @@ def 编译Latex(chatbot, history, main_file_original, main_file_modified, work_f
|
|||||||
shutil.copyfile(concat_pdf, pj(work_folder, '..', 'translation', 'comparison.pdf'))
|
shutil.copyfile(concat_pdf, pj(work_folder, '..', 'translation', 'comparison.pdf'))
|
||||||
promote_file_to_downloadzone(concat_pdf, rename_file=None, chatbot=chatbot) # promote file to web UI
|
promote_file_to_downloadzone(concat_pdf, rename_file=None, chatbot=chatbot) # promote file to web UI
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(e)
|
logger.error(e)
|
||||||
pass
|
pass
|
||||||
return True # 成功啦
|
return True # 成功啦
|
||||||
else:
|
else:
|
||||||
@@ -464,4 +467,71 @@ def write_html(sp_file_contents, sp_file_result, chatbot, project_folder):
|
|||||||
promote_file_to_downloadzone(file=res, chatbot=chatbot)
|
promote_file_to_downloadzone(file=res, chatbot=chatbot)
|
||||||
except:
|
except:
|
||||||
from toolbox import trimmed_format_exc
|
from toolbox import trimmed_format_exc
|
||||||
print('writing html result failed:', trimmed_format_exc())
|
logger.error('writing html result failed:', trimmed_format_exc())
|
||||||
|
|
||||||
|
|
||||||
|
def upload_to_gptac_cloud_if_user_allow(chatbot, arxiv_id):
|
||||||
|
try:
|
||||||
|
# 如果用户允许,我们将arxiv论文PDF上传到GPTAC学术云
|
||||||
|
from toolbox import map_file_to_sha256
|
||||||
|
# 检查是否顺利,如果没有生成预期的文件,则跳过
|
||||||
|
is_result_good = False
|
||||||
|
for file_path in chatbot._cookies.get("files_to_promote", []):
|
||||||
|
if file_path.endswith('translate_zh.pdf'):
|
||||||
|
is_result_good = True
|
||||||
|
if not is_result_good:
|
||||||
|
return
|
||||||
|
# 上传文件
|
||||||
|
for file_path in chatbot._cookies.get("files_to_promote", []):
|
||||||
|
align_name = None
|
||||||
|
# normalized name
|
||||||
|
for name in ['translate_zh.pdf', 'comparison.pdf']:
|
||||||
|
if file_path.endswith(name): align_name = name
|
||||||
|
# if match any align name
|
||||||
|
if align_name:
|
||||||
|
logger.info(f'Uploading to GPTAC cloud as the user has set `allow_cloud_io`: {file_path}')
|
||||||
|
with open(file_path, 'rb') as f:
|
||||||
|
import requests
|
||||||
|
url = 'https://cloud-2.agent-matrix.com/arxiv_tf_paper_normal_upload'
|
||||||
|
files = {'file': (align_name, f, 'application/octet-stream')}
|
||||||
|
data = {
|
||||||
|
'arxiv_id': arxiv_id,
|
||||||
|
'file_hash': map_file_to_sha256(file_path),
|
||||||
|
'language': 'zh',
|
||||||
|
'trans_prompt': 'to_be_implemented',
|
||||||
|
'llm_model': 'to_be_implemented',
|
||||||
|
'llm_model_param': 'to_be_implemented',
|
||||||
|
}
|
||||||
|
resp = requests.post(url=url, files=files, data=data, timeout=30)
|
||||||
|
logger.info(f'Uploading terminate ({resp.status_code})`: {file_path}')
|
||||||
|
except:
|
||||||
|
# 如果上传失败,不会中断程序,因为这是次要功能
|
||||||
|
pass
|
||||||
|
|
||||||
|
def check_gptac_cloud(arxiv_id, chatbot):
|
||||||
|
import requests
|
||||||
|
success = False
|
||||||
|
downloaded = []
|
||||||
|
try:
|
||||||
|
for pdf_target in ['translate_zh.pdf', 'comparison.pdf']:
|
||||||
|
url = 'https://cloud-2.agent-matrix.com/arxiv_tf_paper_normal_exist'
|
||||||
|
data = {
|
||||||
|
'arxiv_id': arxiv_id,
|
||||||
|
'name': pdf_target,
|
||||||
|
}
|
||||||
|
resp = requests.post(url=url, data=data)
|
||||||
|
cache_hit_result = resp.text.strip('"')
|
||||||
|
if cache_hit_result.startswith("http"):
|
||||||
|
url = cache_hit_result
|
||||||
|
logger.info(f'Downloading from GPTAC cloud: {url}')
|
||||||
|
resp = requests.get(url=url, timeout=30)
|
||||||
|
target = os.path.join(get_log_folder(plugin_name='gptac_cloud'), gen_time_str(), pdf_target)
|
||||||
|
os.makedirs(os.path.dirname(target), exist_ok=True)
|
||||||
|
with open(target, 'wb') as f:
|
||||||
|
f.write(resp.content)
|
||||||
|
new_path = promote_file_to_downloadzone(target, chatbot=chatbot)
|
||||||
|
success = True
|
||||||
|
downloaded.append(new_path)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
return success, downloaded
|
||||||
|
|||||||
@@ -0,0 +1,46 @@
|
|||||||
|
import pickle
|
||||||
|
|
||||||
|
|
||||||
|
class SafeUnpickler(pickle.Unpickler):
|
||||||
|
|
||||||
|
def get_safe_classes(self):
|
||||||
|
from crazy_functions.latex_fns.latex_actions import LatexPaperFileGroup, LatexPaperSplit
|
||||||
|
from crazy_functions.latex_fns.latex_toolbox import LinkedListNode
|
||||||
|
# 定义允许的安全类
|
||||||
|
safe_classes = {
|
||||||
|
# 在这里添加其他安全的类
|
||||||
|
'LatexPaperFileGroup': LatexPaperFileGroup,
|
||||||
|
'LatexPaperSplit': LatexPaperSplit,
|
||||||
|
'LinkedListNode': LinkedListNode,
|
||||||
|
}
|
||||||
|
return safe_classes
|
||||||
|
|
||||||
|
def find_class(self, module, name):
|
||||||
|
# 只允许特定的类进行反序列化
|
||||||
|
self.safe_classes = self.get_safe_classes()
|
||||||
|
match_class_name = None
|
||||||
|
for class_name in self.safe_classes.keys():
|
||||||
|
if (class_name in f'{module}.{name}'):
|
||||||
|
match_class_name = class_name
|
||||||
|
if module == 'numpy' or module.startswith('numpy.'):
|
||||||
|
return super().find_class(module, name)
|
||||||
|
if match_class_name is not None:
|
||||||
|
return self.safe_classes[match_class_name]
|
||||||
|
# 如果尝试加载未授权的类,则抛出异常
|
||||||
|
raise pickle.UnpicklingError(f"Attempted to deserialize unauthorized class '{name}' from module '{module}'")
|
||||||
|
|
||||||
|
def objdump(obj, file="objdump.tmp"):
|
||||||
|
|
||||||
|
with open(file, "wb+") as f:
|
||||||
|
pickle.dump(obj, f)
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
def objload(file="objdump.tmp"):
|
||||||
|
import os
|
||||||
|
|
||||||
|
if not os.path.exists(file):
|
||||||
|
return
|
||||||
|
with open(file, "rb") as f:
|
||||||
|
unpickler = SafeUnpickler(f)
|
||||||
|
return unpickler.load()
|
||||||
@@ -1,15 +1,20 @@
|
|||||||
import os, shutil
|
import os
|
||||||
import re
|
import re
|
||||||
|
import shutil
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
from loguru import logger
|
||||||
|
|
||||||
PRESERVE = 0
|
PRESERVE = 0
|
||||||
TRANSFORM = 1
|
TRANSFORM = 1
|
||||||
|
|
||||||
pj = os.path.join
|
pj = os.path.join
|
||||||
|
|
||||||
class LinkedListNode():
|
|
||||||
|
class LinkedListNode:
|
||||||
"""
|
"""
|
||||||
Linked List Node
|
Linked List Node
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, string, preserve=True) -> None:
|
def __init__(self, string, preserve=True) -> None:
|
||||||
self.string = string
|
self.string = string
|
||||||
self.preserve = preserve
|
self.preserve = preserve
|
||||||
@@ -18,12 +23,14 @@ class LinkedListNode():
|
|||||||
# self.begin_line = 0
|
# self.begin_line = 0
|
||||||
# self.begin_char = 0
|
# self.begin_char = 0
|
||||||
|
|
||||||
|
|
||||||
def convert_to_linklist(text, mask):
|
def convert_to_linklist(text, mask):
|
||||||
root = LinkedListNode("", preserve=True)
|
root = LinkedListNode("", preserve=True)
|
||||||
current_node = root
|
current_node = root
|
||||||
for c, m, i in zip(text, mask, range(len(text))):
|
for c, m, i in zip(text, mask, range(len(text))):
|
||||||
if (m==PRESERVE and current_node.preserve) \
|
if (m == PRESERVE and current_node.preserve) or (
|
||||||
or (m==TRANSFORM and not current_node.preserve):
|
m == TRANSFORM and not current_node.preserve
|
||||||
|
):
|
||||||
# add
|
# add
|
||||||
current_node.string += c
|
current_node.string += c
|
||||||
else:
|
else:
|
||||||
@@ -31,6 +38,7 @@ def convert_to_linklist(text, mask):
|
|||||||
current_node = current_node.next
|
current_node = current_node.next
|
||||||
return root
|
return root
|
||||||
|
|
||||||
|
|
||||||
def post_process(root):
|
def post_process(root):
|
||||||
# 修复括号
|
# 修复括号
|
||||||
node = root
|
node = root
|
||||||
@@ -38,21 +46,24 @@ def post_process(root):
|
|||||||
string = node.string
|
string = node.string
|
||||||
if node.preserve:
|
if node.preserve:
|
||||||
node = node.next
|
node = node.next
|
||||||
if node is None: break
|
if node is None:
|
||||||
|
break
|
||||||
continue
|
continue
|
||||||
|
|
||||||
def break_check(string):
|
def break_check(string):
|
||||||
str_stack = [""] # (lv, index)
|
str_stack = [""] # (lv, index)
|
||||||
for i, c in enumerate(string):
|
for i, c in enumerate(string):
|
||||||
if c == '{':
|
if c == "{":
|
||||||
str_stack.append('{')
|
str_stack.append("{")
|
||||||
elif c == '}':
|
elif c == "}":
|
||||||
if len(str_stack) == 1:
|
if len(str_stack) == 1:
|
||||||
print('stack fix')
|
logger.warning("fixing brace error")
|
||||||
return i
|
return i
|
||||||
str_stack.pop(-1)
|
str_stack.pop(-1)
|
||||||
else:
|
else:
|
||||||
str_stack[-1] += c
|
str_stack[-1] += c
|
||||||
return -1
|
return -1
|
||||||
|
|
||||||
bp = break_check(string)
|
bp = break_check(string)
|
||||||
|
|
||||||
if bp == -1:
|
if bp == -1:
|
||||||
@@ -69,51 +80,66 @@ def post_process(root):
|
|||||||
node.next = q
|
node.next = q
|
||||||
|
|
||||||
node = node.next
|
node = node.next
|
||||||
if node is None: break
|
if node is None:
|
||||||
|
break
|
||||||
|
|
||||||
# 屏蔽空行和太短的句子
|
# 屏蔽空行和太短的句子
|
||||||
node = root
|
node = root
|
||||||
while True:
|
while True:
|
||||||
if len(node.string.strip('\n').strip(''))==0: node.preserve = True
|
if len(node.string.strip("\n").strip("")) == 0:
|
||||||
if len(node.string.strip('\n').strip(''))<42: node.preserve = True
|
node.preserve = True
|
||||||
|
if len(node.string.strip("\n").strip("")) < 42:
|
||||||
|
node.preserve = True
|
||||||
node = node.next
|
node = node.next
|
||||||
if node is None: break
|
if node is None:
|
||||||
|
break
|
||||||
node = root
|
node = root
|
||||||
while True:
|
while True:
|
||||||
if node.next and node.preserve and node.next.preserve:
|
if node.next and node.preserve and node.next.preserve:
|
||||||
node.string += node.next.string
|
node.string += node.next.string
|
||||||
node.next = node.next.next
|
node.next = node.next.next
|
||||||
node = node.next
|
node = node.next
|
||||||
if node is None: break
|
if node is None:
|
||||||
|
break
|
||||||
|
|
||||||
# 将前后断行符脱离
|
# 将前后断行符脱离
|
||||||
node = root
|
node = root
|
||||||
prev_node = None
|
prev_node = None
|
||||||
while True:
|
while True:
|
||||||
if not node.preserve:
|
if not node.preserve:
|
||||||
lstriped_ = node.string.lstrip().lstrip('\n')
|
lstriped_ = node.string.lstrip().lstrip("\n")
|
||||||
if (prev_node is not None) and (prev_node.preserve) and (len(lstriped_)!=len(node.string)):
|
if (
|
||||||
|
(prev_node is not None)
|
||||||
|
and (prev_node.preserve)
|
||||||
|
and (len(lstriped_) != len(node.string))
|
||||||
|
):
|
||||||
prev_node.string += node.string[: -len(lstriped_)]
|
prev_node.string += node.string[: -len(lstriped_)]
|
||||||
node.string = lstriped_
|
node.string = lstriped_
|
||||||
rstriped_ = node.string.rstrip().rstrip('\n')
|
rstriped_ = node.string.rstrip().rstrip("\n")
|
||||||
if (node.next is not None) and (node.next.preserve) and (len(rstriped_)!=len(node.string)):
|
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.next.string = node.string[len(rstriped_) :] + node.next.string
|
||||||
node.string = rstriped_
|
node.string = rstriped_
|
||||||
# =====
|
# =-=-=
|
||||||
prev_node = node
|
prev_node = node
|
||||||
node = node.next
|
node = node.next
|
||||||
if node is None: break
|
if node is None:
|
||||||
|
break
|
||||||
|
|
||||||
# 标注节点的行数范围
|
# 标注节点的行数范围
|
||||||
node = root
|
node = root
|
||||||
n_line = 0
|
n_line = 0
|
||||||
expansion = 2
|
expansion = 2
|
||||||
while True:
|
while True:
|
||||||
n_l = node.string.count('\n')
|
n_l = node.string.count("\n")
|
||||||
node.range = [n_line - expansion, n_line + n_l + expansion] # 失败时,扭转的范围
|
node.range = [n_line - expansion, n_line + n_l + expansion] # 失败时,扭转的范围
|
||||||
n_line = n_line + n_l
|
n_line = n_line + n_l
|
||||||
node = node.next
|
node = node.next
|
||||||
if node is None: break
|
if node is None:
|
||||||
|
break
|
||||||
return root
|
return root
|
||||||
|
|
||||||
|
|
||||||
@@ -131,12 +157,14 @@ def set_forbidden_text(text, mask, pattern, flags=0):
|
|||||||
you can mask out (mask = PRESERVE so that text become untouchable for GPT)
|
you can mask out (mask = PRESERVE so that text become untouchable for GPT)
|
||||||
everything between "\begin{equation}" and "\end{equation}"
|
everything between "\begin{equation}" and "\end{equation}"
|
||||||
"""
|
"""
|
||||||
if isinstance(pattern, list): pattern = '|'.join(pattern)
|
if isinstance(pattern, list):
|
||||||
|
pattern = "|".join(pattern)
|
||||||
pattern_compile = re.compile(pattern, flags)
|
pattern_compile = re.compile(pattern, flags)
|
||||||
for res in pattern_compile.finditer(text):
|
for res in pattern_compile.finditer(text):
|
||||||
mask[res.span()[0] : res.span()[1]] = PRESERVE
|
mask[res.span()[0] : res.span()[1]] = PRESERVE
|
||||||
return text, mask
|
return text, mask
|
||||||
|
|
||||||
|
|
||||||
def reverse_forbidden_text(text, mask, pattern, flags=0, forbid_wrapper=True):
|
def reverse_forbidden_text(text, mask, pattern, flags=0, forbid_wrapper=True):
|
||||||
"""
|
"""
|
||||||
Move area out of preserve area (make text editable for GPT)
|
Move area out of preserve area (make text editable for GPT)
|
||||||
@@ -144,7 +172,8 @@ def reverse_forbidden_text(text, mask, pattern, flags=0, forbid_wrapper=True):
|
|||||||
e.g.
|
e.g.
|
||||||
\begin{abstract} blablablablablabla. \end{abstract}
|
\begin{abstract} blablablablablabla. \end{abstract}
|
||||||
"""
|
"""
|
||||||
if isinstance(pattern, list): pattern = '|'.join(pattern)
|
if isinstance(pattern, list):
|
||||||
|
pattern = "|".join(pattern)
|
||||||
pattern_compile = re.compile(pattern, flags)
|
pattern_compile = re.compile(pattern, flags)
|
||||||
for res in pattern_compile.finditer(text):
|
for res in pattern_compile.finditer(text):
|
||||||
if not forbid_wrapper:
|
if not forbid_wrapper:
|
||||||
@@ -155,6 +184,7 @@ def reverse_forbidden_text(text, mask, pattern, flags=0, forbid_wrapper=True):
|
|||||||
mask[res.regs[1][1] : res.regs[0][1]] = PRESERVE # abstract
|
mask[res.regs[1][1] : res.regs[0][1]] = PRESERVE # abstract
|
||||||
return text, mask
|
return text, mask
|
||||||
|
|
||||||
|
|
||||||
def set_forbidden_text_careful_brace(text, mask, pattern, flags=0):
|
def set_forbidden_text_careful_brace(text, mask, pattern, flags=0):
|
||||||
"""
|
"""
|
||||||
Add a preserve text area in this paper (text become untouchable for GPT).
|
Add a preserve text area in this paper (text become untouchable for GPT).
|
||||||
@@ -167,15 +197,21 @@ def set_forbidden_text_careful_brace(text, mask, pattern, flags=0):
|
|||||||
brace_level = -1
|
brace_level = -1
|
||||||
p = begin = end = res.regs[0][0]
|
p = begin = end = res.regs[0][0]
|
||||||
for _ in range(1024 * 16):
|
for _ in range(1024 * 16):
|
||||||
if text[p] == '}' and brace_level == 0: break
|
if text[p] == "}" and brace_level == 0:
|
||||||
elif text[p] == '}': brace_level -= 1
|
break
|
||||||
elif text[p] == '{': brace_level += 1
|
elif text[p] == "}":
|
||||||
|
brace_level -= 1
|
||||||
|
elif text[p] == "{":
|
||||||
|
brace_level += 1
|
||||||
p += 1
|
p += 1
|
||||||
end = p + 1
|
end = p + 1
|
||||||
mask[begin:end] = PRESERVE
|
mask[begin:end] = PRESERVE
|
||||||
return text, mask
|
return text, mask
|
||||||
|
|
||||||
def reverse_forbidden_text_careful_brace(text, mask, pattern, flags=0, forbid_wrapper=True):
|
|
||||||
|
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)
|
Move area out of preserve area (make text editable for GPT)
|
||||||
count the number of the braces so as to catch compelete text area.
|
count the number of the braces so as to catch compelete text area.
|
||||||
@@ -187,9 +223,12 @@ def reverse_forbidden_text_careful_brace(text, mask, pattern, flags=0, forbid_wr
|
|||||||
brace_level = 0
|
brace_level = 0
|
||||||
p = begin = end = res.regs[1][0]
|
p = begin = end = res.regs[1][0]
|
||||||
for _ in range(1024 * 16):
|
for _ in range(1024 * 16):
|
||||||
if text[p] == '}' and brace_level == 0: break
|
if text[p] == "}" and brace_level == 0:
|
||||||
elif text[p] == '}': brace_level -= 1
|
break
|
||||||
elif text[p] == '{': brace_level += 1
|
elif text[p] == "}":
|
||||||
|
brace_level -= 1
|
||||||
|
elif text[p] == "{":
|
||||||
|
brace_level += 1
|
||||||
p += 1
|
p += 1
|
||||||
end = p
|
end = p
|
||||||
mask[begin:end] = TRANSFORM
|
mask[begin:end] = TRANSFORM
|
||||||
@@ -198,27 +237,42 @@ def reverse_forbidden_text_careful_brace(text, mask, pattern, flags=0, forbid_wr
|
|||||||
mask[end : res.regs[0][1]] = PRESERVE
|
mask[end : res.regs[0][1]] = PRESERVE
|
||||||
return text, mask
|
return text, mask
|
||||||
|
|
||||||
|
|
||||||
def set_forbidden_text_begin_end(text, mask, pattern, flags=0, limit_n_lines=42):
|
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.
|
Find all \begin{} ... \end{} text block that with less than limit_n_lines lines.
|
||||||
Add it to preserve area
|
Add it to preserve area
|
||||||
"""
|
"""
|
||||||
pattern_compile = re.compile(pattern, flags)
|
pattern_compile = re.compile(pattern, flags)
|
||||||
|
|
||||||
def search_with_line_limit(text, mask):
|
def search_with_line_limit(text, mask):
|
||||||
for res in pattern_compile.finditer(text):
|
for res in pattern_compile.finditer(text):
|
||||||
cmd = res.group(1) # begin{what}
|
cmd = res.group(1) # begin{what}
|
||||||
this = res.group(2) # content between begin and end
|
this = res.group(2) # content between begin and end
|
||||||
this_mask = mask[res.regs[2][0] : res.regs[2][1]]
|
this_mask = mask[res.regs[2][0] : res.regs[2][1]]
|
||||||
white_list = ['document', 'abstract', 'lemma', 'definition', 'sproof',
|
white_list = [
|
||||||
'em', 'emph', 'textit', 'textbf', 'itemize', 'enumerate']
|
"document",
|
||||||
if (cmd in white_list) or this.count('\n') >= limit_n_lines: # use a magical number 42
|
"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)
|
this, this_mask = search_with_line_limit(this, this_mask)
|
||||||
mask[res.regs[2][0] : res.regs[2][1]] = this_mask
|
mask[res.regs[2][0] : res.regs[2][1]] = this_mask
|
||||||
else:
|
else:
|
||||||
mask[res.regs[0][0] : res.regs[0][1]] = PRESERVE
|
mask[res.regs[0][0] : res.regs[0][1]] = PRESERVE
|
||||||
return text, mask
|
return text, mask
|
||||||
return search_with_line_limit(text, mask)
|
|
||||||
|
|
||||||
|
return search_with_line_limit(text, mask)
|
||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
@@ -227,6 +281,7 @@ Latex Merge File
|
|||||||
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
def find_main_tex_file(file_manifest, mode):
|
def find_main_tex_file(file_manifest, mode):
|
||||||
"""
|
"""
|
||||||
在多Tex文档中,寻找主文件,必须包含documentclass,返回找到的第一个。
|
在多Tex文档中,寻找主文件,必须包含documentclass,返回找到的第一个。
|
||||||
@@ -234,27 +289,36 @@ def find_main_tex_file(file_manifest, mode):
|
|||||||
"""
|
"""
|
||||||
canidates = []
|
canidates = []
|
||||||
for texf in file_manifest:
|
for texf in file_manifest:
|
||||||
if os.path.basename(texf).startswith('merge'):
|
if os.path.basename(texf).startswith("merge"):
|
||||||
continue
|
continue
|
||||||
with open(texf, 'r', encoding='utf8', errors='ignore') as f:
|
with open(texf, "r", encoding="utf8", errors="ignore") as f:
|
||||||
file_content = f.read()
|
file_content = f.read()
|
||||||
if r'\documentclass' in file_content:
|
if r"\documentclass" in file_content:
|
||||||
canidates.append(texf)
|
canidates.append(texf)
|
||||||
else:
|
else:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if len(canidates) == 0:
|
if len(canidates) == 0:
|
||||||
raise RuntimeError('无法找到一个主Tex文件(包含documentclass关键字)')
|
raise RuntimeError("无法找到一个主Tex文件(包含documentclass关键字)")
|
||||||
elif len(canidates) == 1:
|
elif len(canidates) == 1:
|
||||||
return canidates[0]
|
return canidates[0]
|
||||||
else: # if len(canidates) >= 2 通过一些Latex模板中常见(但通常不会出现在正文)的单词,对不同latex源文件扣分,取评分最高者返回
|
else: # if len(canidates) >= 2 通过一些Latex模板中常见(但通常不会出现在正文)的单词,对不同latex源文件扣分,取评分最高者返回
|
||||||
canidates_score = []
|
canidates_score = []
|
||||||
# 给出一些判定模板文档的词作为扣分项
|
# 给出一些判定模板文档的词作为扣分项
|
||||||
unexpected_words = ['\\LaTeX', 'manuscript', 'Guidelines', 'font', 'citations', 'rejected', 'blind review', 'reviewers']
|
unexpected_words = [
|
||||||
expected_words = ['\\input', '\\ref', '\\cite']
|
"\\LaTeX",
|
||||||
|
"manuscript",
|
||||||
|
"Guidelines",
|
||||||
|
"font",
|
||||||
|
"citations",
|
||||||
|
"rejected",
|
||||||
|
"blind review",
|
||||||
|
"reviewers",
|
||||||
|
]
|
||||||
|
expected_words = ["\\input", "\\ref", "\\cite"]
|
||||||
for texf in canidates:
|
for texf in canidates:
|
||||||
canidates_score.append(0)
|
canidates_score.append(0)
|
||||||
with open(texf, 'r', encoding='utf8', errors='ignore') as f:
|
with open(texf, "r", encoding="utf8", errors="ignore") as f:
|
||||||
file_content = f.read()
|
file_content = f.read()
|
||||||
file_content = rm_comments(file_content)
|
file_content = rm_comments(file_content)
|
||||||
for uw in unexpected_words:
|
for uw in unexpected_words:
|
||||||
@@ -266,6 +330,7 @@ def find_main_tex_file(file_manifest, mode):
|
|||||||
select = np.argmax(canidates_score) # 取评分最高者返回
|
select = np.argmax(canidates_score) # 取评分最高者返回
|
||||||
return canidates[select]
|
return canidates[select]
|
||||||
|
|
||||||
|
|
||||||
def rm_comments(main_file):
|
def rm_comments(main_file):
|
||||||
new_file_remove_comment_lines = []
|
new_file_remove_comment_lines = []
|
||||||
for l in main_file.splitlines():
|
for l in main_file.splitlines():
|
||||||
@@ -274,30 +339,39 @@ def rm_comments(main_file):
|
|||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
new_file_remove_comment_lines.append(l)
|
new_file_remove_comment_lines.append(l)
|
||||||
main_file = '\n'.join(new_file_remove_comment_lines)
|
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"\\include{(.*?)}", r"\\input{\1}", main_file) # 将 \include 命令转换为 \input 命令
|
||||||
main_file = re.sub(r'(?<!\\)%.*', '', main_file) # 使用正则表达式查找半行注释, 并替换为空字符串
|
main_file = re.sub(r"(?<!\\)%.*", "", main_file) # 使用正则表达式查找半行注释, 并替换为空字符串
|
||||||
return main_file
|
return main_file
|
||||||
|
|
||||||
|
|
||||||
def find_tex_file_ignore_case(fp):
|
def find_tex_file_ignore_case(fp):
|
||||||
dir_name = os.path.dirname(fp)
|
dir_name = os.path.dirname(fp)
|
||||||
base_name = os.path.basename(fp)
|
base_name = os.path.basename(fp)
|
||||||
# 如果输入的文件路径是正确的
|
# 如果输入的文件路径是正确的
|
||||||
if os.path.isfile(pj(dir_name, base_name)): return pj(dir_name, base_name)
|
if os.path.isfile(pj(dir_name, base_name)):
|
||||||
|
return pj(dir_name, base_name)
|
||||||
# 如果不正确,试着加上.tex后缀试试
|
# 如果不正确,试着加上.tex后缀试试
|
||||||
if not base_name.endswith('.tex'): base_name+='.tex'
|
if not base_name.endswith(".tex"):
|
||||||
if os.path.isfile(pj(dir_name, base_name)): return pj(dir_name, base_name)
|
base_name += ".tex"
|
||||||
|
if os.path.isfile(pj(dir_name, base_name)):
|
||||||
|
return pj(dir_name, base_name)
|
||||||
# 如果还找不到,解除大小写限制,再试一次
|
# 如果还找不到,解除大小写限制,再试一次
|
||||||
import glob
|
import glob
|
||||||
for f in glob.glob(dir_name+'/*.tex'):
|
|
||||||
|
for f in glob.glob(dir_name + "/*.tex"):
|
||||||
base_name_s = os.path.basename(fp)
|
base_name_s = os.path.basename(fp)
|
||||||
base_name_f = os.path.basename(f)
|
base_name_f = os.path.basename(f)
|
||||||
if base_name_s.lower() == base_name_f.lower(): return f
|
if base_name_s.lower() == base_name_f.lower():
|
||||||
|
return f
|
||||||
# 试着加上.tex后缀试试
|
# 试着加上.tex后缀试试
|
||||||
if not base_name_s.endswith('.tex'): base_name_s+='.tex'
|
if not base_name_s.endswith(".tex"):
|
||||||
if base_name_s.lower() == base_name_f.lower(): return f
|
base_name_s += ".tex"
|
||||||
|
if base_name_s.lower() == base_name_f.lower():
|
||||||
|
return f
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def merge_tex_files_(project_foler, main_file, mode):
|
def merge_tex_files_(project_foler, main_file, mode):
|
||||||
"""
|
"""
|
||||||
Merge Tex project recrusively
|
Merge Tex project recrusively
|
||||||
@@ -309,18 +383,18 @@ def merge_tex_files_(project_foler, main_file, mode):
|
|||||||
fp_ = find_tex_file_ignore_case(fp)
|
fp_ = find_tex_file_ignore_case(fp)
|
||||||
if fp_:
|
if fp_:
|
||||||
try:
|
try:
|
||||||
with open(fp_, 'r', encoding='utf-8', errors='replace') as fx: c = fx.read()
|
with open(fp_, "r", encoding="utf-8", errors="replace") as fx:
|
||||||
|
c = fx.read()
|
||||||
except:
|
except:
|
||||||
c = f"\n\nWarning from GPT-Academic: LaTex source file is missing!\n\n"
|
c = f"\n\nWarning from GPT-Academic: LaTex source file is missing!\n\n"
|
||||||
else:
|
else:
|
||||||
raise RuntimeError(f'找不到{fp},Tex源文件缺失!')
|
raise RuntimeError(f"找不到{fp},Tex源文件缺失!")
|
||||||
c = merge_tex_files_(project_foler, c, mode)
|
c = merge_tex_files_(project_foler, c, mode)
|
||||||
main_file = main_file[: s.span()[0]] + c + main_file[s.span()[1] :]
|
main_file = main_file[: s.span()[0]] + c + main_file[s.span()[1] :]
|
||||||
return main_file
|
return main_file
|
||||||
|
|
||||||
|
|
||||||
def find_title_and_abs(main_file):
|
def find_title_and_abs(main_file):
|
||||||
|
|
||||||
def extract_abstract_1(text):
|
def extract_abstract_1(text):
|
||||||
pattern = r"\\abstract\{(.*?)\}"
|
pattern = r"\\abstract\{(.*?)\}"
|
||||||
match = re.search(pattern, text, re.DOTALL)
|
match = re.search(pattern, text, re.DOTALL)
|
||||||
@@ -362,21 +436,30 @@ def merge_tex_files(project_foler, main_file, mode):
|
|||||||
main_file = merge_tex_files_(project_foler, main_file, mode)
|
main_file = merge_tex_files_(project_foler, main_file, mode)
|
||||||
main_file = rm_comments(main_file)
|
main_file = rm_comments(main_file)
|
||||||
|
|
||||||
if mode == 'translate_zh':
|
if mode == "translate_zh":
|
||||||
# find paper documentclass
|
# find paper documentclass
|
||||||
pattern = re.compile(r'\\documentclass.*\n')
|
pattern = re.compile(r"\\documentclass.*\n")
|
||||||
match = pattern.search(main_file)
|
match = pattern.search(main_file)
|
||||||
assert match is not None, "Cannot find documentclass statement!"
|
assert match is not None, "Cannot find documentclass statement!"
|
||||||
position = match.end()
|
position = match.end()
|
||||||
add_ctex = '\\usepackage{ctex}\n'
|
add_ctex = "\\usepackage{ctex}\n"
|
||||||
add_url = '\\usepackage{url}\n' if '{url}' not in main_file else ''
|
add_url = "\\usepackage{url}\n" if "{url}" not in main_file else ""
|
||||||
main_file = main_file[:position] + add_ctex + add_url + main_file[position:]
|
main_file = main_file[:position] + add_ctex + add_url + main_file[position:]
|
||||||
# fontset=windows
|
# fontset=windows
|
||||||
import platform
|
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)
|
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
|
# find paper abstract
|
||||||
pattern_opt1 = re.compile(r'\\begin\{abstract\}.*\n')
|
pattern_opt1 = re.compile(r"\\begin\{abstract\}.*\n")
|
||||||
pattern_opt2 = re.compile(r"\\abstract\{(.*?)\}", flags=re.DOTALL)
|
pattern_opt2 = re.compile(r"\\abstract\{(.*?)\}", flags=re.DOTALL)
|
||||||
match_opt1 = pattern_opt1.search(main_file)
|
match_opt1 = pattern_opt1.search(main_file)
|
||||||
match_opt2 = pattern_opt2.search(main_file)
|
match_opt2 = pattern_opt2.search(main_file)
|
||||||
@@ -385,7 +468,9 @@ def merge_tex_files(project_foler, main_file, mode):
|
|||||||
main_file = insert_abstract(main_file)
|
main_file = insert_abstract(main_file)
|
||||||
match_opt1 = pattern_opt1.search(main_file)
|
match_opt1 = pattern_opt1.search(main_file)
|
||||||
match_opt2 = pattern_opt2.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!"
|
assert (match_opt1 is not None) or (
|
||||||
|
match_opt2 is not None
|
||||||
|
), "Cannot find paper abstract section!"
|
||||||
return main_file
|
return main_file
|
||||||
|
|
||||||
|
|
||||||
@@ -395,6 +480,7 @@ The GPT-Academic program cannot find abstract section in this paper.
|
|||||||
\end{abstract}
|
\end{abstract}
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
def insert_abstract(tex_content):
|
def insert_abstract(tex_content):
|
||||||
if "\\maketitle" in tex_content:
|
if "\\maketitle" in tex_content:
|
||||||
# find the position of "\maketitle"
|
# find the position of "\maketitle"
|
||||||
@@ -402,7 +488,13 @@ def insert_abstract(tex_content):
|
|||||||
# find the nearest ending line
|
# find the nearest ending line
|
||||||
end_line_index = tex_content.find("\n", find_index)
|
end_line_index = tex_content.find("\n", find_index)
|
||||||
# insert "abs_str" on the next line
|
# insert "abs_str" on the next line
|
||||||
modified_tex = tex_content[:end_line_index+1] + '\n\n' + insert_missing_abs_str + '\n\n' + tex_content[end_line_index+1:]
|
modified_tex = (
|
||||||
|
tex_content[: end_line_index + 1]
|
||||||
|
+ "\n\n"
|
||||||
|
+ insert_missing_abs_str
|
||||||
|
+ "\n\n"
|
||||||
|
+ tex_content[end_line_index + 1 :]
|
||||||
|
)
|
||||||
return modified_tex
|
return modified_tex
|
||||||
elif r"\begin{document}" in tex_content:
|
elif r"\begin{document}" in tex_content:
|
||||||
# find the position of "\maketitle"
|
# find the position of "\maketitle"
|
||||||
@@ -410,16 +502,25 @@ def insert_abstract(tex_content):
|
|||||||
# find the nearest ending line
|
# find the nearest ending line
|
||||||
end_line_index = tex_content.find("\n", find_index)
|
end_line_index = tex_content.find("\n", find_index)
|
||||||
# insert "abs_str" on the next line
|
# insert "abs_str" on the next line
|
||||||
modified_tex = tex_content[:end_line_index+1] + '\n\n' + insert_missing_abs_str + '\n\n' + tex_content[end_line_index+1:]
|
modified_tex = (
|
||||||
|
tex_content[: end_line_index + 1]
|
||||||
|
+ "\n\n"
|
||||||
|
+ insert_missing_abs_str
|
||||||
|
+ "\n\n"
|
||||||
|
+ tex_content[end_line_index + 1 :]
|
||||||
|
)
|
||||||
return modified_tex
|
return modified_tex
|
||||||
else:
|
else:
|
||||||
return tex_content
|
return tex_content
|
||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||||
Post process
|
Post process
|
||||||
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
def mod_inbraket(match):
|
def mod_inbraket(match):
|
||||||
"""
|
"""
|
||||||
为啥chatgpt会把cite里面的逗号换成中文逗号呀
|
为啥chatgpt会把cite里面的逗号换成中文逗号呀
|
||||||
@@ -428,11 +529,12 @@ def mod_inbraket(match):
|
|||||||
cmd = match.group(1)
|
cmd = match.group(1)
|
||||||
str_to_modify = match.group(2)
|
str_to_modify = match.group(2)
|
||||||
# modify the matched string
|
# modify the matched string
|
||||||
str_to_modify = str_to_modify.replace(':', ':') # 前面是中文冒号,后面是英文冒号
|
str_to_modify = str_to_modify.replace(":", ":") # 前面是中文冒号,后面是英文冒号
|
||||||
str_to_modify = str_to_modify.replace(',', ',') # 前面是中文逗号,后面是英文逗号
|
str_to_modify = str_to_modify.replace(",", ",") # 前面是中文逗号,后面是英文逗号
|
||||||
# str_to_modify = 'BOOM'
|
# str_to_modify = 'BOOM'
|
||||||
return "\\" + cmd + "{" + str_to_modify + "}"
|
return "\\" + cmd + "{" + str_to_modify + "}"
|
||||||
|
|
||||||
|
|
||||||
def fix_content(final_tex, node_string):
|
def fix_content(final_tex, node_string):
|
||||||
"""
|
"""
|
||||||
Fix common GPT errors to increase success rate
|
Fix common GPT errors to increase success rate
|
||||||
@@ -444,9 +546,9 @@ def fix_content(final_tex, node_string):
|
|||||||
|
|
||||||
if "Traceback" in final_tex and "[Local Message]" in final_tex:
|
if "Traceback" in final_tex and "[Local Message]" in final_tex:
|
||||||
final_tex = node_string # 出问题了,还原原文
|
final_tex = node_string # 出问题了,还原原文
|
||||||
if node_string.count('\\begin') != final_tex.count('\\begin'):
|
if node_string.count("\\begin") != final_tex.count("\\begin"):
|
||||||
final_tex = node_string # 出问题了,还原原文
|
final_tex = node_string # 出问题了,还原原文
|
||||||
if node_string.count('\_') > 0 and node_string.count('\_') > final_tex.count('\_'):
|
if node_string.count("\_") > 0 and node_string.count("\_") > final_tex.count("\_"):
|
||||||
# walk and replace any _ without \
|
# walk and replace any _ without \
|
||||||
final_tex = re.sub(r"(?<!\\)_", "\\_", final_tex)
|
final_tex = re.sub(r"(?<!\\)_", "\\_", final_tex)
|
||||||
|
|
||||||
@@ -454,24 +556,32 @@ def fix_content(final_tex, node_string):
|
|||||||
# this function count the number of { and }
|
# this function count the number of { and }
|
||||||
brace_level = 0
|
brace_level = 0
|
||||||
for c in string:
|
for c in string:
|
||||||
if c == "{": brace_level += 1
|
if c == "{":
|
||||||
elif c == "}": brace_level -= 1
|
brace_level += 1
|
||||||
|
elif c == "}":
|
||||||
|
brace_level -= 1
|
||||||
return brace_level
|
return brace_level
|
||||||
|
|
||||||
def join_most(tex_t, tex_o):
|
def join_most(tex_t, tex_o):
|
||||||
# this function join translated string and original string when something goes wrong
|
# this function join translated string and original string when something goes wrong
|
||||||
p_t = 0
|
p_t = 0
|
||||||
p_o = 0
|
p_o = 0
|
||||||
|
|
||||||
def find_next(string, chars, begin):
|
def find_next(string, chars, begin):
|
||||||
p = begin
|
p = begin
|
||||||
while p < len(string):
|
while p < len(string):
|
||||||
if string[p] in chars: return p, string[p]
|
if string[p] in chars:
|
||||||
|
return p, string[p]
|
||||||
p += 1
|
p += 1
|
||||||
return None, None
|
return None, None
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
res1, char = find_next(tex_o, ['{','}'], p_o)
|
res1, char = find_next(tex_o, ["{", "}"], p_o)
|
||||||
if res1 is None: break
|
if res1 is None:
|
||||||
|
break
|
||||||
res2, char = find_next(tex_t, [char], p_t)
|
res2, char = find_next(tex_t, [char], p_t)
|
||||||
if res2 is None: break
|
if res2 is None:
|
||||||
|
break
|
||||||
p_o = res1 + 1
|
p_o = res1 + 1
|
||||||
p_t = res2 + 1
|
p_t = res2 + 1
|
||||||
return tex_t[:p_t] + tex_o[p_o:]
|
return tex_t[:p_t] + tex_o[p_o:]
|
||||||
@@ -481,55 +591,78 @@ def fix_content(final_tex, node_string):
|
|||||||
final_tex = join_most(final_tex, node_string)
|
final_tex = join_most(final_tex, node_string)
|
||||||
return final_tex
|
return final_tex
|
||||||
|
|
||||||
|
|
||||||
def compile_latex_with_timeout(command, cwd, timeout=60):
|
def compile_latex_with_timeout(command, cwd, timeout=60):
|
||||||
import subprocess
|
import subprocess
|
||||||
process = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=cwd)
|
|
||||||
|
process = subprocess.Popen(
|
||||||
|
command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=cwd
|
||||||
|
)
|
||||||
try:
|
try:
|
||||||
stdout, stderr = process.communicate(timeout=timeout)
|
stdout, stderr = process.communicate(timeout=timeout)
|
||||||
except subprocess.TimeoutExpired:
|
except subprocess.TimeoutExpired:
|
||||||
process.kill()
|
process.kill()
|
||||||
stdout, stderr = process.communicate()
|
stdout, stderr = process.communicate()
|
||||||
print("Process timed out!")
|
logger.error("Process timed out (compile_latex_with_timeout)!")
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def run_in_subprocess_wrapper_func(func, args, kwargs, return_dict, exception_dict):
|
def run_in_subprocess_wrapper_func(func, args, kwargs, return_dict, exception_dict):
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
try:
|
try:
|
||||||
result = func(*args, **kwargs)
|
result = func(*args, **kwargs)
|
||||||
return_dict['result'] = result
|
return_dict["result"] = result
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
exc_info = sys.exc_info()
|
exc_info = sys.exc_info()
|
||||||
exception_dict['exception'] = exc_info
|
exception_dict["exception"] = exc_info
|
||||||
|
|
||||||
|
|
||||||
def run_in_subprocess(func):
|
def run_in_subprocess(func):
|
||||||
import multiprocessing
|
import multiprocessing
|
||||||
|
|
||||||
def wrapper(*args, **kwargs):
|
def wrapper(*args, **kwargs):
|
||||||
return_dict = multiprocessing.Manager().dict()
|
return_dict = multiprocessing.Manager().dict()
|
||||||
exception_dict = multiprocessing.Manager().dict()
|
exception_dict = multiprocessing.Manager().dict()
|
||||||
process = multiprocessing.Process(target=run_in_subprocess_wrapper_func,
|
process = multiprocessing.Process(
|
||||||
args=(func, args, kwargs, return_dict, exception_dict))
|
target=run_in_subprocess_wrapper_func,
|
||||||
|
args=(func, args, kwargs, return_dict, exception_dict),
|
||||||
|
)
|
||||||
process.start()
|
process.start()
|
||||||
process.join()
|
process.join()
|
||||||
process.close()
|
process.close()
|
||||||
if 'exception' in exception_dict:
|
if "exception" in exception_dict:
|
||||||
# ooops, the subprocess ran into an exception
|
# ooops, the subprocess ran into an exception
|
||||||
exc_info = exception_dict['exception']
|
exc_info = exception_dict["exception"]
|
||||||
raise exc_info[1].with_traceback(exc_info[2])
|
raise exc_info[1].with_traceback(exc_info[2])
|
||||||
if 'result' in return_dict.keys():
|
if "result" in return_dict.keys():
|
||||||
# If the subprocess ran successfully, return the result
|
# If the subprocess ran successfully, return the result
|
||||||
return return_dict['result']
|
return return_dict["result"]
|
||||||
|
|
||||||
return wrapper
|
return wrapper
|
||||||
|
|
||||||
|
|
||||||
def _merge_pdfs(pdf1_path, pdf2_path, output_path):
|
def _merge_pdfs(pdf1_path, pdf2_path, output_path):
|
||||||
|
try:
|
||||||
|
logger.info("Merging PDFs using _merge_pdfs_ng")
|
||||||
|
_merge_pdfs_ng(pdf1_path, pdf2_path, output_path)
|
||||||
|
except:
|
||||||
|
logger.info("Merging PDFs using _merge_pdfs_legacy")
|
||||||
|
_merge_pdfs_legacy(pdf1_path, pdf2_path, output_path)
|
||||||
|
|
||||||
|
|
||||||
|
def _merge_pdfs_ng(pdf1_path, pdf2_path, output_path):
|
||||||
import PyPDF2 # PyPDF2这个库有严重的内存泄露问题,把它放到子进程中运行,从而方便内存的释放
|
import PyPDF2 # PyPDF2这个库有严重的内存泄露问题,把它放到子进程中运行,从而方便内存的释放
|
||||||
Percent = 0.95
|
from PyPDF2.generic import NameObject, TextStringObject, ArrayObject, FloatObject, NumberObject
|
||||||
|
|
||||||
|
Percent = 1
|
||||||
# raise RuntimeError('PyPDF2 has a serious memory leak problem, please use other tools to merge PDF files.')
|
# raise RuntimeError('PyPDF2 has a serious memory leak problem, please use other tools to merge PDF files.')
|
||||||
# Open the first PDF file
|
# Open the first PDF file
|
||||||
with open(pdf1_path, 'rb') as pdf1_file:
|
with open(pdf1_path, "rb") as pdf1_file:
|
||||||
pdf1_reader = PyPDF2.PdfFileReader(pdf1_file)
|
pdf1_reader = PyPDF2.PdfFileReader(pdf1_file)
|
||||||
# Open the second PDF file
|
# Open the second PDF file
|
||||||
with open(pdf2_path, 'rb') as pdf2_file:
|
with open(pdf2_path, "rb") as pdf2_file:
|
||||||
pdf2_reader = PyPDF2.PdfFileReader(pdf2_file)
|
pdf2_reader = PyPDF2.PdfFileReader(pdf2_file)
|
||||||
# Create a new PDF file to store the merged pages
|
# Create a new PDF file to store the merged pages
|
||||||
output_writer = PyPDF2.PdfFileWriter()
|
output_writer = PyPDF2.PdfFileWriter()
|
||||||
@@ -549,14 +682,225 @@ def _merge_pdfs(pdf1_path, pdf2_path, output_path):
|
|||||||
page2 = PyPDF2.PageObject.createBlankPage(pdf1_reader)
|
page2 = PyPDF2.PageObject.createBlankPage(pdf1_reader)
|
||||||
# Create a new empty page with double width
|
# Create a new empty page with double width
|
||||||
new_page = PyPDF2.PageObject.createBlankPage(
|
new_page = PyPDF2.PageObject.createBlankPage(
|
||||||
width = int(int(page1.mediaBox.getWidth()) + int(page2.mediaBox.getWidth()) * Percent),
|
width=int(
|
||||||
height = max(page1.mediaBox.getHeight(), page2.mediaBox.getHeight())
|
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(page1, 0, 0)
|
||||||
new_page.mergeTranslatedPage(page2, int(int(page1.mediaBox.getWidth())-int(page2.mediaBox.getWidth())* (1-Percent)), 0)
|
new_page.mergeTranslatedPage(
|
||||||
|
page2,
|
||||||
|
int(
|
||||||
|
int(page1.mediaBox.getWidth())
|
||||||
|
- int(page2.mediaBox.getWidth()) * (1 - Percent)
|
||||||
|
),
|
||||||
|
0,
|
||||||
|
)
|
||||||
|
if "/Annots" in new_page:
|
||||||
|
annotations = new_page["/Annots"]
|
||||||
|
for i, annot in enumerate(annotations):
|
||||||
|
annot_obj = annot.get_object()
|
||||||
|
|
||||||
|
# 检查注释类型是否是链接(/Link)
|
||||||
|
if annot_obj.get("/Subtype") == "/Link":
|
||||||
|
# 检查是否为内部链接跳转(/GoTo)或外部URI链接(/URI)
|
||||||
|
action = annot_obj.get("/A")
|
||||||
|
if action:
|
||||||
|
|
||||||
|
if "/S" in action and action["/S"] == "/GoTo":
|
||||||
|
# 内部链接:跳转到文档中的某个页面
|
||||||
|
dest = action.get("/D") # 目标页或目标位置
|
||||||
|
# if dest and annot.idnum in page2_annot_id:
|
||||||
|
# if dest in pdf2_reader.named_destinations:
|
||||||
|
if dest and page2.annotations:
|
||||||
|
if annot in page2.annotations:
|
||||||
|
# 获取原始文件中跳转信息,包括跳转页面
|
||||||
|
destination = pdf2_reader.named_destinations[
|
||||||
|
dest
|
||||||
|
]
|
||||||
|
page_number = (
|
||||||
|
pdf2_reader.get_destination_page_number(
|
||||||
|
destination
|
||||||
|
)
|
||||||
|
)
|
||||||
|
# 更新跳转信息,跳转到对应的页面和,指定坐标 (100, 150),缩放比例为 100%
|
||||||
|
# “/D”:[10,'/XYZ',100,100,0]
|
||||||
|
if destination.dest_array[1] == "/XYZ":
|
||||||
|
annot_obj["/A"].update(
|
||||||
|
{
|
||||||
|
NameObject("/D"): ArrayObject(
|
||||||
|
[
|
||||||
|
NumberObject(page_number),
|
||||||
|
destination.dest_array[1],
|
||||||
|
FloatObject(
|
||||||
|
destination.dest_array[
|
||||||
|
2
|
||||||
|
]
|
||||||
|
+ int(
|
||||||
|
page1.mediaBox.getWidth()
|
||||||
|
)
|
||||||
|
),
|
||||||
|
destination.dest_array[3],
|
||||||
|
destination.dest_array[4],
|
||||||
|
]
|
||||||
|
) # 确保键和值是 PdfObject
|
||||||
|
}
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
annot_obj["/A"].update(
|
||||||
|
{
|
||||||
|
NameObject("/D"): ArrayObject(
|
||||||
|
[
|
||||||
|
NumberObject(page_number),
|
||||||
|
destination.dest_array[1],
|
||||||
|
]
|
||||||
|
) # 确保键和值是 PdfObject
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
rect = annot_obj.get("/Rect")
|
||||||
|
# 更新点击坐标
|
||||||
|
rect = ArrayObject(
|
||||||
|
[
|
||||||
|
FloatObject(
|
||||||
|
rect[0]
|
||||||
|
+ int(page1.mediaBox.getWidth())
|
||||||
|
),
|
||||||
|
rect[1],
|
||||||
|
FloatObject(
|
||||||
|
rect[2]
|
||||||
|
+ int(page1.mediaBox.getWidth())
|
||||||
|
),
|
||||||
|
rect[3],
|
||||||
|
]
|
||||||
|
)
|
||||||
|
annot_obj.update(
|
||||||
|
{
|
||||||
|
NameObject(
|
||||||
|
"/Rect"
|
||||||
|
): rect # 确保键和值是 PdfObject
|
||||||
|
}
|
||||||
|
)
|
||||||
|
# if dest and annot.idnum in page1_annot_id:
|
||||||
|
# if dest in pdf1_reader.named_destinations:
|
||||||
|
if dest and page1.annotations:
|
||||||
|
if annot in page1.annotations:
|
||||||
|
# 获取原始文件中跳转信息,包括跳转页面
|
||||||
|
destination = pdf1_reader.named_destinations[
|
||||||
|
dest
|
||||||
|
]
|
||||||
|
page_number = (
|
||||||
|
pdf1_reader.get_destination_page_number(
|
||||||
|
destination
|
||||||
|
)
|
||||||
|
)
|
||||||
|
# 更新跳转信息,跳转到对应的页面和,指定坐标 (100, 150),缩放比例为 100%
|
||||||
|
# “/D”:[10,'/XYZ',100,100,0]
|
||||||
|
if destination.dest_array[1] == "/XYZ":
|
||||||
|
annot_obj["/A"].update(
|
||||||
|
{
|
||||||
|
NameObject("/D"): ArrayObject(
|
||||||
|
[
|
||||||
|
NumberObject(page_number),
|
||||||
|
destination.dest_array[1],
|
||||||
|
FloatObject(
|
||||||
|
destination.dest_array[
|
||||||
|
2
|
||||||
|
]
|
||||||
|
),
|
||||||
|
destination.dest_array[3],
|
||||||
|
destination.dest_array[4],
|
||||||
|
]
|
||||||
|
) # 确保键和值是 PdfObject
|
||||||
|
}
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
annot_obj["/A"].update(
|
||||||
|
{
|
||||||
|
NameObject("/D"): ArrayObject(
|
||||||
|
[
|
||||||
|
NumberObject(page_number),
|
||||||
|
destination.dest_array[1],
|
||||||
|
]
|
||||||
|
) # 确保键和值是 PdfObject
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
rect = annot_obj.get("/Rect")
|
||||||
|
rect = ArrayObject(
|
||||||
|
[
|
||||||
|
FloatObject(rect[0]),
|
||||||
|
rect[1],
|
||||||
|
FloatObject(rect[2]),
|
||||||
|
rect[3],
|
||||||
|
]
|
||||||
|
)
|
||||||
|
annot_obj.update(
|
||||||
|
{
|
||||||
|
NameObject(
|
||||||
|
"/Rect"
|
||||||
|
): rect # 确保键和值是 PdfObject
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
elif "/S" in action and action["/S"] == "/URI":
|
||||||
|
# 外部链接:跳转到某个URI
|
||||||
|
uri = action.get("/URI")
|
||||||
output_writer.addPage(new_page)
|
output_writer.addPage(new_page)
|
||||||
# Save the merged PDF file
|
# Save the merged PDF file
|
||||||
with open(output_path, 'wb') as output_file:
|
with open(output_path, "wb") as output_file:
|
||||||
output_writer.write(output_file)
|
output_writer.write(output_file)
|
||||||
|
|
||||||
|
|
||||||
|
def _merge_pdfs_legacy(pdf1_path, pdf2_path, output_path):
|
||||||
|
import PyPDF2 # PyPDF2这个库有严重的内存泄露问题,把它放到子进程中运行,从而方便内存的释放
|
||||||
|
|
||||||
|
Percent = 0.95
|
||||||
|
# raise RuntimeError('PyPDF2 has a serious memory leak problem, please use other tools to merge PDF files.')
|
||||||
|
# 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)
|
||||||
|
|
||||||
|
|
||||||
merge_pdfs = run_in_subprocess(_merge_pdfs) # PyPDF2这个库有严重的内存泄露问题,把它放到子进程中运行,从而方便内存的释放
|
merge_pdfs = run_in_subprocess(_merge_pdfs) # PyPDF2这个库有严重的内存泄露问题,把它放到子进程中运行,从而方便内存的释放
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import time, logging, json, sys, struct
|
import time, json, sys, struct
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
from loguru import logger as logging
|
||||||
from scipy.io.wavfile import WAVE_FORMAT
|
from scipy.io.wavfile import WAVE_FORMAT
|
||||||
|
|
||||||
def write_numpy_to_wave(filename, rate, data, add_header=False):
|
def write_numpy_to_wave(filename, rate, data, add_header=False):
|
||||||
@@ -106,18 +107,14 @@ def is_speaker_speaking(vad, data, sample_rate):
|
|||||||
class AliyunASR():
|
class AliyunASR():
|
||||||
|
|
||||||
def test_on_sentence_begin(self, message, *args):
|
def test_on_sentence_begin(self, message, *args):
|
||||||
# print("test_on_sentence_begin:{}".format(message))
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def test_on_sentence_end(self, message, *args):
|
def test_on_sentence_end(self, message, *args):
|
||||||
# print("test_on_sentence_end:{}".format(message))
|
|
||||||
message = json.loads(message)
|
message = json.loads(message)
|
||||||
self.parsed_sentence = message['payload']['result']
|
self.parsed_sentence = message['payload']['result']
|
||||||
self.event_on_entence_end.set()
|
self.event_on_entence_end.set()
|
||||||
# print(self.parsed_sentence)
|
|
||||||
|
|
||||||
def test_on_start(self, message, *args):
|
def test_on_start(self, message, *args):
|
||||||
# print("test_on_start:{}".format(message))
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def test_on_error(self, message, *args):
|
def test_on_error(self, message, *args):
|
||||||
@@ -129,13 +126,11 @@ class AliyunASR():
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
def test_on_result_chg(self, message, *args):
|
def test_on_result_chg(self, message, *args):
|
||||||
# print("test_on_chg:{}".format(message))
|
|
||||||
message = json.loads(message)
|
message = json.loads(message)
|
||||||
self.parsed_text = message['payload']['result']
|
self.parsed_text = message['payload']['result']
|
||||||
self.event_on_result_chg.set()
|
self.event_on_result_chg.set()
|
||||||
|
|
||||||
def test_on_completed(self, message, *args):
|
def test_on_completed(self, message, *args):
|
||||||
# print("on_completed:args=>{} message=>{}".format(args, message))
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def audio_convertion_thread(self, uuid):
|
def audio_convertion_thread(self, uuid):
|
||||||
@@ -248,14 +243,14 @@ class AliyunASR():
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
response = client.do_action_with_exception(request)
|
response = client.do_action_with_exception(request)
|
||||||
print(response)
|
logging.info(response)
|
||||||
jss = json.loads(response)
|
jss = json.loads(response)
|
||||||
if 'Token' in jss and 'Id' in jss['Token']:
|
if 'Token' in jss and 'Id' in jss['Token']:
|
||||||
token = jss['Token']['Id']
|
token = jss['Token']['Id']
|
||||||
expireTime = jss['Token']['ExpireTime']
|
expireTime = jss['Token']['ExpireTime']
|
||||||
print("token = " + token)
|
logging.info("token = " + token)
|
||||||
print("expireTime = " + str(expireTime))
|
logging.info("expireTime = " + str(expireTime))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(e)
|
logging.error(e)
|
||||||
|
|
||||||
return token
|
return token
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
from crazy_functions.ipc_fns.mp import run_in_subprocess_with_timeout
|
from crazy_functions.ipc_fns.mp import run_in_subprocess_with_timeout
|
||||||
|
from loguru import logger
|
||||||
|
|
||||||
def force_breakdown(txt, limit, get_token_fn):
|
def force_breakdown(txt, limit, get_token_fn):
|
||||||
""" 当无法用标点、空行分割时,我们用最暴力的方法切割
|
""" 当无法用标点、空行分割时,我们用最暴力的方法切割
|
||||||
@@ -76,7 +77,7 @@ def cut(limit, get_token_fn, txt_tocut, must_break_at_empty_line, break_anyway=F
|
|||||||
remain_txt_to_cut = post
|
remain_txt_to_cut = post
|
||||||
remain_txt_to_cut, remain_txt_to_cut_storage = maintain_storage(remain_txt_to_cut, remain_txt_to_cut_storage)
|
remain_txt_to_cut, remain_txt_to_cut_storage = maintain_storage(remain_txt_to_cut, remain_txt_to_cut_storage)
|
||||||
process = fin_len/total_len
|
process = fin_len/total_len
|
||||||
print(f'正在文本切分 {int(process*100)}%')
|
logger.info(f'正在文本切分 {int(process*100)}%')
|
||||||
if len(remain_txt_to_cut.strip()) == 0:
|
if len(remain_txt_to_cut.strip()) == 0:
|
||||||
break
|
break
|
||||||
return res
|
return res
|
||||||
@@ -119,7 +120,7 @@ if __name__ == '__main__':
|
|||||||
for i in range(5):
|
for i in range(5):
|
||||||
file_content += file_content
|
file_content += file_content
|
||||||
|
|
||||||
print(len(file_content))
|
logger.info(len(file_content))
|
||||||
TOKEN_LIMIT_PER_FRAGMENT = 2500
|
TOKEN_LIMIT_PER_FRAGMENT = 2500
|
||||||
res = breakdown_text_to_satisfy_token_limit(file_content, TOKEN_LIMIT_PER_FRAGMENT)
|
res = breakdown_text_to_satisfy_token_limit(file_content, TOKEN_LIMIT_PER_FRAGMENT)
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ from toolbox import promote_file_to_downloadzone
|
|||||||
from toolbox import write_history_to_file, promote_file_to_downloadzone
|
from toolbox import write_history_to_file, promote_file_to_downloadzone
|
||||||
from toolbox import get_conf
|
from toolbox import get_conf
|
||||||
from toolbox import ProxyNetworkActivate
|
from toolbox import ProxyNetworkActivate
|
||||||
from colorful import *
|
from shared_utils.colorful import *
|
||||||
import requests
|
import requests
|
||||||
import random
|
import random
|
||||||
import copy
|
import copy
|
||||||
@@ -72,7 +72,7 @@ def produce_report_markdown(gpt_response_collection, meta, paper_meta_info, chat
|
|||||||
generated_conclusion_files.append(res_path)
|
generated_conclusion_files.append(res_path)
|
||||||
return res_path
|
return res_path
|
||||||
|
|
||||||
def translate_pdf(article_dict, llm_kwargs, chatbot, fp, generated_conclusion_files, TOKEN_LIMIT_PER_FRAGMENT, DST_LANG):
|
def translate_pdf(article_dict, llm_kwargs, chatbot, fp, generated_conclusion_files, TOKEN_LIMIT_PER_FRAGMENT, DST_LANG, plugin_kwargs={}):
|
||||||
from crazy_functions.pdf_fns.report_gen_html import construct_html
|
from crazy_functions.pdf_fns.report_gen_html import construct_html
|
||||||
from crazy_functions.pdf_fns.breakdown_txt import breakdown_text_to_satisfy_token_limit
|
from crazy_functions.pdf_fns.breakdown_txt import breakdown_text_to_satisfy_token_limit
|
||||||
from crazy_functions.crazy_utils import request_gpt_model_in_new_thread_with_ui_alive
|
from crazy_functions.crazy_utils import request_gpt_model_in_new_thread_with_ui_alive
|
||||||
@@ -138,7 +138,7 @@ def translate_pdf(article_dict, llm_kwargs, chatbot, fp, generated_conclusion_fi
|
|||||||
chatbot=chatbot,
|
chatbot=chatbot,
|
||||||
history_array=[meta for _ in inputs_array],
|
history_array=[meta for _ in inputs_array],
|
||||||
sys_prompt_array=[
|
sys_prompt_array=[
|
||||||
"请你作为一个学术翻译,负责把学术论文准确翻译成中文。注意文章中的每一句话都要翻译。" for _ in inputs_array],
|
"请你作为一个学术翻译,负责把学术论文准确翻译成中文。注意文章中的每一句话都要翻译。" + plugin_kwargs.get("additional_prompt", "") for _ in inputs_array],
|
||||||
)
|
)
|
||||||
# -=-=-=-=-=-=-=-= 写出Markdown文件 -=-=-=-=-=-=-=-=
|
# -=-=-=-=-=-=-=-= 写出Markdown文件 -=-=-=-=-=-=-=-=
|
||||||
produce_report_markdown(gpt_response_collection, meta, paper_meta_info, chatbot, fp, generated_conclusion_files)
|
produce_report_markdown(gpt_response_collection, meta, paper_meta_info, chatbot, fp, generated_conclusion_files)
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
import os
|
||||||
|
from toolbox import CatchException, report_exception, get_log_folder, gen_time_str, check_packages
|
||||||
|
from toolbox import update_ui, promote_file_to_downloadzone, update_ui_lastest_msg, disable_auto_promotion
|
||||||
|
from toolbox import write_history_to_file, promote_file_to_downloadzone, get_conf, extract_archive
|
||||||
|
from crazy_functions.pdf_fns.parse_pdf import parse_pdf, translate_pdf
|
||||||
|
|
||||||
|
def 解析PDF_基于GROBID(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, grobid_url):
|
||||||
|
import copy, json
|
||||||
|
TOKEN_LIMIT_PER_FRAGMENT = 1024
|
||||||
|
generated_conclusion_files = []
|
||||||
|
generated_html_files = []
|
||||||
|
DST_LANG = "中文"
|
||||||
|
from crazy_functions.pdf_fns.report_gen_html import construct_html
|
||||||
|
for index, fp in enumerate(file_manifest):
|
||||||
|
chatbot.append(["当前进度:", f"正在连接GROBID服务,请稍候: {grobid_url}\n如果等待时间过长,请修改config中的GROBID_URL,可修改成本地GROBID服务。"]); yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
||||||
|
article_dict = parse_pdf(fp, grobid_url)
|
||||||
|
grobid_json_res = os.path.join(get_log_folder(), gen_time_str() + "grobid.json")
|
||||||
|
with open(grobid_json_res, 'w+', encoding='utf8') as f:
|
||||||
|
f.write(json.dumps(article_dict, indent=4, ensure_ascii=False))
|
||||||
|
promote_file_to_downloadzone(grobid_json_res, chatbot=chatbot)
|
||||||
|
if article_dict is None: raise RuntimeError("解析PDF失败,请检查PDF是否损坏。")
|
||||||
|
yield from translate_pdf(article_dict, llm_kwargs, chatbot, fp, generated_conclusion_files, TOKEN_LIMIT_PER_FRAGMENT, DST_LANG, plugin_kwargs=plugin_kwargs)
|
||||||
|
chatbot.append(("给出输出文件清单", str(generated_conclusion_files + generated_html_files)))
|
||||||
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
||||||
|
|
||||||
|
|
||||||
@@ -1,83 +1,16 @@
|
|||||||
from toolbox import CatchException, report_exception, get_log_folder, gen_time_str, check_packages
|
from toolbox import get_log_folder
|
||||||
from toolbox import update_ui, promote_file_to_downloadzone, update_ui_lastest_msg, disable_auto_promotion
|
from toolbox import update_ui, promote_file_to_downloadzone
|
||||||
from toolbox import write_history_to_file, promote_file_to_downloadzone
|
from toolbox import write_history_to_file, promote_file_to_downloadzone
|
||||||
from .crazy_utils import request_gpt_model_in_new_thread_with_ui_alive
|
from crazy_functions.crazy_utils import request_gpt_model_in_new_thread_with_ui_alive
|
||||||
from .crazy_utils import request_gpt_model_multi_threads_with_very_awesome_ui_and_high_efficiency
|
from crazy_functions.crazy_utils import request_gpt_model_multi_threads_with_very_awesome_ui_and_high_efficiency
|
||||||
from .crazy_utils import read_and_clean_pdf_text
|
from crazy_functions.crazy_utils import read_and_clean_pdf_text
|
||||||
from .pdf_fns.parse_pdf import parse_pdf, get_avail_grobid_url, translate_pdf
|
from shared_utils.colorful import *
|
||||||
from colorful import *
|
from loguru import logger
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
def 解析PDF_简单拆解(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt):
|
||||||
@CatchException
|
|
||||||
def 批量翻译PDF文档(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port):
|
|
||||||
|
|
||||||
disable_auto_promotion(chatbot)
|
|
||||||
# 基本信息:功能、贡献者
|
|
||||||
chatbot.append([
|
|
||||||
"函数插件功能?",
|
|
||||||
"批量翻译PDF文档。函数插件贡献者: Binary-Husky"])
|
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
|
||||||
|
|
||||||
# 尝试导入依赖,如果缺少依赖,则给出安装建议
|
|
||||||
try:
|
|
||||||
check_packages(["fitz", "tiktoken", "scipdf"])
|
|
||||||
except:
|
|
||||||
report_exception(chatbot, history,
|
|
||||||
a=f"解析项目: {txt}",
|
|
||||||
b=f"导入软件依赖失败。使用该模块需要额外依赖,安装方法```pip install --upgrade pymupdf tiktoken scipdf_parser```。")
|
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
|
||||||
return
|
|
||||||
|
|
||||||
# 清空历史,以免输入溢出
|
|
||||||
history = []
|
|
||||||
|
|
||||||
from .crazy_utils import get_files_from_everything
|
|
||||||
success, file_manifest, project_folder = get_files_from_everything(txt, type='.pdf')
|
|
||||||
# 检测输入参数,如没有给定输入参数,直接退出
|
|
||||||
if not success:
|
|
||||||
if txt == "": txt = '空空如也的输入栏'
|
|
||||||
|
|
||||||
# 如果没找到任何文件
|
|
||||||
if len(file_manifest) == 0:
|
|
||||||
report_exception(chatbot, history,
|
|
||||||
a=f"解析项目: {txt}", b=f"找不到任何.pdf拓展名的文件: {txt}")
|
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
|
||||||
return
|
|
||||||
|
|
||||||
# 开始正式执行任务
|
|
||||||
grobid_url = get_avail_grobid_url()
|
|
||||||
if grobid_url is not None:
|
|
||||||
yield from 解析PDF_基于GROBID(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, grobid_url)
|
|
||||||
else:
|
|
||||||
yield from update_ui_lastest_msg("GROBID服务不可用,请检查config中的GROBID_URL。作为替代,现在将执行效果稍差的旧版代码。", chatbot, history, delay=3)
|
|
||||||
yield from 解析PDF(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt)
|
|
||||||
|
|
||||||
|
|
||||||
def 解析PDF_基于GROBID(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, grobid_url):
|
|
||||||
import copy, json
|
|
||||||
TOKEN_LIMIT_PER_FRAGMENT = 1024
|
|
||||||
generated_conclusion_files = []
|
|
||||||
generated_html_files = []
|
|
||||||
DST_LANG = "中文"
|
|
||||||
from crazy_functions.pdf_fns.report_gen_html import construct_html
|
|
||||||
for index, fp in enumerate(file_manifest):
|
|
||||||
chatbot.append(["当前进度:", f"正在连接GROBID服务,请稍候: {grobid_url}\n如果等待时间过长,请修改config中的GROBID_URL,可修改成本地GROBID服务。"]); yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
|
||||||
article_dict = parse_pdf(fp, grobid_url)
|
|
||||||
grobid_json_res = os.path.join(get_log_folder(), gen_time_str() + "grobid.json")
|
|
||||||
with open(grobid_json_res, 'w+', encoding='utf8') as f:
|
|
||||||
f.write(json.dumps(article_dict, indent=4, ensure_ascii=False))
|
|
||||||
promote_file_to_downloadzone(grobid_json_res, chatbot=chatbot)
|
|
||||||
|
|
||||||
if article_dict is None: raise RuntimeError("解析PDF失败,请检查PDF是否损坏。")
|
|
||||||
yield from translate_pdf(article_dict, llm_kwargs, chatbot, fp, generated_conclusion_files, TOKEN_LIMIT_PER_FRAGMENT, DST_LANG)
|
|
||||||
chatbot.append(("给出输出文件清单", str(generated_conclusion_files + generated_html_files)))
|
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
|
||||||
|
|
||||||
|
|
||||||
def 解析PDF(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt):
|
|
||||||
"""
|
"""
|
||||||
此函数已经弃用
|
注意:此函数已经弃用!!新函数位于:crazy_functions/pdf_fns/parse_pdf.py
|
||||||
"""
|
"""
|
||||||
import copy
|
import copy
|
||||||
TOKEN_LIMIT_PER_FRAGMENT = 1024
|
TOKEN_LIMIT_PER_FRAGMENT = 1024
|
||||||
@@ -116,7 +49,8 @@ def 解析PDF(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot,
|
|||||||
chatbot=chatbot,
|
chatbot=chatbot,
|
||||||
history_array=[[paper_meta] for _ in paper_fragments],
|
history_array=[[paper_meta] for _ in paper_fragments],
|
||||||
sys_prompt_array=[
|
sys_prompt_array=[
|
||||||
"请你作为一个学术翻译,负责把学术论文准确翻译成中文。注意文章中的每一句话都要翻译。" for _ in paper_fragments],
|
"请你作为一个学术翻译,负责把学术论文准确翻译成中文。注意文章中的每一句话都要翻译。" + plugin_kwargs.get("additional_prompt", "")
|
||||||
|
for _ in paper_fragments],
|
||||||
# max_workers=5 # OpenAI所允许的最大并行过载
|
# max_workers=5 # OpenAI所允许的最大并行过载
|
||||||
)
|
)
|
||||||
gpt_response_collection_md = copy.deepcopy(gpt_response_collection)
|
gpt_response_collection_md = copy.deepcopy(gpt_response_collection)
|
||||||
@@ -160,7 +94,7 @@ def 解析PDF(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot,
|
|||||||
generated_html_files.append(ch.save_file(create_report_file_name))
|
generated_html_files.append(ch.save_file(create_report_file_name))
|
||||||
except:
|
except:
|
||||||
from toolbox import trimmed_format_exc
|
from toolbox import trimmed_format_exc
|
||||||
print('writing html result failed:', trimmed_format_exc())
|
logger.error('writing html result failed:', trimmed_format_exc())
|
||||||
|
|
||||||
# 准备文件的下载
|
# 准备文件的下载
|
||||||
for pdf_path in generated_conclusion_files:
|
for pdf_path in generated_conclusion_files:
|
||||||
@@ -0,0 +1,250 @@
|
|||||||
|
from toolbox import get_log_folder, gen_time_str, get_conf
|
||||||
|
from toolbox import update_ui, promote_file_to_downloadzone
|
||||||
|
from toolbox import promote_file_to_downloadzone, extract_archive
|
||||||
|
from toolbox import generate_file_link, zip_folder
|
||||||
|
from crazy_functions.crazy_utils import get_files_from_everything
|
||||||
|
from shared_utils.colorful import *
|
||||||
|
from loguru import logger
|
||||||
|
import os
|
||||||
|
import time
|
||||||
|
|
||||||
|
def refresh_key(doc2x_api_key):
|
||||||
|
import requests, json
|
||||||
|
url = "https://api.doc2x.noedgeai.com/api/token/refresh"
|
||||||
|
res = requests.post(
|
||||||
|
url,
|
||||||
|
headers={"Authorization": "Bearer " + doc2x_api_key}
|
||||||
|
)
|
||||||
|
res_json = []
|
||||||
|
if res.status_code == 200:
|
||||||
|
decoded = res.content.decode("utf-8")
|
||||||
|
res_json = json.loads(decoded)
|
||||||
|
doc2x_api_key = res_json['data']['token']
|
||||||
|
else:
|
||||||
|
raise RuntimeError(format("[ERROR] status code: %d, body: %s" % (res.status_code, res.text)))
|
||||||
|
return doc2x_api_key
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def 解析PDF_DOC2X_转Latex(pdf_file_path):
|
||||||
|
zip_file_path, unzipped_folder = 解析PDF_DOC2X(pdf_file_path, format='tex')
|
||||||
|
return unzipped_folder
|
||||||
|
|
||||||
|
|
||||||
|
def 解析PDF_DOC2X(pdf_file_path, format='tex'):
|
||||||
|
"""
|
||||||
|
format: 'tex', 'md', 'docx'
|
||||||
|
"""
|
||||||
|
import requests, json, os
|
||||||
|
DOC2X_API_KEY = get_conf('DOC2X_API_KEY')
|
||||||
|
latex_dir = get_log_folder(plugin_name="pdf_ocr_latex")
|
||||||
|
markdown_dir = get_log_folder(plugin_name="pdf_ocr")
|
||||||
|
doc2x_api_key = DOC2X_API_KEY
|
||||||
|
|
||||||
|
|
||||||
|
# < ------ 第1步:上传 ------ >
|
||||||
|
logger.info("Doc2x 第1步:上传")
|
||||||
|
with open(pdf_file_path, 'rb') as file:
|
||||||
|
res = requests.post(
|
||||||
|
"https://v2.doc2x.noedgeai.com/api/v2/parse/pdf",
|
||||||
|
headers={"Authorization": "Bearer " + doc2x_api_key},
|
||||||
|
data=file
|
||||||
|
)
|
||||||
|
# res_json = []
|
||||||
|
if res.status_code == 200:
|
||||||
|
res_json = res.json()
|
||||||
|
else:
|
||||||
|
raise RuntimeError(f"Doc2x return an error: {res.json()}")
|
||||||
|
uuid = res_json['data']['uid']
|
||||||
|
|
||||||
|
# < ------ 第2步:轮询等待 ------ >
|
||||||
|
logger.info("Doc2x 第2步:轮询等待")
|
||||||
|
params = {'uid': uuid}
|
||||||
|
while True:
|
||||||
|
res = requests.get(
|
||||||
|
'https://v2.doc2x.noedgeai.com/api/v2/parse/status',
|
||||||
|
headers={"Authorization": "Bearer " + doc2x_api_key},
|
||||||
|
params=params
|
||||||
|
)
|
||||||
|
res_json = res.json()
|
||||||
|
if res_json['data']['status'] == "success":
|
||||||
|
break
|
||||||
|
elif res_json['data']['status'] == "processing":
|
||||||
|
time.sleep(3)
|
||||||
|
logger.info(f"Doc2x is processing at {res_json['data']['progress']}%")
|
||||||
|
elif res_json['data']['status'] == "failed":
|
||||||
|
raise RuntimeError(f"Doc2x return an error: {res_json}")
|
||||||
|
|
||||||
|
|
||||||
|
# < ------ 第3步:提交转化 ------ >
|
||||||
|
logger.info("Doc2x 第3步:提交转化")
|
||||||
|
data = {
|
||||||
|
"uid": uuid,
|
||||||
|
"to": format,
|
||||||
|
"formula_mode": "dollar",
|
||||||
|
"filename": "output"
|
||||||
|
}
|
||||||
|
res = requests.post(
|
||||||
|
'https://v2.doc2x.noedgeai.com/api/v2/convert/parse',
|
||||||
|
headers={"Authorization": "Bearer " + doc2x_api_key},
|
||||||
|
json=data
|
||||||
|
)
|
||||||
|
if res.status_code == 200:
|
||||||
|
res_json = res.json()
|
||||||
|
else:
|
||||||
|
raise RuntimeError(f"Doc2x return an error: {res.json()}")
|
||||||
|
|
||||||
|
|
||||||
|
# < ------ 第4步:等待结果 ------ >
|
||||||
|
logger.info("Doc2x 第4步:等待结果")
|
||||||
|
params = {'uid': uuid}
|
||||||
|
while True:
|
||||||
|
res = requests.get(
|
||||||
|
'https://v2.doc2x.noedgeai.com/api/v2/convert/parse/result',
|
||||||
|
headers={"Authorization": "Bearer " + doc2x_api_key},
|
||||||
|
params=params
|
||||||
|
)
|
||||||
|
res_json = res.json()
|
||||||
|
if res_json['data']['status'] == "success":
|
||||||
|
break
|
||||||
|
elif res_json['data']['status'] == "processing":
|
||||||
|
time.sleep(3)
|
||||||
|
logger.info(f"Doc2x still processing")
|
||||||
|
elif res_json['data']['status'] == "failed":
|
||||||
|
raise RuntimeError(f"Doc2x return an error: {res_json}")
|
||||||
|
|
||||||
|
|
||||||
|
# < ------ 第5步:最后的处理 ------ >
|
||||||
|
logger.info("Doc2x 第5步:最后的处理")
|
||||||
|
|
||||||
|
if format=='tex':
|
||||||
|
target_path = latex_dir
|
||||||
|
if format=='md':
|
||||||
|
target_path = markdown_dir
|
||||||
|
os.makedirs(target_path, exist_ok=True)
|
||||||
|
|
||||||
|
max_attempt = 3
|
||||||
|
# < ------ 下载 ------ >
|
||||||
|
for attempt in range(max_attempt):
|
||||||
|
try:
|
||||||
|
result_url = res_json['data']['url']
|
||||||
|
res = requests.get(result_url)
|
||||||
|
zip_path = os.path.join(target_path, gen_time_str() + '.zip')
|
||||||
|
unzip_path = os.path.join(target_path, gen_time_str())
|
||||||
|
if res.status_code == 200:
|
||||||
|
with open(zip_path, "wb") as f: f.write(res.content)
|
||||||
|
else:
|
||||||
|
raise RuntimeError(f"Doc2x return an error: {res.json()}")
|
||||||
|
except Exception as e:
|
||||||
|
if attempt < max_attempt - 1:
|
||||||
|
logger.error(f"Failed to download latex file, retrying... {e}")
|
||||||
|
time.sleep(3)
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
raise e
|
||||||
|
|
||||||
|
# < ------ 解压 ------ >
|
||||||
|
import zipfile
|
||||||
|
with zipfile.ZipFile(zip_path, 'r') as zip_ref:
|
||||||
|
zip_ref.extractall(unzip_path)
|
||||||
|
return zip_path, unzip_path
|
||||||
|
|
||||||
|
|
||||||
|
def 解析PDF_DOC2X_单文件(fp, project_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, DOC2X_API_KEY, user_request):
|
||||||
|
|
||||||
|
def pdf2markdown(filepath):
|
||||||
|
chatbot.append((None, f"Doc2x 解析中"))
|
||||||
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
||||||
|
|
||||||
|
md_zip_path, unzipped_folder = 解析PDF_DOC2X(filepath, format='md')
|
||||||
|
|
||||||
|
promote_file_to_downloadzone(md_zip_path, chatbot=chatbot)
|
||||||
|
chatbot.append((None, f"完成解析 {md_zip_path} ..."))
|
||||||
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
||||||
|
return md_zip_path
|
||||||
|
|
||||||
|
def deliver_to_markdown_plugin(md_zip_path, user_request):
|
||||||
|
from crazy_functions.Markdown_Translate import Markdown英译中
|
||||||
|
import shutil, re
|
||||||
|
|
||||||
|
time_tag = gen_time_str()
|
||||||
|
target_path_base = get_log_folder(chatbot.get_user())
|
||||||
|
file_origin_name = os.path.basename(md_zip_path)
|
||||||
|
this_file_path = os.path.join(target_path_base, file_origin_name)
|
||||||
|
os.makedirs(target_path_base, exist_ok=True)
|
||||||
|
shutil.copyfile(md_zip_path, this_file_path)
|
||||||
|
ex_folder = this_file_path + ".extract"
|
||||||
|
extract_archive(
|
||||||
|
file_path=this_file_path, dest_dir=ex_folder
|
||||||
|
)
|
||||||
|
|
||||||
|
# edit markdown files
|
||||||
|
success, file_manifest, project_folder = get_files_from_everything(ex_folder, type='.md')
|
||||||
|
for generated_fp in file_manifest:
|
||||||
|
# 修正一些公式问题
|
||||||
|
with open(generated_fp, 'r', encoding='utf8') as f:
|
||||||
|
content = f.read()
|
||||||
|
# 将公式中的\[ \]替换成$$
|
||||||
|
content = content.replace(r'\[', r'$$').replace(r'\]', r'$$')
|
||||||
|
# 将公式中的\( \)替换成$
|
||||||
|
content = content.replace(r'\(', r'$').replace(r'\)', r'$')
|
||||||
|
content = content.replace('```markdown', '\n').replace('```', '\n')
|
||||||
|
with open(generated_fp, 'w', encoding='utf8') as f:
|
||||||
|
f.write(content)
|
||||||
|
promote_file_to_downloadzone(generated_fp, chatbot=chatbot)
|
||||||
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
||||||
|
|
||||||
|
# 生成在线预览html
|
||||||
|
file_name = '在线预览翻译(原文)' + gen_time_str() + '.html'
|
||||||
|
preview_fp = os.path.join(ex_folder, file_name)
|
||||||
|
from shared_utils.advanced_markdown_format import markdown_convertion_for_file
|
||||||
|
with open(generated_fp, "r", encoding="utf-8") as f:
|
||||||
|
md = f.read()
|
||||||
|
# # Markdown中使用不标准的表格,需要在表格前加上一个emoji,以便公式渲染
|
||||||
|
# md = re.sub(r'^<table>', r'.<table>', md, flags=re.MULTILINE)
|
||||||
|
html = markdown_convertion_for_file(md)
|
||||||
|
with open(preview_fp, "w", encoding="utf-8") as f: f.write(html)
|
||||||
|
chatbot.append([None, f"生成在线预览:{generate_file_link([preview_fp])}"])
|
||||||
|
promote_file_to_downloadzone(preview_fp, chatbot=chatbot)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
chatbot.append((None, f"调用Markdown插件 {ex_folder} ..."))
|
||||||
|
plugin_kwargs['markdown_expected_output_dir'] = ex_folder
|
||||||
|
|
||||||
|
translated_f_name = 'translated_markdown.md'
|
||||||
|
generated_fp = plugin_kwargs['markdown_expected_output_path'] = os.path.join(ex_folder, translated_f_name)
|
||||||
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
||||||
|
yield from Markdown英译中(ex_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request)
|
||||||
|
if os.path.exists(generated_fp):
|
||||||
|
# 修正一些公式问题
|
||||||
|
with open(generated_fp, 'r', encoding='utf8') as f: content = f.read()
|
||||||
|
content = content.replace('```markdown', '\n').replace('```', '\n')
|
||||||
|
# Markdown中使用不标准的表格,需要在表格前加上一个emoji,以便公式渲染
|
||||||
|
# content = re.sub(r'^<table>', r'.<table>', content, flags=re.MULTILINE)
|
||||||
|
with open(generated_fp, 'w', encoding='utf8') as f: f.write(content)
|
||||||
|
# 生成在线预览html
|
||||||
|
file_name = '在线预览翻译' + gen_time_str() + '.html'
|
||||||
|
preview_fp = os.path.join(ex_folder, file_name)
|
||||||
|
from shared_utils.advanced_markdown_format import markdown_convertion_for_file
|
||||||
|
with open(generated_fp, "r", encoding="utf-8") as f:
|
||||||
|
md = f.read()
|
||||||
|
html = markdown_convertion_for_file(md)
|
||||||
|
with open(preview_fp, "w", encoding="utf-8") as f: f.write(html)
|
||||||
|
promote_file_to_downloadzone(preview_fp, chatbot=chatbot)
|
||||||
|
# 生成包含图片的压缩包
|
||||||
|
dest_folder = get_log_folder(chatbot.get_user())
|
||||||
|
zip_name = '翻译后的带图文档.zip'
|
||||||
|
zip_folder(source_folder=ex_folder, dest_folder=dest_folder, zip_name=zip_name)
|
||||||
|
zip_fp = os.path.join(dest_folder, zip_name)
|
||||||
|
promote_file_to_downloadzone(zip_fp, chatbot=chatbot)
|
||||||
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
||||||
|
md_zip_path = yield from pdf2markdown(fp)
|
||||||
|
yield from deliver_to_markdown_plugin(md_zip_path, user_request)
|
||||||
|
|
||||||
|
def 解析PDF_基于DOC2X(file_manifest, *args):
|
||||||
|
for index, fp in enumerate(file_manifest):
|
||||||
|
yield from 解析PDF_DOC2X_单文件(fp, *args)
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
from crazy_functions.crazy_utils import read_and_clean_pdf_text, get_files_from_everything
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
def extract_text_from_files(txt, chatbot, history):
|
||||||
|
"""
|
||||||
|
查找pdf/md/word并获取文本内容并返回状态以及文本
|
||||||
|
|
||||||
|
输入参数 Args:
|
||||||
|
chatbot: chatbot inputs and outputs (用户界面对话窗口句柄,用于数据流可视化)
|
||||||
|
history (list): List of chat history (历史,对话历史列表)
|
||||||
|
|
||||||
|
输出 Returns:
|
||||||
|
文件是否存在(bool)
|
||||||
|
final_result(list):文本内容
|
||||||
|
page_one(list):第一页内容/摘要
|
||||||
|
file_manifest(list):文件路径
|
||||||
|
excption(string):需要用户手动处理的信息,如没出错则保持为空
|
||||||
|
"""
|
||||||
|
|
||||||
|
final_result = []
|
||||||
|
page_one = []
|
||||||
|
file_manifest = []
|
||||||
|
excption = ""
|
||||||
|
|
||||||
|
if txt == "":
|
||||||
|
final_result.append(txt)
|
||||||
|
return False, final_result, page_one, file_manifest, excption #如输入区内容不是文件则直接返回输入区内容
|
||||||
|
|
||||||
|
#查找输入区内容中的文件
|
||||||
|
file_pdf,pdf_manifest,folder_pdf = get_files_from_everything(txt, '.pdf')
|
||||||
|
file_md,md_manifest,folder_md = get_files_from_everything(txt, '.md')
|
||||||
|
file_word,word_manifest,folder_word = get_files_from_everything(txt, '.docx')
|
||||||
|
file_doc,doc_manifest,folder_doc = get_files_from_everything(txt, '.doc')
|
||||||
|
|
||||||
|
if file_doc:
|
||||||
|
excption = "word"
|
||||||
|
return False, final_result, page_one, file_manifest, excption
|
||||||
|
|
||||||
|
file_num = len(pdf_manifest) + len(md_manifest) + len(word_manifest)
|
||||||
|
if file_num == 0:
|
||||||
|
final_result.append(txt)
|
||||||
|
return False, final_result, page_one, file_manifest, excption #如输入区内容不是文件则直接返回输入区内容
|
||||||
|
|
||||||
|
if file_pdf:
|
||||||
|
try: # 尝试导入依赖,如果缺少依赖,则给出安装建议
|
||||||
|
import fitz
|
||||||
|
except:
|
||||||
|
excption = "pdf"
|
||||||
|
return False, final_result, page_one, file_manifest, excption
|
||||||
|
for index, fp in enumerate(pdf_manifest):
|
||||||
|
file_content, pdf_one = read_and_clean_pdf_text(fp) # (尝试)按照章节切割PDF
|
||||||
|
file_content = file_content.encode('utf-8', 'ignore').decode() # avoid reading non-utf8 chars
|
||||||
|
pdf_one = str(pdf_one).encode('utf-8', 'ignore').decode() # avoid reading non-utf8 chars
|
||||||
|
final_result.append(file_content)
|
||||||
|
page_one.append(pdf_one)
|
||||||
|
file_manifest.append(os.path.relpath(fp, folder_pdf))
|
||||||
|
|
||||||
|
if file_md:
|
||||||
|
for index, fp in enumerate(md_manifest):
|
||||||
|
with open(fp, 'r', encoding='utf-8', errors='replace') as f:
|
||||||
|
file_content = f.read()
|
||||||
|
file_content = file_content.encode('utf-8', 'ignore').decode()
|
||||||
|
headers = re.findall(r'^#\s(.*)$', file_content, re.MULTILINE) #接下来提取md中的一级/二级标题作为摘要
|
||||||
|
if len(headers) > 0:
|
||||||
|
page_one.append("\n".join(headers)) #合并所有的标题,以换行符分割
|
||||||
|
else:
|
||||||
|
page_one.append("")
|
||||||
|
final_result.append(file_content)
|
||||||
|
file_manifest.append(os.path.relpath(fp, folder_md))
|
||||||
|
|
||||||
|
if file_word:
|
||||||
|
try: # 尝试导入依赖,如果缺少依赖,则给出安装建议
|
||||||
|
from docx import Document
|
||||||
|
except:
|
||||||
|
excption = "word_pip"
|
||||||
|
return False, final_result, page_one, file_manifest, excption
|
||||||
|
for index, fp in enumerate(word_manifest):
|
||||||
|
doc = Document(fp)
|
||||||
|
file_content = '\n'.join([p.text for p in doc.paragraphs])
|
||||||
|
file_content = file_content.encode('utf-8', 'ignore').decode()
|
||||||
|
page_one.append(file_content[:200])
|
||||||
|
final_result.append(file_content)
|
||||||
|
file_manifest.append(os.path.relpath(fp, folder_word))
|
||||||
|
|
||||||
|
return True, final_result, page_one, file_manifest, excption
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||||
|
<title>GPT-Academic 翻译报告书</title>
|
||||||
|
<style>
|
||||||
|
.centered-a {
|
||||||
|
color: red;
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 2%;
|
||||||
|
font-size: 1.5em;
|
||||||
|
}
|
||||||
|
.centered-b {
|
||||||
|
color: red;
|
||||||
|
text-align: center;
|
||||||
|
margin-top: 10%;
|
||||||
|
margin-bottom: 20%;
|
||||||
|
font-size: 1.5em;
|
||||||
|
}
|
||||||
|
.centered-c {
|
||||||
|
color: rgba(255, 0, 0, 0);
|
||||||
|
text-align: center;
|
||||||
|
margin-top: 2%;
|
||||||
|
margin-bottom: 20%;
|
||||||
|
font-size: 7em;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<script>
|
||||||
|
// Configure MathJax settings
|
||||||
|
MathJax = {
|
||||||
|
tex: {
|
||||||
|
inlineMath: [
|
||||||
|
['$', '$'],
|
||||||
|
['\(', '\)']
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
addEventListener('zero-md-rendered', () => {MathJax.typeset(); console.log('MathJax typeset!');})
|
||||||
|
</script>
|
||||||
|
<!-- Load MathJax library -->
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-chtml.js"></script>
|
||||||
|
<script
|
||||||
|
type="module"
|
||||||
|
src="https://cdn.jsdelivr.net/gh/zerodevx/zero-md@2/dist/zero-md.min.js"
|
||||||
|
></script>
|
||||||
|
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div class="test_temp1" style="width:10%; height: 500px; float:left;">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="test_temp2" style="width:80%; height: 500px; float:left;">
|
||||||
|
<!-- Simply set the `src` attribute to your MD file and win -->
|
||||||
|
<div class="centered-a">
|
||||||
|
请按Ctrl+S保存此页面,否则该页面可能在几分钟后失效。
|
||||||
|
</div>
|
||||||
|
<zero-md src="translated_markdown.md" no-shadow>
|
||||||
|
</zero-md>
|
||||||
|
<div class="centered-b">
|
||||||
|
本报告由GPT-Academic开源项目生成,地址:https://github.com/binary-husky/gpt_academic。
|
||||||
|
</div>
|
||||||
|
<div class="centered-c">
|
||||||
|
本报告由GPT-Academic开源项目生成,地址:https://github.com/binary-husky/gpt_academic。
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="test_temp3" style="width:10%; height: 500px; float:left;">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
import os, json, base64
|
||||||
|
from pydantic import BaseModel, Field
|
||||||
|
from textwrap import dedent
|
||||||
|
from typing import List
|
||||||
|
|
||||||
|
class ArgProperty(BaseModel): # PLUGIN_ARG_MENU
|
||||||
|
title: str = Field(description="The title", default="")
|
||||||
|
description: str = Field(description="The description", default="")
|
||||||
|
default_value: str = Field(description="The default value", default="")
|
||||||
|
type: str = Field(description="The type", default="") # currently we support ['string', 'dropdown']
|
||||||
|
options: List[str] = Field(default=[], description="List of options available for the argument") # only used when type is 'dropdown'
|
||||||
|
|
||||||
|
class GptAcademicPluginTemplate():
|
||||||
|
def __init__(self):
|
||||||
|
# please note that `execute` method may run in different threads,
|
||||||
|
# thus you should not store any state in the plugin instance,
|
||||||
|
# which may be accessed by multiple threads
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def define_arg_selection_menu(self):
|
||||||
|
"""
|
||||||
|
An example as below:
|
||||||
|
```
|
||||||
|
def define_arg_selection_menu(self):
|
||||||
|
gui_definition = {
|
||||||
|
"main_input":
|
||||||
|
ArgProperty(title="main input", description="description", default_value="default_value", type="string").model_dump_json(),
|
||||||
|
"advanced_arg":
|
||||||
|
ArgProperty(title="advanced arguments", description="description", default_value="default_value", type="string").model_dump_json(),
|
||||||
|
"additional_arg_01":
|
||||||
|
ArgProperty(title="additional", description="description", default_value="default_value", type="string").model_dump_json(),
|
||||||
|
}
|
||||||
|
return gui_definition
|
||||||
|
```
|
||||||
|
"""
|
||||||
|
raise NotImplementedError("You need to implement this method in your plugin class")
|
||||||
|
|
||||||
|
|
||||||
|
def get_js_code_for_generating_menu(self, btnName):
|
||||||
|
define_arg_selection = self.define_arg_selection_menu()
|
||||||
|
|
||||||
|
if len(define_arg_selection.keys()) > 8:
|
||||||
|
raise ValueError("You can only have up to 8 arguments in the define_arg_selection")
|
||||||
|
# if "main_input" not in define_arg_selection:
|
||||||
|
# raise ValueError("You must have a 'main_input' in the define_arg_selection")
|
||||||
|
|
||||||
|
DEFINE_ARG_INPUT_INTERFACE = json.dumps(define_arg_selection)
|
||||||
|
return base64.b64encode(DEFINE_ARG_INPUT_INTERFACE.encode('utf-8')).decode('utf-8')
|
||||||
|
|
||||||
|
def execute(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request):
|
||||||
|
raise NotImplementedError("You need to implement this method in your plugin class")
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
SearchOptimizerPrompt="""作为一个网页搜索助手,你的任务是结合历史记录,从不同角度,为“原问题”生成个不同版本的“检索词”,从而提高网页检索的精度。生成的问题要求指向对象清晰明确,并与“原问题语言相同”。例如:
|
||||||
|
历史记录:
|
||||||
|
"
|
||||||
|
Q: 对话背景。
|
||||||
|
A: 当前对话是关于 Nginx 的介绍和在Ubuntu上的使用等。
|
||||||
|
"
|
||||||
|
原问题: 怎么下载
|
||||||
|
检索词: ["Nginx 下载","Ubuntu Nginx","Ubuntu安装Nginx"]
|
||||||
|
----------------
|
||||||
|
历史记录:
|
||||||
|
"
|
||||||
|
Q: 对话背景。
|
||||||
|
A: 当前对话是关于 Nginx 的介绍和使用等。
|
||||||
|
Q: 报错 "no connection"
|
||||||
|
A: 报错"no connection"可能是因为……
|
||||||
|
"
|
||||||
|
原问题: 怎么解决
|
||||||
|
检索词: ["Nginx报错"no connection" 解决","Nginx'no connection'报错 原因","Nginx提示'no connection'"]
|
||||||
|
----------------
|
||||||
|
历史记录:
|
||||||
|
"
|
||||||
|
|
||||||
|
"
|
||||||
|
原问题: 你知道 Python 么?
|
||||||
|
检索词: ["Python","Python 使用教程。","Python 特点和优势"]
|
||||||
|
----------------
|
||||||
|
历史记录:
|
||||||
|
"
|
||||||
|
Q: 列出Java的三种特点?
|
||||||
|
A: 1. Java 是一种编译型语言。
|
||||||
|
2. Java 是一种面向对象的编程语言。
|
||||||
|
3. Java 是一种跨平台的编程语言。
|
||||||
|
"
|
||||||
|
原问题: 介绍下第2点。
|
||||||
|
检索词: ["Java 面向对象特点","Java 面向对象编程优势。","Java 面向对象编程"]
|
||||||
|
----------------
|
||||||
|
现在有历史记录:
|
||||||
|
"
|
||||||
|
{history}
|
||||||
|
"
|
||||||
|
有其原问题: {query}
|
||||||
|
直接给出最多{num}个检索词,必须以json形式给出,不得有多余字符:
|
||||||
|
"""
|
||||||
|
|
||||||
|
SearchAcademicOptimizerPrompt="""作为一个学术论文搜索助手,你的任务是结合历史记录,从不同角度,为“原问题”生成个不同版本的“检索词”,从而提高学术论文检索的精度。生成的问题要求指向对象清晰明确,并与“原问题语言相同”。例如:
|
||||||
|
历史记录:
|
||||||
|
"
|
||||||
|
Q: 对话背景。
|
||||||
|
A: 当前对话是关于深度学习的介绍和在图像识别中的应用等。
|
||||||
|
"
|
||||||
|
原问题: 怎么下载相关论文
|
||||||
|
检索词: ["深度学习 图像识别 论文下载","图像识别 深度学习 研究论文","深度学习 图像识别 论文资源","Deep Learning Image Recognition Paper Download","Image Recognition Deep Learning Research Paper"]
|
||||||
|
----------------
|
||||||
|
历史记录:
|
||||||
|
"
|
||||||
|
Q: 对话背景。
|
||||||
|
A: 当前对话是关于深度学习的介绍和应用等。
|
||||||
|
Q: 报错 "模型不收敛"
|
||||||
|
A: 报错"模型不收敛"可能是因为……
|
||||||
|
"
|
||||||
|
原问题: 怎么解决
|
||||||
|
检索词: ["深度学习 模型不收敛 解决方案 论文","深度学习 模型不收敛 原因 研究","深度学习 模型不收敛 论文","Deep Learning Model Convergence Issue Solution Paper","Deep Learning Model Convergence Problem Research"]
|
||||||
|
----------------
|
||||||
|
历史记录:
|
||||||
|
"
|
||||||
|
|
||||||
|
"
|
||||||
|
原问题: 你知道 GAN 么?
|
||||||
|
检索词: ["生成对抗网络 论文","GAN 使用教程 论文","GAN 特点和优势 研究","Generative Adversarial Network Paper","GAN Usage Tutorial Paper"]
|
||||||
|
----------------
|
||||||
|
历史记录:
|
||||||
|
"
|
||||||
|
Q: 列出机器学习的三种应用?
|
||||||
|
A: 1. 机器学习在图像识别中的应用。
|
||||||
|
2. 机器学习在自然语言处理中的应用。
|
||||||
|
3. 机器学习在推荐系统中的应用。
|
||||||
|
"
|
||||||
|
原问题: 介绍下第2点。
|
||||||
|
检索词: ["机器学习 自然语言处理 应用 论文","机器学习 自然语言处理 研究","机器学习 NLP 应用 论文","Machine Learning Natural Language Processing Application Paper","Machine Learning NLP Research"]
|
||||||
|
----------------
|
||||||
|
现在有历史记录:
|
||||||
|
"
|
||||||
|
{history}
|
||||||
|
"
|
||||||
|
有其原问题: {query}
|
||||||
|
直接给出最多{num}个检索词,必须以json形式给出,不得有多余字符:
|
||||||
|
"""
|
||||||
@@ -0,0 +1,138 @@
|
|||||||
|
import atexit
|
||||||
|
from loguru import logger
|
||||||
|
from typing import List
|
||||||
|
|
||||||
|
from llama_index.core import Document
|
||||||
|
from llama_index.core.ingestion import run_transformations
|
||||||
|
from llama_index.core.schema import TextNode
|
||||||
|
|
||||||
|
from crazy_functions.rag_fns.vector_store_index import GptacVectorStoreIndex
|
||||||
|
from request_llms.embed_models.openai_embed import OpenAiEmbeddingModel
|
||||||
|
|
||||||
|
DEFAULT_QUERY_GENERATION_PROMPT = """\
|
||||||
|
Now, you have context information as below:
|
||||||
|
---------------------
|
||||||
|
{context_str}
|
||||||
|
---------------------
|
||||||
|
Answer the user request below (use the context information if necessary, otherwise you can ignore them):
|
||||||
|
---------------------
|
||||||
|
{query_str}
|
||||||
|
"""
|
||||||
|
|
||||||
|
QUESTION_ANSWER_RECORD = """\
|
||||||
|
{{
|
||||||
|
"type": "This is a previous conversation with the user",
|
||||||
|
"question": "{question}",
|
||||||
|
"answer": "{answer}",
|
||||||
|
}}
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
class SaveLoad():
|
||||||
|
|
||||||
|
def does_checkpoint_exist(self, checkpoint_dir=None):
|
||||||
|
import os, glob
|
||||||
|
if checkpoint_dir is None: checkpoint_dir = self.checkpoint_dir
|
||||||
|
if not os.path.exists(checkpoint_dir): return False
|
||||||
|
if len(glob.glob(os.path.join(checkpoint_dir, "*.json"))) == 0: return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
def save_to_checkpoint(self, checkpoint_dir=None):
|
||||||
|
logger.info(f'saving vector store to: {checkpoint_dir}')
|
||||||
|
if checkpoint_dir is None: checkpoint_dir = self.checkpoint_dir
|
||||||
|
self.vs_index.storage_context.persist(persist_dir=checkpoint_dir)
|
||||||
|
|
||||||
|
def load_from_checkpoint(self, checkpoint_dir=None):
|
||||||
|
if checkpoint_dir is None: checkpoint_dir = self.checkpoint_dir
|
||||||
|
if self.does_checkpoint_exist(checkpoint_dir=checkpoint_dir):
|
||||||
|
logger.info('loading checkpoint from disk')
|
||||||
|
from llama_index.core import StorageContext, load_index_from_storage
|
||||||
|
storage_context = StorageContext.from_defaults(persist_dir=checkpoint_dir)
|
||||||
|
self.vs_index = load_index_from_storage(storage_context, embed_model=self.embed_model)
|
||||||
|
return self.vs_index
|
||||||
|
else:
|
||||||
|
return self.create_new_vs()
|
||||||
|
|
||||||
|
def create_new_vs(self):
|
||||||
|
return GptacVectorStoreIndex.default_vector_store(embed_model=self.embed_model)
|
||||||
|
|
||||||
|
def purge(self):
|
||||||
|
import shutil
|
||||||
|
shutil.rmtree(self.checkpoint_dir, ignore_errors=True)
|
||||||
|
self.vs_index = self.create_new_vs(self.checkpoint_dir)
|
||||||
|
|
||||||
|
|
||||||
|
class LlamaIndexRagWorker(SaveLoad):
|
||||||
|
def __init__(self, user_name, llm_kwargs, auto_load_checkpoint=True, checkpoint_dir=None) -> None:
|
||||||
|
self.debug_mode = True
|
||||||
|
self.embed_model = OpenAiEmbeddingModel(llm_kwargs)
|
||||||
|
self.user_name = user_name
|
||||||
|
self.checkpoint_dir = checkpoint_dir
|
||||||
|
if auto_load_checkpoint:
|
||||||
|
self.vs_index = self.load_from_checkpoint(checkpoint_dir)
|
||||||
|
else:
|
||||||
|
self.vs_index = self.create_new_vs()
|
||||||
|
atexit.register(lambda: self.save_to_checkpoint(checkpoint_dir))
|
||||||
|
|
||||||
|
def assign_embedding_model(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def inspect_vector_store(self):
|
||||||
|
# This function is for debugging
|
||||||
|
self.vs_index.storage_context.index_store.to_dict()
|
||||||
|
docstore = self.vs_index.storage_context.docstore.docs
|
||||||
|
vector_store_preview = "\n".join([ f"{_id} | {tn.text}" for _id, tn in docstore.items() ])
|
||||||
|
logger.info('\n++ --------inspect_vector_store begin--------')
|
||||||
|
logger.info(vector_store_preview)
|
||||||
|
logger.info('oo --------inspect_vector_store end--------')
|
||||||
|
return vector_store_preview
|
||||||
|
|
||||||
|
def add_documents_to_vector_store(self, document_list: List[Document]):
|
||||||
|
"""
|
||||||
|
Adds a list of Document objects to the vector store after processing.
|
||||||
|
"""
|
||||||
|
documents = document_list
|
||||||
|
documents_nodes = run_transformations(
|
||||||
|
documents, # type: ignore
|
||||||
|
self.vs_index._transformations,
|
||||||
|
show_progress=True
|
||||||
|
)
|
||||||
|
self.vs_index.insert_nodes(documents_nodes)
|
||||||
|
if self.debug_mode:
|
||||||
|
self.inspect_vector_store()
|
||||||
|
|
||||||
|
def add_text_to_vector_store(self, text: str):
|
||||||
|
node = TextNode(text=text)
|
||||||
|
documents_nodes = run_transformations(
|
||||||
|
[node],
|
||||||
|
self.vs_index._transformations,
|
||||||
|
show_progress=True
|
||||||
|
)
|
||||||
|
self.vs_index.insert_nodes(documents_nodes)
|
||||||
|
if self.debug_mode:
|
||||||
|
self.inspect_vector_store()
|
||||||
|
|
||||||
|
def remember_qa(self, question, answer):
|
||||||
|
formatted_str = QUESTION_ANSWER_RECORD.format(question=question, answer=answer)
|
||||||
|
self.add_text_to_vector_store(formatted_str)
|
||||||
|
|
||||||
|
def retrieve_from_store_with_query(self, query):
|
||||||
|
if self.debug_mode:
|
||||||
|
self.inspect_vector_store()
|
||||||
|
retriever = self.vs_index.as_retriever()
|
||||||
|
return retriever.retrieve(query)
|
||||||
|
|
||||||
|
def build_prompt(self, query, nodes):
|
||||||
|
context_str = self.generate_node_array_preview(nodes)
|
||||||
|
return DEFAULT_QUERY_GENERATION_PROMPT.format(context_str=context_str, query_str=query)
|
||||||
|
|
||||||
|
def generate_node_array_preview(self, nodes):
|
||||||
|
buf = "\n".join(([f"(No.{i+1} | score {n.score:.3f}): {n.text}" for i, n in enumerate(nodes)]))
|
||||||
|
if self.debug_mode: logger.info(buf)
|
||||||
|
return buf
|
||||||
|
|
||||||
|
def purge_vector_store(self):
|
||||||
|
"""
|
||||||
|
Purges the current vector store and creates a new one.
|
||||||
|
"""
|
||||||
|
self.purge()
|
||||||
@@ -0,0 +1,108 @@
|
|||||||
|
import llama_index
|
||||||
|
import os
|
||||||
|
import atexit
|
||||||
|
from typing import List
|
||||||
|
from loguru import logger
|
||||||
|
from llama_index.core import Document
|
||||||
|
from llama_index.core.schema import TextNode
|
||||||
|
from request_llms.embed_models.openai_embed import OpenAiEmbeddingModel
|
||||||
|
from shared_utils.connect_void_terminal import get_chat_default_kwargs
|
||||||
|
from llama_index.core import VectorStoreIndex, SimpleDirectoryReader
|
||||||
|
from crazy_functions.rag_fns.vector_store_index import GptacVectorStoreIndex
|
||||||
|
from llama_index.core.ingestion import run_transformations
|
||||||
|
from llama_index.core import PromptTemplate
|
||||||
|
from llama_index.core.response_synthesizers import TreeSummarize
|
||||||
|
from llama_index.core import StorageContext
|
||||||
|
from llama_index.vector_stores.milvus import MilvusVectorStore
|
||||||
|
from crazy_functions.rag_fns.llama_index_worker import LlamaIndexRagWorker
|
||||||
|
|
||||||
|
DEFAULT_QUERY_GENERATION_PROMPT = """\
|
||||||
|
Now, you have context information as below:
|
||||||
|
---------------------
|
||||||
|
{context_str}
|
||||||
|
---------------------
|
||||||
|
Answer the user request below (use the context information if necessary, otherwise you can ignore them):
|
||||||
|
---------------------
|
||||||
|
{query_str}
|
||||||
|
"""
|
||||||
|
|
||||||
|
QUESTION_ANSWER_RECORD = """\
|
||||||
|
{{
|
||||||
|
"type": "This is a previous conversation with the user",
|
||||||
|
"question": "{question}",
|
||||||
|
"answer": "{answer}",
|
||||||
|
}}
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
class MilvusSaveLoad():
|
||||||
|
|
||||||
|
def does_checkpoint_exist(self, checkpoint_dir=None):
|
||||||
|
import os, glob
|
||||||
|
if checkpoint_dir is None: checkpoint_dir = self.checkpoint_dir
|
||||||
|
if not os.path.exists(checkpoint_dir): return False
|
||||||
|
if len(glob.glob(os.path.join(checkpoint_dir, "*.json"))) == 0: return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
def save_to_checkpoint(self, checkpoint_dir=None):
|
||||||
|
logger.info(f'saving vector store to: {checkpoint_dir}')
|
||||||
|
# if checkpoint_dir is None: checkpoint_dir = self.checkpoint_dir
|
||||||
|
# self.vs_index.storage_context.persist(persist_dir=checkpoint_dir)
|
||||||
|
|
||||||
|
def load_from_checkpoint(self, checkpoint_dir=None):
|
||||||
|
if checkpoint_dir is None: checkpoint_dir = self.checkpoint_dir
|
||||||
|
if self.does_checkpoint_exist(checkpoint_dir=checkpoint_dir):
|
||||||
|
logger.info('loading checkpoint from disk')
|
||||||
|
from llama_index.core import StorageContext, load_index_from_storage
|
||||||
|
storage_context = StorageContext.from_defaults(persist_dir=checkpoint_dir)
|
||||||
|
try:
|
||||||
|
self.vs_index = load_index_from_storage(storage_context, embed_model=self.embed_model)
|
||||||
|
return self.vs_index
|
||||||
|
except:
|
||||||
|
return self.create_new_vs(checkpoint_dir)
|
||||||
|
else:
|
||||||
|
return self.create_new_vs(checkpoint_dir)
|
||||||
|
|
||||||
|
def create_new_vs(self, checkpoint_dir, overwrite=False):
|
||||||
|
vector_store = MilvusVectorStore(
|
||||||
|
uri=os.path.join(checkpoint_dir, "milvus_demo.db"),
|
||||||
|
dim=self.embed_model.embedding_dimension(),
|
||||||
|
overwrite=overwrite
|
||||||
|
)
|
||||||
|
storage_context = StorageContext.from_defaults(vector_store=vector_store)
|
||||||
|
index = GptacVectorStoreIndex.default_vector_store(storage_context=storage_context, embed_model=self.embed_model)
|
||||||
|
return index
|
||||||
|
|
||||||
|
def purge(self):
|
||||||
|
self.vs_index = self.create_new_vs(self.checkpoint_dir, overwrite=True)
|
||||||
|
|
||||||
|
class MilvusRagWorker(MilvusSaveLoad, LlamaIndexRagWorker):
|
||||||
|
|
||||||
|
def __init__(self, user_name, llm_kwargs, auto_load_checkpoint=True, checkpoint_dir=None) -> None:
|
||||||
|
self.debug_mode = True
|
||||||
|
self.embed_model = OpenAiEmbeddingModel(llm_kwargs)
|
||||||
|
self.user_name = user_name
|
||||||
|
self.checkpoint_dir = checkpoint_dir
|
||||||
|
if auto_load_checkpoint:
|
||||||
|
self.vs_index = self.load_from_checkpoint(checkpoint_dir)
|
||||||
|
else:
|
||||||
|
self.vs_index = self.create_new_vs(checkpoint_dir)
|
||||||
|
atexit.register(lambda: self.save_to_checkpoint(checkpoint_dir))
|
||||||
|
|
||||||
|
def inspect_vector_store(self):
|
||||||
|
# This function is for debugging
|
||||||
|
try:
|
||||||
|
self.vs_index.storage_context.index_store.to_dict()
|
||||||
|
docstore = self.vs_index.storage_context.docstore.docs
|
||||||
|
if not docstore.items():
|
||||||
|
raise ValueError("cannot inspect")
|
||||||
|
vector_store_preview = "\n".join([ f"{_id} | {tn.text}" for _id, tn in docstore.items() ])
|
||||||
|
except:
|
||||||
|
dummy_retrieve_res: List["NodeWithScore"] = self.vs_index.as_retriever().retrieve(' ')
|
||||||
|
vector_store_preview = "\n".join(
|
||||||
|
[f"{node.id_} | {node.text}" for node in dummy_retrieve_res]
|
||||||
|
)
|
||||||
|
logger.info('\n++ --------inspect_vector_store begin--------')
|
||||||
|
logger.info(vector_store_preview)
|
||||||
|
logger.info('oo --------inspect_vector_store end--------')
|
||||||
|
return vector_store_preview
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
import os
|
||||||
|
from llama_index.core import SimpleDirectoryReader
|
||||||
|
|
||||||
|
supports_format = ['.csv', '.docx','.doc', '.epub', '.ipynb', '.mbox', '.md', '.pdf', '.txt', '.ppt',
|
||||||
|
'.pptm', '.pptx','.py', '.xls', '.xlsx', '.html', '.json', '.xml', '.yaml', '.yml' ,'.m']
|
||||||
|
|
||||||
|
def read_docx_doc(file_path):
|
||||||
|
if file_path.split(".")[-1] == "docx":
|
||||||
|
from docx import Document
|
||||||
|
doc = Document(file_path)
|
||||||
|
file_content = "\n".join([para.text for para in doc.paragraphs])
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
import win32com.client
|
||||||
|
word = win32com.client.Dispatch("Word.Application")
|
||||||
|
word.visible = False
|
||||||
|
# 打开文件
|
||||||
|
doc = word.Documents.Open(os.getcwd() + '/' + file_path)
|
||||||
|
# file_content = doc.Content.Text
|
||||||
|
doc = word.ActiveDocument
|
||||||
|
file_content = doc.Range().Text
|
||||||
|
doc.Close()
|
||||||
|
word.Quit()
|
||||||
|
except:
|
||||||
|
raise RuntimeError('请先将.doc文档转换为.docx文档。')
|
||||||
|
return file_content
|
||||||
|
|
||||||
|
# 修改后的 extract_text 函数,结合 SimpleDirectoryReader 和自定义解析逻辑
|
||||||
|
import os
|
||||||
|
|
||||||
|
def extract_text(file_path):
|
||||||
|
_, ext = os.path.splitext(file_path.lower())
|
||||||
|
|
||||||
|
# 使用 SimpleDirectoryReader 处理它支持的文件格式
|
||||||
|
if ext in ['.docx', '.doc']:
|
||||||
|
return read_docx_doc(file_path)
|
||||||
|
try:
|
||||||
|
reader = SimpleDirectoryReader(input_files=[file_path])
|
||||||
|
documents = reader.load_data()
|
||||||
|
if len(documents) > 0:
|
||||||
|
return documents[0].text
|
||||||
|
except Exception as e:
|
||||||
|
pass
|
||||||
|
|
||||||
|
return None
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
from llama_index.core import VectorStoreIndex
|
||||||
|
from typing import Any, List, Optional
|
||||||
|
|
||||||
|
from llama_index.core.callbacks.base import CallbackManager
|
||||||
|
from llama_index.core.schema import TransformComponent
|
||||||
|
from llama_index.core.service_context import ServiceContext
|
||||||
|
from llama_index.core.settings import (
|
||||||
|
Settings,
|
||||||
|
callback_manager_from_settings_or_context,
|
||||||
|
transformations_from_settings_or_context,
|
||||||
|
)
|
||||||
|
from llama_index.core.storage.storage_context import StorageContext
|
||||||
|
|
||||||
|
|
||||||
|
class GptacVectorStoreIndex(VectorStoreIndex):
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def default_vector_store(
|
||||||
|
cls,
|
||||||
|
storage_context: Optional[StorageContext] = None,
|
||||||
|
show_progress: bool = False,
|
||||||
|
callback_manager: Optional[CallbackManager] = None,
|
||||||
|
transformations: Optional[List[TransformComponent]] = None,
|
||||||
|
# deprecated
|
||||||
|
service_context: Optional[ServiceContext] = None,
|
||||||
|
embed_model = None,
|
||||||
|
**kwargs: Any,
|
||||||
|
):
|
||||||
|
"""Create index from documents.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
documents (Optional[Sequence[BaseDocument]]): List of documents to
|
||||||
|
build the index from.
|
||||||
|
|
||||||
|
"""
|
||||||
|
storage_context = storage_context or StorageContext.from_defaults()
|
||||||
|
docstore = storage_context.docstore
|
||||||
|
callback_manager = (
|
||||||
|
callback_manager
|
||||||
|
or callback_manager_from_settings_or_context(Settings, service_context)
|
||||||
|
)
|
||||||
|
transformations = transformations or transformations_from_settings_or_context(
|
||||||
|
Settings, service_context
|
||||||
|
)
|
||||||
|
|
||||||
|
with callback_manager.as_trace("index_construction"):
|
||||||
|
|
||||||
|
return cls(
|
||||||
|
nodes=[],
|
||||||
|
storage_context=storage_context,
|
||||||
|
callback_manager=callback_manager,
|
||||||
|
show_progress=show_progress,
|
||||||
|
transformations=transformations,
|
||||||
|
service_context=service_context,
|
||||||
|
embed_model=embed_model,
|
||||||
|
**kwargs,
|
||||||
|
)
|
||||||
|
|
||||||
@@ -1,16 +1,17 @@
|
|||||||
# From project chatglm-langchain
|
# From project chatglm-langchain
|
||||||
|
|
||||||
import threading
|
|
||||||
from toolbox import Singleton
|
|
||||||
import os
|
import os
|
||||||
import shutil
|
|
||||||
import os
|
import os
|
||||||
import uuid
|
import uuid
|
||||||
import tqdm
|
import tqdm
|
||||||
|
import shutil
|
||||||
|
import threading
|
||||||
|
import numpy as np
|
||||||
|
from toolbox import Singleton
|
||||||
|
from loguru import logger
|
||||||
from langchain.vectorstores import FAISS
|
from langchain.vectorstores import FAISS
|
||||||
from langchain.docstore.document import Document
|
from langchain.docstore.document import Document
|
||||||
from typing import List, Tuple
|
from typing import List, Tuple
|
||||||
import numpy as np
|
|
||||||
from crazy_functions.vector_fns.general_file_loader import load_file
|
from crazy_functions.vector_fns.general_file_loader import load_file
|
||||||
|
|
||||||
embedding_model_dict = {
|
embedding_model_dict = {
|
||||||
@@ -150,17 +151,17 @@ class LocalDocQA:
|
|||||||
failed_files = []
|
failed_files = []
|
||||||
if isinstance(filepath, str):
|
if isinstance(filepath, str):
|
||||||
if not os.path.exists(filepath):
|
if not os.path.exists(filepath):
|
||||||
print("路径不存在")
|
logger.error("路径不存在")
|
||||||
return None
|
return None
|
||||||
elif os.path.isfile(filepath):
|
elif os.path.isfile(filepath):
|
||||||
file = os.path.split(filepath)[-1]
|
file = os.path.split(filepath)[-1]
|
||||||
try:
|
try:
|
||||||
docs = load_file(filepath, SENTENCE_SIZE)
|
docs = load_file(filepath, SENTENCE_SIZE)
|
||||||
print(f"{file} 已成功加载")
|
logger.info(f"{file} 已成功加载")
|
||||||
loaded_files.append(filepath)
|
loaded_files.append(filepath)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(e)
|
logger.error(e)
|
||||||
print(f"{file} 未能成功加载")
|
logger.error(f"{file} 未能成功加载")
|
||||||
return None
|
return None
|
||||||
elif os.path.isdir(filepath):
|
elif os.path.isdir(filepath):
|
||||||
docs = []
|
docs = []
|
||||||
@@ -170,23 +171,23 @@ class LocalDocQA:
|
|||||||
docs += load_file(fullfilepath, SENTENCE_SIZE)
|
docs += load_file(fullfilepath, SENTENCE_SIZE)
|
||||||
loaded_files.append(fullfilepath)
|
loaded_files.append(fullfilepath)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(e)
|
logger.error(e)
|
||||||
failed_files.append(file)
|
failed_files.append(file)
|
||||||
|
|
||||||
if len(failed_files) > 0:
|
if len(failed_files) > 0:
|
||||||
print("以下文件未能成功加载:")
|
logger.error("以下文件未能成功加载:")
|
||||||
for file in failed_files:
|
for file in failed_files:
|
||||||
print(f"{file}\n")
|
logger.error(f"{file}\n")
|
||||||
|
|
||||||
else:
|
else:
|
||||||
docs = []
|
docs = []
|
||||||
for file in filepath:
|
for file in filepath:
|
||||||
docs += load_file(file, SENTENCE_SIZE)
|
docs += load_file(file, SENTENCE_SIZE)
|
||||||
print(f"{file} 已成功加载")
|
logger.info(f"{file} 已成功加载")
|
||||||
loaded_files.append(file)
|
loaded_files.append(file)
|
||||||
|
|
||||||
if len(docs) > 0:
|
if len(docs) > 0:
|
||||||
print("文件加载完毕,正在生成向量库")
|
logger.info("文件加载完毕,正在生成向量库")
|
||||||
if vs_path and os.path.isdir(vs_path):
|
if vs_path and os.path.isdir(vs_path):
|
||||||
try:
|
try:
|
||||||
self.vector_store = FAISS.load_local(vs_path, text2vec)
|
self.vector_store = FAISS.load_local(vs_path, text2vec)
|
||||||
@@ -233,7 +234,7 @@ class LocalDocQA:
|
|||||||
prompt += "\n\n".join([f"({k}): " + doc.page_content for k, doc in enumerate(related_docs_with_score)])
|
prompt += "\n\n".join([f"({k}): " + doc.page_content for k, doc in enumerate(related_docs_with_score)])
|
||||||
prompt += "\n\n---\n\n"
|
prompt += "\n\n---\n\n"
|
||||||
prompt = prompt.encode('utf-8', 'ignore').decode() # avoid reading non-utf8 chars
|
prompt = prompt.encode('utf-8', 'ignore').decode() # avoid reading non-utf8 chars
|
||||||
# print(prompt)
|
# logger.info(prompt)
|
||||||
response = {"query": query, "source_documents": related_docs_with_score}
|
response = {"query": query, "source_documents": related_docs_with_score}
|
||||||
return response, prompt
|
return response, prompt
|
||||||
|
|
||||||
@@ -262,7 +263,7 @@ def construct_vector_store(vs_id, vs_path, files, sentence_size, history, one_co
|
|||||||
else:
|
else:
|
||||||
pass
|
pass
|
||||||
# file_status = "文件未成功加载,请重新上传文件"
|
# file_status = "文件未成功加载,请重新上传文件"
|
||||||
# print(file_status)
|
# logger.info(file_status)
|
||||||
return local_doc_qa, vs_path
|
return local_doc_qa, vs_path
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
@@ -278,7 +279,7 @@ class knowledge_archive_interface():
|
|||||||
if self.text2vec_large_chinese is None:
|
if self.text2vec_large_chinese is None:
|
||||||
# < -------------------预热文本向量化模组--------------- >
|
# < -------------------预热文本向量化模组--------------- >
|
||||||
from toolbox import ProxyNetworkActivate
|
from toolbox import ProxyNetworkActivate
|
||||||
print('Checking Text2vec ...')
|
logger.info('Checking Text2vec ...')
|
||||||
from langchain.embeddings.huggingface import HuggingFaceEmbeddings
|
from langchain.embeddings.huggingface import HuggingFaceEmbeddings
|
||||||
with ProxyNetworkActivate('Download_LLM'): # 临时地激活代理网络
|
with ProxyNetworkActivate('Download_LLM'): # 临时地激活代理网络
|
||||||
self.text2vec_large_chinese = HuggingFaceEmbeddings(model_name="GanymedeNil/text2vec-large-chinese")
|
self.text2vec_large_chinese = HuggingFaceEmbeddings(model_name="GanymedeNil/text2vec-large-chinese")
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ def read_avail_plugin_enum():
|
|||||||
from crazy_functional import get_crazy_functions
|
from crazy_functional import get_crazy_functions
|
||||||
plugin_arr = get_crazy_functions()
|
plugin_arr = get_crazy_functions()
|
||||||
# remove plugins with out explaination
|
# remove plugins with out explaination
|
||||||
plugin_arr = {k:v for k, v in plugin_arr.items() if 'Info' in v}
|
plugin_arr = {k:v for k, v in plugin_arr.items() if ('Info' in v) and ('Function' in v)}
|
||||||
plugin_arr_info = {"F_{:04d}".format(i):v["Info"] for i, v in enumerate(plugin_arr.values(), start=1)}
|
plugin_arr_info = {"F_{:04d}".format(i):v["Info"] for i, v in enumerate(plugin_arr.values(), start=1)}
|
||||||
plugin_arr_dict = {"F_{:04d}".format(i):v for i, v in enumerate(plugin_arr.values(), start=1)}
|
plugin_arr_dict = {"F_{:04d}".format(i):v for i, v in enumerate(plugin_arr.values(), start=1)}
|
||||||
plugin_arr_dict_parse = {"F_{:04d}".format(i):v for i, v in enumerate(plugin_arr.values(), start=1)}
|
plugin_arr_dict_parse = {"F_{:04d}".format(i):v for i, v in enumerate(plugin_arr.values(), start=1)}
|
||||||
|
|||||||
@@ -1,17 +1,19 @@
|
|||||||
|
import re, requests, unicodedata, os
|
||||||
from toolbox import update_ui, get_log_folder
|
from toolbox import update_ui, get_log_folder
|
||||||
from toolbox import write_history_to_file, promote_file_to_downloadzone
|
from toolbox import write_history_to_file, promote_file_to_downloadzone
|
||||||
from toolbox import CatchException, report_exception, get_conf
|
from toolbox import CatchException, report_exception, get_conf
|
||||||
import re, requests, unicodedata, os
|
from crazy_functions.crazy_utils import request_gpt_model_in_new_thread_with_ui_alive
|
||||||
from .crazy_utils import request_gpt_model_in_new_thread_with_ui_alive
|
from loguru import logger
|
||||||
|
|
||||||
def download_arxiv_(url_pdf):
|
def download_arxiv_(url_pdf):
|
||||||
if 'arxiv.org' not in url_pdf:
|
if 'arxiv.org' not in url_pdf:
|
||||||
if ('.' in url_pdf) and ('/' not in url_pdf):
|
if ('.' in url_pdf) and ('/' not in url_pdf):
|
||||||
new_url = 'https://arxiv.org/abs/'+url_pdf
|
new_url = 'https://arxiv.org/abs/'+url_pdf
|
||||||
print('下载编号:', url_pdf, '自动定位:', new_url)
|
logger.info('下载编号:', url_pdf, '自动定位:', new_url)
|
||||||
# download_arxiv_(new_url)
|
# download_arxiv_(new_url)
|
||||||
return download_arxiv_(new_url)
|
return download_arxiv_(new_url)
|
||||||
else:
|
else:
|
||||||
print('不能识别的URL!')
|
logger.info('不能识别的URL!')
|
||||||
return None
|
return None
|
||||||
if 'abs' in url_pdf:
|
if 'abs' in url_pdf:
|
||||||
url_pdf = url_pdf.replace('abs', 'pdf')
|
url_pdf = url_pdf.replace('abs', 'pdf')
|
||||||
@@ -42,15 +44,12 @@ def download_arxiv_(url_pdf):
|
|||||||
requests_pdf_url = url_pdf
|
requests_pdf_url = url_pdf
|
||||||
file_path = download_dir+title_str
|
file_path = download_dir+title_str
|
||||||
|
|
||||||
print('下载中')
|
logger.info('下载中')
|
||||||
proxies = get_conf('proxies')
|
proxies = get_conf('proxies')
|
||||||
r = requests.get(requests_pdf_url, proxies=proxies)
|
r = requests.get(requests_pdf_url, proxies=proxies)
|
||||||
with open(file_path, 'wb+') as f:
|
with open(file_path, 'wb+') as f:
|
||||||
f.write(r.content)
|
f.write(r.content)
|
||||||
print('下载完成')
|
logger.info('下载完成')
|
||||||
|
|
||||||
# print('输出下载命令:','aria2c -o \"%s\" %s'%(title_str,url_pdf))
|
|
||||||
# subprocess.call('aria2c --all-proxy=\"172.18.116.150:11084\" -o \"%s\" %s'%(download_dir+title_str,url_pdf), shell=True)
|
|
||||||
|
|
||||||
x = "%s %s %s.bib" % (paper_id, other_info['year'], other_info['authors'])
|
x = "%s %s %s.bib" % (paper_id, other_info['year'], other_info['authors'])
|
||||||
x = x.replace('?', '?')\
|
x = x.replace('?', '?')\
|
||||||
@@ -63,19 +62,9 @@ def download_arxiv_(url_pdf):
|
|||||||
|
|
||||||
|
|
||||||
def get_name(_url_):
|
def get_name(_url_):
|
||||||
import os
|
|
||||||
from bs4 import BeautifulSoup
|
from bs4 import BeautifulSoup
|
||||||
print('正在获取文献名!')
|
logger.info('正在获取文献名!')
|
||||||
print(_url_)
|
logger.info(_url_)
|
||||||
|
|
||||||
# arxiv_recall = {}
|
|
||||||
# if os.path.exists('./arxiv_recall.pkl'):
|
|
||||||
# with open('./arxiv_recall.pkl', 'rb') as f:
|
|
||||||
# arxiv_recall = pickle.load(f)
|
|
||||||
|
|
||||||
# if _url_ in arxiv_recall:
|
|
||||||
# print('在缓存中')
|
|
||||||
# return arxiv_recall[_url_]
|
|
||||||
|
|
||||||
proxies = get_conf('proxies')
|
proxies = get_conf('proxies')
|
||||||
res = requests.get(_url_, proxies=proxies)
|
res = requests.get(_url_, proxies=proxies)
|
||||||
@@ -92,7 +81,7 @@ def get_name(_url_):
|
|||||||
other_details['abstract'] = abstract
|
other_details['abstract'] = abstract
|
||||||
except:
|
except:
|
||||||
other_details['year'] = ''
|
other_details['year'] = ''
|
||||||
print('年份获取失败')
|
logger.info('年份获取失败')
|
||||||
|
|
||||||
# get author
|
# get author
|
||||||
try:
|
try:
|
||||||
@@ -101,7 +90,7 @@ def get_name(_url_):
|
|||||||
other_details['authors'] = authors
|
other_details['authors'] = authors
|
||||||
except:
|
except:
|
||||||
other_details['authors'] = ''
|
other_details['authors'] = ''
|
||||||
print('authors获取失败')
|
logger.info('authors获取失败')
|
||||||
|
|
||||||
# get comment
|
# get comment
|
||||||
try:
|
try:
|
||||||
@@ -116,11 +105,11 @@ def get_name(_url_):
|
|||||||
other_details['comment'] = ''
|
other_details['comment'] = ''
|
||||||
except:
|
except:
|
||||||
other_details['comment'] = ''
|
other_details['comment'] = ''
|
||||||
print('年份获取失败')
|
logger.info('年份获取失败')
|
||||||
|
|
||||||
title_str = BeautifulSoup(
|
title_str = BeautifulSoup(
|
||||||
res.text, 'html.parser').find('title').contents[0]
|
res.text, 'html.parser').find('title').contents[0]
|
||||||
print('获取成功:', title_str)
|
logger.info('获取成功:', title_str)
|
||||||
# arxiv_recall[_url_] = (title_str+'.pdf', other_details)
|
# arxiv_recall[_url_] = (title_str+'.pdf', other_details)
|
||||||
# with open('./arxiv_recall.pkl', 'wb') as f:
|
# with open('./arxiv_recall.pkl', 'wb') as f:
|
||||||
# pickle.dump(arxiv_recall, f)
|
# pickle.dump(arxiv_recall, f)
|
||||||
@@ -130,7 +119,7 @@ def get_name(_url_):
|
|||||||
|
|
||||||
|
|
||||||
@CatchException
|
@CatchException
|
||||||
def 下载arxiv论文并翻译摘要(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port):
|
def 下载arxiv论文并翻译摘要(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request):
|
||||||
|
|
||||||
CRAZY_FUNCTION_INFO = "下载arxiv论文并翻译摘要,函数插件作者[binary-husky]。正在提取摘要并下载PDF文档……"
|
CRAZY_FUNCTION_INFO = "下载arxiv论文并翻译摘要,函数插件作者[binary-husky]。正在提取摘要并下载PDF文档……"
|
||||||
import glob
|
import glob
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ from request_llms.bridge_all import predict_no_ui_long_connection
|
|||||||
from crazy_functions.game_fns.game_utils import get_code_block, is_same_thing
|
from crazy_functions.game_fns.game_utils import get_code_block, is_same_thing
|
||||||
|
|
||||||
@CatchException
|
@CatchException
|
||||||
def 随机小游戏(prompt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port):
|
def 随机小游戏(prompt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request):
|
||||||
from crazy_functions.game_fns.game_interactive_story import MiniGame_ResumeStory
|
from crazy_functions.game_fns.game_interactive_story import MiniGame_ResumeStory
|
||||||
# 清空历史
|
# 清空历史
|
||||||
history = []
|
history = []
|
||||||
@@ -23,7 +23,7 @@ def 随机小游戏(prompt, llm_kwargs, plugin_kwargs, chatbot, history, system_
|
|||||||
|
|
||||||
|
|
||||||
@CatchException
|
@CatchException
|
||||||
def 随机小游戏1(prompt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port):
|
def 随机小游戏1(prompt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request):
|
||||||
from crazy_functions.game_fns.game_ascii_art import MiniGame_ASCII_Art
|
from crazy_functions.game_fns.game_ascii_art import MiniGame_ASCII_Art
|
||||||
# 清空历史
|
# 清空历史
|
||||||
history = []
|
history = []
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
from toolbox import CatchException, update_ui
|
from toolbox import CatchException, update_ui
|
||||||
from .crazy_utils import request_gpt_model_in_new_thread_with_ui_alive
|
from crazy_functions.crazy_utils import request_gpt_model_in_new_thread_with_ui_alive
|
||||||
|
|
||||||
|
|
||||||
@CatchException
|
@CatchException
|
||||||
def 交互功能模板函数(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port):
|
def 交互功能模板函数(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request):
|
||||||
"""
|
"""
|
||||||
txt 输入栏用户输入的文本,例如需要翻译的一段话,再例如一个包含了待处理文件的路径
|
txt 输入栏用户输入的文本,例如需要翻译的一段话,再例如一个包含了待处理文件的路径
|
||||||
llm_kwargs gpt模型参数, 如温度和top_p等, 一般原样传递下去就行
|
llm_kwargs gpt模型参数, 如温度和top_p等, 一般原样传递下去就行
|
||||||
@@ -11,7 +10,7 @@ def 交互功能模板函数(txt, llm_kwargs, plugin_kwargs, chatbot, history, s
|
|||||||
chatbot 聊天显示框的句柄,用于显示给用户
|
chatbot 聊天显示框的句柄,用于显示给用户
|
||||||
history 聊天历史,前情提要
|
history 聊天历史,前情提要
|
||||||
system_prompt 给gpt的静默提醒
|
system_prompt 给gpt的静默提醒
|
||||||
web_port 当前软件运行的端口号
|
user_request 当前用户的请求信息(IP地址等)
|
||||||
"""
|
"""
|
||||||
history = [] # 清空历史,以免输入溢出
|
history = [] # 清空历史,以免输入溢出
|
||||||
chatbot.append(("这是什么功能?", "交互功能函数模板。在执行完成之后, 可以将自身的状态存储到cookie中, 等待用户的再次调用。"))
|
chatbot.append(("这是什么功能?", "交互功能函数模板。在执行完成之后, 可以将自身的状态存储到cookie中, 等待用户的再次调用。"))
|
||||||
|
|||||||
@@ -16,8 +16,8 @@ Testing:
|
|||||||
|
|
||||||
from toolbox import CatchException, update_ui, gen_time_str, trimmed_format_exc, is_the_upload_folder
|
from toolbox import CatchException, update_ui, gen_time_str, trimmed_format_exc, is_the_upload_folder
|
||||||
from toolbox import promote_file_to_downloadzone, get_log_folder, update_ui_lastest_msg
|
from toolbox import promote_file_to_downloadzone, get_log_folder, update_ui_lastest_msg
|
||||||
from .crazy_utils import request_gpt_model_in_new_thread_with_ui_alive, get_plugin_arg
|
from crazy_functions.crazy_utils import request_gpt_model_in_new_thread_with_ui_alive, get_plugin_arg
|
||||||
from .crazy_utils import input_clipping, try_install_deps
|
from crazy_functions.crazy_utils import input_clipping, try_install_deps
|
||||||
from crazy_functions.gen_fns.gen_fns_shared import is_function_successfully_generated
|
from crazy_functions.gen_fns.gen_fns_shared import is_function_successfully_generated
|
||||||
from crazy_functions.gen_fns.gen_fns_shared import get_class_name
|
from crazy_functions.gen_fns.gen_fns_shared import get_class_name
|
||||||
from crazy_functions.gen_fns.gen_fns_shared import subprocess_worker
|
from crazy_functions.gen_fns.gen_fns_shared import subprocess_worker
|
||||||
@@ -139,7 +139,7 @@ def get_recent_file_prompt_support(chatbot):
|
|||||||
return path
|
return path
|
||||||
|
|
||||||
@CatchException
|
@CatchException
|
||||||
def 函数动态生成(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port):
|
def 函数动态生成(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request):
|
||||||
"""
|
"""
|
||||||
txt 输入栏用户输入的文本,例如需要翻译的一段话,再例如一个包含了待处理文件的路径
|
txt 输入栏用户输入的文本,例如需要翻译的一段话,再例如一个包含了待处理文件的路径
|
||||||
llm_kwargs gpt模型参数,如温度和top_p等,一般原样传递下去就行
|
llm_kwargs gpt模型参数,如温度和top_p等,一般原样传递下去就行
|
||||||
@@ -147,7 +147,7 @@ def 函数动态生成(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_
|
|||||||
chatbot 聊天显示框的句柄,用于显示给用户
|
chatbot 聊天显示框的句柄,用于显示给用户
|
||||||
history 聊天历史,前情提要
|
history 聊天历史,前情提要
|
||||||
system_prompt 给gpt的静默提醒
|
system_prompt 给gpt的静默提醒
|
||||||
web_port 当前软件运行的端口号
|
user_request 当前用户的请求信息(IP地址等)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# 清空历史
|
# 清空历史
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
from toolbox import CatchException, update_ui, gen_time_str
|
from toolbox import CatchException, update_ui, gen_time_str
|
||||||
from .crazy_utils import request_gpt_model_in_new_thread_with_ui_alive
|
from crazy_functions.crazy_utils import request_gpt_model_in_new_thread_with_ui_alive
|
||||||
from .crazy_utils import input_clipping
|
from crazy_functions.crazy_utils import input_clipping
|
||||||
import copy, json
|
import copy, json
|
||||||
|
|
||||||
@CatchException
|
@CatchException
|
||||||
def 命令行助手(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port):
|
def 命令行助手(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request):
|
||||||
"""
|
"""
|
||||||
txt 输入栏用户输入的文本, 例如需要翻译的一段话, 再例如一个包含了待处理文件的路径
|
txt 输入栏用户输入的文本, 例如需要翻译的一段话, 再例如一个包含了待处理文件的路径
|
||||||
llm_kwargs gpt模型参数, 如温度和top_p等, 一般原样传递下去就行
|
llm_kwargs gpt模型参数, 如温度和top_p等, 一般原样传递下去就行
|
||||||
@@ -12,7 +12,7 @@ def 命令行助手(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_pro
|
|||||||
chatbot 聊天显示框的句柄, 用于显示给用户
|
chatbot 聊天显示框的句柄, 用于显示给用户
|
||||||
history 聊天历史, 前情提要
|
history 聊天历史, 前情提要
|
||||||
system_prompt 给gpt的静默提醒
|
system_prompt 给gpt的静默提醒
|
||||||
web_port 当前软件运行的端口号
|
user_request 当前用户的请求信息(IP地址等)
|
||||||
"""
|
"""
|
||||||
# 清空历史, 以免输入溢出
|
# 清空历史, 以免输入溢出
|
||||||
history = []
|
history = []
|
||||||
|
|||||||
@@ -6,13 +6,14 @@
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
import time
|
||||||
from toolbox import CatchException, update_ui, gen_time_str, trimmed_format_exc, ProxyNetworkActivate
|
from toolbox import CatchException, update_ui, gen_time_str, trimmed_format_exc, ProxyNetworkActivate
|
||||||
from toolbox import get_conf, select_api_key, update_ui_lastest_msg, Singleton
|
from toolbox import get_conf, select_api_key, update_ui_lastest_msg, Singleton
|
||||||
from crazy_functions.crazy_utils import request_gpt_model_in_new_thread_with_ui_alive, get_plugin_arg
|
from crazy_functions.crazy_utils import request_gpt_model_in_new_thread_with_ui_alive, get_plugin_arg
|
||||||
from crazy_functions.crazy_utils import input_clipping, try_install_deps
|
from crazy_functions.crazy_utils import input_clipping, try_install_deps
|
||||||
from crazy_functions.agent_fns.persistent import GradioMultiuserManagerForPersistentClasses
|
from crazy_functions.agent_fns.persistent import GradioMultiuserManagerForPersistentClasses
|
||||||
from crazy_functions.agent_fns.auto_agent import AutoGenMath
|
from crazy_functions.agent_fns.auto_agent import AutoGenMath
|
||||||
import time
|
from loguru import logger
|
||||||
|
|
||||||
def remove_model_prefix(llm):
|
def remove_model_prefix(llm):
|
||||||
if llm.startswith('api2d-'): llm = llm.replace('api2d-', '')
|
if llm.startswith('api2d-'): llm = llm.replace('api2d-', '')
|
||||||
@@ -21,7 +22,7 @@ def remove_model_prefix(llm):
|
|||||||
|
|
||||||
|
|
||||||
@CatchException
|
@CatchException
|
||||||
def 多智能体终端(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port):
|
def 多智能体终端(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request):
|
||||||
"""
|
"""
|
||||||
txt 输入栏用户输入的文本,例如需要翻译的一段话,再例如一个包含了待处理文件的路径
|
txt 输入栏用户输入的文本,例如需要翻译的一段话,再例如一个包含了待处理文件的路径
|
||||||
llm_kwargs gpt模型参数,如温度和top_p等,一般原样传递下去就行
|
llm_kwargs gpt模型参数,如温度和top_p等,一般原样传递下去就行
|
||||||
@@ -29,7 +30,7 @@ def 多智能体终端(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_
|
|||||||
chatbot 聊天显示框的句柄,用于显示给用户
|
chatbot 聊天显示框的句柄,用于显示给用户
|
||||||
history 聊天历史,前情提要
|
history 聊天历史,前情提要
|
||||||
system_prompt 给gpt的静默提醒
|
system_prompt 给gpt的静默提醒
|
||||||
web_port 当前软件运行的端口号
|
user_request 当前用户的请求信息(IP地址等)
|
||||||
"""
|
"""
|
||||||
# 检查当前的模型是否符合要求
|
# 检查当前的模型是否符合要求
|
||||||
supported_llms = [
|
supported_llms = [
|
||||||
@@ -51,13 +52,6 @@ def 多智能体终端(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_
|
|||||||
if model_info[llm_kwargs['llm_model']]["endpoint"] is not None: # 如果不是本地模型,加载API_KEY
|
if model_info[llm_kwargs['llm_model']]["endpoint"] is not None: # 如果不是本地模型,加载API_KEY
|
||||||
llm_kwargs['api_key'] = select_api_key(llm_kwargs['api_key'], llm_kwargs['llm_model'])
|
llm_kwargs['api_key'] = select_api_key(llm_kwargs['api_key'], llm_kwargs['llm_model'])
|
||||||
|
|
||||||
# 检查当前的模型是否符合要求
|
|
||||||
API_URL_REDIRECT = get_conf('API_URL_REDIRECT')
|
|
||||||
if len(API_URL_REDIRECT) > 0:
|
|
||||||
chatbot.append([f"处理任务: {txt}", f"暂不支持中转."])
|
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
|
||||||
return
|
|
||||||
|
|
||||||
# 尝试导入依赖,如果缺少依赖,则给出安装建议
|
# 尝试导入依赖,如果缺少依赖,则给出安装建议
|
||||||
try:
|
try:
|
||||||
import autogen
|
import autogen
|
||||||
@@ -87,16 +81,16 @@ def 多智能体终端(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_
|
|||||||
persistent_key = f"{user_uuid}->多智能体终端"
|
persistent_key = f"{user_uuid}->多智能体终端"
|
||||||
if persistent_class_multi_user_manager.already_alive(persistent_key):
|
if persistent_class_multi_user_manager.already_alive(persistent_key):
|
||||||
# 当已经存在一个正在运行的多智能体终端时,直接将用户输入传递给它,而不是再次启动一个新的多智能体终端
|
# 当已经存在一个正在运行的多智能体终端时,直接将用户输入传递给它,而不是再次启动一个新的多智能体终端
|
||||||
print('[debug] feed new user input')
|
logger.info('[debug] feed new user input')
|
||||||
executor = persistent_class_multi_user_manager.get(persistent_key)
|
executor = persistent_class_multi_user_manager.get(persistent_key)
|
||||||
exit_reason = yield from executor.main_process_ui_control(txt, create_or_resume="resume")
|
exit_reason = yield from executor.main_process_ui_control(txt, create_or_resume="resume")
|
||||||
else:
|
else:
|
||||||
# 运行多智能体终端 (首次)
|
# 运行多智能体终端 (首次)
|
||||||
print('[debug] create new executor instance')
|
logger.info('[debug] create new executor instance')
|
||||||
history = []
|
history = []
|
||||||
chatbot.append(["正在启动: 多智能体终端", "插件动态生成, 执行开始, 作者 Microsoft & Binary-Husky."])
|
chatbot.append(["正在启动: 多智能体终端", "插件动态生成, 执行开始, 作者 Microsoft & Binary-Husky."])
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
||||||
executor = AutoGenMath(llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port)
|
executor = AutoGenMath(llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request)
|
||||||
persistent_class_multi_user_manager.set(persistent_key, executor)
|
persistent_class_multi_user_manager.set(persistent_key, executor)
|
||||||
exit_reason = yield from executor.main_process_ui_control(txt, create_or_resume="create")
|
exit_reason = yield from executor.main_process_ui_control(txt, create_or_resume="create")
|
||||||
|
|
||||||
|
|||||||
@@ -1,152 +0,0 @@
|
|||||||
from toolbox import CatchException, update_ui, promote_file_to_downloadzone, get_log_folder, get_user
|
|
||||||
import re
|
|
||||||
|
|
||||||
f_prefix = 'GPT-Academic对话存档'
|
|
||||||
|
|
||||||
def write_chat_to_file(chatbot, history=None, file_name=None):
|
|
||||||
"""
|
|
||||||
将对话记录history以Markdown格式写入文件中。如果没有指定文件名,则使用当前时间生成文件名。
|
|
||||||
"""
|
|
||||||
import os
|
|
||||||
import time
|
|
||||||
if file_name is None:
|
|
||||||
file_name = f_prefix + time.strftime("%Y-%m-%d-%H-%M-%S", time.localtime()) + '.html'
|
|
||||||
fp = os.path.join(get_log_folder(get_user(chatbot), plugin_name='chat_history'), file_name)
|
|
||||||
with open(fp, 'w', encoding='utf8') as f:
|
|
||||||
from themes.theme import advanced_css
|
|
||||||
f.write(f'<!DOCTYPE html><head><meta charset="utf-8"><title>对话历史</title><style>{advanced_css}</style></head>')
|
|
||||||
for i, contents in enumerate(chatbot):
|
|
||||||
for j, content in enumerate(contents):
|
|
||||||
try: # 这个bug没找到触发条件,暂时先这样顶一下
|
|
||||||
if type(content) != str: content = str(content)
|
|
||||||
except:
|
|
||||||
continue
|
|
||||||
f.write(content)
|
|
||||||
if j == 0:
|
|
||||||
f.write('<hr style="border-top: dotted 3px #ccc;">')
|
|
||||||
f.write('<hr color="red"> \n\n')
|
|
||||||
f.write('<hr color="blue"> \n\n raw chat context:\n')
|
|
||||||
f.write('<code>')
|
|
||||||
for h in history:
|
|
||||||
f.write("\n>>>" + h)
|
|
||||||
f.write('</code>')
|
|
||||||
promote_file_to_downloadzone(fp, rename_file=file_name, chatbot=chatbot)
|
|
||||||
return '对话历史写入:' + fp
|
|
||||||
|
|
||||||
def gen_file_preview(file_name):
|
|
||||||
try:
|
|
||||||
with open(file_name, 'r', encoding='utf8') as f:
|
|
||||||
file_content = f.read()
|
|
||||||
# pattern to match the text between <head> and </head>
|
|
||||||
pattern = re.compile(r'<head>.*?</head>', flags=re.DOTALL)
|
|
||||||
file_content = re.sub(pattern, '', file_content)
|
|
||||||
html, history = file_content.split('<hr color="blue"> \n\n raw chat context:\n')
|
|
||||||
history = history.strip('<code>')
|
|
||||||
history = history.strip('</code>')
|
|
||||||
history = history.split("\n>>>")
|
|
||||||
return list(filter(lambda x:x!="", history))[0][:100]
|
|
||||||
except:
|
|
||||||
return ""
|
|
||||||
|
|
||||||
def read_file_to_chat(chatbot, history, file_name):
|
|
||||||
with open(file_name, 'r', encoding='utf8') as f:
|
|
||||||
file_content = f.read()
|
|
||||||
# pattern to match the text between <head> and </head>
|
|
||||||
pattern = re.compile(r'<head>.*?</head>', flags=re.DOTALL)
|
|
||||||
file_content = re.sub(pattern, '', file_content)
|
|
||||||
html, history = file_content.split('<hr color="blue"> \n\n raw chat context:\n')
|
|
||||||
history = history.strip('<code>')
|
|
||||||
history = history.strip('</code>')
|
|
||||||
history = history.split("\n>>>")
|
|
||||||
history = list(filter(lambda x:x!="", history))
|
|
||||||
html = html.split('<hr color="red"> \n\n')
|
|
||||||
html = list(filter(lambda x:x!="", html))
|
|
||||||
chatbot.clear()
|
|
||||||
for i, h in enumerate(html):
|
|
||||||
i_say, gpt_say = h.split('<hr style="border-top: dotted 3px #ccc;">')
|
|
||||||
chatbot.append([i_say, gpt_say])
|
|
||||||
chatbot.append([f"存档文件详情?", f"[Local Message] 载入对话{len(html)}条,上下文{len(history)}条。"])
|
|
||||||
return chatbot, history
|
|
||||||
|
|
||||||
@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 当前软件运行的端口号
|
|
||||||
"""
|
|
||||||
|
|
||||||
chatbot.append(("保存当前对话",
|
|
||||||
f"[Local Message] {write_chat_to_file(chatbot, history)},您可以调用下拉菜单中的“载入对话历史存档”还原当下的对话。"))
|
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 # 由于请求gpt需要一段时间,我们先及时地做一次界面更新
|
|
||||||
|
|
||||||
def hide_cwd(str):
|
|
||||||
import os
|
|
||||||
current_path = os.getcwd()
|
|
||||||
replace_path = "."
|
|
||||||
return str.replace(current_path, replace_path)
|
|
||||||
|
|
||||||
@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 .crazy_utils import get_files_from_everything
|
|
||||||
success, file_manifest, _ = get_files_from_everything(txt, type='.html')
|
|
||||||
|
|
||||||
if not success:
|
|
||||||
if txt == "": txt = '空空如也的输入栏'
|
|
||||||
import glob
|
|
||||||
local_history = "<br/>".join([
|
|
||||||
"`"+hide_cwd(f)+f" ({gen_file_preview(f)})"+"`"
|
|
||||||
for f in glob.glob(
|
|
||||||
f'{get_log_folder(get_user(chatbot), plugin_name="chat_history")}/**/{f_prefix}*.html',
|
|
||||||
recursive=True
|
|
||||||
)])
|
|
||||||
chatbot.append([f"正在查找对话历史文件(html格式): {txt}", f"找不到任何html文件: {txt}。但本地存储了以下历史文件,您可以将任意一个文件路径粘贴到输入区,然后重试:<br/>{local_history}"])
|
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
|
||||||
return
|
|
||||||
|
|
||||||
try:
|
|
||||||
chatbot, history = read_file_to_chat(chatbot, history, file_manifest[0])
|
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
|
||||||
except:
|
|
||||||
chatbot.append([f"载入对话历史文件", f"对话历史文件损坏!"])
|
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
|
||||||
return
|
|
||||||
|
|
||||||
@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 当前软件运行的端口号
|
|
||||||
"""
|
|
||||||
|
|
||||||
import glob, os
|
|
||||||
local_history = "<br/>".join([
|
|
||||||
"`"+hide_cwd(f)+"`"
|
|
||||||
for f in glob.glob(
|
|
||||||
f'{get_log_folder(get_user(chatbot), plugin_name="chat_history")}/**/{f_prefix}*.html', recursive=True
|
|
||||||
)])
|
|
||||||
for f in glob.glob(f'{get_log_folder(get_user(chatbot), plugin_name="chat_history")}/**/{f_prefix}*.html', recursive=True):
|
|
||||||
os.remove(f)
|
|
||||||
chatbot.append([f"删除所有历史对话文件", f"已删除<br/>{local_history}"])
|
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
|
||||||
return
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,127 +0,0 @@
|
|||||||
from toolbox import update_ui
|
|
||||||
from toolbox import CatchException, report_exception
|
|
||||||
from toolbox import write_history_to_file, promote_file_to_downloadzone
|
|
||||||
from .crazy_utils import request_gpt_model_in_new_thread_with_ui_alive
|
|
||||||
fast_debug = False
|
|
||||||
|
|
||||||
|
|
||||||
def 解析docx(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt):
|
|
||||||
import time, os
|
|
||||||
# pip install python-docx 用于docx格式,跨平台
|
|
||||||
# pip install pywin32 用于doc格式,仅支持Win平台
|
|
||||||
for index, fp in enumerate(file_manifest):
|
|
||||||
if fp.split(".")[-1] == "docx":
|
|
||||||
from docx import Document
|
|
||||||
doc = Document(fp)
|
|
||||||
file_content = "\n".join([para.text for para in doc.paragraphs])
|
|
||||||
else:
|
|
||||||
try:
|
|
||||||
import win32com.client
|
|
||||||
word = win32com.client.Dispatch("Word.Application")
|
|
||||||
word.visible = False
|
|
||||||
# 打开文件
|
|
||||||
doc = word.Documents.Open(os.getcwd() + '/' + fp)
|
|
||||||
# file_content = doc.Content.Text
|
|
||||||
doc = word.ActiveDocument
|
|
||||||
file_content = doc.Range().Text
|
|
||||||
doc.Close()
|
|
||||||
word.Quit()
|
|
||||||
except:
|
|
||||||
raise RuntimeError('请先将.doc文档转换为.docx文档。')
|
|
||||||
|
|
||||||
# private_upload里面的文件名在解压zip后容易出现乱码(rar和7z格式正常),故可以只分析文章内容,不输入文件名
|
|
||||||
from crazy_functions.pdf_fns.breakdown_txt import breakdown_text_to_satisfy_token_limit
|
|
||||||
from request_llms.bridge_all import model_info
|
|
||||||
max_token = model_info[llm_kwargs['llm_model']]['max_token']
|
|
||||||
TOKEN_LIMIT_PER_FRAGMENT = max_token * 3 // 4
|
|
||||||
paper_fragments = breakdown_text_to_satisfy_token_limit(txt=file_content, limit=TOKEN_LIMIT_PER_FRAGMENT, llm_model=llm_kwargs['llm_model'])
|
|
||||||
this_paper_history = []
|
|
||||||
for i, paper_frag in enumerate(paper_fragments):
|
|
||||||
i_say = f'请对下面的文章片段用中文做概述,文件名是{os.path.relpath(fp, project_folder)},文章内容是 ```{paper_frag}```'
|
|
||||||
i_say_show_user = f'请对下面的文章片段做概述: {os.path.abspath(fp)}的第{i+1}/{len(paper_fragments)}个片段。'
|
|
||||||
gpt_say = yield from request_gpt_model_in_new_thread_with_ui_alive(
|
|
||||||
inputs=i_say,
|
|
||||||
inputs_show_user=i_say_show_user,
|
|
||||||
llm_kwargs=llm_kwargs,
|
|
||||||
chatbot=chatbot,
|
|
||||||
history=[],
|
|
||||||
sys_prompt="总结文章。"
|
|
||||||
)
|
|
||||||
|
|
||||||
chatbot[-1] = (i_say_show_user, gpt_say)
|
|
||||||
history.extend([i_say_show_user,gpt_say])
|
|
||||||
this_paper_history.extend([i_say_show_user,gpt_say])
|
|
||||||
|
|
||||||
# 已经对该文章的所有片段总结完毕,如果文章被切分了,
|
|
||||||
if len(paper_fragments) > 1:
|
|
||||||
i_say = f"根据以上的对话,总结文章{os.path.abspath(fp)}的主要内容。"
|
|
||||||
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=this_paper_history,
|
|
||||||
sys_prompt="总结文章。"
|
|
||||||
)
|
|
||||||
|
|
||||||
history.extend([i_say,gpt_say])
|
|
||||||
this_paper_history.extend([i_say,gpt_say])
|
|
||||||
|
|
||||||
res = write_history_to_file(history)
|
|
||||||
promote_file_to_downloadzone(res, chatbot=chatbot)
|
|
||||||
chatbot.append(("完成了吗?", res))
|
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
|
||||||
|
|
||||||
res = write_history_to_file(history)
|
|
||||||
promote_file_to_downloadzone(res, chatbot=chatbot)
|
|
||||||
chatbot.append(("所有文件都总结完成了吗?", res))
|
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
|
||||||
|
|
||||||
|
|
||||||
@CatchException
|
|
||||||
def 总结word文档(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port):
|
|
||||||
import glob, os
|
|
||||||
|
|
||||||
# 基本信息:功能、贡献者
|
|
||||||
chatbot.append([
|
|
||||||
"函数插件功能?",
|
|
||||||
"批量总结Word文档。函数插件贡献者: JasonGuo1。注意, 如果是.doc文件, 请先转化为.docx格式。"])
|
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
|
||||||
|
|
||||||
# 尝试导入依赖,如果缺少依赖,则给出安装建议
|
|
||||||
try:
|
|
||||||
from docx import Document
|
|
||||||
except:
|
|
||||||
report_exception(chatbot, history,
|
|
||||||
a=f"解析项目: {txt}",
|
|
||||||
b=f"导入软件依赖失败。使用该模块需要额外依赖,安装方法```pip install --upgrade python-docx pywin32```。")
|
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
|
||||||
return
|
|
||||||
|
|
||||||
# 清空历史,以免输入溢出
|
|
||||||
history = []
|
|
||||||
|
|
||||||
# 检测输入参数,如没有给定输入参数,直接退出
|
|
||||||
if os.path.exists(txt):
|
|
||||||
project_folder = txt
|
|
||||||
else:
|
|
||||||
if txt == "": txt = '空空如也的输入栏'
|
|
||||||
report_exception(chatbot, history, a=f"解析项目: {txt}", b=f"找不到本地项目或无权访问: {txt}")
|
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
|
||||||
return
|
|
||||||
|
|
||||||
# 搜索需要处理的文件清单
|
|
||||||
if txt.endswith('.docx') or txt.endswith('.doc'):
|
|
||||||
file_manifest = [txt]
|
|
||||||
else:
|
|
||||||
file_manifest = [f for f in glob.glob(f'{project_folder}/**/*.docx', recursive=True)] + \
|
|
||||||
[f for f in glob.glob(f'{project_folder}/**/*.doc', recursive=True)]
|
|
||||||
|
|
||||||
# 如果没找到任何文件
|
|
||||||
if len(file_manifest) == 0:
|
|
||||||
report_exception(chatbot, history, a=f"解析项目: {txt}", b=f"找不到任何.docx或doc文件: {txt}")
|
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
|
||||||
return
|
|
||||||
|
|
||||||
# 开始正式执行任务
|
|
||||||
yield from 解析docx(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt)
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
from toolbox import CatchException, report_exception, select_api_key, update_ui, get_conf
|
from toolbox import CatchException, report_exception, select_api_key, update_ui, get_conf
|
||||||
from .crazy_utils import request_gpt_model_in_new_thread_with_ui_alive
|
from crazy_functions.crazy_utils import request_gpt_model_in_new_thread_with_ui_alive
|
||||||
from toolbox import write_history_to_file, promote_file_to_downloadzone, get_log_folder
|
from toolbox import write_history_to_file, promote_file_to_downloadzone, get_log_folder
|
||||||
|
|
||||||
def split_audio_file(filename, split_duration=1000):
|
def split_audio_file(filename, split_duration=1000):
|
||||||
|
|||||||
@@ -1,16 +1,18 @@
|
|||||||
|
from loguru import logger
|
||||||
|
|
||||||
from toolbox import update_ui, promote_file_to_downloadzone, gen_time_str
|
from toolbox import update_ui, promote_file_to_downloadzone, gen_time_str
|
||||||
from toolbox import CatchException, report_exception
|
from toolbox import CatchException, report_exception
|
||||||
from toolbox import write_history_to_file, promote_file_to_downloadzone
|
from toolbox import write_history_to_file, promote_file_to_downloadzone
|
||||||
from .crazy_utils import request_gpt_model_in_new_thread_with_ui_alive
|
from crazy_functions.crazy_utils import request_gpt_model_in_new_thread_with_ui_alive
|
||||||
from .crazy_utils import read_and_clean_pdf_text
|
from crazy_functions.crazy_utils import read_and_clean_pdf_text
|
||||||
from .crazy_utils import input_clipping
|
from crazy_functions.crazy_utils import input_clipping
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def 解析PDF(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt):
|
def 解析PDF(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt):
|
||||||
file_write_buffer = []
|
file_write_buffer = []
|
||||||
for file_name in file_manifest:
|
for file_name in file_manifest:
|
||||||
print('begin analysis on:', file_name)
|
logger.info('begin analysis on:', file_name)
|
||||||
############################## <第 0 步,切割PDF> ##################################
|
############################## <第 0 步,切割PDF> ##################################
|
||||||
# 递归地切割PDF文件,每一块(尽量是完整的一个section,比如introduction,experiment等,必要时再进行切割)
|
# 递归地切割PDF文件,每一块(尽量是完整的一个section,比如introduction,experiment等,必要时再进行切割)
|
||||||
# 的长度必须小于 2500 个 Token
|
# 的长度必须小于 2500 个 Token
|
||||||
@@ -38,7 +40,7 @@ def 解析PDF(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot,
|
|||||||
last_iteration_result = paper_meta # 初始值是摘要
|
last_iteration_result = paper_meta # 初始值是摘要
|
||||||
MAX_WORD_TOTAL = 4096 * 0.7
|
MAX_WORD_TOTAL = 4096 * 0.7
|
||||||
n_fragment = len(paper_fragments)
|
n_fragment = len(paper_fragments)
|
||||||
if n_fragment >= 20: print('文章极长,不能达到预期效果')
|
if n_fragment >= 20: logger.warning('文章极长,不能达到预期效果')
|
||||||
for i in range(n_fragment):
|
for i in range(n_fragment):
|
||||||
NUM_OF_WORD = MAX_WORD_TOTAL // n_fragment
|
NUM_OF_WORD = MAX_WORD_TOTAL // n_fragment
|
||||||
i_say = f"Read this section, recapitulate the content of this section with less than {NUM_OF_WORD} Chinese characters: {paper_fragments[i]}"
|
i_say = f"Read this section, recapitulate the content of this section with less than {NUM_OF_WORD} Chinese characters: {paper_fragments[i]}"
|
||||||
@@ -101,7 +103,7 @@ do not have too much repetitive information, numerical values using the original
|
|||||||
|
|
||||||
|
|
||||||
@CatchException
|
@CatchException
|
||||||
def 批量总结PDF文档(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port):
|
def 批量总结PDF文档(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request):
|
||||||
import glob, os
|
import glob, os
|
||||||
|
|
||||||
# 基本信息:功能、贡献者
|
# 基本信息:功能、贡献者
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
|
from loguru import logger
|
||||||
from toolbox import update_ui
|
from toolbox import update_ui
|
||||||
from toolbox import CatchException, report_exception
|
from toolbox import CatchException, report_exception
|
||||||
from .crazy_utils import request_gpt_model_in_new_thread_with_ui_alive
|
from crazy_functions.crazy_utils import request_gpt_model_in_new_thread_with_ui_alive
|
||||||
from toolbox import write_history_to_file, promote_file_to_downloadzone
|
from toolbox import write_history_to_file, promote_file_to_downloadzone
|
||||||
|
|
||||||
fast_debug = False
|
fast_debug = False
|
||||||
@@ -57,7 +58,6 @@ def readPdf(pdfPath):
|
|||||||
layout = device.get_result()
|
layout = device.get_result()
|
||||||
for obj in layout._objs:
|
for obj in layout._objs:
|
||||||
if isinstance(obj, pdfminer.layout.LTTextBoxHorizontal):
|
if isinstance(obj, pdfminer.layout.LTTextBoxHorizontal):
|
||||||
# print(obj.get_text())
|
|
||||||
outTextList.append(obj.get_text())
|
outTextList.append(obj.get_text())
|
||||||
|
|
||||||
return outTextList
|
return outTextList
|
||||||
@@ -66,7 +66,7 @@ def readPdf(pdfPath):
|
|||||||
def 解析Paper(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt):
|
def 解析Paper(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt):
|
||||||
import time, glob, os
|
import time, glob, os
|
||||||
from bs4 import BeautifulSoup
|
from bs4 import BeautifulSoup
|
||||||
print('begin analysis on:', file_manifest)
|
logger.info('begin analysis on:', file_manifest)
|
||||||
for index, fp in enumerate(file_manifest):
|
for index, fp in enumerate(file_manifest):
|
||||||
if ".tex" in fp:
|
if ".tex" in fp:
|
||||||
with open(fp, 'r', encoding='utf-8', errors='replace') as f:
|
with open(fp, 'r', encoding='utf-8', errors='replace') as f:
|
||||||
@@ -77,7 +77,7 @@ def 解析Paper(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbo
|
|||||||
|
|
||||||
prefix = "接下来请你逐文件分析下面的论文文件,概括其内容" if index==0 else ""
|
prefix = "接下来请你逐文件分析下面的论文文件,概括其内容" if index==0 else ""
|
||||||
i_say = prefix + f'请对下面的文章片段用中文做一个概述,文件名是{os.path.relpath(fp, project_folder)},文章内容是 ```{file_content}```'
|
i_say = prefix + f'请对下面的文章片段用中文做一个概述,文件名是{os.path.relpath(fp, project_folder)},文章内容是 ```{file_content}```'
|
||||||
i_say_show_user = prefix + f'[{index}/{len(file_manifest)}] 请对下面的文章片段做一个概述: {os.path.abspath(fp)}'
|
i_say_show_user = prefix + f'[{index+1}/{len(file_manifest)}] 请对下面的文章片段做一个概述: {os.path.abspath(fp)}'
|
||||||
chatbot.append((i_say_show_user, "[Local Message] waiting gpt response."))
|
chatbot.append((i_say_show_user, "[Local Message] waiting gpt response."))
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
||||||
|
|
||||||
@@ -124,7 +124,7 @@ def 解析Paper(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbo
|
|||||||
|
|
||||||
|
|
||||||
@CatchException
|
@CatchException
|
||||||
def 批量总结PDF文档pdfminer(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port):
|
def 批量总结PDF文档pdfminer(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request):
|
||||||
history = [] # 清空历史,以免输入溢出
|
history = [] # 清空历史,以免输入溢出
|
||||||
import glob, os
|
import glob, os
|
||||||
|
|
||||||
|
|||||||
496
crazy_functions/批量文件询问.py
普通文件
496
crazy_functions/批量文件询问.py
普通文件
@@ -0,0 +1,496 @@
|
|||||||
|
import os
|
||||||
|
import threading
|
||||||
|
import time
|
||||||
|
from dataclasses import dataclass
|
||||||
|
from typing import List, Tuple, Dict, Generator
|
||||||
|
|
||||||
|
from crazy_functions.crazy_utils import request_gpt_model_multi_threads_with_very_awesome_ui_and_high_efficiency
|
||||||
|
from crazy_functions.pdf_fns.breakdown_txt import breakdown_text_to_satisfy_token_limit
|
||||||
|
from crazy_functions.rag_fns.rag_file_support import extract_text
|
||||||
|
from request_llms.bridge_all import model_info
|
||||||
|
from toolbox import update_ui, CatchException, report_exception
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class FileFragment:
|
||||||
|
"""文件片段数据类,用于组织处理单元"""
|
||||||
|
file_path: str
|
||||||
|
content: str
|
||||||
|
rel_path: str
|
||||||
|
fragment_index: int
|
||||||
|
total_fragments: int
|
||||||
|
|
||||||
|
|
||||||
|
class BatchDocumentSummarizer:
|
||||||
|
"""优化的文档总结器 - 批处理版本"""
|
||||||
|
|
||||||
|
def __init__(self, llm_kwargs: Dict, plugin_kwargs: Dict, chatbot: List, history: List, system_prompt: str):
|
||||||
|
"""初始化总结器"""
|
||||||
|
self.llm_kwargs = llm_kwargs
|
||||||
|
self.plugin_kwargs = plugin_kwargs
|
||||||
|
self.chatbot = chatbot
|
||||||
|
self.history = history
|
||||||
|
self.system_prompt = system_prompt
|
||||||
|
self.failed_files = []
|
||||||
|
self.file_summaries_map = {}
|
||||||
|
|
||||||
|
def _get_token_limit(self) -> int:
|
||||||
|
"""获取模型token限制"""
|
||||||
|
max_token = model_info[self.llm_kwargs['llm_model']]['max_token']
|
||||||
|
return max_token * 3 // 4
|
||||||
|
|
||||||
|
def _create_batch_inputs(self, fragments: List[FileFragment]) -> Tuple[List, List, List]:
|
||||||
|
"""创建批处理输入"""
|
||||||
|
inputs_array = []
|
||||||
|
inputs_show_user_array = []
|
||||||
|
history_array = []
|
||||||
|
|
||||||
|
for frag in fragments:
|
||||||
|
if self.plugin_kwargs.get("advanced_arg"):
|
||||||
|
i_say = (f'请按照用户要求对文件内容进行处理,文件名为{os.path.basename(frag.file_path)},'
|
||||||
|
f'用户要求为:{self.plugin_kwargs["advanced_arg"]}:'
|
||||||
|
f'文件内容是 ```{frag.content}```')
|
||||||
|
i_say_show_user = (f'正在处理 {frag.rel_path} (片段 {frag.fragment_index + 1}/{frag.total_fragments})')
|
||||||
|
else:
|
||||||
|
i_say = (f'请对下面的内容用中文做总结,不超过500字,文件名是{os.path.basename(frag.file_path)},'
|
||||||
|
f'内容是 ```{frag.content}```')
|
||||||
|
i_say_show_user = f'正在处理 {frag.rel_path} (片段 {frag.fragment_index + 1}/{frag.total_fragments})'
|
||||||
|
|
||||||
|
inputs_array.append(i_say)
|
||||||
|
inputs_show_user_array.append(i_say_show_user)
|
||||||
|
history_array.append([])
|
||||||
|
|
||||||
|
return inputs_array, inputs_show_user_array, history_array
|
||||||
|
|
||||||
|
def _process_single_file_with_timeout(self, file_info: Tuple[str, str], mutable_status: List) -> List[FileFragment]:
|
||||||
|
"""包装了超时控制的文件处理函数"""
|
||||||
|
|
||||||
|
def timeout_handler():
|
||||||
|
thread = threading.current_thread()
|
||||||
|
if hasattr(thread, '_timeout_occurred'):
|
||||||
|
thread._timeout_occurred = True
|
||||||
|
|
||||||
|
# 设置超时标记
|
||||||
|
thread = threading.current_thread()
|
||||||
|
thread._timeout_occurred = False
|
||||||
|
|
||||||
|
# 设置超时定时器
|
||||||
|
timer = threading.Timer(self.watch_dog_patience, timeout_handler)
|
||||||
|
timer.start()
|
||||||
|
|
||||||
|
try:
|
||||||
|
fp, project_folder = file_info
|
||||||
|
fragments = []
|
||||||
|
|
||||||
|
# 定期检查是否超时
|
||||||
|
def check_timeout():
|
||||||
|
if hasattr(thread, '_timeout_occurred') and thread._timeout_occurred:
|
||||||
|
raise TimeoutError("处理超时")
|
||||||
|
|
||||||
|
# 更新状态
|
||||||
|
mutable_status[0] = "检查文件大小"
|
||||||
|
mutable_status[1] = time.time()
|
||||||
|
check_timeout()
|
||||||
|
|
||||||
|
# 文件大小检查
|
||||||
|
if os.path.getsize(fp) > self.max_file_size:
|
||||||
|
self.failed_files.append((fp, f"文件过大:超过{self.max_file_size / 1024 / 1024}MB"))
|
||||||
|
mutable_status[2] = "文件过大"
|
||||||
|
return fragments
|
||||||
|
|
||||||
|
check_timeout()
|
||||||
|
|
||||||
|
# 更新状态
|
||||||
|
mutable_status[0] = "提取文件内容"
|
||||||
|
mutable_status[1] = time.time()
|
||||||
|
|
||||||
|
# 提取内容
|
||||||
|
content = extract_text(fp)
|
||||||
|
if content is None:
|
||||||
|
self.failed_files.append((fp, "文件解析失败:不支持的格式或文件损坏"))
|
||||||
|
mutable_status[2] = "格式不支持"
|
||||||
|
return fragments
|
||||||
|
elif not content.strip():
|
||||||
|
self.failed_files.append((fp, "文件内容为空"))
|
||||||
|
mutable_status[2] = "内容为空"
|
||||||
|
return fragments
|
||||||
|
|
||||||
|
check_timeout()
|
||||||
|
|
||||||
|
# 更新状态
|
||||||
|
mutable_status[0] = "分割文本"
|
||||||
|
mutable_status[1] = time.time()
|
||||||
|
|
||||||
|
# 分割文本
|
||||||
|
try:
|
||||||
|
paper_fragments = breakdown_text_to_satisfy_token_limit(
|
||||||
|
txt=content,
|
||||||
|
limit=self._get_token_limit(),
|
||||||
|
llm_model=self.llm_kwargs['llm_model']
|
||||||
|
)
|
||||||
|
except Exception as e:
|
||||||
|
self.failed_files.append((fp, f"文本分割失败:{str(e)}"))
|
||||||
|
mutable_status[2] = "分割失败"
|
||||||
|
return fragments
|
||||||
|
|
||||||
|
check_timeout()
|
||||||
|
|
||||||
|
# 处理片段
|
||||||
|
rel_path = os.path.relpath(fp, project_folder)
|
||||||
|
for i, frag in enumerate(paper_fragments):
|
||||||
|
if frag.strip():
|
||||||
|
fragments.append(FileFragment(
|
||||||
|
file_path=fp,
|
||||||
|
content=frag,
|
||||||
|
rel_path=rel_path,
|
||||||
|
fragment_index=i,
|
||||||
|
total_fragments=len(paper_fragments)
|
||||||
|
))
|
||||||
|
|
||||||
|
mutable_status[2] = "处理完成"
|
||||||
|
return fragments
|
||||||
|
|
||||||
|
except TimeoutError as e:
|
||||||
|
self.failed_files.append((fp, "处理超时"))
|
||||||
|
mutable_status[2] = "处理超时"
|
||||||
|
return []
|
||||||
|
except Exception as e:
|
||||||
|
self.failed_files.append((fp, f"处理失败:{str(e)}"))
|
||||||
|
mutable_status[2] = "处理异常"
|
||||||
|
return []
|
||||||
|
finally:
|
||||||
|
timer.cancel()
|
||||||
|
|
||||||
|
def prepare_fragments(self, project_folder: str, file_paths: List[str]) -> Generator:
|
||||||
|
import concurrent.futures
|
||||||
|
|
||||||
|
|
||||||
|
from concurrent.futures import ThreadPoolExecutor
|
||||||
|
from typing import Generator, List
|
||||||
|
"""并行准备所有文件的处理片段"""
|
||||||
|
all_fragments = []
|
||||||
|
total_files = len(file_paths)
|
||||||
|
|
||||||
|
# 配置参数
|
||||||
|
self.refresh_interval = 0.2 # UI刷新间隔
|
||||||
|
self.watch_dog_patience = 5 # 看门狗超时时间
|
||||||
|
self.max_file_size = 10 * 1024 * 1024 # 10MB限制
|
||||||
|
self.max_workers = min(32, len(file_paths)) # 最多32个线程
|
||||||
|
|
||||||
|
# 创建有超时控制的线程池
|
||||||
|
executor = ThreadPoolExecutor(max_workers=self.max_workers)
|
||||||
|
|
||||||
|
# 用于跨线程状态传递的可变列表 - 增加文件名信息
|
||||||
|
mutable_status_array = [["等待中", time.time(), "pending", file_path] for file_path in file_paths]
|
||||||
|
|
||||||
|
# 创建文件处理任务
|
||||||
|
file_infos = [(fp, project_folder) for fp in file_paths]
|
||||||
|
|
||||||
|
# 提交所有任务,使用带超时控制的处理函数
|
||||||
|
futures = [
|
||||||
|
executor.submit(
|
||||||
|
self._process_single_file_with_timeout,
|
||||||
|
file_info,
|
||||||
|
mutable_status_array[i]
|
||||||
|
) for i, file_info in enumerate(file_infos)
|
||||||
|
]
|
||||||
|
|
||||||
|
# 更新UI的计数器
|
||||||
|
cnt = 0
|
||||||
|
|
||||||
|
try:
|
||||||
|
# 监控任务执行
|
||||||
|
while True:
|
||||||
|
time.sleep(self.refresh_interval)
|
||||||
|
cnt += 1
|
||||||
|
|
||||||
|
# 检查任务完成状态
|
||||||
|
worker_done = [f.done() for f in futures]
|
||||||
|
|
||||||
|
# 更新状态显示
|
||||||
|
status_str = ""
|
||||||
|
for i, (status, timestamp, desc, file_path) in enumerate(mutable_status_array):
|
||||||
|
# 获取文件名(去掉路径)
|
||||||
|
file_name = os.path.basename(file_path)
|
||||||
|
if worker_done[i]:
|
||||||
|
status_str += f"文件 {file_name}: {desc}\n"
|
||||||
|
else:
|
||||||
|
status_str += f"文件 {file_name}: {status} {desc}\n"
|
||||||
|
|
||||||
|
# 更新UI
|
||||||
|
self.chatbot[-1] = [
|
||||||
|
"处理进度",
|
||||||
|
f"正在处理文件...\n\n{status_str}" + "." * (cnt % 10 + 1)
|
||||||
|
]
|
||||||
|
yield from update_ui(chatbot=self.chatbot, history=self.history)
|
||||||
|
|
||||||
|
# 检查是否所有任务完成
|
||||||
|
if all(worker_done):
|
||||||
|
break
|
||||||
|
|
||||||
|
finally:
|
||||||
|
# 确保线程池正确关闭
|
||||||
|
executor.shutdown(wait=False)
|
||||||
|
|
||||||
|
# 收集结果
|
||||||
|
processed_files = 0
|
||||||
|
for future in futures:
|
||||||
|
try:
|
||||||
|
fragments = future.result(timeout=0.1) # 给予一个短暂的超时时间来获取结果
|
||||||
|
all_fragments.extend(fragments)
|
||||||
|
processed_files += 1
|
||||||
|
except concurrent.futures.TimeoutError:
|
||||||
|
# 处理获取结果超时
|
||||||
|
file_index = futures.index(future)
|
||||||
|
self.failed_files.append((file_paths[file_index], "结果获取超时"))
|
||||||
|
continue
|
||||||
|
except Exception as e:
|
||||||
|
# 处理其他异常
|
||||||
|
file_index = futures.index(future)
|
||||||
|
self.failed_files.append((file_paths[file_index], f"未知错误:{str(e)}"))
|
||||||
|
continue
|
||||||
|
|
||||||
|
# 最终进度更新
|
||||||
|
self.chatbot.append([
|
||||||
|
"文件处理完成",
|
||||||
|
f"成功处理 {len(all_fragments)} 个片段,失败 {len(self.failed_files)} 个文件"
|
||||||
|
])
|
||||||
|
yield from update_ui(chatbot=self.chatbot, history=self.history)
|
||||||
|
|
||||||
|
return all_fragments
|
||||||
|
|
||||||
|
def _process_fragments_batch(self, fragments: List[FileFragment]) -> Generator:
|
||||||
|
"""批量处理文件片段"""
|
||||||
|
from collections import defaultdict
|
||||||
|
batch_size = 64 # 每批处理的片段数
|
||||||
|
max_retries = 3 # 最大重试次数
|
||||||
|
retry_delay = 5 # 重试延迟(秒)
|
||||||
|
results = defaultdict(list)
|
||||||
|
|
||||||
|
# 按批次处理
|
||||||
|
for i in range(0, len(fragments), batch_size):
|
||||||
|
batch = fragments[i:i + batch_size]
|
||||||
|
|
||||||
|
inputs_array, inputs_show_user_array, history_array = self._create_batch_inputs(batch)
|
||||||
|
sys_prompt_array = ["请总结以下内容:"] * len(batch)
|
||||||
|
|
||||||
|
# 添加重试机制
|
||||||
|
for retry in range(max_retries):
|
||||||
|
try:
|
||||||
|
response_collection = yield from request_gpt_model_multi_threads_with_very_awesome_ui_and_high_efficiency(
|
||||||
|
inputs_array=inputs_array,
|
||||||
|
inputs_show_user_array=inputs_show_user_array,
|
||||||
|
llm_kwargs=self.llm_kwargs,
|
||||||
|
chatbot=self.chatbot,
|
||||||
|
history_array=history_array,
|
||||||
|
sys_prompt_array=sys_prompt_array,
|
||||||
|
)
|
||||||
|
|
||||||
|
# 处理响应
|
||||||
|
for j, frag in enumerate(batch):
|
||||||
|
summary = response_collection[j * 2 + 1]
|
||||||
|
if summary and summary.strip():
|
||||||
|
results[frag.rel_path].append({
|
||||||
|
'index': frag.fragment_index,
|
||||||
|
'summary': summary,
|
||||||
|
'total': frag.total_fragments
|
||||||
|
})
|
||||||
|
break # 成功处理,跳出重试循环
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
if retry == max_retries - 1: # 最后一次重试失败
|
||||||
|
for frag in batch:
|
||||||
|
self.failed_files.append((frag.file_path, f"处理失败:{str(e)}"))
|
||||||
|
else:
|
||||||
|
yield from update_ui(self.chatbot.append([f"批次处理失败,{retry_delay}秒后重试...", str(e)]))
|
||||||
|
time.sleep(retry_delay)
|
||||||
|
|
||||||
|
return results
|
||||||
|
|
||||||
|
def _generate_final_summary_request(self) -> Tuple[List, List, List]:
|
||||||
|
"""准备最终总结请求"""
|
||||||
|
if not self.file_summaries_map:
|
||||||
|
return (["无可用的文件总结"], ["生成最终总结"], [[]])
|
||||||
|
|
||||||
|
summaries = list(self.file_summaries_map.values())
|
||||||
|
if all(not summary for summary in summaries):
|
||||||
|
return (["所有文件处理均失败"], ["生成最终总结"], [[]])
|
||||||
|
|
||||||
|
if self.plugin_kwargs.get("advanced_arg"):
|
||||||
|
i_say = "根据以上所有文件的处理结果,按要求进行综合处理:" + self.plugin_kwargs['advanced_arg']
|
||||||
|
else:
|
||||||
|
i_say = "请根据以上所有文件的处理结果,生成最终的总结,不超过1000字。"
|
||||||
|
|
||||||
|
return ([i_say], [i_say], [summaries])
|
||||||
|
|
||||||
|
def process_files(self, project_folder: str, file_paths: List[str]) -> Generator:
|
||||||
|
"""处理所有文件"""
|
||||||
|
total_files = len(file_paths)
|
||||||
|
self.chatbot.append([f"开始处理", f"总计 {total_files} 个文件"])
|
||||||
|
yield from update_ui(chatbot=self.chatbot, history=self.history)
|
||||||
|
|
||||||
|
# 1. 准备所有文件片段
|
||||||
|
# 在 process_files 函数中:
|
||||||
|
fragments = yield from self.prepare_fragments(project_folder, file_paths)
|
||||||
|
if not fragments:
|
||||||
|
self.chatbot.append(["处理失败", "没有可处理的文件内容"])
|
||||||
|
return "没有可处理的文件内容"
|
||||||
|
|
||||||
|
# 2. 批量处理所有文件片段
|
||||||
|
self.chatbot.append([f"文件分析", f"共计 {len(fragments)} 个处理单元"])
|
||||||
|
yield from update_ui(chatbot=self.chatbot, history=self.history)
|
||||||
|
|
||||||
|
try:
|
||||||
|
file_summaries = yield from self._process_fragments_batch(fragments)
|
||||||
|
except Exception as e:
|
||||||
|
self.chatbot.append(["处理错误", f"批处理过程失败:{str(e)}"])
|
||||||
|
return "处理过程发生错误"
|
||||||
|
|
||||||
|
# 3. 为每个文件生成整体总结
|
||||||
|
self.chatbot.append(["生成总结", "正在汇总文件内容..."])
|
||||||
|
yield from update_ui(chatbot=self.chatbot, history=self.history)
|
||||||
|
|
||||||
|
# 处理每个文件的总结
|
||||||
|
for rel_path, summaries in file_summaries.items():
|
||||||
|
if len(summaries) > 1: # 多片段文件需要生成整体总结
|
||||||
|
sorted_summaries = sorted(summaries, key=lambda x: x['index'])
|
||||||
|
if self.plugin_kwargs.get("advanced_arg"):
|
||||||
|
|
||||||
|
i_say = f'请按照用户要求对文件内容进行处理,用户要求为:{self.plugin_kwargs["advanced_arg"]}:'
|
||||||
|
else:
|
||||||
|
i_say = f"请总结文件 {os.path.basename(rel_path)} 的主要内容,不超过500字。"
|
||||||
|
|
||||||
|
try:
|
||||||
|
summary_texts = [s['summary'] for s in sorted_summaries]
|
||||||
|
response_collection = yield from request_gpt_model_multi_threads_with_very_awesome_ui_and_high_efficiency(
|
||||||
|
inputs_array=[i_say],
|
||||||
|
inputs_show_user_array=[f"生成 {rel_path} 的处理结果"],
|
||||||
|
llm_kwargs=self.llm_kwargs,
|
||||||
|
chatbot=self.chatbot,
|
||||||
|
history_array=[summary_texts],
|
||||||
|
sys_prompt_array=["你是一个优秀的助手,"],
|
||||||
|
)
|
||||||
|
self.file_summaries_map[rel_path] = response_collection[1]
|
||||||
|
except Exception as e:
|
||||||
|
self.chatbot.append(["警告", f"文件 {rel_path} 总结生成失败:{str(e)}"])
|
||||||
|
self.file_summaries_map[rel_path] = "总结生成失败"
|
||||||
|
else: # 单片段文件直接使用其唯一的总结
|
||||||
|
self.file_summaries_map[rel_path] = summaries[0]['summary']
|
||||||
|
|
||||||
|
# 4. 生成最终总结
|
||||||
|
if total_files ==1:
|
||||||
|
return "文件数为1,此时不调用总结模块"
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
# 收集所有文件的总结用于生成最终总结
|
||||||
|
file_summaries_for_final = []
|
||||||
|
for rel_path, summary in self.file_summaries_map.items():
|
||||||
|
file_summaries_for_final.append(f"文件 {rel_path} 的总结:\n{summary}")
|
||||||
|
|
||||||
|
if self.plugin_kwargs.get("advanced_arg"):
|
||||||
|
final_summary_prompt = ("根据以下所有文件的总结内容,按要求进行综合处理:" +
|
||||||
|
self.plugin_kwargs['advanced_arg'])
|
||||||
|
else:
|
||||||
|
final_summary_prompt = "请根据以下所有文件的总结内容,生成最终的总结报告。"
|
||||||
|
|
||||||
|
response_collection = yield from request_gpt_model_multi_threads_with_very_awesome_ui_and_high_efficiency(
|
||||||
|
inputs_array=[final_summary_prompt],
|
||||||
|
inputs_show_user_array=["生成最终总结报告"],
|
||||||
|
llm_kwargs=self.llm_kwargs,
|
||||||
|
chatbot=self.chatbot,
|
||||||
|
history_array=[file_summaries_for_final],
|
||||||
|
sys_prompt_array=["总结所有文件内容。"],
|
||||||
|
max_workers=1
|
||||||
|
)
|
||||||
|
|
||||||
|
return response_collection[1] if len(response_collection) > 1 else "生成总结失败"
|
||||||
|
except Exception as e:
|
||||||
|
self.chatbot.append(["错误", f"最终总结生成失败:{str(e)}"])
|
||||||
|
return "生成总结失败"
|
||||||
|
|
||||||
|
def save_results(self, final_summary: str):
|
||||||
|
"""保存结果到文件"""
|
||||||
|
from toolbox import promote_file_to_downloadzone, write_history_to_file
|
||||||
|
from crazy_functions.doc_fns.batch_file_query_doc import MarkdownFormatter, HtmlFormatter, WordFormatter
|
||||||
|
import os
|
||||||
|
timestamp = time.strftime("%Y%m%d_%H%M%S")
|
||||||
|
|
||||||
|
# 创建各种格式化器
|
||||||
|
md_formatter = MarkdownFormatter(final_summary, self.file_summaries_map, self.failed_files)
|
||||||
|
html_formatter = HtmlFormatter(final_summary, self.file_summaries_map, self.failed_files)
|
||||||
|
word_formatter = WordFormatter(final_summary, self.file_summaries_map, self.failed_files)
|
||||||
|
|
||||||
|
result_files = []
|
||||||
|
|
||||||
|
# 保存 Markdown
|
||||||
|
md_content = md_formatter.create_document()
|
||||||
|
result_file_md = write_history_to_file(
|
||||||
|
history=[md_content], # 直接传入内容列表
|
||||||
|
file_basename=f"文档总结_{timestamp}.md"
|
||||||
|
)
|
||||||
|
result_files.append(result_file_md)
|
||||||
|
|
||||||
|
# 保存 HTML
|
||||||
|
html_content = html_formatter.create_document()
|
||||||
|
result_file_html = write_history_to_file(
|
||||||
|
history=[html_content],
|
||||||
|
file_basename=f"文档总结_{timestamp}.html"
|
||||||
|
)
|
||||||
|
result_files.append(result_file_html)
|
||||||
|
|
||||||
|
# 保存 Word
|
||||||
|
doc = word_formatter.create_document()
|
||||||
|
# 由于 Word 文档需要用 doc.save(),我们使用与 md 文件相同的目录
|
||||||
|
result_file_docx = os.path.join(
|
||||||
|
os.path.dirname(result_file_md),
|
||||||
|
f"文档总结_{timestamp}.docx"
|
||||||
|
)
|
||||||
|
doc.save(result_file_docx)
|
||||||
|
result_files.append(result_file_docx)
|
||||||
|
|
||||||
|
# 添加到下载区
|
||||||
|
for file in result_files:
|
||||||
|
promote_file_to_downloadzone(file, chatbot=self.chatbot)
|
||||||
|
|
||||||
|
self.chatbot.append(["处理完成", f"结果已保存至: {', '.join(result_files)}"])
|
||||||
|
@CatchException
|
||||||
|
def 批量文件询问(txt: str, llm_kwargs: Dict, plugin_kwargs: Dict, chatbot: List,
|
||||||
|
history: List, system_prompt: str, user_request: str):
|
||||||
|
"""主函数 - 优化版本"""
|
||||||
|
# 初始化
|
||||||
|
import glob
|
||||||
|
import re
|
||||||
|
from crazy_functions.rag_fns.rag_file_support import supports_format
|
||||||
|
from toolbox import report_exception
|
||||||
|
|
||||||
|
summarizer = BatchDocumentSummarizer(llm_kwargs, plugin_kwargs, chatbot, history, system_prompt)
|
||||||
|
chatbot.append(["函数插件功能", f"作者:lbykkkk,批量总结文件。支持格式: {', '.join(supports_format)}等其他文本格式文件,如果长时间卡在文件处理过程,请查看处理进度,然后删除所有处于“pending”状态的文件,然后重新上传处理。"])
|
||||||
|
yield from update_ui(chatbot=chatbot, history=history)
|
||||||
|
|
||||||
|
# 验证输入路径
|
||||||
|
if not os.path.exists(txt):
|
||||||
|
report_exception(chatbot, history, a=f"解析项目: {txt}", b=f"找不到项目或无权访问: {txt}")
|
||||||
|
yield from update_ui(chatbot=chatbot, history=history)
|
||||||
|
return
|
||||||
|
|
||||||
|
# 获取文件列表
|
||||||
|
project_folder = txt
|
||||||
|
extract_folder = next((d for d in glob.glob(f'{project_folder}/*')
|
||||||
|
if os.path.isdir(d) and d.endswith('.extract')), project_folder)
|
||||||
|
|
||||||
|
exclude_patterns = r'/[^/]+\.(zip|rar|7z|tar|gz)$'
|
||||||
|
file_manifest = [f for f in glob.glob(f'{extract_folder}/**', recursive=True)
|
||||||
|
if os.path.isfile(f) and not re.search(exclude_patterns, f)]
|
||||||
|
|
||||||
|
if not file_manifest:
|
||||||
|
report_exception(chatbot, history, a=f"解析项目: {txt}", b="未找到支持的文件类型")
|
||||||
|
yield from update_ui(chatbot=chatbot, history=history)
|
||||||
|
return
|
||||||
|
|
||||||
|
# 处理所有文件并生成总结
|
||||||
|
final_summary = yield from summarizer.process_files(project_folder, file_manifest)
|
||||||
|
yield from update_ui(chatbot=chatbot, history=history)
|
||||||
|
|
||||||
|
# 保存结果
|
||||||
|
summarizer.save_results(final_summary)
|
||||||
|
yield from update_ui(chatbot=chatbot, history=history)
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
from toolbox import CatchException, report_exception, get_log_folder, gen_time_str
|
from toolbox import CatchException, report_exception, get_log_folder, gen_time_str
|
||||||
from toolbox import update_ui, promote_file_to_downloadzone, update_ui_lastest_msg, disable_auto_promotion
|
from toolbox import update_ui, promote_file_to_downloadzone, update_ui_lastest_msg, disable_auto_promotion
|
||||||
from toolbox import write_history_to_file, promote_file_to_downloadzone
|
from toolbox import write_history_to_file, promote_file_to_downloadzone
|
||||||
from .crazy_utils import request_gpt_model_in_new_thread_with_ui_alive
|
from crazy_functions.crazy_utils import request_gpt_model_in_new_thread_with_ui_alive
|
||||||
from .crazy_utils import request_gpt_model_multi_threads_with_very_awesome_ui_and_high_efficiency
|
from crazy_functions.crazy_utils import request_gpt_model_multi_threads_with_very_awesome_ui_and_high_efficiency
|
||||||
from .crazy_utils import read_and_clean_pdf_text
|
from crazy_functions.crazy_utils import read_and_clean_pdf_text
|
||||||
from .pdf_fns.parse_pdf import parse_pdf, get_avail_grobid_url, translate_pdf
|
from .pdf_fns.parse_pdf import parse_pdf, get_avail_grobid_url, translate_pdf
|
||||||
from colorful import *
|
from shared_utils.colorful import *
|
||||||
import copy
|
import copy
|
||||||
import os
|
import os
|
||||||
import math
|
import math
|
||||||
@@ -48,7 +48,7 @@ def markdown_to_dict(article_content):
|
|||||||
|
|
||||||
|
|
||||||
@CatchException
|
@CatchException
|
||||||
def 批量翻译PDF文档(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port):
|
def 批量翻译PDF文档(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request):
|
||||||
|
|
||||||
disable_auto_promotion(chatbot)
|
disable_auto_promotion(chatbot)
|
||||||
# 基本信息:功能、贡献者
|
# 基本信息:功能、贡献者
|
||||||
@@ -60,7 +60,7 @@ def 批量翻译PDF文档(txt, llm_kwargs, plugin_kwargs, chatbot, history, syst
|
|||||||
# 清空历史,以免输入溢出
|
# 清空历史,以免输入溢出
|
||||||
history = []
|
history = []
|
||||||
|
|
||||||
from .crazy_utils import get_files_from_everything
|
from crazy_functions.crazy_utils import get_files_from_everything
|
||||||
success, file_manifest, project_folder = get_files_from_everything(txt, type='.pdf')
|
success, file_manifest, project_folder = get_files_from_everything(txt, type='.pdf')
|
||||||
if len(file_manifest) > 0:
|
if len(file_manifest) > 0:
|
||||||
# 尝试导入依赖,如果缺少依赖,则给出安装建议
|
# 尝试导入依赖,如果缺少依赖,则给出安装建议
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
from toolbox import CatchException, update_ui, gen_time_str
|
import os
|
||||||
from .crazy_utils import request_gpt_model_in_new_thread_with_ui_alive
|
from loguru import logger
|
||||||
from .crazy_utils import input_clipping
|
from toolbox import CatchException, update_ui, gen_time_str, promote_file_to_downloadzone
|
||||||
|
from crazy_functions.crazy_utils import request_gpt_model_in_new_thread_with_ui_alive
|
||||||
|
from crazy_functions.crazy_utils import input_clipping
|
||||||
|
|
||||||
def inspect_dependency(chatbot, history):
|
def inspect_dependency(chatbot, history):
|
||||||
# 尝试导入依赖,如果缺少依赖,则给出安装建议
|
# 尝试导入依赖,如果缺少依赖,则给出安装建议
|
||||||
@@ -27,15 +29,16 @@ def eval_manim(code):
|
|||||||
class_name = get_class_name(code)
|
class_name = get_class_name(code)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
time_str = gen_time_str()
|
||||||
subprocess.check_output([sys.executable, '-c', f"from gpt_log.MyAnimation import {class_name}; {class_name}().render()"])
|
subprocess.check_output([sys.executable, '-c', f"from gpt_log.MyAnimation import {class_name}; {class_name}().render()"])
|
||||||
shutil.move('media/videos/1080p60/{class_name}.mp4', f'gpt_log/{class_name}-{gen_time_str()}.mp4')
|
shutil.move(f'media/videos/1080p60/{class_name}.mp4', f'gpt_log/{class_name}-{time_str}.mp4')
|
||||||
return f'gpt_log/{gen_time_str()}.mp4'
|
return f'gpt_log/{time_str}.mp4'
|
||||||
except subprocess.CalledProcessError as e:
|
except subprocess.CalledProcessError as e:
|
||||||
output = e.output.decode()
|
output = e.output.decode()
|
||||||
print(f"Command returned non-zero exit status {e.returncode}: {output}.")
|
logger.error(f"Command returned non-zero exit status {e.returncode}: {output}.")
|
||||||
return f"Evaluating python script failed: {e.output}."
|
return f"Evaluating python script failed: {e.output}."
|
||||||
except:
|
except:
|
||||||
print('generating mp4 failed')
|
logger.error('generating mp4 failed')
|
||||||
return "Generating mp4 failed."
|
return "Generating mp4 failed."
|
||||||
|
|
||||||
|
|
||||||
@@ -48,7 +51,7 @@ def get_code_block(reply):
|
|||||||
return matches[0].strip('python') # code block
|
return matches[0].strip('python') # code block
|
||||||
|
|
||||||
@CatchException
|
@CatchException
|
||||||
def 动画生成(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port):
|
def 动画生成(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request):
|
||||||
"""
|
"""
|
||||||
txt 输入栏用户输入的文本,例如需要翻译的一段话,再例如一个包含了待处理文件的路径
|
txt 输入栏用户输入的文本,例如需要翻译的一段话,再例如一个包含了待处理文件的路径
|
||||||
llm_kwargs gpt模型参数,如温度和top_p等,一般原样传递下去就行
|
llm_kwargs gpt模型参数,如温度和top_p等,一般原样传递下去就行
|
||||||
@@ -56,7 +59,7 @@ def 动画生成(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt
|
|||||||
chatbot 聊天显示框的句柄,用于显示给用户
|
chatbot 聊天显示框的句柄,用于显示给用户
|
||||||
history 聊天历史,前情提要
|
history 聊天历史,前情提要
|
||||||
system_prompt 给gpt的静默提醒
|
system_prompt 给gpt的静默提醒
|
||||||
web_port 当前软件运行的端口号
|
user_request 当前用户的请求信息(IP地址等)
|
||||||
"""
|
"""
|
||||||
# 清空历史,以免输入溢出
|
# 清空历史,以免输入溢出
|
||||||
history = []
|
history = []
|
||||||
@@ -94,6 +97,8 @@ def 动画生成(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt
|
|||||||
res = eval_manim(code)
|
res = eval_manim(code)
|
||||||
|
|
||||||
chatbot.append(("生成的视频文件路径", res))
|
chatbot.append(("生成的视频文件路径", res))
|
||||||
|
if os.path.exists(res):
|
||||||
|
promote_file_to_downloadzone(res, chatbot=chatbot)
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 # 界面更新
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 # 界面更新
|
||||||
|
|
||||||
# 在这里放一些网上搜集的demo,辅助gpt生成代码
|
# 在这里放一些网上搜集的demo,辅助gpt生成代码
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
|
from loguru import logger
|
||||||
from toolbox import update_ui
|
from toolbox import update_ui
|
||||||
from toolbox import CatchException, report_exception
|
from toolbox import CatchException, report_exception
|
||||||
from .crazy_utils import read_and_clean_pdf_text
|
from crazy_functions.crazy_utils import read_and_clean_pdf_text
|
||||||
from .crazy_utils import request_gpt_model_in_new_thread_with_ui_alive
|
from crazy_functions.crazy_utils import request_gpt_model_in_new_thread_with_ui_alive
|
||||||
fast_debug = False
|
|
||||||
|
|
||||||
|
|
||||||
def 解析PDF(file_name, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt):
|
def 解析PDF(file_name, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt):
|
||||||
import tiktoken
|
logger.info('begin analysis on:', file_name)
|
||||||
print('begin analysis on:', file_name)
|
|
||||||
|
|
||||||
############################## <第 0 步,切割PDF> ##################################
|
############################## <第 0 步,切割PDF> ##################################
|
||||||
# 递归地切割PDF文件,每一块(尽量是完整的一个section,比如introduction,experiment等,必要时再进行切割)
|
# 递归地切割PDF文件,每一块(尽量是完整的一个section,比如introduction,experiment等,必要时再进行切割)
|
||||||
@@ -36,7 +35,7 @@ def 解析PDF(file_name, llm_kwargs, plugin_kwargs, chatbot, history, system_pro
|
|||||||
last_iteration_result = paper_meta # 初始值是摘要
|
last_iteration_result = paper_meta # 初始值是摘要
|
||||||
MAX_WORD_TOTAL = 4096
|
MAX_WORD_TOTAL = 4096
|
||||||
n_fragment = len(paper_fragments)
|
n_fragment = len(paper_fragments)
|
||||||
if n_fragment >= 20: print('文章极长,不能达到预期效果')
|
if n_fragment >= 20: logger.warning('文章极长,不能达到预期效果')
|
||||||
for i in range(n_fragment):
|
for i in range(n_fragment):
|
||||||
NUM_OF_WORD = MAX_WORD_TOTAL // n_fragment
|
NUM_OF_WORD = MAX_WORD_TOTAL // n_fragment
|
||||||
i_say = f"Read this section, recapitulate the content of this section with less than {NUM_OF_WORD} words: {paper_fragments[i]}"
|
i_say = f"Read this section, recapitulate the content of this section with less than {NUM_OF_WORD} words: {paper_fragments[i]}"
|
||||||
@@ -57,13 +56,13 @@ def 解析PDF(file_name, llm_kwargs, plugin_kwargs, chatbot, history, system_pro
|
|||||||
chatbot.append([i_say_show_user, gpt_say])
|
chatbot.append([i_say_show_user, gpt_say])
|
||||||
|
|
||||||
############################## <第 4 步,设置一个token上限,防止回答时Token溢出> ##################################
|
############################## <第 4 步,设置一个token上限,防止回答时Token溢出> ##################################
|
||||||
from .crazy_utils import input_clipping
|
from crazy_functions.crazy_utils import input_clipping
|
||||||
_, final_results = input_clipping("", final_results, max_token_limit=3200)
|
_, final_results = input_clipping("", final_results, max_token_limit=3200)
|
||||||
yield from update_ui(chatbot=chatbot, history=final_results) # 注意这里的历史记录被替代了
|
yield from update_ui(chatbot=chatbot, history=final_results) # 注意这里的历史记录被替代了
|
||||||
|
|
||||||
|
|
||||||
@CatchException
|
@CatchException
|
||||||
def 理解PDF文档内容标准文件输入(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port):
|
def 理解PDF文档内容标准文件输入(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request):
|
||||||
import glob, os
|
import glob, os
|
||||||
|
|
||||||
# 基本信息:功能、贡献者
|
# 基本信息:功能、贡献者
|
||||||
|
|||||||
@@ -1,22 +1,21 @@
|
|||||||
|
from loguru import logger
|
||||||
from toolbox import update_ui
|
from toolbox import update_ui
|
||||||
from toolbox import CatchException, report_exception
|
from toolbox import CatchException, report_exception
|
||||||
from toolbox import write_history_to_file, promote_file_to_downloadzone
|
from toolbox import write_history_to_file, promote_file_to_downloadzone
|
||||||
from .crazy_utils import request_gpt_model_in_new_thread_with_ui_alive
|
from crazy_functions.crazy_utils import request_gpt_model_in_new_thread_with_ui_alive
|
||||||
fast_debug = False
|
|
||||||
|
|
||||||
def 生成函数注释(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt):
|
def 生成函数注释(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt):
|
||||||
import time, os
|
import time, os
|
||||||
print('begin analysis on:', file_manifest)
|
logger.info('begin analysis on:', file_manifest)
|
||||||
for index, fp in enumerate(file_manifest):
|
for index, fp in enumerate(file_manifest):
|
||||||
with open(fp, 'r', encoding='utf-8', errors='replace') as f:
|
with open(fp, 'r', encoding='utf-8', errors='replace') as f:
|
||||||
file_content = f.read()
|
file_content = f.read()
|
||||||
|
|
||||||
i_say = f'请对下面的程序文件做一个概述,并对文件中的所有函数生成注释,使用markdown表格输出结果,文件名是{os.path.relpath(fp, project_folder)},文件内容是 ```{file_content}```'
|
i_say = f'请对下面的程序文件做一个概述,并对文件中的所有函数生成注释,使用markdown表格输出结果,文件名是{os.path.relpath(fp, project_folder)},文件内容是 ```{file_content}```'
|
||||||
i_say_show_user = f'[{index}/{len(file_manifest)}] 请对下面的程序文件做一个概述,并对文件中的所有函数生成注释: {os.path.abspath(fp)}'
|
i_say_show_user = f'[{index+1}/{len(file_manifest)}] 请对下面的程序文件做一个概述,并对文件中的所有函数生成注释: {os.path.abspath(fp)}'
|
||||||
chatbot.append((i_say_show_user, "[Local Message] waiting gpt response."))
|
chatbot.append((i_say_show_user, "[Local Message] waiting gpt response."))
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
||||||
|
|
||||||
if not fast_debug:
|
|
||||||
msg = '正常'
|
msg = '正常'
|
||||||
# ** gpt request **
|
# ** gpt request **
|
||||||
gpt_say = yield from request_gpt_model_in_new_thread_with_ui_alive(
|
gpt_say = yield from request_gpt_model_in_new_thread_with_ui_alive(
|
||||||
@@ -25,9 +24,8 @@ def 生成函数注释(file_manifest, project_folder, llm_kwargs, plugin_kwargs,
|
|||||||
chatbot[-1] = (i_say_show_user, gpt_say)
|
chatbot[-1] = (i_say_show_user, gpt_say)
|
||||||
history.append(i_say_show_user); history.append(gpt_say)
|
history.append(i_say_show_user); history.append(gpt_say)
|
||||||
yield from update_ui(chatbot=chatbot, history=history, msg=msg) # 刷新界面
|
yield from update_ui(chatbot=chatbot, history=history, msg=msg) # 刷新界面
|
||||||
if not fast_debug: time.sleep(2)
|
time.sleep(2)
|
||||||
|
|
||||||
if not fast_debug:
|
|
||||||
res = write_history_to_file(history)
|
res = write_history_to_file(history)
|
||||||
promote_file_to_downloadzone(res, chatbot=chatbot)
|
promote_file_to_downloadzone(res, chatbot=chatbot)
|
||||||
chatbot.append(("完成了吗?", res))
|
chatbot.append(("完成了吗?", res))
|
||||||
@@ -36,7 +34,7 @@ def 生成函数注释(file_manifest, project_folder, llm_kwargs, plugin_kwargs,
|
|||||||
|
|
||||||
|
|
||||||
@CatchException
|
@CatchException
|
||||||
def 批量生成函数注释(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port):
|
def 批量生成函数注释(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request):
|
||||||
history = [] # 清空历史,以免输入溢出
|
history = [] # 清空历史,以免输入溢出
|
||||||
import glob, os
|
import glob, os
|
||||||
if os.path.exists(txt):
|
if os.path.exists(txt):
|
||||||
|
|||||||
437
crazy_functions/生成多种Mermaid图表.py
普通文件
437
crazy_functions/生成多种Mermaid图表.py
普通文件
@@ -0,0 +1,437 @@
|
|||||||
|
from toolbox import CatchException, update_ui, report_exception
|
||||||
|
from crazy_functions.crazy_utils import request_gpt_model_in_new_thread_with_ui_alive
|
||||||
|
from crazy_functions.plugin_template.plugin_class_template import (
|
||||||
|
GptAcademicPluginTemplate,
|
||||||
|
)
|
||||||
|
from crazy_functions.plugin_template.plugin_class_template import ArgProperty
|
||||||
|
|
||||||
|
# 以下是每类图表的PROMPT
|
||||||
|
SELECT_PROMPT = """
|
||||||
|
“{subject}”
|
||||||
|
=============
|
||||||
|
以上是从文章中提取的摘要,将会使用这些摘要绘制图表。请你选择一个合适的图表类型:
|
||||||
|
1 流程图
|
||||||
|
2 序列图
|
||||||
|
3 类图
|
||||||
|
4 饼图
|
||||||
|
5 甘特图
|
||||||
|
6 状态图
|
||||||
|
7 实体关系图
|
||||||
|
8 象限提示图
|
||||||
|
不需要解释原因,仅需要输出单个不带任何标点符号的数字。
|
||||||
|
"""
|
||||||
|
# 没有思维导图!!!测试发现模型始终会优先选择思维导图
|
||||||
|
# 流程图
|
||||||
|
PROMPT_1 = """
|
||||||
|
请你给出围绕“{subject}”的逻辑关系图,使用mermaid语法,注意需要使用双引号将内容括起来。
|
||||||
|
mermaid语法举例:
|
||||||
|
```mermaid
|
||||||
|
graph TD
|
||||||
|
P("编程") --> L1("Python")
|
||||||
|
P("编程") --> L2("C")
|
||||||
|
P("编程") --> L3("C++")
|
||||||
|
P("编程") --> L4("Javascipt")
|
||||||
|
P("编程") --> L5("PHP")
|
||||||
|
```
|
||||||
|
"""
|
||||||
|
# 序列图
|
||||||
|
PROMPT_2 = """
|
||||||
|
请你给出围绕“{subject}”的序列图,使用mermaid语法。
|
||||||
|
mermaid语法举例:
|
||||||
|
```mermaid
|
||||||
|
sequenceDiagram
|
||||||
|
participant A as 用户
|
||||||
|
participant B as 系统
|
||||||
|
A->>B: 登录请求
|
||||||
|
B->>A: 登录成功
|
||||||
|
A->>B: 获取数据
|
||||||
|
B->>A: 返回数据
|
||||||
|
```
|
||||||
|
"""
|
||||||
|
# 类图
|
||||||
|
PROMPT_3 = """
|
||||||
|
请你给出围绕“{subject}”的类图,使用mermaid语法。
|
||||||
|
mermaid语法举例:
|
||||||
|
```mermaid
|
||||||
|
classDiagram
|
||||||
|
Class01 <|-- AveryLongClass : Cool
|
||||||
|
Class03 *-- Class04
|
||||||
|
Class05 o-- Class06
|
||||||
|
Class07 .. Class08
|
||||||
|
Class09 --> C2 : Where am i?
|
||||||
|
Class09 --* C3
|
||||||
|
Class09 --|> Class07
|
||||||
|
Class07 : equals()
|
||||||
|
Class07 : Object[] elementData
|
||||||
|
Class01 : size()
|
||||||
|
Class01 : int chimp
|
||||||
|
Class01 : int gorilla
|
||||||
|
Class08 <--> C2: Cool label
|
||||||
|
```
|
||||||
|
"""
|
||||||
|
# 饼图
|
||||||
|
PROMPT_4 = """
|
||||||
|
请你给出围绕“{subject}”的饼图,使用mermaid语法,注意需要使用双引号将内容括起来。
|
||||||
|
mermaid语法举例:
|
||||||
|
```mermaid
|
||||||
|
pie title Pets adopted by volunteers
|
||||||
|
"狗" : 386
|
||||||
|
"猫" : 85
|
||||||
|
"兔子" : 15
|
||||||
|
```
|
||||||
|
"""
|
||||||
|
# 甘特图
|
||||||
|
PROMPT_5 = """
|
||||||
|
请你给出围绕“{subject}”的甘特图,使用mermaid语法,注意需要使用双引号将内容括起来。
|
||||||
|
mermaid语法举例:
|
||||||
|
```mermaid
|
||||||
|
gantt
|
||||||
|
title "项目开发流程"
|
||||||
|
dateFormat YYYY-MM-DD
|
||||||
|
section "设计"
|
||||||
|
"需求分析" :done, des1, 2024-01-06,2024-01-08
|
||||||
|
"原型设计" :active, des2, 2024-01-09, 3d
|
||||||
|
"UI设计" : des3, after des2, 5d
|
||||||
|
section "开发"
|
||||||
|
"前端开发" :2024-01-20, 10d
|
||||||
|
"后端开发" :2024-01-20, 10d
|
||||||
|
```
|
||||||
|
"""
|
||||||
|
# 状态图
|
||||||
|
PROMPT_6 = """
|
||||||
|
请你给出围绕“{subject}”的状态图,使用mermaid语法,注意需要使用双引号将内容括起来。
|
||||||
|
mermaid语法举例:
|
||||||
|
```mermaid
|
||||||
|
stateDiagram-v2
|
||||||
|
[*] --> "Still"
|
||||||
|
"Still" --> [*]
|
||||||
|
"Still" --> "Moving"
|
||||||
|
"Moving" --> "Still"
|
||||||
|
"Moving" --> "Crash"
|
||||||
|
"Crash" --> [*]
|
||||||
|
```
|
||||||
|
"""
|
||||||
|
# 实体关系图
|
||||||
|
PROMPT_7 = """
|
||||||
|
请你给出围绕“{subject}”的实体关系图,使用mermaid语法。
|
||||||
|
mermaid语法举例:
|
||||||
|
```mermaid
|
||||||
|
erDiagram
|
||||||
|
CUSTOMER ||--o{ ORDER : places
|
||||||
|
ORDER ||--|{ LINE-ITEM : contains
|
||||||
|
CUSTOMER {
|
||||||
|
string name
|
||||||
|
string id
|
||||||
|
}
|
||||||
|
ORDER {
|
||||||
|
string orderNumber
|
||||||
|
date orderDate
|
||||||
|
string customerID
|
||||||
|
}
|
||||||
|
LINE-ITEM {
|
||||||
|
number quantity
|
||||||
|
string productID
|
||||||
|
}
|
||||||
|
```
|
||||||
|
"""
|
||||||
|
# 象限提示图
|
||||||
|
PROMPT_8 = """
|
||||||
|
请你给出围绕“{subject}”的象限图,使用mermaid语法,注意需要使用双引号将内容括起来。
|
||||||
|
mermaid语法举例:
|
||||||
|
```mermaid
|
||||||
|
graph LR
|
||||||
|
A["Hard skill"] --> B("Programming")
|
||||||
|
A["Hard skill"] --> C("Design")
|
||||||
|
D["Soft skill"] --> E("Coordination")
|
||||||
|
D["Soft skill"] --> F("Communication")
|
||||||
|
```
|
||||||
|
"""
|
||||||
|
# 思维导图
|
||||||
|
PROMPT_9 = """
|
||||||
|
{subject}
|
||||||
|
==========
|
||||||
|
请给出上方内容的思维导图,充分考虑其之间的逻辑,使用mermaid语法,注意需要使用双引号将内容括起来。
|
||||||
|
mermaid语法举例:
|
||||||
|
```mermaid
|
||||||
|
mindmap
|
||||||
|
root((mindmap))
|
||||||
|
("Origins")
|
||||||
|
("Long history")
|
||||||
|
::icon(fa fa-book)
|
||||||
|
("Popularisation")
|
||||||
|
("British popular psychology author Tony Buzan")
|
||||||
|
::icon(fa fa-user)
|
||||||
|
("Research")
|
||||||
|
("On effectiveness<br/>and features")
|
||||||
|
::icon(fa fa-search)
|
||||||
|
("On Automatic creation")
|
||||||
|
::icon(fa fa-robot)
|
||||||
|
("Uses")
|
||||||
|
("Creative techniques")
|
||||||
|
::icon(fa fa-lightbulb-o)
|
||||||
|
("Strategic planning")
|
||||||
|
::icon(fa fa-flag)
|
||||||
|
("Argument mapping")
|
||||||
|
::icon(fa fa-comments)
|
||||||
|
("Tools")
|
||||||
|
("Pen and paper")
|
||||||
|
::icon(fa fa-pencil)
|
||||||
|
("Mermaid")
|
||||||
|
::icon(fa fa-code)
|
||||||
|
```
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def 解析历史输入(history, llm_kwargs, file_manifest, chatbot, plugin_kwargs):
|
||||||
|
############################## <第 0 步,切割输入> ##################################
|
||||||
|
# 借用PDF切割中的函数对文本进行切割
|
||||||
|
TOKEN_LIMIT_PER_FRAGMENT = 2500
|
||||||
|
txt = (
|
||||||
|
str(history).encode("utf-8", "ignore").decode()
|
||||||
|
) # avoid reading non-utf8 chars
|
||||||
|
from crazy_functions.pdf_fns.breakdown_txt import (
|
||||||
|
breakdown_text_to_satisfy_token_limit,
|
||||||
|
)
|
||||||
|
|
||||||
|
txt = breakdown_text_to_satisfy_token_limit(
|
||||||
|
txt=txt, limit=TOKEN_LIMIT_PER_FRAGMENT, llm_model=llm_kwargs["llm_model"]
|
||||||
|
)
|
||||||
|
############################## <第 1 步,迭代地历遍整个文章,提取精炼信息> ##################################
|
||||||
|
results = []
|
||||||
|
MAX_WORD_TOTAL = 4096
|
||||||
|
n_txt = len(txt)
|
||||||
|
last_iteration_result = "从以下文本中提取摘要。"
|
||||||
|
|
||||||
|
for i in range(n_txt):
|
||||||
|
NUM_OF_WORD = MAX_WORD_TOTAL // n_txt
|
||||||
|
i_say = f"Read this section, recapitulate the content of this section with less than {NUM_OF_WORD} words in Chinese: {txt[i]}"
|
||||||
|
i_say_show_user = f"[{i+1}/{n_txt}] Read this section, recapitulate the content of this section with less than {NUM_OF_WORD} words: {txt[i][:200]} ...."
|
||||||
|
gpt_say = yield from request_gpt_model_in_new_thread_with_ui_alive(
|
||||||
|
i_say,
|
||||||
|
i_say_show_user, # i_say=真正给chatgpt的提问, i_say_show_user=给用户看的提问
|
||||||
|
llm_kwargs,
|
||||||
|
chatbot,
|
||||||
|
history=[
|
||||||
|
"The main content of the previous section is?",
|
||||||
|
last_iteration_result,
|
||||||
|
], # 迭代上一次的结果
|
||||||
|
sys_prompt="Extracts the main content from the text section where it is located for graphing purposes, answer me with Chinese.", # 提示
|
||||||
|
)
|
||||||
|
results.append(gpt_say)
|
||||||
|
last_iteration_result = gpt_say
|
||||||
|
############################## <第 2 步,根据整理的摘要选择图表类型> ##################################
|
||||||
|
gpt_say = str(plugin_kwargs) # 将图表类型参数赋值为插件参数
|
||||||
|
results_txt = "\n".join(results) # 合并摘要
|
||||||
|
if gpt_say not in [
|
||||||
|
"1",
|
||||||
|
"2",
|
||||||
|
"3",
|
||||||
|
"4",
|
||||||
|
"5",
|
||||||
|
"6",
|
||||||
|
"7",
|
||||||
|
"8",
|
||||||
|
"9",
|
||||||
|
]: # 如插件参数不正确则使用对话模型判断
|
||||||
|
i_say_show_user = (
|
||||||
|
f"接下来将判断适合的图表类型,如连续3次判断失败将会使用流程图进行绘制"
|
||||||
|
)
|
||||||
|
gpt_say = "[Local Message] 收到。" # 用户提示
|
||||||
|
chatbot.append([i_say_show_user, gpt_say])
|
||||||
|
yield from update_ui(chatbot=chatbot, history=[]) # 更新UI
|
||||||
|
i_say = SELECT_PROMPT.format(subject=results_txt)
|
||||||
|
i_say_show_user = f'请判断适合使用的流程图类型,其中数字对应关系为:1-流程图,2-序列图,3-类图,4-饼图,5-甘特图,6-状态图,7-实体关系图,8-象限提示图。由于不管提供文本是什么,模型大概率认为"思维导图"最合适,因此思维导图仅能通过参数调用。'
|
||||||
|
for i in range(3):
|
||||||
|
gpt_say = yield from request_gpt_model_in_new_thread_with_ui_alive(
|
||||||
|
inputs=i_say,
|
||||||
|
inputs_show_user=i_say_show_user,
|
||||||
|
llm_kwargs=llm_kwargs,
|
||||||
|
chatbot=chatbot,
|
||||||
|
history=[],
|
||||||
|
sys_prompt="",
|
||||||
|
)
|
||||||
|
if gpt_say in [
|
||||||
|
"1",
|
||||||
|
"2",
|
||||||
|
"3",
|
||||||
|
"4",
|
||||||
|
"5",
|
||||||
|
"6",
|
||||||
|
"7",
|
||||||
|
"8",
|
||||||
|
"9",
|
||||||
|
]: # 判断返回是否正确
|
||||||
|
break
|
||||||
|
if gpt_say not in ["1", "2", "3", "4", "5", "6", "7", "8", "9"]:
|
||||||
|
gpt_say = "1"
|
||||||
|
############################## <第 3 步,根据选择的图表类型绘制图表> ##################################
|
||||||
|
if gpt_say == "1":
|
||||||
|
i_say = PROMPT_1.format(subject=results_txt)
|
||||||
|
elif gpt_say == "2":
|
||||||
|
i_say = PROMPT_2.format(subject=results_txt)
|
||||||
|
elif gpt_say == "3":
|
||||||
|
i_say = PROMPT_3.format(subject=results_txt)
|
||||||
|
elif gpt_say == "4":
|
||||||
|
i_say = PROMPT_4.format(subject=results_txt)
|
||||||
|
elif gpt_say == "5":
|
||||||
|
i_say = PROMPT_5.format(subject=results_txt)
|
||||||
|
elif gpt_say == "6":
|
||||||
|
i_say = PROMPT_6.format(subject=results_txt)
|
||||||
|
elif gpt_say == "7":
|
||||||
|
i_say = PROMPT_7.replace("{subject}", results_txt) # 由于实体关系图用到了{}符号
|
||||||
|
elif gpt_say == "8":
|
||||||
|
i_say = PROMPT_8.format(subject=results_txt)
|
||||||
|
elif gpt_say == "9":
|
||||||
|
i_say = PROMPT_9.format(subject=results_txt)
|
||||||
|
i_say_show_user = f"请根据判断结果绘制相应的图表。如需绘制思维导图请使用参数调用,同时过大的图表可能需要复制到在线编辑器中进行渲染。"
|
||||||
|
gpt_say = yield from request_gpt_model_in_new_thread_with_ui_alive(
|
||||||
|
inputs=i_say,
|
||||||
|
inputs_show_user=i_say_show_user,
|
||||||
|
llm_kwargs=llm_kwargs,
|
||||||
|
chatbot=chatbot,
|
||||||
|
history=[],
|
||||||
|
sys_prompt="",
|
||||||
|
)
|
||||||
|
history.append(gpt_say)
|
||||||
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 # 界面更新
|
||||||
|
|
||||||
|
|
||||||
|
@CatchException
|
||||||
|
def 生成多种Mermaid图表(
|
||||||
|
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 当前软件运行的端口号
|
||||||
|
"""
|
||||||
|
import os
|
||||||
|
|
||||||
|
# 基本信息:功能、贡献者
|
||||||
|
chatbot.append(
|
||||||
|
[
|
||||||
|
"函数插件功能?",
|
||||||
|
"根据当前聊天历史或指定的路径文件(文件内容优先)绘制多种mermaid图表,将会由对话模型首先判断适合的图表类型,随后绘制图表。\
|
||||||
|
\n您也可以使用插件参数指定绘制的图表类型,函数插件贡献者: Menghuan1918",
|
||||||
|
]
|
||||||
|
)
|
||||||
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
||||||
|
|
||||||
|
if os.path.exists(txt): # 如输入区无内容则直接解析历史记录
|
||||||
|
from crazy_functions.pdf_fns.parse_word import extract_text_from_files
|
||||||
|
|
||||||
|
file_exist, final_result, page_one, file_manifest, excption = (
|
||||||
|
extract_text_from_files(txt, chatbot, history)
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
file_exist = False
|
||||||
|
excption = ""
|
||||||
|
file_manifest = []
|
||||||
|
|
||||||
|
if excption != "":
|
||||||
|
if excption == "word":
|
||||||
|
report_exception(
|
||||||
|
chatbot,
|
||||||
|
history,
|
||||||
|
a=f"解析项目: {txt}",
|
||||||
|
b=f"找到了.doc文件,但是该文件格式不被支持,请先转化为.docx格式。",
|
||||||
|
)
|
||||||
|
|
||||||
|
elif excption == "pdf":
|
||||||
|
report_exception(
|
||||||
|
chatbot,
|
||||||
|
history,
|
||||||
|
a=f"解析项目: {txt}",
|
||||||
|
b=f"导入软件依赖失败。使用该模块需要额外依赖,安装方法```pip install --upgrade pymupdf```。",
|
||||||
|
)
|
||||||
|
|
||||||
|
elif excption == "word_pip":
|
||||||
|
report_exception(
|
||||||
|
chatbot,
|
||||||
|
history,
|
||||||
|
a=f"解析项目: {txt}",
|
||||||
|
b=f"导入软件依赖失败。使用该模块需要额外依赖,安装方法```pip install --upgrade python-docx pywin32```。",
|
||||||
|
)
|
||||||
|
|
||||||
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
||||||
|
|
||||||
|
else:
|
||||||
|
if not file_exist:
|
||||||
|
history.append(txt) # 如输入区不是文件则将输入区内容加入历史记录
|
||||||
|
i_say_show_user = f"首先你从历史记录中提取摘要。"
|
||||||
|
gpt_say = "[Local Message] 收到。" # 用户提示
|
||||||
|
chatbot.append([i_say_show_user, gpt_say])
|
||||||
|
yield from update_ui(chatbot=chatbot, history=history) # 更新UI
|
||||||
|
yield from 解析历史输入(
|
||||||
|
history, llm_kwargs, file_manifest, chatbot, plugin_kwargs
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
file_num = len(file_manifest)
|
||||||
|
for i in range(file_num): # 依次处理文件
|
||||||
|
i_say_show_user = f"[{i+1}/{file_num}]处理文件{file_manifest[i]}"
|
||||||
|
gpt_say = "[Local Message] 收到。" # 用户提示
|
||||||
|
chatbot.append([i_say_show_user, gpt_say])
|
||||||
|
yield from update_ui(chatbot=chatbot, history=history) # 更新UI
|
||||||
|
history = [] # 如输入区内容为文件则清空历史记录
|
||||||
|
history.append(final_result[i])
|
||||||
|
yield from 解析历史输入(
|
||||||
|
history, llm_kwargs, file_manifest, chatbot, plugin_kwargs
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class Mermaid_Gen(GptAcademicPluginTemplate):
|
||||||
|
def __init__(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def define_arg_selection_menu(self):
|
||||||
|
gui_definition = {
|
||||||
|
"Type_of_Mermaid": ArgProperty(
|
||||||
|
title="绘制的Mermaid图表类型",
|
||||||
|
options=[
|
||||||
|
"由LLM决定",
|
||||||
|
"流程图",
|
||||||
|
"序列图",
|
||||||
|
"类图",
|
||||||
|
"饼图",
|
||||||
|
"甘特图",
|
||||||
|
"状态图",
|
||||||
|
"实体关系图",
|
||||||
|
"象限提示图",
|
||||||
|
"思维导图",
|
||||||
|
],
|
||||||
|
default_value="由LLM决定",
|
||||||
|
description="选择'由LLM决定'时将由对话模型判断适合的图表类型(不包括思维导图),选择其他类型时将直接绘制指定的图表类型。",
|
||||||
|
type="dropdown",
|
||||||
|
).model_dump_json(),
|
||||||
|
}
|
||||||
|
return gui_definition
|
||||||
|
|
||||||
|
def execute(
|
||||||
|
txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request
|
||||||
|
):
|
||||||
|
options = [
|
||||||
|
"由LLM决定",
|
||||||
|
"流程图",
|
||||||
|
"序列图",
|
||||||
|
"类图",
|
||||||
|
"饼图",
|
||||||
|
"甘特图",
|
||||||
|
"状态图",
|
||||||
|
"实体关系图",
|
||||||
|
"象限提示图",
|
||||||
|
"思维导图",
|
||||||
|
]
|
||||||
|
plugin_kwargs = options.index(plugin_kwargs['Type_of_Mermaid'])
|
||||||
|
yield from 生成多种Mermaid图表(
|
||||||
|
txt,
|
||||||
|
llm_kwargs,
|
||||||
|
plugin_kwargs,
|
||||||
|
chatbot,
|
||||||
|
history,
|
||||||
|
system_prompt,
|
||||||
|
user_request,
|
||||||
|
)
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
from toolbox import CatchException, update_ui, ProxyNetworkActivate, update_ui_lastest_msg, get_log_folder, get_user
|
from toolbox import CatchException, update_ui, ProxyNetworkActivate, update_ui_lastest_msg, get_log_folder, get_user
|
||||||
from .crazy_utils import request_gpt_model_in_new_thread_with_ui_alive, get_files_from_everything
|
from crazy_functions.crazy_utils import request_gpt_model_in_new_thread_with_ui_alive, get_files_from_everything
|
||||||
|
from loguru import logger
|
||||||
install_msg ="""
|
install_msg ="""
|
||||||
|
|
||||||
1. python -m pip install torch --index-url https://download.pytorch.org/whl/cpu
|
1. python -m pip install torch --index-url https://download.pytorch.org/whl/cpu
|
||||||
@@ -13,7 +13,7 @@ install_msg ="""
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
@CatchException
|
@CatchException
|
||||||
def 知识库文件注入(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port):
|
def 知识库文件注入(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request):
|
||||||
"""
|
"""
|
||||||
txt 输入栏用户输入的文本,例如需要翻译的一段话,再例如一个包含了待处理文件的路径
|
txt 输入栏用户输入的文本,例如需要翻译的一段话,再例如一个包含了待处理文件的路径
|
||||||
llm_kwargs gpt模型参数, 如温度和top_p等, 一般原样传递下去就行
|
llm_kwargs gpt模型参数, 如温度和top_p等, 一般原样传递下去就行
|
||||||
@@ -21,7 +21,7 @@ def 知识库文件注入(txt, llm_kwargs, plugin_kwargs, chatbot, history, syst
|
|||||||
chatbot 聊天显示框的句柄,用于显示给用户
|
chatbot 聊天显示框的句柄,用于显示给用户
|
||||||
history 聊天历史,前情提要
|
history 聊天历史,前情提要
|
||||||
system_prompt 给gpt的静默提醒
|
system_prompt 给gpt的静默提醒
|
||||||
web_port 当前软件运行的端口号
|
user_request 当前用户的请求信息(IP地址等)
|
||||||
"""
|
"""
|
||||||
history = [] # 清空历史,以免输入溢出
|
history = [] # 清空历史,以免输入溢出
|
||||||
|
|
||||||
@@ -40,7 +40,7 @@ def 知识库文件注入(txt, llm_kwargs, plugin_kwargs, chatbot, history, syst
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
chatbot.append(["依赖不足", f"{str(e)}\n\n导入依赖失败。请用以下命令安装" + install_msg])
|
chatbot.append(["依赖不足", f"{str(e)}\n\n导入依赖失败。请用以下命令安装" + install_msg])
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
||||||
# from .crazy_utils import try_install_deps
|
# from crazy_functions.crazy_utils import try_install_deps
|
||||||
# try_install_deps(['zh_langchain==0.2.1', 'pypinyin'], reload_m=['pypinyin', 'zh_langchain'])
|
# try_install_deps(['zh_langchain==0.2.1', 'pypinyin'], reload_m=['pypinyin', 'zh_langchain'])
|
||||||
# yield from update_ui_lastest_msg("安装完成,您可以再次重试。", chatbot, history)
|
# yield from update_ui_lastest_msg("安装完成,您可以再次重试。", chatbot, history)
|
||||||
return
|
return
|
||||||
@@ -60,7 +60,7 @@ def 知识库文件注入(txt, llm_kwargs, plugin_kwargs, chatbot, history, syst
|
|||||||
# < -------------------预热文本向量化模组--------------- >
|
# < -------------------预热文本向量化模组--------------- >
|
||||||
chatbot.append(['<br/>'.join(file_manifest), "正在预热文本向量化模组, 如果是第一次运行, 将消耗较长时间下载中文向量化模型..."])
|
chatbot.append(['<br/>'.join(file_manifest), "正在预热文本向量化模组, 如果是第一次运行, 将消耗较长时间下载中文向量化模型..."])
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
||||||
print('Checking Text2vec ...')
|
logger.info('Checking Text2vec ...')
|
||||||
from langchain.embeddings.huggingface import HuggingFaceEmbeddings
|
from langchain.embeddings.huggingface import HuggingFaceEmbeddings
|
||||||
with ProxyNetworkActivate('Download_LLM'): # 临时地激活代理网络
|
with ProxyNetworkActivate('Download_LLM'): # 临时地激活代理网络
|
||||||
HuggingFaceEmbeddings(model_name="GanymedeNil/text2vec-large-chinese")
|
HuggingFaceEmbeddings(model_name="GanymedeNil/text2vec-large-chinese")
|
||||||
@@ -68,7 +68,7 @@ def 知识库文件注入(txt, llm_kwargs, plugin_kwargs, chatbot, history, syst
|
|||||||
# < -------------------构建知识库--------------- >
|
# < -------------------构建知识库--------------- >
|
||||||
chatbot.append(['<br/>'.join(file_manifest), "正在构建知识库..."])
|
chatbot.append(['<br/>'.join(file_manifest), "正在构建知识库..."])
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
||||||
print('Establishing knowledge archive ...')
|
logger.info('Establishing knowledge archive ...')
|
||||||
with ProxyNetworkActivate('Download_LLM'): # 临时地激活代理网络
|
with ProxyNetworkActivate('Download_LLM'): # 临时地激活代理网络
|
||||||
kai = knowledge_archive_interface()
|
kai = knowledge_archive_interface()
|
||||||
vs_path = get_log_folder(user=get_user(chatbot), plugin_name='vec_store')
|
vs_path = get_log_folder(user=get_user(chatbot), plugin_name='vec_store')
|
||||||
@@ -84,7 +84,7 @@ def 知识库文件注入(txt, llm_kwargs, plugin_kwargs, chatbot, history, syst
|
|||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 # 由于请求gpt需要一段时间,我们先及时地做一次界面更新
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 # 由于请求gpt需要一段时间,我们先及时地做一次界面更新
|
||||||
|
|
||||||
@CatchException
|
@CatchException
|
||||||
def 读取知识库作答(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port=-1):
|
def 读取知识库作答(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request=-1):
|
||||||
# resolve deps
|
# resolve deps
|
||||||
try:
|
try:
|
||||||
# from zh_langchain import construct_vector_store
|
# from zh_langchain import construct_vector_store
|
||||||
@@ -93,7 +93,7 @@ def 读取知识库作答(txt, llm_kwargs, plugin_kwargs, chatbot, history, syst
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
chatbot.append(["依赖不足", f"{str(e)}\n\n导入依赖失败。请用以下命令安装" + install_msg])
|
chatbot.append(["依赖不足", f"{str(e)}\n\n导入依赖失败。请用以下命令安装" + install_msg])
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
||||||
# from .crazy_utils import try_install_deps
|
# from crazy_functions.crazy_utils import try_install_deps
|
||||||
# try_install_deps(['zh_langchain==0.2.1', 'pypinyin'], reload_m=['pypinyin', 'zh_langchain'])
|
# try_install_deps(['zh_langchain==0.2.1', 'pypinyin'], reload_m=['pypinyin', 'zh_langchain'])
|
||||||
# yield from update_ui_lastest_msg("安装完成,您可以再次重试。", chatbot, history)
|
# yield from update_ui_lastest_msg("安装完成,您可以再次重试。", chatbot, history)
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
from toolbox import CatchException, update_ui
|
from toolbox import CatchException, update_ui
|
||||||
from .crazy_utils import request_gpt_model_in_new_thread_with_ui_alive, input_clipping
|
from crazy_functions.crazy_utils import request_gpt_model_in_new_thread_with_ui_alive, input_clipping
|
||||||
import requests
|
import requests
|
||||||
from bs4 import BeautifulSoup
|
from bs4 import BeautifulSoup
|
||||||
from request_llms.bridge_all import model_info
|
from request_llms.bridge_all import model_info
|
||||||
@@ -23,8 +23,8 @@ def google(query, proxies):
|
|||||||
item = {'title': title, 'link': link}
|
item = {'title': title, 'link': link}
|
||||||
results.append(item)
|
results.append(item)
|
||||||
|
|
||||||
for r in results:
|
# for r in results:
|
||||||
print(r['link'])
|
# print(r['link'])
|
||||||
return results
|
return results
|
||||||
|
|
||||||
def scrape_text(url, proxies) -> str:
|
def scrape_text(url, proxies) -> str:
|
||||||
@@ -55,7 +55,7 @@ def scrape_text(url, proxies) -> str:
|
|||||||
return text
|
return text
|
||||||
|
|
||||||
@CatchException
|
@CatchException
|
||||||
def 连接网络回答问题(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port):
|
def 连接网络回答问题(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request):
|
||||||
"""
|
"""
|
||||||
txt 输入栏用户输入的文本,例如需要翻译的一段话,再例如一个包含了待处理文件的路径
|
txt 输入栏用户输入的文本,例如需要翻译的一段话,再例如一个包含了待处理文件的路径
|
||||||
llm_kwargs gpt模型参数,如温度和top_p等,一般原样传递下去就行
|
llm_kwargs gpt模型参数,如温度和top_p等,一般原样传递下去就行
|
||||||
@@ -63,7 +63,7 @@ def 连接网络回答问题(txt, llm_kwargs, plugin_kwargs, chatbot, history, s
|
|||||||
chatbot 聊天显示框的句柄,用于显示给用户
|
chatbot 聊天显示框的句柄,用于显示给用户
|
||||||
history 聊天历史,前情提要
|
history 聊天历史,前情提要
|
||||||
system_prompt 给gpt的静默提醒
|
system_prompt 给gpt的静默提醒
|
||||||
web_port 当前软件运行的端口号
|
user_request 当前用户的请求信息(IP地址等)
|
||||||
"""
|
"""
|
||||||
history = [] # 清空历史,以免输入溢出
|
history = [] # 清空历史,以免输入溢出
|
||||||
chatbot.append((f"请结合互联网信息回答以下问题:{txt}",
|
chatbot.append((f"请结合互联网信息回答以下问题:{txt}",
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
from toolbox import CatchException, update_ui
|
from toolbox import CatchException, update_ui
|
||||||
from .crazy_utils import request_gpt_model_in_new_thread_with_ui_alive, input_clipping
|
from crazy_functions.crazy_utils import request_gpt_model_in_new_thread_with_ui_alive, input_clipping
|
||||||
import requests
|
import requests
|
||||||
from bs4 import BeautifulSoup
|
from bs4 import BeautifulSoup
|
||||||
from request_llms.bridge_all import model_info
|
from request_llms.bridge_all import model_info
|
||||||
@@ -22,8 +22,8 @@ def bing_search(query, proxies=None):
|
|||||||
item = {'title': title, 'link': link}
|
item = {'title': title, 'link': link}
|
||||||
results.append(item)
|
results.append(item)
|
||||||
|
|
||||||
for r in results:
|
# for r in results:
|
||||||
print(r['link'])
|
# print(r['link'])
|
||||||
return results
|
return results
|
||||||
|
|
||||||
|
|
||||||
@@ -55,7 +55,7 @@ def scrape_text(url, proxies) -> str:
|
|||||||
return text
|
return text
|
||||||
|
|
||||||
@CatchException
|
@CatchException
|
||||||
def 连接bing搜索回答问题(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port):
|
def 连接bing搜索回答问题(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request):
|
||||||
"""
|
"""
|
||||||
txt 输入栏用户输入的文本,例如需要翻译的一段话,再例如一个包含了待处理文件的路径
|
txt 输入栏用户输入的文本,例如需要翻译的一段话,再例如一个包含了待处理文件的路径
|
||||||
llm_kwargs gpt模型参数,如温度和top_p等,一般原样传递下去就行
|
llm_kwargs gpt模型参数,如温度和top_p等,一般原样传递下去就行
|
||||||
@@ -63,7 +63,7 @@ def 连接bing搜索回答问题(txt, llm_kwargs, plugin_kwargs, chatbot, histor
|
|||||||
chatbot 聊天显示框的句柄,用于显示给用户
|
chatbot 聊天显示框的句柄,用于显示给用户
|
||||||
history 聊天历史,前情提要
|
history 聊天历史,前情提要
|
||||||
system_prompt 给gpt的静默提醒
|
system_prompt 给gpt的静默提醒
|
||||||
web_port 当前软件运行的端口号
|
user_request 当前用户的请求信息(IP地址等)
|
||||||
"""
|
"""
|
||||||
history = [] # 清空历史,以免输入溢出
|
history = [] # 清空历史,以免输入溢出
|
||||||
chatbot.append((f"请结合互联网信息回答以下问题:{txt}",
|
chatbot.append((f"请结合互联网信息回答以下问题:{txt}",
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ def analyze_intention_with_simple_rules(txt):
|
|||||||
|
|
||||||
|
|
||||||
@CatchException
|
@CatchException
|
||||||
def 虚空终端(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port):
|
def 虚空终端(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request):
|
||||||
disable_auto_promotion(chatbot=chatbot)
|
disable_auto_promotion(chatbot=chatbot)
|
||||||
# 获取当前虚空终端状态
|
# 获取当前虚空终端状态
|
||||||
state = VoidTerminalState.get_state(chatbot)
|
state = VoidTerminalState.get_state(chatbot)
|
||||||
@@ -121,7 +121,7 @@ def 虚空终端(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt
|
|||||||
state.set_state(chatbot=chatbot, key='has_provided_explaination', value=True)
|
state.set_state(chatbot=chatbot, key='has_provided_explaination', value=True)
|
||||||
state.unlock_plugin(chatbot=chatbot)
|
state.unlock_plugin(chatbot=chatbot)
|
||||||
yield from update_ui(chatbot=chatbot, history=history)
|
yield from update_ui(chatbot=chatbot, history=history)
|
||||||
yield from 虚空终端主路由(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port)
|
yield from 虚空终端主路由(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request)
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
# 如果意图模糊,提示
|
# 如果意图模糊,提示
|
||||||
@@ -133,7 +133,7 @@ def 虚空终端(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
def 虚空终端主路由(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port):
|
def 虚空终端主路由(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request):
|
||||||
history = []
|
history = []
|
||||||
chatbot.append(("虚空终端状态: ", f"正在执行任务: {txt}"))
|
chatbot.append(("虚空终端状态: ", f"正在执行任务: {txt}"))
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
||||||
|
|||||||
@@ -12,6 +12,12 @@ class PaperFileGroup():
|
|||||||
self.sp_file_index = []
|
self.sp_file_index = []
|
||||||
self.sp_file_tag = []
|
self.sp_file_tag = []
|
||||||
|
|
||||||
|
# count_token
|
||||||
|
from request_llms.bridge_all import model_info
|
||||||
|
enc = model_info["gpt-3.5-turbo"]['tokenizer']
|
||||||
|
def get_token_num(txt): return len(enc.encode(txt, disallowed_special=()))
|
||||||
|
self.get_token_num = get_token_num
|
||||||
|
|
||||||
def run_file_split(self, max_token_limit=1900):
|
def run_file_split(self, max_token_limit=1900):
|
||||||
"""
|
"""
|
||||||
将长文本分离开来
|
将长文本分离开来
|
||||||
@@ -58,7 +64,7 @@ def parseNotebook(filename, enable_markdown=1):
|
|||||||
|
|
||||||
|
|
||||||
def ipynb解释(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt):
|
def ipynb解释(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt):
|
||||||
from .crazy_utils import request_gpt_model_multi_threads_with_very_awesome_ui_and_high_efficiency
|
from crazy_functions.crazy_utils import request_gpt_model_multi_threads_with_very_awesome_ui_and_high_efficiency
|
||||||
|
|
||||||
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")
|
||||||
enable_markdown = plugin_kwargs.get("advanced_arg", "1")
|
enable_markdown = plugin_kwargs.get("advanced_arg", "1")
|
||||||
@@ -109,7 +115,7 @@ def ipynb解释(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbo
|
|||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
||||||
|
|
||||||
@CatchException
|
@CatchException
|
||||||
def 解析ipynb文件(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port):
|
def 解析ipynb文件(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request):
|
||||||
chatbot.append([
|
chatbot.append([
|
||||||
"函数插件功能?",
|
"函数插件功能?",
|
||||||
"对IPynb文件进行解析。Contributor: codycjy."])
|
"对IPynb文件进行解析。Contributor: codycjy."])
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
from toolbox import CatchException, update_ui, get_conf
|
from toolbox import CatchException, update_ui, get_conf
|
||||||
from .crazy_utils import request_gpt_model_in_new_thread_with_ui_alive
|
from crazy_functions.crazy_utils import request_gpt_model_in_new_thread_with_ui_alive
|
||||||
import datetime
|
import datetime
|
||||||
@CatchException
|
@CatchException
|
||||||
def 同时问询(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port):
|
def 同时问询(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request):
|
||||||
"""
|
"""
|
||||||
txt 输入栏用户输入的文本,例如需要翻译的一段话,再例如一个包含了待处理文件的路径
|
txt 输入栏用户输入的文本,例如需要翻译的一段话,再例如一个包含了待处理文件的路径
|
||||||
llm_kwargs gpt模型参数,如温度和top_p等,一般原样传递下去就行
|
llm_kwargs gpt模型参数,如温度和top_p等,一般原样传递下去就行
|
||||||
@@ -10,7 +10,7 @@ def 同时问询(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt
|
|||||||
chatbot 聊天显示框的句柄,用于显示给用户
|
chatbot 聊天显示框的句柄,用于显示给用户
|
||||||
history 聊天历史,前情提要
|
history 聊天历史,前情提要
|
||||||
system_prompt 给gpt的静默提醒
|
system_prompt 给gpt的静默提醒
|
||||||
web_port 当前软件运行的端口号
|
user_request 当前用户的请求信息(IP地址等)
|
||||||
"""
|
"""
|
||||||
history = [] # 清空历史,以免输入溢出
|
history = [] # 清空历史,以免输入溢出
|
||||||
MULTI_QUERY_LLM_MODELS = get_conf('MULTI_QUERY_LLM_MODELS')
|
MULTI_QUERY_LLM_MODELS = get_conf('MULTI_QUERY_LLM_MODELS')
|
||||||
@@ -32,7 +32,7 @@ def 同时问询(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt
|
|||||||
|
|
||||||
|
|
||||||
@CatchException
|
@CatchException
|
||||||
def 同时问询_指定模型(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port):
|
def 同时问询_指定模型(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request):
|
||||||
"""
|
"""
|
||||||
txt 输入栏用户输入的文本,例如需要翻译的一段话,再例如一个包含了待处理文件的路径
|
txt 输入栏用户输入的文本,例如需要翻译的一段话,再例如一个包含了待处理文件的路径
|
||||||
llm_kwargs gpt模型参数,如温度和top_p等,一般原样传递下去就行
|
llm_kwargs gpt模型参数,如温度和top_p等,一般原样传递下去就行
|
||||||
@@ -40,7 +40,7 @@ def 同时问询_指定模型(txt, llm_kwargs, plugin_kwargs, chatbot, history,
|
|||||||
chatbot 聊天显示框的句柄,用于显示给用户
|
chatbot 聊天显示框的句柄,用于显示给用户
|
||||||
history 聊天历史,前情提要
|
history 聊天历史,前情提要
|
||||||
system_prompt 给gpt的静默提醒
|
system_prompt 给gpt的静默提醒
|
||||||
web_port 当前软件运行的端口号
|
user_request 当前用户的请求信息(IP地址等)
|
||||||
"""
|
"""
|
||||||
history = [] # 清空历史,以免输入溢出
|
history = [] # 清空历史,以免输入溢出
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
from toolbox import update_ui
|
from toolbox import update_ui
|
||||||
from toolbox import CatchException, get_conf, markdown_convertion
|
from toolbox import CatchException, get_conf, markdown_convertion
|
||||||
|
from request_llms.bridge_all import predict_no_ui_long_connection
|
||||||
from crazy_functions.crazy_utils import input_clipping
|
from crazy_functions.crazy_utils import input_clipping
|
||||||
from crazy_functions.agent_fns.watchdog import WatchDog
|
from crazy_functions.agent_fns.watchdog import WatchDog
|
||||||
from request_llms.bridge_all import predict_no_ui_long_connection
|
from crazy_functions.live_audio.aliyunASR import AliyunASR
|
||||||
|
from loguru import logger
|
||||||
|
|
||||||
import threading, time
|
import threading, time
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from .live_audio.aliyunASR import AliyunASR
|
|
||||||
import json
|
import json
|
||||||
import re
|
import re
|
||||||
|
|
||||||
@@ -42,9 +44,9 @@ class AsyncGptTask():
|
|||||||
gpt_say_partial = predict_no_ui_long_connection(inputs=i_say, llm_kwargs=llm_kwargs, history=history, sys_prompt=sys_prompt,
|
gpt_say_partial = predict_no_ui_long_connection(inputs=i_say, llm_kwargs=llm_kwargs, history=history, sys_prompt=sys_prompt,
|
||||||
observe_window=observe_window[index], console_slience=True)
|
observe_window=observe_window[index], console_slience=True)
|
||||||
except ConnectionAbortedError as token_exceed_err:
|
except ConnectionAbortedError as token_exceed_err:
|
||||||
print('至少一个线程任务Token溢出而失败', e)
|
logger.error('至少一个线程任务Token溢出而失败', e)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print('至少一个线程任务意外失败', e)
|
logger.error('至少一个线程任务意外失败', e)
|
||||||
|
|
||||||
def add_async_gpt_task(self, i_say, chatbot_index, llm_kwargs, history, system_prompt):
|
def add_async_gpt_task(self, i_say, chatbot_index, llm_kwargs, history, system_prompt):
|
||||||
self.observe_future.append([""])
|
self.observe_future.append([""])
|
||||||
@@ -166,7 +168,7 @@ class InterviewAssistant(AliyunASR):
|
|||||||
|
|
||||||
|
|
||||||
@CatchException
|
@CatchException
|
||||||
def 语音助手(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port):
|
def 语音助手(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request):
|
||||||
# pip install -U openai-whisper
|
# pip install -U openai-whisper
|
||||||
chatbot.append(["对话助手函数插件:使用时,双手离开鼠标键盘吧", "音频助手, 正在听您讲话(点击“停止”键可终止程序)..."])
|
chatbot.append(["对话助手函数插件:使用时,双手离开鼠标键盘吧", "音频助手, 正在听您讲话(点击“停止”键可终止程序)..."])
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
||||||
|
|||||||
@@ -1,19 +1,18 @@
|
|||||||
from toolbox import update_ui
|
from toolbox import update_ui
|
||||||
from toolbox import CatchException, report_exception
|
from toolbox import CatchException, report_exception
|
||||||
from toolbox import write_history_to_file, promote_file_to_downloadzone
|
from toolbox import write_history_to_file, promote_file_to_downloadzone
|
||||||
from .crazy_utils import request_gpt_model_in_new_thread_with_ui_alive
|
from crazy_functions.crazy_utils import request_gpt_model_in_new_thread_with_ui_alive
|
||||||
|
|
||||||
|
|
||||||
def 解析Paper(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt):
|
def 解析Paper(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt):
|
||||||
import time, glob, os
|
import time, glob, os
|
||||||
print('begin analysis on:', file_manifest)
|
|
||||||
for index, fp in enumerate(file_manifest):
|
for index, fp in enumerate(file_manifest):
|
||||||
with open(fp, 'r', encoding='utf-8', errors='replace') as f:
|
with open(fp, 'r', encoding='utf-8', errors='replace') as f:
|
||||||
file_content = f.read()
|
file_content = f.read()
|
||||||
|
|
||||||
prefix = "接下来请你逐文件分析下面的论文文件,概括其内容" if index==0 else ""
|
prefix = "接下来请你逐文件分析下面的论文文件,概括其内容" if index==0 else ""
|
||||||
i_say = prefix + f'请对下面的文章片段用中文做一个概述,文件名是{os.path.relpath(fp, project_folder)},文章内容是 ```{file_content}```'
|
i_say = prefix + f'请对下面的文章片段用中文做一个概述,文件名是{os.path.relpath(fp, project_folder)},文章内容是 ```{file_content}```'
|
||||||
i_say_show_user = prefix + f'[{index}/{len(file_manifest)}] 请对下面的文章片段做一个概述: {os.path.abspath(fp)}'
|
i_say_show_user = prefix + f'[{index+1}/{len(file_manifest)}] 请对下面的文章片段做一个概述: {os.path.abspath(fp)}'
|
||||||
chatbot.append((i_say_show_user, "[Local Message] waiting gpt response."))
|
chatbot.append((i_say_show_user, "[Local Message] waiting gpt response."))
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
||||||
|
|
||||||
@@ -44,7 +43,7 @@ def 解析Paper(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbo
|
|||||||
|
|
||||||
|
|
||||||
@CatchException
|
@CatchException
|
||||||
def 读文章写摘要(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port):
|
def 读文章写摘要(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request):
|
||||||
history = [] # 清空历史,以免输入溢出
|
history = [] # 清空历史,以免输入溢出
|
||||||
import glob, os
|
import glob, os
|
||||||
if os.path.exists(txt):
|
if os.path.exists(txt):
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
from .crazy_utils import request_gpt_model_in_new_thread_with_ui_alive
|
from crazy_functions.crazy_utils import request_gpt_model_in_new_thread_with_ui_alive
|
||||||
from toolbox import CatchException, report_exception, promote_file_to_downloadzone
|
from toolbox import CatchException, report_exception, promote_file_to_downloadzone
|
||||||
from toolbox import update_ui, update_ui_lastest_msg, disable_auto_promotion, write_history_to_file
|
from toolbox import update_ui, update_ui_lastest_msg, disable_auto_promotion, write_history_to_file
|
||||||
import logging
|
import logging
|
||||||
@@ -132,7 +132,7 @@ def get_meta_information(url, chatbot, history):
|
|||||||
return profile
|
return profile
|
||||||
|
|
||||||
@CatchException
|
@CatchException
|
||||||
def 谷歌检索小助手(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port):
|
def 谷歌检索小助手(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request):
|
||||||
disable_auto_promotion(chatbot=chatbot)
|
disable_auto_promotion(chatbot=chatbot)
|
||||||
# 基本信息:功能、贡献者
|
# 基本信息:功能、贡献者
|
||||||
chatbot.append([
|
chatbot.append([
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import os
|
|||||||
|
|
||||||
|
|
||||||
@CatchException
|
@CatchException
|
||||||
def 猜你想问(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port):
|
def 猜你想问(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request):
|
||||||
if txt:
|
if txt:
|
||||||
show_say = txt
|
show_say = txt
|
||||||
prompt = txt+'\n回答完问题后,再列出用户可能提出的三个问题。'
|
prompt = txt+'\n回答完问题后,再列出用户可能提出的三个问题。'
|
||||||
@@ -32,7 +32,7 @@ def 猜你想问(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt
|
|||||||
|
|
||||||
|
|
||||||
@CatchException
|
@CatchException
|
||||||
def 清除缓存(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port):
|
def 清除缓存(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request):
|
||||||
chatbot.append(['清除本地缓存数据', '执行中. 删除数据'])
|
chatbot.append(['清除本地缓存数据', '执行中. 删除数据'])
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
||||||
|
|
||||||
|
|||||||
@@ -1,21 +1,53 @@
|
|||||||
from toolbox import CatchException, update_ui
|
from toolbox import CatchException, update_ui
|
||||||
from .crazy_utils import request_gpt_model_in_new_thread_with_ui_alive
|
from crazy_functions.crazy_utils import request_gpt_model_in_new_thread_with_ui_alive
|
||||||
import datetime
|
import datetime
|
||||||
@CatchException
|
|
||||||
def 高阶功能模板函数(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port):
|
####################################################################################################################
|
||||||
|
# Demo 1: 一个非常简单的插件 #########################################################################################
|
||||||
|
####################################################################################################################
|
||||||
|
|
||||||
|
高阶功能模板函数示意图 = f"""
|
||||||
|
```mermaid
|
||||||
|
flowchart TD
|
||||||
|
%% <gpt_academic_hide_mermaid_code> 一个特殊标记,用于在生成mermaid图表时隐藏代码块
|
||||||
|
subgraph 函数调用["函数调用过程"]
|
||||||
|
AA["输入栏用户输入的文本(txt)"] --> BB["gpt模型参数(llm_kwargs)"]
|
||||||
|
BB --> CC["插件模型参数(plugin_kwargs)"]
|
||||||
|
CC --> DD["对话显示框的句柄(chatbot)"]
|
||||||
|
DD --> EE["对话历史(history)"]
|
||||||
|
EE --> FF["系统提示词(system_prompt)"]
|
||||||
|
FF --> GG["当前用户信息(web_port)"]
|
||||||
|
|
||||||
|
A["开始(查询5天历史事件)"]
|
||||||
|
A --> B["获取当前月份和日期"]
|
||||||
|
B --> C["生成历史事件查询提示词"]
|
||||||
|
C --> D["调用大模型"]
|
||||||
|
D --> E["更新界面"]
|
||||||
|
E --> F["记录历史"]
|
||||||
|
F --> |"下一天"| B
|
||||||
|
end
|
||||||
|
```
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
@CatchException
|
||||||
|
def 高阶功能模板函数(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request, num_day=5):
|
||||||
|
"""
|
||||||
|
# 高阶功能模板函数示意图:https://mermaid.live/edit#pako:eNptk1tvEkEYhv8KmattQpvlvOyFCcdeeaVXuoYssBwie8gyhCIlqVoLhrbbtAWNUpEGUkyMEDW2Fmn_DDOL_8LZHdOwxrnamX3f7_3mmZk6yKhZCfAgV1KrmYKoQ9fDuKC4yChX0nld1Aou1JzjznQ5fWmejh8LYHW6vG2a47YAnlCLNSIRolnenKBXI_zRIBrcuqRT890u7jZx7zMDt-AaMbnW1--5olGiz2sQjwfoQxsZL0hxplSSU0-rop4vrzmKR6O2JxYjHmwcL2Y_HDatVMkXlf86YzHbGY9bO5j8XE7O8Nsbc3iNB3ukL2SMcH-XIQBgWoVOZzxuOxOJOyc63EPGV6ZQLENVrznViYStTiaJ2vw2M2d9bByRnOXkgCnXylCSU5quyto_IcmkbdvctELmJ-j1ASW3uB3g5xOmKqVTmqr_Na3AtuS_dtBFm8H90XJyHkDDT7S9xXWb4HGmRChx64AOL5HRpUm411rM5uh4H78Z4V7fCZzytjZz2seto9XaNPFue07clLaVZF8UNLygJ-VES8lah_n-O-5Ozc7-77NzJ0-K0yr0ZYrmHdqAk50t2RbA4qq9uNohBASw7YpSgaRkLWCCAtxAlnRZLGbJba9bPwUAC5IsCYAnn1kpJ1ZKUACC0iBSsQLVBzUlA3ioVyQ3qGhZEUrxokiehAz4nFgqk1VNVABfB1uAD_g2_AGPl-W8nMcbCvsDblADfNCz4feyobDPy3rYEMtxwYYbPFNVUoHdCPmDHBv2cP4AMfrCbiBli-Q-3afv0X6WdsIjW2-10fgDy1SAig
|
||||||
|
|
||||||
txt 输入栏用户输入的文本,例如需要翻译的一段话,再例如一个包含了待处理文件的路径
|
txt 输入栏用户输入的文本,例如需要翻译的一段话,再例如一个包含了待处理文件的路径
|
||||||
llm_kwargs gpt模型参数,如温度和top_p等,一般原样传递下去就行
|
llm_kwargs gpt模型参数,如温度和top_p等,一般原样传递下去就行
|
||||||
plugin_kwargs 插件模型的参数,用于灵活调整复杂功能的各种参数
|
plugin_kwargs 插件模型的参数,用于灵活调整复杂功能的各种参数
|
||||||
chatbot 聊天显示框的句柄,用于显示给用户
|
chatbot 聊天显示框的句柄,用于显示给用户
|
||||||
history 聊天历史,前情提要
|
history 聊天历史,前情提要
|
||||||
system_prompt 给gpt的静默提醒
|
system_prompt 给gpt的静默提醒
|
||||||
web_port 当前软件运行的端口号
|
user_request 当前用户的请求信息(IP地址等)
|
||||||
"""
|
"""
|
||||||
history = [] # 清空历史,以免输入溢出
|
history = [] # 清空历史,以免输入溢出
|
||||||
chatbot.append(("这是什么功能?", "[Local Message] 请注意,您正在调用一个[函数插件]的模板,该函数面向希望实现更多有趣功能的开发者,它可以作为创建新功能函数的模板(该函数只有20多行代码)。此外我们也提供可同步处理大量文件的多线程Demo供您参考。您若希望分享新的功能模组,请不吝PR!"))
|
chatbot.append((
|
||||||
|
"您正在调用插件:历史上的今天",
|
||||||
|
"[Local Message] 请注意,您正在调用一个[函数插件]的模板,该函数面向希望实现更多有趣功能的开发者,它可以作为创建新功能函数的模板(该函数只有20多行代码)。此外我们也提供可同步处理大量文件的多线程Demo供您参考。您若希望分享新的功能模组,请不吝PR!" + 高阶功能模板函数示意图))
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 # 由于请求gpt需要一段时间,我们先及时地做一次界面更新
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 # 由于请求gpt需要一段时间,我们先及时地做一次界面更新
|
||||||
for i in range(5):
|
for i in range(int(num_day)):
|
||||||
currentMonth = (datetime.date.today() + datetime.timedelta(days=i)).month
|
currentMonth = (datetime.date.today() + datetime.timedelta(days=i)).month
|
||||||
currentDay = (datetime.date.today() + datetime.timedelta(days=i)).day
|
currentDay = (datetime.date.today() + datetime.timedelta(days=i)).day
|
||||||
i_say = f'历史中哪些事件发生在{currentMonth}月{currentDay}日?列举两条并发送相关图片。发送图片时,请使用Markdown,将Unsplash API中的PUT_YOUR_QUERY_HERE替换成描述该事件的一个最重要的单词。'
|
i_say = f'历史中哪些事件发生在{currentMonth}月{currentDay}日?列举两条并发送相关图片。发送图片时,请使用Markdown,将Unsplash API中的PUT_YOUR_QUERY_HERE替换成描述该事件的一个最重要的单词。'
|
||||||
@@ -27,3 +59,95 @@ def 高阶功能模板函数(txt, llm_kwargs, plugin_kwargs, chatbot, history, s
|
|||||||
chatbot[-1] = (i_say, gpt_say)
|
chatbot[-1] = (i_say, gpt_say)
|
||||||
history.append(i_say);history.append(gpt_say)
|
history.append(i_say);history.append(gpt_say)
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 # 界面更新
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 # 界面更新
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
####################################################################################################################
|
||||||
|
# Demo 2: 一个带二级菜单的插件 #######################################################################################
|
||||||
|
####################################################################################################################
|
||||||
|
|
||||||
|
from crazy_functions.plugin_template.plugin_class_template import GptAcademicPluginTemplate, ArgProperty
|
||||||
|
class Demo_Wrap(GptAcademicPluginTemplate):
|
||||||
|
def __init__(self):
|
||||||
|
"""
|
||||||
|
请注意`execute`会执行在不同的线程中,因此您在定义和使用类变量时,应当慎之又慎!
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
def define_arg_selection_menu(self):
|
||||||
|
"""
|
||||||
|
定义插件的二级选项菜单
|
||||||
|
"""
|
||||||
|
gui_definition = {
|
||||||
|
"num_day":
|
||||||
|
ArgProperty(title="日期选择", options=["仅今天", "未来3天", "未来5天"], default_value="未来3天", description="无", type="dropdown").model_dump_json(),
|
||||||
|
}
|
||||||
|
return gui_definition
|
||||||
|
|
||||||
|
def execute(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request):
|
||||||
|
"""
|
||||||
|
执行插件
|
||||||
|
"""
|
||||||
|
num_day = plugin_kwargs["num_day"]
|
||||||
|
if num_day == "仅今天": num_day = 1
|
||||||
|
if num_day == "未来3天": num_day = 3
|
||||||
|
if num_day == "未来5天": num_day = 5
|
||||||
|
yield from 高阶功能模板函数(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request, num_day=num_day)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
####################################################################################################################
|
||||||
|
# Demo 3: 绘制脑图的Demo ############################################################################################
|
||||||
|
####################################################################################################################
|
||||||
|
|
||||||
|
PROMPT = """
|
||||||
|
请你给出围绕“{subject}”的逻辑关系图,使用mermaid语法,mermaid语法举例:
|
||||||
|
```mermaid
|
||||||
|
graph TD
|
||||||
|
P(编程) --> L1(Python)
|
||||||
|
P(编程) --> L2(C)
|
||||||
|
P(编程) --> L3(C++)
|
||||||
|
P(编程) --> L4(Javascipt)
|
||||||
|
P(编程) --> L5(PHP)
|
||||||
|
```
|
||||||
|
"""
|
||||||
|
@CatchException
|
||||||
|
def 测试图表渲染(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request):
|
||||||
|
"""
|
||||||
|
txt 输入栏用户输入的文本,例如需要翻译的一段话,再例如一个包含了待处理文件的路径
|
||||||
|
llm_kwargs gpt模型参数,如温度和top_p等,一般原样传递下去就行
|
||||||
|
plugin_kwargs 插件模型的参数,用于灵活调整复杂功能的各种参数
|
||||||
|
chatbot 聊天显示框的句柄,用于显示给用户
|
||||||
|
history 聊天历史,前情提要
|
||||||
|
system_prompt 给gpt的静默提醒
|
||||||
|
user_request 当前用户的请求信息(IP地址等)
|
||||||
|
"""
|
||||||
|
history = [] # 清空历史,以免输入溢出
|
||||||
|
chatbot.append(("这是什么功能?", "一个测试mermaid绘制图表的功能,您可以在输入框中输入一些关键词,然后使用mermaid+llm绘制图表。"))
|
||||||
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 # 由于请求gpt需要一段时间,我们先及时地做一次界面更新
|
||||||
|
|
||||||
|
if txt == "": txt = "空白的输入栏" # 调皮一下
|
||||||
|
|
||||||
|
i_say_show_user = f'请绘制有关“{txt}”的逻辑关系图。'
|
||||||
|
i_say = PROMPT.format(subject=txt)
|
||||||
|
gpt_say = yield from request_gpt_model_in_new_thread_with_ui_alive(
|
||||||
|
inputs=i_say,
|
||||||
|
inputs_show_user=i_say_show_user,
|
||||||
|
llm_kwargs=llm_kwargs, chatbot=chatbot, history=[],
|
||||||
|
sys_prompt=""
|
||||||
|
)
|
||||||
|
history.append(i_say); history.append(gpt_say)
|
||||||
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 # 界面更新
|
||||||
@@ -4,9 +4,9 @@
|
|||||||
# 1. 请在以下方案中选择任意一种,然后删除其他的方案
|
# 1. 请在以下方案中选择任意一种,然后删除其他的方案
|
||||||
# 2. 修改你选择的方案中的environment环境变量,详情请见github wiki或者config.py
|
# 2. 修改你选择的方案中的environment环境变量,详情请见github wiki或者config.py
|
||||||
# 3. 选择一种暴露服务端口的方法,并对相应的配置做出修改:
|
# 3. 选择一种暴露服务端口的方法,并对相应的配置做出修改:
|
||||||
# 【方法1: 适用于Linux,很方便,可惜windows不支持】与宿主的网络融合为一体,这个是默认配置
|
# 「方法1: 适用于Linux,很方便,可惜windows不支持」与宿主的网络融合为一体,这个是默认配置
|
||||||
# network_mode: "host"
|
# network_mode: "host"
|
||||||
# 【方法2: 适用于所有系统包括Windows和MacOS】端口映射,把容器的端口映射到宿主的端口(注意您需要先删除network_mode: "host",再追加以下内容)
|
# 「方法2: 适用于所有系统包括Windows和MacOS」端口映射,把容器的端口映射到宿主的端口(注意您需要先删除network_mode: "host",再追加以下内容)
|
||||||
# ports:
|
# ports:
|
||||||
# - "12345:12345" # 注意!12345必须与WEB_PORT环境变量相互对应
|
# - "12345:12345" # 注意!12345必须与WEB_PORT环境变量相互对应
|
||||||
# 4. 最后`docker-compose up`运行
|
# 4. 最后`docker-compose up`运行
|
||||||
@@ -25,7 +25,7 @@
|
|||||||
## ===================================================
|
## ===================================================
|
||||||
|
|
||||||
## ===================================================
|
## ===================================================
|
||||||
## 【方案零】 部署项目的全部能力(这个是包含cuda和latex的大型镜像。如果您网速慢、硬盘小或没有显卡,则不推荐使用这个)
|
## 「方案零」 部署项目的全部能力(这个是包含cuda和latex的大型镜像。如果您网速慢、硬盘小或没有显卡,则不推荐使用这个)
|
||||||
## ===================================================
|
## ===================================================
|
||||||
version: '3'
|
version: '3'
|
||||||
services:
|
services:
|
||||||
@@ -63,10 +63,10 @@ services:
|
|||||||
# count: 1
|
# count: 1
|
||||||
# capabilities: [gpu]
|
# capabilities: [gpu]
|
||||||
|
|
||||||
# 【WEB_PORT暴露方法1: 适用于Linux】与宿主的网络融合
|
# 「WEB_PORT暴露方法1: 适用于Linux」与宿主的网络融合
|
||||||
network_mode: "host"
|
network_mode: "host"
|
||||||
|
|
||||||
# 【WEB_PORT暴露方法2: 适用于所有系统】端口映射
|
# 「WEB_PORT暴露方法2: 适用于所有系统」端口映射
|
||||||
# ports:
|
# ports:
|
||||||
# - "12345:12345" # 12345必须与WEB_PORT相互对应
|
# - "12345:12345" # 12345必须与WEB_PORT相互对应
|
||||||
|
|
||||||
@@ -75,10 +75,8 @@ services:
|
|||||||
bash -c "python3 -u main.py"
|
bash -c "python3 -u main.py"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## ===================================================
|
## ===================================================
|
||||||
## 【方案一】 如果不需要运行本地模型(仅 chatgpt, azure, 星火, 千帆, claude 等在线大模型服务)
|
## 「方案一」 如果不需要运行本地模型(仅 chatgpt, azure, 星火, 千帆, claude 等在线大模型服务)
|
||||||
## ===================================================
|
## ===================================================
|
||||||
version: '3'
|
version: '3'
|
||||||
services:
|
services:
|
||||||
@@ -97,16 +95,16 @@ services:
|
|||||||
# DEFAULT_WORKER_NUM: ' 10 '
|
# DEFAULT_WORKER_NUM: ' 10 '
|
||||||
# AUTHENTICATION: ' [("username", "passwd"), ("username2", "passwd2")] '
|
# AUTHENTICATION: ' [("username", "passwd"), ("username2", "passwd2")] '
|
||||||
|
|
||||||
# 与宿主的网络融合
|
# 「WEB_PORT暴露方法1: 适用于Linux」与宿主的网络融合
|
||||||
network_mode: "host"
|
network_mode: "host"
|
||||||
|
|
||||||
# 不使用代理网络拉取最新代码
|
# 启动命令
|
||||||
command: >
|
command: >
|
||||||
bash -c "python3 -u main.py"
|
bash -c "python3 -u main.py"
|
||||||
|
|
||||||
|
|
||||||
### ===================================================
|
### ===================================================
|
||||||
### 【方案二】 如果需要运行ChatGLM + Qwen + MOSS等本地模型
|
### 「方案二」 如果需要运行ChatGLM + Qwen + MOSS等本地模型
|
||||||
### ===================================================
|
### ===================================================
|
||||||
version: '3'
|
version: '3'
|
||||||
services:
|
services:
|
||||||
@@ -130,8 +128,10 @@ services:
|
|||||||
devices:
|
devices:
|
||||||
- /dev/nvidia0:/dev/nvidia0
|
- /dev/nvidia0:/dev/nvidia0
|
||||||
|
|
||||||
# 与宿主的网络融合
|
# 「WEB_PORT暴露方法1: 适用于Linux」与宿主的网络融合
|
||||||
network_mode: "host"
|
network_mode: "host"
|
||||||
|
|
||||||
|
# 启动命令
|
||||||
command: >
|
command: >
|
||||||
bash -c "python3 -u main.py"
|
bash -c "python3 -u main.py"
|
||||||
|
|
||||||
@@ -139,8 +139,9 @@ services:
|
|||||||
# command: >
|
# command: >
|
||||||
# bash -c "pip install -r request_llms/requirements_qwen.txt && python3 -u main.py"
|
# bash -c "pip install -r request_llms/requirements_qwen.txt && python3 -u main.py"
|
||||||
|
|
||||||
|
|
||||||
### ===================================================
|
### ===================================================
|
||||||
### 【方案三】 如果需要运行ChatGPT + LLAMA + 盘古 + RWKV本地模型
|
### 「方案三」 如果需要运行ChatGPT + LLAMA + 盘古 + RWKV本地模型
|
||||||
### ===================================================
|
### ===================================================
|
||||||
version: '3'
|
version: '3'
|
||||||
services:
|
services:
|
||||||
@@ -164,21 +165,22 @@ services:
|
|||||||
devices:
|
devices:
|
||||||
- /dev/nvidia0:/dev/nvidia0
|
- /dev/nvidia0:/dev/nvidia0
|
||||||
|
|
||||||
# 与宿主的网络融合
|
# 「WEB_PORT暴露方法1: 适用于Linux」与宿主的网络融合
|
||||||
network_mode: "host"
|
network_mode: "host"
|
||||||
|
|
||||||
# 不使用代理网络拉取最新代码
|
# 启动命令
|
||||||
command: >
|
command: >
|
||||||
python3 -u main.py
|
python3 -u main.py
|
||||||
|
|
||||||
|
|
||||||
## ===================================================
|
## ===================================================
|
||||||
## 【方案四】 ChatGPT + Latex
|
## 「方案四」 ChatGPT + Latex
|
||||||
## ===================================================
|
## ===================================================
|
||||||
version: '3'
|
version: '3'
|
||||||
services:
|
services:
|
||||||
gpt_academic_with_latex:
|
gpt_academic_with_latex:
|
||||||
image: ghcr.io/binary-husky/gpt_academic_with_latex:master # (Auto Built by Dockerfile: docs/GithubAction+NoLocal+Latex)
|
image: ghcr.io/binary-husky/gpt_academic_with_latex:master # (Auto Built by Dockerfile: docs/GithubAction+NoLocal+Latex)
|
||||||
|
# 对于ARM64设备,请将以上镜像名称替换为 ghcr.io/binary-husky/gpt_academic_with_latex_arm:master
|
||||||
environment:
|
environment:
|
||||||
# 请查阅 `config.py` 以查看所有的配置信息
|
# 请查阅 `config.py` 以查看所有的配置信息
|
||||||
API_KEY: ' sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx '
|
API_KEY: ' sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx '
|
||||||
@@ -190,16 +192,16 @@ services:
|
|||||||
DEFAULT_WORKER_NUM: ' 10 '
|
DEFAULT_WORKER_NUM: ' 10 '
|
||||||
WEB_PORT: ' 12303 '
|
WEB_PORT: ' 12303 '
|
||||||
|
|
||||||
# 与宿主的网络融合
|
# 「WEB_PORT暴露方法1: 适用于Linux」与宿主的网络融合
|
||||||
network_mode: "host"
|
network_mode: "host"
|
||||||
|
|
||||||
# 不使用代理网络拉取最新代码
|
# 启动命令
|
||||||
command: >
|
command: >
|
||||||
bash -c "python3 -u main.py"
|
bash -c "python3 -u main.py"
|
||||||
|
|
||||||
|
|
||||||
## ===================================================
|
## ===================================================
|
||||||
## 【方案五】 ChatGPT + 语音助手 (请先阅读 docs/use_audio.md)
|
## 「方案五」 ChatGPT + 语音助手 (请先阅读 docs/use_audio.md)
|
||||||
## ===================================================
|
## ===================================================
|
||||||
version: '3'
|
version: '3'
|
||||||
services:
|
services:
|
||||||
@@ -223,9 +225,9 @@ services:
|
|||||||
# (无需填写) ALIYUN_ACCESSKEY: ' LTAI5q6BrFUzoRXVGUWnekh1 '
|
# (无需填写) ALIYUN_ACCESSKEY: ' LTAI5q6BrFUzoRXVGUWnekh1 '
|
||||||
# (无需填写) ALIYUN_SECRET: ' eHmI20AVWIaQZ0CiTD2bGQVsaP9i68 '
|
# (无需填写) ALIYUN_SECRET: ' eHmI20AVWIaQZ0CiTD2bGQVsaP9i68 '
|
||||||
|
|
||||||
# 与宿主的网络融合
|
# 「WEB_PORT暴露方法1: 适用于Linux」与宿主的网络融合
|
||||||
network_mode: "host"
|
network_mode: "host"
|
||||||
|
|
||||||
# 不使用代理网络拉取最新代码
|
# 启动命令
|
||||||
command: >
|
command: >
|
||||||
bash -c "python3 -u main.py"
|
bash -c "python3 -u main.py"
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
# 此Dockerfile不再维护,请前往docs/GithubAction+JittorLLMs
|
|
||||||
@@ -3,6 +3,9 @@
|
|||||||
# 从NVIDIA源,从而支持显卡(检查宿主的nvidia-smi中的cuda版本必须>=11.3)
|
# 从NVIDIA源,从而支持显卡(检查宿主的nvidia-smi中的cuda版本必须>=11.3)
|
||||||
FROM fuqingxu/11.3.1-runtime-ubuntu20.04-with-texlive:latest
|
FROM fuqingxu/11.3.1-runtime-ubuntu20.04-with-texlive:latest
|
||||||
|
|
||||||
|
# edge-tts需要的依赖,某些pip包所需的依赖
|
||||||
|
RUN apt update && apt install ffmpeg build-essential -y
|
||||||
|
|
||||||
# use python3 as the system default python
|
# use python3 as the system default python
|
||||||
WORKDIR /gpt
|
WORKDIR /gpt
|
||||||
RUN curl -sS https://bootstrap.pypa.io/get-pip.py | python3.8
|
RUN curl -sS https://bootstrap.pypa.io/get-pip.py | python3.8
|
||||||
|
|||||||
@@ -1,53 +0,0 @@
|
|||||||
# docker build -t gpt-academic-all-capacity -f docs/GithubAction+AllCapacity --network=host --build-arg http_proxy=http://localhost:10881 --build-arg https_proxy=http://localhost:10881 .
|
|
||||||
# docker build -t gpt-academic-all-capacity -f docs/GithubAction+AllCapacityBeta --network=host .
|
|
||||||
# docker run -it --net=host gpt-academic-all-capacity bash
|
|
||||||
|
|
||||||
# 从NVIDIA源,从而支持显卡(检查宿主的nvidia-smi中的cuda版本必须>=11.3)
|
|
||||||
FROM fuqingxu/11.3.1-runtime-ubuntu20.04-with-texlive:latest
|
|
||||||
|
|
||||||
# use python3 as the system default python
|
|
||||||
WORKDIR /gpt
|
|
||||||
RUN curl -sS https://bootstrap.pypa.io/get-pip.py | python3.8
|
|
||||||
|
|
||||||
# # 非必要步骤,更换pip源 (以下三行,可以删除)
|
|
||||||
# RUN echo '[global]' > /etc/pip.conf && \
|
|
||||||
# echo 'index-url = https://mirrors.aliyun.com/pypi/simple/' >> /etc/pip.conf && \
|
|
||||||
# echo 'trusted-host = mirrors.aliyun.com' >> /etc/pip.conf
|
|
||||||
|
|
||||||
# 下载pytorch
|
|
||||||
RUN python3 -m pip install torch torchvision --extra-index-url https://download.pytorch.org/whl/cu113
|
|
||||||
# 准备pip依赖
|
|
||||||
RUN python3 -m pip install openai numpy arxiv rich
|
|
||||||
RUN python3 -m pip install colorama Markdown pygments pymupdf
|
|
||||||
RUN python3 -m pip install python-docx moviepy pdfminer
|
|
||||||
RUN python3 -m pip install zh_langchain==0.2.1 pypinyin
|
|
||||||
RUN python3 -m pip install rarfile py7zr
|
|
||||||
RUN python3 -m pip install aliyun-python-sdk-core==2.13.3 pyOpenSSL webrtcvad scipy git+https://github.com/aliyun/alibabacloud-nls-python-sdk.git
|
|
||||||
# 下载分支
|
|
||||||
WORKDIR /gpt
|
|
||||||
RUN git clone --depth=1 https://github.com/binary-husky/gpt_academic.git
|
|
||||||
WORKDIR /gpt/gpt_academic
|
|
||||||
RUN git clone --depth=1 https://github.com/OpenLMLab/MOSS.git request_llms/moss
|
|
||||||
|
|
||||||
RUN python3 -m pip install -r requirements.txt
|
|
||||||
RUN python3 -m pip install -r request_llms/requirements_moss.txt
|
|
||||||
RUN python3 -m pip install -r request_llms/requirements_qwen.txt
|
|
||||||
RUN python3 -m pip install -r request_llms/requirements_chatglm.txt
|
|
||||||
RUN python3 -m pip install -r request_llms/requirements_newbing.txt
|
|
||||||
RUN python3 -m pip install nougat-ocr
|
|
||||||
|
|
||||||
# 预热Tiktoken模块
|
|
||||||
RUN python3 -c 'from check_proxy import warm_up_modules; warm_up_modules()'
|
|
||||||
|
|
||||||
# 安装知识库插件的额外依赖
|
|
||||||
RUN apt-get update && apt-get install libgl1 -y
|
|
||||||
RUN pip3 install transformers protobuf langchain sentence-transformers faiss-cpu nltk beautifulsoup4 bitsandbytes tabulate icetk --upgrade
|
|
||||||
RUN pip3 install unstructured[all-docs] --upgrade
|
|
||||||
RUN python3 -c 'from check_proxy import warm_up_vectordb; warm_up_vectordb()'
|
|
||||||
RUN rm -rf /usr/local/lib/python3.8/dist-packages/tests
|
|
||||||
|
|
||||||
|
|
||||||
# COPY .cache /root/.cache
|
|
||||||
# COPY config_private.py config_private.py
|
|
||||||
# 启动
|
|
||||||
CMD ["python3", "-u", "main.py"]
|
|
||||||
@@ -5,6 +5,8 @@ RUN apt-get update
|
|||||||
RUN apt-get install -y curl proxychains curl gcc
|
RUN apt-get install -y curl proxychains curl gcc
|
||||||
RUN apt-get install -y git python python3 python-dev python3-dev --fix-missing
|
RUN apt-get install -y git python python3 python-dev python3-dev --fix-missing
|
||||||
|
|
||||||
|
# edge-tts需要的依赖,某些pip包所需的依赖
|
||||||
|
RUN apt update && apt install ffmpeg build-essential -y
|
||||||
|
|
||||||
# use python3 as the system default python
|
# use python3 as the system default python
|
||||||
RUN curl -sS https://bootstrap.pypa.io/get-pip.py | python3.8
|
RUN curl -sS https://bootstrap.pypa.io/get-pip.py | python3.8
|
||||||
@@ -22,7 +24,6 @@ RUN python3 -m pip install -r request_llms/requirements_chatglm.txt
|
|||||||
RUN python3 -m pip install -r request_llms/requirements_newbing.txt
|
RUN python3 -m pip install -r request_llms/requirements_newbing.txt
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# 预热Tiktoken模块
|
# 预热Tiktoken模块
|
||||||
RUN python3 -c 'from check_proxy import warm_up_modules; warm_up_modules()'
|
RUN python3 -c 'from check_proxy import warm_up_modules; warm_up_modules()'
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,9 @@ RUN python3 -m pip install -r request_llms/requirements_jittorllms.txt -i https:
|
|||||||
# 下载JittorLLMs
|
# 下载JittorLLMs
|
||||||
RUN git clone https://github.com/binary-husky/JittorLLMs.git --depth 1 request_llms/jittorllms
|
RUN git clone https://github.com/binary-husky/JittorLLMs.git --depth 1 request_llms/jittorllms
|
||||||
|
|
||||||
|
# edge-tts需要的依赖
|
||||||
|
RUN apt update && apt install ffmpeg -y
|
||||||
|
|
||||||
# 禁用缓存,确保更新代码
|
# 禁用缓存,确保更新代码
|
||||||
ADD "https://www.random.org/cgi-bin/randbyte?nbytes=10&format=h" skipcache
|
ADD "https://www.random.org/cgi-bin/randbyte?nbytes=10&format=h" skipcache
|
||||||
RUN git pull
|
RUN git pull
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ COPY . .
|
|||||||
# 安装依赖
|
# 安装依赖
|
||||||
RUN pip3 install -r requirements.txt
|
RUN pip3 install -r requirements.txt
|
||||||
|
|
||||||
|
# edge-tts需要的依赖
|
||||||
|
RUN apt update && apt install ffmpeg -y
|
||||||
|
|
||||||
# 可选步骤,用于预热模块
|
# 可选步骤,用于预热模块
|
||||||
RUN python3 -c 'from check_proxy import warm_up_modules; warm_up_modules()'
|
RUN python3 -c 'from check_proxy import warm_up_modules; warm_up_modules()'
|
||||||
|
|||||||
@@ -13,7 +13,10 @@ COPY . .
|
|||||||
RUN pip3 install -r requirements.txt
|
RUN pip3 install -r requirements.txt
|
||||||
|
|
||||||
# 安装语音插件的额外依赖
|
# 安装语音插件的额外依赖
|
||||||
RUN pip3 install pyOpenSSL scipy git+https://github.com/aliyun/alibabacloud-nls-python-sdk.git
|
RUN pip3 install aliyun-python-sdk-core==2.13.3 pyOpenSSL webrtcvad scipy git+https://github.com/aliyun/alibabacloud-nls-python-sdk.git
|
||||||
|
|
||||||
|
# edge-tts需要的依赖
|
||||||
|
RUN apt update && apt install ffmpeg -y
|
||||||
|
|
||||||
# 可选步骤,用于预热模块
|
# 可选步骤,用于预热模块
|
||||||
RUN python3 -c 'from check_proxy import warm_up_modules; warm_up_modules()'
|
RUN python3 -c 'from check_proxy import warm_up_modules; warm_up_modules()'
|
||||||
|
|||||||
@@ -1,29 +1,31 @@
|
|||||||
# 此Dockerfile适用于“无本地模型”的环境构建,如果需要使用chatglm等本地模型,请参考 docs/Dockerfile+ChatGLM
|
# 此Dockerfile适用于"无本地模型"的环境构建,如果需要使用chatglm等本地模型,请参考 docs/Dockerfile+ChatGLM
|
||||||
# - 1 修改 `config.py`
|
# - 1 修改 `config.py`
|
||||||
# - 2 构建 docker build -t gpt-academic-nolocal-latex -f docs/GithubAction+NoLocal+Latex .
|
# - 2 构建 docker build -t gpt-academic-nolocal-latex -f docs/GithubAction+NoLocal+Latex .
|
||||||
# - 3 运行 docker run -v /home/fuqingxu/arxiv_cache:/root/arxiv_cache --rm -it --net=host gpt-academic-nolocal-latex
|
# - 3 运行 docker run -v /home/fuqingxu/arxiv_cache:/root/arxiv_cache --rm -it --net=host gpt-academic-nolocal-latex
|
||||||
|
|
||||||
FROM fuqingxu/python311_texlive_ctex:latest
|
FROM menghuan1918/ubuntu_uv_ctex:latest
|
||||||
ENV PATH "$PATH:/usr/local/texlive/2022/bin/x86_64-linux"
|
ENV DEBIAN_FRONTEND=noninteractive
|
||||||
ENV PATH "$PATH:/usr/local/texlive/2023/bin/x86_64-linux"
|
SHELL ["/bin/bash", "-c"]
|
||||||
ENV PATH "$PATH:/usr/local/texlive/2024/bin/x86_64-linux"
|
|
||||||
ENV PATH "$PATH:/usr/local/texlive/2025/bin/x86_64-linux"
|
|
||||||
ENV PATH "$PATH:/usr/local/texlive/2026/bin/x86_64-linux"
|
|
||||||
|
|
||||||
# 指定路径
|
|
||||||
WORKDIR /gpt
|
WORKDIR /gpt
|
||||||
|
|
||||||
RUN pip3 install openai numpy arxiv rich
|
# 先复制依赖文件
|
||||||
RUN pip3 install colorama Markdown pygments pymupdf
|
COPY requirements.txt .
|
||||||
RUN pip3 install python-docx pdfminer
|
|
||||||
RUN pip3 install nougat-ocr
|
|
||||||
|
|
||||||
# 装载项目文件
|
|
||||||
COPY . .
|
|
||||||
|
|
||||||
|
|
||||||
# 安装依赖
|
# 安装依赖
|
||||||
RUN pip3 install -r requirements.txt
|
RUN pip install --break-system-packages openai numpy arxiv rich colorama Markdown pygments pymupdf python-docx pdfminer \
|
||||||
|
&& pip install --break-system-packages -r requirements.txt \
|
||||||
|
&& if [ "$(uname -m)" = "x86_64" ]; then \
|
||||||
|
pip install --break-system-packages nougat-ocr; \
|
||||||
|
fi \
|
||||||
|
&& pip cache purge \
|
||||||
|
&& rm -rf /root/.cache/pip/*
|
||||||
|
|
||||||
|
# 创建非root用户
|
||||||
|
RUN useradd -m gptuser && chown -R gptuser /gpt
|
||||||
|
USER gptuser
|
||||||
|
|
||||||
|
# 最后才复制代码文件,这样代码更新时只需重建最后几层,可以大幅减少docker pull所需的大小
|
||||||
|
COPY --chown=gptuser:gptuser . .
|
||||||
|
|
||||||
# 可选步骤,用于预热模块
|
# 可选步骤,用于预热模块
|
||||||
RUN python3 -c 'from check_proxy import warm_up_modules; warm_up_modules()'
|
RUN python3 -c 'from check_proxy import warm_up_modules; warm_up_modules()'
|
||||||
|
|||||||
@@ -19,6 +19,9 @@ RUN pip3 install transformers protobuf langchain sentence-transformers faiss-cp
|
|||||||
RUN pip3 install unstructured[all-docs] --upgrade
|
RUN pip3 install unstructured[all-docs] --upgrade
|
||||||
RUN python3 -c 'from check_proxy import warm_up_vectordb; warm_up_vectordb()'
|
RUN python3 -c 'from check_proxy import warm_up_vectordb; warm_up_vectordb()'
|
||||||
|
|
||||||
|
# edge-tts需要的依赖
|
||||||
|
RUN apt update && apt install ffmpeg -y
|
||||||
|
|
||||||
# 可选步骤,用于预热模块
|
# 可选步骤,用于预热模块
|
||||||
RUN python3 -c 'from check_proxy import warm_up_modules; warm_up_modules()'
|
RUN python3 -c 'from check_proxy import warm_up_modules; warm_up_modules()'
|
||||||
|
|
||||||
|
|||||||
@@ -35,7 +35,6 @@ if __name__ == "__main__":
|
|||||||
main()
|
main()
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
3. Go!
|
3. Go!
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
|
|||||||
某些文件未显示,因为此 diff 中更改的文件太多 显示更多
在新工单中引用
屏蔽一个用户